-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathsample-app.tsx
More file actions
105 lines (89 loc) · 3.17 KB
/
Copy pathsample-app.tsx
File metadata and controls
105 lines (89 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { createContext, useContext, useState } from "react";
// --- Types ---
interface ThemeContextValue {
mode: "light" | "dark";
setMode: (mode: "light" | "dark") => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
// --- Provider with React.ReactNode children ---
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [mode, setMode] = useState<"light" | "dark">("light");
return (
<ThemeContext.Provider value={{ mode, setMode }}>
{children}
</ThemeContext.Provider>
);
}
// --- Component with mixed props (simple + React types) ---
interface User {
name: string;
email: string;
id: number;
joinedAt: Date;
}
interface UserCardProps {
user: User;
role: "admin" | "editor" | "viewer";
permissions: string[];
onEdit: (id: number) => void;
tags: Map<string, boolean>;
statusIndicator: React.ReactElement;
actionBar?: React.ReactNode;
}
function UserCard({ user, role, permissions, onEdit, tags, statusIndicator, actionBar }: UserCardProps) {
const [expanded, setExpanded] = useState(false);
const theme = useContext(ThemeContext);
return (
<div style={{ border: "1px solid #eee", padding: 12, borderRadius: 8, marginBottom: 8 }}>
<strong>{user.name}</strong> ({role})
<div style={{ fontSize: 12 }}>{user.email}</div>
<div>{permissions.join(", ")}</div>
<div>{statusIndicator}</div>
{actionBar}
<button type="button" onClick={() => setExpanded(!expanded)}>
{expanded ? "Hide" : "Show"}
</button>
{expanded && (
<div>
<div>ID: {user.id}</div>
<button type="button" onClick={() => onEdit(user.id)}>Edit</button>
</div>
)}
</div>
);
}
// --- Simple component (no React types) ---
interface TodoItemProps {
id: number;
title: string;
completed: boolean;
priority: "low" | "medium" | "high";
onToggle: (id: number) => void;
}
function TodoItem({ id, title, completed, priority, onToggle }: TodoItemProps) {
return (
<div style={{ display: "flex", gap: 8, padding: 4 }}>
<input type="checkbox" checked={completed} onChange={() => onToggle(id)} />
<span style={{ textDecoration: completed ? "line-through" : "none" }}>{title}</span>
<span>({priority})</span>
</div>
);
}
// --- Main sample app ---
function SampleApp() {
return (
<ThemeProvider>
<h3>Sample App (iframe)</h3>
<UserCard
user={{ name: "Alice", email: "alice@test.com", id: 1, joinedAt: new Date() }}
role="admin"
permissions={["read", "write"]}
onEdit={(id) => console.log("edit", id)}
tags={new Map([["verified", true]])}
statusIndicator={<span>Active</span>}
/>
<TodoItem id={1} title="Write docs" completed={false} priority="high" onToggle={() => {}} />
</ThemeProvider>
);
}
export { ThemeProvider, ThemeContext, UserCard, TodoItem, SampleApp };