@silvery/examples 0.17.3 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/UPNG-ShUlaTDh.mjs +5074 -0
  2. package/dist/__vite-browser-external-2447137e-Bopa5BFR.mjs +4 -0
  3. package/dist/_banner-A70_y2Vi.mjs +43 -0
  4. package/dist/ansi-0VXlUmNn.mjs +16397 -0
  5. package/dist/apng-B0gRaDVT.mjs +3 -0
  6. package/dist/apng-BTRDTfDW.mjs +68 -0
  7. package/dist/apps/aichat/index.mjs +1298 -0
  8. package/dist/apps/app-todo.mjs +138 -0
  9. package/dist/apps/async-data.mjs +203 -0
  10. package/dist/apps/cli-wizard.mjs +338 -0
  11. package/dist/apps/clipboard.mjs +197 -0
  12. package/dist/apps/components.mjs +863 -0
  13. package/dist/apps/data-explorer.mjs +482 -0
  14. package/dist/apps/dev-tools.mjs +396 -0
  15. package/dist/apps/explorer.mjs +697 -0
  16. package/dist/apps/gallery.mjs +765 -0
  17. package/dist/apps/inline-bench.mjs +115 -0
  18. package/dist/apps/kanban.mjs +279 -0
  19. package/dist/apps/layout-ref.mjs +186 -0
  20. package/dist/apps/outline.mjs +202 -0
  21. package/dist/apps/paste-demo.mjs +188 -0
  22. package/dist/apps/scroll.mjs +85 -0
  23. package/dist/apps/search-filter.mjs +286 -0
  24. package/dist/apps/selection.mjs +354 -0
  25. package/dist/apps/spatial-focus-demo.mjs +387 -0
  26. package/dist/apps/task-list.mjs +257 -0
  27. package/dist/apps/terminal-caps-demo.mjs +314 -0
  28. package/dist/apps/terminal.mjs +871 -0
  29. package/dist/apps/text-selection-demo.mjs +253 -0
  30. package/dist/apps/textarea.mjs +177 -0
  31. package/dist/apps/theme.mjs +660 -0
  32. package/dist/apps/transform.mjs +214 -0
  33. package/dist/apps/virtual-10k.mjs +421 -0
  34. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  35. package/dist/backends-Dj-11kZF.mjs +1179 -0
  36. package/dist/backends-U3QwStfO.mjs +3 -0
  37. package/dist/{cli.mjs → bin/cli.mjs} +15 -19
  38. package/dist/chunk-BSw8zbkd.mjs +37 -0
  39. package/dist/components/counter.mjs +47 -0
  40. package/dist/components/hello.mjs +30 -0
  41. package/dist/components/progress-bar.mjs +58 -0
  42. package/dist/components/select-list.mjs +84 -0
  43. package/dist/components/spinner.mjs +56 -0
  44. package/dist/components/text-input.mjs +61 -0
  45. package/dist/components/virtual-list.mjs +50 -0
  46. package/dist/flexily-zero-adapter-ByVzLTFP.mjs +3374 -0
  47. package/dist/gif-B6NGH5gs.mjs +3 -0
  48. package/dist/gif-CfkOF-iG.mjs +71 -0
  49. package/dist/gifenc-BI4ihP_T.mjs +728 -0
  50. package/dist/key-mapping-5oYQdAQE.mjs +3 -0
  51. package/dist/key-mapping-D4LR1go6.mjs +130 -0
  52. package/dist/layout/dashboard.mjs +1203 -0
  53. package/dist/layout/live-resize.mjs +302 -0
  54. package/dist/layout/overflow.mjs +69 -0
  55. package/dist/layout/text-layout.mjs +334 -0
  56. package/dist/node-nsrAOjH4.mjs +1083 -0
  57. package/dist/plugins-CT0DdV_E.mjs +3056 -0
  58. package/dist/resvg-js-Cnk2o49d.mjs +201 -0
  59. package/dist/src-9ZhfQyzD.mjs +814 -0
  60. package/dist/src-CUUOuRH6.mjs +5322 -0
  61. package/dist/src-jO3Zuzjj.mjs +23538 -0
  62. package/dist/usingCtx-CsEf0xO3.mjs +57 -0
  63. package/dist/yoga-adapter-BSQHuMV9.mjs +237 -0
  64. package/package.json +21 -14
  65. package/_banner.tsx +0 -60
  66. package/apps/aichat/components.tsx +0 -469
  67. package/apps/aichat/index.tsx +0 -220
  68. package/apps/aichat/script.ts +0 -460
  69. package/apps/aichat/state.ts +0 -325
  70. package/apps/aichat/types.ts +0 -19
  71. package/apps/app-todo.tsx +0 -201
  72. package/apps/async-data.tsx +0 -196
  73. package/apps/cli-wizard.tsx +0 -332
  74. package/apps/clipboard.tsx +0 -183
  75. package/apps/components.tsx +0 -658
  76. package/apps/data-explorer.tsx +0 -490
  77. package/apps/dev-tools.tsx +0 -395
  78. package/apps/explorer.tsx +0 -731
  79. package/apps/gallery.tsx +0 -653
  80. package/apps/inline-bench.tsx +0 -138
  81. package/apps/kanban.tsx +0 -265
  82. package/apps/layout-ref.tsx +0 -173
  83. package/apps/outline.tsx +0 -160
  84. package/apps/panes/index.tsx +0 -203
  85. package/apps/paste-demo.tsx +0 -185
  86. package/apps/scroll.tsx +0 -80
  87. package/apps/search-filter.tsx +0 -240
  88. package/apps/selection.tsx +0 -346
  89. package/apps/spatial-focus-demo.tsx +0 -372
  90. package/apps/task-list.tsx +0 -271
  91. package/apps/terminal-caps-demo.tsx +0 -317
  92. package/apps/terminal.tsx +0 -784
  93. package/apps/text-selection-demo.tsx +0 -193
  94. package/apps/textarea.tsx +0 -155
  95. package/apps/theme.tsx +0 -515
  96. package/apps/transform.tsx +0 -229
  97. package/apps/virtual-10k.tsx +0 -405
  98. package/apps/vterm-demo/index.tsx +0 -216
  99. package/components/counter.tsx +0 -49
  100. package/components/hello.tsx +0 -38
  101. package/components/progress-bar.tsx +0 -52
  102. package/components/select-list.tsx +0 -54
  103. package/components/spinner.tsx +0 -44
  104. package/components/text-input.tsx +0 -61
  105. package/components/virtual-list.tsx +0 -56
  106. package/dist/cli.d.mts +0 -1
  107. package/dist/cli.mjs.map +0 -1
  108. package/layout/dashboard.tsx +0 -953
  109. package/layout/live-resize.tsx +0 -282
  110. package/layout/overflow.tsx +0 -51
  111. package/layout/text-layout.tsx +0 -283
