@silvery/examples 0.5.6 → 0.17.4

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