@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
@@ -1,395 +0,0 @@
1
- /**
2
- * Dev Tools — Log Viewer Example
3
- *
4
- * A live log viewer demonstrating:
5
- * - ListView for efficient rendering of thousands of log entries
6
- * - Keyboard shortcuts to add log entries at different severity levels
7
- * - Color-coded severity levels (DEBUG, INFO, WARN, ERROR)
8
- * - j/k navigation through log history
9
- * - Auto-scroll to latest entry
10
- *
11
- * Usage: bun run examples/apps/dev-tools.tsx
12
- *
13
- * Controls:
14
- * j/k or Up/Down - Navigate through log entries
15
- * g/G - Jump to first/last entry
16
- * d - Add DEBUG entry
17
- * i - Add INFO entry
18
- * w - Add WARN entry
19
- * e - Add ERROR entry
20
- * c - Clear all logs
21
- * q or Esc - Quit
22
- */
23
-
24
- import React, { useState, useCallback, useMemo } from "react"
25
- import {
26
- render,
27
- Box,
28
- Text,
29
- ListView,
30
- Divider,
31
- useBoxRect,
32
- useInput,
33
- useApp,
34
- createTerm,
35
- Strong,
36
- Kbd,
37
- Muted,
38
- type Key,
39
- } from "silvery"
40
- import { ExampleBanner, type ExampleMeta } from "../_banner.js"
41
-
42
- export const meta: ExampleMeta = {
43
- name: "Dev Tools",
44
- description: "Log viewer with severity levels, ListView, and keyboard-driven log injection",
45
- features: ["ListView", "useInput()", "useBoxRect()", "keyboard navigation"],
46
- }
47
-
48
- // ============================================================================
49
- // Types
50
- // ============================================================================
51
-
52
- type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR"
53
-
54
- interface LogEntry {
55
- id: number
56
- timestamp: Date
57
- level: LogLevel
58
- source: string
59
- message: string
60
- }
61
-
62
- // ============================================================================
63
- // Data Generation
64
- // ============================================================================
65
-
66
- const SOURCES = ["http", "db", "auth", "cache", "worker", "api", "scheduler", "queue", "metrics", "ws"]
67
-
68
- const LOG_TEMPLATES: Record<LogLevel, string[]> = {
69
- DEBUG: [
70
- "Cache miss for key user:session:{{id}}",
71
- "Query plan: sequential scan on events ({{n}} rows)",
72
- "WebSocket frame received: {{n}} bytes",
73
- "GC pause: {{n}}ms (minor collection)",
74
- "Connection pool stats: {{n}} active, {{n}} idle",
75
- "Route matched: GET /api/v2/resources/{{id}}",
76
- ],
77
- INFO: [
78
- "Request completed: 200 OK ({{n}}ms)",
79
- "User {{id}} authenticated via OAuth",
80
- "Background job processed: email_dispatch #{{id}}",
81
- "Server listening on port {{n}}",
82
- "Database migration applied: v{{n}}",
83
- "Health check passed (latency: {{n}}ms)",
84
- ],
85
- WARN: [
86
- "Slow query detected: {{n}}ms (threshold: 200ms)",
87
- "Rate limit approaching: {{n}}/1000 requests",
88
- "Memory usage: {{n}}% of allocated heap",
89
- "Retry attempt {{n}}/3 for external API call",
90
- "Certificate expires in {{n}} days",
91
- "Connection pool near capacity: {{n}}/100",
92
- ],
93
- ERROR: [
94
- "Unhandled exception in request handler: TypeError",
95
- "Database connection refused: ECONNREFUSED",
96
- "Authentication failed for user {{id}}: invalid token",
97
- "Timeout after {{n}}ms waiting for upstream service",
98
- "Disk usage critical: {{n}}% on /var/data",
99
- "Failed to process message from queue: malformed payload",
100
- ],
101
- }
102
-
103
- let nextLogId = 1
104
-
105
- function seededRandom(seed: number): () => number {
106
- let s = seed
107
- return () => {
108
- s = (s * 1664525 + 1013904223) & 0x7fffffff
109
- return s / 0x7fffffff
110
- }
111
- }
112
-
113
- function generateMessage(level: LogLevel, rng: () => number): string {
114
- const templates = LOG_TEMPLATES[level]
115
- const template = templates[Math.floor(rng() * templates.length)]!
116
- return template
117
- .replace(/\{\{id\}\}/g, () => String(Math.floor(rng() * 99999)))
118
- .replace(/\{\{n\}\}/g, () => String(Math.floor(rng() * 999)))
119
- }
120
-
121
- function createLogEntry(level: LogLevel, rng: () => number): LogEntry {
122
- return {
123
- id: nextLogId++,
124
- timestamp: new Date(),
125
- level,
126
- source: SOURCES[Math.floor(rng() * SOURCES.length)]!,
127
- message: generateMessage(level, rng),
128
- }
129
- }
130
-
131
- function generateInitialLogs(count: number): LogEntry[] {
132
- const rng = seededRandom(42)
133
- const levels: LogLevel[] = ["DEBUG", "INFO", "INFO", "INFO", "WARN", "ERROR"]
134
- const entries: LogEntry[] = []
135
- const now = Date.now()
136
-
137
- for (let i = 0; i < count; i++) {
138
- const level = levels[Math.floor(rng() * levels.length)]!
139
- const entry = createLogEntry(level, rng)
140
- // Spread timestamps over the last hour
141
- entry.timestamp = new Date(now - (count - i) * 1200)
142
- entries.push(entry)
143
- }
144
- return entries
145
- }
146
-
147
- // ============================================================================
148
- // Constants
149
- // ============================================================================
150
-
151
- const LEVEL_COLORS: Record<LogLevel, string> = {
152
- DEBUG: "$muted",
153
- INFO: "$primary",
154
- WARN: "$warning",
155
- ERROR: "$error",
156
- }
157
-
158
- const LEVEL_BADGES: Record<LogLevel, string> = {
159
- DEBUG: "DBG",
160
- INFO: "INF",
161
- WARN: "WRN",
162
- ERROR: "ERR",
163
- }
164
-
165
- // ============================================================================
166
- // Components
167
- // ============================================================================
168
-
169
- function formatTime(date: Date): string {
170
- return date.toLocaleTimeString("en-US", {
171
- hour: "2-digit",
172
- minute: "2-digit",
173
- second: "2-digit",
174
- hour12: false,
175
- })
176
- }
177
-
178
- function LogRow({ entry, isSelected }: { entry: LogEntry; isSelected: boolean }) {
179
- const badge = LEVEL_BADGES[entry.level]
180
- const color = LEVEL_COLORS[entry.level]
181
-
182
- // When selected, use $primary-fg for all text to ensure contrast against $primary bg.
183
- // When not selected, use level-specific colors for visual distinction.
184
- if (isSelected) {
185
- return (
186
- <Box paddingX={1} backgroundColor="$primary">
187
- <Text color="$primary-fg">{formatTime(entry.timestamp)} </Text>
188
- <Text color="$primary-fg" bold>
189
- {badge}
190
- </Text>
191
- <Text color="$primary-fg"> [{entry.source.padEnd(9)}] </Text>
192
- <Text color="$primary-fg" bold>
193
- {entry.message}
194
- </Text>
195
- </Box>
196
- )
197
- }
198
-
199
- return (
200
- <Box paddingX={1}>
201
- <Muted>{formatTime(entry.timestamp)} </Muted>
202
- <Strong color={color}>{badge}</Strong>
203
- <Muted> [{entry.source.padEnd(9)}] </Muted>
204
- <Text>{entry.message}</Text>
205
- </Box>
206
- )
207
- }
208
-
209
- function LevelCounts({ entries }: { entries: LogEntry[] }) {
210
- const counts = useMemo(() => {
211
- const c = { DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0 }
212
- for (const e of entries) c[e.level]++
213
- return c
214
- }, [entries])
215
-
216
- return (
217
- <Box gap={2}>
218
- <Strong color="$muted">
219
- {LEVEL_BADGES.DEBUG}:{counts.DEBUG}
220
- </Strong>
221
- <Strong color="$primary">
222
- {LEVEL_BADGES.INFO}:{counts.INFO}
223
- </Strong>
224
- <Strong color="$warning">
225
- {LEVEL_BADGES.WARN}:{counts.WARN}
226
- </Strong>
227
- <Strong color="$error">
228
- {LEVEL_BADGES.ERROR}:{counts.ERROR}
229
- </Strong>
230
- </Box>
231
- )
232
- }
233
-
234
- /** Inner component that reads the flex container's height via useBoxRect */
235
- function LogListArea({ entries, cursor }: { entries: LogEntry[]; cursor: number }) {
236
- const { height } = useBoxRect()
237
-
238
- return (
239
- <ListView
240
- items={entries}
241
- height={height}
242
- estimateHeight={1}
243
- scrollTo={cursor}
244
- overscan={5}
245
- renderItem={(entry, index) => <LogRow key={entry.id} entry={entry} isSelected={index === cursor} />}
246
- />
247
- )
248
- }
249
-
250
- // ============================================================================
251
- // Main App
252
- // ============================================================================
253
-
254
- const INITIAL_COUNT = 200
255
- const rng = seededRandom(12345)
256
-
257
- export function DevTools() {
258
- const { exit } = useApp()
259
- const [entries, setEntries] = useState<LogEntry[]>(() => generateInitialLogs(INITIAL_COUNT))
260
- const [cursor, setCursor] = useState(INITIAL_COUNT - 1)
261
- const [autoScroll, setAutoScroll] = useState(true)
262
-
263
- const addEntry = useCallback(
264
- (level: LogLevel) => {
265
- const entry = createLogEntry(level, rng)
266
- setEntries((prev) => [...prev, entry])
267
- if (autoScroll) {
268
- setCursor((prev) => prev + 1)
269
- }
270
- },
271
- [autoScroll],
272
- )
273
-
274
- useInput(
275
- useCallback(
276
- (input: string, key: Key) => {
277
- // Quit
278
- if (input === "q" || key.escape) {
279
- exit()
280
- return
281
- }
282
-
283
- // Navigation
284
- if (input === "j" || key.downArrow) {
285
- setCursor((c) => Math.min(entries.length - 1, c + 1))
286
- setAutoScroll(false)
287
- return
288
- }
289
- if (input === "k" || key.upArrow) {
290
- setCursor((c) => Math.max(0, c - 1))
291
- setAutoScroll(false)
292
- return
293
- }
294
-
295
- // Jump to start/end
296
- if (input === "g" || key.home) {
297
- setCursor(0)
298
- setAutoScroll(false)
299
- return
300
- }
301
- if (input === "G" || key.end) {
302
- setCursor(entries.length - 1)
303
- setAutoScroll(true)
304
- return
305
- }
306
-
307
- // Add log entries
308
- if (input === "d") {
309
- addEntry("DEBUG")
310
- return
311
- }
312
- if (input === "i") {
313
- addEntry("INFO")
314
- return
315
- }
316
- if (input === "w") {
317
- addEntry("WARN")
318
- return
319
- }
320
- if (input === "e") {
321
- addEntry("ERROR")
322
- return
323
- }
324
-
325
- // Clear
326
- if (input === "c") {
327
- setEntries([])
328
- setCursor(0)
329
- setAutoScroll(true)
330
- return
331
- }
332
- },
333
- [entries.length, exit, addEntry],
334
- ),
335
- )
336
-
337
- return (
338
- <Box flexDirection="column" flexGrow={1} padding={1}>
339
- {/* Header */}
340
- <Box justifyContent="space-between" backgroundColor="$surfacebg">
341
- <Box gap={2}>
342
- <Text bold color="$primary">
343
- {"▸"} Log Viewer
344
- </Text>
345
- <LevelCounts entries={entries} />
346
- </Box>
347
- <Box gap={1}>
348
- {autoScroll && (
349
- <Text backgroundColor="$success" color="$success-fg" bold>
350
- {" LIVE "}
351
- </Text>
352
- )}
353
- <Strong color="$primary">{cursor + 1}</Strong>
354
- <Muted>/ {entries.length}</Muted>
355
- </Box>
356
- </Box>
357
-
358
- {/* Column headers */}
359
- <Box paddingX={1}>
360
- <Muted>{"Time "} </Muted>
361
- <Muted>{"Lvl"} </Muted>
362
- <Muted>{"[Source ]"} </Muted>
363
- <Muted>Message</Muted>
364
- </Box>
365
-
366
- <Box paddingX={1}>
367
- <Divider />
368
- </Box>
369
-
370
- {/* Log list in a flex-grow container */}
371
- <Box flexGrow={1} flexDirection="column">
372
- <LogListArea entries={entries} cursor={cursor} />
373
- </Box>
374
- </Box>
375
- )
376
- }
377
-
378
- // ============================================================================
379
- // Main
380
- // ============================================================================
381
-
382
- export async function main() {
383
- using term = createTerm()
384
- const { waitUntilExit } = await render(
385
- <ExampleBanner meta={meta} controls="j/k navigate g/G start/end d/i/w/e add log c clear Esc/q quit">
386
- <DevTools />
387
- </ExampleBanner>,
388
- term,
389
- )
390
- await waitUntilExit()
391
- }
392
-
393
- if (import.meta.main) {
394
- await main()
395
- }