@@ -0,0 +1,138 @@
1
+ import { a as createApp, i as pipe, n as withTerminal, o as useApp$1, r as withReact } from "../plugins-CT0DdV_E.mjs";
2
+ import { t as ExampleBanner } from "../_banner-A70_y2Vi.mjs";
3
+ import "react";
4
+ import { Box, Kbd, Muted, Text } from "silvery";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region apps/app-todo.tsx
7
+ const meta = {
8
+ name: "Todo App",
9
+ description: "Layer 3: pipe() + createApp() + withReact() + withTerminal()",
10
+ features: [
11
+ "pipe()",
12
+ "createApp()",
13
+ "withReact()",
14
+ "withTerminal()"
15
+ ]
16
+ };
17
+ function TodoItem({ todo, isCursor }) {
18
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
19
+ color: isCursor ? "$primary" : void 0,
20
+ children: isCursor ? "› " : " "
21
+ }), /* @__PURE__ */ jsxs(Text, {
22
+ color: todo.completed ? "$success" : void 0,
23
+ strikethrough: todo.completed,
24
+ children: [
25
+ todo.completed ? "✓" : "○",
26
+ " ",
27
+ todo.text
28
+ ]
29
+ })] });
30
+ }
31
+ function TodoList() {
32
+ const todos = useApp$1((s) => s.todos);
33
+ const cursor = useApp$1((s) => s.cursor);
34
+ return /* @__PURE__ */ jsxs(Box, {
35
+ flexDirection: "column",
36
+ children: [todos.map((todo, i) => /* @__PURE__ */ jsx(TodoItem, {
37
+ todo,
38
+ isCursor: i === cursor
39
+ }, todo.id)), todos.length === 0 && /* @__PURE__ */ jsx(Muted, { children: "No todos. Press 'a' to add one." })]
40
+ });
41
+ }
42
+ function TodoApp() {
43
+ return /* @__PURE__ */ jsxs(Box, {
44
+ flexDirection: "column",
45
+ padding: 1,
46
+ children: [
47
+ /* @__PURE__ */ jsx(TodoList, {}),
48
+ /* @__PURE__ */ jsx(Text, { children: " " }),
49
+ /* @__PURE__ */ jsxs(Muted, { children: [
50
+ /* @__PURE__ */ jsx(Kbd, { children: "j/k" }),
51
+ " move ",
52
+ /* @__PURE__ */ jsx(Kbd, { children: "x" }),
53
+ " toggle ",
54
+ /* @__PURE__ */ jsx(Kbd, { children: "a" }),
55
+ " add ",
56
+ /* @__PURE__ */ jsx(Kbd, { children: "d" }),
57
+ " delete ",
58
+ /* @__PURE__ */ jsx(Kbd, { children: "Esc/q" }),
59
+ " quit"
60
+ ] })
61
+ ]
62
+ });
63
+ }
64
+ const app = pipe(createApp(() => (set, get) => ({
65
+ todos: [
66
+ {
67
+ id: 1,
68
+ text: "Learn silvery plugin composition",
69
+ completed: true
70
+ },
71
+ {
72
+ id: 2,
73
+ text: "Build an app with pipe()",
74
+ completed: false
75
+ },
76
+ {
77
+ id: 3,
78
+ text: "Ship to production",
79
+ completed: false
80
+ }
81
+ ],
82
+ cursor: 0,
83
+ nextId: 4,
84
+ addTodo: (text) => set((s) => ({
85
+ todos: [...s.todos, {
86
+ id: s.nextId,
87
+ text,
88
+ completed: false
89
+ }],
90
+ nextId: s.nextId + 1
91
+ })),
92
+ toggleTodo: () => set((s) => ({ todos: s.todos.map((t, i) => i === s.cursor ? {
93
+ ...t,
94
+ completed: !t.completed
95
+ } : t) })),
96
+ deleteTodo: () => set((s) => {
97
+ const newTodos = s.todos.filter((_, i) => i !== s.cursor);
98
+ return {
99
+ todos: newTodos,
100
+ cursor: Math.min(s.cursor, newTodos.length - 1)
101
+ };
102
+ }),
103
+ moveCursor: (delta) => set((s) => ({ cursor: Math.max(0, Math.min(s.cursor + delta, s.todos.length - 1)) }))
104
+ }), { "term:key": (data, ctx) => {
105
+ const { input: k, key } = data;
106
+ const state = ctx.get();
107
+ if (key.escape) return "exit";
108
+ switch (k) {
109
+ case "j":
110
+ state.moveCursor(1);
111
+ break;
112
+ case "k":
113
+ state.moveCursor(-1);
114
+ break;
115
+ case "x":
116
+ state.toggleTodo();
117
+ break;
118
+ case "d":
119
+ if (state.todos.length > 0) state.deleteTodo();
120
+ break;
121
+ case "a":
122
+ state.addTodo(`New todo ${state.nextId}`);
123
+ break;
124
+ case "q": return "exit";
125
+ }
126
+ } }), withReact(/* @__PURE__ */ jsx(ExampleBanner, {
127
+ meta,
128
+ controls: "j/k move x toggle a add d delete Esc/q quit",
129
+ children: /* @__PURE__ */ jsx(TodoApp, {})
130
+ })), withTerminal(process));
131
+ async function main() {
132
+ const handle = await app.run();
133
+ await handle.waitUntilExit();
134
+ console.log("\nFinal state:", handle.store.getState().todos.length, "todos");
135
+ }
136
+ if (import.meta.main) await main();
137
+ //#endregion
138
+ export { main, meta };
@@ -0,0 +1,203 @@
1
+ import { t as _usingCtx } from "../usingCtx-CsEf0xO3.mjs";
2
+ import { t as ExampleBanner } from "../_banner-A70_y2Vi.mjs";
3
+ import { Suspense, use, useState } from "react";
4
+ import { Box, ErrorBoundary, H1, Kbd, Muted, Text, createTerm, render, useApp, useInput } from "silvery";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region apps/async-data.tsx
7
+ /**
8
+ * Async Data Example
9
+ *
10
+ * Demonstrates React Suspense for async data loading:
11
+ * - Suspense boundaries with fallback UI
12
+ * - Multiple independent suspending components
13
+ * - Error handling with ErrorBoundary
14
+ */
15
+ const meta = {
16
+ name: "Async Data",
17
+ description: "React Suspense with independent data sources and error boundaries",
18
+ features: [
19
+ "React Suspense",
20
+ "use() hook",
21
+ "ErrorBoundary"
22
+ ]
23
+ };
24
+ const cache = /* @__PURE__ */ new Map();
25
+ function fetchData(key, ms, data) {
26
+ if (!cache.has(key)) cache.set(key, new Promise((resolve) => setTimeout(() => resolve(data), ms)));
27
+ return cache.get(key);
28
+ }
29
+ function clearCache() {
30
+ cache.clear();
31
+ }
32
+ function UserProfile() {
33
+ const user = use(fetchData("user", 1500, {
34
+ name: "Alice Chen",
35
+ email: "alice@example.com",
36
+ role: "Developer"
37
+ }));
38
+ return /* @__PURE__ */ jsxs(Box, {
39
+ flexDirection: "column",
40
+ borderStyle: "round",
41
+ borderColor: "$success",
42
+ padding: 1,
43
+ children: [
44
+ /* @__PURE__ */ jsx(H1, {
45
+ color: "$success",
46
+ children: "User Profile"
47
+ }),
48
+ /* @__PURE__ */ jsxs(Text, { children: ["Name: ", user.name] }),
49
+ /* @__PURE__ */ jsxs(Text, { children: ["Email: ", user.email] }),
50
+ /* @__PURE__ */ jsxs(Text, { children: ["Role: ", user.role] })
51
+ ]
52
+ });
53
+ }
54
+ function Statistics() {
55
+ const stats = use(fetchData("stats", 2500, {
56
+ projects: 12,
57
+ commits: 847,
58
+ reviews: 156
59
+ }));
60
+ return /* @__PURE__ */ jsxs(Box, {
61
+ flexDirection: "column",
62
+ borderStyle: "round",
63
+ borderColor: "$primary",
64
+ padding: 1,
65
+ children: [
66
+ /* @__PURE__ */ jsx(H1, { children: "Statistics" }),
67
+ /* @__PURE__ */ jsxs(Text, { children: ["Projects: ", stats.projects] }),
68
+ /* @__PURE__ */ jsxs(Text, { children: ["Commits: ", stats.commits] }),
69
+ /* @__PURE__ */ jsxs(Text, { children: ["Reviews: ", stats.reviews] })
70
+ ]
71
+ });
72
+ }
73
+ function RecentActivity() {
74
+ const activities = use(fetchData("activity", 3500, [
75
+ {
76
+ id: 1,
77
+ action: "Merged PR #423",
78
+ time: "2h ago"
79
+ },
80
+ {
81
+ id: 2,
82
+ action: "Reviewed PR #421",
83
+ time: "4h ago"
84
+ },
85
+ {
86
+ id: 3,
87
+ action: "Created issue #89",
88
+ time: "1d ago"
89
+ }
90
+ ]));
91
+ return /* @__PURE__ */ jsxs(Box, {
92
+ flexDirection: "column",
93
+ borderStyle: "round",
94
+ borderColor: "$warning",
95
+ padding: 1,
96
+ children: [/* @__PURE__ */ jsx(H1, {
97
+ color: "$warning",
98
+ children: "Recent Activity"
99
+ }), activities.map((a) => /* @__PURE__ */ jsxs(Text, { children: [
100
+ /* @__PURE__ */ jsx(Text, {
101
+ dim: true,
102
+ children: a.time
103
+ }),
104
+ " ",
105
+ a.action
106
+ ] }, a.id))]
107
+ });
108
+ }
109
+ function LoadingBox({ label }) {
110
+ return /* @__PURE__ */ jsx(Box, {
111
+ borderStyle: "round",
112
+ borderColor: "$border",
113
+ padding: 1,
114
+ children: /* @__PURE__ */ jsxs(Text, {
115
+ color: "$muted",
116
+ children: [
117
+ "Loading ",
118
+ label,
119
+ "..."
120
+ ]
121
+ })
122
+ });
123
+ }
124
+ function AsyncDataApp() {
125
+ const { exit } = useApp();
126
+ const [refreshKey, setRefreshKey] = useState(0);
127
+ useInput((input, key) => {
128
+ if (input === "q" || key.escape) {
129
+ exit();
130
+ return;
131
+ }
132
+ if (input === "r") {
133
+ clearCache();
134
+ setRefreshKey((k) => k + 1);
135
+ }
136
+ });
137
+ return /* @__PURE__ */ jsxs(Box, {
138
+ flexDirection: "column",
139
+ padding: 1,
140
+ children: [/* @__PURE__ */ jsxs(Box, {
141
+ flexGrow: 1,
142
+ flexDirection: "row",
143
+ gap: 1,
144
+ children: [
145
+ /* @__PURE__ */ jsx(ErrorBoundary, {
146
+ fallback: /* @__PURE__ */ jsx(Text, {
147
+ color: "$error",
148
+ children: "User error"
149
+ }),
150
+ children: /* @__PURE__ */ jsx(Suspense, {
151
+ fallback: /* @__PURE__ */ jsx(LoadingBox, { label: "user" }),
152
+ children: /* @__PURE__ */ jsx(UserProfile, {})
153
+ })
154
+ }),
155
+ /* @__PURE__ */ jsx(ErrorBoundary, {
156
+ fallback: /* @__PURE__ */ jsx(Text, {
157
+ color: "$error",
158
+ children: "Stats error"
159
+ }),
160
+ children: /* @__PURE__ */ jsx(Suspense, {
161
+ fallback: /* @__PURE__ */ jsx(LoadingBox, { label: "stats" }),
162
+ children: /* @__PURE__ */ jsx(Statistics, {})
163
+ })
164
+ }),
165
+ /* @__PURE__ */ jsx(ErrorBoundary, {
166
+ fallback: /* @__PURE__ */ jsx(Text, {
167
+ color: "$error",
168
+ children: "Activity error"
169
+ }),
170
+ children: /* @__PURE__ */ jsx(Suspense, {
171
+ fallback: /* @__PURE__ */ jsx(LoadingBox, { label: "activity" }),
172
+ children: /* @__PURE__ */ jsx(RecentActivity, {})
173
+ })
174
+ })
175
+ ]
176
+ }), /* @__PURE__ */ jsxs(Muted, { children: [
177
+ " ",
178
+ /* @__PURE__ */ jsx(Kbd, { children: "r" }),
179
+ " refresh ",
180
+ /* @__PURE__ */ jsx(Kbd, { children: "Esc/q" }),
181
+ " quit"
182
+ ] })]
183
+ }, refreshKey);
184
+ }
185
+ async function main() {
186
+ try {
187
+ var _usingCtx$1 = _usingCtx();
188
+ const term = _usingCtx$1.u(createTerm());
189
+ const { waitUntilExit } = await render(/* @__PURE__ */ jsx(ExampleBanner, {
190
+ meta,
191
+ controls: "r refresh Esc/q quit",
192
+ children: /* @__PURE__ */ jsx(AsyncDataApp, {})
193
+ }), term);
194
+ await waitUntilExit();
195
+ } catch (_) {
196
+ _usingCtx$1.e = _;
197
+ } finally {
198
+ _usingCtx$1.d();
199
+ }
200
+ }
201
+ if (import.meta.main) await main();
202
+ //#endregion
203
+ export { AsyncDataApp, main, meta };
@@ -0,0 +1,338 @@
1
+ import { t as _usingCtx } from "../usingCtx-CsEf0xO3.mjs";
2
+ import { t as ExampleBanner } from "../_banner-A70_y2Vi.mjs";
3
+ import { useCallback, useEffect, useState } from "react";
4
+ import { Box, Code, H1, Kbd, Lead, Muted, ProgressBar, SelectList, Spinner, Text, TextInput, createTerm, render, useApp, useInput } from "silvery";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region apps/cli-wizard.tsx
7
+ /**
8
+ * CLI Wizard Example
9
+ *
10
+ * A multi-step project scaffolding wizard demonstrating:
11
+ * - SelectList for option selection with keyboard navigation
12
+ * - TextInput for free-form text entry
13
+ * - ProgressBar for visual progress feedback
14
+ * - Step-by-step flow with state transitions
15
+ *
16
+ * Usage: bun run examples/apps/cli-wizard.tsx
17
+ *
18
+ * Controls:
19
+ * j/k or Up/Down - Navigate options (step 1)
20
+ * Enter - Confirm selection / submit input
21
+ * Type - Enter project name (step 2)
22
+ * q or Esc - Quit (when not typing)
23
+ */
24
+ const meta = {
25
+ name: "CLI Wizard",
26
+ description: "Multi-step project scaffolding wizard with selection, input, and progress",
27
+ demo: true,
28
+ features: [
29
+ "SelectList",
30
+ "TextInput",
31
+ "ProgressBar",
32
+ "Spinner",
33
+ "useInput()"
34
+ ]
35
+ };
36
+ const FRAMEWORKS = [
37
+ {
38
+ label: "React — A JavaScript library for building user interfaces",
39
+ value: "react"
40
+ },
41
+ {
42
+ label: "Vue — The progressive JavaScript framework",
43
+ value: "vue"
44
+ },
45
+ {
46
+ label: "Svelte — Cybernetically enhanced web apps",
47
+ value: "svelte"
48
+ },
49
+ {
50
+ label: "Solid — Simple and performant reactivity",
51
+ value: "solid"
52
+ },
53
+ {
54
+ label: "Angular — Platform for building web applications",
55
+ value: "angular",
56
+ disabled: true
57
+ }
58
+ ];
59
+ const INSTALL_STEPS = [
60
+ "Resolving dependencies...",
61
+ "Downloading packages...",
62
+ "Linking dependencies...",
63
+ "Building project...",
64
+ "Generating types...",
65
+ "Setting up config...",
66
+ "Done!"
67
+ ];
68
+ /** Step indicator showing current position in the wizard */
69
+ function StepIndicator({ current, total }) {
70
+ return /* @__PURE__ */ jsx(Box, {
71
+ paddingX: 1,
72
+ marginBottom: 1,
73
+ children: Array.from({ length: total }, (_, i) => {
74
+ const isDone = i < current;
75
+ const isCurrent = i === current;
76
+ return /* @__PURE__ */ jsxs(Text, {
77
+ color: isDone ? "$success" : isCurrent ? "$primary" : "$muted",
78
+ bold: isCurrent,
79
+ children: [isDone ? "●" : isCurrent ? "○" : "○", i < total - 1 ? " ─ " : ""]
80
+ }, i);
81
+ })
82
+ });
83
+ }
84
+ /** Step 1: Framework selection */
85
+ function FrameworkStep({ onSelect }) {
86
+ return /* @__PURE__ */ jsxs(Box, {
87
+ flexDirection: "column",
88
+ paddingX: 1,
89
+ children: [
90
+ /* @__PURE__ */ jsx(Box, {
91
+ marginBottom: 1,
92
+ children: /* @__PURE__ */ jsx(H1, { children: "? Select a framework:" })
93
+ }),
94
+ /* @__PURE__ */ jsx(SelectList, {
95
+ items: FRAMEWORKS,
96
+ onSelect
97
+ }),
98
+ /* @__PURE__ */ jsx(Box, {
99
+ marginTop: 1,
100
+ children: /* @__PURE__ */ jsx(Lead, { children: "(Angular is coming soon)" })
101
+ })
102
+ ]
103
+ });
104
+ }
105
+ /** Step 2: Project name input */
106
+ function NameStep({ value, onChange, onSubmit, framework }) {
107
+ return /* @__PURE__ */ jsxs(Box, {
108
+ flexDirection: "column",
109
+ paddingX: 1,
110
+ children: [
111
+ /* @__PURE__ */ jsxs(Box, {
112
+ marginBottom: 1,
113
+ children: [
114
+ /* @__PURE__ */ jsx(H1, { children: "? Project name" }),
115
+ /* @__PURE__ */ jsxs(Muted, { children: [
116
+ " (",
117
+ framework,
118
+ ")"
119
+ ] }),
120
+ /* @__PURE__ */ jsx(H1, { children: ":" })
121
+ ]
122
+ }),
123
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
124
+ color: "$muted",
125
+ children: "❯ "
126
+ }), /* @__PURE__ */ jsx(TextInput, {
127
+ value,
128
+ onChange,
129
+ onSubmit,
130
+ prompt: ""
131
+ })] }),
132
+ /* @__PURE__ */ jsx(Box, {
133
+ marginTop: 1,
134
+ children: /* @__PURE__ */ jsx(Muted, { children: "Press Enter to confirm" })
135
+ })
136
+ ]
137
+ });
138
+ }
139
+ /** Step 3: Installation progress */
140
+ function InstallStep({ progress, stepIndex }) {
141
+ const currentStep = INSTALL_STEPS[Math.min(stepIndex, INSTALL_STEPS.length - 1)];
142
+ return /* @__PURE__ */ jsxs(Box, {
143
+ flexDirection: "column",
144
+ paddingX: 1,
145
+ children: [
146
+ /* @__PURE__ */ jsxs(Box, {
147
+ marginBottom: 1,
148
+ children: [/* @__PURE__ */ jsx(Spinner, { type: "dots" }), /* @__PURE__ */ jsxs(Text, {
149
+ bold: true,
150
+ color: "$warning",
151
+ children: [" ", "Installing dependencies..."]
152
+ })]
153
+ }),
154
+ /* @__PURE__ */ jsx(Box, {
155
+ marginBottom: 1,
156
+ children: /* @__PURE__ */ jsx(ProgressBar, {
157
+ value: progress,
158
+ color: "$primary",
159
+ label: ""
160
+ })
161
+ }),
162
+ /* @__PURE__ */ jsx(Muted, { children: currentStep })
163
+ ]
164
+ });
165
+ }
166
+ /** Step 4: Completion summary */
167
+ function DoneStep({ framework, projectName }) {
168
+ return /* @__PURE__ */ jsxs(Box, {
169
+ flexDirection: "column",
170
+ paddingX: 1,
171
+ children: [
172
+ /* @__PURE__ */ jsx(Box, {
173
+ marginBottom: 1,
174
+ children: /* @__PURE__ */ jsxs(H1, {
175
+ color: "$success",
176
+ children: ["✔", " Project created successfully!"]
177
+ })
178
+ }),
179
+ /* @__PURE__ */ jsxs(Box, {
180
+ flexDirection: "column",
181
+ borderStyle: "round",
182
+ borderColor: "$success",
183
+ paddingX: 2,
184
+ paddingY: 1,
185
+ children: [
186
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Muted, { children: "Framework: " }), /* @__PURE__ */ jsx(Text, {
187
+ bold: true,
188
+ children: framework
189
+ })] }),
190
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Muted, { children: "Project: " }), /* @__PURE__ */ jsx(Text, {
191
+ bold: true,
192
+ children: projectName
193
+ })] }),
194
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Muted, { children: "Location: " }), /* @__PURE__ */ jsxs(Text, {
195
+ bold: true,
196
+ children: [
197
+ "./",
198
+ projectName,
199
+ "/"
200
+ ]
201
+ })] })
202
+ ]
203
+ }),
204
+ /* @__PURE__ */ jsxs(Box, {
205
+ flexDirection: "column",
206
+ marginTop: 1,
207
+ children: [
208
+ /* @__PURE__ */ jsx(Muted, { children: "Get started:" }),
209
+ /* @__PURE__ */ jsxs(Code, { children: [
210
+ " ",
211
+ "cd ",
212
+ projectName
213
+ ] }),
214
+ /* @__PURE__ */ jsxs(Code, { children: [" ", "bun install"] }),
215
+ /* @__PURE__ */ jsxs(Code, { children: [" ", "bun dev"] })
216
+ ]
217
+ }),
218
+ /* @__PURE__ */ jsx(Box, {
219
+ marginTop: 1,
220
+ children: /* @__PURE__ */ jsxs(Muted, { children: [
221
+ "Press ",
222
+ /* @__PURE__ */ jsx(Kbd, { children: "q" }),
223
+ " or ",
224
+ /* @__PURE__ */ jsx(Kbd, { children: "Esc" }),
225
+ " to exit"
226
+ ] })
227
+ })
228
+ ]
229
+ });
230
+ }
231
+ function CliWizard() {
232
+ const { exit } = useApp();
233
+ const [state, setState] = useState({
234
+ step: "framework",
235
+ framework: null,
236
+ projectName: "",
237
+ progress: 0
238
+ });
239
+ const handleFrameworkSelect = useCallback((option) => {
240
+ setState((prev) => ({
241
+ ...prev,
242
+ step: "name",
243
+ framework: option.value,
244
+ projectName: `my-${option.value}-app`
245
+ }));
246
+ }, []);
247
+ const handleNameChange = useCallback((value) => {
248
+ setState((prev) => ({
249
+ ...prev,
250
+ projectName: value
251
+ }));
252
+ }, []);
253
+ const handleNameSubmit = useCallback((value) => {
254
+ if (value.trim()) setState((prev) => ({
255
+ ...prev,
256
+ step: "installing",
257
+ progress: 0
258
+ }));
259
+ }, []);
260
+ useEffect(() => {
261
+ if (state.step !== "installing") return;
262
+ const timer = setInterval(() => {
263
+ setState((prev) => {
264
+ const next = prev.progress + .08 + Math.random() * .04;
265
+ if (next >= 1) {
266
+ clearInterval(timer);
267
+ return {
268
+ ...prev,
269
+ step: "done",
270
+ progress: 1
271
+ };
272
+ }
273
+ return {
274
+ ...prev,
275
+ progress: next
276
+ };
277
+ });
278
+ }, 200);
279
+ return () => clearInterval(timer);
280
+ }, [state.step]);
281
+ useInput((input, key) => {
282
+ if (state.step === "name") return;
283
+ if (input === "q" || key.escape) exit();
284
+ });
285
+ const installStepIndex = Math.floor(state.progress * (INSTALL_STEPS.length - 1));
286
+ const stepNumber = state.step === "framework" ? 0 : state.step === "name" ? 1 : state.step === "installing" ? 2 : 3;
287
+ return /* @__PURE__ */ jsxs(Box, {
288
+ flexDirection: "column",
289
+ flexGrow: 1,
290
+ children: [
291
+ /* @__PURE__ */ jsxs(Box, {
292
+ borderStyle: "single",
293
+ borderColor: "$primary",
294
+ paddingX: 2,
295
+ marginBottom: 1,
296
+ children: [/* @__PURE__ */ jsx(H1, { children: "create-app" }), /* @__PURE__ */ jsx(Muted, { children: " v1.0.0" })]
297
+ }),
298
+ /* @__PURE__ */ jsx(StepIndicator, {
299
+ current: stepNumber,
300
+ total: 4
301
+ }),
302
+ state.step === "framework" && /* @__PURE__ */ jsx(FrameworkStep, { onSelect: handleFrameworkSelect }),
303
+ state.step === "name" && state.framework && /* @__PURE__ */ jsx(NameStep, {
304
+ value: state.projectName,
305
+ onChange: handleNameChange,
306
+ onSubmit: handleNameSubmit,
307
+ framework: state.framework
308
+ }),
309
+ state.step === "installing" && /* @__PURE__ */ jsx(InstallStep, {
310
+ progress: state.progress,
311
+ stepIndex: installStepIndex
312
+ }),
313
+ state.step === "done" && state.framework && /* @__PURE__ */ jsx(DoneStep, {
314
+ framework: state.framework,
315
+ projectName: state.projectName
316
+ })
317
+ ]
318
+ });
319
+ }
320
+ async function main() {
321
+ try {
322
+ var _usingCtx$1 = _usingCtx();
323
+ const term = _usingCtx$1.u(createTerm());
324
+ const { waitUntilExit } = await render(/* @__PURE__ */ jsx(ExampleBanner, {
325
+ meta,
326
+ controls: "j/k navigate Enter select q/Esc quit",
327
+ children: /* @__PURE__ */ jsx(CliWizard, {})
328
+ }), term);
329
+ await waitUntilExit();
330
+ } catch (_) {
331
+ _usingCtx$1.e = _;
332
+ } finally {
333
+ _usingCtx$1.d();
334
+ }
335
+ }
336
+ if (import.meta.main) await main();
337
+ //#endregion
338
+ export { CliWizard, main, meta };