@gridland/demo 0.2.12 → 0.2.15

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.
package/dist/run.js CHANGED
@@ -1,1576 +1,32 @@
1
+ import {
2
+ ChatPanel,
3
+ GRADIENTS,
4
+ Gradient,
5
+ LandingApp,
6
+ LinkDemo,
7
+ Message,
8
+ Modal,
9
+ MultiSelect,
10
+ PromptInput,
11
+ SelectInput,
12
+ SpinnerPicker,
13
+ StatusBar,
14
+ TabBar,
15
+ Table,
16
+ TextInput,
17
+ Timeline,
18
+ textStyle
19
+ } from "./chunk-R3ENBVV6.js";
20
+
1
21
  // src/run.tsx
2
22
  import { createCliRenderer } from "@opentui/core";
3
23
  import { createRoot, useKeyboard as useKeyboard2 } from "@opentui/react";
4
24
 
5
25
  // ../ui/scripts/demo-apps.tsx
6
- import { useState as useState9, useCallback as useCallback2, useRef as useRef6 } from "react";
26
+ import { useState, useCallback, useRef, useEffect } from "react";
7
27
  import { useKeyboard } from "@opentui/react";
8
-
9
- // ../ui/components/link/link.tsx
10
- import { jsx } from "react/jsx-runtime";
11
- var UNDERLINE = 1 << 3;
12
- var UNDERLINE_DASHED = 1 << 4;
13
- var UNDERLINE_DOTTED = 1 << 6;
14
- function Link({ children, url, underline = "solid" }) {
15
- let attributes = 0;
16
- if (underline === "solid") {
17
- attributes = UNDERLINE;
18
- } else if (underline === "dashed") {
19
- attributes = UNDERLINE | UNDERLINE_DASHED;
20
- } else if (underline === "dotted") {
21
- attributes = UNDERLINE | UNDERLINE_DOTTED;
22
- }
23
- return /* @__PURE__ */ jsx("text", { children: /* @__PURE__ */ jsx("a", { href: url, style: { attributes }, children }) });
24
- }
25
-
26
- // ../ui/components/link/link-demo.tsx
27
- import { useState } from "react";
28
-
29
- // ../ui/components/text-style.ts
30
- var BOLD = 1 << 0;
31
- var DIM = 1 << 1;
32
- var ITALIC = 1 << 2;
33
- var UNDERLINE2 = 1 << 3;
34
- var INVERSE = 1 << 5;
35
- function textStyle(opts) {
36
- let attributes = 0;
37
- if (opts.bold) attributes |= BOLD;
38
- if (opts.dim) attributes |= DIM;
39
- if (opts.italic) attributes |= ITALIC;
40
- if (opts.underline) attributes |= UNDERLINE2;
41
- if (opts.inverse) attributes |= INVERSE;
42
- return {
43
- ...opts.fg ? { fg: opts.fg } : {},
44
- ...opts.bg ? { bg: opts.bg } : {},
45
- ...attributes ? { attributes } : {}
46
- };
47
- }
48
-
49
- // ../ui/components/status-bar/status-bar.tsx
50
- import { jsx as jsx2 } from "react/jsx-runtime";
51
- function StatusBar({ items, extra }) {
52
- const parts = [];
53
- if (extra !== void 0) {
54
- parts.push(
55
- /* @__PURE__ */ jsx2("span", { children: extra }, "extra")
56
- );
57
- parts.push(
58
- /* @__PURE__ */ jsx2("span", { style: textStyle({ dim: true }), children: " \u2502 " }, "pipe")
59
- );
60
- }
61
- items.forEach((item, i) => {
62
- if (i > 0) {
63
- parts.push(/* @__PURE__ */ jsx2("span", { children: " " }, `gap-${i}`));
64
- }
65
- parts.push(
66
- /* @__PURE__ */ jsx2("span", { style: textStyle({ inverse: true, bold: true }), children: ` ${item.key} ` }, `key-${i}`)
67
- );
68
- parts.push(
69
- /* @__PURE__ */ jsx2("span", { style: textStyle({ dim: true }), children: ` ${item.label}` }, `label-${i}`)
70
- );
71
- });
72
- if (parts.length === 0) {
73
- return null;
74
- }
75
- return /* @__PURE__ */ jsx2("text", { children: parts });
76
- }
77
-
78
- // ../ui/components/link/link-demo.tsx
79
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
80
- var MODES = ["solid", "dashed", "dotted", "none"];
81
- function LinkDemo({
82
- url = "https://opentui.com",
83
- label = "Visit opentui.com",
84
- useKeyboard: useKeyboard3
85
- }) {
86
- const [modeIndex, setModeIndex] = useState(0);
87
- const mode = MODES[modeIndex];
88
- useKeyboard3?.((event) => {
89
- if (event.name === "right") {
90
- setModeIndex((i) => (i + 1) % MODES.length);
91
- } else if (event.name === "left") {
92
- setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
93
- }
94
- });
95
- return /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, children: [
96
- /* @__PURE__ */ jsx3(Link, { url, underline: mode, children: label }),
97
- /* @__PURE__ */ jsx3(
98
- StatusBar,
99
- {
100
- extra: /* @__PURE__ */ jsx3("span", { style: textStyle({ bold: true }), children: mode.padEnd(6) }),
101
- items: [
102
- { key: "\u2190\u2192", label: "underline style" }
103
- ]
104
- }
105
- )
106
- ] });
107
- }
108
-
109
- // ../ui/components/ascii/ascii.tsx
110
- import { jsx as jsx4 } from "react/jsx-runtime";
111
-
112
- // ../ui/components/spinner/spinner.tsx
113
- import { useEffect, useState as useState2 } from "react";
114
-
115
- // ../ui/components/theme/themes.ts
116
- var darkTheme = {
117
- primary: "#FF71CE",
118
- accent: "#01CDFE",
119
- secondary: "#B967FF",
120
- muted: "#7B6F8E",
121
- border: "#B967FF",
122
- text: "#F0E6FF",
123
- success: "#05FFA1",
124
- error: "#FF6B6B",
125
- warning: "#FFC164"
126
- };
127
-
128
- // ../ui/components/theme/theme-context.tsx
129
- import { createContext, useContext } from "react";
130
- import { jsx as jsx5 } from "react/jsx-runtime";
131
- var ThemeContext = createContext(null);
132
- function useTheme() {
133
- return useContext(ThemeContext) ?? darkTheme;
134
- }
135
-
136
- // ../ui/components/spinner/spinner.tsx
137
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
138
- var VARIANTS = {
139
- dots: { frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"], interval: 83 },
140
- pulse: { frames: ["\xB7", "\u2219", "\u25CF", "\u2219", "\xB7", "\xB7", "\xB7"], interval: 180 },
141
- meter: { frames: ["\u25B1\u25B1\u25B1", "\u25B0\u25B1\u25B1", "\u25B0\u25B0\u25B1", "\u25B0\u25B0\u25B0", "\u25B0\u25B0\u25B1", "\u25B0\u25B1\u25B1", "\u25B1\u25B1\u25B1"], interval: 143 },
142
- bloom: { frames: ["\xB7", "\u2726", "\u2727", "\u2739", "\u273A", "\u274B", "\u2738", "\u2735", "\u2738", "\u274B", "\u273A", "\u2739", "\u2727", "\u2726", "\xB7", "\xB7"], interval: 100 },
143
- ellipsis: { frames: [" ", ". ", ".. ", "..."], interval: 333 }
144
- };
145
- var VARIANT_NAMES = Object.keys(VARIANTS);
146
- function Spinner({ variant = "dots", text, color }) {
147
- const theme = useTheme();
148
- const resolvedColor = color ?? theme.accent;
149
- const { frames, interval } = VARIANTS[variant];
150
- const [frame, setFrame] = useState2(0);
151
- useEffect(() => {
152
- setFrame(0);
153
- const timer = setInterval(() => {
154
- setFrame((prev) => (prev + 1) % frames.length);
155
- }, interval);
156
- return () => clearInterval(timer);
157
- }, [variant]);
158
- return /* @__PURE__ */ jsxs2("text", { children: [
159
- /* @__PURE__ */ jsx6("span", { style: { fg: resolvedColor }, children: frames[frame] }),
160
- text ? /* @__PURE__ */ jsxs2("span", { children: [
161
- " ",
162
- text
163
- ] }) : null
164
- ] });
165
- }
166
-
167
- // ../ui/components/spinner/spinner-showcase.tsx
168
- import { useState as useState3 } from "react";
169
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
170
- function SpinnerPicker({ useKeyboard: useKeyboard3 }) {
171
- const theme = useTheme();
172
- const [selected, setSelected] = useState3(0);
173
- useKeyboard3?.((event) => {
174
- if (event.name === "left") {
175
- setSelected((s) => s > 0 ? s - 1 : VARIANT_NAMES.length - 1);
176
- } else if (event.name === "right") {
177
- setSelected((s) => s < VARIANT_NAMES.length - 1 ? s + 1 : 0);
178
- }
179
- });
180
- const selectedName = VARIANT_NAMES[selected];
181
- return /* @__PURE__ */ jsxs3("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
182
- /* @__PURE__ */ jsx7("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx7(Spinner, { variant: selectedName, color: theme.accent }) }),
183
- /* @__PURE__ */ jsx7(
184
- StatusBar,
185
- {
186
- items: [{ key: "\u2190\u2192", label: "change spinner type" }],
187
- extra: /* @__PURE__ */ jsx7("span", { style: textStyle({ fg: theme.accent, bold: true }), children: selectedName.padEnd(8) })
188
- }
189
- )
190
- ] });
191
- }
192
-
193
- // ../ui/components/text-input/text-input.tsx
194
- import { useState as useState4, useCallback } from "react";
195
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
196
- function TextInput({
197
- value: controlledValue,
198
- onChange,
199
- onSubmit,
200
- placeholder = "",
201
- prompt = "> ",
202
- promptColor,
203
- focus = true,
204
- maxLength
205
- }) {
206
- const theme = useTheme();
207
- const resolvedPromptColor = promptColor ?? theme.accent;
208
- const [internalValue, setInternalValue] = useState4("");
209
- const isControlled = controlledValue !== void 0;
210
- const displayValue = isControlled ? controlledValue : internalValue;
211
- const handleInput = useCallback(
212
- (newValue) => {
213
- if (!isControlled) setInternalValue(newValue);
214
- onChange?.(newValue);
215
- },
216
- [isControlled, onChange]
217
- );
218
- const handleSubmit = useCallback(
219
- (value) => {
220
- onSubmit?.(value);
221
- if (!isControlled) setInternalValue("");
222
- },
223
- [isControlled, onSubmit]
224
- );
225
- return /* @__PURE__ */ jsxs4("box", { children: [
226
- prompt && /* @__PURE__ */ jsx8("text", { style: { fg: resolvedPromptColor }, children: prompt }),
227
- /* @__PURE__ */ jsx8(
228
- "input",
229
- {
230
- value: displayValue,
231
- placeholder,
232
- maxLength,
233
- focused: focus,
234
- onInput: handleInput,
235
- onSubmit: handleSubmit
236
- }
237
- )
238
- ] });
239
- }
240
-
241
- // ../ui/components/select-input/select-input.tsx
242
- import { useReducer, useMemo, useRef } from "react";
243
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
244
- function reducer(state, action) {
245
- switch (action.type) {
246
- case "MOVE": {
247
- let next = state.cursor + action.direction;
248
- if (next < 0) next = action.max - 1;
249
- if (next >= action.max) next = 0;
250
- return { ...state, cursor: next };
251
- }
252
- case "SUBMIT":
253
- return { ...state, submitted: true };
254
- default:
255
- return state;
256
- }
257
- }
258
- var VISIBLE = 12;
259
- var BAR = "\u2502";
260
- var RADIO = "\u25CB";
261
- var CURSOR = "\u25B8";
262
- var SEPARATOR = "\u2500";
263
- function SelectInput({
264
- items = [],
265
- defaultValue,
266
- value: controlledValue,
267
- onChange,
268
- disabled = false,
269
- invalid = false,
270
- required = false,
271
- placeholder,
272
- title = "Select",
273
- submittedStatus = "submitted",
274
- limit,
275
- highlightColor,
276
- onSubmit,
277
- useKeyboard: useKeyboard3
278
- }) {
279
- const theme = useTheme();
280
- const resolvedHighlight = highlightColor ?? theme.primary;
281
- const isControlled = controlledValue !== void 0;
282
- const controlledRef = useRef(isControlled);
283
- if (controlledRef.current !== isControlled) {
284
- console.warn("SelectInput: switching between controlled and uncontrolled is not supported.");
285
- }
286
- const initialIndex = items.findIndex((i) => i.value === (isControlled ? controlledValue : defaultValue));
287
- const [state, dispatch] = useReducer(reducer, {
288
- cursor: Math.max(0, initialIndex),
289
- submitted: false
290
- });
291
- const { flatRows, selectableItems } = useMemo(() => {
292
- const rows = [];
293
- const selectable = [];
294
- let index = 0;
295
- const grouped = /* @__PURE__ */ new Map();
296
- for (const item of items) {
297
- const group = item.group ?? "";
298
- const list = grouped.get(group) ?? [];
299
- list.push(item);
300
- grouped.set(group, list);
301
- }
302
- let groupIndex = 0;
303
- for (const [group, groupItems] of grouped) {
304
- if (groupIndex > 0) {
305
- rows.push({ type: "separator" });
306
- }
307
- if (group) {
308
- rows.push({ type: "group", label: group });
309
- }
310
- for (const item of groupItems) {
311
- rows.push({ type: "item", item, index });
312
- selectable.push({ item, index });
313
- index++;
314
- }
315
- groupIndex++;
316
- }
317
- return { flatRows: rows, selectableItems: selectable };
318
- }, [items]);
319
- const visibleCount = limit ?? VISIBLE;
320
- const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
321
- const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
322
- const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
323
- const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
324
- useKeyboard3?.((event) => {
325
- if (state.submitted || disabled) return;
326
- if (event.name === "up" || event.name === "k") {
327
- const direction = -1;
328
- let next = state.cursor + direction;
329
- if (next < 0) next = selectableItems.length - 1;
330
- dispatch({ type: "MOVE", direction, max: selectableItems.length });
331
- const nextItem = selectableItems[next];
332
- if (nextItem && !nextItem.item.disabled) {
333
- onChange?.(nextItem.item.value);
334
- }
335
- } else if (event.name === "down" || event.name === "j") {
336
- const direction = 1;
337
- let next = state.cursor + direction;
338
- if (next >= selectableItems.length) next = 0;
339
- dispatch({ type: "MOVE", direction, max: selectableItems.length });
340
- const nextItem = selectableItems[next];
341
- if (nextItem && !nextItem.item.disabled) {
342
- onChange?.(nextItem.item.value);
343
- }
344
- } else if (event.name === "return") {
345
- const current = selectableItems[state.cursor];
346
- if (current && !current.item.disabled) {
347
- dispatch({ type: "SUBMIT" });
348
- onSubmit?.(isControlled ? controlledValue : current.item.value);
349
- }
350
- }
351
- });
352
- if (state.submitted) {
353
- const selectedItem = isControlled ? items.find((i) => i.value === controlledValue) : selectableItems[state.cursor]?.item;
354
- return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
355
- /* @__PURE__ */ jsxs5("text", { children: [
356
- /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
357
- /* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true }), children: title })
358
- ] }),
359
- selectedItem && /* @__PURE__ */ jsxs5("text", { children: [
360
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.success }), children: [
361
- BAR,
362
- " "
363
- ] }),
364
- /* @__PURE__ */ jsx9("span", { children: " " }),
365
- /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.success }), children: "\u25CF " }),
366
- /* @__PURE__ */ jsx9("span", { children: selectedItem.label })
367
- ] }),
368
- /* @__PURE__ */ jsx9("text", { children: " " }),
369
- /* @__PURE__ */ jsx9("text", { children: /* @__PURE__ */ jsx9("span", { style: textStyle({ dim: true }), children: submittedStatus }) })
370
- ] });
371
- }
372
- const hasItems = selectableItems.length > 0;
373
- return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
374
- /* @__PURE__ */ jsxs5("text", { children: [
375
- /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: diamondColor, dim: disabled }), children: "\u25C6 " }),
376
- /* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true, dim: disabled }), children: title }),
377
- required && /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.error }), children: " *" })
378
- ] }),
379
- invalid && /* @__PURE__ */ jsxs5("text", { children: [
380
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
381
- BAR,
382
- " "
383
- ] }),
384
- /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.error }), children: " Please select an option" })
385
- ] }),
386
- !hasItems && placeholder && /* @__PURE__ */ jsxs5("text", { children: [
387
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
388
- BAR,
389
- " "
390
- ] }),
391
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ dim: true }), children: [
392
- " ",
393
- placeholder
394
- ] })
395
- ] }),
396
- visibleRows.map((row, i) => {
397
- if (row.type === "separator") {
398
- return /* @__PURE__ */ jsxs5("text", { children: [
399
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
400
- BAR,
401
- " "
402
- ] }),
403
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
404
- " ",
405
- SEPARATOR.repeat(20)
406
- ] })
407
- ] }, `sep-${i}`);
408
- }
409
- if (row.type === "group") {
410
- return /* @__PURE__ */ jsxs5("text", { children: [
411
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
412
- BAR,
413
- " "
414
- ] }),
415
- /* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true, fg: theme.muted }), children: ` ${row.label}` })
416
- ] }, `group-${row.label}`);
417
- }
418
- const { item, index: itemIndex } = row;
419
- const isHighlighted = !disabled && itemIndex === state.cursor;
420
- const isItemDisabled = disabled || !!item.disabled;
421
- const itemColor = isItemDisabled ? theme.muted : isHighlighted ? resolvedHighlight : void 0;
422
- return /* @__PURE__ */ jsxs5("text", { children: [
423
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
424
- BAR,
425
- " "
426
- ] }),
427
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: isHighlighted ? resolvedHighlight : void 0 }), children: [
428
- isHighlighted ? CURSOR : " ",
429
- " "
430
- ] }),
431
- /* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted, dim: isItemDisabled }), children: [
432
- RADIO,
433
- " "
434
- ] }),
435
- /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: itemColor, dim: isItemDisabled }), children: item.label })
436
- ] }, item.key ?? String(item.value));
437
- })
438
- ] });
439
- }
440
-
441
- // ../ui/components/multi-select/multi-select.tsx
442
- import { useReducer as useReducer2, useMemo as useMemo2, useRef as useRef2 } from "react";
443
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
444
- function reducer2(state, action) {
445
- switch (action.type) {
446
- case "MOVE": {
447
- let next = state.cursor + action.direction;
448
- if (next < 0) next = action.max - 1;
449
- if (next >= action.max) next = 0;
450
- return { ...state, cursor: next };
451
- }
452
- case "SET_SELECTED":
453
- return { ...state, selected: new Set(action.values) };
454
- case "SUBMIT":
455
- return { ...state, submitted: true };
456
- default:
457
- return state;
458
- }
459
- }
460
- var VISIBLE2 = 12;
461
- var BAR2 = "\u2502";
462
- var CHECKED = "\u25CF";
463
- var UNCHECKED = "\u25CB";
464
- var CURSOR2 = "\u25B8";
465
- var SEPARATOR2 = "\u2500";
466
- function MultiSelect({
467
- items = [],
468
- defaultSelected = [],
469
- selected: controlledSelected,
470
- onChange,
471
- disabled = false,
472
- invalid = false,
473
- required = false,
474
- placeholder,
475
- maxCount,
476
- title = "Select",
477
- submittedStatus = "submitted",
478
- limit,
479
- enableSelectAll = true,
480
- enableClear = true,
481
- highlightColor,
482
- checkboxColor,
483
- onSubmit,
484
- useKeyboard: useKeyboard3
485
- }) {
486
- const theme = useTheme();
487
- const resolvedHighlight = highlightColor ?? theme.primary;
488
- const resolvedCheckbox = checkboxColor ?? theme.accent;
489
- const isControlled = controlledSelected !== void 0;
490
- const controlledRef = useRef2(isControlled);
491
- if (controlledRef.current !== isControlled) {
492
- console.warn("MultiSelect: switching between controlled and uncontrolled is not supported.");
493
- }
494
- const [state, dispatch] = useReducer2(reducer2, {
495
- cursor: 0,
496
- selected: new Set(isControlled ? controlledSelected : defaultSelected),
497
- submitted: false
498
- });
499
- const currentSelected = useMemo2(
500
- () => isControlled ? new Set(controlledSelected) : state.selected,
501
- [isControlled, controlledSelected, state.selected]
502
- );
503
- const { flatRows, selectableItems } = useMemo2(() => {
504
- const rows = [];
505
- const selectable = [];
506
- let index = 0;
507
- const grouped = /* @__PURE__ */ new Map();
508
- for (const item of items) {
509
- const group = item.group ?? "";
510
- const list = grouped.get(group) ?? [];
511
- list.push(item);
512
- grouped.set(group, list);
513
- }
514
- let groupIndex = 0;
515
- for (const [group, groupItems] of grouped) {
516
- if (groupIndex > 0) {
517
- rows.push({ type: "separator" });
518
- }
519
- if (group) {
520
- rows.push({ type: "group", label: group });
521
- }
522
- for (const item of groupItems) {
523
- rows.push({ type: "item", item, index });
524
- selectable.push({ item, index });
525
- index++;
526
- }
527
- groupIndex++;
528
- }
529
- return { flatRows: rows, selectableItems: selectable };
530
- }, [items]);
531
- const visibleCount = limit ?? VISIBLE2;
532
- const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
533
- const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
534
- const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
535
- const setSelected = (values) => {
536
- if (isControlled) {
537
- onChange?.(values);
538
- } else {
539
- dispatch({ type: "SET_SELECTED", values });
540
- }
541
- };
542
- const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
543
- useKeyboard3?.((event) => {
544
- if (state.submitted || disabled) return;
545
- if (event.name === "up" || event.name === "k") {
546
- dispatch({ type: "MOVE", direction: -1, max: selectableItems.length });
547
- } else if (event.name === "down" || event.name === "j") {
548
- dispatch({ type: "MOVE", direction: 1, max: selectableItems.length });
549
- } else if (event.name === "return") {
550
- const current = selectableItems[state.cursor];
551
- if (current && !current.item.disabled) {
552
- const isDeselecting = currentSelected.has(current.item.value);
553
- if (!isDeselecting && maxCount !== void 0 && currentSelected.size >= maxCount) return;
554
- const next = new Set(currentSelected);
555
- if (isDeselecting) next.delete(current.item.value);
556
- else next.add(current.item.value);
557
- setSelected(Array.from(next));
558
- }
559
- } else if (event.name === "a" && enableSelectAll) {
560
- const enabledValues = items.filter((i) => !i.disabled).map((i) => i.value);
561
- setSelected(maxCount !== void 0 ? enabledValues.slice(0, maxCount) : enabledValues);
562
- } else if (event.name === "x" && enableClear) {
563
- setSelected([]);
564
- } else if (event.name === "space" && currentSelected.size > 0) {
565
- dispatch({ type: "SUBMIT" });
566
- onSubmit?.(Array.from(currentSelected));
567
- }
568
- });
569
- if (state.submitted) {
570
- const selectedItems = items.filter((i) => currentSelected.has(i.value));
571
- return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
572
- /* @__PURE__ */ jsxs6("text", { children: [
573
- /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
574
- /* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true }), children: title })
575
- ] }),
576
- selectedItems.map((item) => /* @__PURE__ */ jsxs6("text", { children: [
577
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.success }), children: [
578
- BAR2,
579
- " "
580
- ] }),
581
- /* @__PURE__ */ jsx10("span", { children: " " }),
582
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.success }), children: [
583
- CHECKED,
584
- " "
585
- ] }),
586
- /* @__PURE__ */ jsx10("span", { children: item.label })
587
- ] }, item.key ?? String(item.value))),
588
- /* @__PURE__ */ jsx10("text", { children: " " }),
589
- /* @__PURE__ */ jsx10("text", { children: /* @__PURE__ */ jsxs6("span", { style: textStyle({ dim: true }), children: [
590
- selectedItems.length,
591
- " selected \u2014 ",
592
- submittedStatus
593
- ] }) })
594
- ] });
595
- }
596
- const hasItems = selectableItems.length > 0;
597
- return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
598
- /* @__PURE__ */ jsxs6("text", { children: [
599
- /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: diamondColor, dim: disabled }), children: "\u25C6 " }),
600
- /* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true, dim: disabled }), children: title }),
601
- required && /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.error }), children: " *" }),
602
- maxCount !== void 0 && /* @__PURE__ */ jsx10("span", { style: textStyle({ dim: true }), children: ` (${currentSelected.size}/${maxCount})` })
603
- ] }),
604
- invalid && /* @__PURE__ */ jsxs6("text", { children: [
605
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
606
- BAR2,
607
- " "
608
- ] }),
609
- /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.error }), children: " Please select at least one option" })
610
- ] }),
611
- !hasItems && placeholder && /* @__PURE__ */ jsxs6("text", { children: [
612
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
613
- BAR2,
614
- " "
615
- ] }),
616
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ dim: true }), children: [
617
- " ",
618
- placeholder
619
- ] })
620
- ] }),
621
- visibleRows.map((row, i) => {
622
- if (row.type === "separator") {
623
- return /* @__PURE__ */ jsxs6("text", { children: [
624
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
625
- BAR2,
626
- " "
627
- ] }),
628
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
629
- " ",
630
- SEPARATOR2.repeat(20)
631
- ] })
632
- ] }, `sep-${i}`);
633
- }
634
- if (row.type === "group") {
635
- return /* @__PURE__ */ jsxs6("text", { children: [
636
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
637
- BAR2,
638
- " "
639
- ] }),
640
- /* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true, fg: theme.muted }), children: ` ${row.label}` })
641
- ] }, `group-${row.label}`);
642
- }
643
- const { item, index: itemIndex } = row;
644
- const isHighlighted = !disabled && itemIndex === state.cursor;
645
- const isSelected = currentSelected.has(item.value);
646
- const isItemDisabled = disabled || !!item.disabled;
647
- const itemColor = isItemDisabled ? theme.muted : isHighlighted ? resolvedHighlight : isSelected ? resolvedCheckbox : void 0;
648
- return /* @__PURE__ */ jsxs6("text", { children: [
649
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
650
- BAR2,
651
- " "
652
- ] }),
653
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isHighlighted ? resolvedHighlight : void 0 }), children: [
654
- isHighlighted ? CURSOR2 : " ",
655
- " "
656
- ] }),
657
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isSelected && !isItemDisabled ? resolvedCheckbox : theme.muted, dim: isItemDisabled }), children: [
658
- isSelected ? CHECKED : UNCHECKED,
659
- " "
660
- ] }),
661
- /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: itemColor, dim: isItemDisabled }), children: item.label })
662
- ] }, item.key ?? String(item.value));
663
- }),
664
- currentSelected.size > 0 && /* @__PURE__ */ jsxs6("text", { children: [
665
- /* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
666
- BAR2,
667
- " "
668
- ] }),
669
- /* @__PURE__ */ jsx10("span", { style: textStyle({ dim: true }), children: " space to submit" })
670
- ] })
671
- ] });
672
- }
673
-
674
- // ../ui/components/table/table.tsx
675
- import { Fragment } from "react";
676
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
677
- function getColumns(data, columnsProp) {
678
- if (columnsProp) return columnsProp;
679
- const keys = /* @__PURE__ */ new Set();
680
- for (const row of data) {
681
- for (const key in row) keys.add(key);
682
- }
683
- return Array.from(keys);
684
- }
685
- function calculateColumnWidths(columns, data, padding) {
686
- return columns.map((field) => {
687
- const headerWidth = String(field).length;
688
- const maxDataWidth = data.reduce((max, row) => {
689
- const val = row[field];
690
- return Math.max(max, val == null ? 0 : String(val).length);
691
- }, 0);
692
- return { field, width: Math.max(headerWidth, maxDataWidth) + padding * 2 };
693
- });
694
- }
695
- function padCell(value, width, padding) {
696
- const rightPad = width - value.length - padding;
697
- return " ".repeat(padding) + value + " ".repeat(Math.max(0, rightPad));
698
- }
699
- function Table({
700
- data,
701
- columns: columnsProp,
702
- padding = 1,
703
- headerColor,
704
- borderColor
705
- }) {
706
- const theme = useTheme();
707
- const resolvedHeaderColor = headerColor ?? theme.primary;
708
- const resolvedBorderColor = borderColor ?? theme.border;
709
- const columns = getColumns(data, columnsProp);
710
- const colInfo = calculateColumnWidths(columns, data, padding);
711
- const borderLine = (left, mid, right) => {
712
- const inner = colInfo.map((c) => "\u2500".repeat(c.width)).join(mid);
713
- return /* @__PURE__ */ jsx11("text", { children: /* @__PURE__ */ jsxs7("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: [
714
- left,
715
- inner,
716
- right
717
- ] }) });
718
- };
719
- const contentRow = (rowData, isHeader) => {
720
- const parts = [];
721
- parts.push(
722
- /* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "left-border")
723
- );
724
- colInfo.forEach((col, i) => {
725
- const val = rowData[col.field];
726
- const str = val == null ? "" : String(val);
727
- const padded = padCell(str, col.width, padding);
728
- if (isHeader) {
729
- parts.push(
730
- /* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedHeaderColor, bold: true }), children: padded }, `cell-${i}`)
731
- );
732
- } else {
733
- parts.push(/* @__PURE__ */ jsx11("span", { children: padded }, `cell-${i}`));
734
- }
735
- if (i < colInfo.length - 1) {
736
- parts.push(
737
- /* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, `sep-${i}`)
738
- );
739
- }
740
- });
741
- parts.push(
742
- /* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "right-border")
743
- );
744
- return /* @__PURE__ */ jsx11("text", { children: parts });
745
- };
746
- const headerData = columns.reduce(
747
- (acc, col) => ({ ...acc, [col]: col }),
748
- {}
749
- );
750
- return /* @__PURE__ */ jsxs7("box", { children: [
751
- borderLine("\u250C", "\u252C", "\u2510"),
752
- contentRow(headerData, true),
753
- data.map((row, index) => /* @__PURE__ */ jsxs7(Fragment, { children: [
754
- borderLine("\u251C", "\u253C", "\u2524"),
755
- contentRow(row, false)
756
- ] }, index)),
757
- borderLine("\u2514", "\u2534", "\u2518")
758
- ] });
759
- }
760
-
761
- // ../ui/components/gradient/gradient.tsx
762
- import { Fragment as Fragment2, jsx as jsx12 } from "react/jsx-runtime";
763
- var GRADIENTS = {
764
- cristal: ["#bdfff3", "#4ac29a"],
765
- teen: ["#77a1d3", "#79cbca", "#e684ae"],
766
- mind: ["#473b7b", "#3584a7", "#30d2be"],
767
- morning: ["#ff5f6d", "#ffc371"],
768
- vice: ["#5ee7df", "#b490ca"],
769
- passion: ["#f43b47", "#453a94"],
770
- fruit: ["#ff4e50", "#f9d423"],
771
- instagram: ["#833ab4", "#fd1d1d", "#fcb045"],
772
- atlas: ["#feac5e", "#c779d0", "#4bc0c8"],
773
- retro: ["#3f51b1", "#5a55ae", "#7b5fac", "#8f6aae", "#a86aa4", "#cc6b8e", "#f18271", "#f3a469", "#f7c978"],
774
- summer: ["#fdbb2d", "#22c1c3"],
775
- rainbow: ["#ff0000", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#ff00ff", "#ff0000"],
776
- pastel: ["#74ebd5", "#ACB6E5"]
777
- };
778
- function hexToRgb(hex) {
779
- const normalized = hex.replace("#", "");
780
- return {
781
- r: parseInt(normalized.substring(0, 2), 16),
782
- g: parseInt(normalized.substring(2, 4), 16),
783
- b: parseInt(normalized.substring(4, 6), 16)
784
- };
785
- }
786
- function rgbToHex(rgb) {
787
- const r = rgb.r.toString(16).padStart(2, "0");
788
- const g = rgb.g.toString(16).padStart(2, "0");
789
- const b = rgb.b.toString(16).padStart(2, "0");
790
- return `#${r}${g}${b}`;
791
- }
792
- function lerp(a, b, t) {
793
- return a + (b - a) * t;
794
- }
795
- function interpolateColor(color1, color2, t) {
796
- return {
797
- r: Math.round(lerp(color1.r, color2.r, t)),
798
- g: Math.round(lerp(color1.g, color2.g, t)),
799
- b: Math.round(lerp(color1.b, color2.b, t))
800
- };
801
- }
802
- function generateGradient(colors, steps) {
803
- if (colors.length === 0) throw new Error("At least one color is required");
804
- if (colors.length === 1 || steps <= 1) return Array(steps).fill(colors[0]);
805
- const rgbColors = colors.map(hexToRgb);
806
- const result = [];
807
- const segmentLength = (steps - 1) / (rgbColors.length - 1);
808
- for (let i = 0; i < steps; i++) {
809
- const segmentIndex = Math.min(Math.floor(i / segmentLength), rgbColors.length - 2);
810
- const segmentProgress = segmentLength > 0 ? (i - segmentIndex * segmentLength) / segmentLength : 0;
811
- const color = interpolateColor(rgbColors[segmentIndex], rgbColors[segmentIndex + 1], Math.min(segmentProgress, 1));
812
- result.push(rgbToHex(color));
813
- }
814
- return result;
815
- }
816
- function Gradient({ children, name, colors }) {
817
- if (name && colors) throw new Error("The `name` and `colors` props are mutually exclusive");
818
- if (!name && !colors) throw new Error("Either `name` or `colors` prop must be provided");
819
- const gradientColors = name ? GRADIENTS[name] : colors;
820
- const lines = children.split("\n");
821
- const maxLength = Math.max(...lines.map((l) => l.length));
822
- if (maxLength === 0) return /* @__PURE__ */ jsx12("text", { children });
823
- const hexColors = generateGradient(gradientColors, maxLength);
824
- return /* @__PURE__ */ jsx12(Fragment2, { children: lines.map((line, lineIndex) => /* @__PURE__ */ jsx12("text", { children: line.split("").map((char, charIndex) => /* @__PURE__ */ jsx12("span", { style: { fg: hexColors[charIndex] }, children: char }, charIndex)) }, lineIndex)) });
825
- }
826
-
827
- // ../ui/components/tab-bar/tab-bar.tsx
828
- import { jsx as jsx13 } from "react/jsx-runtime";
829
- function TabBar({
830
- label,
831
- options,
832
- selectedIndex,
833
- focused = true,
834
- activeColor
835
- }) {
836
- const theme = useTheme();
837
- const resolvedActiveColor = activeColor ?? theme.accent;
838
- const parts = [];
839
- if (label !== void 0) {
840
- parts.push(
841
- /* @__PURE__ */ jsx13(
842
- "span",
843
- {
844
- style: focused ? textStyle({ bold: true }) : textStyle({ dim: true }),
845
- children: label
846
- },
847
- "label"
848
- )
849
- );
850
- }
851
- parts.push(/* @__PURE__ */ jsx13("span", { children: " " }, "sep"));
852
- options.forEach((option, i) => {
853
- const isSelected = i === selectedIndex;
854
- const padded = ` ${option} `;
855
- if (isSelected && focused) {
856
- parts.push(
857
- /* @__PURE__ */ jsx13(
858
- "span",
859
- {
860
- style: textStyle({ inverse: true, bold: true, fg: resolvedActiveColor }),
861
- children: padded
862
- },
863
- `opt-${i}`
864
- )
865
- );
866
- } else if (isSelected && !focused) {
867
- parts.push(
868
- /* @__PURE__ */ jsx13(
869
- "span",
870
- {
871
- style: textStyle({ inverse: true, bold: true, dim: true }),
872
- children: padded
873
- },
874
- `opt-${i}`
875
- )
876
- );
877
- } else if (!focused) {
878
- parts.push(
879
- /* @__PURE__ */ jsx13("span", { style: textStyle({ dim: true }), children: padded }, `opt-${i}`)
880
- );
881
- } else {
882
- parts.push(/* @__PURE__ */ jsx13("span", { children: padded }, `opt-${i}`));
883
- }
884
- });
885
- return /* @__PURE__ */ jsx13("text", { children: parts });
886
- }
887
-
888
- // ../ui/components/modal/modal.tsx
889
- import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
890
- function Modal({
891
- children,
892
- title,
893
- borderColor,
894
- borderStyle = "rounded",
895
- onClose,
896
- useKeyboard: useKeyboard3
897
- }) {
898
- const theme = useTheme();
899
- const resolvedBorderColor = borderColor ?? theme.border;
900
- useKeyboard3?.((event) => {
901
- if (event.name === "escape" && onClose) {
902
- onClose();
903
- }
904
- });
905
- return /* @__PURE__ */ jsx14("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx14(
906
- "box",
907
- {
908
- flexDirection: "column",
909
- flexGrow: 1,
910
- border: true,
911
- borderStyle,
912
- borderColor: resolvedBorderColor,
913
- children: title ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
914
- /* @__PURE__ */ jsx14("box", { paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ jsx14("text", { style: textStyle({ bold: true, fg: resolvedBorderColor }), children: title }) }),
915
- children
916
- ] }) : children
917
- }
918
- ) });
919
- }
920
-
921
- // ../ui/components/chat/chat.tsx
922
- import { useState as useState5, useRef as useRef3 } from "react";
923
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
924
- var STATUS_ICONS = {
925
- pending: "\u2022",
926
- in_progress: "\u280B",
927
- completed: "\u2713",
928
- failed: "\u2717"
929
- };
930
- function getStatusColors(theme) {
931
- return {
932
- pending: theme.muted,
933
- in_progress: theme.warning,
934
- completed: theme.success,
935
- failed: theme.error
936
- };
937
- }
938
- function MessageBubble({
939
- message,
940
- userColor,
941
- assistantColor
942
- }) {
943
- const isUser = message.role === "user";
944
- const prefix = isUser ? "> " : "< ";
945
- const color = isUser ? userColor : assistantColor;
946
- return /* @__PURE__ */ jsxs9("text", { wrapMode: "word", children: [
947
- /* @__PURE__ */ jsx15("span", { style: textStyle({ bold: true, fg: color }), children: prefix }),
948
- /* @__PURE__ */ jsx15("span", { children: message.content })
949
- ] });
950
- }
951
- function StreamingTextDisplay({
952
- text,
953
- assistantColor,
954
- cursorChar = "_"
955
- }) {
956
- if (!text) return null;
957
- return /* @__PURE__ */ jsxs9("text", { wrapMode: "word", children: [
958
- /* @__PURE__ */ jsx15("span", { style: textStyle({ bold: true, fg: assistantColor }), children: "< " }),
959
- /* @__PURE__ */ jsx15("span", { children: text }),
960
- /* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: cursorChar })
961
- ] });
962
- }
963
- function ToolCallCard({ toolCall, statusColors }) {
964
- const icon = STATUS_ICONS[toolCall.status] || "\u2022";
965
- const color = statusColors[toolCall.status] || "gray";
966
- const showEllipsis = toolCall.status === "pending" || toolCall.status === "in_progress";
967
- return /* @__PURE__ */ jsxs9("text", { children: [
968
- /* @__PURE__ */ jsx15("span", { children: " " }),
969
- /* @__PURE__ */ jsx15("span", { style: textStyle({ fg: color }), children: icon }),
970
- /* @__PURE__ */ jsx15("span", { children: " " }),
971
- /* @__PURE__ */ jsx15("span", { style: textStyle({ fg: color }), children: toolCall.title }),
972
- showEllipsis && /* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: " ..." })
973
- ] });
974
- }
975
- function ChatInput({
976
- onSubmit,
977
- placeholder = "Type a message...",
978
- prompt = "> ",
979
- promptColor,
980
- disabled = false,
981
- useKeyboard: useKeyboard3
982
- }) {
983
- const [value, setValue] = useState5("");
984
- const valueRef = useRef3("");
985
- const updateValue = (newValue) => {
986
- valueRef.current = newValue;
987
- setValue(newValue);
988
- };
989
- useKeyboard3?.((event) => {
990
- if (disabled) return;
991
- if (event.name === "return") {
992
- const trimmed = valueRef.current.trim();
993
- if (trimmed) {
994
- onSubmit(trimmed);
995
- updateValue("");
996
- }
997
- return;
998
- }
999
- if (event.name === "backspace" || event.name === "delete") {
1000
- updateValue(valueRef.current.slice(0, -1));
1001
- return;
1002
- }
1003
- if (event.ctrl || event.meta) return;
1004
- if (event.name && event.name.length === 1) {
1005
- updateValue(valueRef.current + event.name);
1006
- return;
1007
- }
1008
- if (event.name === "space") {
1009
- updateValue(valueRef.current + " ");
1010
- return;
1011
- }
1012
- });
1013
- const showPlaceholder = value.length === 0;
1014
- return /* @__PURE__ */ jsxs9("text", { children: [
1015
- /* @__PURE__ */ jsx15("span", { style: textStyle({ fg: promptColor }), children: prompt }),
1016
- showPlaceholder ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
1017
- /* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: placeholder }),
1018
- !disabled && /* @__PURE__ */ jsx15("span", { style: textStyle({ inverse: true }), children: " " })
1019
- ] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
1020
- /* @__PURE__ */ jsx15("span", { children: value }),
1021
- !disabled && /* @__PURE__ */ jsx15("span", { style: textStyle({ inverse: true }), children: " " })
1022
- ] })
1023
- ] });
1024
- }
1025
- function ChatPanel({
1026
- messages,
1027
- streamingText = "",
1028
- isLoading = false,
1029
- activeToolCalls = [],
1030
- onSendMessage,
1031
- onCancel,
1032
- placeholder = "Type a message...",
1033
- promptChar = "> ",
1034
- promptColor,
1035
- userColor,
1036
- assistantColor,
1037
- loadingText = "Thinking...",
1038
- useKeyboard: useKeyboard3
1039
- }) {
1040
- const theme = useTheme();
1041
- const resolvedUserColor = userColor ?? theme.secondary;
1042
- const resolvedAssistantColor = assistantColor ?? theme.primary;
1043
- const resolvedPromptColor = promptColor ?? theme.secondary;
1044
- const statusColors = getStatusColors(theme);
1045
- const inputDisabled = isLoading || !!streamingText;
1046
- const wrappedUseKeyboard = useKeyboard3 ? (handler) => {
1047
- useKeyboard3((event) => {
1048
- if (event.name === "escape" && inputDisabled && onCancel) {
1049
- onCancel();
1050
- return;
1051
- }
1052
- handler(event);
1053
- });
1054
- } : void 0;
1055
- return /* @__PURE__ */ jsxs9("box", { flexDirection: "column", paddingX: 1, children: [
1056
- messages.map((msg) => /* @__PURE__ */ jsx15(
1057
- MessageBubble,
1058
- {
1059
- message: msg,
1060
- userColor: resolvedUserColor,
1061
- assistantColor: resolvedAssistantColor
1062
- },
1063
- msg.id
1064
- )),
1065
- activeToolCalls.map((tc) => /* @__PURE__ */ jsx15(ToolCallCard, { toolCall: tc, statusColors }, tc.id)),
1066
- streamingText ? /* @__PURE__ */ jsx15(
1067
- StreamingTextDisplay,
1068
- {
1069
- text: streamingText,
1070
- assistantColor: resolvedAssistantColor
1071
- }
1072
- ) : isLoading ? /* @__PURE__ */ jsxs9("text", { style: textStyle({ dim: true }), children: [
1073
- " ",
1074
- loadingText
1075
- ] }) : null,
1076
- /* @__PURE__ */ jsx15("box", { marginTop: 1, children: /* @__PURE__ */ jsx15(
1077
- ChatInput,
1078
- {
1079
- onSubmit: onSendMessage,
1080
- placeholder,
1081
- prompt: promptChar,
1082
- promptColor: resolvedPromptColor,
1083
- disabled: inputDisabled,
1084
- useKeyboard: wrappedUseKeyboard
1085
- }
1086
- ) })
1087
- ] });
1088
- }
1089
-
1090
- // ../ui/components/terminal-window/terminal-window.tsx
1091
- import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
1092
-
1093
- // ../ui/components/made-with-opentui/made-with-opentui.tsx
1094
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
1095
-
1096
- // ../ui/components/made-with-gridland/made-with-gridland.tsx
1097
- import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
1098
-
1099
- // ../ui/components/breakpoints/use-breakpoints.ts
1100
- import { useTerminalDimensions } from "@opentui/react";
1101
- var BREAKPOINTS = {
1102
- tiny: 40,
1103
- narrow: 60,
1104
- mobile: 70
1105
- };
1106
- function useBreakpoints() {
1107
- const { width, height } = useTerminalDimensions();
1108
- return {
1109
- isTiny: width < BREAKPOINTS.tiny,
1110
- isNarrow: width < BREAKPOINTS.narrow,
1111
- isMobile: width < BREAKPOINTS.mobile,
1112
- isDesktop: width >= BREAKPOINTS.mobile,
1113
- width,
1114
- height
1115
- };
1116
- }
1117
-
1118
- // ../docs/components/landing/landing-app.tsx
1119
- import { useState as useState8 } from "react";
1120
-
1121
- // ../docs/components/landing/logo.tsx
1122
- import { useState as useState6, useEffect as useEffect2, useRef as useRef4, useMemo as useMemo3 } from "react";
1123
28
  import figlet from "figlet";
1124
29
  import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
1125
- import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
1126
- figlet.parseFont("ANSI Shadow", ansiShadow);
1127
- function makeArt(text) {
1128
- return figlet.textSync(text, { font: "ANSI Shadow" }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
1129
- }
1130
- var fullArt = makeArt("gridland");
1131
- var gridArt = makeArt("grid");
1132
- var landArt = makeArt("land");
1133
- var ART_HEIGHT = 6;
1134
- function useAnimation(duration = 1e3) {
1135
- const isBrowser = typeof document !== "undefined";
1136
- const [progress, setProgress] = useState6(isBrowser ? 0 : 1);
1137
- const startTime = useRef4(null);
1138
- useEffect2(() => {
1139
- if (!isBrowser) return;
1140
- let raf;
1141
- const tick = (time) => {
1142
- if (startTime.current === null) startTime.current = time;
1143
- const elapsed = time - startTime.current;
1144
- const t = Math.min(1, elapsed / duration);
1145
- const eased = 1 - Math.pow(1 - t, 3);
1146
- setProgress(eased);
1147
- if (t < 1) raf = requestAnimationFrame(tick);
1148
- };
1149
- raf = requestAnimationFrame(tick);
1150
- return () => cancelAnimationFrame(raf);
1151
- }, []);
1152
- return progress;
1153
- }
1154
- function RevealGradient({ children, revealCol }) {
1155
- const gradientColors = GRADIENTS.instagram;
1156
- const lines = children.split("\n");
1157
- const maxLength = Math.max(...lines.map((l) => l.length));
1158
- if (maxLength === 0) return /* @__PURE__ */ jsx19("text", { children });
1159
- const hexColors = useMemo3(() => generateGradient(gradientColors, maxLength), [maxLength]);
1160
- return /* @__PURE__ */ jsx19("box", { position: "relative", width: maxLength, height: lines.length, shouldFill: false, children: lines.map((line, lineIndex) => {
1161
- const runs = [];
1162
- let current = null;
1163
- for (let i = 0; i < line.length; i++) {
1164
- const revealed = i <= revealCol;
1165
- const char = line[i];
1166
- const isVisible = revealed && char !== " ";
1167
- if (isVisible) {
1168
- if (!current) {
1169
- current = { start: i, chars: [] };
1170
- }
1171
- current.chars.push(char);
1172
- } else {
1173
- if (current) {
1174
- runs.push(current);
1175
- current = null;
1176
- }
1177
- }
1178
- }
1179
- if (current) runs.push(current);
1180
- return runs.map((run, runIndex) => /* @__PURE__ */ jsx19(
1181
- "box",
1182
- {
1183
- position: "absolute",
1184
- top: lineIndex,
1185
- left: run.start,
1186
- shouldFill: false,
1187
- children: /* @__PURE__ */ jsx19("text", { shouldFill: false, children: run.chars.map((char, ci) => /* @__PURE__ */ jsx19(
1188
- "span",
1189
- {
1190
- style: { fg: hexColors[run.start + ci] },
1191
- children: char
1192
- },
1193
- ci
1194
- )) })
1195
- },
1196
- `${lineIndex}-${runIndex}`
1197
- ));
1198
- }) });
1199
- }
1200
- function Logo({ compact, narrow, mobile }) {
1201
- const isBrowser = typeof document !== "undefined";
1202
- const progress = useAnimation(900);
1203
- const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
1204
- const dropOffset = Math.round((1 - progress) * -artHeight);
1205
- const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
1206
- const maxWidth = compact ? 8 : narrow ? 40 : 62;
1207
- const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
1208
- const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
1209
- const subtitle = /* @__PURE__ */ jsxs13(Fragment5, { children: [
1210
- /* @__PURE__ */ jsx19("text", { children: " " }),
1211
- /* @__PURE__ */ jsx19("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs13("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false, children: [
1212
- "A framework for building terminal apps, built on ",
1213
- /* @__PURE__ */ jsx19("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
1214
- " + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
1215
- ] }) })
1216
- ] });
1217
- if (!isBrowser) {
1218
- const art = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
1219
- return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", children: [
1220
- /* @__PURE__ */ jsx19(Gradient, { name: "instagram", children: art }),
1221
- /* @__PURE__ */ jsx19("text", { children: " " }),
1222
- /* @__PURE__ */ jsx19("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs13("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
1223
- "A framework for building terminal apps, built on OpenTUI + React.",
1224
- "\n",
1225
- "(Gridland apps, like this website, work in the browser and terminal.)"
1226
- ] }) })
1227
- ] });
1228
- }
1229
- if (compact) {
1230
- return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
1231
- /* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx19("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: "gridland" }) }) }),
1232
- subtitle
1233
- ] });
1234
- }
1235
- if (narrow) {
1236
- return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
1237
- /* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsxs13("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: [
1238
- /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: gridArt }),
1239
- /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: landArt })
1240
- ] }) }),
1241
- subtitle
1242
- ] });
1243
- }
1244
- return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
1245
- /* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx19("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: fullArt }) }) }),
1246
- subtitle
1247
- ] });
1248
- }
1249
-
1250
- // ../docs/components/landing/install-box.tsx
1251
- import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1252
- function InstallBox() {
1253
- const theme = useTheme();
1254
- return /* @__PURE__ */ jsx20(
1255
- "box",
1256
- {
1257
- border: true,
1258
- borderStyle: "rounded",
1259
- borderColor: theme.border,
1260
- paddingX: 1,
1261
- flexDirection: "column",
1262
- flexShrink: 0,
1263
- children: /* @__PURE__ */ jsxs14("text", { children: [
1264
- /* @__PURE__ */ jsx20("span", { style: textStyle({ dim: true }), children: "$ " }),
1265
- /* @__PURE__ */ jsx20("span", { style: textStyle({ bold: true }), children: "npm create " }),
1266
- /* @__PURE__ */ jsx20("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
1267
- ] })
1268
- }
1269
- );
1270
- }
1271
-
1272
- // ../docs/components/landing/links-box.tsx
1273
- import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
1274
- var UNDERLINE3 = 1 << 3;
1275
- function LinksBox() {
1276
- const theme = useTheme();
1277
- return /* @__PURE__ */ jsx21(
1278
- "box",
1279
- {
1280
- border: true,
1281
- borderStyle: "rounded",
1282
- borderColor: theme.border,
1283
- paddingX: 1,
1284
- flexDirection: "column",
1285
- flexShrink: 0,
1286
- children: /* @__PURE__ */ jsxs15("text", { children: [
1287
- /* @__PURE__ */ jsx21("span", { children: "\u{1F431}" }),
1288
- /* @__PURE__ */ jsx21("a", { href: "https://github.com/cjroth/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
1289
- /* @__PURE__ */ jsx21("span", { children: " " }),
1290
- /* @__PURE__ */ jsx21("span", { children: "\u{1F4D6}" }),
1291
- /* @__PURE__ */ jsx21("a", { href: "/docs", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
1292
- ] })
1293
- }
1294
- );
1295
- }
1296
-
1297
- // ../docs/components/landing/matrix-background.tsx
1298
- import { useMemo as useMemo4 } from "react";
1299
-
1300
- // ../docs/components/landing/use-matrix.ts
1301
- import { useState as useState7, useEffect as useEffect3, useRef as useRef5 } from "react";
1302
- var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
1303
- function randomChar() {
1304
- return CHARS[Math.floor(Math.random() * CHARS.length)];
1305
- }
1306
- function createDrop(height, seeded = false) {
1307
- const length = Math.floor(Math.random() * Math.floor(height * 0.6)) + 4;
1308
- return {
1309
- y: seeded ? Math.floor(Math.random() * (height + length)) : -Math.floor(Math.random() * height),
1310
- speed: 1,
1311
- length,
1312
- chars: Array.from({ length }, randomChar)
1313
- };
1314
- }
1315
- function buildGrid(columns, width, height) {
1316
- const grid = Array.from({ length: height }, () => Array(width).fill(" "));
1317
- const brightness = Array.from({ length: height }, () => Array(width).fill(0));
1318
- for (let x = 0; x < width; x++) {
1319
- const drop = columns[x];
1320
- if (!drop) continue;
1321
- for (let i = 0; i < drop.length; i++) {
1322
- const row = Math.floor(drop.y) - i;
1323
- if (row < 0 || row >= height) continue;
1324
- grid[row][x] = drop.chars[i];
1325
- if (i === 0) {
1326
- brightness[row][x] = 1;
1327
- } else {
1328
- brightness[row][x] = Math.max(0.15, 1 - i / drop.length);
1329
- }
1330
- }
1331
- }
1332
- return { grid, brightness };
1333
- }
1334
- function useMatrix(width, height) {
1335
- const columnsRef = useRef5([]);
1336
- const [state, setState] = useState7(() => {
1337
- const columns = Array.from(
1338
- { length: width },
1339
- () => Math.random() < 0.5 ? createDrop(height, true) : null
1340
- );
1341
- columnsRef.current = columns;
1342
- return buildGrid(columns, width, height);
1343
- });
1344
- useEffect3(() => {
1345
- if (width < 2 || height < 2) return;
1346
- const id = setInterval(() => {
1347
- const columns = columnsRef.current;
1348
- for (let x = 0; x < width; x++) {
1349
- if (columns[x] === null || columns[x] === void 0) {
1350
- if (Math.random() < 0.03) {
1351
- columns[x] = createDrop(height);
1352
- }
1353
- continue;
1354
- }
1355
- const drop = columns[x];
1356
- drop.y += drop.speed;
1357
- if (Math.random() < 0.1) {
1358
- const idx = Math.floor(Math.random() * drop.chars.length);
1359
- drop.chars[idx] = randomChar();
1360
- }
1361
- if (drop.y - drop.length > height) {
1362
- columns[x] = null;
1363
- }
1364
- }
1365
- setState(buildGrid(columns, width, height));
1366
- }, 80);
1367
- return () => clearInterval(id);
1368
- }, [width, height]);
1369
- useEffect3(() => {
1370
- columnsRef.current = Array.from(
1371
- { length: width },
1372
- () => Math.random() < 0.5 ? createDrop(height, true) : null
1373
- );
1374
- setState(buildGrid(columnsRef.current, width, height));
1375
- }, [width, height]);
1376
- return state;
1377
- }
1378
-
1379
- // ../docs/components/landing/matrix-background.tsx
1380
- import { jsx as jsx22 } from "react/jsx-runtime";
1381
- var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
1382
- var BG = hexToRgb("#1a1a2e");
1383
- function buildMutedColors(baseHex) {
1384
- const fg = hexToRgb(baseHex);
1385
- return MUTE_LEVELS.map((factor) => rgbToHex({
1386
- r: Math.round(BG.r + (fg.r - BG.r) * factor),
1387
- g: Math.round(BG.g + (fg.g - BG.g) * factor),
1388
- b: Math.round(BG.b + (fg.b - BG.b) * factor)
1389
- }));
1390
- }
1391
- function colorForCell(mutedColors, b) {
1392
- if (b >= 1) return mutedColors[4];
1393
- const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
1394
- return mutedColors[idx];
1395
- }
1396
- function MatrixBackground({ width, height, clearRect, clearRects }) {
1397
- const { grid, brightness } = useMatrix(width, height);
1398
- const theme = useTheme();
1399
- const columnColors = useMemo4(
1400
- () => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
1401
- [width, theme.accent, theme.secondary, theme.primary]
1402
- );
1403
- const columnMutedColors = useMemo4(
1404
- () => columnColors.map(buildMutedColors),
1405
- [columnColors]
1406
- );
1407
- return /* @__PURE__ */ jsx22("box", { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx22("text", { children: row.map((cell, x) => {
1408
- const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
1409
- (r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
1410
- );
1411
- const mutedColors = columnMutedColors[x];
1412
- if (cell === " " || inClearRect || !mutedColors) {
1413
- return /* @__PURE__ */ jsx22("span", { children: " " }, x);
1414
- }
1415
- return /* @__PURE__ */ jsx22(
1416
- "span",
1417
- {
1418
- style: {
1419
- fg: colorForCell(mutedColors, brightness[y][x])
1420
- },
1421
- children: cell
1422
- },
1423
- x
1424
- );
1425
- }) }, y)) });
1426
- }
1427
-
1428
- // ../docs/components/landing/about-modal.tsx
1429
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1430
- function AboutModal({ onClose, useKeyboard: useKeyboard3 }) {
1431
- const theme = useTheme();
1432
- return /* @__PURE__ */ jsx23(Modal, { title: "About Gridland", useKeyboard: useKeyboard3, onClose, children: /* @__PURE__ */ jsxs16("box", { paddingX: 1, flexDirection: "column", gap: 1, children: [
1433
- /* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "What is Gridland?" }),
1434
- /* @__PURE__ */ jsx23("text", { children: "Gridland renders terminal UIs to HTML5 Canvas with React." }),
1435
- /* @__PURE__ */ jsx23("text", { children: "No xterm.js. No terminal emulator. Just pixels." }),
1436
- /* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Features" }),
1437
- /* @__PURE__ */ jsxs16("text", { children: [
1438
- /* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
1439
- "\u2022",
1440
- " "
1441
- ] }),
1442
- "Canvas-rendered TUI components"
1443
- ] }),
1444
- /* @__PURE__ */ jsxs16("text", { children: [
1445
- /* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
1446
- "\u2022",
1447
- " "
1448
- ] }),
1449
- "React reconciler with JSX"
1450
- ] }),
1451
- /* @__PURE__ */ jsxs16("text", { children: [
1452
- /* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
1453
- "\u2022",
1454
- " "
1455
- ] }),
1456
- "Yoga flexbox layout engine"
1457
- ] }),
1458
- /* @__PURE__ */ jsxs16("text", { children: [
1459
- /* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
1460
- "\u2022",
1461
- " "
1462
- ] }),
1463
- "Keyboard, mouse, and clipboard support"
1464
- ] }),
1465
- /* @__PURE__ */ jsxs16("text", { children: [
1466
- /* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
1467
- "\u2022",
1468
- " "
1469
- ] }),
1470
- "Next.js and Vite plugins"
1471
- ] }),
1472
- /* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Tech Stack" }),
1473
- /* @__PURE__ */ jsx23("text", { children: "React + opentui engine + yoga-layout + HTML5 Canvas" }),
1474
- /* @__PURE__ */ jsx23("text", { style: textStyle({ dim: true }), children: "Press q to close" })
1475
- ] }) });
1476
- }
1477
-
1478
- // ../docs/components/landing/landing-app.tsx
1479
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1480
- function LandingApp({ useKeyboard: useKeyboard3 }) {
1481
- const theme = useTheme();
1482
- const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
1483
- const [showAbout, setShowAbout] = useState8(false);
1484
- useKeyboard3((event) => {
1485
- if (event.name === "a" && !showAbout) {
1486
- setShowAbout(true);
1487
- }
1488
- if (event.name === "q" && showAbout) {
1489
- setShowAbout(false);
1490
- }
1491
- });
1492
- if (showAbout) {
1493
- return /* @__PURE__ */ jsxs17("box", { flexDirection: "column", width: "100%", height: "100%", children: [
1494
- /* @__PURE__ */ jsx24("box", { flexGrow: 1, children: /* @__PURE__ */ jsx24(AboutModal, { onClose: () => setShowAbout(false), useKeyboard: useKeyboard3 }) }),
1495
- /* @__PURE__ */ jsx24(StatusBar, { items: [{ key: "q", label: "close" }] })
1496
- ] });
1497
- }
1498
- const isBrowser = typeof document !== "undefined";
1499
- const logoHeight = isTiny ? 2 : isNarrow ? 13 : 7;
1500
- const logoExtra = isBrowser ? 1 : 0;
1501
- const gap = isMobile ? 0 : 1;
1502
- const installLinksTop = 3 + logoHeight + logoExtra + gap;
1503
- const installLinksHeight = 3;
1504
- const boxTop = installLinksTop + installLinksHeight + gap + 1;
1505
- const boxHeight = height - boxTop - 1 - 1;
1506
- const clearRect = { top: boxTop, left: 1, width: width - 2, height: boxHeight };
1507
- const installLinksClearRect = { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight };
1508
- return /* @__PURE__ */ jsxs17("box", { width: "100%", height: "100%", position: "relative", children: [
1509
- /* @__PURE__ */ jsx24(MatrixBackground, { width, height, clearRect, clearRects: [installLinksClearRect] }),
1510
- /* @__PURE__ */ jsxs17(
1511
- "box",
1512
- {
1513
- position: "absolute",
1514
- top: 0,
1515
- left: 0,
1516
- width,
1517
- height,
1518
- zIndex: 1,
1519
- flexDirection: "column",
1520
- shouldFill: false,
1521
- children: [
1522
- /* @__PURE__ */ jsxs17("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false, children: [
1523
- /* @__PURE__ */ jsx24("box", { flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx24(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile }) }),
1524
- /* @__PURE__ */ jsxs17("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false, children: [
1525
- /* @__PURE__ */ jsx24(
1526
- "box",
1527
- {
1528
- border: true,
1529
- borderStyle: "rounded",
1530
- borderColor: theme.border,
1531
- paddingX: 1,
1532
- flexDirection: "column",
1533
- flexShrink: 0,
1534
- children: /* @__PURE__ */ jsxs17("text", { children: [
1535
- /* @__PURE__ */ jsx24("span", { style: textStyle({ dim: true }), children: "$ " }),
1536
- /* @__PURE__ */ jsx24("span", { style: textStyle({ bold: true }), children: "npx " }),
1537
- /* @__PURE__ */ jsx24("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
1538
- ] })
1539
- }
1540
- ),
1541
- /* @__PURE__ */ jsx24(InstallBox, {}),
1542
- /* @__PURE__ */ jsx24(LinksBox, {})
1543
- ] }),
1544
- /* @__PURE__ */ jsx24(
1545
- "box",
1546
- {
1547
- flexGrow: 1,
1548
- border: true,
1549
- borderStyle: "rounded",
1550
- borderColor: theme.border
1551
- }
1552
- )
1553
- ] }),
1554
- /* @__PURE__ */ jsx24(
1555
- StatusBar,
1556
- {
1557
- items: [
1558
- { key: "a", label: "about" }
1559
- ]
1560
- }
1561
- )
1562
- ]
1563
- }
1564
- )
1565
- ] });
1566
- }
1567
-
1568
- // ../docs/components/landing/matrix-rain.tsx
1569
- import { jsx as jsx25 } from "react/jsx-runtime";
1570
-
1571
- // ../ui/scripts/demo-apps.tsx
1572
- import figlet2 from "figlet";
1573
- import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
1574
30
  import big from "figlet/importable-fonts/Big.js";
1575
31
  import doom from "figlet/importable-fonts/Doom.js";
1576
32
  import slant from "figlet/importable-fonts/Slant.js";
@@ -1578,9 +34,9 @@ import speed from "figlet/importable-fonts/Speed.js";
1578
34
  import standard from "figlet/importable-fonts/Standard.js";
1579
35
  import block from "figlet/importable-fonts/Block.js";
1580
36
  import colossal from "figlet/importable-fonts/Colossal.js";
1581
- import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
37
+ import { jsx, jsxs } from "react/jsx-runtime";
1582
38
  var fonts = [
1583
- { name: "ANSI Shadow", data: ansiShadow2 },
39
+ { name: "ANSI Shadow", data: ansiShadow },
1584
40
  { name: "Standard", data: standard },
1585
41
  { name: "Big", data: big },
1586
42
  { name: "Doom", data: doom },
@@ -1590,49 +46,49 @@ var fonts = [
1590
46
  { name: "Colossal", data: colossal }
1591
47
  ];
1592
48
  for (const f of fonts) {
1593
- figlet2.parseFont(f.name, f.data);
49
+ figlet.parseFont(f.name, f.data);
1594
50
  }
1595
51
  function getFigletLines(fontName, text = "gridland") {
1596
- const art = figlet2.textSync(text, { font: fontName });
52
+ const art = figlet.textSync(text, { font: fontName });
1597
53
  return art.split("\n").filter((l) => l.trimEnd().length > 0);
1598
54
  }
1599
55
  var gradientNames = Object.keys(GRADIENTS);
1600
56
  function GradientApp() {
1601
- const [index, setIndex] = useState9(0);
57
+ const [index, setIndex] = useState(0);
1602
58
  const name = gradientNames[index];
1603
59
  const lines = getFigletLines("ANSI Shadow");
1604
60
  useKeyboard((event) => {
1605
61
  if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
1606
62
  if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
1607
63
  });
1608
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1609
- /* @__PURE__ */ jsx26("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx26(Gradient, { name, children: lines.join("\n") }) }),
1610
- /* @__PURE__ */ jsx26(
64
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
65
+ /* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx(Gradient, { name, children: lines.join("\n") }) }),
66
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(
1611
67
  StatusBar,
1612
68
  {
1613
69
  items: [{ key: "\u2190\u2192", label: "gradient" }, { key: "q", label: "quit" }],
1614
- extra: /* @__PURE__ */ jsx26("span", { style: textStyle({ fg: "cyan", bold: true }), children: name.padEnd(11) })
70
+ extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "cyan", bold: true }), children: name.padEnd(11) })
1615
71
  }
1616
- )
72
+ ) })
1617
73
  ] });
1618
74
  }
1619
75
  function AsciiApp() {
1620
- const [fontIndex, setFontIndex] = useState9(0);
76
+ const [fontIndex, setFontIndex] = useState(0);
1621
77
  const font = fonts[fontIndex];
1622
78
  const lines = getFigletLines(font.name);
1623
79
  useKeyboard((event) => {
1624
80
  if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
1625
81
  if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
1626
82
  });
1627
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1628
- /* @__PURE__ */ jsx26("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx26("text", { fg: "#88c0d0", bold: true, children: line }, i)) }),
1629
- /* @__PURE__ */ jsx26(
83
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
84
+ /* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx("text", { fg: "#88c0d0", bold: true, children: line }, i)) }),
85
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(
1630
86
  StatusBar,
1631
87
  {
1632
88
  items: [{ key: "\u2190\u2192", label: "change font" }, { key: "q", label: "quit" }],
1633
- extra: /* @__PURE__ */ jsx26("span", { style: textStyle({ fg: "cyan", bold: true }), children: font.name.padEnd(11) })
89
+ extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "cyan", bold: true }), children: font.name.padEnd(11) })
1634
90
  }
1635
- )
91
+ ) })
1636
92
  ] });
