@sigx/terminal-ui 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/Spinner-JpmBtbPo.js +25 -0
- package/dist/Spinner-JpmBtbPo.js.map +1 -0
- package/dist/buttons/Button.d.ts +8 -0
- package/dist/buttons/index.d.ts +1 -0
- package/dist/buttons/index.js +2 -0
- package/dist/buttons-D5iaiJ6G.js +38 -0
- package/dist/buttons-D5iaiJ6G.js.map +1 -0
- package/dist/data/QRCode.d.ts +17 -0
- package/dist/data/Table.d.ts +11 -0
- package/dist/data/index.d.ts +2 -0
- package/dist/data/index.js +2 -0
- package/dist/data-DKKLsE5K.js +43 -0
- package/dist/data-DKKLsE5K.js.map +1 -0
- package/dist/feedback/Badge.d.ts +14 -0
- package/dist/feedback/ProgressBar.d.ts +31 -0
- package/dist/feedback/Spinner.d.ts +21 -0
- package/dist/feedback/index.d.ts +3 -0
- package/dist/feedback/index.js +3 -0
- package/dist/feedback-1WqdARfx.js +62 -0
- package/dist/feedback-1WqdARfx.js.map +1 -0
- package/dist/forms/Checkbox.d.ts +15 -0
- package/dist/forms/Confirm.d.ts +21 -0
- package/dist/forms/Input.d.ts +15 -0
- package/dist/forms/MultiSelect.d.ts +36 -0
- package/dist/forms/Radio.d.ts +23 -0
- package/dist/forms/Select.d.ts +22 -0
- package/dist/forms/TextArea.d.ts +37 -0
- package/dist/forms/index.d.ts +7 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms-MgpyoQI5.js +399 -0
- package/dist/forms-MgpyoQI5.js.map +1 -0
- package/dist/fx/Banner.d.ts +19 -0
- package/dist/fx/Gradient.d.ts +18 -0
- package/dist/fx/PixelArt.d.ts +16 -0
- package/dist/fx/Shimmer.d.ts +18 -0
- package/dist/fx/blockFont.d.ts +13 -0
- package/dist/fx/index.d.ts +6 -0
- package/dist/fx/index.js +3 -0
- package/dist/fx/paint.d.ts +15 -0
- package/dist/fx/presets.d.ts +14 -0
- package/dist/fx-igWaVCkB.js +452 -0
- package/dist/fx-igWaVCkB.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +13 -0
- package/dist/layout/Card.d.ts +11 -0
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/index.js +2 -0
- package/dist/layout-CJzMVMDf.js +18 -0
- package/dist/layout-CJzMVMDf.js.map +1 -0
- package/dist/navigation/KeyHints.d.ts +15 -0
- package/dist/navigation/StatusBar.d.ts +9 -0
- package/dist/navigation/SuggestionList.d.ts +22 -0
- package/dist/navigation/Tabs.d.ts +18 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation-B-nI3g0k.js +133 -0
- package/dist/navigation-B-nI3g0k.js.map +1 -0
- package/dist/presets-uqseGRqO.js +31 -0
- package/dist/presets-uqseGRqO.js.map +1 -0
- package/dist/prompts/PromptShell.d.ts +11 -0
- package/dist/prompts/confirm.d.ts +14 -0
- package/dist/prompts/index.d.ts +35 -0
- package/dist/prompts/index.js +2 -0
- package/dist/prompts/multiselect.d.ts +14 -0
- package/dist/prompts/select.d.ts +20 -0
- package/dist/prompts/spinner.d.ts +22 -0
- package/dist/prompts/statics.d.ts +8 -0
- package/dist/prompts/text.d.ts +19 -0
- package/dist/prompts-BLtLCen_.js +381 -0
- package/dist/prompts-BLtLCen_.js.map +1 -0
- package/dist/tasks/LogPanel.d.ts +28 -0
- package/dist/tasks/LogView.d.ts +24 -0
- package/dist/tasks/TaskList.d.ts +26 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +2 -0
- package/dist/tasks/logStore.d.ts +40 -0
- package/dist/tasks-CdVFFOFs.js +254 -0
- package/dist/tasks-CdVFFOFs.js.map +1 -0
- package/dist/theme/builtins.d.ts +7 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme-DASuxf6k.js +150 -0
- package/dist/theme-DASuxf6k.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { GLYPHS as e, READY_DELAY_MS as t, cursorToRowCol as n, deleteAt as r, deleteBefore as i, focus as a, focusState as o, getTerminalSize as s, insertAt as c, layoutText as l, moveLeft as u, moveLineEnd as d, moveLineStart as f, moveRight as p, moveVertical as m, onKey as h, registerFocusable as g, resolveColor as _, unregisterFocusable as v } from "@sigx/terminal-zero";
|
|
2
|
+
import { component as y, onMounted as b, onUnmounted as x, signal as S } from "@sigx/runtime-core";
|
|
3
|
+
import { jsx as C, jsxs as w } from "@sigx/runtime-core/jsx-runtime";
|
|
4
|
+
//#region src/forms/Input.tsx
|
|
5
|
+
var T = y(({ props: e, emit: t }) => {
|
|
6
|
+
let n = Math.random().toString(36).slice(2), r = !1, i = () => o.activeId === n, s = () => e.model?.value || "", c = (n) => {
|
|
7
|
+
if (!i() || !r) return;
|
|
8
|
+
if (n === "\r" || n === "\n") {
|
|
9
|
+
t("submit", s());
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (n === "" || n === "\b") {
|
|
13
|
+
let n = s();
|
|
14
|
+
if (n.length > 0) {
|
|
15
|
+
let r = n.slice(0, -1);
|
|
16
|
+
e.model && (e.model.value = r), t("input", r);
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (n.length !== 1 || n < " ") return;
|
|
21
|
+
let a = s() + n;
|
|
22
|
+
e.model && (e.model.value = a), t("input", a);
|
|
23
|
+
}, l = null;
|
|
24
|
+
return b(() => {
|
|
25
|
+
g(n), e.autofocus && a(n), l = h(c), setTimeout(() => {
|
|
26
|
+
r = !0;
|
|
27
|
+
}, 50);
|
|
28
|
+
}), x(() => {
|
|
29
|
+
l && l(), v(n);
|
|
30
|
+
}), () => {
|
|
31
|
+
let t = s().replace(/[\r\n]+/g, " "), n = (e.placeholder || "").replace(/[\r\n]+/g, " "), r = i(), a = t.length > 0;
|
|
32
|
+
return /* @__PURE__ */ w("box", {
|
|
33
|
+
border: "rounded",
|
|
34
|
+
borderColor: _(r ? "accent" : "line"),
|
|
35
|
+
label: e.label,
|
|
36
|
+
labelColor: _(r ? "accent" : "dim"),
|
|
37
|
+
children: [/* @__PURE__ */ C("text", {
|
|
38
|
+
color: _(a ? "fg" : "dim"),
|
|
39
|
+
children: t || n
|
|
40
|
+
}), r && /* @__PURE__ */ C("text", {
|
|
41
|
+
backgroundColor: _("accent"),
|
|
42
|
+
color: _("accentText"),
|
|
43
|
+
children: " "
|
|
44
|
+
})]
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}, { name: "Input" }), E = y(({ props: t, emit: n }) => {
|
|
48
|
+
let r = Math.random().toString(36).slice(2), i = () => o.activeId === r, s = () => !!t.model?.value, c = (e) => {
|
|
49
|
+
if (!(!i() || t.disabled) && (e === "\r" || e === " ")) {
|
|
50
|
+
let e = !s();
|
|
51
|
+
t.model && (t.model.value = e), n("change", e);
|
|
52
|
+
}
|
|
53
|
+
}, l = null;
|
|
54
|
+
return b(() => {
|
|
55
|
+
g(r), t.autofocus && a(r), l = h(c);
|
|
56
|
+
}), x(() => {
|
|
57
|
+
l && l(), v(r);
|
|
58
|
+
}), () => {
|
|
59
|
+
let n = t.label || "", r = i(), a = s(), o = !!t.disabled, c = a ? e.checkboxOn : e.checkboxOff, l = _(o ? "faint" : a ? "success" : r ? "accent" : "line"), u = _(o ? "faint" : r ? "accent" : "fg");
|
|
60
|
+
return /* @__PURE__ */ w("box", { children: [
|
|
61
|
+
r && /* @__PURE__ */ w("text", {
|
|
62
|
+
color: _("accent"),
|
|
63
|
+
children: [e.focusBar, " "]
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ C("text", {
|
|
66
|
+
color: l,
|
|
67
|
+
children: c
|
|
68
|
+
}),
|
|
69
|
+
n && /* @__PURE__ */ w("text", {
|
|
70
|
+
color: u,
|
|
71
|
+
children: [" ", n]
|
|
72
|
+
})
|
|
73
|
+
] });
|
|
74
|
+
};
|
|
75
|
+
}, { name: "Checkbox" }), D = y(({ props: t, emit: n }) => {
|
|
76
|
+
let r = Math.random().toString(36).slice(2), i = !1, s = () => o.activeId === r, c = () => {
|
|
77
|
+
let e = (t.options || []).findIndex((e) => e.value === t.model?.value);
|
|
78
|
+
return e >= 0 ? e : 0;
|
|
79
|
+
}, l = (e) => {
|
|
80
|
+
if (!s() || !i) return;
|
|
81
|
+
let r = t.options || [];
|
|
82
|
+
if (r.length === 0) return;
|
|
83
|
+
let a = c();
|
|
84
|
+
if (e === "\x1B[A" || e === "k") {
|
|
85
|
+
let e = r[a > 0 ? a - 1 : r.length - 1].value;
|
|
86
|
+
t.model && (t.model.value = e), n("change", e);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (e === "\x1B[B" || e === "j") {
|
|
90
|
+
let e = r[a < r.length - 1 ? a + 1 : 0].value;
|
|
91
|
+
t.model && (t.model.value = e), n("change", e);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (e === "\r" || e === "\n") {
|
|
95
|
+
n("submit", t.model?.value || r[0]?.value || "");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}, u = null;
|
|
99
|
+
return b(() => {
|
|
100
|
+
g(r), t.autofocus && a(r), u = h(l), setTimeout(() => {
|
|
101
|
+
i = !0;
|
|
102
|
+
}, 50);
|
|
103
|
+
}), x(() => {
|
|
104
|
+
u && u(), v(r);
|
|
105
|
+
}), () => {
|
|
106
|
+
let n = t.options || [], r = s(), i = t.model?.value || n[0]?.value || "", a = n.find((e) => e.value === i), o = n.map((t) => {
|
|
107
|
+
let n = t.value === i, r = n ? e.cursor : " ", a = _(n ? "accent" : "fg");
|
|
108
|
+
return /* @__PURE__ */ w("box", { children: [/* @__PURE__ */ w("text", {
|
|
109
|
+
color: _(n ? "accent" : "faint"),
|
|
110
|
+
children: [r, " "]
|
|
111
|
+
}), /* @__PURE__ */ C("text", {
|
|
112
|
+
color: a,
|
|
113
|
+
children: t.label
|
|
114
|
+
})] });
|
|
115
|
+
}), c = t.showDescription && a?.description ? /* @__PURE__ */ C("box", { children: /* @__PURE__ */ w("text", {
|
|
116
|
+
color: _("dim"),
|
|
117
|
+
children: [" ↳ ", a.description]
|
|
118
|
+
}) }) : null;
|
|
119
|
+
return /* @__PURE__ */ w("box", { children: [/* @__PURE__ */ C("box", {
|
|
120
|
+
border: "rounded",
|
|
121
|
+
borderColor: _(r ? "accent" : "line"),
|
|
122
|
+
label: t.label,
|
|
123
|
+
labelColor: _(r ? "accent" : "dim"),
|
|
124
|
+
children: o
|
|
125
|
+
}), c] });
|
|
126
|
+
};
|
|
127
|
+
}, { name: "Select" }), O = y(({ props: t, emit: n }) => {
|
|
128
|
+
let r = Math.random().toString(36).slice(2), i = () => o.activeId === r, s = () => {
|
|
129
|
+
let e = (t.options || []).findIndex((e) => e.value === t.model?.value);
|
|
130
|
+
return e >= 0 ? e : 0;
|
|
131
|
+
}, c = (e) => {
|
|
132
|
+
let r = t.options || [];
|
|
133
|
+
if (r.length === 0) return;
|
|
134
|
+
let i = r.length, a = r[(s() + e + i) % i].value;
|
|
135
|
+
t.model && (t.model.value = a), n("change", a);
|
|
136
|
+
}, l = (e) => {
|
|
137
|
+
i() && (e === "\x1B[A" || e === "k" ? c(-1) : (e === "\x1B[B" || e === "j") && c(1));
|
|
138
|
+
}, u = null;
|
|
139
|
+
return b(() => {
|
|
140
|
+
g(r), t.autofocus && a(r), u = h(l);
|
|
141
|
+
}), x(() => {
|
|
142
|
+
u && u(), v(r);
|
|
143
|
+
}), () => {
|
|
144
|
+
let n = t.options || [], r = i(), a = t.model?.value || n[0]?.value || "", o = n.map((t) => {
|
|
145
|
+
let n = t.value === a, r = n ? e.radioOn : e.radioOff;
|
|
146
|
+
return /* @__PURE__ */ w("box", { children: [/* @__PURE__ */ w("text", {
|
|
147
|
+
color: _(n ? "accent" : "faint"),
|
|
148
|
+
children: [r, " "]
|
|
149
|
+
}), /* @__PURE__ */ C("text", {
|
|
150
|
+
color: _(n ? "fg" : "dim"),
|
|
151
|
+
children: t.label
|
|
152
|
+
})] });
|
|
153
|
+
});
|
|
154
|
+
return /* @__PURE__ */ C("box", {
|
|
155
|
+
border: "rounded",
|
|
156
|
+
borderColor: _(r ? "accent" : "line"),
|
|
157
|
+
label: t.label,
|
|
158
|
+
labelColor: _(r ? "accent" : "dim"),
|
|
159
|
+
children: o
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}, { name: "Radio" }), k = y(({ props: n, emit: r }) => {
|
|
163
|
+
let i = Math.random().toString(36).slice(2), s = !1, c = () => o.activeId === i, l = S({
|
|
164
|
+
cursor: 0,
|
|
165
|
+
requiredHint: !1
|
|
166
|
+
}), u = () => n.model?.value ?? [], d = (e) => {
|
|
167
|
+
n.model && (n.model.value = e), r("change", e);
|
|
168
|
+
}, f = (e) => {
|
|
169
|
+
if (!c() || !s) return;
|
|
170
|
+
let t = n.options || [];
|
|
171
|
+
if (t.length !== 0) {
|
|
172
|
+
if (e === "\x1B[A" || e === "k") {
|
|
173
|
+
l.cursor = l.cursor > 0 ? l.cursor - 1 : t.length - 1;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (e === "\x1B[B" || e === "j") {
|
|
177
|
+
l.cursor = l.cursor < t.length - 1 ? l.cursor + 1 : 0;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (e === " ") {
|
|
181
|
+
let e = t[l.cursor].value, n = u();
|
|
182
|
+
d(n.includes(e) ? n.filter((t) => t !== e) : [...n, e]), l.requiredHint = !1;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (e === "a") {
|
|
186
|
+
let e = t.map((e) => e.value);
|
|
187
|
+
d(u().length === e.length ? [] : e), l.requiredHint = !1;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (e === "\r" || e === "\n") {
|
|
191
|
+
let e = u();
|
|
192
|
+
if (n.required && e.length === 0) {
|
|
193
|
+
l.requiredHint = !0;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
r("submit", e);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}, p = null;
|
|
201
|
+
return b(() => {
|
|
202
|
+
g(i), n.autofocus && a(i), p = h(f), setTimeout(() => {
|
|
203
|
+
s = !0;
|
|
204
|
+
}, t);
|
|
205
|
+
}), x(() => {
|
|
206
|
+
p && p(), v(i);
|
|
207
|
+
}), () => {
|
|
208
|
+
let t = n.options || [], r = c(), i = u(), a = t.flatMap((n, r) => {
|
|
209
|
+
let a = r === l.cursor, o = i.includes(n.value);
|
|
210
|
+
return [...n.group && n.group !== t[r - 1]?.group ? [/* @__PURE__ */ C("box", { children: /* @__PURE__ */ C("text", {
|
|
211
|
+
color: _("dim"),
|
|
212
|
+
children: n.group
|
|
213
|
+
}) })] : [], /* @__PURE__ */ w("box", { children: [
|
|
214
|
+
/* @__PURE__ */ w("text", {
|
|
215
|
+
color: _("accent"),
|
|
216
|
+
children: [a ? e.cursor : " ", " "]
|
|
217
|
+
}),
|
|
218
|
+
/* @__PURE__ */ C("text", {
|
|
219
|
+
color: _(o ? "success" : "line"),
|
|
220
|
+
children: o ? e.checkboxOn : e.checkboxOff
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ w("text", {
|
|
223
|
+
color: _(a ? "accent" : "fg"),
|
|
224
|
+
children: [" ", n.label]
|
|
225
|
+
}),
|
|
226
|
+
n.description && a && /* @__PURE__ */ w("text", {
|
|
227
|
+
color: _("dim"),
|
|
228
|
+
children: [" — ", n.description]
|
|
229
|
+
})
|
|
230
|
+
] })];
|
|
231
|
+
}), o = l.requiredHint ? /* @__PURE__ */ C("box", { children: /* @__PURE__ */ C("text", {
|
|
232
|
+
color: _("danger"),
|
|
233
|
+
children: " select at least one option (space)"
|
|
234
|
+
}) }) : n.showHint ? /* @__PURE__ */ C("box", { children: /* @__PURE__ */ C("text", {
|
|
235
|
+
color: _("dim"),
|
|
236
|
+
children: " space select · a all · enter confirm"
|
|
237
|
+
}) }) : null;
|
|
238
|
+
return /* @__PURE__ */ w("box", { children: [/* @__PURE__ */ C("box", {
|
|
239
|
+
border: "rounded",
|
|
240
|
+
borderColor: _(r ? "accent" : "line"),
|
|
241
|
+
label: n.label,
|
|
242
|
+
labelColor: _(r ? "accent" : "dim"),
|
|
243
|
+
children: a
|
|
244
|
+
}), o] });
|
|
245
|
+
};
|
|
246
|
+
}, { name: "MultiSelect" }), A = y(({ props: n, emit: r }) => {
|
|
247
|
+
let i = Math.random().toString(36).slice(2), s = !1, c = () => o.activeId === i, l = () => n.model?.value ?? !0, u = (e) => {
|
|
248
|
+
n.model && (n.model.value = e), r("change", e);
|
|
249
|
+
}, d = (e) => {
|
|
250
|
+
if (!(!c() || !s)) {
|
|
251
|
+
if (e === "y" || e === "Y") {
|
|
252
|
+
u(!0), r("submit", !0);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (e === "n" || e === "N") {
|
|
256
|
+
u(!1), r("submit", !1);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (e === "\x1B[D" || e === "\x1B[C" || e === "h" || e === "l") {
|
|
260
|
+
u(!l());
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (e === "\r" || e === "\n") {
|
|
264
|
+
r("submit", l());
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}, f = null;
|
|
269
|
+
return b(() => {
|
|
270
|
+
g(i), n.autofocus && a(i), f = h(d), setTimeout(() => {
|
|
271
|
+
s = !0;
|
|
272
|
+
}, t);
|
|
273
|
+
}), x(() => {
|
|
274
|
+
f && f(), v(i);
|
|
275
|
+
}), () => {
|
|
276
|
+
let t = c(), r = l(), i = n.activeLabel || "Yes", a = n.inactiveLabel || "No";
|
|
277
|
+
return /* @__PURE__ */ w("box", { children: [
|
|
278
|
+
/* @__PURE__ */ w("text", {
|
|
279
|
+
color: _(t ? "accent" : "line"),
|
|
280
|
+
children: [t ? e.focusBar : " ", " "]
|
|
281
|
+
}),
|
|
282
|
+
n.label && /* @__PURE__ */ w("text", {
|
|
283
|
+
color: _("fg"),
|
|
284
|
+
children: [n.label, " "]
|
|
285
|
+
}),
|
|
286
|
+
/* @__PURE__ */ w("text", {
|
|
287
|
+
color: _(r ? "accent" : "dim"),
|
|
288
|
+
children: [
|
|
289
|
+
r ? e.radioOn : e.radioOff,
|
|
290
|
+
" ",
|
|
291
|
+
i
|
|
292
|
+
]
|
|
293
|
+
}),
|
|
294
|
+
/* @__PURE__ */ C("text", { children: " " }),
|
|
295
|
+
/* @__PURE__ */ w("text", {
|
|
296
|
+
color: _(r ? "dim" : "accent"),
|
|
297
|
+
children: [
|
|
298
|
+
r ? e.radioOff : e.radioOn,
|
|
299
|
+
" ",
|
|
300
|
+
a
|
|
301
|
+
]
|
|
302
|
+
})
|
|
303
|
+
] });
|
|
304
|
+
};
|
|
305
|
+
}, { name: "Confirm" }), j = "", M = "\b", N = "\x1B", P = y(({ props: y, emit: T }) => {
|
|
306
|
+
let E = Math.random().toString(36).slice(2), D = !1, O = () => o.activeId === E, k = S({
|
|
307
|
+
cursor: 0,
|
|
308
|
+
goalCol: -1
|
|
309
|
+
}), A = () => y.model?.value ?? "", P = () => Math.max(4, (y.width || Math.max(20, s().columns - 4)) - 2), F = () => {
|
|
310
|
+
let e = A();
|
|
311
|
+
return {
|
|
312
|
+
text: e,
|
|
313
|
+
cursor: Math.min(k.cursor, [...e].length)
|
|
314
|
+
};
|
|
315
|
+
}, I = (e, t) => {
|
|
316
|
+
y.model && (y.model.value = e.text), k.cursor = e.cursor, t && T("input", e.text);
|
|
317
|
+
}, L = (e) => {
|
|
318
|
+
if (!O() || !D) return;
|
|
319
|
+
let t = P();
|
|
320
|
+
if (e === "\r") {
|
|
321
|
+
let e = A();
|
|
322
|
+
if (e.endsWith("\\")) {
|
|
323
|
+
let t = [...e];
|
|
324
|
+
return I(c({
|
|
325
|
+
text: t.slice(0, -1).join(""),
|
|
326
|
+
cursor: Math.min(F().cursor, t.length - 1)
|
|
327
|
+
}, "\n"), !0), k.goalCol = -1, !0;
|
|
328
|
+
}
|
|
329
|
+
return T("submit", e), !0;
|
|
330
|
+
}
|
|
331
|
+
if (e === "\n" || e === N + "\r" || e === N + "[13;2u" || e === N + "[13;5u") return I(c(F(), "\n"), !0), k.goalCol = -1, !0;
|
|
332
|
+
if (e === j || e === M) return I(i(F()), !0), k.goalCol = -1, !0;
|
|
333
|
+
if (e === N + "[3~") return I(r(F()), !0), k.goalCol = -1, !0;
|
|
334
|
+
if (e === N + "[D") return I(u(F()), !1), k.goalCol = -1, !0;
|
|
335
|
+
if (e === N + "[C") return I(p(F()), !1), k.goalCol = -1, !0;
|
|
336
|
+
if (e === N + "[A" || e === N + "[B") {
|
|
337
|
+
let n = e === N + "[A" ? -1 : 1, r = m(F(), t, n, k.goalCol >= 0 ? k.goalCol : void 0);
|
|
338
|
+
return I(r.state, !1), k.goalCol = r.goalCol, !0;
|
|
339
|
+
}
|
|
340
|
+
if (e === N + "[H" || e === N + "[1~") return I(f(F(), t), !1), k.goalCol = -1, !0;
|
|
341
|
+
if (e === N + "[F" || e === N + "[4~") return I(d(F(), t), !1), k.goalCol = -1, !0;
|
|
342
|
+
if (e.length >= 1 && e.charCodeAt(0) !== 27) {
|
|
343
|
+
let t = e.replace(/\r\n|\r/g, "\n"), n = t.indexOf(N);
|
|
344
|
+
return n >= 0 && (t = t.slice(0, n)), t = [...t].filter((e) => e === "\n" || e >= " ").join(""), t.length === 0 ? void 0 : (I(c(F(), t), !0), k.goalCol = -1, !0);
|
|
345
|
+
}
|
|
346
|
+
}, R = null;
|
|
347
|
+
return b(() => {
|
|
348
|
+
g(E), y.autofocus && a(E), R = h(L), setTimeout(() => {
|
|
349
|
+
D = !0;
|
|
350
|
+
}, t);
|
|
351
|
+
}), x(() => {
|
|
352
|
+
R && R(), v(E);
|
|
353
|
+
}), () => {
|
|
354
|
+
let t = O(), r = P(), i = Math.max(1, y.maxRows || 6), a = y.promptGlyph || e.cursor, o = A(), s = Math.min(k.cursor, [...o].length), c = l(o, r), u = n(c, s), d = c.rows.length, f = Math.min(d, i), p = 0;
|
|
355
|
+
d > i && (p = Math.min(Math.max(0, u.row - i + 1), d - i), u.row < p && (p = u.row));
|
|
356
|
+
let m = [];
|
|
357
|
+
for (let e = p; e < p + f; e++) {
|
|
358
|
+
let n = c.rows[e], r = e === 0 ? /* @__PURE__ */ w("text", {
|
|
359
|
+
color: _(t ? "accent" : "dim"),
|
|
360
|
+
children: [a, " "]
|
|
361
|
+
}) : /* @__PURE__ */ C("text", { children: " " }), i;
|
|
362
|
+
if (t && e === u.row) {
|
|
363
|
+
let e = [...n.text], t = s - n.start, r = e.slice(0, t).join(""), a = t < e.length ? e[t] : " ", o = t < e.length ? e.slice(t + 1).join("") : "";
|
|
364
|
+
i = /* @__PURE__ */ w("text", { children: [
|
|
365
|
+
/* @__PURE__ */ C("text", {
|
|
366
|
+
color: _("fg"),
|
|
367
|
+
children: r
|
|
368
|
+
}),
|
|
369
|
+
/* @__PURE__ */ C("text", {
|
|
370
|
+
backgroundColor: _("accent"),
|
|
371
|
+
color: _("accentText"),
|
|
372
|
+
children: a
|
|
373
|
+
}),
|
|
374
|
+
/* @__PURE__ */ C("text", {
|
|
375
|
+
color: _("fg"),
|
|
376
|
+
children: o
|
|
377
|
+
})
|
|
378
|
+
] });
|
|
379
|
+
} else i = /* @__PURE__ */ C("text", {
|
|
380
|
+
color: _("fg"),
|
|
381
|
+
children: n.text
|
|
382
|
+
});
|
|
383
|
+
let l = e === 0 && o.length === 0 && y.placeholder;
|
|
384
|
+
m.push(/* @__PURE__ */ w("box", { children: [
|
|
385
|
+
r,
|
|
386
|
+
i,
|
|
387
|
+
l && /* @__PURE__ */ C("text", {
|
|
388
|
+
color: _("dim"),
|
|
389
|
+
children: y.placeholder
|
|
390
|
+
})
|
|
391
|
+
] }));
|
|
392
|
+
}
|
|
393
|
+
return /* @__PURE__ */ C("box", { children: m });
|
|
394
|
+
};
|
|
395
|
+
}, { name: "TextArea" });
|
|
396
|
+
//#endregion
|
|
397
|
+
export { D as a, O as i, A as n, E as o, k as r, T as s, P as t };
|
|
398
|
+
|
|
399
|
+
//# sourceMappingURL=forms-MgpyoQI5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms-MgpyoQI5.js","names":[],"sources":["../src/forms/Input.tsx","../src/forms/Checkbox.tsx","../src/forms/Select.tsx","../src/forms/Radio.tsx","../src/forms/MultiSelect.tsx","../src/forms/Confirm.tsx","../src/forms/TextArea.tsx"],"sourcesContent":["/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor,\r\n} from '@sigx/terminal-zero';\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;\r\n const isFocused = () => focusState.activeId === id;\r\n const getValue = () => props.model?.value || '';\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused() || !isReady) return;\r\n\r\n if (key === '\\r' || key === '\\n') {\r\n emit('submit', getValue());\r\n return;\r\n }\r\n if (key === '\\u007F' || key === '\\b') { // Backspace / Delete\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 // Printable characters only — control bytes (incl. Tab, which now\r\n // cascades through the key layers to the focus-cycle handler) and\r\n // escape sequences are ignored.\r\n if (key.length !== 1 || key < ' ') 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) focus(id);\r\n keyCleanup = onKey(handleKey);\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 focused = isFocused();\r\n const hasValue = val.length > 0;\r\n\r\n return (\r\n <box border=\"rounded\" borderColor={resolveColor(focused ? 'accent' : 'line')} label={props.label} labelColor={resolveColor(focused ? 'accent' : 'dim')}>\r\n <text color={resolveColor(hasValue ? 'fg' : 'dim')}>{val || placeholder}</text>\r\n {focused && (\r\n // Block cursor: a reverse-video space (exactly one cell).\r\n <text backgroundColor={resolveColor('accent')} color={resolveColor('accentText')}> </text>\r\n )}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Input' });\r\n\r\nexport default Input;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor, GLYPHS,\r\n} from '@sigx/terminal-zero';\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 const isFocused = () => focusState.activeId === id;\r\n const checked = () => !!props.model?.value;\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused() || props.disabled) return;\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 const marker = isChecked ? GLYPHS.checkboxOn : GLYPHS.checkboxOff;\r\n const markerColor = disabled\r\n ? resolveColor('faint')\r\n : resolveColor(isChecked ? 'success' : (focused ? 'accent' : 'line'));\r\n const labelColor = disabled\r\n ? resolveColor('faint')\r\n : resolveColor(focused ? 'accent' : 'fg');\r\n\r\n return (\r\n <box>\r\n {focused && <text color={resolveColor('accent')}>{GLYPHS.focusBar} </text>}\r\n <text color={markerColor}>{marker}</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 {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor, GLYPHS,\r\n} from '@sigx/terminal-zero';\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;\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() || !isReady) return;\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n const currentIndex = getCurrentIndex();\r\n\r\n if (key === '\\x1B[A' || key === 'k') { // up\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 if (key === '\\x1B[B' || key === 'j') { // down\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 if (key === '\\r' || key === '\\n') { // submit\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) focus(id);\r\n keyCleanup = onKey(handleKey);\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 selectedOption = options.find(o => o.value === currentValue);\r\n\r\n const optionElements = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const indicator = isSelected ? GLYPHS.cursor : ' ';\r\n const rowColor = resolveColor(isSelected ? 'accent' : 'fg');\r\n return (\r\n <box>\r\n <text color={resolveColor(isSelected ? 'accent' : 'faint')}>{indicator} </text>\r\n <text color={rowColor}>{option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n const descriptionElement = props.showDescription && selectedOption?.description ? (\r\n <box>\r\n <text color={resolveColor('dim')}> ↳ {selectedOption.description}</text>\r\n </box>\r\n ) : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"rounded\" borderColor={resolveColor(focused ? 'accent' : 'line')} label={props.label} labelColor={resolveColor(focused ? 'accent' : 'dim')}>\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","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor, GLYPHS,\r\n} from '@sigx/terminal-zero';\r\n\r\nexport interface RadioOption<T = string> {\r\n label: string;\r\n value: T;\r\n}\r\n\r\n/**\r\n * Single-choice group. Like Select, but every option is always visible with a\r\n * ● / ○ marker. Arrow keys (or j/k) move the selection.\r\n */\r\nexport const Radio = component<\r\n Define.Model<string> &\r\n Define.Prop<\"options\", RadioOption[], true> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Event<\"change\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\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 move = (delta: number) => {\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n const len = options.length;\r\n const newIndex = (getCurrentIndex() + delta + len) % len;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (key === '\\x1B[A' || key === 'k') move(-1);\r\n else if (key === '\\x1B[B' || key === 'j') move(1);\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 options = props.options || [];\r\n const focused = isFocused();\r\n const currentValue = props.model?.value || options[0]?.value || '';\r\n\r\n const rows = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const marker = isSelected ? GLYPHS.radioOn : GLYPHS.radioOff;\r\n return (\r\n <box>\r\n <text color={resolveColor(isSelected ? 'accent' : 'faint')}>{marker} </text>\r\n <text color={resolveColor(isSelected ? 'fg' : 'dim')}>{option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n return (\r\n <box border=\"rounded\" borderColor={resolveColor(focused ? 'accent' : 'line')} label={props.label} labelColor={resolveColor(focused ? 'accent' : 'dim')}>\r\n {rows}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Radio' });\r\n\r\nexport default Radio;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor, GLYPHS, READY_DELAY_MS,\r\n} from '@sigx/terminal-zero';\r\n\r\nexport interface MultiSelectOption<T = string> {\r\n label: string;\r\n value: T;\r\n description?: string;\r\n /**\r\n * Section header rendered above this option when it differs from the\r\n * previous option's group (e.g. \"connected devices\" / \"available to\r\n * boot\"). Purely visual — the cursor skips headers and indexes stay\r\n * option-based. Pre-sort options by group.\r\n */\r\n group?: string;\r\n}\r\n\r\n/**\r\n * Checkbox list with a movable cursor. Model holds the checked values.\r\n * Keys (while focused): ↑/k ↓/j move, Space toggles, `a` toggles all,\r\n * Enter submits (blocked with a hint when `required` and nothing is checked).\r\n */\r\nexport const MultiSelect = component<\r\n Define.Model<string[]> &\r\n Define.Prop<\"options\", MultiSelectOption[], true> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Prop<\"required\", boolean, false> &\r\n Define.Prop<\"showHint\", 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;\r\n const isFocused = () => focusState.activeId === id;\r\n const state = signal({ cursor: 0, requiredHint: false });\r\n\r\n const getChecked = () => props.model?.value ?? [];\r\n const setChecked = (next: string[]) => {\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused() || !isReady) return;\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n\r\n if (key === '\\x1B[A' || key === 'k') {\r\n state.cursor = state.cursor > 0 ? state.cursor - 1 : options.length - 1;\r\n return;\r\n }\r\n if (key === '\\x1B[B' || key === 'j') {\r\n state.cursor = state.cursor < options.length - 1 ? state.cursor + 1 : 0;\r\n return;\r\n }\r\n if (key === ' ') {\r\n const value = options[state.cursor].value;\r\n const checked = getChecked();\r\n setChecked(checked.includes(value) ? checked.filter((v) => v !== value) : [...checked, value]);\r\n state.requiredHint = false;\r\n return;\r\n }\r\n if (key === 'a') {\r\n const all = options.map((o) => o.value);\r\n setChecked(getChecked().length === all.length ? [] : all);\r\n state.requiredHint = false;\r\n return;\r\n }\r\n if (key === '\\r' || key === '\\n') {\r\n const checked = getChecked();\r\n if (props.required && checked.length === 0) {\r\n state.requiredHint = true;\r\n return;\r\n }\r\n emit('submit', checked);\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) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n setTimeout(() => { isReady = true; }, READY_DELAY_MS);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const options = props.options || [];\r\n const focused = isFocused();\r\n const checked = getChecked();\r\n\r\n const rows = options.flatMap((option, i) => {\r\n const onCursor = i === state.cursor;\r\n const isChecked = checked.includes(option.value);\r\n const header = option.group && option.group !== options[i - 1]?.group\r\n ? [<box><text color={resolveColor('dim')}>{option.group}</text></box>]\r\n : [];\r\n return [\r\n ...header,\r\n <box>\r\n <text color={resolveColor('accent')}>{onCursor ? GLYPHS.cursor : ' '} </text>\r\n <text color={resolveColor(isChecked ? 'success' : 'line')}>\r\n {isChecked ? GLYPHS.checkboxOn : GLYPHS.checkboxOff}\r\n </text>\r\n <text color={resolveColor(onCursor ? 'accent' : 'fg')}> {option.label}</text>\r\n {option.description && onCursor && <text color={resolveColor('dim')}> — {option.description}</text>}\r\n </box>,\r\n ];\r\n });\r\n\r\n const hint = state.requiredHint\r\n ? <box><text color={resolveColor('danger')}> select at least one option (space)</text></box>\r\n : props.showHint\r\n ? <box><text color={resolveColor('dim')}> space select · a all · enter confirm</text></box>\r\n : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"rounded\" borderColor={resolveColor(focused ? 'accent' : 'line')} label={props.label} labelColor={resolveColor(focused ? 'accent' : 'dim')}>\r\n {rows}\r\n </box>\r\n {hint}\r\n </box>\r\n );\r\n };\r\n}, { name: 'MultiSelect' });\r\n\r\nexport default MultiSelect;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor, GLYPHS, READY_DELAY_MS,\r\n} from '@sigx/terminal-zero';\r\n\r\n/**\r\n * Yes/No toggle. Keys (while focused): y/Y and n/N answer immediately,\r\n * ←/→ (or h/l) flip the selection, Enter submits the current value.\r\n */\r\nexport const Confirm = component<\r\n Define.Model<boolean> &\r\n Define.Prop<\"label\", string, false> &\r\n Define.Prop<\"activeLabel\", string, false> &\r\n Define.Prop<\"inactiveLabel\", string, false> &\r\n Define.Prop<\"autofocus\", boolean, false> &\r\n Define.Event<\"change\", boolean> &\r\n Define.Event<\"submit\", boolean>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false;\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getValue = () => props.model?.value ?? true;\r\n const setValue = (next: boolean) => {\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused() || !isReady) return;\r\n if (key === 'y' || key === 'Y') {\r\n setValue(true);\r\n emit('submit', true);\r\n return;\r\n }\r\n if (key === 'n' || key === 'N') {\r\n setValue(false);\r\n emit('submit', false);\r\n return;\r\n }\r\n if (key === '\\x1B[D' || key === '\\x1B[C' || key === 'h' || key === 'l') {\r\n setValue(!getValue());\r\n return;\r\n }\r\n if (key === '\\r' || key === '\\n') {\r\n emit('submit', getValue());\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) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n setTimeout(() => { isReady = true; }, READY_DELAY_MS);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const value = getValue();\r\n const yes = props.activeLabel || 'Yes';\r\n const no = props.inactiveLabel || 'No';\r\n\r\n return (\r\n <box>\r\n <text color={resolveColor(focused ? 'accent' : 'line')}>{focused ? GLYPHS.focusBar : ' '} </text>\r\n {props.label && <text color={resolveColor('fg')}>{props.label} </text>}\r\n <text color={resolveColor(value ? 'accent' : 'dim')}>\r\n {value ? GLYPHS.radioOn : GLYPHS.radioOff} {yes}\r\n </text>\r\n <text> </text>\r\n <text color={resolveColor(value ? 'dim' : 'accent')}>\r\n {value ? GLYPHS.radioOff : GLYPHS.radioOn} {no}\r\n </text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'Confirm' });\r\n\r\nexport default Confirm;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type Define } from '@sigx/runtime-core';\r\nimport {\r\n onKey, registerFocusable, unregisterFocusable, focusState, focus, resolveColor,\r\n getTerminalSize, GLYPHS, READY_DELAY_MS,\r\n layoutText, cursorToRowCol, insertAt, deleteBefore, deleteAt,\r\n moveLeft, moveRight, moveVertical, moveLineStart, moveLineEnd,\r\n type TextBufferState,\r\n} from '@sigx/terminal-zero';\r\n\r\nconst DEL = String.fromCharCode(127);\r\nconst BS = String.fromCharCode(8);\r\nconst ESC = String.fromCharCode(27);\r\n\r\n/**\r\n * Growing multi-line text input — the Claude-style prompt box. Soft-wraps to\r\n * `width`, grows from one row up to `maxRows` (then scrolls internally,\r\n * keeping the cursor visible), with a movable block cursor.\r\n *\r\n * Keys (while focused): printable characters and paste chunks insert at the\r\n * cursor; ←/→/↑/↓ move (↑/↓ keep a sticky goal column); Home/End jump within\r\n * the visual row; Backspace/Delete edit around the cursor. Enter (`\\r`)\r\n * submits — unless the text ends with `\\`, which is stripped and replaced by\r\n * a newline (continuation). Newlines: Ctrl+J always; ESC+`\\r` and the CSI-u\r\n * Shift/Ctrl+Enter encodings for terminals configured to send them (plain\r\n * Shift+Enter is indistinguishable from Enter on unconfigured terminals).\r\n * NOTE: this deliberately diverges from the prompt engine's `isEnter` (which\r\n * treats `\\r` and `\\n` alike) — an editor needs the distinction.\r\n *\r\n * Paste chunks containing escape sequences keep only the printable prefix\r\n * (bracketed-paste mode is not implemented).\r\n */\r\nexport const TextArea = component<\r\n Define.Model<string> &\r\n Define.Prop<'placeholder', string, false> &\r\n Define.Prop<'promptGlyph', string, false> &\r\n Define.Prop<'width', number, false> &\r\n Define.Prop<'maxRows', number, false> &\r\n Define.Prop<'autofocus', boolean, 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;\r\n const isFocused = () => focusState.activeId === id;\r\n const state = signal({ cursor: 0, goalCol: -1 });\r\n\r\n const getValue = () => props.model?.value ?? '';\r\n const innerWidth = () => Math.max(4, (props.width || Math.max(20, getTerminalSize().columns - 4)) - 2);\r\n\r\n const buf = (): TextBufferState => {\r\n const text = getValue();\r\n return { text, cursor: Math.min(state.cursor, [...text].length) };\r\n };\r\n const apply = (next: TextBufferState, emitInput: boolean) => {\r\n if (props.model) props.model.value = next.text;\r\n state.cursor = next.cursor;\r\n if (emitInput) emit('input', next.text);\r\n };\r\n\r\n const handleKey = (key: string): boolean | void => {\r\n if (!isFocused() || !isReady) return;\r\n const width = innerWidth();\r\n\r\n if (key === '\\r') {\r\n const text = getValue();\r\n if (text.endsWith('\\\\')) {\r\n // Continuation: strip the backslash, insert a newline.\r\n const chars = [...text];\r\n const stripped = { text: chars.slice(0, -1).join(''), cursor: Math.min(buf().cursor, chars.length - 1) };\r\n apply(insertAt(stripped, '\\n'), true);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n emit('submit', text);\r\n return true;\r\n }\r\n // Newline keys: Ctrl+J (bare \\n) works everywhere; ESC+\\r is what\r\n // terminals configured for Shift+Enter/Alt+Enter send (e.g. Claude\r\n // Code's /terminal-setup binding); \\x1b[13;2u (and ;5u) is the CSI-u\r\n // encoding of Shift+Enter / Ctrl+Enter. Plain Shift+Enter on an\r\n // unconfigured terminal is indistinguishable from Enter (\\r).\r\n if (key === '\\n' || key === ESC + '\\r' || key === ESC + '[13;2u' || key === ESC + '[13;5u') {\r\n apply(insertAt(buf(), '\\n'), true);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === DEL || key === BS) {\r\n apply(deleteBefore(buf()), true);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === ESC + '[3~') { // forward delete\r\n apply(deleteAt(buf()), true);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === ESC + '[D') {\r\n apply(moveLeft(buf()), false);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === ESC + '[C') {\r\n apply(moveRight(buf()), false);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === ESC + '[A' || key === ESC + '[B') {\r\n const dir = key === ESC + '[A' ? -1 : 1;\r\n const r = moveVertical(buf(), width, dir, state.goalCol >= 0 ? state.goalCol : undefined);\r\n apply(r.state, false);\r\n state.goalCol = r.goalCol;\r\n return true;\r\n }\r\n if (key === ESC + '[H' || key === ESC + '[1~') {\r\n apply(moveLineStart(buf(), width), false);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n if (key === ESC + '[F' || key === ESC + '[4~') {\r\n apply(moveLineEnd(buf(), width), false);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n // Printable characters and paste chunks. A chunk starting with ESC is\r\n // a key sequence (handled above or not ours); a mixed chunk keeps only\r\n // the printable prefix.\r\n if (key.length >= 1 && key.charCodeAt(0) !== 27) {\r\n let chunk = key.replace(/\\r\\n|\\r/g, '\\n');\r\n const escIdx = chunk.indexOf(ESC);\r\n if (escIdx >= 0) chunk = chunk.slice(0, escIdx);\r\n // Strip control bytes except newline.\r\n chunk = [...chunk].filter((ch) => ch === '\\n' || ch >= ' ').join('');\r\n if (chunk.length === 0) return;\r\n apply(insertAt(buf(), chunk), true);\r\n state.goalCol = -1;\r\n return true;\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n setTimeout(() => { isReady = true; }, READY_DELAY_MS);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const width = innerWidth();\r\n const maxRows = Math.max(1, props.maxRows || 6);\r\n const glyph = props.promptGlyph || GLYPHS.cursor;\r\n const text = getValue();\r\n const cursor = Math.min(state.cursor, [...text].length);\r\n\r\n const layout = layoutText(text, width);\r\n const pos = cursorToRowCol(layout, cursor);\r\n\r\n // Window the rows so the cursor row is always visible.\r\n const totalRows = layout.rows.length;\r\n const visible = Math.min(totalRows, maxRows);\r\n let top = 0;\r\n if (totalRows > maxRows) {\r\n top = Math.min(Math.max(0, pos.row - maxRows + 1), totalRows - maxRows);\r\n if (pos.row < top) top = pos.row;\r\n }\r\n\r\n const rows = [];\r\n for (let r = top; r < top + visible; r++) {\r\n const row = layout.rows[r];\r\n const prefix = r === 0\r\n ? <text color={resolveColor(focused ? 'accent' : 'dim')}>{glyph} </text>\r\n : <text>{' '}</text>;\r\n\r\n let body;\r\n if (focused && r === pos.row) {\r\n // Split the row around the cursor; invert the glyph under it.\r\n const chars = [...row.text];\r\n const at = cursor - row.start;\r\n const before = chars.slice(0, at).join('');\r\n const under = at < chars.length ? chars[at] : ' ';\r\n const after = at < chars.length ? chars.slice(at + 1).join('') : '';\r\n body = (\r\n <text>\r\n <text color={resolveColor('fg')}>{before}</text>\r\n <text backgroundColor={resolveColor('accent')} color={resolveColor('accentText')}>{under}</text>\r\n <text color={resolveColor('fg')}>{after}</text>\r\n </text>\r\n );\r\n } else {\r\n body = <text color={resolveColor('fg')}>{row.text}</text>;\r\n }\r\n\r\n const isPlaceholderRow = r === 0 && text.length === 0 && props.placeholder;\r\n rows.push(\r\n <box>\r\n {prefix}\r\n {body}\r\n {isPlaceholderRow && <text color={resolveColor('dim')}>{props.placeholder}</text>}\r\n </box>,\r\n );\r\n }\r\n\r\n return <box>{rows}</box>;\r\n };\r\n}, { name: 'TextArea' });\r\n\r\nexport default TextArea;\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A large gradient-filled headline in the built-in 5-row block font
|
|
3
|
+
* (A–Z 0–9 and basic punctuation; other characters render as spaces).
|
|
4
|
+
* `direction` picks the gradient axis; `animate` scrolls it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const Banner: import("@sigx/runtime-core").ComponentFactory<{
|
|
7
|
+
text: string;
|
|
8
|
+
} & {
|
|
9
|
+
colors?: string[] | undefined;
|
|
10
|
+
} & {
|
|
11
|
+
preset?: "fire" | "ocean" | "rainbow" | "sigx" | "sunset" | undefined;
|
|
12
|
+
} & {
|
|
13
|
+
direction?: "diagonal" | "horizontal" | "vertical" | undefined;
|
|
14
|
+
} & {
|
|
15
|
+
animate?: boolean | undefined;
|
|
16
|
+
} & {
|
|
17
|
+
speed?: number | undefined;
|
|
18
|
+
}, void, {}>;
|
|
19
|
+
export default Banner;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text colored across a multi-stop gradient, one sample per character.
|
|
3
|
+
* Stops are theme tokens or hex; `animate` scrolls the gradient through the
|
|
4
|
+
* text (ping-pong, seamless). Degrades by color depth: a single accent color
|
|
5
|
+
* at ansi16 (per-char nearest-16 is speckle noise), plain text at none.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Gradient: import("@sigx/runtime-core").ComponentFactory<{
|
|
8
|
+
text: string;
|
|
9
|
+
} & {
|
|
10
|
+
colors?: string[] | undefined;
|
|
11
|
+
} & {
|
|
12
|
+
preset?: "fire" | "ocean" | "rainbow" | "sigx" | "sunset" | undefined;
|
|
13
|
+
} & {
|
|
14
|
+
animate?: boolean | undefined;
|
|
15
|
+
} & {
|
|
16
|
+
speed?: number | undefined;
|
|
17
|
+
}, void, {}>;
|
|
18
|
+
export default Gradient;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a pixel grid as terminal half-blocks (two pixel rows per terminal
|
|
3
|
+
* line). Each character in `rows` is a pixel keyed into `palette`; `.` and
|
|
4
|
+
* space are transparent. Palette values are theme tokens or `#hex` —
|
|
5
|
+
* resolved per color depth (plain block glyphs at depth none).
|
|
6
|
+
*
|
|
7
|
+
* The pure builder is exported so apps can `printStatic` a logo into the
|
|
8
|
+
* scrollback transcript; the component renders it live.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderPixelArt(rows: string[], palette: Record<string, string>): string[];
|
|
11
|
+
export declare const PixelArt: import("@sigx/runtime-core").ComponentFactory<{
|
|
12
|
+
rows: string[];
|
|
13
|
+
} & {
|
|
14
|
+
palette: Record<string, string>;
|
|
15
|
+
}, void, {}>;
|
|
16
|
+
export default PixelArt;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A highlight sweep travelling across muted text — the "thinking…" effect.
|
|
3
|
+
* `color` is the base (default `dim`), `highlight` the sweep peak (default
|
|
4
|
+
* `fg`), `width` the sweep half-width in characters. Static base color at
|
|
5
|
+
* ansi16/none depth.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Shimmer: import("@sigx/runtime-core").ComponentFactory<{
|
|
8
|
+
text: string;
|
|
9
|
+
} & {
|
|
10
|
+
color?: string | undefined;
|
|
11
|
+
} & {
|
|
12
|
+
highlight?: string | undefined;
|
|
13
|
+
} & {
|
|
14
|
+
width?: number | undefined;
|
|
15
|
+
} & {
|
|
16
|
+
speed?: number | undefined;
|
|
17
|
+
}, void, {}>;
|
|
18
|
+
export default Shimmer;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in 5-row block font for <Banner> — full blocks and spaces only, so
|
|
3
|
+
* every cell is width-1 (gradient-fillable, no wide-glyph drift). Glyphs are
|
|
4
|
+
* authored as '#'/'.' strings for readability and converted once at load.
|
|
5
|
+
* No external font dependency.
|
|
6
|
+
*/
|
|
7
|
+
export declare const BLOCK_FONT_HEIGHT = 5;
|
|
8
|
+
/**
|
|
9
|
+
* Render text in the block font: 5 equal-width rows of '█'/space. Input is
|
|
10
|
+
* uppercased; unsupported characters render as a space glyph. Glyphs are
|
|
11
|
+
* separated by a one-column gap.
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderBlock(text: string): string[];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Gradient } from './Gradient';
|
|
2
|
+
export { Shimmer } from './Shimmer';
|
|
3
|
+
export { Banner } from './Banner';
|
|
4
|
+
export { GRADIENT_PRESETS, type GradientPreset } from './presets';
|
|
5
|
+
export { renderBlock, BLOCK_FONT_HEIGHT } from './blockFont';
|
|
6
|
+
export { PixelArt, renderPixelArt } from './PixelArt';
|
package/dist/fx/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { t as e } from "../presets-uqseGRqO.js";
|
|
2
|
+
import { a as t, i as n, n as r, o as i, r as a, s as o, t as s } from "../fx-igWaVCkB.js";
|
|
3
|
+
export { n as BLOCK_FONT_HEIGHT, a as Banner, e as GRADIENT_PRESETS, o as Gradient, s as PixelArt, i as Shimmer, t as renderBlock, r as renderPixelArt };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colorize per code point. `hexAt(i, len)` returns the hex for visible char
|
|
3
|
+
* `i`. Run-length emission: an SGR is only emitted when the sampled color
|
|
4
|
+
* changes (spaces keep the current run). Ends with default-fg (`\x1b[39m`,
|
|
5
|
+
* not a full reset — it must not clobber renderer-applied backgrounds) when
|
|
6
|
+
* any color was emitted.
|
|
7
|
+
*/
|
|
8
|
+
export declare function colorizeByIndex(text: string, hexAt: (i: number, len: number) => string): string;
|
|
9
|
+
/** Resolve gradient stops: explicit colors win over a preset; tokens → hex. */
|
|
10
|
+
export declare function resolveStops(colors: string[] | undefined, preset: string | undefined): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Ping-pong a sample sequence (a → b → a without repeating the endpoints), so
|
|
13
|
+
* scrolling a non-cyclic palette has no seam.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pingPong(samples: string[]): string[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gradient stop presets. Stops are theme tokens OR raw hex: tokens resolve
|
|
3
|
+
* through `resolveColor` at render time, so token-based presets (like `sigx`)
|
|
4
|
+
* re-color live when the theme changes; fixed-hex presets look the same on
|
|
5
|
+
* every theme.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GRADIENT_PRESETS: {
|
|
8
|
+
readonly sigx: readonly ['accent', 'info', 'success'];
|
|
9
|
+
readonly rainbow: readonly ['#ff5f5f', '#f5c518', '#3fd07f', '#34d4d4', '#4a9eff', '#c678dd'];
|
|
10
|
+
readonly sunset: readonly ['#ff7e5f', '#feb47b', '#ffcd94'];
|
|
11
|
+
readonly ocean: readonly ['#2193b0', '#6dd5ed', '#b8e8f4'];
|
|
12
|
+
readonly fire: readonly ['#f12711', '#f5af19'];
|
|
13
|
+
};
|
|
14
|
+
export type GradientPreset = keyof typeof GRADIENT_PRESETS;
|