@sigx/terminal-ui 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Spinner-JpmBtbPo.js +25 -0
  3. package/dist/Spinner-JpmBtbPo.js.map +1 -0
  4. package/dist/buttons/Button.d.ts +8 -0
  5. package/dist/buttons/index.d.ts +1 -0
  6. package/dist/buttons/index.js +2 -0
  7. package/dist/buttons-D5iaiJ6G.js +38 -0
  8. package/dist/buttons-D5iaiJ6G.js.map +1 -0
  9. package/dist/data/QRCode.d.ts +17 -0
  10. package/dist/data/Table.d.ts +11 -0
  11. package/dist/data/index.d.ts +2 -0
  12. package/dist/data/index.js +2 -0
  13. package/dist/data-DKKLsE5K.js +43 -0
  14. package/dist/data-DKKLsE5K.js.map +1 -0
  15. package/dist/feedback/Badge.d.ts +14 -0
  16. package/dist/feedback/ProgressBar.d.ts +31 -0
  17. package/dist/feedback/Spinner.d.ts +21 -0
  18. package/dist/feedback/index.d.ts +3 -0
  19. package/dist/feedback/index.js +3 -0
  20. package/dist/feedback-1WqdARfx.js +62 -0
  21. package/dist/feedback-1WqdARfx.js.map +1 -0
  22. package/dist/forms/Checkbox.d.ts +15 -0
  23. package/dist/forms/Confirm.d.ts +21 -0
  24. package/dist/forms/Input.d.ts +15 -0
  25. package/dist/forms/MultiSelect.d.ts +36 -0
  26. package/dist/forms/Radio.d.ts +23 -0
  27. package/dist/forms/Select.d.ts +22 -0
  28. package/dist/forms/TextArea.d.ts +37 -0
  29. package/dist/forms/index.d.ts +7 -0
  30. package/dist/forms/index.js +2 -0
  31. package/dist/forms-MgpyoQI5.js +399 -0
  32. package/dist/forms-MgpyoQI5.js.map +1 -0
  33. package/dist/fx/Banner.d.ts +19 -0
  34. package/dist/fx/Gradient.d.ts +18 -0
  35. package/dist/fx/PixelArt.d.ts +16 -0
  36. package/dist/fx/Shimmer.d.ts +18 -0
  37. package/dist/fx/blockFont.d.ts +13 -0
  38. package/dist/fx/index.d.ts +6 -0
  39. package/dist/fx/index.js +3 -0
  40. package/dist/fx/paint.d.ts +15 -0
  41. package/dist/fx/presets.d.ts +14 -0
  42. package/dist/fx-igWaVCkB.js +452 -0
  43. package/dist/fx-igWaVCkB.js.map +1 -0
  44. package/dist/index.d.ts +17 -0
  45. package/dist/index.js +13 -0
  46. package/dist/layout/Card.d.ts +11 -0
  47. package/dist/layout/index.d.ts +2 -0
  48. package/dist/layout/index.js +2 -0
  49. package/dist/layout-CJzMVMDf.js +18 -0
  50. package/dist/layout-CJzMVMDf.js.map +1 -0
  51. package/dist/navigation/KeyHints.d.ts +15 -0
  52. package/dist/navigation/StatusBar.d.ts +9 -0
  53. package/dist/navigation/SuggestionList.d.ts +22 -0
  54. package/dist/navigation/Tabs.d.ts +18 -0
  55. package/dist/navigation/index.d.ts +4 -0
  56. package/dist/navigation/index.js +2 -0
  57. package/dist/navigation-B-nI3g0k.js +133 -0
  58. package/dist/navigation-B-nI3g0k.js.map +1 -0
  59. package/dist/presets-uqseGRqO.js +31 -0
  60. package/dist/presets-uqseGRqO.js.map +1 -0
  61. package/dist/prompts/PromptShell.d.ts +11 -0
  62. package/dist/prompts/confirm.d.ts +14 -0
  63. package/dist/prompts/index.d.ts +35 -0
  64. package/dist/prompts/index.js +2 -0
  65. package/dist/prompts/multiselect.d.ts +14 -0
  66. package/dist/prompts/select.d.ts +20 -0
  67. package/dist/prompts/spinner.d.ts +22 -0
  68. package/dist/prompts/statics.d.ts +8 -0
  69. package/dist/prompts/text.d.ts +19 -0
  70. package/dist/prompts-BLtLCen_.js +381 -0
  71. package/dist/prompts-BLtLCen_.js.map +1 -0
  72. package/dist/tasks/LogPanel.d.ts +28 -0
  73. package/dist/tasks/LogView.d.ts +24 -0
  74. package/dist/tasks/TaskList.d.ts +26 -0
  75. package/dist/tasks/index.d.ts +4 -0
  76. package/dist/tasks/index.js +2 -0
  77. package/dist/tasks/logStore.d.ts +40 -0
  78. package/dist/tasks-CdVFFOFs.js +254 -0
  79. package/dist/tasks-CdVFFOFs.js.map +1 -0
  80. package/dist/theme/builtins.d.ts +7 -0
  81. package/dist/theme/index.d.ts +3 -0
  82. package/dist/theme/index.js +2 -0
  83. package/dist/theme-DASuxf6k.js +150 -0
  84. package/dist/theme-DASuxf6k.js.map +1 -0
  85. package/package.json +95 -0