1637
93
  }
1638
94
  function TableApp() {
@@ -1641,82 +97,201 @@ function TableApp() {
1641
97
  { name: "Bob", role: "Designer", status: "Active" },
1642
98
  { name: "Charlie", role: "PM", status: "Away" }
1643
99
  ];
1644
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1645
- /* @__PURE__ */ jsx26("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx26(Table, { data, headerColor: "cyan", borderColor: "#5e81ac" }) }),
1646
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
100
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
101
+ /* @__PURE__ */ jsx("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(Table, { data, headerColor: "cyan", borderColor: "#5e81ac" }) }),
102
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
1647
103
  ] });
1648
104
  }
1649
105
  function SpinnerApp() {
1650
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1651
- /* @__PURE__ */ jsx26("box", { flexGrow: 1, children: /* @__PURE__ */ jsx26(SpinnerPicker, { useKeyboard }) }),
1652
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }, { key: "q", label: "quit" }] })
106
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
107
+ /* @__PURE__ */ jsx("box", { flexGrow: 1, children: /* @__PURE__ */ jsx(SpinnerPicker, { useKeyboard }) }),
108
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }, { key: "q", label: "quit" }] }) })
1653
109
  ] });
1654
110
  }
1655
111
  function SelectInputApp() {
1656
- const [submitted, setSubmitted] = useState9(false);
112
+ const [submitted, setSubmitted] = useState(false);
1657
113
  const items = [
1658
114
  { label: "TypeScript", value: "ts" },
1659
115
  { label: "JavaScript", value: "js" },
1660
116
  { label: "Python", value: "py" },
1661
117
  { label: "Rust", value: "rs" }
1662
118
  ];
1663
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1664
- /* @__PURE__ */ jsx26("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx26(SelectInput, { items, title: "Choose a language", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
1665
- /* @__PURE__ */ jsx26(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
119
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
120
+ /* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx(SelectInput, { items, title: "Choose a language", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
121
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
1666
122
  { key: "\u2191\u2193", label: "select" },
1667
123
  { key: "enter", label: "submit" },
1668
124
  { key: "q", label: "quit" }
1669
- ] })
125
+ ] }) })
1670
126
  ] });
1671
127
  }
1672
128
  function MultiSelectApp() {
1673
- const [submitted, setSubmitted] = useState9(false);
129
+ const [submitted, setSubmitted] = useState(false);
1674
130
  const items = [
1675
131
  { label: "TypeScript", value: "ts" },
1676
132
  { label: "JavaScript", value: "js" },
1677
133
  { label: "Python", value: "py" },
1678
134
  { label: "Rust", value: "rs" }
1679
135
  ];
1680
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1681
- /* @__PURE__ */ jsx26("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx26(MultiSelect, { items, title: "Select languages", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
1682
- /* @__PURE__ */ jsx26(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
136
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
137
+ /* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx(MultiSelect, { items, title: "Select languages", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
138
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
1683
139
  { key: "\u2191\u2193", label: "move" },
1684
140
  { key: "enter", label: "select" },
1685
141
  { key: "a", label: "all" },
1686
142
  { key: "x", label: "clear" },
1687
- { key: "space", label: "submit" },
1688
143
  { key: "q", label: "quit" }
1689
- ] })
144
+ ] }) })
145
+ ] });
146
+ }
147
+ function PromptInputApp() {
148
+ const [lastMessage, setLastMessage] = useState("");
149
+ const [model, setModel] = useState("opus");
150
+ const [showModelPicker, setShowModelPicker] = useState(false);
151
+ const [resetKey, setResetKey] = useState(0);
152
+ const commands = [
153
+ { cmd: "/help", desc: "Show commands" },
154
+ { cmd: "/model", desc: "Switch model" },
155
+ { cmd: "/clear", desc: "Clear conversation" }
156
+ ];
157
+ const files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
158
+ const models = [
159
+ { label: "Claude Opus", value: "opus" },
160
+ { label: "Claude Sonnet", value: "sonnet" },
161
+ { label: "Claude Haiku", value: "haiku" }
162
+ ];
163
+ const handleSubmit = (msg) => {
164
+ if (msg.text === "/model") {
165
+ setShowModelPicker(true);
166
+ setResetKey((k) => k + 1);
167
+ return;
168
+ }
169
+ if (msg.text === "/clear") {
170
+ setLastMessage("");
171
+ setResetKey((k) => k + 1);
172
+ return;
173
+ }
174
+ setLastMessage(msg.text);
175
+ };
176
+ if (showModelPicker) {
177
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
178
+ /* @__PURE__ */ jsx(
179
+ Modal,
180
+ {
181
+ title: "Select Model",
182
+ useKeyboard,
183
+ onClose: () => setShowModelPicker(false),
184
+ children: /* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsx(
185
+ SelectInput,
186
+ {
187
+ items: models,
188
+ defaultValue: model,
189
+ useKeyboard,
190
+ onSubmit: (value) => {
191
+ setModel(value);
192
+ setShowModelPicker(false);
193
+ }
194
+ }
195
+ ) })
196
+ }
197
+ ),
198
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
199
+ { key: "\u23CE", label: "select" },
200
+ { key: "esc", label: "cancel" },
201
+ { key: "q", label: "quit" }
202
+ ] }) })
203
+ ] });
204
+ }
205
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
206
+ /* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: lastMessage ? /* @__PURE__ */ jsxs("text", { children: [
207
+ /* @__PURE__ */ jsx("span", { children: "Sent: " }),
208
+ /* @__PURE__ */ jsx("span", { children: lastMessage })
209
+ ] }) : /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Type a message and press enter" }) }),
210
+ /* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsx(
211
+ PromptInput,
212
+ {
213
+ commands,
214
+ files,
215
+ placeholder: "Message Claude...",
216
+ showDividers: true,
217
+ useKeyboard,
218
+ onSubmit: handleSubmit
219
+ },
220
+ resetKey
221
+ ) }),
222
+ /* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsxs("text", { children: [
223
+ /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "#C4A8FF" }), children: "[\u22A1_\u22A1]" }),
224
+ /* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " " + model })
225
+ ] }) }),
226
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
227
+ { key: "\u23CE", label: "send" },
228
+ { key: "/", label: "commands" },
229
+ { key: "@", label: "files" },
230
+ { key: "\u2191", label: "history" },
231
+ { key: "q", label: "quit" }
232
+ ] }) })
1690
233
  ] });
1691
234
  }
235
+ var TEXT_INPUT_FIELDS = [
236
+ { label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
237
+ { label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
238
+ { label: "Password", placeholder: "enter password", maxLength: 40 },
239
+ { label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
240
+ ];
1692
241
  function TextInputApp() {
1693
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1694
- /* @__PURE__ */ jsxs18("box", { padding: 1, flexDirection: "column", gap: 1, flexGrow: 1, children: [
1695
- /* @__PURE__ */ jsx26("text", { fg: "#d8dee9", bold: true, children: "Enter your name:" }),
1696
- /* @__PURE__ */ jsx26(TextInput, { placeholder: "Type something...", prompt: "> " })
1697
- ] }),
1698
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
242
+ const [activeField, setActiveField] = useState(0);
243
+ const [values, setValues] = useState(TEXT_INPUT_FIELDS.map(() => ""));
244
+ useKeyboard((event) => {
245
+ if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
246
+ if (event.name === "down" || event.name === "tab") setActiveField((i) => Math.min(TEXT_INPUT_FIELDS.length - 1, i + 1));
247
+ });
248
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
249
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingTop: 1, children: /* @__PURE__ */ jsxs("text", { children: [
250
+ /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "#FF71CE", bold: true }), children: "TextInput" }),
251
+ /* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " Form with multiple input types" })
252
+ ] }) }),
253
+ /* @__PURE__ */ jsx("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: TEXT_INPUT_FIELDS.map((field, i) => /* @__PURE__ */ jsx("box", { marginBottom: 1, children: /* @__PURE__ */ jsx(
254
+ TextInput,
255
+ {
256
+ label: field.label,
257
+ placeholder: field.placeholder,
258
+ prompt: "> ",
259
+ focus: i === activeField,
260
+ maxLength: field.maxLength,
261
+ value: values[i],
262
+ onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
263
+ required: field.required,
264
+ disabled: field.disabled,
265
+ description: field.description
266
+ }
267
+ ) }, field.label)) }),
268
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
269
+ { key: "\u2191\u2193", label: "field" },
270
+ { key: "\u2190\u2192", label: "cursor" },
271
+ { key: "tab", label: "complete" },
272
+ { key: "^k/^u", label: "kill" }
273
+ ] }) })
1699
274
  ] });
