@termuijs/ui 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,780 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Box: () => import_widgets12.Box,
24
+ CommandPalette: () => CommandPalette,
25
+ ConfirmDialog: () => ConfirmDialog,
26
+ Divider: () => Divider,
27
+ Form: () => Form,
28
+ Gauge: () => import_widgets12.Gauge,
29
+ List: () => import_widgets12.List,
30
+ LogView: () => import_widgets12.LogView,
31
+ Modal: () => Modal,
32
+ MultiSelect: () => MultiSelect,
33
+ ProgressBar: () => import_widgets12.ProgressBar,
34
+ Select: () => Select,
35
+ Spacer: () => Spacer,
36
+ Sparkline: () => import_widgets12.Sparkline,
37
+ Spinner: () => import_widgets12.Spinner,
38
+ StatusIndicator: () => import_widgets12.StatusIndicator,
39
+ Table: () => import_widgets12.Table,
40
+ Tabs: () => Tabs,
41
+ Text: () => import_widgets12.Text,
42
+ TextInput: () => import_widgets12.TextInput,
43
+ Toast: () => Toast,
44
+ Tree: () => Tree,
45
+ Widget: () => import_widgets12.Widget
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+ var import_widgets12 = require("@termuijs/widgets");
49
+
50
+ // src/Divider.ts
51
+ var import_widgets = require("@termuijs/widgets");
52
+ var import_core = require("@termuijs/core");
53
+ var Divider = class extends import_widgets.Widget {
54
+ _char;
55
+ _color;
56
+ _title;
57
+ constructor(options = {}) {
58
+ super((0, import_core.mergeStyles)((0, import_core.defaultStyle)(), { height: 1 }));
59
+ this._char = options.char ?? "\u2500";
60
+ this._color = options.color;
61
+ this._title = options.title ?? "";
62
+ }
63
+ _renderSelf(screen) {
64
+ const { x, y, width } = this._rect;
65
+ if (width <= 0) return;
66
+ const attrs = (0, import_core.styleToCellAttrs)(this.style);
67
+ if (this._color) attrs.fg = this._color;
68
+ attrs.dim = true;
69
+ if (this._title) {
70
+ const titleStr = ` ${this._title} `;
71
+ const padLeft = Math.max(0, Math.floor((width - titleStr.length) / 2));
72
+ const padRight = Math.max(0, width - padLeft - titleStr.length);
73
+ const line = this._char.repeat(padLeft) + titleStr + this._char.repeat(padRight);
74
+ screen.writeString(x, y, line.slice(0, width), attrs);
75
+ } else {
76
+ screen.writeString(x, y, this._char.repeat(width), attrs);
77
+ }
78
+ }
79
+ };
80
+
81
+ // src/Spacer.ts
82
+ var import_widgets2 = require("@termuijs/widgets");
83
+ var import_core2 = require("@termuijs/core");
84
+ var Spacer = class extends import_widgets2.Widget {
85
+ constructor(grow = 1) {
86
+ super((0, import_core2.mergeStyles)((0, import_core2.defaultStyle)(), { flexGrow: grow }));
87
+ }
88
+ _renderSelf(_screen) {
89
+ }
90
+ };
91
+
92
+ // src/Tabs.ts
93
+ var import_widgets3 = require("@termuijs/widgets");
94
+ var import_core3 = require("@termuijs/core");
95
+ var Tabs = class extends import_widgets3.Widget {
96
+ _tabs = [];
97
+ _activeIndex = 0;
98
+ _activeColor;
99
+ _inactiveColor;
100
+ focusable = true;
101
+ constructor(tabs, options = {}) {
102
+ super((0, import_core3.mergeStyles)((0, import_core3.defaultStyle)(), { flexGrow: 1, border: options.border ?? "single" }));
103
+ this._tabs = tabs;
104
+ this._activeColor = options.activeColor ?? { type: "named", name: "cyan" };
105
+ this._inactiveColor = options.inactiveColor ?? { type: "named", name: "brightBlack" };
106
+ }
107
+ get activeIndex() {
108
+ return this._activeIndex;
109
+ }
110
+ selectTab(i) {
111
+ if (i >= 0 && i < this._tabs.length) this._activeIndex = i;
112
+ }
113
+ nextTab() {
114
+ this._activeIndex = (this._activeIndex + 1) % this._tabs.length;
115
+ }
116
+ prevTab() {
117
+ this._activeIndex = (this._activeIndex - 1 + this._tabs.length) % this._tabs.length;
118
+ }
119
+ get activeContent() {
120
+ return this._tabs[this._activeIndex]?.content;
121
+ }
122
+ _renderSelf(screen) {
123
+ const { x, y, width, height } = this._rect;
124
+ if (width <= 0 || height <= 0) return;
125
+ const attrs = (0, import_core3.styleToCellAttrs)(this.style);
126
+ let col = x;
127
+ for (let i = 0; i < this._tabs.length; i++) {
128
+ const tab = this._tabs[i];
129
+ const isActive = i === this._activeIndex;
130
+ const label = isActive ? ` \u25CF ${tab.label} ` : ` ${tab.label} `;
131
+ screen.writeString(col, y, label, {
132
+ ...attrs,
133
+ fg: isActive ? this._activeColor : this._inactiveColor,
134
+ bold: isActive,
135
+ dim: !isActive
136
+ });
137
+ col += label.length;
138
+ if (i < this._tabs.length - 1) {
139
+ screen.writeString(col, y, "\u2502", { ...attrs, dim: true });
140
+ col++;
141
+ }
142
+ }
143
+ if (height > 1) screen.writeString(x, y + 1, "\u2500".repeat(width), { ...attrs, dim: true });
144
+ }
145
+ };
146
+
147
+ // src/Modal.ts
148
+ var import_widgets4 = require("@termuijs/widgets");
149
+ var import_core4 = require("@termuijs/core");
150
+ var Modal = class extends import_widgets4.Widget {
151
+ _title;
152
+ _modalWidth;
153
+ _modalHeight;
154
+ _borderColor;
155
+ _backdropChar;
156
+ _visible = false;
157
+ _content = null;
158
+ constructor(options = {}) {
159
+ super((0, import_core4.mergeStyles)((0, import_core4.defaultStyle)(), {}));
160
+ this._title = options.title ?? "";
161
+ this._modalWidth = options.width ?? 50;
162
+ this._modalHeight = options.height ?? 15;
163
+ this._borderColor = options.borderColor ?? { type: "named", name: "cyan" };
164
+ this._backdropChar = options.backdropChar ?? "\u2591";
165
+ }
166
+ get visible() {
167
+ return this._visible;
168
+ }
169
+ show() {
170
+ this._visible = true;
171
+ }
172
+ hide() {
173
+ this._visible = false;
174
+ }
175
+ toggle() {
176
+ this._visible = !this._visible;
177
+ }
178
+ setContent(content) {
179
+ this._content = content;
180
+ }
181
+ _renderSelf(screen) {
182
+ if (!this._visible) return;
183
+ const { x, y, width, height } = this._rect;
184
+ const attrs = (0, import_core4.styleToCellAttrs)(this.style);
185
+ for (let r = 0; r < height; r++) {
186
+ screen.writeString(x, y + r, this._backdropChar.repeat(width), { ...attrs, dim: true });
187
+ }
188
+ const mw = Math.min(this._modalWidth, width - 4);
189
+ const mh = Math.min(this._modalHeight, height - 2);
190
+ const mx = x + Math.floor((width - mw) / 2);
191
+ const my = y + Math.floor((height - mh) / 2);
192
+ const border = (0, import_core4.getBorderChars)("single");
193
+ if (!border) return;
194
+ const bAttrs = { ...attrs, fg: this._borderColor };
195
+ const titleStr = this._title ? ` ${this._title} ` : "";
196
+ const topFill = mw - 2 - titleStr.length;
197
+ const tl = Math.floor(topFill / 2);
198
+ const tr = topFill - tl;
199
+ screen.writeString(mx, my, border.topLeft + border.top.repeat(tl) + titleStr + border.top.repeat(Math.max(0, tr)) + border.topRight, bAttrs);
200
+ const clr = (0, import_core4.styleToCellAttrs)(this.style);
201
+ for (let r = 1; r < mh - 1; r++) {
202
+ screen.writeString(mx, my + r, border.left, bAttrs);
203
+ screen.writeString(mx + 1, my + r, " ".repeat(mw - 2), clr);
204
+ screen.writeString(mx + mw - 1, my + r, border.right, bAttrs);
205
+ }
206
+ screen.writeString(mx, my + mh - 1, border.bottomLeft + border.bottom.repeat(mw - 2) + border.bottomRight, bAttrs);
207
+ if (this._content) {
208
+ const cr = { x: mx + 2, y: my + 1, width: mw - 4, height: mh - 2 };
209
+ this._content._rect = cr;
210
+ this._content._renderSelf(screen);
211
+ }
212
+ }
213
+ };
214
+
215
+ // src/Select.ts
216
+ var import_widgets5 = require("@termuijs/widgets");
217
+ var import_core5 = require("@termuijs/core");
218
+ var Select = class extends import_widgets5.Widget {
219
+ _options;
220
+ _selectedIndex = 0;
221
+ _isOpen = false;
222
+ _placeholder;
223
+ _activeColor;
224
+ _onSelect;
225
+ focusable = true;
226
+ constructor(options, config = {}) {
227
+ super((0, import_core5.mergeStyles)((0, import_core5.defaultStyle)(), { height: 1 }));
228
+ this._options = options;
229
+ this._placeholder = config.placeholder ?? "Select...";
230
+ this._activeColor = config.activeColor ?? { type: "named", name: "cyan" };
231
+ this._onSelect = config.onSelect;
232
+ }
233
+ get selectedOption() {
234
+ return this._options[this._selectedIndex];
235
+ }
236
+ get selectedIndex() {
237
+ return this._selectedIndex;
238
+ }
239
+ get isOpen() {
240
+ return this._isOpen;
241
+ }
242
+ open() {
243
+ this._isOpen = true;
244
+ }
245
+ close() {
246
+ this._isOpen = false;
247
+ }
248
+ toggle() {
249
+ this._isOpen = !this._isOpen;
250
+ }
251
+ selectNext() {
252
+ let n = this._selectedIndex + 1;
253
+ while (n < this._options.length && this._options[n].disabled) n++;
254
+ if (n < this._options.length) this._selectedIndex = n;
255
+ }
256
+ selectPrev() {
257
+ let n = this._selectedIndex - 1;
258
+ while (n >= 0 && this._options[n].disabled) n--;
259
+ if (n >= 0) this._selectedIndex = n;
260
+ }
261
+ confirm() {
262
+ const opt = this._options[this._selectedIndex];
263
+ if (opt && !opt.disabled) {
264
+ this._onSelect?.(opt, this._selectedIndex);
265
+ this._isOpen = false;
266
+ }
267
+ }
268
+ _renderSelf(screen) {
269
+ const { x, y, width } = this._rect;
270
+ if (width <= 0) return;
271
+ const attrs = (0, import_core5.styleToCellAttrs)(this.style);
272
+ const sel = this._options[this._selectedIndex];
273
+ const label = sel ? sel.label : this._placeholder;
274
+ const prefix = this._isOpen ? "\u25BC " : "\u25B6 ";
275
+ screen.writeString(x, y, prefix + label.slice(0, width - 2), { ...attrs, fg: this._activeColor });
276
+ if (this._isOpen) {
277
+ for (let i = 0; i < this._options.length; i++) {
278
+ const o = this._options[i];
279
+ const isSel = i === this._selectedIndex;
280
+ const m = isSel ? "\u25CF " : " ";
281
+ screen.writeString(x, y + 1 + i, m + o.label.slice(0, width - 2), {
282
+ ...attrs,
283
+ fg: o.disabled ? { type: "named", name: "brightBlack" } : isSel ? this._activeColor : attrs.fg,
284
+ bold: isSel,
285
+ dim: o.disabled
286
+ });
287
+ }
288
+ }
289
+ }
290
+ };
291
+
292
+ // src/MultiSelect.ts
293
+ var import_widgets6 = require("@termuijs/widgets");
294
+ var import_core6 = require("@termuijs/core");
295
+ var MultiSelect = class extends import_widgets6.Widget {
296
+ _options;
297
+ _cursorIndex = 0;
298
+ _checked = /* @__PURE__ */ new Set();
299
+ _activeColor;
300
+ _checkChar;
301
+ _uncheckChar;
302
+ _onSubmit;
303
+ focusable = true;
304
+ constructor(options, config = {}) {
305
+ super((0, import_core6.mergeStyles)((0, import_core6.defaultStyle)(), { height: Math.max(options.length, 1) }));
306
+ this._options = options;
307
+ this._activeColor = config.activeColor ?? { type: "named", name: "cyan" };
308
+ this._checkChar = config.checkChar ?? "\u25FC";
309
+ this._uncheckChar = config.uncheckChar ?? "\u25FB";
310
+ this._onSubmit = config.onSubmit;
311
+ }
312
+ get selectedOptions() {
313
+ return [...this._checked].sort().map((i) => this._options[i]);
314
+ }
315
+ selectNext() {
316
+ let n = this._cursorIndex + 1;
317
+ while (n < this._options.length && this._options[n].disabled) n++;
318
+ if (n < this._options.length) this._cursorIndex = n;
319
+ }
320
+ selectPrev() {
321
+ let n = this._cursorIndex - 1;
322
+ while (n >= 0 && this._options[n].disabled) n--;
323
+ if (n >= 0) this._cursorIndex = n;
324
+ }
325
+ toggleCurrent() {
326
+ const o = this._options[this._cursorIndex];
327
+ if (o && !o.disabled) {
328
+ this._checked.has(this._cursorIndex) ? this._checked.delete(this._cursorIndex) : this._checked.add(this._cursorIndex);
329
+ }
330
+ }
331
+ submit() {
332
+ this._onSubmit?.(this.selectedOptions);
333
+ }
334
+ _renderSelf(screen) {
335
+ const { x, y, width, height } = this._rect;
336
+ if (width <= 0 || height <= 0) return;
337
+ const attrs = (0, import_core6.styleToCellAttrs)(this.style);
338
+ for (let i = 0; i < this._options.length && i < height; i++) {
339
+ const o = this._options[i];
340
+ const active = i === this._cursorIndex;
341
+ const checked = this._checked.has(i);
342
+ const label = `${active ? "\u276F " : " "}${checked ? this._checkChar : this._uncheckChar} ${o.label}`;
343
+ screen.writeString(x, y + i, label.slice(0, width), {
344
+ ...attrs,
345
+ fg: o.disabled ? { type: "named", name: "brightBlack" } : active ? this._activeColor : attrs.fg,
346
+ bold: active,
347
+ dim: o.disabled
348
+ });
349
+ }
350
+ }
351
+ };
352
+
353
+ // src/Tree.ts
354
+ var import_widgets7 = require("@termuijs/widgets");
355
+ var import_core7 = require("@termuijs/core");
356
+ var Tree = class extends import_widgets7.Widget {
357
+ _roots;
358
+ _cursorIndex = 0;
359
+ _activeColor;
360
+ _onSelect;
361
+ focusable = true;
362
+ constructor(roots, options = {}) {
363
+ super((0, import_core7.mergeStyles)((0, import_core7.defaultStyle)(), { flexGrow: 1 }));
364
+ this._roots = roots;
365
+ this._activeColor = options.activeColor ?? { type: "named", name: "cyan" };
366
+ this._onSelect = options.onSelect;
367
+ }
368
+ _flatten() {
369
+ const result = [];
370
+ const walk = (nodes, depth, path) => {
371
+ for (let i = 0; i < nodes.length; i++) {
372
+ const node = nodes[i];
373
+ const hasChildren = (node.children?.length ?? 0) > 0;
374
+ result.push({ node, depth, path: [...path, i], hasChildren });
375
+ if (hasChildren && node.expanded) walk(node.children, depth + 1, [...path, i]);
376
+ }
377
+ };
378
+ walk(this._roots, 0, []);
379
+ return result;
380
+ }
381
+ selectNext() {
382
+ const f = this._flatten();
383
+ if (this._cursorIndex < f.length - 1) this._cursorIndex++;
384
+ }
385
+ selectPrev() {
386
+ if (this._cursorIndex > 0) this._cursorIndex--;
387
+ }
388
+ toggleExpand() {
389
+ const f = this._flatten();
390
+ const it = f[this._cursorIndex];
391
+ if (it?.hasChildren) it.node.expanded = !it.node.expanded;
392
+ }
393
+ confirm() {
394
+ const f = this._flatten();
395
+ const it = f[this._cursorIndex];
396
+ if (it) {
397
+ it.hasChildren ? this.toggleExpand() : this._onSelect?.(it.node, it.path);
398
+ }
399
+ }
400
+ _renderSelf(screen) {
401
+ const { x, y, width, height } = this._rect;
402
+ if (width <= 0 || height <= 0) return;
403
+ const attrs = (0, import_core7.styleToCellAttrs)(this.style);
404
+ const flat = this._flatten();
405
+ for (let i = 0; i < flat.length && i < height; i++) {
406
+ const it = flat[i];
407
+ const active = i === this._cursorIndex;
408
+ const indent = " ".repeat(it.depth);
409
+ const icon = it.hasChildren ? it.node.expanded ? "\u25BC " : "\u25B6 " : " ";
410
+ const nodeIcon = it.node.icon ? `${it.node.icon} ` : "";
411
+ const line = `${indent}${icon}${nodeIcon}${it.node.label}`;
412
+ screen.writeString(x, y + i, line.slice(0, width), { ...attrs, fg: active ? this._activeColor : attrs.fg, bold: active });
413
+ }
414
+ }
415
+ };
416
+
417
+ // src/Toast.ts
418
+ var import_widgets8 = require("@termuijs/widgets");
419
+ var import_core8 = require("@termuijs/core");
420
+ var ICONS = { info: "\u2139", success: "\u2713", warning: "\u26A0", error: "\u2717" };
421
+ var COLORS = { info: "cyan", success: "green", warning: "yellow", error: "red" };
422
+ var Toast = class extends import_widgets8.Widget {
423
+ _messages = [];
424
+ _position;
425
+ _durationMs;
426
+ _maxVisible;
427
+ constructor(options = {}) {
428
+ super((0, import_core8.mergeStyles)((0, import_core8.defaultStyle)(), {}));
429
+ this._position = options.position ?? "top-right";
430
+ this._durationMs = options.durationMs ?? 3e3;
431
+ this._maxVisible = options.maxVisible ?? 5;
432
+ }
433
+ push(text, type = "info") {
434
+ this._messages.push({ text, type, expireAt: Date.now() + this._durationMs });
435
+ }
436
+ info(text) {
437
+ this.push(text, "info");
438
+ }
439
+ success(text) {
440
+ this.push(text, "success");
441
+ }
442
+ warning(text) {
443
+ this.push(text, "warning");
444
+ }
445
+ error(text) {
446
+ this.push(text, "error");
447
+ }
448
+ _renderSelf(screen) {
449
+ const now = Date.now();
450
+ this._messages = this._messages.filter((m) => m.expireAt > now);
451
+ if (this._messages.length === 0) return;
452
+ const { x, y, width, height } = this._rect;
453
+ const visible = this._messages.slice(-this._maxVisible);
454
+ const tw = Math.min(40, width - 2);
455
+ const isRight = this._position.includes("right");
456
+ const isBottom = this._position.includes("bottom");
457
+ const sx = isRight ? x + width - tw - 1 : x + 1;
458
+ const sy = isBottom ? y + height - visible.length - 1 : y + 1;
459
+ const attrs = (0, import_core8.styleToCellAttrs)(this.style);
460
+ for (let i = 0; i < visible.length; i++) {
461
+ const m = visible[i];
462
+ const label = ` ${ICONS[m.type]} ${m.text} `.slice(0, tw).padEnd(tw);
463
+ screen.writeString(sx, sy + i, label, { ...attrs, fg: { type: "named", name: COLORS[m.type] }, bold: true });
464
+ }
465
+ }
466
+ };
467
+
468
+ // src/ConfirmDialog.ts
469
+ var import_widgets9 = require("@termuijs/widgets");
470
+ var import_core9 = require("@termuijs/core");
471
+ var ConfirmDialog = class extends import_widgets9.Widget {
472
+ _message;
473
+ _confirmLabel;
474
+ _cancelLabel;
475
+ _borderColor;
476
+ _selected = "confirm";
477
+ _visible = false;
478
+ _onConfirm;
479
+ _onCancel;
480
+ focusable = true;
481
+ constructor(options) {
482
+ super((0, import_core9.mergeStyles)((0, import_core9.defaultStyle)(), {}));
483
+ this._message = options.message;
484
+ this._confirmLabel = options.confirmLabel ?? "Yes";
485
+ this._cancelLabel = options.cancelLabel ?? "No";
486
+ this._borderColor = options.borderColor ?? { type: "named", name: "yellow" };
487
+ this._onConfirm = options.onConfirm;
488
+ this._onCancel = options.onCancel;
489
+ }
490
+ get visible() {
491
+ return this._visible;
492
+ }
493
+ show() {
494
+ this._visible = true;
495
+ this._selected = "confirm";
496
+ }
497
+ hide() {
498
+ this._visible = false;
499
+ }
500
+ selectConfirm() {
501
+ this._selected = "confirm";
502
+ }
503
+ selectCancel() {
504
+ this._selected = "cancel";
505
+ }
506
+ toggleSelection() {
507
+ this._selected = this._selected === "confirm" ? "cancel" : "confirm";
508
+ }
509
+ confirm() {
510
+ (this._selected === "confirm" ? this._onConfirm : this._onCancel)?.();
511
+ this._visible = false;
512
+ }
513
+ _renderSelf(screen) {
514
+ if (!this._visible) return;
515
+ const { x, y, width, height } = this._rect;
516
+ const attrs = (0, import_core9.styleToCellAttrs)(this.style);
517
+ for (let r = 0; r < height; r++) screen.writeString(x, y + r, "\u2591".repeat(width), { ...attrs, dim: true });
518
+ const bw = Math.min(40, width - 4);
519
+ const bh = 5;
520
+ const bx = x + Math.floor((width - bw) / 2);
521
+ const by = y + Math.floor((height - bh) / 2);
522
+ const border = (0, import_core9.getBorderChars)("single");
523
+ if (!border) return;
524
+ const ba = { ...attrs, fg: this._borderColor };
525
+ screen.writeString(bx, by, border.topLeft + border.top.repeat(bw - 2) + border.topRight, ba);
526
+ for (let r = 1; r < bh - 1; r++) {
527
+ screen.writeString(bx, by + r, border.left, ba);
528
+ screen.writeString(bx + 1, by + r, " ".repeat(bw - 2), attrs);
529
+ screen.writeString(bx + bw - 1, by + r, border.right, ba);
530
+ }
531
+ screen.writeString(bx, by + bh - 1, border.bottomLeft + border.bottom.repeat(bw - 2) + border.bottomRight, ba);
532
+ screen.writeString(bx + 2, by + 1, this._message.slice(0, bw - 4), { ...attrs, bold: true });
533
+ const yesStr = this._selected === "confirm" ? ` [${this._confirmLabel}] ` : ` ${this._confirmLabel} `;
534
+ const noStr = this._selected === "cancel" ? ` [${this._cancelLabel}] ` : ` ${this._cancelLabel} `;
535
+ screen.writeString(bx + 2, by + 3, yesStr, { ...attrs, fg: this._selected === "confirm" ? { type: "named", name: "green" } : attrs.fg, bold: this._selected === "confirm" });
536
+ screen.writeString(bx + 2 + yesStr.length + 2, by + 3, noStr, { ...attrs, fg: this._selected === "cancel" ? { type: "named", name: "red" } : attrs.fg, bold: this._selected === "cancel" });
537
+ }
538
+ };
539
+
540
+ // src/Form.ts
541
+ var import_widgets10 = require("@termuijs/widgets");
542
+ var import_core10 = require("@termuijs/core");
543
+ var Form = class extends import_widgets10.Widget {
544
+ _fields;
545
+ _values = /* @__PURE__ */ new Map();
546
+ _errors = /* @__PURE__ */ new Map();
547
+ _activeField = 0;
548
+ _cursorPos = 0;
549
+ _labelColor;
550
+ _errorColor;
551
+ _activeColor;
552
+ _onSubmit;
553
+ focusable = true;
554
+ constructor(fields, options = {}) {
555
+ super((0, import_core10.mergeStyles)((0, import_core10.defaultStyle)(), { height: fields.length * 2 + 1, flexGrow: 1 }));
556
+ this._fields = fields;
557
+ this._labelColor = options.labelColor ?? { type: "named", name: "cyan" };
558
+ this._errorColor = options.errorColor ?? { type: "named", name: "red" };
559
+ this._activeColor = options.activeColor ?? { type: "named", name: "cyan" };
560
+ this._onSubmit = options.onSubmit;
561
+ for (const f of fields) this._values.set(f.name, "");
562
+ }
563
+ get values() {
564
+ const r = {};
565
+ for (const [k, v] of this._values) r[k] = v;
566
+ return r;
567
+ }
568
+ nextField() {
569
+ if (this._activeField < this._fields.length) {
570
+ this._activeField++;
571
+ this._cursorPos = 0;
572
+ }
573
+ }
574
+ prevField() {
575
+ if (this._activeField > 0) {
576
+ this._activeField--;
577
+ this._cursorPos = (this._values.get(this._fields[this._activeField].name) ?? "").length;
578
+ }
579
+ }
580
+ insertChar(ch) {
581
+ if (this._activeField >= this._fields.length) return;
582
+ const f = this._fields[this._activeField];
583
+ const cur = this._values.get(f.name) ?? "";
584
+ this._values.set(f.name, cur.slice(0, this._cursorPos) + ch + cur.slice(this._cursorPos));
585
+ this._cursorPos++;
586
+ this._errors.delete(f.name);
587
+ }
588
+ deleteBack() {
589
+ if (this._activeField >= this._fields.length) return;
590
+ const f = this._fields[this._activeField];
591
+ const cur = this._values.get(f.name) ?? "";
592
+ if (this._cursorPos > 0) {
593
+ this._values.set(f.name, cur.slice(0, this._cursorPos - 1) + cur.slice(this._cursorPos));
594
+ this._cursorPos--;
595
+ }
596
+ }
597
+ submit() {
598
+ this._errors.clear();
599
+ let hasErr = false;
600
+ for (const f of this._fields) {
601
+ const v = this._values.get(f.name) ?? "";
602
+ if (f.required && !v.trim()) {
603
+ this._errors.set(f.name, `${f.label} is required`);
604
+ hasErr = true;
605
+ }
606
+ if (f.validate) {
607
+ const e = f.validate(v);
608
+ if (e) {
609
+ this._errors.set(f.name, e);
610
+ hasErr = true;
611
+ }
612
+ }
613
+ }
614
+ if (!hasErr) this._onSubmit?.(this.values);
615
+ }
616
+ _renderSelf(screen) {
617
+ const { x, y, width, height } = this._rect;
618
+ if (width <= 0 || height <= 0) return;
619
+ const attrs = (0, import_core10.styleToCellAttrs)(this.style);
620
+ let row = 0;
621
+ for (let i = 0; i < this._fields.length && row < height - 1; i++) {
622
+ const f = this._fields[i];
623
+ const active = i === this._activeField;
624
+ const val = this._values.get(f.name) ?? "";
625
+ const err = this._errors.get(f.name);
626
+ screen.writeString(x, y + row, `${f.label}${f.required ? " *" : ""}:`.slice(0, width), { ...attrs, fg: err ? this._errorColor : this._labelColor, bold: active });
627
+ row++;
628
+ if (row >= height) break;
629
+ const display = val || (f.placeholder ?? "");
630
+ screen.writeString(x, y + row, `${active ? "\u276F " : " "}${display}`.slice(0, width), { ...attrs, fg: active ? this._activeColor : attrs.fg, dim: !val && !!f.placeholder });
631
+ row++;
632
+ }
633
+ if (row < height) {
634
+ const isSub = this._activeField >= this._fields.length;
635
+ screen.writeString(x, y + row, isSub ? " [ Submit ]" : " Submit ", { ...attrs, fg: isSub ? { type: "named", name: "green" } : attrs.fg, bold: isSub });
636
+ }
637
+ }
638
+ };
639
+
640
+ // src/CommandPalette.ts
641
+ var import_widgets11 = require("@termuijs/widgets");
642
+ var import_core11 = require("@termuijs/core");
643
+ var CommandPalette = class extends import_widgets11.Widget {
644
+ _commands;
645
+ _filtered = [];
646
+ _query = "";
647
+ _cursorPos = 0;
648
+ _selectedIndex = 0;
649
+ _visible = false;
650
+ _placeholder;
651
+ _borderColor;
652
+ _activeColor;
653
+ _maxVisible;
654
+ focusable = true;
655
+ constructor(commands, options = {}) {
656
+ super((0, import_core11.mergeStyles)((0, import_core11.defaultStyle)(), {}));
657
+ this._commands = commands;
658
+ this._filtered = [...commands];
659
+ this._placeholder = options.placeholder ?? "Type a command...";
660
+ this._borderColor = options.borderColor ?? { type: "named", name: "cyan" };
661
+ this._activeColor = options.activeColor ?? { type: "named", name: "cyan" };
662
+ this._maxVisible = options.maxVisible ?? 10;
663
+ }
664
+ get visible() {
665
+ return this._visible;
666
+ }
667
+ show() {
668
+ this._visible = true;
669
+ this._query = "";
670
+ this._cursorPos = 0;
671
+ this._selectedIndex = 0;
672
+ this._filtered = [...this._commands];
673
+ }
674
+ hide() {
675
+ this._visible = false;
676
+ }
677
+ toggle() {
678
+ this._visible ? this.hide() : this.show();
679
+ }
680
+ insertChar(ch) {
681
+ this._query = this._query.slice(0, this._cursorPos) + ch + this._query.slice(this._cursorPos);
682
+ this._cursorPos++;
683
+ this._filter();
684
+ }
685
+ deleteBack() {
686
+ if (this._cursorPos > 0) {
687
+ this._query = this._query.slice(0, this._cursorPos - 1) + this._query.slice(this._cursorPos);
688
+ this._cursorPos--;
689
+ this._filter();
690
+ }
691
+ }
692
+ selectNext() {
693
+ if (this._selectedIndex < this._filtered.length - 1) this._selectedIndex++;
694
+ }
695
+ selectPrev() {
696
+ if (this._selectedIndex > 0) this._selectedIndex--;
697
+ }
698
+ confirm() {
699
+ const c = this._filtered[this._selectedIndex];
700
+ if (c) {
701
+ this.hide();
702
+ c.action();
703
+ }
704
+ }
705
+ _filter() {
706
+ const q = this._query.toLowerCase();
707
+ if (!q) {
708
+ this._filtered = [...this._commands];
709
+ } else {
710
+ this._filtered = this._commands.filter((c) => {
711
+ const l = c.label.toLowerCase();
712
+ let qi = 0;
713
+ for (let i = 0; i < l.length && qi < q.length; i++) {
714
+ if (l[i] === q[qi]) qi++;
715
+ }
716
+ return qi === q.length;
717
+ });
718
+ }
719
+ this._selectedIndex = 0;
720
+ }
721
+ _renderSelf(screen) {
722
+ if (!this._visible) return;
723
+ const { x, y, width, height } = this._rect;
724
+ const attrs = (0, import_core11.styleToCellAttrs)(this.style);
725
+ for (let r = 0; r < height; r++) screen.writeString(x, y + r, "\u2591".repeat(width), { ...attrs, dim: true });
726
+ const vis = this._filtered.slice(0, this._maxVisible);
727
+ const bw = Math.min(60, width - 4);
728
+ const bh = Math.min(vis.length + 3, height - 2);
729
+ const bx = x + Math.floor((width - bw) / 2);
730
+ const by = y + 2;
731
+ const border = (0, import_core11.getBorderChars)("single");
732
+ if (!border) return;
733
+ const ba = { ...attrs, fg: this._borderColor };
734
+ screen.writeString(bx, by, border.topLeft + border.top.repeat(bw - 2) + border.topRight, ba);
735
+ screen.writeString(bx, by + 1, border.left, ba);
736
+ const input = this._query || this._placeholder;
737
+ screen.writeString(bx + 1, by + 1, (" \u{1F50D} " + input).slice(0, bw - 2).padEnd(bw - 2), { ...attrs, dim: !this._query });
738
+ screen.writeString(bx + bw - 1, by + 1, border.right, ba);
739
+ screen.writeString(bx, by + 2, border.left + "\u2500".repeat(bw - 2) + border.right, ba);
740
+ for (let i = 0; i < vis.length && i + 3 < bh - 1; i++) {
741
+ const c = vis[i];
742
+ const active = i === this._selectedIndex;
743
+ const label = (active ? "\u276F " : " ") + c.label;
744
+ const sc = c.shortcut ?? "";
745
+ screen.writeString(bx, by + 3 + i, border.left, ba);
746
+ screen.writeString(bx + 1, by + 3 + i, (" " + label).slice(0, bw - sc.length - 3).padEnd(bw - sc.length - 3), { ...attrs, fg: active ? this._activeColor : attrs.fg, bold: active });
747
+ if (sc) screen.writeString(bx + bw - sc.length - 2, by + 3 + i, sc, { ...attrs, dim: true });
748
+ screen.writeString(bx + bw - 1, by + 3 + i, border.right, ba);
749
+ }
750
+ const last = Math.min(by + 3 + vis.length, by + bh - 1);
751
+ screen.writeString(bx, last, border.bottomLeft + border.bottom.repeat(bw - 2) + border.bottomRight, ba);
752
+ }
753
+ };
754
+ // Annotate the CommonJS export names for ESM import in node:
755
+ 0 && (module.exports = {
756
+ Box,
757
+ CommandPalette,
758
+ ConfirmDialog,
759
+ Divider,
760
+ Form,
761
+ Gauge,
762
+ List,
763
+ LogView,
764
+ Modal,
765
+ MultiSelect,
766
+ ProgressBar,
767
+ Select,
768
+ Spacer,
769
+ Sparkline,
770
+ Spinner,
771
+ StatusIndicator,
772
+ Table,
773
+ Tabs,
774
+ Text,
775
+ TextInput,
776
+ Toast,
777
+ Tree,
778
+ Widget
779
+ });
780
+ //# sourceMappingURL=index.cjs.map