silvery 0.3.0 → 0.4.1

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 (120) hide show
  1. package/README.md +41 -145
  2. package/dist/chalk.js +3 -0
  3. package/dist/chalk.js.map +11 -0
  4. package/dist/index.js +340 -0
  5. package/dist/index.js.map +282 -0
  6. package/dist/ink.js +129 -0
  7. package/dist/ink.js.map +140 -0
  8. package/dist/runtime.js +394 -0
  9. package/dist/runtime.js.map +286 -0
  10. package/dist/theme.js +343 -0
  11. package/dist/theme.js.map +286 -0
  12. package/dist/ui/animation.js +3 -0
  13. package/dist/ui/animation.js.map +15 -0
  14. package/dist/ui/ansi.js +3 -0
  15. package/dist/ui/ansi.js.map +10 -0
  16. package/dist/ui/cli.js +8 -0
  17. package/dist/ui/cli.js.map +14 -0
  18. package/dist/ui/display.js +4 -0
  19. package/dist/ui/display.js.map +10 -0
  20. package/dist/ui/image.js +4 -0
  21. package/dist/ui/image.js.map +15 -0
  22. package/dist/ui/input.js +3 -0
  23. package/dist/ui/input.js.map +11 -0
  24. package/dist/ui/progress.js +8 -0
  25. package/dist/ui/progress.js.map +20 -0
  26. package/dist/ui/react.js +3 -0
  27. package/dist/ui/react.js.map +15 -0
  28. package/dist/ui/utils.js +3 -0
  29. package/dist/ui/utils.js.map +10 -0
  30. package/dist/ui/wrappers.js +14 -0
  31. package/dist/ui/wrappers.js.map +19 -0
  32. package/dist/ui.js +17 -0
  33. package/dist/ui.js.map +20 -0
  34. package/package.json +67 -15
  35. package/src/index.ts +67 -1
  36. package/src/runtime.ts +4 -0
  37. package/src/theme.ts +4 -0
  38. package/src/ui/animation.ts +2 -0
  39. package/src/ui/ansi.ts +2 -0
  40. package/src/ui/cli.ts +2 -0
  41. package/src/ui/display.ts +2 -0
  42. package/src/ui/image.ts +2 -0
  43. package/src/ui/input.ts +2 -0
  44. package/src/ui/progress.ts +2 -0
  45. package/src/ui/react.ts +2 -0
  46. package/src/ui/utils.ts +2 -0
  47. package/src/ui/wrappers.ts +2 -0
  48. package/src/ui.ts +4 -0
  49. package/examples/CLAUDE.md +0 -75
  50. package/examples/_banner.tsx +0 -60
  51. package/examples/cli.ts +0 -228
  52. package/examples/index.md +0 -101
  53. package/examples/inline/inline-nontty.tsx +0 -98
  54. package/examples/inline/inline-progress.tsx +0 -79
  55. package/examples/inline/inline-simple.tsx +0 -63
  56. package/examples/inline/scrollback.tsx +0 -185
  57. package/examples/interactive/_input-debug.tsx +0 -110
  58. package/examples/interactive/_stdin-test.ts +0 -71
  59. package/examples/interactive/_textarea-bare.tsx +0 -45
  60. package/examples/interactive/aichat/components.tsx +0 -468
  61. package/examples/interactive/aichat/index.tsx +0 -207
  62. package/examples/interactive/aichat/script.ts +0 -460
  63. package/examples/interactive/aichat/state.ts +0 -326
  64. package/examples/interactive/aichat/types.ts +0 -19
  65. package/examples/interactive/app-todo.tsx +0 -198
  66. package/examples/interactive/async-data.tsx +0 -208
  67. package/examples/interactive/cli-wizard.tsx +0 -332
  68. package/examples/interactive/clipboard.tsx +0 -183
  69. package/examples/interactive/components.tsx +0 -463
  70. package/examples/interactive/data-explorer.tsx +0 -506
  71. package/examples/interactive/dev-tools.tsx +0 -379
  72. package/examples/interactive/explorer.tsx +0 -747
  73. package/examples/interactive/gallery.tsx +0 -652
  74. package/examples/interactive/inline-bench.tsx +0 -136
  75. package/examples/interactive/kanban.tsx +0 -267
  76. package/examples/interactive/layout-ref.tsx +0 -185
  77. package/examples/interactive/outline.tsx +0 -171
  78. package/examples/interactive/paste-demo.tsx +0 -198
  79. package/examples/interactive/scroll.tsx +0 -77
  80. package/examples/interactive/search-filter.tsx +0 -240
  81. package/examples/interactive/task-list.tsx +0 -279
  82. package/examples/interactive/terminal.tsx +0 -798
  83. package/examples/interactive/textarea.tsx +0 -103
  84. package/examples/interactive/theme.tsx +0 -336
  85. package/examples/interactive/transform.tsx +0 -256
  86. package/examples/interactive/virtual-10k.tsx +0 -413
  87. package/examples/kitty/canvas.tsx +0 -519
  88. package/examples/kitty/generate-samples.ts +0 -236
  89. package/examples/kitty/image-component.tsx +0 -273
  90. package/examples/kitty/images.tsx +0 -604
  91. package/examples/kitty/input.tsx +0 -371
  92. package/examples/kitty/keys.tsx +0 -378
  93. package/examples/kitty/paint.tsx +0 -1017
  94. package/examples/layout/dashboard.tsx +0 -551
  95. package/examples/layout/live-resize.tsx +0 -290
  96. package/examples/layout/overflow.tsx +0 -51
  97. package/examples/playground/README.md +0 -69
  98. package/examples/playground/build.ts +0 -61
  99. package/examples/playground/index.html +0 -420
  100. package/examples/playground/playground-app.tsx +0 -416
  101. package/examples/runtime/elm-counter.tsx +0 -206
  102. package/examples/runtime/hello-runtime.tsx +0 -73
  103. package/examples/runtime/pipe-composition.tsx +0 -184
  104. package/examples/runtime/run-counter.tsx +0 -78
  105. package/examples/runtime/runtime-counter.tsx +0 -197
  106. package/examples/screenshots/generate.tsx +0 -563
  107. package/examples/scrollback-perf.tsx +0 -230
  108. package/examples/viewer.tsx +0 -654
  109. package/examples/web/build.ts +0 -365
  110. package/examples/web/canvas-app.tsx +0 -80
  111. package/examples/web/canvas.html +0 -89
  112. package/examples/web/dom-app.tsx +0 -81
  113. package/examples/web/dom.html +0 -113
  114. package/examples/web/showcase-app.tsx +0 -107
  115. package/examples/web/showcase.html +0 -34
  116. package/examples/web/showcases/index.tsx +0 -56
  117. package/examples/web/viewer-app.tsx +0 -555
  118. package/examples/web/viewer.html +0 -30
  119. package/examples/web/xterm-app.tsx +0 -105
  120. package/examples/web/xterm.html +0 -118