1700
275
  }
1701
276
  function LinkApp() {
1702
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1703
- /* @__PURE__ */ jsx26("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx26(LinkDemo, { useKeyboard }) }),
1704
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
277
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
278
+ /* @__PURE__ */ jsx("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(LinkDemo, { useKeyboard }) }),
279
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
1705
280
  ] });
1706
281
  }
1707
282
  function TabBarApp() {
1708
283
  const tabs = ["Files", "Search", "Git", "Debug"];
1709
- const [selectedIndex, setSelectedIndex] = useState9(0);
284
+ const [selectedIndex, setSelectedIndex] = useState(0);
1710
285
  useKeyboard((event) => {
1711
286
  if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
1712
287
  if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
1713
288
  });
1714
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1715
- /* @__PURE__ */ jsxs18("box", { flexDirection: "column", gap: 1, padding: 1, flexGrow: 1, children: [
1716
- /* @__PURE__ */ jsx26(TabBar, { label: "View", options: tabs, selectedIndex }),
1717
- /* @__PURE__ */ jsx26("text", { style: textStyle({ dim: true }), children: "Use \u2190/\u2192 arrow keys to switch tabs" })
289
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
290
+ /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, padding: 1, flexGrow: 1, children: [
291
+ /* @__PURE__ */ jsx(TabBar, { label: "View", options: tabs, selectedIndex }),
292
+ /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Use \u2190/\u2192 arrow keys to switch tabs" })
1718
293
  ] }),
1719
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }, { key: "q", label: "quit" }] })
294
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }, { key: "q", label: "quit" }] }) })
1720
295
  ] });
