@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 +252 -473
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
13
|
-
|
|
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
|
|
20
|
-
|
|
13
|
+
function p(e) {
|
|
14
|
+
l.has(e) && (u.activeId = e);
|
|
21
15
|
}
|
|
22
|
-
function
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
35
|
-
switch (
|
|
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
|
|
47
|
-
switch (
|
|
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
|
|
59
|
-
return
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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 (
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
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 (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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:
|
|
111
|
-
label:
|
|
112
|
-
children: [/* @__PURE__ */
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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:
|
|
175
|
-
backgroundColor:
|
|
176
|
-
dropShadow:
|
|
177
|
-
children: /* @__PURE__ */
|
|
178
|
-
color:
|
|
179
|
-
children:
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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__ */
|
|
221
|
-
color:
|
|
139
|
+
/* @__PURE__ */ c("text", {
|
|
140
|
+
color: a ? "white" : i ? "green" : n ? "cyan" : "white",
|
|
222
141
|
children: [
|
|
223
142
|
"[",
|
|
224
|
-
|
|
143
|
+
i ? "x" : " ",
|
|
225
144
|
"]"
|
|
226
145
|
]
|
|
227
146
|
}),
|
|
228
|
-
|
|
229
|
-
color:
|
|
230
|
-
children: [" ",
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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 (
|
|
259
|
-
|
|
260
|
-
|
|
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 (
|
|
265
|
-
|
|
172
|
+
if (n === "\r") {
|
|
173
|
+
t("submit", e.model?.value || i[0]?.value || "");
|
|
266
174
|
return;
|
|
267
175
|
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
189
|
+
t ? "❯" : " ",
|
|
294
190
|
" ",
|
|
295
|
-
|
|
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: [" ↳ ",
|
|
196
|
+
children: [" ↳ ", a.description]
|
|
302
197
|
}) }) : null;
|
|
303
|
-
return /* @__PURE__ */
|
|
198
|
+
return /* @__PURE__ */ c("box", { children: [/* @__PURE__ */ s("box", {
|
|
304
199
|
border: "single",
|
|
305
|
-
borderColor:
|
|
306
|
-
label,
|
|
307
|
-
children:
|
|
308
|
-
}),
|
|
200
|
+
borderColor: n ? "green" : "white",
|
|
201
|
+
label: i,
|
|
202
|
+
children: l
|
|
203
|
+
}), u] });
|
|
309
204
|
};
|
|
310
|
-
}, { name: "Select" })
|
|
311
|
-
|
|
312
|
-
|
|
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: (
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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: (
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
330
|
-
},
|
|
331
|
-
createElement: (tag) => {
|
|
332
|
-
return {
|
|
333
|
-
type: "element",
|
|
334
|
-
tag,
|
|
335
|
-
props: {},
|
|
336
|
-
children: []
|
|
337
|
-
};
|
|
219
|
+
D();
|
|
338
220
|
},
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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: (
|
|
360
|
-
|
|
242
|
+
setElementText: (e, t) => {
|
|
243
|
+
e.children = [{
|
|
361
244
|
type: "text",
|
|
362
|
-
text,
|
|
245
|
+
text: t,
|
|
363
246
|
props: {},
|
|
364
247
|
children: [],
|
|
365
|
-
parentNode:
|
|
366
|
-
}];
|
|
367
|
-
scheduleRender();
|
|
248
|
+
parentNode: e
|
|
249
|
+
}], D();
|
|
368
250
|
},
|
|
369
|
-
parentNode: (
|
|
370
|
-
nextSibling: (
|
|
371
|
-
if (!
|
|
372
|
-
|
|
373
|
-
return
|
|
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: (
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
|
393
|
-
if (!
|
|
267
|
+
function O() {
|
|
268
|
+
if (!T) return;
|
|
394
269
|
process.stdout.write("\x1B[H");
|
|
395
|
-
|
|
396
|
-
process.stdout.write(
|
|
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
|
-
|
|
401
|
-
|
|
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
|
|
408
|
-
if (
|
|
409
|
-
if (
|
|
410
|
-
let
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
418
|
-
if (
|
|
419
|
-
else
|
|
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
|
-
|
|
424
|
-
for (let
|
|
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
|
-
|
|
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
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
|
312
|
+
return b;
|
|
464
313
|
}
|
|
465
|
-
function
|
|
466
|
-
|
|
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
|
|
492
|
-
function
|
|
493
|
-
|
|
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
|
|
497
|
-
if (
|
|
498
|
-
|
|
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 (
|
|
506
|
-
|
|
347
|
+
if (e === "\x1B[Z") {
|
|
348
|
+
h();
|
|
507
349
|
return;
|
|
508
350
|
}
|
|
509
|
-
for (
|
|
351
|
+
for (let t of N) t(e);
|
|
510
352
|
}
|
|
511
|
-
function
|
|
512
|
-
|
|
353
|
+
function I(e, t = {}) {
|
|
354
|
+
T = {
|
|
513
355
|
type: "root",
|
|
514
356
|
props: {},
|
|
515
357
|
children: []
|
|
516
358
|
};
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
process.stdin.setRawMode(
|
|
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
|
|
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:
|
|
551
|
-
options,
|
|
552
|
-
onMount: (
|
|
553
|
-
|
|
367
|
+
mount: B,
|
|
368
|
+
options: e,
|
|
369
|
+
onMount: (e) => {
|
|
370
|
+
L = e;
|
|
554
371
|
}
|
|
555
372
|
};
|
|
556
373
|
}
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
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
|
-
|
|
589
|
-
|
|
590
|
-
process.stdin.setRawMode(
|
|
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
|
-
|
|
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.
|
|
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/
|
|
37
|
-
"@sigx/
|
|
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.
|
|
43
|
+
"@sigx/vite": "^0.2.2"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "vite build && tsgo --emitDeclarationOnly",
|