@silvery/examples 0.17.3 → 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} +15 -19
  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 +18 -13
  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 -80
  88. package/apps/search-filter.tsx +0 -240
  89. package/apps/selection.tsx +0 -346
  90. package/apps/spatial-focus-demo.tsx +0 -372
  91. package/apps/task-list.tsx +0 -271
  92. package/apps/terminal-caps-demo.tsx +0 -317
  93. package/apps/terminal.tsx +0 -784
  94. package/apps/text-selection-demo.tsx +0 -193
  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 -49
  101. package/components/hello.tsx +0 -38
  102. package/components/progress-bar.tsx +0 -52
  103. package/components/select-list.tsx +0 -54
  104. package/components/spinner.tsx +0 -44
  105. package/components/text-input.tsx +0 -61
  106. package/components/virtual-list.tsx +0 -56
  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,388 @@
1
+ import { t as _usingCtx } from "../usingCtx-CsEf0xO3.mjs";
2
+ import { t as require_jsx_runtime } from "../jsx-runtime-dMs_8fNu.mjs";
3
+ import { useMemo, useState } from "react";
4
+ import { Box, Text } from "silvery";
5
+ import { run, useInput as useInput$1 } from "silvery/runtime";
6
+ //#region apps/spatial-focus-demo.tsx
7
+ /**
8
+ * Spatial Focus Navigation Demo — Kanban Board
9
+ *
10
+ * A kanban board where arrow keys spatially navigate between cards across columns.
11
+ * Uses React state for focus tracking with spatial nearest-neighbor lookup.
12
+ *
13
+ * Cards have varied heights to prove spatial navigation handles non-uniform layouts.
14
+ * Focus is shown via yellow border and bold title on the focused card.
15
+ *
16
+ * Run: bun vendor/silvery/examples/apps/spatial-focus-demo.tsx
17
+ */
18
+ var import_jsx_runtime = require_jsx_runtime();
19
+ const columns = [
20
+ {
21
+ id: "backlog",
22
+ title: "Backlog",
23
+ cards: [
24
+ {
25
+ id: "b1",
26
+ title: "Design system audit",
27
+ tags: ["design"],
28
+ priority: "low"
29
+ },
30
+ {
31
+ id: "b2",
32
+ title: "Refactor auth module",
33
+ description: "Move from JWT to session-based auth.\nUpdate all middleware.\nAdd refresh token rotation.",
34
+ tags: ["backend", "security"],
35
+ priority: "high"
36
+ },
37
+ {
38
+ id: "b3",
39
+ title: "Add dark mode",
40
+ tags: ["frontend"]
41
+ },
42
+ {
43
+ id: "b4",
44
+ title: "Database migration tool",
45
+ description: "Schema versioning with rollback support.",
46
+ tags: ["backend", "devops"],
47
+ priority: "medium"
48
+ },
49
+ {
50
+ id: "b5",
51
+ title: "Update dependencies",
52
+ tags: ["maintenance"]
53
+ }
54
+ ]
55
+ },
56
+ {
57
+ id: "todo",
58
+ title: "To Do",
59
+ cards: [
60
+ {
61
+ id: "t1",
62
+ title: "User dashboard",
63
+ description: "Activity feed, stats overview,\nrecent projects, and quick actions.",
64
+ tags: ["frontend", "ux"],
65
+ priority: "high"
66
+ },
67
+ {
68
+ id: "t2",
69
+ title: "API rate limiting",
70
+ tags: ["backend"],
71
+ priority: "medium"
72
+ },
73
+ {
74
+ id: "t3",
75
+ title: "E2E test suite",
76
+ description: "Cover critical user flows:\n- Login/signup\n- Project CRUD\n- Team management\n- Billing",
77
+ tags: ["testing"],
78
+ priority: "high"
79
+ },
80
+ {
81
+ id: "t4",
82
+ title: "Webhook support",
83
+ tags: ["backend", "api"]
84
+ }
85
+ ]
86
+ },
87
+ {
88
+ id: "progress",
89
+ title: "In Progress",
90
+ cards: [
91
+ {
92
+ id: "p1",
93
+ title: "Search feature",
94
+ description: "Full-text search with filters.",
95
+ tags: ["frontend", "backend"],
96
+ priority: "high"
97
+ },
98
+ {
99
+ id: "p2",
100
+ title: "Fix memory leak",
101
+ tags: ["bug"],
102
+ priority: "high"
103
+ },
104
+ {
105
+ id: "p3",
106
+ title: "CI/CD pipeline",
107
+ description: "GitHub Actions workflow:\n- Lint + typecheck\n- Unit tests\n- E2E tests\n- Deploy to staging",
108
+ tags: ["devops"],
109
+ priority: "medium"
110
+ }
111
+ ]
112
+ },
113
+ {
114
+ id: "done",
115
+ title: "Done",
116
+ cards: [
117
+ {
118
+ id: "d1",
119
+ title: "Project setup",
120
+ tags: ["devops"]
121
+ },
122
+ {
123
+ id: "d2",
124
+ title: "Auth system",
125
+ description: "Login, signup, password reset,\nOAuth providers.",
126
+ tags: ["backend", "security"]
127
+ },
128
+ {
129
+ id: "d3",
130
+ title: "Landing page",
131
+ tags: ["frontend", "design"]
132
+ }
133
+ ]
134
+ }
135
+ ];
136
+ function buildIndex() {
137
+ const index = /* @__PURE__ */ new Map();
138
+ for (let ci = 0; ci < columns.length; ci++) for (let ri = 0; ri < columns[ci].cards.length; ri++) {
139
+ const card = columns[ci].cards[ri];
140
+ index.set(card.id, {
141
+ id: card.id,
142
+ colIndex: ci,
143
+ cardIndex: ri
144
+ });
145
+ }
146
+ return index;
147
+ }
148
+ function navigate(currentId, direction, index) {
149
+ const pos = index.get(currentId);
150
+ if (!pos) return currentId;
151
+ switch (direction) {
152
+ case "up":
153
+ if (pos.cardIndex > 0) return columns[pos.colIndex].cards[pos.cardIndex - 1].id;
154
+ return currentId;
155
+ case "down": {
156
+ const col = columns[pos.colIndex];
157
+ if (pos.cardIndex < col.cards.length - 1) return col.cards[pos.cardIndex + 1].id;
158
+ return currentId;
159
+ }
160
+ case "left":
161
+ if (pos.colIndex > 0) {
162
+ const targetCol = columns[pos.colIndex - 1];
163
+ const targetIdx = Math.min(pos.cardIndex, targetCol.cards.length - 1);
164
+ return targetCol.cards[targetIdx].id;
165
+ }
166
+ return currentId;
167
+ case "right":
168
+ if (pos.colIndex < columns.length - 1) {
169
+ const targetCol = columns[pos.colIndex + 1];
170
+ const targetIdx = Math.min(pos.cardIndex, targetCol.cards.length - 1);
171
+ return targetCol.cards[targetIdx].id;
172
+ }
173
+ return currentId;
174
+ }
175
+ }
176
+ const tagColors = {
177
+ frontend: "$info",
178
+ backend: "$accent",
179
+ design: "$warning",
180
+ devops: "$success",
181
+ testing: "$primary",
182
+ ux: "$muted",
183
+ security: "$error",
184
+ bug: "$error",
185
+ api: "$primary",
186
+ maintenance: "$muted"
187
+ };
188
+ const prioritySymbols = {
189
+ high: {
190
+ symbol: "▲",
191
+ color: "$error"
192
+ },
193
+ medium: {
194
+ symbol: "◆",
195
+ color: "$warning"
196
+ },
197
+ low: {
198
+ symbol: "▽",
199
+ color: "$muted"
200
+ }
201
+ };
202
+ function Tag({ name }) {
203
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
204
+ color: tagColors[name] ?? "$muted",
205
+ dim: true,
206
+ children: ["#", name]
207
+ });
208
+ }
209
+ function CardView({ card, focused }) {
210
+ const priority = card.priority ? prioritySymbols[card.priority] : null;
211
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
212
+ testID: card.id,
213
+ flexDirection: "column",
214
+ borderStyle: "round",
215
+ borderColor: focused ? "$warning" : "$border",
216
+ children: [
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
218
+ paddingX: 1,
219
+ gap: 1,
220
+ children: [priority && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
221
+ color: priority.color,
222
+ children: priority.symbol
223
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
224
+ bold: focused,
225
+ color: focused ? "$warning" : void 0,
226
+ wrap: "truncate",
227
+ children: card.title
228
+ })]
229
+ }),
230
+ card.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
231
+ paddingX: 1,
232
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
233
+ color: "$muted",
234
+ dim: true,
235
+ wrap: "truncate",
236
+ children: card.description
237
+ })
238
+ }),
239
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
240
+ gap: 1,
241
+ paddingX: 1,
242
+ children: card.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag, { name: tag }, tag))
243
+ })
244
+ ]
245
+ });
246
+ }
247
+ function ColumnView({ column, focusedCardId }) {
248
+ const hasFocus = column.cards.some((c) => c.id === focusedCardId);
249
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
250
+ flexDirection: "column",
251
+ flexGrow: 1,
252
+ flexBasis: 0,
253
+ borderStyle: "single",
254
+ borderColor: hasFocus ? "$warning" : "$border",
255
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
256
+ backgroundColor: hasFocus ? "$warning" : void 0,
257
+ paddingX: 1,
258
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
259
+ bold: true,
260
+ color: hasFocus ? "$warning-fg" : void 0,
261
+ children: column.title
262
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
263
+ color: hasFocus ? "$warning-fg" : "$muted",
264
+ children: [
265
+ " (",
266
+ column.cards.length,
267
+ ")"
268
+ ]
269
+ })]
270
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
271
+ flexDirection: "column",
272
+ paddingX: 1,
273
+ flexGrow: 1,
274
+ children: column.cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardView, {
275
+ card,
276
+ focused: card.id === focusedCardId
277
+ }, card.id))
278
+ })]
279
+ });
280
+ }
281
+ function StatusBar({ focusedId }) {
282
+ let focusedColumn = null;
283
+ let focusedCard = null;
284
+ for (const col of columns) {
285
+ const card = col.cards.find((c) => c.id === focusedId);
286
+ if (card) {
287
+ focusedColumn = col.title;
288
+ focusedCard = card;
289
+ break;
290
+ }
291
+ }
292
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
293
+ paddingX: 1,
294
+ gap: 2,
295
+ children: [
296
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
297
+ color: "$muted",
298
+ dim: true,
299
+ children: "←↑↓→/hjkl navigate"
300
+ }),
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
302
+ color: "$muted",
303
+ dim: true,
304
+ children: "q quit"
305
+ }),
306
+ focusedCard && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
308
+ color: "$border",
309
+ children: "│"
310
+ }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
312
+ color: "$warning",
313
+ children: focusedColumn
314
+ }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
316
+ color: "$muted",
317
+ children: "→"
318
+ }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: focusedCard.title })
320
+ ] })
321
+ ]
322
+ });
323
+ }
324
+ function SpatialFocusBoard() {
325
+ const [focusedId, setFocusedId] = useState("b1");
326
+ const index = useMemo(() => buildIndex(), []);
327
+ useInput$1((input, key) => {
328
+ if (input === "q") return "exit";
329
+ const hasArrow = key.upArrow || key.downArrow || key.leftArrow || key.rightArrow;
330
+ const dir = key.upArrow ? "up" : key.downArrow ? "down" : key.leftArrow ? "left" : key.rightArrow ? "right" : !hasArrow && input === "k" ? "up" : !hasArrow && input === "j" ? "down" : !hasArrow && input === "h" ? "left" : !hasArrow && input === "l" ? "right" : null;
331
+ if (dir) setFocusedId((id) => navigate(id, dir, index));
332
+ });
333
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
334
+ flexDirection: "column",
335
+ padding: 1,
336
+ height: "100%",
337
+ children: [
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
339
+ marginBottom: 1,
340
+ paddingX: 1,
341
+ gap: 1,
342
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
343
+ bold: true,
344
+ color: "$warning",
345
+ children: "Spatial Focus"
346
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
347
+ color: "$muted",
348
+ children: "— arrow keys / hjkl navigate between cards across columns"
349
+ })]
350
+ }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
352
+ flexGrow: 1,
353
+ flexDirection: "row",
354
+ gap: 1,
355
+ overflow: "hidden",
356
+ children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ColumnView, {
357
+ column,
358
+ focusedCardId: focusedId
359
+ }, column.id))
360
+ }),
361
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, { focusedId })
362
+ ]
363
+ });
364
+ }
365
+ const meta = {
366
+ name: "Spatial Focus",
367
+ description: "Kanban board with spatial navigation — arrow keys / hjkl move between cards across columns",
368
+ demo: true,
369
+ features: [
370
+ "spatial navigation",
371
+ "kanban layout",
372
+ "varied card heights",
373
+ "column focus tracking"
374
+ ]
375
+ };
376
+ async function main() {
377
+ try {
378
+ var _usingCtx$1 = _usingCtx();
379
+ await _usingCtx$1.u(await run(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpatialFocusBoard, {}), { mode: "fullscreen" })).waitUntilExit();
380
+ } catch (_) {
381
+ _usingCtx$1.e = _;
382
+ } finally {
383
+ _usingCtx$1.d();
384
+ }
385
+ }
386
+ if (import.meta.main) await main();
387
+ //#endregion
388
+ export { main, meta };
@@ -0,0 +1,258 @@
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 { useMemo, useState } from "react";
5
+ import { Box, Kbd, Muted, Text, createTerm, render, useApp, useInput } from "silvery";
6
+ //#region apps/task-list.tsx
7
+ /**
8
+ * Task List Example
9
+ *
10
+ * A scrollable task list demonstrating:
11
+ * - 50+ items for scrolling demonstration
12
+ * - overflow="hidden" with manual scroll state
13
+ * - Toggle task completion with space
14
+ * - Variable height items (some with subtasks)
15
+ */
16
+ var import_jsx_runtime = require_jsx_runtime();
17
+ const meta = {
18
+ name: "Task List",
19
+ description: "Scrollable list with priority badges, toggles, and expandable subtasks",
20
+ features: [
21
+ "ListView",
22
+ "variable estimateHeight",
23
+ "Box overflow"
24
+ ]
25
+ };
26
+ function generateTasks(count) {
27
+ const priorities = [
28
+ "high",
29
+ "medium",
30
+ "low"
31
+ ];
32
+ const taskTemplates = [
33
+ "Review pull request",
34
+ "Update documentation",
35
+ "Fix bug in authentication",
36
+ "Implement new feature",
37
+ "Write unit tests",
38
+ "Refactor legacy code",
39
+ "Update dependencies",
40
+ "Create API endpoint",
41
+ "Design database schema",
42
+ "Optimize performance",
43
+ "Add error handling",
44
+ "Setup CI/CD pipeline",
45
+ "Write integration tests",
46
+ "Code review feedback",
47
+ "Deploy to staging"
48
+ ];
49
+ const subtaskTemplates = [
50
+ [
51
+ "Research solutions",
52
+ "Implement changes",
53
+ "Test thoroughly"
54
+ ],
55
+ ["Check requirements", "Update code"],
56
+ [
57
+ "Review with team",
58
+ "Make adjustments",
59
+ "Get approval",
60
+ "Merge"
61
+ ]
62
+ ];
63
+ return Array.from({ length: count }, (_, i) => ({
64
+ id: i + 1,
65
+ title: `${taskTemplates[i % taskTemplates.length]} #${Math.floor(i / taskTemplates.length) + 1}`,
66
+ completed: Math.random() > .7,
67
+ priority: priorities[i % 3],
68
+ subtasks: i % 5 === 0 ? subtaskTemplates[i % subtaskTemplates.length] : void 0
69
+ }));
70
+ }
71
+ function PriorityBadge({ priority }) {
72
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
73
+ color: {
74
+ high: "$error",
75
+ medium: "$warning",
76
+ low: "$success"
77
+ }[priority],
78
+ bold: true,
79
+ children: [
80
+ "[",
81
+ {
82
+ high: "!!!",
83
+ medium: "!!",
84
+ low: "!"
85
+ }[priority],
86
+ "]"
87
+ ]
88
+ });
89
+ }
90
+ function TaskItem({ task, isSelected, isExpanded }) {
91
+ const checkbox = task.completed ? "[x]" : "[ ]";
92
+ const hasSubtasks = task.subtasks && task.subtasks.length > 0;
93
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
94
+ flexDirection: "column",
95
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, { children: [
96
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
97
+ backgroundColor: "$primary",
98
+ color: "$primary-fg",
99
+ children: [
100
+ " ",
101
+ checkbox,
102
+ " ",
103
+ task.title,
104
+ " "
105
+ ]
106
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
107
+ strikethrough: task.completed,
108
+ dim: task.completed,
109
+ children: [
110
+ checkbox,
111
+ " ",
112
+ task.title
113
+ ]
114
+ }),
115
+ " ",
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PriorityBadge, { priority: task.priority }),
117
+ hasSubtasks && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
118
+ dim: true,
119
+ children: [
120
+ " (",
121
+ task.subtasks.length,
122
+ " subtasks)"
123
+ ]
124
+ })
125
+ ] }), hasSubtasks && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
126
+ flexDirection: "column",
127
+ marginLeft: 4,
128
+ children: task.subtasks.map((subtask, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
129
+ dim: true,
130
+ children: ["- ", subtask]
131
+ }, idx))
132
+ })]
133
+ });
134
+ }
135
+ function StatusBar({ tasks, cursor, scrollOffset, visibleCount }) {
136
+ const completed = tasks.filter((t) => t.completed).length;
137
+ const total = tasks.length;
138
+ const percent = Math.round(completed / total * 100);
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
140
+ justifyContent: "space-between",
141
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Muted, { children: [
142
+ " ",
143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: "j/k" }),
144
+ " navigate ",
145
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: "space" }),
146
+ " toggle ",
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: "enter" }),
148
+ " expand ",
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: "Esc/q" }),
150
+ " quit"
151
+ ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Muted, { children: [
152
+ " ",
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
154
+ bold: true,
155
+ children: completed
156
+ }),
157
+ "/",
158
+ total,
159
+ " (",
160
+ percent,
161
+ "%) | ",
162
+ cursor + 1,
163
+ "/",
164
+ total,
165
+ " "
166
+ ] })]
167
+ });
168
+ }
169
+ function TaskList() {
170
+ const { exit } = useApp();
171
+ const [tasks, setTasks] = useState(() => generateTasks(60));
172
+ const [cursor, setCursor] = useState(0);
173
+ const [expandedTasks, setExpandedTasks] = useState(/* @__PURE__ */ new Set());
174
+ const visibleCount = 15;
175
+ const scrollOffset = useMemo(() => {
176
+ const halfVisible = Math.floor(visibleCount / 2);
177
+ const maxOffset = Math.max(0, tasks.length - visibleCount);
178
+ let offset = cursor - halfVisible;
179
+ offset = Math.max(0, Math.min(offset, maxOffset));
180
+ return offset;
181
+ }, [
182
+ cursor,
183
+ visibleCount,
184
+ tasks.length
185
+ ]);
186
+ const visibleTasks = useMemo(() => {
187
+ return tasks.slice(scrollOffset, scrollOffset + visibleCount);
188
+ }, [
189
+ tasks,
190
+ scrollOffset,
191
+ visibleCount
192
+ ]);
193
+ useInput((input, key) => {
194
+ if (input === "q" || key.escape) exit();
195
+ if (key.upArrow || input === "k") setCursor((prev) => Math.max(0, prev - 1));
196
+ if (key.downArrow || input === "j") setCursor((prev) => Math.min(tasks.length - 1, prev + 1));
197
+ if (key.pageUp) setCursor((prev) => Math.max(0, prev - visibleCount));
198
+ if (key.pageDown) setCursor((prev) => Math.min(tasks.length - 1, prev + visibleCount));
199
+ if (key.home) setCursor(0);
200
+ if (key.end) setCursor(tasks.length - 1);
201
+ if (input === " ") setTasks((prev) => prev.map((task, idx) => idx === cursor ? {
202
+ ...task,
203
+ completed: !task.completed
204
+ } : task));
205
+ if (key.return || input === "e") {
206
+ const taskId = tasks[cursor]?.id;
207
+ if (taskId !== void 0 && tasks[cursor]?.subtasks) setExpandedTasks((prev) => {
208
+ const next = new Set(prev);
209
+ if (next.has(taskId)) next.delete(taskId);
210
+ else next.add(taskId);
211
+ return next;
212
+ });
213
+ }
214
+ });
215
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
216
+ flexDirection: "column",
217
+ padding: 1,
218
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
219
+ flexGrow: 1,
220
+ flexDirection: "column",
221
+ borderStyle: "round",
222
+ borderColor: "$border",
223
+ overflow: "hidden",
224
+ height: visibleCount + 2,
225
+ children: visibleTasks.map((task, visibleIndex) => {
226
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskItem, {
227
+ task,
228
+ isSelected: scrollOffset + visibleIndex === cursor,
229
+ isExpanded: expandedTasks.has(task.id)
230
+ }, task.id);
231
+ })
232
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, {
233
+ tasks,
234
+ cursor,
235
+ scrollOffset,
236
+ visibleCount
237
+ })]
238
+ });
239
+ }
240
+ async function main() {
241
+ try {
242
+ var _usingCtx$1 = _usingCtx();
243
+ const term = _usingCtx$1.u(createTerm());
244
+ const { waitUntilExit } = await render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExampleBanner, {
245
+ meta,
246
+ controls: "j/k navigate space toggle enter expand Esc/q quit",
247
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskList, {})
248
+ }), term);
249
+ await waitUntilExit();
250
+ } catch (_) {
251
+ _usingCtx$1.e = _;
252
+ } finally {
253
+ _usingCtx$1.d();
254
+ }
255
+ }
256
+ if (import.meta.main) await main();
257
+ //#endregion
258
+ export { TaskList, main, meta };