1721
296
  }
1722
297
  function StatusBarApp() {
@@ -1726,7 +301,7 @@ function StatusBarApp() {
1726
301
  { key: "b", label: "back" },
1727
302
  { key: "z", label: "reset" }
1728
303
  ];
1729
- const [lastKey, setLastKey] = useState9(null);
304
+ const [lastKey, setLastKey] = useState(null);
1730
305
  useKeyboard((event) => {
1731
306
  if (event.name === "tab") setLastKey("switch focus (Tab)");
1732
307
  else if (event.name === "left") setLastKey("cycle (\u2190)");
@@ -1734,66 +309,224 @@ function StatusBarApp() {
1734
309
  else if (event.name === "b") setLastKey("back (b)");
1735
310
  else if (event.name === "z") setLastKey("reset (z)");
1736
311
  });
1737
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", gap: 1, padding: 1, children: [
1738
- lastKey ? /* @__PURE__ */ jsxs18("text", { children: [
1739
- /* @__PURE__ */ jsx26("span", { children: "Pressed: " }),
1740
- /* @__PURE__ */ jsx26("span", { style: textStyle({ bold: true, fg: "cyan" }), children: lastKey })
1741
- ] }) : /* @__PURE__ */ jsx26("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
1742
- /* @__PURE__ */ jsx26(
312
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, padding: 1, children: [
313
+ lastKey ? /* @__PURE__ */ jsxs("text", { children: [
314
+ /* @__PURE__ */ jsx("span", { children: "Pressed: " }),
315
+ /* @__PURE__ */ jsx("span", { style: textStyle({ bold: true, fg: "cyan" }), children: lastKey })
316
+ ] }) : /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
317
+ /* @__PURE__ */ jsx(
1743
318
  StatusBar,
1744
319
  {
1745
320
  items: [...shortcuts, { key: "q", label: "quit" }],
1746
- extra: /* @__PURE__ */ jsx26("span", { style: textStyle({ fg: "green" }), children: "\u25CF Ready" })
321
+ extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "green" }), children: "\u25CF Ready" })
1747
322
  }
1748
323
  )
1749
324
  ] });
