@sigx/runtime-terminal 0.2.1 → 0.2.2

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/index.js CHANGED
@@ -1,38 +1,32 @@
1
- import { createRenderer, setDefaultMount } from "@sigx/runtime-core/internals";
2
- import { signal } from "@sigx/reactivity";
3
- import { component, onMounted, onUnmounted, signal as signal$1 } from "@sigx/runtime-core";
4
- import { jsx, jsxs } from "@sigx/runtime-core/jsx-runtime";
1
+ import { createRenderer as e, setDefaultMount as t } from "@sigx/runtime-core/internals";
2
+ import { signal as n } from "@sigx/reactivity";
3
+ import { component as r, onMounted as i, onUnmounted as a, signal as o } from "@sigx/runtime-core";
4
+ import { jsx as s, jsxs as c } from "@sigx/runtime-core/jsx-runtime";
5
5
  //#region src/focus.ts
6
- var focusableIds = /* @__PURE__ */ new Set();
7
- var focusState = signal({ activeId: null });
8
- function registerFocusable(id) {
9
- focusableIds.add(id);
10
- if (focusState.activeId === null) focusState.activeId = id;
6
+ var l = /* @__PURE__ */ new Set(), u = n({ activeId: null });
7
+ function d(e) {
8
+ l.add(e), u.activeId === null && (u.activeId = e);
11
9
  }
12
- function unregisterFocusable(id) {
13
- focusableIds.delete(id);
14
- if (focusState.activeId === id) {
15
- focusState.activeId = null;
16
- if (focusableIds.size > 0) focusState.activeId = focusableIds.values().next().value || null;
17
- }
10
+ function f(e) {
11
+ l.delete(e), u.activeId === e && (u.activeId = null, l.size > 0 && (u.activeId = l.values().next().value || null));
18
12
  }
19
- function focus(id) {
20
- if (focusableIds.has(id)) focusState.activeId = id;
13
+ function p(e) {
14
+ l.has(e) && (u.activeId = e);
21
15
  }
22
- function focusNext() {
23
- if (focusableIds.size === 0) return;
24
- const ids = Array.from(focusableIds);
25
- focusState.activeId = ids[((focusState.activeId ? ids.indexOf(focusState.activeId) : -1) + 1) % ids.length];
16
+ function m() {
17
+ if (l.size === 0) return;
18
+ let e = Array.from(l);
19
+ u.activeId = e[((u.activeId ? e.indexOf(u.activeId) : -1) + 1) % e.length];
26
20
  }
27
- function focusPrev() {
28
- if (focusableIds.size === 0) return;
29
- const ids = Array.from(focusableIds);
30
- focusState.activeId = ids[((focusState.activeId ? ids.indexOf(focusState.activeId) : -1) - 1 + ids.length) % ids.length];
21
+ function h() {
22
+ if (l.size === 0) return;
23
+ let e = Array.from(l);
24
+ u.activeId = e[((u.activeId ? e.indexOf(u.activeId) : -1) - 1 + e.length) % e.length];
31
25
  }
32
26
  //#endregion
33
27
  //#region src/utils.ts
34
- function getColorCode(color) {
35
- switch (color) {
28
+ function g(e) {
29
+ switch (e) {
36
30
  case "red": return "\x1B[31m";
37
31
  case "green": return "\x1B[32m";
38
32
  case "blue": return "\x1B[34m";
@@ -43,8 +37,8 @@ function getColorCode(color) {
43
37
  default: return "";
44
38
  }
45
39
  }
46
- function getBackgroundColorCode(color) {
47
- switch (color) {
40
+ function _(e) {
41
+ switch (e) {
48
42
  case "red": return "\x1B[41m";
49
43
  case "green": return "\x1B[42m";
50
44
  case "blue": return "\x1B[44m";
@@ -55,431 +49,284 @@ function getBackgroundColorCode(color) {
55
49
  default: return "";
56
50
  }
57
51
  }
58
- function stripAnsi(str) {
59
- return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
52
+ function v(e) {
53
+ return e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
60
54
  }
61
55
  //#endregion
62
56
  //#region src/components/Input.tsx
63
- /** @jsxImportSource @sigx/runtime-core */
64
- var Input = component(({ props, emit }) => {
65
- const id = Math.random().toString(36).slice(2);
66
- let isReady = false;
67
- const isFocused = () => focusState.activeId === id;
68
- const getValue = () => props.model?.value || "";
69
- const handleKey = (key) => {
70
- if (!isFocused()) return;
71
- if (!isReady) return;
72
- if (key === "\r") {
73
- emit("submit", getValue());
57
+ var y = r(({ props: e, emit: t }) => {
58
+ let n = Math.random().toString(36).slice(2), r = !1, o = () => u.activeId === n, l = () => e.model?.value || "", m = (n) => {
59
+ if (!o() || !r) return;
60
+ if (n === "\r") {
61
+ t("submit", l());
74
62
  return;
75
63
  }
76
- if (key === "\n") return;
77
- if (key === "" || key === "\b") {
78
- const val = getValue();
79
- if (val.length > 0) {
80
- const newValue = val.slice(0, -1);
81
- if (props.model) props.model.value = newValue;
82
- emit("input", newValue);
64
+ if (n === "\n") return;
65
+ if (n === "" || n === "\b") {
66
+ let n = l();
67
+ if (n.length > 0) {
68
+ let r = n.slice(0, -1);
69
+ e.model && (e.model.value = r), t("input", r);
83
70
  }
84
71
  return;
85
72
  }
86
- if (key.length > 1) return;
87
- const newValue = getValue() + key;
88
- if (props.model) props.model.value = newValue;
89
- emit("input", newValue);
90
- };
91
- let keyCleanup = null;
92
- onMounted(() => {
93
- registerFocusable(id);
94
- if (props.autofocus) focus(id);
95
- keyCleanup = onKey(handleKey);
96
- setTimeout(() => {
97
- isReady = true;
73
+ if (n.length > 1) return;
74
+ let i = l() + n;
75
+ e.model && (e.model.value = i), t("input", i);
76
+ }, h = null;
77
+ return i(() => {
78
+ d(n), e.autofocus && p(n), h = P(m), setTimeout(() => {
79
+ r = !0;
98
80
  }, 50);
99
- });
100
- onUnmounted(() => {
101
- if (keyCleanup) keyCleanup();
102
- unregisterFocusable(id);
103
- });
104
- return () => {
105
- const val = getValue().replace(/[\r\n]+/g, " ");
106
- const placeholder = (props.placeholder || "").replace(/[\r\n]+/g, " ");
107
- const showCursor = isFocused();
108
- return /* @__PURE__ */ jsxs("box", {
81
+ }), a(() => {
82
+ h && h(), f(n);
83
+ }), () => {
84
+ let t = l().replace(/[\r\n]+/g, " "), n = (e.placeholder || "").replace(/[\r\n]+/g, " "), r = o();
85
+ return /* @__PURE__ */ c("box", {
109
86
  border: "single",
110
- borderColor: showCursor ? "green" : "white",
111
- label: props.label,
112
- children: [/* @__PURE__ */ jsx("text", { children: val || placeholder }), showCursor && /* @__PURE__ */ jsx("text", {
87
+ borderColor: r ? "green" : "white",
88
+ label: e.label,
89
+ children: [/* @__PURE__ */ s("text", { children: t || n }), r && /* @__PURE__ */ s("text", {
113
90
  color: "cyan",
114
91
  children: "_"
115
92
  })]
116
93
  });
117
94
  };
118
- }, { name: "Input" });
119
- //#endregion
120
- //#region src/components/ProgressBar.tsx
121
- /** @jsxImportSource @sigx/runtime-core */
122
- var ProgressBar = component(({ props }) => {
123
- return () => {
124
- const value = props.value || 0;
125
- const max = props.max || 100;
126
- const width = props.width || 20;
127
- const barChar = props.char || "█";
128
- const emptyChar = props.emptyChar || "░";
129
- const color = props.color;
130
- const colorCode = color ? getColorCode(color) : "";
131
- const reset = color ? "\x1B[0m" : "";
132
- const percentage = Math.min(Math.max(value / max, 0), 1);
133
- const filledLen = Math.round(width * percentage);
134
- const emptyLen = width - filledLen;
135
- return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsx("text", { children: colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset + ` ${Math.round(percentage * 100)}%` }) });
136
- };
137
- }, { name: "ProgressBar" });
138
- //#endregion
139
- //#region src/components/Button.tsx
140
- /** @jsxImportSource @sigx/runtime-core */
141
- var Button = component(({ props, emit }) => {
142
- const id = Math.random().toString(36).slice(2);
143
- const isFocused = () => focusState.activeId === id;
144
- const pressed = signal$1({ value: false });
145
- const handleKey = (key) => {
146
- if (!isFocused()) return;
147
- if (key === "\r" || key === " ") {
148
- pressed.value = true;
149
- if (pressTimer) clearTimeout(pressTimer);
150
- pressTimer = setTimeout(() => {
151
- pressed.value = false;
152
- pressTimer = null;
153
- }, 120);
154
- emit("click");
155
- }
156
- };
157
- let keyCleanup = null;
158
- let pressTimer = null;
159
- onMounted(() => {
160
- registerFocusable(id);
161
- keyCleanup = onKey(handleKey);
162
- });
163
- onUnmounted(() => {
164
- if (keyCleanup) keyCleanup();
165
- unregisterFocusable(id);
166
- if (pressTimer) clearTimeout(pressTimer);
167
- });
168
- return () => {
169
- const focused = isFocused();
170
- const label = props.label || "Button";
171
- const isPressed = pressed.value;
172
- return /* @__PURE__ */ jsx("box", {
95
+ }, { name: "Input" }), b = r(({ props: e }) => () => {
96
+ let t = e.value || 0, n = e.max || 100, r = e.width || 20, i = e.char || "█", a = e.emptyChar || "░", o = e.color, c = o ? g(o) : "", l = o ? "\x1B[0m" : "", u = Math.min(Math.max(t / n, 0), 1), d = Math.round(r * u), f = r - d;
97
+ return /* @__PURE__ */ s("box", { children: /* @__PURE__ */ s("text", { children: c + i.repeat(d) + a.repeat(f) + l + ` ${Math.round(u * 100)}%` }) });
98
+ }, { name: "ProgressBar" }), x = r(({ props: e, emit: t }) => {
99
+ let n = Math.random().toString(36).slice(2), r = () => u.activeId === n, c = o({ value: !1 }), l = (e) => {
100
+ r() && (e === "\r" || e === " ") && (c.value = !0, m && clearTimeout(m), m = setTimeout(() => {
101
+ c.value = !1, m = null;
102
+ }, 120), t("click"));
103
+ }, p = null, m = null;
104
+ return i(() => {
105
+ d(n), p = P(l);
106
+ }), a(() => {
107
+ p && p(), f(n), m && clearTimeout(m);
108
+ }), () => {
109
+ let t = r(), n = e.label || "Button", i = c.value;
110
+ return /* @__PURE__ */ s("box", {
173
111
  border: "single",
174
- borderColor: isPressed ? "yellow" : focused ? "green" : "white",
175
- backgroundColor: isPressed ? "red" : focused ? "blue" : void 0,
176
- dropShadow: props.dropShadow,
177
- children: /* @__PURE__ */ jsx("text", {
178
- color: focused ? "white" : void 0,
179
- children: label
112
+ borderColor: i ? "yellow" : t ? "green" : "white",
113
+ backgroundColor: i ? "red" : t ? "blue" : void 0,
114
+ dropShadow: e.dropShadow,
115
+ children: /* @__PURE__ */ s("text", {
116
+ color: t ? "white" : void 0,
117
+ children: n
180
118
  })
181
119
  });
182
120
  };
183
- }, { name: "Button" });
184
- //#endregion
185
- //#region src/components/Checkbox.tsx
186
- /** @jsxImportSource @sigx/runtime-core */
187
- var Checkbox = component(({ props, emit }) => {
188
- const id = Math.random().toString(36).slice(2);
189
- const isFocused = () => focusState.activeId === id;
190
- const checked = () => !!props.model?.value;
191
- const handleKey = (key) => {
192
- if (!isFocused()) return;
193
- if (props.disabled) return;
194
- if (key === "\r" || key === " ") {
195
- const next = !checked();
196
- if (props.model) props.model.value = next;
197
- emit("change", next);
121
+ }, { name: "Button" }), S = r(({ props: e, emit: t }) => {
122
+ let n = Math.random().toString(36).slice(2), r = () => u.activeId === n, o = () => !!e.model?.value, l = (n) => {
123
+ if (r() && !e.disabled && (n === "\r" || n === " ")) {
124
+ let n = !o();
125
+ e.model && (e.model.value = n), t("change", n);
198
126
  }
199
- };
200
- let keyCleanup = null;
201
- onMounted(() => {
202
- registerFocusable(id);
203
- if (props.autofocus) focus(id);
204
- keyCleanup = onKey(handleKey);
205
- });
206
- onUnmounted(() => {
207
- if (keyCleanup) keyCleanup();
208
- unregisterFocusable(id);
209
- });
210
- return () => {
211
- const label = props.label || "";
212
- const focused = isFocused();
213
- const isChecked = checked();
214
- const disabled = !!props.disabled;
215
- return /* @__PURE__ */ jsxs("box", { children: [
216
- /* @__PURE__ */ jsx("text", {
217
- color: focused ? "cyan" : "white",
218
- children: focused ? ">" : " "
127
+ }, m = null;
128
+ return i(() => {
129
+ d(n), e.autofocus && p(n), m = P(l);
130
+ }), a(() => {
131
+ m && m(), f(n);
132
+ }), () => {
133
+ let t = e.label || "", n = r(), i = o(), a = !!e.disabled;
134
+ return /* @__PURE__ */ c("box", { children: [
135
+ /* @__PURE__ */ s("text", {
136
+ color: n ? "cyan" : "white",
137
+ children: n ? ">" : " "
219
138
  }),
220
- /* @__PURE__ */ jsxs("text", {
221
- color: disabled ? "white" : isChecked ? "green" : focused ? "cyan" : "white",
139
+ /* @__PURE__ */ c("text", {
140
+ color: a ? "white" : i ? "green" : n ? "cyan" : "white",
222
141
  children: [
223
142
  "[",
224
- isChecked ? "x" : " ",
143
+ i ? "x" : " ",
225
144
  "]"
226
145
  ]
227
146
  }),
228
- label && /* @__PURE__ */ jsxs("text", {
229
- color: disabled ? "white" : focused ? "cyan" : void 0,
230
- children: [" ", label]
147
+ t && /* @__PURE__ */ c("text", {
148
+ color: a ? "white" : n ? "cyan" : void 0,
149
+ children: [" ", t]
231
150
  })
232
151
  ] });
233
152
  };
234
- }, { name: "Checkbox" });
235
- //#endregion
236
- //#region src/components/Select.tsx
237
- /** @jsxImportSource @sigx/runtime-core */
238
- var Select = component(({ props, emit }) => {
239
- const id = Math.random().toString(36).slice(2);
240
- let isReady = false;
241
- const isFocused = () => focusState.activeId === id;
242
- const getCurrentIndex = () => {
243
- const idx = (props.options || []).findIndex((o) => o.value === props.model?.value);
244
- return idx >= 0 ? idx : 0;
245
- };
246
- const handleKey = (key) => {
247
- if (!isFocused()) return;
248
- if (!isReady) return;
249
- const options = props.options || [];
250
- if (options.length === 0) return;
251
- const currentIndex = getCurrentIndex();
252
- if (key === "\x1B[A" || key === "k") {
253
- const newValue = options[currentIndex > 0 ? currentIndex - 1 : options.length - 1].value;
254
- if (props.model) props.model.value = newValue;
255
- emit("change", newValue);
153
+ }, { name: "Checkbox" }), C = r(({ props: e, emit: t }) => {
154
+ let n = Math.random().toString(36).slice(2), r = !1, o = () => u.activeId === n, l = () => {
155
+ let t = (e.options || []).findIndex((t) => t.value === e.model?.value);
156
+ return t >= 0 ? t : 0;
157
+ }, m = (n) => {
158
+ if (!o() || !r) return;
159
+ let i = e.options || [];
160
+ if (i.length === 0) return;
161
+ let a = l();
162
+ if (n === "\x1B[A" || n === "k") {
163
+ let n = i[a > 0 ? a - 1 : i.length - 1].value;
164
+ e.model && (e.model.value = n), t("change", n);
256
165
  return;
257
166
  }
258
- if (key === "\x1B[B" || key === "j") {
259
- const newValue = options[currentIndex < options.length - 1 ? currentIndex + 1 : 0].value;
260
- if (props.model) props.model.value = newValue;
261
- emit("change", newValue);
167
+ if (n === "\x1B[B" || n === "j") {
168
+ let n = i[a < i.length - 1 ? a + 1 : 0].value;
169
+ e.model && (e.model.value = n), t("change", n);
262
170
  return;
263
171
  }
264
- if (key === "\r") {
265
- emit("submit", props.model?.value || options[0]?.value || "");
172
+ if (n === "\r") {
173
+ t("submit", e.model?.value || i[0]?.value || "");
266
174
  return;
267
175
  }
268
- };
269
- let keyCleanup = null;
270
- onMounted(() => {
271
- registerFocusable(id);
272
- if (props.autofocus) focus(id);
273
- keyCleanup = onKey(handleKey);
274
- setTimeout(() => {
275
- isReady = true;
176
+ }, h = null;
177
+ return i(() => {
178
+ d(n), e.autofocus && p(n), h = P(m), setTimeout(() => {
179
+ r = !0;
276
180
  }, 50);
277
- });
278
- onUnmounted(() => {
279
- if (keyCleanup) keyCleanup();
280
- unregisterFocusable(id);
281
- });
282
- return () => {
283
- const options = props.options || [];
284
- const focused = isFocused();
285
- const currentValue = props.model?.value || options[0]?.value || "";
286
- const label = props.label;
287
- const selectedOption = options.find((o) => o.value === currentValue);
288
- const optionElements = options.map((option) => {
289
- const isSelected = option.value === currentValue;
290
- return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsxs("text", {
291
- color: isSelected ? "cyan" : "white",
181
+ }), a(() => {
182
+ h && h(), f(n);
183
+ }), () => {
184
+ let t = e.options || [], n = o(), r = e.model?.value || t[0]?.value || "", i = e.label, a = t.find((e) => e.value === r), l = t.map((e) => {
185
+ let t = e.value === r;
186
+ return /* @__PURE__ */ s("box", { children: /* @__PURE__ */ c("text", {
187
+ color: t ? "cyan" : "white",
292
188
  children: [
293
- isSelected ? "❯" : " ",
189
+ t ? "❯" : " ",
294
190
  " ",
295
- option.label
191
+ e.label
296
192
  ]
297
193
  }) });
298
- });
299
- const descriptionElement = props.showDescription && selectedOption?.description ? /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsxs("text", {
194
+ }), u = e.showDescription && a?.description ? /* @__PURE__ */ s("box", { children: /* @__PURE__ */ c("text", {
300
195
  color: "#666666",
301
- children: [" ↳ ", selectedOption.description]
196
+ children: [" ↳ ", a.description]
302
197
  }) }) : null;
303
- return /* @__PURE__ */ jsxs("box", { children: [/* @__PURE__ */ jsx("box", {
198
+ return /* @__PURE__ */ c("box", { children: [/* @__PURE__ */ s("box", {
304
199
  border: "single",
305
- borderColor: focused ? "green" : "white",
306
- label,
307
- children: optionElements
308
- }), descriptionElement] });
200
+ borderColor: n ? "green" : "white",
201
+ label: i,
202
+ children: l
203
+ }), u] });
309
204
  };
310
- }, { name: "Select" });
311
- var { render } = createRenderer({
312
- patchProp: (el, key, prev, next) => {
313
- el.props[key] = next;
314
- scheduleRender();
205
+ }, { name: "Select" }), { render: w } = e({
206
+ patchProp: (e, t, n, r) => {
207
+ e.props[t] = r, D();
315
208
  },
316
- insert: (child, parent, anchor) => {
317
- child.parentNode = parent;
318
- const index = anchor ? parent.children.indexOf(anchor) : -1;
319
- if (index > -1) parent.children.splice(index, 0, child);
320
- else parent.children.push(child);
321
- scheduleRender();
209
+ insert: (e, t, n) => {
210
+ e.parentNode = t;
211
+ let r = n ? t.children.indexOf(n) : -1;
212
+ r > -1 ? t.children.splice(r, 0, e) : t.children.push(e), D();
322
213
  },
323
- remove: (child) => {
324
- if (child.parentNode) {
325
- const index = child.parentNode.children.indexOf(child);
326
- if (index > -1) child.parentNode.children.splice(index, 1);
327
- child.parentNode = null;
214
+ remove: (e) => {
215
+ if (e.parentNode) {
216
+ let t = e.parentNode.children.indexOf(e);
217
+ t > -1 && e.parentNode.children.splice(t, 1), e.parentNode = null;
328
218
  }
329
- scheduleRender();
330
- },
331
- createElement: (tag) => {
332
- return {
333
- type: "element",
334
- tag,
335
- props: {},
336
- children: []
337
- };
219
+ D();
338
220
  },
339
- createText: (text) => {
340
- return {
341
- type: "text",
342
- text,
343
- props: {},
344
- children: []
345
- };
346
- },
347
- createComment: (text) => {
348
- return {
349
- type: "comment",
350
- text,
351
- props: {},
352
- children: []
353
- };
354
- },
355
- setText: (node, text) => {
356
- node.text = text;
357
- scheduleRender();
221
+ createElement: (e) => ({
222
+ type: "element",
223
+ tag: e,
224
+ props: {},
225
+ children: []
226
+ }),
227
+ createText: (e) => ({
228
+ type: "text",
229
+ text: e,
230
+ props: {},
231
+ children: []
232
+ }),
233
+ createComment: (e) => ({
234
+ type: "comment",
235
+ text: e,
236
+ props: {},
237
+ children: []
238
+ }),
239
+ setText: (e, t) => {
240
+ e.text = t, D();
358
241
  },
359
- setElementText: (node, text) => {
360
- node.children = [{
242
+ setElementText: (e, t) => {
243
+ e.children = [{
361
244
  type: "text",
362
- text,
245
+ text: t,
363
246
  props: {},
364
247
  children: [],
365
- parentNode: node
366
- }];
367
- scheduleRender();
248
+ parentNode: e
249
+ }], D();
368
250
  },
369
- parentNode: (node) => node.parentNode || null,
370
- nextSibling: (node) => {
371
- if (!node.parentNode) return null;
372
- const idx = node.parentNode.children.indexOf(node);
373
- return node.parentNode.children[idx + 1] || null;
251
+ parentNode: (e) => e.parentNode || null,
252
+ nextSibling: (e) => {
253
+ if (!e.parentNode) return null;
254
+ let t = e.parentNode.children.indexOf(e);
255
+ return e.parentNode.children[t + 1] || null;
374
256
  },
375
- cloneNode: (node) => {
376
- return {
377
- ...node,
378
- children: []
379
- };
380
- }
381
- });
382
- var rootNode = null;
383
- var isRendering = false;
384
- function scheduleRender() {
385
- if (isRendering) return;
386
- isRendering = true;
387
- setTimeout(() => {
388
- flushRender();
389
- isRendering = false;
390
- }, 10);
257
+ cloneNode: (e) => ({
258
+ ...e,
259
+ children: []
260
+ })
261
+ }), T = null, E = !1;
262
+ function D() {
263
+ E || (E = !0, setTimeout(() => {
264
+ O(), E = !1;
265
+ }, 10));
391
266
  }
392
- function flushRender() {
393
- if (!rootNode) return;
267
+ function O() {
268
+ if (!T) return;
394
269
  process.stdout.write("\x1B[H");
395
- const lines = renderNodeToLines(rootNode);
396
- process.stdout.write(lines.join("\x1B[K\n") + "\x1B[K");
397
- process.stdout.write("\x1B[J");
270
+ let e = A(T);
271
+ process.stdout.write(e.join("\x1B[K\n") + "\x1B[K"), process.stdout.write("\x1B[J");
398
272
  }
399
- /**
400
- * Check if a node has a box element as an immediate child.
401
- * This is used to determine if a component wrapper should be treated as a block element.
402
- */
403
- function hasBoxChild(node) {
404
- for (const child of node.children) if (child.tag === "box") return true;
405
- return false;
273
+ function k(e) {
274
+ for (let t of e.children) if (t.tag === "box") return !0;
275
+ return !1;
406
276
  }
407
- function renderNodeToLines(node) {
408
- if (node.type === "text") return [node.text || ""];
409
- if (node.type === "comment") return [];
410
- let lines = [""];
411
- const color = node.props.color;
412
- const reset = color ? "\x1B[0m" : "";
413
- const colorCode = getColorCode(color);
414
- for (const child of node.children) if (child.type === "text") lines[lines.length - 1] += colorCode + (child.text || "") + reset;
415
- else if (child.tag === "br") lines.push("");
277
+ function A(e) {
278
+ if (e.type === "text") return [e.text || ""];
279
+ if (e.type === "comment") return [];
280
+ let t = [""], n = e.props.color, r = n ? "\x1B[0m" : "", i = g(n);
281
+ for (let n of e.children) if (n.type === "text") t[t.length - 1] += i + (n.text || "") + r;
282
+ else if (n.tag === "br") t.push("");
416
283
  else {
417
- const childLines = renderNodeToLines(child);
418
- if (child.tag === "box" || hasBoxChild(child)) if (lines.length === 1 && lines[0] === "") lines = childLines;
419
- else lines.push(...childLines);
420
- else if (childLines.length > 0) if (childLines.length > 1) if (lines.length === 1 && lines[0] === "") lines = childLines;
421
- else lines.push(...childLines);
284
+ let e = A(n);
285
+ if (n.tag === "box" || k(n)) t.length === 1 && t[0] === "" ? t = e : t.push(...e);
286
+ else if (e.length > 0) if (e.length > 1) t.length === 1 && t[0] === "" ? t = e : t.push(...e);
422
287
  else {
423
- lines[lines.length - 1] += childLines[0];
424
- for (let i = 1; i < childLines.length; i++) lines.push(childLines[i]);
288
+ t[t.length - 1] += e[0];
289
+ for (let n = 1; n < e.length; n++) t.push(e[n]);
425
290
  }
426
291
  }
427
- if (node.tag === "box" && node.props.border) return drawBox(lines, node.props.border, node.props.borderColor, node.props.backgroundColor, node.props.dropShadow, node.props.label);
428
- return lines;
292
+ return e.tag === "box" && e.props.border ? j(t, e.props.border, e.props.borderColor, e.props.backgroundColor, e.props.dropShadow, e.props.label) : t;
429
293
  }
430
- function drawBox(contentLines, style, color, backgroundColor, dropShadow, label) {
431
- const borderChars = getBorderChars(style);
432
- const colorCode = color ? getColorCode(color) : "";
433
- const bgCode = backgroundColor ? getBackgroundColorCode(backgroundColor) : "";
434
- const reset = color || backgroundColor ? "\x1B[0m" : "";
435
- const width = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);
436
- const labelText = label || "";
437
- const labelLength = stripAnsi(labelText).length;
438
- const boxInnerWidth = Math.max(width, labelLength + 2);
439
- let topInner = "";
440
- if (labelText) {
441
- const spaceForLabel = boxInnerWidth - labelLength - 2;
442
- const leftH = Math.floor(spaceForLabel / 2);
443
- const rightH = spaceForLabel - leftH;
444
- topInner = borderChars.h.repeat(leftH) + " " + labelText + " " + borderChars.h.repeat(rightH);
445
- } else topInner = borderChars.h.repeat(boxInnerWidth);
446
- const top = bgCode + colorCode + borderChars.tl + topInner + borderChars.tr + reset;
447
- const bottom = bgCode + colorCode + borderChars.bl + borderChars.h.repeat(boxInnerWidth) + borderChars.br + reset;
448
- const result = [];
449
- result.push(top);
450
- for (const line of contentLines) {
451
- const visibleLength = stripAnsi(line).length;
452
- const padding = " ".repeat(boxInnerWidth - visibleLength);
453
- const lineWithBg = bgCode + line.replace(/\x1b\[0m/g, `\x1b[0m${bgCode}`);
454
- result.push(bgCode + colorCode + borderChars.v + reset + lineWithBg + bgCode + padding + colorCode + borderChars.v + reset);
294
+ function j(e, t, n, r, i, a) {
295
+ let o = M(t), s = n ? g(n) : "", c = r ? _(r) : "", l = n || r ? "\x1B[0m" : "", u = e.reduce((e, t) => Math.max(e, v(t).length), 0), d = a || "", f = v(d).length, p = Math.max(u, f + 2), m = "";
296
+ if (d) {
297
+ let e = p - f - 2, t = Math.floor(e / 2), n = e - t;
298
+ m = o.h.repeat(t) + " " + d + " " + o.h.repeat(n);
299
+ } else m = o.h.repeat(p);
300
+ let h = c + s + o.tl + m + o.tr + l, y = c + s + o.bl + o.h.repeat(p) + o.br + l, b = [];
301
+ b.push(h);
302
+ for (let t of e) {
303
+ let e = v(t).length, n = " ".repeat(p - e), r = c + t.replace(/\x1b\[0m/g, `\x1b[0m${c}`);
304
+ b.push(c + s + o.v + l + r + c + n + s + o.v + l);
455
305
  }
456
- result.push(bottom);
457
- if (dropShadow) {
458
- const shadowBlock = "\x1B[90m▒\x1B[0m";
459
- for (let i = 1; i < result.length; i++) result[i] += shadowBlock;
460
- const bottomShadow = " " + shadowBlock.repeat(width + 2);
461
- result.push(bottomShadow);
306
+ if (b.push(y), i) {
307
+ let e = "\x1B[90m▒\x1B[0m";
308
+ for (let t = 1; t < b.length; t++) b[t] += e;
309
+ let t = " " + e.repeat(u + 2);
310
+ b.push(t);
462
311
  }
463
- return result;
312
+ return b;
464
313
  }
465
- function getBorderChars(style) {
466
- if (style === "double") return {
314
+ function M(e) {
315
+ return e === "double" ? {
467
316
  tl: "╔",
468
317
  tr: "╗",
469
318
  bl: "╚",
470
319
  br: "╝",
471
320
  h: "═",
472
321
  v: "║"
473
- };
474
- if (style === "rounded") return {
322
+ } : e === "rounded" ? {
475
323
  tl: "╭",
476
324
  tr: "╮",
477
325
  bl: "╰",
478
326
  br: "╯",
479
327
  h: "─",
480
328
  v: "│"
481
- };
482
- return {
329
+ } : {
483
330
  tl: "┌",
484
331
  tr: "┐",
485
332
  bl: "└",
@@ -488,126 +335,58 @@ function getBorderChars(style) {
488
335
  v: "│"
489
336
  };
490
337
  }
491
- var keyHandlers = /* @__PURE__ */ new Set();
492
- function onKey(handler) {
493
- keyHandlers.add(handler);
494
- return () => keyHandlers.delete(handler);
338
+ var N = /* @__PURE__ */ new Set();
339
+ function P(e) {
340
+ return N.add(e), () => N.delete(e);
495
341
  }
496
- function handleInput(key) {
497
- if (key === "") {
498
- process.stdout.write("\x1B[?25h");
499
- process.exit();
500
- }
501
- if (key === " ") {
502
- focusNext();
342
+ function F(e) {
343
+ if (e === "" && (process.stdout.write("\x1B[?25h"), process.exit()), e === " ") {
344
+ m();
503
345
  return;
504
346
  }
505
- if (key === "\x1B[Z") {
506
- focusPrev();
347
+ if (e === "\x1B[Z") {
348
+ h();
507
349
  return;
508
350
  }
509
- for (const handler of keyHandlers) handler(key);
351
+ for (let t of N) t(e);
510
352
  }
511
- function renderTerminal(app, options = {}) {
512
- rootNode = {
353
+ function I(e, t = {}) {
354
+ T = {
513
355
  type: "root",
514
356
  props: {},
515
357
  children: []
516
358
  };
517
- const container = rootNode;
518
- if (process.stdin.isTTY) {
519
- process.stdin.setRawMode(true);
520
- process.stdin.resume();
521
- process.stdin.setEncoding("utf8");
522
- process.stdin.on("data", handleInput);
523
- }
524
- if (options.clearConsole) process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
525
- process.stdout.write("\x1B[?25l");
526
- render(app, container);
527
- flushRender();
528
- return { unmount: () => {
529
- render(null, container);
530
- process.stdout.write("\x1B[?25h");
531
- if (process.stdin.isTTY) {
532
- process.stdin.setRawMode(false);
533
- process.stdin.pause();
534
- process.stdin.off("data", handleInput);
535
- }
359
+ let n = T;
360
+ return process.stdin.isTTY && (process.stdin.setRawMode(!0), process.stdin.resume(), process.stdin.setEncoding("utf8"), process.stdin.on("data", F)), t.clearConsole && process.stdout.write("\x1B[2J\x1B[3J\x1B[H"), process.stdout.write("\x1B[?25l"), w(e, n), O(), { unmount: () => {
361
+ w(null, n), process.stdout.write("\x1B[?25h"), process.stdin.isTTY && (process.stdin.setRawMode(!1), process.stdin.pause(), process.stdin.off("data", F));
536
362
  } };
537
363
  }
538
- var unmountFn = null;
539
- /**
540
- * Helper function to mount the terminal for CLI apps.
541
- * Returns a mount target that can be passed to defineApp().mount().
542
- *
543
- * @example
544
- * ```tsx
545
- * defineApp(MyApp).mount(mountTerminal());
546
- * ```
547
- */
548
- function mountTerminal(options = { clearConsole: true }) {
364
+ var L = null;
365
+ function R(e = { clearConsole: !0 }) {
549
366
  return {
550
- mount: terminalMount,
551
- options,
552
- onMount: (unmount) => {
553
- unmountFn = unmount;
367
+ mount: B,
368
+ options: e,
369
+ onMount: (e) => {
370
+ L = e;
554
371
  }
555
372
  };
556
373
  }
557
- /**
558
- * Exit the terminal app cleanly, restoring terminal state.
559
- */
560
- function exitTerminal() {
561
- if (unmountFn) {
562
- unmountFn();
563
- unmountFn = null;
564
- }
565
- process.stdout.write("\x1B[?25h");
566
- process.stdout.write("\x1B[2J\x1B[H");
374
+ function z() {
375
+ L &&= (L(), null), process.stdout.write("\x1B[?25h"), process.stdout.write("\x1B[2J\x1B[H");
567
376
  }
568
- /**
569
- * Mount function for Terminal environments.
570
- * Use this with defineApp().mount() to render to the terminal.
571
- *
572
- * @example
573
- * ```tsx
574
- * import { defineApp } from '@sigx/runtime-core';
575
- * import { terminalMount } from '@sigx/runtime-terminal';
576
- *
577
- * const app = defineApp(<Counter />);
578
- * app.use(loggingPlugin)
579
- * .mount({ clearConsole: true }, terminalMount);
580
- * ```
581
- */
582
- var terminalMount = (component, options, appContext) => {
583
- rootNode = {
377
+ var B = (e, t, n) => {
378
+ T = {
584
379
  type: "root",
585
380
  props: {},
586
381
  children: []
587
382
  };
588
- const container = rootNode;
589
- if (process.stdin.isTTY) {
590
- process.stdin.setRawMode(true);
591
- process.stdin.resume();
592
- process.stdin.setEncoding("utf8");
593
- process.stdin.on("data", handleInput);
594
- }
595
- if (options?.clearConsole) process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
596
- process.stdout.write("\x1B[?25l");
597
- render(component, container, appContext);
598
- flushRender();
599
- return () => {
600
- render(null, container);
601
- process.stdout.write("\x1B[?25h");
602
- if (process.stdin.isTTY) {
603
- process.stdin.setRawMode(false);
604
- process.stdin.pause();
605
- process.stdin.off("data", handleInput);
606
- }
383
+ let r = T;
384
+ return process.stdin.isTTY && (process.stdin.setRawMode(!0), process.stdin.resume(), process.stdin.setEncoding("utf8"), process.stdin.on("data", F)), t?.clearConsole && process.stdout.write("\x1B[2J\x1B[3J\x1B[H"), process.stdout.write("\x1B[?25l"), w(e, r, n), O(), () => {
385
+ w(null, r), process.stdout.write("\x1B[?25h"), process.stdin.isTTY && (process.stdin.setRawMode(!1), process.stdin.pause(), process.stdin.off("data", F));
607
386
  };
608
387
  };
609
- setDefaultMount(terminalMount);
388
+ t(B);
610
389
  //#endregion
611
- export { Button, Checkbox, Input, ProgressBar, Select, exitTerminal, focus, focusNext, focusPrev, focusState, mountTerminal, onKey, registerFocusable, render, renderNodeToLines, renderTerminal, terminalMount, unregisterFocusable };
390
+ export { x as Button, S as Checkbox, y as Input, b as ProgressBar, C as Select, z as exitTerminal, p as focus, m as focusNext, h as focusPrev, u as focusState, R as mountTerminal, P as onKey, d as registerFocusable, w as render, A as renderNodeToLines, I as renderTerminal, B as terminalMount, f as unregisterFocusable };
612
391
 
613
392
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/focus.ts","../src/utils.ts","../src/components/Input.tsx","../src/components/ProgressBar.tsx","../src/components/Button.tsx","../src/components/Checkbox.tsx","../src/components/Select.tsx","../src/index.ts"],"sourcesContent":["import { signal } from '@sigx/reactivity';\r\n\r\nconst focusableIds = new Set<string>();\r\nexport const focusState = signal({ activeId: null as string | null });\r\n\r\nexport function registerFocusable(id: string) {\r\n focusableIds.add(id);\r\n if (focusState.activeId === null) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function unregisterFocusable(id: string) {\r\n focusableIds.delete(id);\r\n if (focusState.activeId === id) {\r\n focusState.activeId = null;\r\n // Try to focus another one\r\n if (focusableIds.size > 0) {\r\n focusState.activeId = focusableIds.values().next().value || null;\r\n }\r\n }\r\n}\r\n\r\nexport function focus(id: string) {\r\n if (focusableIds.has(id)) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function focusNext() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const nextIndex = (currentIndex + 1) % ids.length;\r\n focusState.activeId = ids[nextIndex];\r\n}\r\n\r\nexport function focusPrev() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const prevIndex = (currentIndex - 1 + ids.length) % ids.length;\r\n focusState.activeId = ids[prevIndex];\r\n}\r\n","\r\nexport function getColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[31m';\r\n case 'green': return '\\x1b[32m';\r\n case 'blue': return '\\x1b[34m';\r\n case 'yellow': return '\\x1b[33m';\r\n case 'cyan': return '\\x1b[36m';\r\n case 'white': return '\\x1b[37m';\r\n case 'black': return '\\x1b[30m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function getBackgroundColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[41m';\r\n case 'green': return '\\x1b[42m';\r\n case 'blue': return '\\x1b[44m';\r\n case 'yellow': return '\\x1b[43m';\r\n case 'cyan': return '\\x1b[46m';\r\n case 'white': return '\\x1b[47m';\r\n case 'black': return '\\x1b[40m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function stripAnsi(str: string): string {\r\n return str.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, '');\r\n}\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Input = component<\r\n Define.Model<string> &\r\n Define.Prop<\"placeholder\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Event<\"input\", string> &\r\n Define.Event<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getValue = () => props.model?.value || '';\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n if (key === '\\r') { // Enter\r\n emit('submit', getValue());\r\n return;\r\n }\r\n\r\n if (key === '\\n') return;\r\n\r\n if (key === '\\u007F' || key === '\\b') { // Backspace\r\n const val = getValue();\r\n if (val.length > 0) {\r\n const newValue = val.slice(0, -1);\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n }\r\n return;\r\n }\r\n\r\n // Ignore control characters\r\n if (key.length > 1) return;\r\n\r\n const newValue = getValue() + key;\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\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) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\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 val = getValue().replace(/[\\r\\n]+/g, ' ');\r\n const placeholder = (props.placeholder || '').replace(/[\\r\\n]+/g, ' ');\r\n const showCursor = isFocused();\r\n // console.log('Input render', { val, placeholder, showCursor });\r\n\r\n return (\r\n <box border=\"single\" borderColor={showCursor ? 'green' : 'white'} label={props.label}>\r\n <text>{val || placeholder}</text>\r\n {showCursor && <text color=\"cyan\">_</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Input' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, type Define } from '@sigx/runtime-core';\r\nimport { getColorCode } from '../utils';\r\n\r\nexport const ProgressBar = component<\r\n Define.Prop<\"value\", number, false> &\r\n Define.Prop<\"max\", number, false> &\r\n Define.Prop<\"width\", number, false> &\r\n Define.Prop<\"char\", string, false> &\r\n Define.Prop<\"emptyChar\", string, false> &\r\n Define.Prop<\"color\", string, false>\r\n>(({ props }) => {\r\n return () => {\r\n const value = props.value || 0;\r\n const max = props.max || 100;\r\n const width = props.width || 20;\r\n const barChar = props.char || '█';\r\n const emptyChar = props.emptyChar || '░';\r\n const color = props.color;\r\n const colorCode = color ? getColorCode(color) : '';\r\n const reset = color ? '\\x1b[0m' : '';\r\n\r\n const percentage = Math.min(Math.max(value / max, 0), 1);\r\n const filledLen = Math.round(width * percentage);\r\n const emptyLen = width - filledLen;\r\n\r\n const bar = colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset;\r\n const label = ` ${Math.round(percentage * 100)}%`;\r\n\r\n return (\r\n <box>\r\n <text>{bar + label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'ProgressBar' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState } from '../focus';\r\n\r\nexport const Button = component<\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"dropShadow\", boolean, false> &\r\n Define.Event<\"click\">\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const pressed = signal({ value: false });\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space\r\n // Visual press effect + emit click\r\n pressed.value = true as any;\r\n if (pressTimer) clearTimeout(pressTimer);\r\n pressTimer = setTimeout(() => {\r\n pressed.value = false as any;\r\n pressTimer = null;\r\n }, 120);\r\n emit('click');\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n let pressTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n if (pressTimer) clearTimeout(pressTimer);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const label = props.label || 'Button';\r\n const isPressed = pressed.value as boolean;\r\n\r\n return (\r\n <box\r\n border=\"single\"\r\n borderColor={isPressed ? 'yellow' : (focused ? 'green' : 'white')}\r\n backgroundColor={isPressed ? 'red' : (focused ? 'blue' : undefined)}\r\n dropShadow={props.dropShadow}\r\n >\r\n <text color={focused ? 'white' : undefined}>{label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'Button' });","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Checkbox = component<\r\n Define.Model<boolean> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"disabled\", boolean, false> &\r\n Define.Event<\"change\", boolean>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const checked = () => !!props.model?.value;\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (props.disabled) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space toggles\r\n const next = !checked();\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\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 });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const label = props.label || '';\r\n const focused = isFocused();\r\n const isChecked = checked();\r\n const disabled = !!props.disabled;\r\n\r\n // Visual: [x] Label or [ ] Label\r\n // When focused, show a cursor indicator and highlight the label\r\n const boxColor = disabled ? 'white' : (isChecked ? 'green' : (focused ? 'cyan' : 'white'));\r\n const labelColor = disabled ? 'white' : (focused ? 'cyan' : undefined);\r\n const checkMark = isChecked ? 'x' : ' ';\r\n const focusIndicator = focused ? '>' : ' ';\r\n\r\n return (\r\n <box>\r\n <text color={focused ? 'cyan' : 'white'}>{focusIndicator}</text>\r\n <text color={boxColor}>[{checkMark}]</text>\r\n {label && <text color={labelColor}> {label}</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Checkbox' });\r\n\r\nexport default Checkbox;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport interface SelectOption<T = string> {\r\n label: string;\r\n value: T;\r\n description?: string;\r\n}\r\n\r\nexport const Select = component<\r\n Define.Model<string> &\r\n Define.Prop<\"options\", SelectOption[], true> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"showDescription\", boolean, false> &\r\n Define.Event<\"change\", string> &\r\n Define.Event<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getCurrentIndex = () => {\r\n const options = props.options || [];\r\n const idx = options.findIndex(o => o.value === props.model?.value);\r\n return idx >= 0 ? idx : 0;\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n\r\n const currentIndex = getCurrentIndex();\r\n\r\n // Arrow up or 'k'\r\n if (key === '\\x1B[A' || key === 'k') {\r\n const newIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Arrow down or 'j'\r\n if (key === '\\x1B[B' || key === 'j') {\r\n const newIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Enter to submit\r\n if (key === '\\r') {\r\n emit('submit', props.model?.value || options[0]?.value || '');\r\n return;\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) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\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 options = props.options || [];\r\n const focused = isFocused();\r\n const currentValue = props.model?.value || options[0]?.value || '';\r\n const label = props.label;\r\n const selectedOption = options.find(o => o.value === currentValue);\r\n\r\n // Render options\r\n const optionElements = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const indicator = isSelected ? '❯' : ' ';\r\n const color = isSelected ? 'cyan' : 'white';\r\n\r\n return (\r\n <box>\r\n <text color={color}>{indicator} {option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n // Description shown below the box (common pattern in CLI tools)\r\n const descriptionElement = props.showDescription && selectedOption?.description ? (\r\n <box>\r\n <text color=\"#666666\"> ↳ {selectedOption.description}</text>\r\n </box>\r\n ) : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"single\" borderColor={focused ? 'green' : 'white'} label={label}>\r\n {optionElements}\r\n </box>\r\n {descriptionElement}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Select' });\r\n\r\nexport default Select;\r\n","import { createRenderer, RendererOptions, setDefaultMount } from '@sigx/runtime-core/internals';\r\nimport { VNode } from '@sigx/runtime-core';\r\nimport { focusNext, focusPrev } from './focus';\r\nimport { getColorCode, getBackgroundColorCode, stripAnsi } from './utils';\r\n\r\n// Import type augmentation\r\nimport './types.js';\r\n\r\nexport * from './focus';\r\nexport * from './components/Input';\r\nexport * from './components/ProgressBar';\r\nexport * from './components/Button';\r\nexport * from './components/Checkbox';\r\nexport * from './components/Select';\r\n\r\n// --- Terminal Node Types ---\r\n\r\nexport interface TerminalNode {\r\n type: 'root' | 'element' | 'text' | 'comment';\r\n tag?: string;\r\n text?: string;\r\n props: Record<string, any>;\r\n children: TerminalNode[];\r\n parentNode?: TerminalNode | null;\r\n}\r\n\r\n// --- Node Operations ---\r\n\r\nconst nodeOps: RendererOptions<TerminalNode, TerminalNode> = {\r\n patchProp: (el, key, prev, next) => {\r\n el.props[key] = next;\r\n scheduleRender();\r\n },\r\n insert: (child, parent, anchor) => {\r\n child.parentNode = parent;\r\n const index = anchor ? parent.children.indexOf(anchor) : -1;\r\n if (index > -1) {\r\n parent.children.splice(index, 0, child);\r\n } else {\r\n parent.children.push(child);\r\n }\r\n scheduleRender();\r\n },\r\n remove: (child) => {\r\n if (child.parentNode) {\r\n const index = child.parentNode.children.indexOf(child);\r\n if (index > -1) {\r\n child.parentNode.children.splice(index, 1);\r\n }\r\n child.parentNode = null;\r\n }\r\n scheduleRender();\r\n },\r\n createElement: (tag) => {\r\n return { type: 'element', tag, props: {}, children: [] };\r\n },\r\n createText: (text) => {\r\n return { type: 'text', text, props: {}, children: [] };\r\n },\r\n createComment: (text) => {\r\n return { type: 'comment', text, props: {}, children: [] };\r\n },\r\n setText: (node, text) => {\r\n node.text = text;\r\n scheduleRender();\r\n },\r\n setElementText: (node, text) => {\r\n node.children = [{ type: 'text', text, props: {}, children: [], parentNode: node }];\r\n scheduleRender();\r\n },\r\n parentNode: (node) => node.parentNode || null,\r\n nextSibling: (node) => {\r\n if (!node.parentNode) return null;\r\n const idx = node.parentNode.children.indexOf(node);\r\n return node.parentNode.children[idx + 1] || null;\r\n },\r\n cloneNode: (node) => {\r\n // Shallow clone for simplicity in this demo\r\n return { ...node, children: [] };\r\n }\r\n};\r\n\r\n// --- Renderer Creation ---\r\n\r\nconst renderer = createRenderer(nodeOps);\r\nexport const { render } = renderer;\r\n\r\n// --- Terminal Rendering Logic ---\r\n\r\nlet rootNode: TerminalNode | null = null;\r\nlet isRendering = false;\r\n\r\nfunction scheduleRender() {\r\n if (isRendering) return;\r\n isRendering = true;\r\n // Use setImmediate or setTimeout to batch updates\r\n setTimeout(() => {\r\n flushRender();\r\n isRendering = false;\r\n }, 10);\r\n}\r\n\r\nfunction flushRender() {\r\n if (!rootNode) return;\r\n\r\n // Move cursor to top-left\r\n process.stdout.write('\\x1B[H');\r\n\r\n // Render tree\r\n const lines = renderNodeToLines(rootNode);\r\n process.stdout.write(lines.join('\\x1B[K\\n') + '\\x1B[K');\r\n\r\n // Clear rest of screen\r\n process.stdout.write('\\x1B[J');\r\n}\r\n\r\n\r\n/**\r\n * Check if a node has a box element as an immediate child.\r\n * This is used to determine if a component wrapper should be treated as a block element.\r\n */\r\nfunction hasBoxChild(node: TerminalNode): boolean {\r\n for (const child of node.children) {\r\n if (child.tag === 'box') {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport function renderNodeToLines(node: TerminalNode): string[] {\r\n // if (node.tag === 'box') console.log('Rendering box', node.props);\r\n if (node.type === 'text') {\r\n return [node.text || ''];\r\n }\r\n if (node.type === 'comment') {\r\n return [];\r\n }\r\n\r\n let lines: string[] = [''];\r\n\r\n // Simple styling based on props (e.g., color)\r\n const color = node.props.color;\r\n const reset = color ? '\\x1b[0m' : '';\r\n const colorCode = getColorCode(color);\r\n\r\n // Render children\r\n for (const child of node.children) {\r\n if (child.type === 'text') {\r\n // Append text to the last line\r\n lines[lines.length - 1] += colorCode + (child.text || '') + reset;\r\n } else if (child.tag === 'br') {\r\n // Start a new line\r\n lines.push('');\r\n } else {\r\n // Recursively render child\r\n const childLines = renderNodeToLines(child);\r\n\r\n // Check if this child contains a box element (making it a block)\r\n // A box is always a block element, and component wrappers that contain\r\n // a box should also be treated as blocks\r\n const isBlockElement = child.tag === 'box' || hasBoxChild(child);\r\n\r\n if (isBlockElement) {\r\n // Block element - start on a new line\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n // Inline element (like text wrapper)\r\n // This is tricky. If child returns multiple lines, it breaks the flow.\r\n // For now, assume non-box elements are inline-ish or just append.\r\n if (childLines.length > 0) {\r\n // If the child has multiple lines, treat it as a block to avoid\r\n // appending a box top border to the end of a text line.\r\n if (childLines.length > 1) {\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n lines[lines.length - 1] += childLines[0];\r\n for (let i = 1; i < childLines.length; i++) {\r\n lines.push(childLines[i]);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply box borders if needed\r\n if (node.tag === 'box' && node.props.border) {\r\n return drawBox(lines, node.props.border, node.props.borderColor, node.props.backgroundColor, node.props.dropShadow, node.props.label);\r\n }\r\n\r\n return lines;\r\n}\r\n\r\nfunction drawBox(contentLines: string[], style: string, color?: string, backgroundColor?: string, dropShadow?: boolean, label?: string): string[] {\r\n const borderChars = getBorderChars(style);\r\n const colorCode = color ? getColorCode(color) : '';\r\n const bgCode = backgroundColor ? getBackgroundColorCode(backgroundColor) : '';\r\n const reset = (color || backgroundColor) ? '\\x1b[0m' : '';\r\n\r\n // Calculate width\r\n const width = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);\r\n\r\n // If there's a label, ensure box is wide enough to accommodate it\r\n const labelText = label || '';\r\n const labelLength = stripAnsi(labelText).length;\r\n const boxInnerWidth = Math.max(width, labelLength + 2);\r\n\r\n // Build top border. If label exists, center it in the top border like a fieldset legend\r\n let topInner = '';\r\n if (labelText) {\r\n const spaceForLabel = boxInnerWidth - labelLength - 2; // remaining space for horiz lines\r\n const leftH = Math.floor(spaceForLabel / 2);\r\n const rightH = spaceForLabel - leftH;\r\n topInner = borderChars.h.repeat(leftH) + ' ' + labelText + ' ' + borderChars.h.repeat(rightH);\r\n } else {\r\n topInner = borderChars.h.repeat(boxInnerWidth);\r\n }\r\n\r\n const top = bgCode + colorCode + borderChars.tl + topInner + borderChars.tr + reset;\r\n const bottom = bgCode + colorCode + borderChars.bl + borderChars.h.repeat(boxInnerWidth) + borderChars.br + reset;\r\n\r\n const result: string[] = [];\r\n result.push(top);\r\n\r\n for (const line of contentLines) {\r\n const visibleLength = stripAnsi(line).length;\r\n const padding = ' '.repeat(boxInnerWidth - visibleLength);\r\n // We need to apply background to the content line as well, but be careful not to double apply if it already has it?\r\n // Actually, the content might have its own colors.\r\n // But the padding needs the background color.\r\n // And the border needs the background color.\r\n\r\n // If we wrap the whole line in bgCode, it should work, provided we reset at the end.\r\n // But `line` might have resets in it.\r\n // A simple approach: apply bgCode to the border chars and the padding.\r\n // For the content, if it doesn't have bg, we might want to apply it.\r\n // But `line` is already a string with ANSI codes.\r\n\r\n // Let's try wrapping the whole thing.\r\n // Note: `line` comes from `renderNodeToLines`, which might have resets.\r\n // If `line` has `\\x1b[0m`, it will reset the background too.\r\n // So we might need to replace `\\x1b[0m` with `\\x1b[0m` + bgCode + colorCode?\r\n // That's getting complicated.\r\n\r\n // For now, let's just apply bg to borders and padding.\r\n // And maybe prepend bgCode to the line?\r\n\r\n // If we just prepend bgCode to `line`, and `line` has a reset, the rest of the line will lose the bg.\r\n // So we should replace resets in `line` with `reset + bgCode + colorCode` (if we want to maintain the box style).\r\n // But `colorCode` is for the border. The content might have its own text color.\r\n\r\n // Let's assume content handles its own text color, but we want to enforce background.\r\n // We can replace `\\x1b[0m` with `\\x1b[0m${bgCode}`.\r\n\r\n const lineWithBg = bgCode + line.replace(/\\x1b\\[0m/g, `\\x1b[0m${bgCode}`);\r\n\r\n result.push(bgCode + colorCode + borderChars.v + reset + lineWithBg + bgCode + padding + colorCode + borderChars.v + reset);\r\n }\r\n\r\n result.push(bottom);\r\n\r\n if (dropShadow) {\r\n const shadowColor = '\\x1b[90m'; // Bright black (gray)\r\n const resetShadow = '\\x1b[0m';\r\n const shadowChar = '▒';\r\n const shadowBlock = shadowColor + shadowChar + resetShadow;\r\n\r\n // Apply to lines 1 to end (skipping top line 0)\r\n for (let i = 1; i < result.length; i++) {\r\n result[i] += shadowBlock;\r\n }\r\n\r\n // Add bottom shadow line\r\n // Width is boxWidth (width + 2)\r\n const bottomShadow = ' ' + shadowBlock.repeat(width + 2);\r\n result.push(bottomShadow);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getBorderChars(style: string) {\r\n if (style === 'double') {\r\n return { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' };\r\n }\r\n if (style === 'rounded') {\r\n return { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };\r\n }\r\n // Default single\r\n return { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };\r\n}\r\n\r\nfunction renderNodeToString(node: TerminalNode, depth = 0): string {\r\n // Deprecated, but kept for compatibility if needed, or just redirect\r\n return renderNodeToLines(node).join('\\n');\r\n}\r\n\r\n\r\n// --- Public API for mounting ---\r\n\r\ntype KeyHandler = (key: string) => void;\r\nconst keyHandlers = new Set<KeyHandler>();\r\n\r\nexport function onKey(handler: KeyHandler) {\r\n keyHandlers.add(handler);\r\n return () => keyHandlers.delete(handler);\r\n}\r\n\r\nfunction handleInput(key: string) {\r\n // Ctrl+C to exit\r\n if (key === '\\u0003') {\r\n process.stdout.write('\\x1B[?25h'); // Show cursor\r\n process.exit();\r\n }\r\n\r\n // Tab navigation\r\n if (key === '\\t') {\r\n focusNext();\r\n return;\r\n }\r\n // Shift+Tab (often \\x1b[Z)\r\n if (key === '\\x1b[Z') {\r\n focusPrev();\r\n return;\r\n }\r\n\r\n for (const handler of keyHandlers) {\r\n handler(key);\r\n }\r\n}\r\n\r\nexport interface RenderTerminalOptions {\r\n clearConsole?: boolean;\r\n}\r\n\r\nexport function renderTerminal(app: any, options: RenderTerminalOptions = {}) {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n // Create a proxy container that looks like a HostElement\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n render(app, container);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n return {\r\n unmount: () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n }\r\n };\r\n}\r\n\r\nlet unmountFn: (() => void) | null = null;\r\n\r\n/**\r\n * Helper function to mount the terminal for CLI apps.\r\n * Returns a mount target that can be passed to defineApp().mount().\r\n * \r\n * @example\r\n * ```tsx\r\n * defineApp(MyApp).mount(mountTerminal());\r\n * ```\r\n */\r\nexport function mountTerminal(options: RenderTerminalOptions = { clearConsole: true }) {\r\n return {\r\n mount: terminalMount,\r\n options,\r\n onMount: (unmount: () => void) => {\r\n unmountFn = unmount;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Exit the terminal app cleanly, restoring terminal state.\r\n */\r\nexport function exitTerminal() {\r\n if (unmountFn) {\r\n unmountFn();\r\n unmountFn = null;\r\n }\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n // Clear screen\r\n process.stdout.write('\\x1B[2J\\x1B[H');\r\n}\r\n\r\n/**\r\n * Mount function for Terminal environments.\r\n * Use this with defineApp().mount() to render to the terminal.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from '@sigx/runtime-core';\r\n * import { terminalMount } from '@sigx/runtime-terminal';\r\n * \r\n * const app = defineApp(<Counter />);\r\n * app.use(loggingPlugin)\r\n * .mount({ clearConsole: true }, terminalMount);\r\n * ```\r\n */\r\nexport const terminalMount = (component: any, options: RenderTerminalOptions, appContext?: any): (() => void) => {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options?.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n // Render with app context support\r\n render(component, container, appContext);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n // Return unmount function\r\n return () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n };\r\n};\r\n\r\n// Set terminalMount as the default mount function for this platform\r\nsetDefaultMount(terminalMount);\r\n\r\ndeclare global {\r\n namespace JSX {\r\n interface IntrinsicElements {\r\n box: TerminalAttributes;\r\n text: TerminalAttributes;\r\n br: TerminalAttributes;\r\n }\r\n\r\n interface TerminalAttributes {\r\n color?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n backgroundColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n border?: 'single' | 'double' | 'rounded' | 'none';\r\n borderColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n dropShadow?: boolean;\r\n label?: string;\r\n children?: any;\r\n }\r\n\r\n }\r\n}\r\n\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/focus.ts","../src/utils.ts","../src/components/Input.tsx","../src/components/ProgressBar.tsx","../src/components/Button.tsx","../src/components/Checkbox.tsx","../src/components/Select.tsx","../src/index.ts"],"sourcesContent":["import { signal } from '@sigx/reactivity';\r\n\r\nconst focusableIds = new Set<string>();\r\nexport const focusState = signal({ activeId: null as string | null });\r\n\r\nexport function registerFocusable(id: string) {\r\n focusableIds.add(id);\r\n if (focusState.activeId === null) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function unregisterFocusable(id: string) {\r\n focusableIds.delete(id);\r\n if (focusState.activeId === id) {\r\n focusState.activeId = null;\r\n // Try to focus another one\r\n if (focusableIds.size > 0) {\r\n focusState.activeId = focusableIds.values().next().value || null;\r\n }\r\n }\r\n}\r\n\r\nexport function focus(id: string) {\r\n if (focusableIds.has(id)) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function focusNext() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const nextIndex = (currentIndex + 1) % ids.length;\r\n focusState.activeId = ids[nextIndex];\r\n}\r\n\r\nexport function focusPrev() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const prevIndex = (currentIndex - 1 + ids.length) % ids.length;\r\n focusState.activeId = ids[prevIndex];\r\n}\r\n","\r\nexport function getColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[31m';\r\n case 'green': return '\\x1b[32m';\r\n case 'blue': return '\\x1b[34m';\r\n case 'yellow': return '\\x1b[33m';\r\n case 'cyan': return '\\x1b[36m';\r\n case 'white': return '\\x1b[37m';\r\n case 'black': return '\\x1b[30m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function getBackgroundColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[41m';\r\n case 'green': return '\\x1b[42m';\r\n case 'blue': return '\\x1b[44m';\r\n case 'yellow': return '\\x1b[43m';\r\n case 'cyan': return '\\x1b[46m';\r\n case 'white': return '\\x1b[47m';\r\n case 'black': return '\\x1b[40m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function stripAnsi(str: string): string {\r\n return str.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, '');\r\n}\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Input = component<\r\n Define.Model<string> &\r\n Define.Prop<\"placeholder\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Event<\"input\", string> &\r\n Define.Event<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getValue = () => props.model?.value || '';\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n if (key === '\\r') { // Enter\r\n emit('submit', getValue());\r\n return;\r\n }\r\n\r\n if (key === '\\n') return;\r\n\r\n if (key === '\\u007F' || key === '\\b') { // Backspace\r\n const val = getValue();\r\n if (val.length > 0) {\r\n const newValue = val.slice(0, -1);\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n }\r\n return;\r\n }\r\n\r\n // Ignore control characters\r\n if (key.length > 1) return;\r\n\r\n const newValue = getValue() + key;\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\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) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\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 val = getValue().replace(/[\\r\\n]+/g, ' ');\r\n const placeholder = (props.placeholder || '').replace(/[\\r\\n]+/g, ' ');\r\n const showCursor = isFocused();\r\n // console.log('Input render', { val, placeholder, showCursor });\r\n\r\n return (\r\n <box border=\"single\" borderColor={showCursor ? 'green' : 'white'} label={props.label}>\r\n <text>{val || placeholder}</text>\r\n {showCursor && <text color=\"cyan\">_</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Input' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, type Define } from '@sigx/runtime-core';\r\nimport { getColorCode } from '../utils';\r\n\r\nexport const ProgressBar = component<\r\n Define.Prop<\"value\", number, false> &\r\n Define.Prop<\"max\", number, false> &\r\n Define.Prop<\"width\", number, false> &\r\n Define.Prop<\"char\", string, false> &\r\n Define.Prop<\"emptyChar\", string, false> &\r\n Define.Prop<\"color\", string, false>\r\n>(({ props }) => {\r\n return () => {\r\n const value = props.value || 0;\r\n const max = props.max || 100;\r\n const width = props.width || 20;\r\n const barChar = props.char || '█';\r\n const emptyChar = props.emptyChar || '░';\r\n const color = props.color;\r\n const colorCode = color ? getColorCode(color) : '';\r\n const reset = color ? '\\x1b[0m' : '';\r\n\r\n const percentage = Math.min(Math.max(value / max, 0), 1);\r\n const filledLen = Math.round(width * percentage);\r\n const emptyLen = width - filledLen;\r\n\r\n const bar = colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset;\r\n const label = ` ${Math.round(percentage * 100)}%`;\r\n\r\n return (\r\n <box>\r\n <text>{bar + label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'ProgressBar' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState } from '../focus';\r\n\r\nexport const Button = component<\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"dropShadow\", boolean, false> &\r\n Define.Event<\"click\">\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const pressed = signal({ value: false });\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space\r\n // Visual press effect + emit click\r\n pressed.value = true as any;\r\n if (pressTimer) clearTimeout(pressTimer);\r\n pressTimer = setTimeout(() => {\r\n pressed.value = false as any;\r\n pressTimer = null;\r\n }, 120);\r\n emit('click');\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n let pressTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n if (pressTimer) clearTimeout(pressTimer);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const label = props.label || 'Button';\r\n const isPressed = pressed.value as boolean;\r\n\r\n return (\r\n <box\r\n border=\"single\"\r\n borderColor={isPressed ? 'yellow' : (focused ? 'green' : 'white')}\r\n backgroundColor={isPressed ? 'red' : (focused ? 'blue' : undefined)}\r\n dropShadow={props.dropShadow}\r\n >\r\n <text color={focused ? 'white' : undefined}>{label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'Button' });","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Checkbox = component<\r\n Define.Model<boolean> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"disabled\", boolean, false> &\r\n Define.Event<\"change\", boolean>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const checked = () => !!props.model?.value;\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (props.disabled) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space toggles\r\n const next = !checked();\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\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 });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const label = props.label || '';\r\n const focused = isFocused();\r\n const isChecked = checked();\r\n const disabled = !!props.disabled;\r\n\r\n // Visual: [x] Label or [ ] Label\r\n // When focused, show a cursor indicator and highlight the label\r\n const boxColor = disabled ? 'white' : (isChecked ? 'green' : (focused ? 'cyan' : 'white'));\r\n const labelColor = disabled ? 'white' : (focused ? 'cyan' : undefined);\r\n const checkMark = isChecked ? 'x' : ' ';\r\n const focusIndicator = focused ? '>' : ' ';\r\n\r\n return (\r\n <box>\r\n <text color={focused ? 'cyan' : 'white'}>{focusIndicator}</text>\r\n <text color={boxColor}>[{checkMark}]</text>\r\n {label && <text color={labelColor}> {label}</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Checkbox' });\r\n\r\nexport default Checkbox;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport interface SelectOption<T = string> {\r\n label: string;\r\n value: T;\r\n description?: string;\r\n}\r\n\r\nexport const Select = component<\r\n Define.Model<string> &\r\n Define.Prop<\"options\", SelectOption[], true> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"showDescription\", boolean, false> &\r\n Define.Event<\"change\", string> &\r\n Define.Event<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getCurrentIndex = () => {\r\n const options = props.options || [];\r\n const idx = options.findIndex(o => o.value === props.model?.value);\r\n return idx >= 0 ? idx : 0;\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n\r\n const currentIndex = getCurrentIndex();\r\n\r\n // Arrow up or 'k'\r\n if (key === '\\x1B[A' || key === 'k') {\r\n const newIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Arrow down or 'j'\r\n if (key === '\\x1B[B' || key === 'j') {\r\n const newIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Enter to submit\r\n if (key === '\\r') {\r\n emit('submit', props.model?.value || options[0]?.value || '');\r\n return;\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) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\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 options = props.options || [];\r\n const focused = isFocused();\r\n const currentValue = props.model?.value || options[0]?.value || '';\r\n const label = props.label;\r\n const selectedOption = options.find(o => o.value === currentValue);\r\n\r\n // Render options\r\n const optionElements = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const indicator = isSelected ? '❯' : ' ';\r\n const color = isSelected ? 'cyan' : 'white';\r\n\r\n return (\r\n <box>\r\n <text color={color}>{indicator} {option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n // Description shown below the box (common pattern in CLI tools)\r\n const descriptionElement = props.showDescription && selectedOption?.description ? (\r\n <box>\r\n <text color=\"#666666\"> ↳ {selectedOption.description}</text>\r\n </box>\r\n ) : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"single\" borderColor={focused ? 'green' : 'white'} label={label}>\r\n {optionElements}\r\n </box>\r\n {descriptionElement}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Select' });\r\n\r\nexport default Select;\r\n","import { createRenderer, RendererOptions, setDefaultMount } from '@sigx/runtime-core/internals';\r\nimport { VNode } from '@sigx/runtime-core';\r\nimport { focusNext, focusPrev } from './focus';\r\nimport { getColorCode, getBackgroundColorCode, stripAnsi } from './utils';\r\n\r\n// Import type augmentation\r\nimport './types.js';\r\n\r\nexport * from './focus';\r\nexport * from './components/Input';\r\nexport * from './components/ProgressBar';\r\nexport * from './components/Button';\r\nexport * from './components/Checkbox';\r\nexport * from './components/Select';\r\n\r\n// --- Terminal Node Types ---\r\n\r\nexport interface TerminalNode {\r\n type: 'root' | 'element' | 'text' | 'comment';\r\n tag?: string;\r\n text?: string;\r\n props: Record<string, any>;\r\n children: TerminalNode[];\r\n parentNode?: TerminalNode | null;\r\n}\r\n\r\n// --- Node Operations ---\r\n\r\nconst nodeOps: RendererOptions<TerminalNode, TerminalNode> = {\r\n patchProp: (el, key, prev, next) => {\r\n el.props[key] = next;\r\n scheduleRender();\r\n },\r\n insert: (child, parent, anchor) => {\r\n child.parentNode = parent;\r\n const index = anchor ? parent.children.indexOf(anchor) : -1;\r\n if (index > -1) {\r\n parent.children.splice(index, 0, child);\r\n } else {\r\n parent.children.push(child);\r\n }\r\n scheduleRender();\r\n },\r\n remove: (child) => {\r\n if (child.parentNode) {\r\n const index = child.parentNode.children.indexOf(child);\r\n if (index > -1) {\r\n child.parentNode.children.splice(index, 1);\r\n }\r\n child.parentNode = null;\r\n }\r\n scheduleRender();\r\n },\r\n createElement: (tag) => {\r\n return { type: 'element', tag, props: {}, children: [] };\r\n },\r\n createText: (text) => {\r\n return { type: 'text', text, props: {}, children: [] };\r\n },\r\n createComment: (text) => {\r\n return { type: 'comment', text, props: {}, children: [] };\r\n },\r\n setText: (node, text) => {\r\n node.text = text;\r\n scheduleRender();\r\n },\r\n setElementText: (node, text) => {\r\n node.children = [{ type: 'text', text, props: {}, children: [], parentNode: node }];\r\n scheduleRender();\r\n },\r\n parentNode: (node) => node.parentNode || null,\r\n nextSibling: (node) => {\r\n if (!node.parentNode) return null;\r\n const idx = node.parentNode.children.indexOf(node);\r\n return node.parentNode.children[idx + 1] || null;\r\n },\r\n cloneNode: (node) => {\r\n // Shallow clone for simplicity in this demo\r\n return { ...node, children: [] };\r\n }\r\n};\r\n\r\n// --- Renderer Creation ---\r\n\r\nconst renderer = createRenderer(nodeOps);\r\nexport const { render } = renderer;\r\n\r\n// --- Terminal Rendering Logic ---\r\n\r\nlet rootNode: TerminalNode | null = null;\r\nlet isRendering = false;\r\n\r\nfunction scheduleRender() {\r\n if (isRendering) return;\r\n isRendering = true;\r\n // Use setImmediate or setTimeout to batch updates\r\n setTimeout(() => {\r\n flushRender();\r\n isRendering = false;\r\n }, 10);\r\n}\r\n\r\nfunction flushRender() {\r\n if (!rootNode) return;\r\n\r\n // Move cursor to top-left\r\n process.stdout.write('\\x1B[H');\r\n\r\n // Render tree\r\n const lines = renderNodeToLines(rootNode);\r\n process.stdout.write(lines.join('\\x1B[K\\n') + '\\x1B[K');\r\n\r\n // Clear rest of screen\r\n process.stdout.write('\\x1B[J');\r\n}\r\n\r\n\r\n/**\r\n * Check if a node has a box element as an immediate child.\r\n * This is used to determine if a component wrapper should be treated as a block element.\r\n */\r\nfunction hasBoxChild(node: TerminalNode): boolean {\r\n for (const child of node.children) {\r\n if (child.tag === 'box') {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport function renderNodeToLines(node: TerminalNode): string[] {\r\n // if (node.tag === 'box') console.log('Rendering box', node.props);\r\n if (node.type === 'text') {\r\n return [node.text || ''];\r\n }\r\n if (node.type === 'comment') {\r\n return [];\r\n }\r\n\r\n let lines: string[] = [''];\r\n\r\n // Simple styling based on props (e.g., color)\r\n const color = node.props.color;\r\n const reset = color ? '\\x1b[0m' : '';\r\n const colorCode = getColorCode(color);\r\n\r\n // Render children\r\n for (const child of node.children) {\r\n if (child.type === 'text') {\r\n // Append text to the last line\r\n lines[lines.length - 1] += colorCode + (child.text || '') + reset;\r\n } else if (child.tag === 'br') {\r\n // Start a new line\r\n lines.push('');\r\n } else {\r\n // Recursively render child\r\n const childLines = renderNodeToLines(child);\r\n\r\n // Check if this child contains a box element (making it a block)\r\n // A box is always a block element, and component wrappers that contain\r\n // a box should also be treated as blocks\r\n const isBlockElement = child.tag === 'box' || hasBoxChild(child);\r\n\r\n if (isBlockElement) {\r\n // Block element - start on a new line\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n // Inline element (like text wrapper)\r\n // This is tricky. If child returns multiple lines, it breaks the flow.\r\n // For now, assume non-box elements are inline-ish or just append.\r\n if (childLines.length > 0) {\r\n // If the child has multiple lines, treat it as a block to avoid\r\n // appending a box top border to the end of a text line.\r\n if (childLines.length > 1) {\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n lines[lines.length - 1] += childLines[0];\r\n for (let i = 1; i < childLines.length; i++) {\r\n lines.push(childLines[i]);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply box borders if needed\r\n if (node.tag === 'box' && node.props.border) {\r\n return drawBox(lines, node.props.border, node.props.borderColor, node.props.backgroundColor, node.props.dropShadow, node.props.label);\r\n }\r\n\r\n return lines;\r\n}\r\n\r\nfunction drawBox(contentLines: string[], style: string, color?: string, backgroundColor?: string, dropShadow?: boolean, label?: string): string[] {\r\n const borderChars = getBorderChars(style);\r\n const colorCode = color ? getColorCode(color) : '';\r\n const bgCode = backgroundColor ? getBackgroundColorCode(backgroundColor) : '';\r\n const reset = (color || backgroundColor) ? '\\x1b[0m' : '';\r\n\r\n // Calculate width\r\n const width = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);\r\n\r\n // If there's a label, ensure box is wide enough to accommodate it\r\n const labelText = label || '';\r\n const labelLength = stripAnsi(labelText).length;\r\n const boxInnerWidth = Math.max(width, labelLength + 2);\r\n\r\n // Build top border. If label exists, center it in the top border like a fieldset legend\r\n let topInner = '';\r\n if (labelText) {\r\n const spaceForLabel = boxInnerWidth - labelLength - 2; // remaining space for horiz lines\r\n const leftH = Math.floor(spaceForLabel / 2);\r\n const rightH = spaceForLabel - leftH;\r\n topInner = borderChars.h.repeat(leftH) + ' ' + labelText + ' ' + borderChars.h.repeat(rightH);\r\n } else {\r\n topInner = borderChars.h.repeat(boxInnerWidth);\r\n }\r\n\r\n const top = bgCode + colorCode + borderChars.tl + topInner + borderChars.tr + reset;\r\n const bottom = bgCode + colorCode + borderChars.bl + borderChars.h.repeat(boxInnerWidth) + borderChars.br + reset;\r\n\r\n const result: string[] = [];\r\n result.push(top);\r\n\r\n for (const line of contentLines) {\r\n const visibleLength = stripAnsi(line).length;\r\n const padding = ' '.repeat(boxInnerWidth - visibleLength);\r\n // We need to apply background to the content line as well, but be careful not to double apply if it already has it?\r\n // Actually, the content might have its own colors.\r\n // But the padding needs the background color.\r\n // And the border needs the background color.\r\n\r\n // If we wrap the whole line in bgCode, it should work, provided we reset at the end.\r\n // But `line` might have resets in it.\r\n // A simple approach: apply bgCode to the border chars and the padding.\r\n // For the content, if it doesn't have bg, we might want to apply it.\r\n // But `line` is already a string with ANSI codes.\r\n\r\n // Let's try wrapping the whole thing.\r\n // Note: `line` comes from `renderNodeToLines`, which might have resets.\r\n // If `line` has `\\x1b[0m`, it will reset the background too.\r\n // So we might need to replace `\\x1b[0m` with `\\x1b[0m` + bgCode + colorCode?\r\n // That's getting complicated.\r\n\r\n // For now, let's just apply bg to borders and padding.\r\n // And maybe prepend bgCode to the line?\r\n\r\n // If we just prepend bgCode to `line`, and `line` has a reset, the rest of the line will lose the bg.\r\n // So we should replace resets in `line` with `reset + bgCode + colorCode` (if we want to maintain the box style).\r\n // But `colorCode` is for the border. The content might have its own text color.\r\n\r\n // Let's assume content handles its own text color, but we want to enforce background.\r\n // We can replace `\\x1b[0m` with `\\x1b[0m${bgCode}`.\r\n\r\n const lineWithBg = bgCode + line.replace(/\\x1b\\[0m/g, `\\x1b[0m${bgCode}`);\r\n\r\n result.push(bgCode + colorCode + borderChars.v + reset + lineWithBg + bgCode + padding + colorCode + borderChars.v + reset);\r\n }\r\n\r\n result.push(bottom);\r\n\r\n if (dropShadow) {\r\n const shadowColor = '\\x1b[90m'; // Bright black (gray)\r\n const resetShadow = '\\x1b[0m';\r\n const shadowChar = '▒';\r\n const shadowBlock = shadowColor + shadowChar + resetShadow;\r\n\r\n // Apply to lines 1 to end (skipping top line 0)\r\n for (let i = 1; i < result.length; i++) {\r\n result[i] += shadowBlock;\r\n }\r\n\r\n // Add bottom shadow line\r\n // Width is boxWidth (width + 2)\r\n const bottomShadow = ' ' + shadowBlock.repeat(width + 2);\r\n result.push(bottomShadow);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getBorderChars(style: string) {\r\n if (style === 'double') {\r\n return { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' };\r\n }\r\n if (style === 'rounded') {\r\n return { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };\r\n }\r\n // Default single\r\n return { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };\r\n}\r\n\r\nfunction renderNodeToString(node: TerminalNode, depth = 0): string {\r\n // Deprecated, but kept for compatibility if needed, or just redirect\r\n return renderNodeToLines(node).join('\\n');\r\n}\r\n\r\n\r\n// --- Public API for mounting ---\r\n\r\ntype KeyHandler = (key: string) => void;\r\nconst keyHandlers = new Set<KeyHandler>();\r\n\r\nexport function onKey(handler: KeyHandler) {\r\n keyHandlers.add(handler);\r\n return () => keyHandlers.delete(handler);\r\n}\r\n\r\nfunction handleInput(key: string) {\r\n // Ctrl+C to exit\r\n if (key === '\\u0003') {\r\n process.stdout.write('\\x1B[?25h'); // Show cursor\r\n process.exit();\r\n }\r\n\r\n // Tab navigation\r\n if (key === '\\t') {\r\n focusNext();\r\n return;\r\n }\r\n // Shift+Tab (often \\x1b[Z)\r\n if (key === '\\x1b[Z') {\r\n focusPrev();\r\n return;\r\n }\r\n\r\n for (const handler of keyHandlers) {\r\n handler(key);\r\n }\r\n}\r\n\r\nexport interface RenderTerminalOptions {\r\n clearConsole?: boolean;\r\n}\r\n\r\nexport function renderTerminal(app: any, options: RenderTerminalOptions = {}) {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n // Create a proxy container that looks like a HostElement\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n render(app, container);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n return {\r\n unmount: () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n }\r\n };\r\n}\r\n\r\nlet unmountFn: (() => void) | null = null;\r\n\r\n/**\r\n * Helper function to mount the terminal for CLI apps.\r\n * Returns a mount target that can be passed to defineApp().mount().\r\n * \r\n * @example\r\n * ```tsx\r\n * defineApp(MyApp).mount(mountTerminal());\r\n * ```\r\n */\r\nexport function mountTerminal(options: RenderTerminalOptions = { clearConsole: true }) {\r\n return {\r\n mount: terminalMount,\r\n options,\r\n onMount: (unmount: () => void) => {\r\n unmountFn = unmount;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Exit the terminal app cleanly, restoring terminal state.\r\n */\r\nexport function exitTerminal() {\r\n if (unmountFn) {\r\n unmountFn();\r\n unmountFn = null;\r\n }\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n // Clear screen\r\n process.stdout.write('\\x1B[2J\\x1B[H');\r\n}\r\n\r\n/**\r\n * Mount function for Terminal environments.\r\n * Use this with defineApp().mount() to render to the terminal.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from '@sigx/runtime-core';\r\n * import { terminalMount } from '@sigx/runtime-terminal';\r\n * \r\n * const app = defineApp(<Counter />);\r\n * app.use(loggingPlugin)\r\n * .mount({ clearConsole: true }, terminalMount);\r\n * ```\r\n */\r\nexport const terminalMount = (component: any, options: RenderTerminalOptions, appContext?: any): (() => void) => {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options?.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n // Render with app context support\r\n render(component, container, appContext);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n // Return unmount function\r\n return () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n };\r\n};\r\n\r\n// Set terminalMount as the default mount function for this platform\r\nsetDefaultMount(terminalMount);\r\n\r\ndeclare global {\r\n namespace JSX {\r\n interface IntrinsicElements {\r\n box: TerminalAttributes;\r\n text: TerminalAttributes;\r\n br: TerminalAttributes;\r\n }\r\n\r\n interface TerminalAttributes {\r\n color?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n backgroundColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n border?: 'single' | 'double' | 'rounded' | 'none';\r\n borderColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n dropShadow?: boolean;\r\n label?: string;\r\n children?: any;\r\n }\r\n\r\n }\r\n}\r\n\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/runtime-terminal",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Terminal renderer for SignalX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,14 +33,14 @@
33
33
  "url": "https://github.com/signalxjs/core/issues"
34
34
  },
35
35
  "dependencies": {
36
- "@sigx/runtime-core": "^0.2.1",
37
- "@sigx/reactivity": "^0.2.1"
36
+ "@sigx/reactivity": "^0.2.2",
37
+ "@sigx/runtime-core": "^0.2.2"
38
38
  },
39
39
  "devDependencies": {
40
40
  "typescript": "^5.9.3",
41
41
  "@types/node": "^20.0.0",
42
42
  "vite": "^8.0.3",
43
- "@sigx/vite": "^0.2.1"
43
+ "@sigx/vite": "^0.2.2"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "vite build && tsgo --emitDeclarationOnly",