@@ -0,0 +1,254 @@
1
+ import { GLYPHS as e, READY_DELAY_MS as t, SPINNERS as n, displayWidth as r, focus as i, focusState as a, getOutputTarget as o, getTerminalSize as s, getTick as c, onKey as l, printStatic as u, registerFocusable as d, resolveColor as f, resolveFg as p, subscribeTicker as m, truncateToWidth as h, unregisterFocusable as g } from "@sigx/terminal-zero";
2
+ import { component as _, onMounted as v, onUnmounted as y, signal as b } from "@sigx/runtime-core";
3
+ import { jsx as x, jsxs as S } from "@sigx/runtime-core/jsx-runtime";
4
+ import { signal as C } from "@sigx/reactivity";
5
+ //#region src/tasks/LogPanel.tsx
6
+ var w = _(({ props: e }) => () => {
7
+ let t = e.height || 6, n = e.width || Math.max(20, s().columns - 4), r = e.variant || "bar", i = f(e.color || "dim"), a = f("line"), o = f("dim"), c = e.store ? e.store.tail(t) : (e.lines ?? []).slice(-t);
8
+ if (r === "panel") return /* @__PURE__ */ S("box", {
9
+ border: "rounded",
10
+ borderColor: a,
11
+ label: e.title,
12
+ labelColor: f("accent"),
13
+ padX: 1,
14
+ children: [c.flatMap((e, t) => {
15
+ let r = /* @__PURE__ */ x("text", {
16
+ color: i,
17
+ children: h(e, n - 4)
18
+ });
19
+ return t > 0 ? [/* @__PURE__ */ x("br", {}), r] : [r];
20
+ }), c.length === 0 && /* @__PURE__ */ x("text", {
21
+ color: f("faint"),
22
+ children: "…"
23
+ })]
24
+ });
25
+ let l = r === "bar" ? 2 : 0, u = c.flatMap((e, t) => {
26
+ let a = /* @__PURE__ */ S("text", { children: [r === "bar" && /* @__PURE__ */ x("text", {
27
+ color: o,
28
+ children: "│ "
29
+ }), /* @__PURE__ */ x("text", {
30
+ color: i,
31
+ children: h(e, n - l)
32
+ })] });
33
+ return t > 0 ? [/* @__PURE__ */ x("br", {}), a] : [a];
34
+ });
35
+ return /* @__PURE__ */ S("box", { children: [e.title && [
36
+ /* @__PURE__ */ x("text", {
37
+ color: o,
38
+ children: r === "bar" ? "┌ " : ""
39
+ }),
40
+ /* @__PURE__ */ x("text", {
41
+ color: f("dim"),
42
+ children: e.title
43
+ }),
44
+ /* @__PURE__ */ x("br", {})
45
+ ], u] });
46
+ }, { name: "LogPanel" }), T = _(({ props: t }) => {
47
+ let r = null;
48
+ return v(() => {
49
+ r = m();
50
+ }), y(() => {
51
+ r?.();
52
+ }), () => {
53
+ let r = t.tasks ?? [], i = t.variant === "tree", a = f("dim"), o = (t) => {
54
+ switch (t) {
55
+ case "running": return [
56
+ n.dots[c() % n.dots.length],
57
+ "accent",
58
+ "fg"
59
+ ];
60
+ case "success": return [
61
+ e.check,
62
+ "success",
63
+ "fg"
64
+ ];
65
+ case "fail": return [
66
+ e.cross,
67
+ "danger",
68
+ "danger"
69
+ ];
70
+ case "skipped": return [
71
+ "−",
72
+ "dim",
73
+ "dim"
74
+ ];
75
+ default: return [
76
+ "◌",
77
+ "faint",
78
+ "dim"
79
+ ];
80
+ }
81
+ };
82
+ return /* @__PURE__ */ x("box", { children: r.flatMap((e, n) => {
83
+ let [s, c, l] = o(e.status), u = i ? n === r.length - 1 ? "└─ " : "├─ " : "", d = /* @__PURE__ */ S("text", { children: [
84
+ i && /* @__PURE__ */ x("text", {
85
+ color: a,
86
+ children: u
87
+ }),
88
+ /* @__PURE__ */ x("text", {
89
+ color: f(c),
90
+ children: s
91
+ }),
92
+ /* @__PURE__ */ S("text", {
93
+ color: f(l),
94
+ children: [" ", e.label]
95
+ }),
96
+ e.detail && /* @__PURE__ */ S("text", {
97
+ color: f("dim"),
98
+ children: [
99
+ " (",
100
+ e.detail,
101
+ ")"
102
+ ]
103
+ })
104
+ ] }), p = n > 0 ? [/* @__PURE__ */ x("br", {}), d] : [d];
105
+ return e.status === "running" && t.log && p.push(/* @__PURE__ */ x(w, {
106
+ store: t.log,
107
+ height: t.logHeight || 6,
108
+ variant: "bar"
109
+ })), p;
110
+ }) });
111
+ };
112
+ }, { name: "TaskList" });
113
+ //#endregion
114
+ //#region src/tasks/logStore.ts
115
+ function E(e) {
116
+ return e.includes("\r") ? e.split("\r").reduce((e, t) => t + e.slice(t.length)) : e;
117
+ }
118
+ function D(e = {}) {
119
+ let t = e.limit ?? 1e4, n = e.passthrough ?? !o().isTTY, r = C({
120
+ lines: [],
121
+ partial: ""
122
+ }), i = (e) => {
123
+ let i = E(e);
124
+ r.lines.push(i), r.lines.length > t && r.lines.splice(0, r.lines.length - t), n && u(i);
125
+ };
126
+ return {
127
+ passthrough: n,
128
+ push(e) {
129
+ let t = (r.partial + e.replace(/\r\n/g, "\n")).split("\n");
130
+ r.partial = t.pop();
131
+ for (let e of t) i(e);
132
+ },
133
+ end() {
134
+ if (r.partial) {
135
+ let e = r.partial;
136
+ r.partial = "", i(e);
137
+ }
138
+ },
139
+ clear() {
140
+ r.lines.splice(0, r.lines.length), r.partial = "";
141
+ },
142
+ lines() {
143
+ let e = r.lines.slice();
144
+ return r.partial && e.push(E(r.partial)), e;
145
+ },
146
+ count() {
147
+ return r.lines.length + +!!r.partial;
148
+ },
149
+ tail(e) {
150
+ return e <= 0 ? [] : this.lines().slice(-e);
151
+ }
152
+ };
153
+ }
154
+ function O(e) {
155
+ return e < 1e3 ? `${Math.round(e)}ms` : `${(e / 1e3).toFixed(1)}s`;
156
+ }
157
+ function k(t) {
158
+ let n = (e) => p(f(e)), r = n("dim"), i = (e) => e ? "\x1B[39m" : "";
159
+ if (!t.ok && t.store && !t.store.passthrough) {
160
+ let e = t.store.lines();
161
+ e.length && u(e.join("\n"));
162
+ }
163
+ let a = n(t.ok ? "success" : "danger"), o = t.ok ? e.check : e.cross, s = t.durationMs === void 0 ? "" : ` ${r}(${O(t.durationMs)})${i(r)}`;
164
+ u(`${a}${o}${i(a)} ${t.label}${s}`);
165
+ }
166
+ //#endregion
167
+ //#region src/tasks/LogView.tsx
168
+ var A = _(({ props: e }) => {
169
+ let n = Math.random().toString(36).slice(2), o = !1, c = () => a.activeId === n, u = b({
170
+ offset: 0,
171
+ follow: !0,
172
+ anchorTotal: 0
173
+ }), p = () => e.store ? e.store.lines() : e.lines ?? [], m = () => e.height || 10, _ = (e) => {
174
+ if (u.follow) return 0;
175
+ let t = u.offset + Math.max(0, e - u.anchorTotal);
176
+ return Math.min(Math.max(0, t), Math.max(0, e - m()));
177
+ }, C = (e, t) => {
178
+ let n = Math.max(0, t - m()), r = Math.min(Math.max(0, e), n);
179
+ u.offset = r, u.anchorTotal = t, u.follow = r === 0;
180
+ }, w = (e) => {
181
+ if (!c() || !o) return;
182
+ let t = p().length, n = _(t), r = m();
183
+ if (e === "\x1B[A" || e === "k") {
184
+ C(n + 1, t);
185
+ return;
186
+ }
187
+ if (e === "\x1B[B" || e === "j") {
188
+ C(n - 1, t);
189
+ return;
190
+ }
191
+ if (e === "\x1B[5~") {
192
+ C(n + r, t);
193
+ return;
194
+ }
195
+ if (e === "\x1B[6~") {
196
+ C(n - r, t);
197
+ return;
198
+ }
199
+ if (e === "\x1B[H" || e === "\x1B[1~") {
200
+ C(2 ** 53 - 1, t);
201
+ return;
202
+ }
203
+ if (e === "\x1B[F" || e === "\x1B[4~") {
204
+ C(0, t);
205
+ return;
206
+ }
207
+ e === "f" && (u.follow ? (u.offset = n, u.anchorTotal = t, u.follow = !1) : C(0, t));
208
+ }, T = null;
209
+ return v(() => {
210
+ d(n), e.autofocus && i(n), T = l(w), setTimeout(() => {
211
+ o = !0;
212
+ }, t);
213
+ }), y(() => {
214
+ T && T(), g(n);
215
+ }), () => {
216
+ let t = c(), n = m(), i = e.width || Math.max(20, s().columns - 4), a = p(), o = a.length, l = o - _(o), d = Math.max(0, l - n), g = Math.max(1, i - 4), v = a.slice(d, l).map((e) => {
217
+ let t = h(e, g);
218
+ return t + " ".repeat(Math.max(0, g - r(t)));
219
+ });
220
+ for (; v.length < n;) v.push(" ".repeat(g));
221
+ let y = v.flatMap((e, t) => {
222
+ let n = /* @__PURE__ */ x("text", {
223
+ color: f("dim"),
224
+ children: e
225
+ });
226
+ return t > 0 ? [/* @__PURE__ */ x("br", {}), n] : [n];
227
+ });
228
+ return /* @__PURE__ */ S("box", { children: [/* @__PURE__ */ x("box", {
229
+ border: "rounded",
230
+ borderColor: f(t ? "accent" : "line"),
231
+ label: e.title,
232
+ labelColor: f(t ? "accent" : "dim"),
233
+ padX: 1,
234
+ children: y
235
+ }), /* @__PURE__ */ S("box", { children: [/* @__PURE__ */ S("text", {
236
+ color: f("dim"),
237
+ children: [
238
+ " ",
239
+ o ? `${d + 1}–${l}/${o}` : "0/0",
240
+ " · "
241
+ ]
242
+ }), u.follow ? /* @__PURE__ */ x("text", {
243
+ color: f("dim"),
244
+ children: "following"
245
+ }) : /* @__PURE__ */ x("text", {
246
+ color: f("warn"),
247
+ children: "paused"
248
+ })] })] });
249
+ };
250
+ }, { name: "LogView" });
251
+ //#endregion
252
+ export { w as a, T as i, k as n, D as r, A as t };
253
+
254
+ //# sourceMappingURL=tasks-CdVFFOFs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks-CdVFFOFs.js","names":[],"sources":["../src/tasks/LogPanel.tsx","../src/tasks/TaskList.tsx","../src/tasks/logStore.ts","../src/tasks/LogView.tsx"],"sourcesContent":["/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, type Define } from '@sigx/runtime-core';\r\nimport { resolveColor, getTerminalSize, truncateToWidth } from '@sigx/terminal-zero';\r\nimport type { LogStore } from './logStore';\r\n\r\n/**\r\n * Streaming log tail: the last `height` lines of a stream, dimmed, in\r\n * one of three variants:\r\n * - `bar` — `│` gutter in the `line` color (default)\r\n * - `panel` — rounded bordered box with the title as its label\r\n * - `plain` — bare lines\r\n * Feed it a LogStore (preferred — reactive, `\\r`-aware) or a plain `lines`\r\n * array. Follow-tail is inherent: it always shows the last `height` lines.\r\n * Lines are truncated escape-aware, so tool output containing its own ANSI\r\n * can't overflow the inline live region.\r\n */\r\nexport const LogPanel = component<\r\n Define.Prop<\"store\", LogStore, false> &\r\n Define.Prop<\"lines\", string[], false> &\r\n Define.Prop<\"height\", number, false> &\r\n Define.Prop<\"width\", number, false> &\r\n Define.Prop<\"title\", string, false> &\r\n Define.Prop<\"variant\", 'bar' | 'plain' | 'panel', false> &\r\n Define.Prop<\"color\", string, false>\r\n>(({ props }) => {\r\n return () => {\r\n const height = props.height || 6;\r\n const width = props.width || Math.max(20, getTerminalSize().columns - 4);\r\n const variant = props.variant || 'bar';\r\n const textColor = resolveColor(props.color || 'dim');\r\n // Box borders keep the `line` token (drawn on the themed canvas), but\r\n // the bare bar/title glyphs render on the terminal's own background in\r\n // inline mode, where `line` can be near-invisible — use `dim`.\r\n const borderColor = resolveColor('line');\r\n const glyphColor = resolveColor('dim');\r\n\r\n const src = props.store\r\n ? props.store.tail(height)\r\n : (props.lines ?? []).slice(-height);\r\n\r\n if (variant === 'panel') {\r\n return (\r\n <box border=\"rounded\" borderColor={borderColor} label={props.title} labelColor={resolveColor('accent')} padX={1}>\r\n {src.flatMap((line, i) => {\r\n const row = <text color={textColor}>{truncateToWidth(line, width - 4)}</text>;\r\n return i > 0 ? [<br />, row] : [row];\r\n })}\r\n {src.length === 0 && <text color={resolveColor('faint')}>…</text>}\r\n </box>\r\n );\r\n }\r\n\r\n const gutter = variant === 'bar' ? 2 : 0;\r\n const rows = src.flatMap((line, i) => {\r\n const row = (\r\n <text>\r\n {variant === 'bar' && <text color={glyphColor}>│ </text>}\r\n <text color={textColor}>{truncateToWidth(line, width - gutter)}</text>\r\n </text>\r\n );\r\n return i > 0 ? [<br />, row] : [row];\r\n });\r\n\r\n return (\r\n <box>\r\n {props.title && [\r\n <text color={glyphColor}>{variant === 'bar' ? '┌ ' : ''}</text>,\r\n <text color={resolveColor('dim')}>{props.title}</text>,\r\n <br />,\r\n ]}\r\n {rows}\r\n </box>\r\n );\r\n };\r\n}, { name: 'LogPanel' });\r\n\r\nexport default LogPanel;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport { resolveColor, GLYPHS, SPINNERS, getTick, subscribeTicker } from '@sigx/terminal-zero';\r\nimport { LogPanel } from './LogPanel';\r\nimport type { LogStore } from './logStore';\r\n\r\nexport type TaskStatus = 'pending' | 'running' | 'success' | 'fail' | 'skipped';\r\n\r\nexport interface TaskItem {\r\n id: string;\r\n label: string;\r\n status: TaskStatus;\r\n /** Optional dimmed suffix, e.g. a duration or a count. */\r\n detail?: string;\r\n}\r\n\r\n/**\r\n * Build-pipeline task list: one row per task with a status glyph (pending ◌,\r\n * running spinner, ✔/✖, skipped −), in `plain` or `tree` (├─/└─ guides)\r\n * variants. Pass a LogStore via `log` to stream a LogPanel tail under the\r\n * running task. Data-driven: mutate the `tasks` array in place (statuses are\r\n * reactive through the signal proxy).\r\n */\r\nexport const TaskList = component<\r\n Define.Prop<\"tasks\", TaskItem[], true> &\r\n Define.Prop<\"variant\", 'plain' | 'tree', false> &\r\n Define.Prop<\"log\", LogStore, false> &\r\n Define.Prop<\"logHeight\", number, false>\r\n>(({ props }) => {\r\n let unsub: (() => void) | null = null;\r\n\r\n onMounted(() => { unsub = subscribeTicker(); });\r\n onUnmounted(() => { unsub?.(); });\r\n\r\n return () => {\r\n const tasks = props.tasks ?? [];\r\n const tree = props.variant === 'tree';\r\n // `dim`, not `line`: tree guides render on the terminal's own\r\n // background in inline mode, where `line` can be near-invisible.\r\n const guideColor = resolveColor('dim');\r\n\r\n const glyphFor = (status: TaskStatus): [string, string, string] => {\r\n // [glyph, glyph color token, label color token]\r\n switch (status) {\r\n case 'running': return [SPINNERS.dots[getTick() % SPINNERS.dots.length], 'accent', 'fg'];\r\n case 'success': return [GLYPHS.check, 'success', 'fg'];\r\n case 'fail': return [GLYPHS.cross, 'danger', 'danger'];\r\n case 'skipped': return ['−', 'dim', 'dim'];\r\n default: return ['◌', 'faint', 'dim'];\r\n }\r\n };\r\n\r\n return (\r\n <box>\r\n {tasks.flatMap((task, i) => {\r\n const [glyph, glyphToken, labelToken] = glyphFor(task.status);\r\n const guide = tree ? (i === tasks.length - 1 ? '└─ ' : '├─ ') : '';\r\n const row = (\r\n <text>\r\n {tree && <text color={guideColor}>{guide}</text>}\r\n <text color={resolveColor(glyphToken)}>{glyph}</text>\r\n <text color={resolveColor(labelToken)}> {task.label}</text>\r\n {task.detail && <text color={resolveColor('dim')}> ({task.detail})</text>}\r\n </text>\r\n );\r\n const parts = i > 0 ? [<br />, row] : [row];\r\n if (task.status === 'running' && props.log) {\r\n parts.push(<LogPanel store={props.log} height={props.logHeight || 6} variant=\"bar\" />);\r\n }\r\n return parts;\r\n })}\r\n </box>\r\n );\r\n };\r\n}, { name: 'TaskList' });\r\n\r\nexport default TaskList;\r\n","/**\r\n * Reactive log store for streaming tool output (pod install, gradle, …) into\r\n * a LogPanel: a ring buffer of completed lines plus the live partial line.\r\n * Headless and transport-agnostic — pipe anything into it:\r\n *\r\n * proc.stdout.on('data', (d) => store.push(d.toString()));\r\n *\r\n * `\\r` inside a line is resolved with terminal overlay semantics, so progress\r\n * lines (\"Downloading 42%\\r\") render their latest frame, and a shorter frame\r\n * overwrites only the prefix of a longer one — like a real terminal.\r\n */\r\nimport { signal } from '@sigx/reactivity';\r\nimport { resolveColor, GLYPHS, getOutputTarget, printStatic, resolveFg } from '@sigx/terminal-zero';\r\n\r\nexport interface LogStoreOptions {\r\n /** Max retained completed lines (ring buffer). Default 10 000. */\r\n limit?: number;\r\n /**\r\n * Stream completed lines straight to printStatic as they arrive.\r\n * Default: on when stdout is not a TTY (piped/CI logs stay complete and\r\n * ordered), off when interactive (the LogPanel shows the tail instead).\r\n */\r\n passthrough?: boolean;\r\n}\r\n\r\nexport interface LogStore {\r\n /** Whether this store streams lines to printStatic (fixed at creation). */\r\n readonly passthrough: boolean;\r\n push(chunk: string): void;\r\n /** Commit a trailing partial line, if any. */\r\n end(): void;\r\n clear(): void;\r\n /** Completed lines, plus the live partial as the last entry. Reactive. */\r\n lines(): readonly string[];\r\n /** The last `n` of lines(). Reactive. */\r\n tail(n: number): string[];\r\n count(): number;\r\n}\r\n\r\n/** Resolve `\\r` overwrites: each segment overlays the prefix of what it follows. */\r\nfunction overlayCR(line: string): string {\r\n if (!line.includes('\\r')) return line;\r\n return line.split('\\r').reduce((acc, seg) => seg + acc.slice(seg.length));\r\n}\r\n\r\nexport function createLogStore(opts: LogStoreOptions = {}): LogStore {\r\n const limit = opts.limit ?? 10_000;\r\n const passthrough = opts.passthrough ?? !getOutputTarget().isTTY;\r\n const state = signal({ lines: [] as string[], partial: '' });\r\n\r\n const commit = (raw: string) => {\r\n const line = overlayCR(raw);\r\n state.lines.push(line);\r\n if (state.lines.length > limit) {\r\n state.lines.splice(0, state.lines.length - limit);\r\n }\r\n if (passthrough) printStatic(line);\r\n };\r\n\r\n return {\r\n passthrough,\r\n push(chunk: string) {\r\n const buf = state.partial + chunk.replace(/\\r\\n/g, '\\n');\r\n const parts = buf.split('\\n');\r\n state.partial = parts.pop()!;\r\n for (const part of parts) commit(part);\r\n },\r\n end() {\r\n if (state.partial) {\r\n const rest = state.partial;\r\n state.partial = '';\r\n commit(rest);\r\n }\r\n },\r\n clear() {\r\n state.lines.splice(0, state.lines.length);\r\n state.partial = '';\r\n },\r\n lines() {\r\n const all = state.lines.slice();\r\n if (state.partial) all.push(overlayCR(state.partial));\r\n return all;\r\n },\r\n count() {\r\n return state.lines.length + (state.partial ? 1 : 0);\r\n },\r\n tail(n: number) {\r\n if (n <= 0) return [];\r\n return this.lines().slice(-n);\r\n },\r\n };\r\n}\r\n\r\nfunction formatDuration(ms: number): string {\r\n return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;\r\n}\r\n\r\nexport interface CollapseOptions {\r\n label: string;\r\n ok: boolean;\r\n durationMs?: number;\r\n /** On failure, the full captured log is flushed into scrollback first. */\r\n store?: LogStore;\r\n}\r\n\r\n/**\r\n * Print a task's permanent one-line summary above the live region —\r\n * `✔ pod install (3.2s)` on success; on failure the full log flushes first so\r\n * it's greppable in scrollback, then `✖ label`. The live-region collapse\r\n * itself is the consumer flipping the task off `running` (the panel unmounts\r\n * and the repaint shrinks the region). Inline-mode pattern: in fullscreen,\r\n * static output queues until the alt screen exits, by design.\r\n */\r\nexport function collapseTask(o: CollapseOptions): void {\r\n // resolveFg accepts both hex (truecolor/256) and ANSI names (ansi16) and\r\n // returns '' at depth none — exactly the degradation static lines need.\r\n const sgr = (token: string) => resolveFg(resolveColor(token));\r\n const dim = sgr('dim');\r\n const off = (code: string) => (code ? '\\x1b[39m' : '');\r\n\r\n if (!o.ok && o.store && !o.store.passthrough) {\r\n const lines = o.store.lines();\r\n if (lines.length) printStatic(lines.join('\\n'));\r\n }\r\n\r\n const mark = sgr(o.ok ? 'success' : 'danger');\r\n const glyph = o.ok ? GLYPHS.check : GLYPHS.cross;\r\n const duration = o.durationMs !== undefined\r\n ? ` ${dim}(${formatDuration(o.durationMs)})${off(dim)}`\r\n : '';\r\n printStatic(`${mark}${glyph}${off(mark)} ${o.label}${duration}`);\r\n}\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor,\r\n getTerminalSize, truncateToWidth, displayWidth, READY_DELAY_MS,\r\n} from '@sigx/terminal-zero';\r\nimport type { LogStore } from './logStore';\r\n\r\n/**\r\n * Focusable, scrollable log viewer — the \"logs tab\" of a persistent dev TUI.\r\n * Follows the tail by default; scrolling up pauses follow and pins the\r\n * visible window even while the stream keeps growing; scrolling back to the\r\n * bottom (or End / `f`) re-engages follow.\r\n *\r\n * Keys while focused: ↑/k ↓/j scroll one line, PgUp/PgDn a page,\r\n * Home jump to the oldest, End jump to the tail (re-follows), `f` toggle.\r\n */\r\nexport const LogView = component<\r\n Define.Prop<'store', LogStore, false> &\r\n Define.Prop<'lines', string[], false> &\r\n Define.Prop<'height', number, false> &\r\n Define.Prop<'width', number, false> &\r\n Define.Prop<'title', string, false> &\r\n Define.Prop<'autofocus', boolean, false>\r\n>(({ props }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false;\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n // `offset` counts lines back from the tail. `anchorTotal` records the\r\n // stream length when the offset was set, so while paused the window stays\r\n // pinned to the same CONTENT as new lines arrive (drift compensation) —\r\n // without writing signals during render.\r\n const state = signal({ offset: 0, follow: true, anchorTotal: 0 });\r\n\r\n const src = () => (props.store ? props.store.lines() : (props.lines ?? []));\r\n const getHeight = () => props.height || 10;\r\n\r\n const effOffset = (total: number) => {\r\n if (state.follow) return 0;\r\n const drifted = state.offset + Math.max(0, total - state.anchorTotal);\r\n return Math.min(Math.max(0, drifted), Math.max(0, total - getHeight()));\r\n };\r\n\r\n const setOffset = (next: number, total: number) => {\r\n const max = Math.max(0, total - getHeight());\r\n const clamped = Math.min(Math.max(0, next), max);\r\n state.offset = clamped;\r\n state.anchorTotal = total;\r\n state.follow = clamped === 0;\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused() || !isReady) return;\r\n const total = src().length;\r\n const cur = effOffset(total);\r\n const page = getHeight();\r\n\r\n if (key === '\\x1B[A' || key === 'k') {\r\n setOffset(cur + 1, total);\r\n return;\r\n }\r\n if (key === '\\x1B[B' || key === 'j') {\r\n setOffset(cur - 1, total);\r\n return;\r\n }\r\n if (key === '\\x1b[5~') { // PgUp\r\n setOffset(cur + page, total);\r\n return;\r\n }\r\n if (key === '\\x1b[6~') { // PgDn\r\n setOffset(cur - page, total);\r\n return;\r\n }\r\n if (key === '\\x1b[H' || key === '\\x1b[1~') { // Home → oldest\r\n setOffset(Number.MAX_SAFE_INTEGER, total);\r\n return;\r\n }\r\n if (key === '\\x1b[F' || key === '\\x1b[4~') { // End → tail, re-follow\r\n setOffset(0, total);\r\n return;\r\n }\r\n if (key === 'f') {\r\n if (state.follow) {\r\n // Pause in place.\r\n state.offset = cur;\r\n state.anchorTotal = total;\r\n state.follow = false;\r\n } else {\r\n setOffset(0, total);\r\n }\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n setTimeout(() => { isReady = true; }, READY_DELAY_MS);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const height = getHeight();\r\n const width = props.width || Math.max(20, getTerminalSize().columns - 4);\r\n const all = src();\r\n const total = all.length;\r\n const off = effOffset(total);\r\n const end = total - off;\r\n const start = Math.max(0, end - height);\r\n\r\n // The box sizes itself to its widest line, so pad every line to the\r\n // interior width — the viewport then spans the full configured width\r\n // (terminal width by default) instead of hugging its content.\r\n const inner = Math.max(1, width - 4); // rounded border (2) + padX (2)\r\n const window = all.slice(start, end).map((line) => {\r\n const cut = truncateToWidth(line, inner);\r\n return cut + ' '.repeat(Math.max(0, inner - displayWidth(cut)));\r\n });\r\n while (window.length < height) window.push(' '.repeat(inner)); // stable frame height\r\n\r\n const rows = window.flatMap((line, i) => {\r\n const node = <text color={resolveColor('dim')}>{line}</text>;\r\n return i > 0 ? [<br />, node] : [node];\r\n });\r\n\r\n return (\r\n <box>\r\n <box\r\n border=\"rounded\"\r\n borderColor={resolveColor(focused ? 'accent' : 'line')}\r\n label={props.title}\r\n labelColor={resolveColor(focused ? 'accent' : 'dim')}\r\n padX={1}\r\n >\r\n {rows}\r\n </box>\r\n <box>\r\n <text color={resolveColor('dim')}> {total ? `${start + 1}–${end}/${total}` : '0/0'} · </text>\r\n {state.follow\r\n ? <text color={resolveColor('dim')}>following</text>\r\n : <text color={resolveColor('warn')}>paused</text>}\r\n </box>\r\n </box>\r\n );\r\n };\r\n}, { name: 'LogView' });\r\n\r\nexport default LogView;\r\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The five SigX-tui themes. Registered with the @sigx/terminal-zero engine on
3
+ * import; `obsidian` becomes the default. Hex values are the single source of
4
+ * truth — the renderer degrades them to 256/16-color as needed.
5
+ */
6
+ import { type Theme } from '@sigx/terminal-zero';
7
+ export declare const THEMES: Record<string, Theme>;
@@ -0,0 +1,3 @@
1
+ import './builtins';
2
+ export { THEMES } from './builtins';
3
+ export { setTheme, getTheme, getActiveTheme, registerTheme, hasTheme, listThemes, resolveColor, applyThemeCanvas, disableThemeCanvas, type Theme, } from '@sigx/terminal-zero';
@@ -0,0 +1,2 @@
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "../theme-DASuxf6k.js";
2
+ export { l as THEMES, c as applyThemeCanvas, i as disableThemeCanvas, o as getActiveTheme, n as getTheme, e as hasTheme, a as listThemes, s as registerTheme, t as resolveColor, r as setTheme };
@@ -0,0 +1,150 @@
1
+ import { applyThemeCanvas as e, applyThemeCanvas as t, disableThemeCanvas as n, getActiveTheme as r, getTheme as i, hasTheme as a, listThemes as o, registerTheme as s, registerTheme as c, resolveColor as l, setTheme as u, setTheme as d } from "@sigx/terminal-zero";
2
+ //#region src/theme/builtins.ts
3
+ var f = {
4
+ obsidian: {
5
+ name: "Obsidian",
6
+ mode: "dark",
7
+ bg: "#16161e",
8
+ panel: "#1a1b26",
9
+ chrome: "#13131a",
10
+ line: "#2a2c3d",
11
+ fg: "#c0caf5",
12
+ dim: "#565f89",
13
+ faint: "#3b4261",
14
+ shadow: "#0d0d12",
15
+ accent: "#7aa2f7",
16
+ accentSoft: "#283250",
17
+ accentText: "#16161e",
18
+ selSoft: "#272d44",
19
+ success: "#9ece6a",
20
+ warn: "#e0af68",
21
+ danger: "#f7768e",
22
+ info: "#7dcfff",
23
+ black: "#16161e",
24
+ red: "#f7768e",
25
+ green: "#9ece6a",
26
+ yellow: "#e0af68",
27
+ blue: "#7aa2f7",
28
+ magenta: "#bb9af7",
29
+ cyan: "#7dcfff",
30
+ white: "#c0caf5"
31
+ },
32
+ nord: {
33
+ name: "Nord",
34
+ mode: "dark",
35
+ bg: "#2e3440",
36
+ panel: "#3b4252",
37
+ chrome: "#2b303b",
38
+ line: "#434c5e",
39
+ fg: "#e5e9f0",
40
+ dim: "#7b8494",
41
+ faint: "#4c566a",
42
+ shadow: "#21252e",
43
+ accent: "#88c0d0",
44
+ accentSoft: "#3b4860",
45
+ accentText: "#2e3440",
46
+ selSoft: "#3b4456",
47
+ success: "#a3be8c",
48
+ warn: "#ebcb8b",
49
+ danger: "#bf616a",
50
+ info: "#81a1c1",
51
+ black: "#2e3440",
52
+ red: "#bf616a",
53
+ green: "#a3be8c",
54
+ yellow: "#ebcb8b",
55
+ blue: "#81a1c1",
56
+ magenta: "#b48ead",
57
+ cyan: "#88c0d0",
58
+ white: "#e5e9f0"
59
+ },
60
+ gum: {
61
+ name: "Gum",
62
+ mode: "dark",
63
+ bg: "#191724",
64
+ panel: "#1f1d2e",
65
+ chrome: "#16141f",
66
+ line: "#2a273f",
67
+ fg: "#e0def4",
68
+ dim: "#6e6a86",
69
+ faint: "#403d52",
70
+ shadow: "#100e17",
71
+ accent: "#c4a7e7",
72
+ accentSoft: "#2a2438",
73
+ accentText: "#191724",
74
+ selSoft: "#2a273f",
75
+ success: "#abc4a0",
76
+ warn: "#f6c177",
77
+ danger: "#eb6f92",
78
+ info: "#9ccfd8",
79
+ black: "#191724",
80
+ red: "#eb6f92",
81
+ green: "#abc4a0",
82
+ yellow: "#f6c177",
83
+ blue: "#31a1c2",
84
+ magenta: "#c4a7e7",
85
+ cyan: "#9ccfd8",
86
+ white: "#e0def4"
87
+ },
88
+ paper: {
89
+ name: "Paper",
90
+ mode: "light",
91
+ bg: "#faf9f5",
92
+ panel: "#ffffff",
93
+ chrome: "#f1efe8",
94
+ line: "#e6e3da",
95
+ fg: "#2a2733",
96
+ dim: "#8b8794",
97
+ faint: "#c4c0b6",
98
+ shadow: "#d9d6cc",
99
+ accent: "#5b5bd6",
100
+ accentSoft: "#ecebfb",
101
+ accentText: "#ffffff",
102
+ selSoft: "#f1f0fb",
103
+ success: "#2a8a4f",
104
+ warn: "#b07a1a",
105
+ danger: "#d1495b",
106
+ info: "#1b8a9a",
107
+ black: "#2a2733",
108
+ red: "#d1495b",
109
+ green: "#2a8a4f",
110
+ yellow: "#b07a1a",
111
+ blue: "#2f6feb",
112
+ magenta: "#8250df",
113
+ cyan: "#1b8a9a",
114
+ white: "#6e7481"
115
+ },
116
+ classic: {
117
+ name: "Classic",
118
+ mode: "dark",
119
+ bg: "#0c0e13",
120
+ panel: "#11141b",
121
+ chrome: "#0a0b0f",
122
+ line: "#1d2129",
123
+ fg: "#c9cdd6",
124
+ dim: "#6b7280",
125
+ faint: "#3a3f4b",
126
+ shadow: "#000000",
127
+ accent: "#3fd07f",
128
+ accentSoft: "#10271c",
129
+ accentText: "#0c0e13",
130
+ selSoft: "#15211b",
131
+ success: "#3fd07f",
132
+ warn: "#f5c518",
133
+ danger: "#e5484d",
134
+ info: "#34d4d4",
135
+ black: "#0c0e13",
136
+ red: "#e5484d",
137
+ green: "#3fd07f",
138
+ yellow: "#f5c518",
139
+ blue: "#4a9eff",
140
+ magenta: "#c678dd",
141
+ cyan: "#34d4d4",
142
+ white: "#c9cdd6"
143
+ }
144
+ };
145
+ for (let [e, t] of Object.entries(f)) s(e, t);
146
+ u("obsidian"), e();
147
+ //#endregion
148
+ export { a, l as c, i, d as l, n, o, r, c as s, t, f as u };
149
+
150
+ //# sourceMappingURL=theme-DASuxf6k.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-DASuxf6k.js","names":[],"sources":["../src/theme/builtins.ts"],"sourcesContent":["/**\r\n * The five SigX-tui themes. Registered with the @sigx/terminal-zero engine on\r\n * import; `obsidian` becomes the default. Hex values are the single source of\r\n * truth — the renderer degrades them to 256/16-color as needed.\r\n */\r\nimport { registerTheme, setTheme, applyThemeCanvas, type Theme } from '@sigx/terminal-zero';\r\n\r\nexport const THEMES: Record<string, Theme> = {\r\n obsidian: {\r\n name: 'Obsidian', mode: 'dark',\r\n bg: '#16161e', panel: '#1a1b26', chrome: '#13131a', line: '#2a2c3d',\r\n fg: '#c0caf5', dim: '#565f89', faint: '#3b4261', shadow: '#0d0d12',\r\n accent: '#7aa2f7', accentSoft: '#283250', accentText: '#16161e', selSoft: '#272d44',\r\n success: '#9ece6a', warn: '#e0af68', danger: '#f7768e', info: '#7dcfff',\r\n black: '#16161e', red: '#f7768e', green: '#9ece6a', yellow: '#e0af68',\r\n blue: '#7aa2f7', magenta: '#bb9af7', cyan: '#7dcfff', white: '#c0caf5',\r\n },\r\n nord: {\r\n name: 'Nord', mode: 'dark',\r\n bg: '#2e3440', panel: '#3b4252', chrome: '#2b303b', line: '#434c5e',\r\n fg: '#e5e9f0', dim: '#7b8494', faint: '#4c566a', shadow: '#21252e',\r\n accent: '#88c0d0', accentSoft: '#3b4860', accentText: '#2e3440', selSoft: '#3b4456',\r\n success: '#a3be8c', warn: '#ebcb8b', danger: '#bf616a', info: '#81a1c1',\r\n black: '#2e3440', red: '#bf616a', green: '#a3be8c', yellow: '#ebcb8b',\r\n blue: '#81a1c1', magenta: '#b48ead', cyan: '#88c0d0', white: '#e5e9f0',\r\n },\r\n gum: {\r\n name: 'Gum', mode: 'dark',\r\n bg: '#191724', panel: '#1f1d2e', chrome: '#16141f', line: '#2a273f',\r\n fg: '#e0def4', dim: '#6e6a86', faint: '#403d52', shadow: '#100e17',\r\n accent: '#c4a7e7', accentSoft: '#2a2438', accentText: '#191724', selSoft: '#2a273f',\r\n success: '#abc4a0', warn: '#f6c177', danger: '#eb6f92', info: '#9ccfd8',\r\n black: '#191724', red: '#eb6f92', green: '#abc4a0', yellow: '#f6c177',\r\n blue: '#31a1c2', magenta: '#c4a7e7', cyan: '#9ccfd8', white: '#e0def4',\r\n },\r\n paper: {\r\n name: 'Paper', mode: 'light',\r\n bg: '#faf9f5', panel: '#ffffff', chrome: '#f1efe8', line: '#e6e3da',\r\n fg: '#2a2733', dim: '#8b8794', faint: '#c4c0b6', shadow: '#d9d6cc',\r\n accent: '#5b5bd6', accentSoft: '#ecebfb', accentText: '#ffffff', selSoft: '#f1f0fb',\r\n success: '#2a8a4f', warn: '#b07a1a', danger: '#d1495b', info: '#1b8a9a',\r\n black: '#2a2733', red: '#d1495b', green: '#2a8a4f', yellow: '#b07a1a',\r\n blue: '#2f6feb', magenta: '#8250df', cyan: '#1b8a9a', white: '#6e7481',\r\n },\r\n classic: {\r\n name: 'Classic', mode: 'dark',\r\n bg: '#0c0e13', panel: '#11141b', chrome: '#0a0b0f', line: '#1d2129',\r\n fg: '#c9cdd6', dim: '#6b7280', faint: '#3a3f4b', shadow: '#000000',\r\n accent: '#3fd07f', accentSoft: '#10271c', accentText: '#0c0e13', selSoft: '#15211b',\r\n success: '#3fd07f', warn: '#f5c518', danger: '#e5484d', info: '#34d4d4',\r\n black: '#0c0e13', red: '#e5484d', green: '#3fd07f', yellow: '#f5c518',\r\n blue: '#4a9eff', magenta: '#c678dd', cyan: '#34d4d4', white: '#c9cdd6',\r\n },\r\n};\r\n\r\nfor (const [id, theme] of Object.entries(THEMES)) {\r\n registerTheme(id, theme);\r\n}\r\n\r\n// The SigX-tui default.\r\nsetTheme('obsidian');\r\n\r\n// Auto-paint the themed screen canvas from the active theme. Reacts to runtime\r\n// setTheme/setColorDepth. Call disableThemeCanvas() to opt out (transparent /\r\n// inline apps that don't want a themed background).\r\napplyThemeCanvas();\r\n"],"mappings":";;AAOA,IAAa,IAAgC;CACzC,UAAU;EACN,MAAM;EAAY,MAAM;EACxB,IAAI;EAAW,OAAO;EAAW,QAAQ;EAAW,MAAM;EAC1D,IAAI;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EACzD,QAAQ;EAAW,YAAY;EAAW,YAAY;EAAW,SAAS;EAC1E,SAAS;EAAW,MAAM;EAAW,QAAQ;EAAW,MAAM;EAC9D,OAAO;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EAC5D,MAAM;EAAW,SAAS;EAAW,MAAM;EAAW,OAAO;EAChE;CACD,MAAM;EACF,MAAM;EAAQ,MAAM;EACpB,IAAI;EAAW,OAAO;EAAW,QAAQ;EAAW,MAAM;EAC1D,IAAI;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EACzD,QAAQ;EAAW,YAAY;EAAW,YAAY;EAAW,SAAS;EAC1E,SAAS;EAAW,MAAM;EAAW,QAAQ;EAAW,MAAM;EAC9D,OAAO;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EAC5D,MAAM;EAAW,SAAS;EAAW,MAAM;EAAW,OAAO;EAChE;CACD,KAAK;EACD,MAAM;EAAO,MAAM;EACnB,IAAI;EAAW,OAAO;EAAW,QAAQ;EAAW,MAAM;EAC1D,IAAI;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EACzD,QAAQ;EAAW,YAAY;EAAW,YAAY;EAAW,SAAS;EAC1E,SAAS;EAAW,MAAM;EAAW,QAAQ;EAAW,MAAM;EAC9D,OAAO;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EAC5D,MAAM;EAAW,SAAS;EAAW,MAAM;EAAW,OAAO;EAChE;CACD,OAAO;EACH,MAAM;EAAS,MAAM;EACrB,IAAI;EAAW,OAAO;EAAW,QAAQ;EAAW,MAAM;EAC1D,IAAI;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EACzD,QAAQ;EAAW,YAAY;EAAW,YAAY;EAAW,SAAS;EAC1E,SAAS;EAAW,MAAM;EAAW,QAAQ;EAAW,MAAM;EAC9D,OAAO;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EAC5D,MAAM;EAAW,SAAS;EAAW,MAAM;EAAW,OAAO;EAChE;CACD,SAAS;EACL,MAAM;EAAW,MAAM;EACvB,IAAI;EAAW,OAAO;EAAW,QAAQ;EAAW,MAAM;EAC1D,IAAI;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EACzD,QAAQ;EAAW,YAAY;EAAW,YAAY;EAAW,SAAS;EAC1E,SAAS;EAAW,MAAM;EAAW,QAAQ;EAAW,MAAM;EAC9D,OAAO;EAAW,KAAK;EAAW,OAAO;EAAW,QAAQ;EAC5D,MAAM;EAAW,SAAS;EAAW,MAAM;EAAW,OAAO;EAChE;CACJ;AAED,KAAK,IAAM,CAAC,GAAI,MAAU,OAAO,QAAQ,EAAO,EAC5C,EAAc,GAAI,EAAM;AAI5B,EAAS,WAAW,EAKpB,GAAkB"}
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "@sigx/terminal-ui",
3
+ "version": "0.5.0",
4
+ "description": "SigX-tui design-system components for SignalX terminal UIs, built on @sigx/terminal-zero",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./theme": {
14
+ "import": "./dist/theme/index.js",
15
+ "types": "./dist/theme/index.d.ts"
16
+ },
17
+ "./buttons": {
18
+ "import": "./dist/buttons/index.js",
19
+ "types": "./dist/buttons/index.d.ts"
20
+ },
21
+ "./forms": {
22
+ "import": "./dist/forms/index.js",
23
+ "types": "./dist/forms/index.d.ts"
24
+ },
25
+ "./feedback": {
26
+ "import": "./dist/feedback/index.js",
27
+ "types": "./dist/feedback/index.d.ts"
28
+ },
29
+ "./navigation": {
30
+ "import": "./dist/navigation/index.js",
31
+ "types": "./dist/navigation/index.d.ts"
32
+ },
33
+ "./layout": {
34
+ "import": "./dist/layout/index.js",
35
+ "types": "./dist/layout/index.d.ts"
36
+ },
37
+ "./data": {
38
+ "import": "./dist/data/index.js",
39
+ "types": "./dist/data/index.d.ts"
40
+ },
41
+ "./fx": {
42
+ "import": "./dist/fx/index.js",
43
+ "types": "./dist/fx/index.d.ts"
44
+ },
45
+ "./tasks": {
46
+ "import": "./dist/tasks/index.js",
47
+ "types": "./dist/tasks/index.d.ts"
48
+ },
49
+ "./prompts": {
50
+ "import": "./dist/prompts/index.js",
51
+ "types": "./dist/prompts/index.d.ts"
52
+ }
53
+ },
54
+ "files": [
55
+ "dist"
56
+ ],
57
+ "keywords": [
58
+ "sigx",
59
+ "signalx",
60
+ "terminal",
61
+ "tui",
62
+ "cli",
63
+ "components",
64
+ "design-system"
65
+ ],
66
+ "author": "Andreas Ekdahl",
67
+ "license": "MIT",
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "git+https://github.com/signalxjs/terminal.git",
71
+ "directory": "packages/terminal-ui"
72
+ },
73
+ "homepage": "https://github.com/signalxjs/terminal/tree/main/packages/terminal-ui",
74
+ "bugs": {
75
+ "url": "https://github.com/signalxjs/terminal/issues"
76
+ },
77
+ "dependencies": {
78
+ "@sigx/reactivity": "^0.4.9",
79
+ "@sigx/runtime-core": "^0.4.9",
80
+ "@sigx/terminal-zero": "^0.5.0"
81
+ },
82
+ "devDependencies": {
83
+ "@sigx/vite": "^0.4.7",
84
+ "@types/node": "^22.0.0",
85
+ "typescript": "^5.9.3",
86
+ "vite": "^8.0.3"
87
+ },
88
+ "publishConfig": {
89
+ "access": "public"
90
+ },
91
+ "scripts": {
92
+ "build": "vite build && tsgo --emitDeclarationOnly",
93
+ "dev": "vite build --watch"
94
+ }
95
+ }