1750
325
  }
1751
326
  function ModalApp() {
1752
- const [isOpen, setIsOpen] = useState9(false);
327
+ const [isOpen, setIsOpen] = useState(false);
1753
328
  useKeyboard((event) => {
1754
329
  if (!isOpen && event.name === "m") setIsOpen(true);
1755
330
  if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
1756
331
  });
1757
332
  if (isOpen) {
1758
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1759
- /* @__PURE__ */ jsx26(Modal, { title: "Example Modal", borderColor: "blue", useKeyboard, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs18("box", { paddingX: 1, flexDirection: "column", children: [
1760
- /* @__PURE__ */ jsx26("text", { children: "This is a modal overlay component." }),
1761
- /* @__PURE__ */ jsx26("text", { children: " " }),
1762
- /* @__PURE__ */ jsx26("text", { style: textStyle({ dim: true }), children: "It stretches to fill the full terminal height." })
333
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
334
+ /* @__PURE__ */ jsx(Modal, { title: "Example Modal", borderColor: "blue", useKeyboard, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs("box", { paddingX: 1, flexDirection: "column", children: [
335
+ /* @__PURE__ */ jsx("text", { children: "This is a modal overlay component." }),
336
+ /* @__PURE__ */ jsx("text", { children: " " }),
337
+ /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "It stretches to fill the full terminal height." })
1763
338
  ] }) }),
1764
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "close" }, { key: "Esc", label: "quit" }] })
339
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "close" }, { key: "Esc", label: "quit" }] }) })
1765
340
  ] });