@@ -1,279 +0,0 @@
1
- /**
2
- * Task List Example
3
- *
4
- * A scrollable task list demonstrating:
5
- * - 50+ items for scrolling demonstration
6
- * - overflow="hidden" with manual scroll state
7
- * - Toggle task completion with space
8
- * - Variable height items (some with subtasks)
9
- */
10
-
11
- import React, { useState, useMemo } from "react"
12
- import { render, Box, Text, Kbd, Muted, useInput, useApp, createTerm, type Key } from "../../src/index.js"
13
- import { ExampleBanner, type ExampleMeta } from "../_banner.js"
14
-
15
- export const meta: ExampleMeta = {
16
- name: "Task List",
17
- description: "Scrollable list with priority badges, toggles, and expandable subtasks",
18
- features: ["VirtualList", "variable itemHeight", "Box overflow"],
19
- }
20
-
21
- // ============================================================================
22
- // Types
23
- // ============================================================================
24
-
25
- interface Task {
26
- id: number
27
- title: string
28
- completed: boolean
29
- priority: "high" | "medium" | "low"
30
- subtasks?: string[]
31
- }
32
-
33
- // ============================================================================
34
- // Data Generation
35
- // ============================================================================
36
-
37
- function generateTasks(count: number): Task[] {
38
- const priorities: Array<"high" | "medium" | "low"> = ["high", "medium", "low"]
39
- const taskTemplates = [
40
- "Review pull request",
41
- "Update documentation",
42
- "Fix bug in authentication",
43
- "Implement new feature",
44
- "Write unit tests",
45
- "Refactor legacy code",
46
- "Update dependencies",
47
- "Create API endpoint",
48
- "Design database schema",
49
- "Optimize performance",
50
- "Add error handling",
51
- "Setup CI/CD pipeline",
52
- "Write integration tests",
53
- "Code review feedback",
54
- "Deploy to staging",
55
- ]
56
-
57
- const subtaskTemplates = [
58
- ["Research solutions", "Implement changes", "Test thoroughly"],
59
- ["Check requirements", "Update code"],
60
- ["Review with team", "Make adjustments", "Get approval", "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() > 0.7,
67
- priority: priorities[i % 3] as "high" | "medium" | "low",
68
- // Every 5th task has subtasks
69
- subtasks: i % 5 === 0 ? subtaskTemplates[i % subtaskTemplates.length] : undefined,
70
- }))
71
- }
72
-
73
- // ============================================================================
74
- // Components
75
- // ============================================================================
76
-
77
- function PriorityBadge({ priority }: { priority: "high" | "medium" | "low" }): JSX.Element {
78
- const colors = {
79
- high: "$error",
80
- medium: "$warning",
81
- low: "$success",
82
- }
83
- const symbols = {
84
- high: "!!!",
85
- medium: "!!",
86
- low: "!",
87
- }
88
-
89
- return (
90
- <Text color={colors[priority]} bold>
91
- [{symbols[priority]}]
92
- </Text>
93
- )
94
- }
95
-
96
- function TaskItem({
97
- task,
98
- isSelected,
99
- isExpanded,
100
- }: {
101
- task: Task
102
- isSelected: boolean
103
- isExpanded: boolean
104
- }): JSX.Element {
105
- const checkbox = task.completed ? "[x]" : "[ ]"
106
- const hasSubtasks = task.subtasks && task.subtasks.length > 0
107
-
108
- return (
109
- <Box flexDirection="column">
110
- <Box>
111
- {isSelected ? (
112
- <Text backgroundColor="$primary" color="black">
113
- {" "}
114
- {checkbox} {task.title}{" "}
115
- </Text>
116
- ) : (
117
- <Text strikethrough={task.completed} dim={task.completed}>
118
- {checkbox} {task.title}
119
- </Text>
120
- )}{" "}
121
- <PriorityBadge priority={task.priority} />
122
- {hasSubtasks && <Text dim> ({task.subtasks!.length} subtasks)</Text>}
123
- </Box>
124
- {hasSubtasks && isExpanded && (
125
- <Box flexDirection="column" marginLeft={4}>
126
- {task.subtasks!.map((subtask, idx) => (
127
- <Text key={idx} dim>
128
- - {subtask}
129
- </Text>
130
- ))}
131
- </Box>
132
- )}
133
- </Box>
134
- )
135
- }
136
-
137
- function StatusBar({
138
- tasks,
139
- cursor,
140
- scrollOffset,
141
- visibleCount,
142
- }: {
143
- tasks: Task[]
144
- cursor: number
145
- scrollOffset: number
146
- visibleCount: number
147
- }): JSX.Element {
148
- const completed = tasks.filter((t) => t.completed).length
149
- const total = tasks.length
150
- const percent = Math.round((completed / total) * 100)
151
-
152
- return (
153
- <Box justifyContent="space-between">
154
- <Muted>
155
- {" "}
156
- <Kbd>j/k</Kbd> navigate <Kbd>space</Kbd> toggle <Kbd>enter</Kbd> expand <Kbd>Esc/q</Kbd> quit
157
- </Muted>
158
- <Muted>
159
- {" "}
160
- <Text bold>{completed}</Text>/{total} ({percent}%) | {cursor + 1}/{total}{" "}
161
- </Muted>
162
- </Box>
163
- )
164
- }
165
-
166
- export function TaskList(): JSX.Element {
167
- const { exit } = useApp()
168
- const [tasks, setTasks] = useState(() => generateTasks(60))
169
- const [cursor, setCursor] = useState(0)
170
- const [expandedTasks, setExpandedTasks] = useState<Set<number>>(new Set())
171
-
172
- // Fixed visible count (in a real app, this would use useContentRect)
173
- const visibleCount = 15
174
-
175
- // Calculate scroll offset to keep cursor visible
176
- const scrollOffset = useMemo(() => {
177
- const halfVisible = Math.floor(visibleCount / 2)
178
- const maxOffset = Math.max(0, tasks.length - visibleCount)
179
-
180
- // Keep cursor centered when possible
181
- let offset = cursor - halfVisible
182
- offset = Math.max(0, Math.min(offset, maxOffset))
183
- return offset
184
- }, [cursor, visibleCount, tasks.length])
185
-
186
- // Get visible tasks
187
- const visibleTasks = useMemo(() => {
188
- return tasks.slice(scrollOffset, scrollOffset + visibleCount)
189
- }, [tasks, scrollOffset, visibleCount])
190
-
191
- useInput((input: string, key: Key) => {
192
- if (input === "q" || key.escape) {
193
- exit()
194
- }
195
- if (key.upArrow || input === "k") {
196
- setCursor((prev) => Math.max(0, prev - 1))
197
- }
198
- if (key.downArrow || input === "j") {
199
- setCursor((prev) => Math.min(tasks.length - 1, prev + 1))
200
- }
201
- if (key.pageUp) {
202
- setCursor((prev) => Math.max(0, prev - visibleCount))
203
- }
204
- if (key.pageDown) {
205
- setCursor((prev) => Math.min(tasks.length - 1, prev + visibleCount))
206
- }
207
- if (key.home) {
208
- setCursor(0)
209
- }
210
- if (key.end) {
211
- setCursor(tasks.length - 1)
212
- }
213
- if (input === " ") {
214
- // Toggle completion
215
- setTasks((prev) => prev.map((task, idx) => (idx === cursor ? { ...task, completed: !task.completed } : task)))
216
- }
217
- if (key.return || input === "e") {
218
- // Toggle expand/collapse subtasks
219
- const taskId = tasks[cursor]?.id
220
- if (taskId !== undefined && tasks[cursor]?.subtasks) {
221
- setExpandedTasks((prev) => {
222
- const next = new Set(prev)
223
- if (next.has(taskId)) {
224
- next.delete(taskId)
225
- } else {
226
- next.add(taskId)
227
- }
228
- return next
229
- })
230
- }
231
- }
232
- })
233
-
234
- return (
235
- <Box flexDirection="column" padding={1}>
236
- <Box
237
- flexGrow={1}
238
- flexDirection="column"
239
- borderStyle="round"
240
- borderColor="$border"
241
- overflow="hidden"
242
- height={visibleCount + 2}
243
- >
244
- {visibleTasks.map((task, visibleIndex) => {
245
- const actualIndex = scrollOffset + visibleIndex
246
- return (
247
- <TaskItem
248
- key={task.id}
249
- task={task}
250
- isSelected={actualIndex === cursor}
251
- isExpanded={expandedTasks.has(task.id)}
252
- />
253
- )
254
- })}
255
- </Box>
256
-
257
- <StatusBar tasks={tasks} cursor={cursor} scrollOffset={scrollOffset} visibleCount={visibleCount} />
258
- </Box>
259
- )
260
- }
261
-
262
- // ============================================================================
263
- // Main
264
- // ============================================================================
265
-
266
- async function main() {
267
- using term = createTerm()
268
- const { waitUntilExit } = await render(
269
- <ExampleBanner meta={meta} controls="j/k navigate space toggle enter expand Esc/q quit">
270
- <TaskList />
271
- </ExampleBanner>,
272
- term,
273
- )
274
- await waitUntilExit()
275
- }
276
-
277
- if (import.meta.main) {
278
- main().catch(console.error)
279
- }