1766
341
  }
1767
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1768
- /* @__PURE__ */ jsx26("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs18("text", { children: [
1769
- /* @__PURE__ */ jsx26("span", { style: textStyle({ dim: true }), children: "Press " }),
1770
- /* @__PURE__ */ jsx26("span", { style: textStyle({ inverse: true, bold: true }), children: " m " }),
1771
- /* @__PURE__ */ jsx26("span", { style: textStyle({ dim: true }), children: " to open modal" })
342
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
343
+ /* @__PURE__ */ jsx("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs("text", { children: [
344
+ /* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: "Press " }),
345
+ /* @__PURE__ */ jsx("span", { style: textStyle({ inverse: true, bold: true }), children: " m " }),
346
+ /* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " to open modal" })
1772
347
  ] }) }),
1773
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "m", label: "open modal" }, { key: "q", label: "quit" }] })
348
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "m", label: "open modal" }, { key: "q", label: "quit" }] }) })
1774
349
  ] });
1775
350
  }
1776
351
  function PrimitivesApp() {
1777
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1778
- /* @__PURE__ */ jsxs18("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
1779
- /* @__PURE__ */ jsx26("box", { border: true, borderStyle: "rounded", borderColor: "#5e81ac", title: "Layout", titleAlignment: "center", padding: 1, children: /* @__PURE__ */ jsxs18("box", { flexDirection: "row", gap: 2, children: [
1780
- /* @__PURE__ */ jsx26("box", { border: true, borderStyle: "single", borderColor: "#a3be8c", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx26("text", { fg: "#a3be8c", bold: true, children: "Box 1" }) }),
1781
- /* @__PURE__ */ jsx26("box", { border: true, borderStyle: "single", borderColor: "#ebcb8b", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx26("text", { fg: "#ebcb8b", bold: true, children: "Box 2" }) }),
1782
- /* @__PURE__ */ jsx26("box", { border: true, borderStyle: "single", borderColor: "#b48ead", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx26("text", { fg: "#b48ead", bold: true, children: "Box 3" }) })
352
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
353
+ /* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
354
+ /* @__PURE__ */ jsx("box", { border: true, borderStyle: "rounded", borderColor: "#5e81ac", title: "Layout", titleAlignment: "center", padding: 1, children: /* @__PURE__ */ jsxs("box", { flexDirection: "row", gap: 2, children: [
355
+ /* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#a3be8c", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#a3be8c", bold: true, children: "Box 1" }) }),
356
+ /* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#ebcb8b", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#ebcb8b", bold: true, children: "Box 2" }) }),
357
+ /* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#b48ead", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#b48ead", bold: true, children: "Box 3" }) })
1783
358
  ] }) }),
1784
- /* @__PURE__ */ jsx26("text", { fg: "#d8dee9", dim: true, children: " Nested boxes with borders, colors & flexbox layout" })
359
+ /* @__PURE__ */ jsx("text", { fg: "#d8dee9", dim: true, children: " Nested boxes with borders, colors & flexbox layout" })
1785
360
  ] }),
1786
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
361
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
1787
362
  ] });
1788
363
  }
1789
364
  function TerminalWindowApp() {
1790
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1791
- /* @__PURE__ */ jsxs18("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
1792
- /* @__PURE__ */ jsx26("text", { style: textStyle({ fg: "green" }), children: '$ echo "Hello from OpenTUI"' }),
1793
- /* @__PURE__ */ jsx26("text", { children: "Hello from OpenTUI" }),
1794
- /* @__PURE__ */ jsx26("text", { style: textStyle({ fg: "green" }), children: "$ _" })
365
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
366
+ /* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
367
+ /* @__PURE__ */ jsx("text", { style: textStyle({ fg: "green" }), children: '$ echo "Hello from OpenTUI"' }),
368
+ /* @__PURE__ */ jsx("text", { children: "Hello from OpenTUI" }),
369
+ /* @__PURE__ */ jsx("text", { style: textStyle({ fg: "green" }), children: "$ _" })
1795
370
  ] }),
1796
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
371
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
372
+ ] });
373
+ }
374
+ var TIMELINE_STEPS = [
375
+ { tool: "Read", label: "Reading codebase \u2014 src/", status: "done", delay: 1800 },
376
+ { tool: "Think", label: "Planning changes \u2014 auth module", status: "done", delay: 2500 },
377
+ { tool: "Edit", label: "Editing files \u2014 4 files", status: "done", delay: 3200 },
378
+ { tool: "Bash", label: "Running tests \u2014 vitest", status: "done", delay: 2e3 },
379
+ { tool: "Edit", label: "Fixing test \u2014 routes.test.ts", status: "done", delay: 1500 }
380
+ ];
381
+ function TimelineApp() {
382
+ const [expanded, setExpanded] = useState(true);
383
+ const [phase, setPhase] = useState("running");
384
+ const [stepIndex, setStepIndex] = useState(0);
385
+ const timerRef = useRef(null);
386
+ useKeyboard((event) => {
387
+ if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
388
+ if (event.name === "r") timelineRestart();
389
+ });
390
+ function timelineRestart() {
391
+ if (timerRef.current) clearTimeout(timerRef.current);
392
+ setPhase("running");
393
+ setStepIndex(0);
394
+ }
395
+ useEffect(() => {
396
+ if (phase !== "running") return;
397
+ if (stepIndex < TIMELINE_STEPS.length) {
398
+ const delay = TIMELINE_STEPS[stepIndex].delay;
399
+ timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
400
+ } else {
401
+ timerRef.current = setTimeout(() => setPhase("done"), 500);
402
+ }
403
+ return () => {
404
+ if (timerRef.current) clearTimeout(timerRef.current);
405
+ };
406
+ }, [phase, stepIndex]);
407
+ useEffect(() => {
408
+ if (phase === "done") {
409
+ timerRef.current = setTimeout(() => timelineRestart(), 3e3);
410
+ }
411
+ return () => {
412
+ if (timerRef.current) clearTimeout(timerRef.current);
413
+ };
414
+ }, [phase]);
415
+ const steps = TIMELINE_STEPS.map((s, i) => {
416
+ if (i < stepIndex) return { ...s, status: "done" };
417
+ if (i === stepIndex && phase === "running") return { ...s, status: "running" };
418
+ return { ...s, status: phase === "done" ? "done" : "pending" };
419
+ });
420
+ const elapsedMs = TIMELINE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
421
+ const totalMs = TIMELINE_STEPS.reduce((sum, s) => sum + s.delay, 0);
422
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
423
+ /* @__PURE__ */ jsx("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(
424
+ Timeline,
425
+ {
426
+ steps,
427
+ duration: phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`,
428
+ collapsed: !expanded
429
+ }
430
+ ) }),
431
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
432
+ { key: "ctrl+shift+e", label: "toggle" },
433
+ { key: "r", label: "restart" },
434
+ { key: "q", label: "quit" }
435
+ ] }) })
436
+ ] });
437
+ }
438
+ var BUBBLE_STEPS = [
439
+ { tool: "Read", label: "Reading codebase \u2014 src/", status: "done", delay: 1800 },
440
+ { tool: "Think", label: "Planning changes \u2014 auth module", status: "done", delay: 2500 },
441
+ { tool: "Edit", label: "Editing files \u2014 4 files", status: "done", delay: 3200 },
442
+ { tool: "Bash", label: "Running tests \u2014 vitest", status: "done", delay: 2e3 },
443
+ { tool: "Edit", label: "Fixing test \u2014 routes.test.ts", status: "done", delay: 1500 }
444
+ ];
445
+ var BUBBLE_RESPONSE = "I've refactored the auth module. The changes include extracting the token validation into a shared helper, consolidating the middleware chain, and updating the test suite to match.";
446
+ var BUBBLE_TOTAL_MS = BUBBLE_STEPS.reduce((sum, s) => sum + s.delay, 0);
447
+ function MessageApp() {
448
+ const [expanded, setExpanded] = useState(true);
449
+ const [phase, setPhase] = useState("idle");
450
+ const [stepIndex, setStepIndex] = useState(0);
451
+ const [streamedText, setStreamedText] = useState("");
452
+ const timerRef = useRef(null);
453
+ useKeyboard((event) => {
454
+ if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
455
+ if (event.name === "r") bubbleRestart();
456
+ });
457
+ function bubbleRestart() {
458
+ if (timerRef.current) clearTimeout(timerRef.current);
459
+ setPhase("idle");
460
+ setStepIndex(0);
461
+ setStreamedText("");
462
+ }
463
+ useEffect(() => {
464
+ if (phase === "idle") {
465
+ timerRef.current = setTimeout(() => setPhase("thinking"), 800);
466
+ }
467
+ return () => {
468
+ if (timerRef.current) clearTimeout(timerRef.current);
469
+ };
470
+ }, [phase]);
471
+ useEffect(() => {
472
+ if (phase !== "thinking") return;
473
+ if (stepIndex < BUBBLE_STEPS.length) {
474
+ const delay = BUBBLE_STEPS[stepIndex].delay;
475
+ timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
476
+ } else {
477
+ timerRef.current = setTimeout(() => setPhase("streaming"), 500);
478
+ }
479
+ return () => {
480
+ if (timerRef.current) clearTimeout(timerRef.current);
481
+ };
482
+ }, [phase, stepIndex]);
483
+ useEffect(() => {
484
+ if (phase !== "streaming") return;
485
+ if (streamedText.length < BUBBLE_RESPONSE.length) {
486
+ timerRef.current = setTimeout(() => {
487
+ setStreamedText(BUBBLE_RESPONSE.slice(0, streamedText.length + 2));
488
+ }, 25);
489
+ } else {
490
+ timerRef.current = setTimeout(() => setPhase("done"), 500);
491
+ }
492
+ return () => {
493
+ if (timerRef.current) clearTimeout(timerRef.current);
494
+ };
495
+ }, [phase, streamedText]);
496
+ useEffect(() => {
497
+ if (phase === "done") {
498
+ timerRef.current = setTimeout(() => bubbleRestart(), 3e3);
499
+ }
500
+ return () => {
501
+ if (timerRef.current) clearTimeout(timerRef.current);
502
+ };
503
+ }, [phase]);
504
+ const steps = BUBBLE_STEPS.map((s, i) => {
505
+ if (i < stepIndex) return { ...s, status: "done" };
506
+ if (i === stepIndex) return { ...s, status: "running" };
507
+ return { ...s, status: "pending" };
508
+ });
509
+ const isThinking = phase === "thinking";
510
+ const isStreaming = phase === "streaming";
511
+ const isDone = phase === "done";
512
+ const showAssistant = phase !== "idle";
513
+ const elapsedMs = BUBBLE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
514
+ const reasoningDuration = isThinking ? `${(elapsedMs / 1e3).toFixed(1)}s` : `${(BUBBLE_TOTAL_MS / 1e3).toFixed(1)}s`;
515
+ const reasoningSteps = isThinking ? steps : BUBBLE_STEPS.map((s) => ({ ...s, status: "done" }));
516
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
517
+ /* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
518
+ /* @__PURE__ */ jsx(Message, { role: "user", children: /* @__PURE__ */ jsx(Message.Content, { children: /* @__PURE__ */ jsx(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
519
+ showAssistant && /* @__PURE__ */ jsxs(Message, { role: "assistant", isStreaming, children: [
520
+ /* @__PURE__ */ jsx(Message.Reasoning, { part: {
521
+ type: "reasoning",
522
+ duration: reasoningDuration,
523
+ collapsed: !expanded,
524
+ steps: reasoningSteps
525
+ } }),
526
+ (isStreaming || isDone) && /* @__PURE__ */ jsx(Message.Content, { children: /* @__PURE__ */ jsx(Message.Text, { isLast: true, children: isDone ? BUBBLE_RESPONSE : streamedText }) })
527
+ ] })
528
+ ] }),
529
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "ctrl+shift+e", label: "toggle timeline" }, { key: "r", label: "restart" }, { key: "q", label: "quit" }] }) })
1797
530
  ] });
1798
531
  }
1799
532
  var initialChatMessages = [
@@ -1804,12 +537,12 @@ var initialChatMessages = [
1804
537
  ];
1805
538
  var chatNextId = 5;
1806
539
  function ChatApp() {
1807
- const [messages, setMessages] = useState9(initialChatMessages);
1808
- const [isLoading, setIsLoading] = useState9(false);
1809
- const [streamingText, setStreamingText] = useState9("");
1810
- const [activeToolCalls, setActiveToolCalls] = useState9([]);
1811
- const intervalRef = useRef6(null);
1812
- const handleSend = useCallback2((text) => {
540
+ const [messages, setMessages] = useState(initialChatMessages);
541
+ const [isLoading, setIsLoading] = useState(false);
542
+ const [streamingText, setStreamingText] = useState("");
543
+ const [activeToolCalls, setActiveToolCalls] = useState([]);
544
+ const intervalRef = useRef(null);
545
+ const handleSend = useCallback((text) => {
1813
546
  const userMsg = { id: String(chatNextId++), role: "user", content: text };
1814
547
  setMessages((prev) => [...prev, userMsg]);
1815
548
  setIsLoading(true);
@@ -1840,14 +573,14 @@ function ChatApp() {
1840
573
  }, 50);
1841
574
  }, 1400);
1842
575
  }, []);
1843
- const handleCancel = useCallback2(() => {
576
+ const handleCancel = useCallback(() => {
1844
577
  if (intervalRef.current) clearInterval(intervalRef.current);
1845
578
  setIsLoading(false);
1846
579
  setStreamingText("");
1847
580
  setActiveToolCalls([]);
1848
581
  }, []);
1849
- return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, children: [
1850
- /* @__PURE__ */ jsx26(
582
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
583
+ /* @__PURE__ */ jsx(
1851
584
  ChatPanel,
1852
585
  {
1853
586
  messages,
@@ -1860,29 +593,32 @@ function ChatApp() {
1860
593
  useKeyboard
1861
594
  }
1862
595
  ),
1863
- /* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "quit" }] })
596
+ /* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
1864
597
  ] });
1865
598
  }
1866
599
  var demos = [
1867
- { name: "gradient", app: () => /* @__PURE__ */ jsx26(GradientApp, {}) },
1868
- { name: "ascii", app: () => /* @__PURE__ */ jsx26(AsciiApp, {}) },
1869
- { name: "table", app: () => /* @__PURE__ */ jsx26(TableApp, {}) },
1870
- { name: "spinner", app: () => /* @__PURE__ */ jsx26(SpinnerApp, {}) },
1871
- { name: "select-input", app: () => /* @__PURE__ */ jsx26(SelectInputApp, {}) },
1872
- { name: "multi-select", app: () => /* @__PURE__ */ jsx26(MultiSelectApp, {}) },
1873
- { name: "text-input", app: () => /* @__PURE__ */ jsx26(TextInputApp, {}) },
1874
- { name: "link", app: () => /* @__PURE__ */ jsx26(LinkApp, {}) },
1875
- { name: "tab-bar", app: () => /* @__PURE__ */ jsx26(TabBarApp, {}) },
1876
- { name: "status-bar", app: () => /* @__PURE__ */ jsx26(StatusBarApp, {}) },
1877
- { name: "modal", app: () => /* @__PURE__ */ jsx26(ModalApp, {}) },
1878
- { name: "primitives", app: () => /* @__PURE__ */ jsx26(PrimitivesApp, {}) },
1879
- { name: "chat", app: () => /* @__PURE__ */ jsx26(ChatApp, {}) },
1880
- { name: "terminal", app: () => /* @__PURE__ */ jsx26(TerminalWindowApp, {}) },
1881
- { name: "landing", app: () => /* @__PURE__ */ jsx26(LandingApp, { useKeyboard }) }
600
+ { name: "gradient", app: () => /* @__PURE__ */ jsx(GradientApp, {}) },
601
+ { name: "ascii", app: () => /* @__PURE__ */ jsx(AsciiApp, {}) },
602
+ { name: "table", app: () => /* @__PURE__ */ jsx(TableApp, {}) },
603
+ { name: "spinner", app: () => /* @__PURE__ */ jsx(SpinnerApp, {}) },
604
+ { name: "select-input", app: () => /* @__PURE__ */ jsx(SelectInputApp, {}) },
605
+ { name: "multi-select", app: () => /* @__PURE__ */ jsx(MultiSelectApp, {}) },
606
+ { name: "prompt-input", app: () => /* @__PURE__ */ jsx(PromptInputApp, {}) },
607
+ { name: "text-input", app: () => /* @__PURE__ */ jsx(TextInputApp, {}) },
608
+ { name: "link", app: () => /* @__PURE__ */ jsx(LinkApp, {}) },
609
+ { name: "tabs", app: () => /* @__PURE__ */ jsx(TabBarApp, {}) },
610
+ { name: "status-bar", app: () => /* @__PURE__ */ jsx(StatusBarApp, {}) },
611
+ { name: "modal", app: () => /* @__PURE__ */ jsx(ModalApp, {}) },
612
+ { name: "primitives", app: () => /* @__PURE__ */ jsx(PrimitivesApp, {}) },
613
+ { name: "chat", app: () => /* @__PURE__ */ jsx(ChatApp, {}) },
614
+ { name: "timeline", app: () => /* @__PURE__ */ jsx(TimelineApp, {}) },
615
+ { name: "message", app: () => /* @__PURE__ */ jsx(MessageApp, {}) },
616
+ { name: "terminal-window", app: () => /* @__PURE__ */ jsx(TerminalWindowApp, {}) },
617
+ { name: "landing", app: () => /* @__PURE__ */ jsx(LandingApp, { useKeyboard }) }
1882
618
  ];
1883
619
 
1884
620
  // src/run.tsx
1885
- import { jsx as jsx27 } from "react/jsx-runtime";
621
+ import { jsx as jsx2 } from "react/jsx-runtime";
1886
622
  var _renderer;
1887
623
  function DemoShell({ children }) {
1888
624
  useKeyboard2((event) => {
@@ -1890,7 +626,7 @@ function DemoShell({ children }) {
1890
626
  _renderer.destroy();
1891
627
  }
1892
628
  });
1893
- return /* @__PURE__ */ jsx27("box", { flexDirection: "column", flexGrow: 1, children });
629
+ return /* @__PURE__ */ jsx2("box", { flexDirection: "column", flexGrow: 1, children });
1894
630
  }
1895
631
  async function runDemo(name) {
1896
632
  const demo = demos.find((d) => d.name === name);
@@ -1900,7 +636,7 @@ async function runDemo(name) {
1900
636
  process.exit(1);
1901
637
  }
1902
638
  _renderer = await createCliRenderer({ exitOnCtrlC: true });
1903
- createRoot(_renderer).render(/* @__PURE__ */ jsx27(DemoShell, { children: demo.app() }));
639
+ createRoot(_renderer).render(/* @__PURE__ */ jsx2(DemoShell, { children: demo.app() }));
1904
640
  }
1905
641
  export {
1906
642
  demos,