@termuijs/ui 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,37 +17,55 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
- Box: () => import_widgets12.Box,
33
+ Box: () => import_widgets17.Box,
24
34
  CommandPalette: () => CommandPalette,
25
35
  ConfirmDialog: () => ConfirmDialog,
26
36
  Divider: () => Divider,
27
37
  Form: () => Form,
28
- Gauge: () => import_widgets12.Gauge,
29
- List: () => import_widgets12.List,
30
- LogView: () => import_widgets12.LogView,
38
+ Gauge: () => import_widgets17.Gauge,
39
+ KeyboardShortcuts: () => KeyboardShortcuts,
40
+ List: () => import_widgets17.List,
41
+ LogView: () => import_widgets17.LogView,
31
42
  Modal: () => Modal,
32
43
  MultiSelect: () => MultiSelect,
33
- ProgressBar: () => import_widgets12.ProgressBar,
44
+ NonInteractiveError: () => NonInteractiveError,
45
+ NotificationCenter: () => NotificationCenter,
46
+ NotificationStore: () => NotificationStore,
47
+ NumberInput: () => NumberInput,
48
+ PasswordInput: () => PasswordInput,
49
+ PathInput: () => PathInput,
50
+ ProgressBar: () => import_widgets17.ProgressBar,
34
51
  Select: () => Select,
35
52
  Spacer: () => Spacer,
36
- Sparkline: () => import_widgets12.Sparkline,
37
- Spinner: () => import_widgets12.Spinner,
38
- StatusIndicator: () => import_widgets12.StatusIndicator,
39
- Table: () => import_widgets12.Table,
53
+ Sparkline: () => import_widgets17.Sparkline,
54
+ Spinner: () => import_widgets17.Spinner,
55
+ StatusIndicator: () => import_widgets17.StatusIndicator,
56
+ Table: () => import_widgets17.Table,
40
57
  Tabs: () => Tabs,
41
- Text: () => import_widgets12.Text,
42
- TextInput: () => import_widgets12.TextInput,
58
+ Text: () => import_widgets17.Text,
59
+ TextInput: () => import_widgets17.TextInput,
43
60
  Toast: () => Toast,
44
61
  Tree: () => Tree,
45
- Widget: () => import_widgets12.Widget
62
+ Widget: () => import_widgets17.Widget,
63
+ notifications: () => notifications,
64
+ prompt: () => prompt,
65
+ useNotifications: () => useNotifications
46
66
  });
47
67
  module.exports = __toCommonJS(index_exports);
48
- var import_widgets12 = require("@termuijs/widgets");
68
+ var import_widgets17 = require("@termuijs/widgets");
49
69
 
50
70
  // src/Divider.ts
51
71
  var import_widgets = require("@termuijs/widgets");
@@ -132,7 +152,7 @@ var Tabs = class extends import_widgets3.Widget {
132
152
  for (let i = 0; i < this._tabs.length; i++) {
133
153
  const tab = this._tabs[i];
134
154
  const isActive = i === this._activeIndex;
135
- const label = isActive ? ` \u25CF ${tab.label} ` : ` ${tab.label} `;
155
+ const label = isActive ? ` ${import_core3.caps.unicode ? "\u25CF" : "*"} ${tab.label} ` : ` ${tab.label} `;
136
156
  screen.writeString(col, y, label, {
137
157
  ...attrs,
138
158
  fg: isActive ? this._activeColor : this._inactiveColor,
@@ -141,7 +161,7 @@ var Tabs = class extends import_widgets3.Widget {
141
161
  });
142
162
  col += label.length;
143
163
  if (i < this._tabs.length - 1) {
144
- screen.writeString(col, y, "\u2502", { ...attrs, dim: true });
164
+ screen.writeString(col, y, import_core3.caps.unicode ? "\u2502" : "|", { ...attrs, dim: true });
145
165
  col++;
146
166
  }
147
167
  }
@@ -166,7 +186,7 @@ var Modal = class extends import_widgets4.Widget {
166
186
  this._modalWidth = options.width ?? 50;
167
187
  this._modalHeight = options.height ?? 15;
168
188
  this._borderColor = options.borderColor ?? { type: "named", name: "cyan" };
169
- this._backdropChar = options.backdropChar ?? "\u2591";
189
+ this._backdropChar = options.backdropChar ?? (import_core4.caps.unicode ? "\u2591" : " ");
170
190
  }
171
191
  get visible() {
172
192
  return this._visible;
@@ -290,13 +310,13 @@ var Select = class extends import_widgets5.Widget {
290
310
  const attrs = (0, import_core5.styleToCellAttrs)(this.style);
291
311
  const sel = this._options[this._selectedIndex];
292
312
  const label = sel ? sel.label : this._placeholder;
293
- const prefix = this._isOpen ? "\u25BC " : "\u25B6 ";
313
+ const prefix = this._isOpen ? import_core5.caps.unicode ? "\u25BC " : "v " : import_core5.caps.unicode ? "\u25B6 " : "> ";
294
314
  screen.writeString(x, y, prefix + label.slice(0, width - 2), { ...attrs, fg: this._activeColor });
295
315
  if (this._isOpen) {
296
316
  for (let i = 0; i < this._options.length; i++) {
297
317
  const o = this._options[i];
298
318
  const isSel = i === this._selectedIndex;
299
- const m = isSel ? "\u25CF " : " ";
319
+ const m = isSel ? import_core5.caps.unicode ? "\u25CF " : "* " : " ";
300
320
  screen.writeString(x, y + 1 + i, m + o.label.slice(0, width - 2), {
301
321
  ...attrs,
302
322
  fg: o.disabled ? { type: "named", name: "brightBlack" } : isSel ? this._activeColor : attrs.fg,
@@ -324,8 +344,8 @@ var MultiSelect = class extends import_widgets6.Widget {
324
344
  super((0, import_core6.mergeStyles)((0, import_core6.defaultStyle)(), { height: Math.max(options.length, 1) }));
325
345
  this._options = options;
326
346
  this._activeColor = config.activeColor ?? { type: "named", name: "cyan" };
327
- this._checkChar = config.checkChar ?? "\u25FC";
328
- this._uncheckChar = config.uncheckChar ?? "\u25FB";
347
+ this._checkChar = config.checkChar ?? (import_core6.caps.unicode ? "\u25FC" : "[x]");
348
+ this._uncheckChar = config.uncheckChar ?? (import_core6.caps.unicode ? "\u25FB" : "[ ]");
329
349
  this._onSubmit = config.onSubmit;
330
350
  }
331
351
  get selectedOptions() {
@@ -365,7 +385,7 @@ var MultiSelect = class extends import_widgets6.Widget {
365
385
  const o = this._options[i];
366
386
  const active = i === this._cursorIndex;
367
387
  const checked = this._checked.has(i);
368
- const label = `${active ? "\u276F " : " "}${checked ? this._checkChar : this._uncheckChar} ${o.label}`;
388
+ const label = `${active ? import_core6.caps.unicode ? "\u276F " : "> " : " "}${checked ? this._checkChar : this._uncheckChar} ${o.label}`;
369
389
  screen.writeString(x, y + i, label.slice(0, width), {
370
390
  ...attrs,
371
391
  fg: o.disabled ? { type: "named", name: "brightBlack" } : active ? this._activeColor : attrs.fg,
@@ -393,12 +413,12 @@ var Tree = class extends import_widgets7.Widget {
393
413
  }
394
414
  _flatten() {
395
415
  const result = [];
396
- const walk = (nodes, depth, path) => {
416
+ const walk = (nodes, depth, path2) => {
397
417
  for (let i = 0; i < nodes.length; i++) {
398
418
  const node = nodes[i];
399
419
  const hasChildren = (node.children?.length ?? 0) > 0;
400
- result.push({ node, depth, path: [...path, i], hasChildren });
401
- if (hasChildren && node.expanded) walk(node.children, depth + 1, [...path, i]);
420
+ result.push({ node, depth, path: [...path2, i], hasChildren });
421
+ if (hasChildren && node.expanded) walk(node.children, depth + 1, [...path2, i]);
402
422
  }
403
423
  };
404
424
  walk(this._roots, 0, []);
@@ -441,7 +461,7 @@ var Tree = class extends import_widgets7.Widget {
441
461
  const it = flat[i];
442
462
  const active = i === this._cursorIndex;
443
463
  const indent = " ".repeat(it.depth);
444
- const icon = it.hasChildren ? it.node.expanded ? "\u25BC " : "\u25B6 " : " ";
464
+ const icon = it.hasChildren ? it.node.expanded ? import_core7.caps.unicode ? "\u25BC " : "v " : import_core7.caps.unicode ? "\u25B6 " : "> " : " ";
445
465
  const nodeIcon = it.node.icon ? `${it.node.icon} ` : "";
446
466
  const line = `${indent}${icon}${nodeIcon}${it.node.label}`;
447
467
  screen.writeString(x, y + i, line.slice(0, width), { ...attrs, fg: active ? this._activeColor : attrs.fg, bold: active });
@@ -452,7 +472,8 @@ var Tree = class extends import_widgets7.Widget {
452
472
  // src/Toast.ts
453
473
  var import_widgets8 = require("@termuijs/widgets");
454
474
  var import_core8 = require("@termuijs/core");
455
- var ICONS = { info: "\u2139", success: "\u2713", warning: "\u26A0", error: "\u2717" };
475
+ var ICONS_UNICODE = { info: "\u2139", success: "\u2713", warning: "\u26A0", error: "\u2717" };
476
+ var ICONS_ASCII = { info: "i", success: "+", warning: "!", error: "x" };
456
477
  var COLORS = { info: "cyan", success: "green", warning: "yellow", error: "red" };
457
478
  var Toast = class extends import_widgets8.Widget {
458
479
  _messages = [];
@@ -492,10 +513,11 @@ var Toast = class extends import_widgets8.Widget {
492
513
  const isBottom = this._position.includes("bottom");
493
514
  const sx = isRight ? x + width - tw - 1 : x + 1;
494
515
  const sy = isBottom ? y + height - visible.length - 1 : y + 1;
516
+ const icons = import_core8.caps.unicode ? ICONS_UNICODE : ICONS_ASCII;
495
517
  const attrs = (0, import_core8.styleToCellAttrs)(this.style);
496
518
  for (let i = 0; i < visible.length; i++) {
497
519
  const m = visible[i];
498
- const label = ` ${ICONS[m.type]} ${m.text} `.slice(0, tw).padEnd(tw);
520
+ const label = ` ${icons[m.type]} ${m.text} `.slice(0, tw).padEnd(tw);
499
521
  screen.writeString(sx, sy + i, label, { ...attrs, fg: { type: "named", name: COLORS[m.type] }, bold: true });
500
522
  }
501
523
  }
@@ -779,7 +801,8 @@ var CommandPalette = class extends import_widgets11.Widget {
779
801
  if (!this._visible) return;
780
802
  const { x, y, width, height } = this._rect;
781
803
  const attrs = (0, import_core11.styleToCellAttrs)(this.style);
782
- for (let r = 0; r < height; r++) screen.writeString(x, y + r, "\u2591".repeat(width), { ...attrs, dim: true });
804
+ const backdropCh = import_core11.caps.unicode ? "\u2591" : " ";
805
+ for (let r = 0; r < height; r++) screen.writeString(x, y + r, backdropCh.repeat(width), { ...attrs, dim: true });
783
806
  const vis = this._filtered.slice(0, this._maxVisible);
784
807
  const bw = Math.min(60, width - 4);
785
808
  const bh = Math.min(vis.length + 3, height - 2);
@@ -791,13 +814,13 @@ var CommandPalette = class extends import_widgets11.Widget {
791
814
  screen.writeString(bx, by, border.topLeft + border.top.repeat(bw - 2) + border.topRight, ba);
792
815
  screen.writeString(bx, by + 1, border.left, ba);
793
816
  const input = this._query || this._placeholder;
794
- screen.writeString(bx + 1, by + 1, (" \u{1F50D} " + input).slice(0, bw - 2).padEnd(bw - 2), { ...attrs, dim: !this._query });
817
+ screen.writeString(bx + 1, by + 1, (` ${import_core11.caps.unicode ? "\u{1F50D}" : "[?]"} ` + input).slice(0, bw - 2).padEnd(bw - 2), { ...attrs, dim: !this._query });
795
818
  screen.writeString(bx + bw - 1, by + 1, border.right, ba);
796
819
  screen.writeString(bx, by + 2, border.left + "\u2500".repeat(bw - 2) + border.right, ba);
797
820
  for (let i = 0; i < vis.length && i + 3 < bh - 1; i++) {
798
821
  const c = vis[i];
799
822
  const active = i === this._selectedIndex;
800
- const label = (active ? "\u276F " : " ") + c.label;
823
+ const label = (active ? import_core11.caps.unicode ? "\u276F " : "> " : " ") + c.label;
801
824
  const sc = c.shortcut ?? "";
802
825
  screen.writeString(bx, by + 3 + i, border.left, ba);
803
826
  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 });
@@ -808,6 +831,919 @@ var CommandPalette = class extends import_widgets11.Widget {
808
831
  screen.writeString(bx, last, border.bottomLeft + border.bottom.repeat(bw - 2) + border.bottomRight, ba);
809
832
  }
810
833
  };
834
+
835
+ // src/prompts.ts
836
+ var readline = __toESM(require("readline"), 1);
837
+ var NonInteractiveError = class extends Error {
838
+ constructor() {
839
+ super("Prompts require an interactive TTY. stdin is not a TTY.");
840
+ this.name = "NonInteractiveError";
841
+ }
842
+ };
843
+ async function promptText(options) {
844
+ if (!process.stdin.isTTY) throw new NonInteractiveError();
845
+ const defaultHint = options.default ? ` (${options.default})` : "";
846
+ const placeholder = options.placeholder ? ` [${options.placeholder}]` : "";
847
+ return new Promise((resolve) => {
848
+ const rl = readline.createInterface({
849
+ input: process.stdin,
850
+ output: process.stdout
851
+ });
852
+ const ask = () => {
853
+ rl.question(`${options.message}${defaultHint}${placeholder}: `, (answer) => {
854
+ const value = answer.trim() || options.default || "";
855
+ if (options.validate) {
856
+ const error = options.validate(value);
857
+ if (error) {
858
+ process.stdout.write(` ${error}
859
+ `);
860
+ ask();
861
+ return;
862
+ }
863
+ }
864
+ rl.close();
865
+ resolve(value);
866
+ });
867
+ };
868
+ ask();
869
+ });
870
+ }
871
+ async function promptConfirm(options) {
872
+ if (!process.stdin.isTTY) throw new NonInteractiveError();
873
+ const hint = options.default === true ? "Y/n" : options.default === false ? "y/N" : "y/n";
874
+ return new Promise((resolve) => {
875
+ const rl = readline.createInterface({
876
+ input: process.stdin,
877
+ output: process.stdout
878
+ });
879
+ rl.question(`${options.message} [${hint}]: `, (answer) => {
880
+ rl.close();
881
+ const a = answer.trim().toLowerCase();
882
+ if (a === "y" || a === "yes") {
883
+ resolve(true);
884
+ return;
885
+ }
886
+ if (a === "n" || a === "no") {
887
+ resolve(false);
888
+ return;
889
+ }
890
+ if (a === "" && options.default !== void 0) {
891
+ resolve(options.default);
892
+ return;
893
+ }
894
+ resolve(false);
895
+ });
896
+ });
897
+ }
898
+ async function promptSelect(options) {
899
+ if (!process.stdin.isTTY) throw new NonInteractiveError();
900
+ const { options: choices, default: defaultValue } = options;
901
+ process.stdout.write(`${options.message}
902
+ `);
903
+ choices.forEach((opt, i) => {
904
+ const isDefault = opt.value === defaultValue;
905
+ process.stdout.write(` ${i + 1}. ${opt.label}${isDefault ? " (default)" : ""}
906
+ `);
907
+ });
908
+ return new Promise((resolve) => {
909
+ const rl = readline.createInterface({
910
+ input: process.stdin,
911
+ output: process.stdout
912
+ });
913
+ const ask = () => {
914
+ rl.question(`Enter number (1-${choices.length}): `, (answer) => {
915
+ const trimmed = answer.trim();
916
+ if (trimmed === "" && defaultValue !== void 0) {
917
+ rl.close();
918
+ resolve(defaultValue);
919
+ return;
920
+ }
921
+ const n = parseInt(trimmed, 10);
922
+ if (!isNaN(n) && n >= 1 && n <= choices.length) {
923
+ rl.close();
924
+ resolve(choices[n - 1].value);
925
+ return;
926
+ }
927
+ process.stdout.write(` Invalid choice. Enter a number 1-${choices.length}.
928
+ `);
929
+ ask();
930
+ });
931
+ };
932
+ ask();
933
+ });
934
+ }
935
+ var prompt = {
936
+ text: promptText,
937
+ confirm: promptConfirm,
938
+ select: promptSelect
939
+ };
940
+
941
+ // src/NotificationCenter.ts
942
+ var import_widgets12 = require("@termuijs/widgets");
943
+ var import_jsx = require("@termuijs/jsx");
944
+ var import_core12 = require("@termuijs/core");
945
+ var NotificationStore = class _NotificationStore {
946
+ static _instance;
947
+ _notifications = [];
948
+ _subs = /* @__PURE__ */ new Set();
949
+ static getInstance() {
950
+ if (!_NotificationStore._instance) {
951
+ _NotificationStore._instance = new _NotificationStore();
952
+ }
953
+ return _NotificationStore._instance;
954
+ }
955
+ push(message, type = "info", durationMs) {
956
+ const id = Date.now().toString(36) + Math.random().toString(36).slice(2);
957
+ const notification = { id, message, type, durationMs, createdAt: Date.now() };
958
+ this._notifications = [...this._notifications, notification];
959
+ this._emit();
960
+ if (durationMs && durationMs > 0) {
961
+ setTimeout(() => this.dismiss(id), durationMs);
962
+ }
963
+ return id;
964
+ }
965
+ dismiss(id) {
966
+ const prev = this._notifications;
967
+ this._notifications = this._notifications.filter((n) => n.id !== id);
968
+ if (this._notifications.length !== prev.length) {
969
+ this._emit();
970
+ }
971
+ }
972
+ dismissAll() {
973
+ if (this._notifications.length > 0) {
974
+ this._notifications = [];
975
+ this._emit();
976
+ }
977
+ }
978
+ subscribe(fn) {
979
+ this._subs.add(fn);
980
+ return () => this._subs.delete(fn);
981
+ }
982
+ get notifications() {
983
+ return this._notifications;
984
+ }
985
+ _emit() {
986
+ for (const fn of this._subs) fn(this._notifications);
987
+ }
988
+ };
989
+ var notifications = NotificationStore.getInstance();
990
+ function useNotifications() {
991
+ const store = NotificationStore.getInstance();
992
+ const [current, setCurrent] = (0, import_jsx.useState)(store.notifications);
993
+ (0, import_jsx.useEffect)(() => {
994
+ const unsub = store.subscribe((ns) => setCurrent([...ns]));
995
+ return unsub;
996
+ }, []);
997
+ return {
998
+ notifications: current,
999
+ push: (msg, type, dur) => store.push(msg, type, dur),
1000
+ dismiss: (id) => store.dismiss(id),
1001
+ dismissAll: () => store.dismissAll()
1002
+ };
1003
+ }
1004
+ var TYPE_ICONS = {
1005
+ info: { unicode: "\u2139", ascii: "i" },
1006
+ success: { unicode: "\u2713", ascii: "+" },
1007
+ warning: { unicode: "\u26A0", ascii: "!" },
1008
+ error: { unicode: "\u2717", ascii: "x" }
1009
+ };
1010
+ var TYPE_COLORS = {
1011
+ info: { type: "named", name: "cyan" },
1012
+ success: { type: "named", name: "green" },
1013
+ warning: { type: "named", name: "yellow" },
1014
+ error: { type: "named", name: "red" }
1015
+ };
1016
+ var NotificationCenter = class extends import_widgets12.Widget {
1017
+ _position;
1018
+ _maxVisible;
1019
+ _notifWidth;
1020
+ _unsub;
1021
+ _current = [];
1022
+ constructor(options = {}) {
1023
+ super();
1024
+ this._position = options.position ?? "top-right";
1025
+ this._maxVisible = options.maxVisible ?? 5;
1026
+ this._notifWidth = options.width ?? 40;
1027
+ const store = NotificationStore.getInstance();
1028
+ this._current = store.notifications;
1029
+ this._unsub = store.subscribe((ns) => {
1030
+ this._current = ns;
1031
+ this.markDirty();
1032
+ });
1033
+ }
1034
+ unmount() {
1035
+ this._unsub?.();
1036
+ this._unsub = void 0;
1037
+ super.unmount();
1038
+ }
1039
+ _renderSelf(screen) {
1040
+ const visible = this._current.slice(-this._maxVisible);
1041
+ if (visible.length === 0) return;
1042
+ const { x, y, width, height } = this._rect;
1043
+ const tw = Math.min(this._notifWidth, width - 2);
1044
+ if (tw <= 0) return;
1045
+ const isRight = this._position.includes("right");
1046
+ const isBottom = this._position.includes("bottom");
1047
+ const sx = isRight ? x + width - tw - 1 : x + 1;
1048
+ const sy = isBottom ? y + height - visible.length - 1 : y + 1;
1049
+ for (let i = 0; i < visible.length; i++) {
1050
+ const notif = visible[i];
1051
+ const icon = import_core12.caps.unicode ? TYPE_ICONS[notif.type].unicode : TYPE_ICONS[notif.type].ascii;
1052
+ const raw = `${icon} ${notif.message}`;
1053
+ const label = ` ${raw} `.slice(0, tw).padEnd(tw);
1054
+ screen.writeString(sx, sy + i, label, {
1055
+ fg: TYPE_COLORS[notif.type],
1056
+ bold: true
1057
+ });
1058
+ }
1059
+ }
1060
+ };
1061
+
1062
+ // src/PasswordInput.ts
1063
+ var import_widgets13 = require("@termuijs/widgets");
1064
+ var import_core13 = require("@termuijs/core");
1065
+ var PasswordInput = class extends import_widgets13.Widget {
1066
+ _value = "";
1067
+ _cursorPos = 0;
1068
+ _placeholder;
1069
+ _maxLength;
1070
+ _showText = false;
1071
+ _onChange;
1072
+ _onSubmit;
1073
+ focusable = true;
1074
+ // '●' in unicode terminals, '*' in ASCII fallback
1075
+ get _maskChar() {
1076
+ return import_core13.caps.unicode ? "\u25CF" : "*";
1077
+ }
1078
+ constructor(style = {}, options = {}) {
1079
+ super({ border: "single", height: 3, ...style });
1080
+ this._placeholder = options.placeholder ?? "";
1081
+ this._maxLength = options.maxLength ?? Infinity;
1082
+ this._onChange = options.onChange;
1083
+ this._onSubmit = options.onSubmit;
1084
+ }
1085
+ /** The actual (unmasked) value. */
1086
+ get value() {
1087
+ return this._value;
1088
+ }
1089
+ set value(v) {
1090
+ this._value = v.slice(0, this._maxLength);
1091
+ this._cursorPos = Math.min(this._cursorPos, this._value.length);
1092
+ }
1093
+ /** Whether the text is currently visible (unmaksed). */
1094
+ get showText() {
1095
+ return this._showText;
1096
+ }
1097
+ /** Toggle visibility of the actual text (Alt+V). */
1098
+ toggleVisibility() {
1099
+ this._showText = !this._showText;
1100
+ this.markDirty();
1101
+ }
1102
+ insertChar(char) {
1103
+ if (this._value.length >= this._maxLength) return;
1104
+ this._value = this._value.slice(0, this._cursorPos) + char + this._value.slice(this._cursorPos);
1105
+ this._cursorPos++;
1106
+ this._onChange?.(this._value);
1107
+ this.markDirty();
1108
+ }
1109
+ deleteBack() {
1110
+ if (this._cursorPos > 0) {
1111
+ this._value = this._value.slice(0, this._cursorPos - 1) + this._value.slice(this._cursorPos);
1112
+ this._cursorPos--;
1113
+ this._onChange?.(this._value);
1114
+ this.markDirty();
1115
+ }
1116
+ }
1117
+ deleteForward() {
1118
+ if (this._cursorPos < this._value.length) {
1119
+ this._value = this._value.slice(0, this._cursorPos) + this._value.slice(this._cursorPos + 1);
1120
+ this._onChange?.(this._value);
1121
+ this.markDirty();
1122
+ }
1123
+ }
1124
+ moveCursorLeft() {
1125
+ this._cursorPos = Math.max(0, this._cursorPos - 1);
1126
+ this.markDirty();
1127
+ }
1128
+ moveCursorRight() {
1129
+ this._cursorPos = Math.min(this._value.length, this._cursorPos + 1);
1130
+ this.markDirty();
1131
+ }
1132
+ moveCursorHome() {
1133
+ this._cursorPos = 0;
1134
+ this.markDirty();
1135
+ }
1136
+ moveCursorEnd() {
1137
+ this._cursorPos = this._value.length;
1138
+ this.markDirty();
1139
+ }
1140
+ submit() {
1141
+ this._onSubmit?.(this._value);
1142
+ }
1143
+ clear() {
1144
+ this._value = "";
1145
+ this._cursorPos = 0;
1146
+ this._onChange?.("");
1147
+ this.markDirty();
1148
+ }
1149
+ /**
1150
+ * Handle key events. Call this from your input loop.
1151
+ * Alt+V — toggle visibility
1152
+ * Other — standard text editing
1153
+ */
1154
+ handleKey(event) {
1155
+ if (event.alt && event.key === "v") {
1156
+ this.toggleVisibility();
1157
+ return;
1158
+ }
1159
+ switch (event.key) {
1160
+ case "backspace":
1161
+ this.deleteBack();
1162
+ break;
1163
+ case "delete":
1164
+ this.deleteForward();
1165
+ break;
1166
+ case "left":
1167
+ this.moveCursorLeft();
1168
+ break;
1169
+ case "right":
1170
+ this.moveCursorRight();
1171
+ break;
1172
+ case "home":
1173
+ this.moveCursorHome();
1174
+ break;
1175
+ case "end":
1176
+ this.moveCursorEnd();
1177
+ break;
1178
+ case "return":
1179
+ case "enter":
1180
+ this.submit();
1181
+ break;
1182
+ default:
1183
+ if (event.key && event.key.length === 1 && !event.ctrl && !event.alt) {
1184
+ this.insertChar(event.key);
1185
+ }
1186
+ }
1187
+ }
1188
+ _renderSelf(screen) {
1189
+ const rect = this._getContentRect();
1190
+ const { x, y, width, height } = rect;
1191
+ if (width <= 0 || height <= 0) return;
1192
+ const attrs = (0, import_core13.styleToCellAttrs)(this._style);
1193
+ if (this._value.length === 0 && !this.isFocused) {
1194
+ screen.writeString(x, y, (0, import_core13.truncate)(this._placeholder, width), { ...attrs, dim: true });
1195
+ return;
1196
+ }
1197
+ const displayValue = this._showText ? this._value : this._maskChar.repeat(this._value.length);
1198
+ const visibleWidth = width - 1;
1199
+ let scrollX = 0;
1200
+ if (this._cursorPos > visibleWidth) {
1201
+ scrollX = this._cursorPos - visibleWidth;
1202
+ }
1203
+ const visibleText = displayValue.slice(scrollX, scrollX + visibleWidth);
1204
+ screen.writeString(x, y, visibleText, attrs);
1205
+ if (this.isFocused) {
1206
+ const cursorScreenPos = x + this._cursorPos - scrollX;
1207
+ if (cursorScreenPos >= x && cursorScreenPos < x + width) {
1208
+ const cursorChar = this._cursorPos < displayValue.length ? displayValue[this._cursorPos] : " ";
1209
+ screen.setCell(cursorScreenPos, y, {
1210
+ char: cursorChar,
1211
+ ...attrs,
1212
+ inverse: true
1213
+ });
1214
+ }
1215
+ }
1216
+ if (this._showText && width > 4) {
1217
+ const indicator = import_core13.caps.unicode ? " \u{1F441}" : "[v]";
1218
+ screen.writeString(x + width - indicator.length, y, indicator, { ...attrs, dim: true });
1219
+ }
1220
+ }
1221
+ };
1222
+
1223
+ // src/NumberInput.ts
1224
+ var import_widgets14 = require("@termuijs/widgets");
1225
+ var import_core14 = require("@termuijs/core");
1226
+ var NumberInput = class extends import_widgets14.Widget {
1227
+ _raw = "";
1228
+ // raw string the user typed
1229
+ _cursorPos = 0;
1230
+ _placeholder;
1231
+ _step;
1232
+ _min;
1233
+ _max;
1234
+ _allowDecimal;
1235
+ _onChange;
1236
+ _onSubmit;
1237
+ focusable = true;
1238
+ constructor(style = {}, options = {}) {
1239
+ super({ border: "single", height: 3, ...style });
1240
+ this._placeholder = options.placeholder ?? "";
1241
+ this._step = options.step ?? 1;
1242
+ this._min = options.min ?? -Infinity;
1243
+ this._max = options.max ?? Infinity;
1244
+ this._allowDecimal = options.allowDecimal ?? true;
1245
+ this._onChange = options.onChange;
1246
+ this._onSubmit = options.onSubmit;
1247
+ }
1248
+ /** The numeric value, or null if the field is empty / invalid. */
1249
+ get numericValue() {
1250
+ if (this._raw === "" || this._raw === "-") return null;
1251
+ const n = parseFloat(this._raw);
1252
+ return isNaN(n) ? null : n;
1253
+ }
1254
+ /** Raw text string (what the user typed). */
1255
+ get rawValue() {
1256
+ return this._raw;
1257
+ }
1258
+ set rawValue(v) {
1259
+ this._raw = v;
1260
+ this._cursorPos = Math.min(this._cursorPos, this._raw.length);
1261
+ }
1262
+ _clamp(n) {
1263
+ return Math.min(this._max, Math.max(this._min, n));
1264
+ }
1265
+ _notify() {
1266
+ this._onChange?.(this.numericValue);
1267
+ this.markDirty();
1268
+ }
1269
+ /** Accept only digits, '-' at position 0 (if min < 0), and (optionally) one '.'. */
1270
+ _isAllowed(char) {
1271
+ if (char === "-" && this._cursorPos === 0 && !this._raw.includes("-")) {
1272
+ return this._min < 0;
1273
+ }
1274
+ if (char === "." && this._allowDecimal && !this._raw.includes(".")) return true;
1275
+ return /^\d$/.test(char);
1276
+ }
1277
+ insertChar(char) {
1278
+ if (!this._isAllowed(char)) return;
1279
+ this._raw = this._raw.slice(0, this._cursorPos) + char + this._raw.slice(this._cursorPos);
1280
+ this._cursorPos++;
1281
+ this._notify();
1282
+ }
1283
+ deleteBack() {
1284
+ if (this._cursorPos > 0) {
1285
+ this._raw = this._raw.slice(0, this._cursorPos - 1) + this._raw.slice(this._cursorPos);
1286
+ this._cursorPos--;
1287
+ this._notify();
1288
+ }
1289
+ }
1290
+ deleteForward() {
1291
+ if (this._cursorPos < this._raw.length) {
1292
+ this._raw = this._raw.slice(0, this._cursorPos) + this._raw.slice(this._cursorPos + 1);
1293
+ this._notify();
1294
+ }
1295
+ }
1296
+ moveCursorLeft() {
1297
+ this._cursorPos = Math.max(0, this._cursorPos - 1);
1298
+ this.markDirty();
1299
+ }
1300
+ moveCursorRight() {
1301
+ this._cursorPos = Math.min(this._raw.length, this._cursorPos + 1);
1302
+ this.markDirty();
1303
+ }
1304
+ moveCursorHome() {
1305
+ this._cursorPos = 0;
1306
+ this.markDirty();
1307
+ }
1308
+ moveCursorEnd() {
1309
+ this._cursorPos = this._raw.length;
1310
+ this.markDirty();
1311
+ }
1312
+ /** Increment value by step (↑ arrow). */
1313
+ increment() {
1314
+ const current = this.numericValue ?? 0;
1315
+ const next = this._clamp(current + this._step);
1316
+ this._raw = String(next);
1317
+ this._cursorPos = this._raw.length;
1318
+ this._notify();
1319
+ }
1320
+ /** Decrement value by step (↓ arrow). */
1321
+ decrement() {
1322
+ const current = this.numericValue ?? 0;
1323
+ const next = this._clamp(current - this._step);
1324
+ this._raw = String(next);
1325
+ this._cursorPos = this._raw.length;
1326
+ this._notify();
1327
+ }
1328
+ submit() {
1329
+ this._onSubmit?.(this.numericValue);
1330
+ }
1331
+ clear() {
1332
+ this._raw = "";
1333
+ this._cursorPos = 0;
1334
+ this._notify();
1335
+ }
1336
+ /**
1337
+ * Handle key events. Call this from your input loop.
1338
+ */
1339
+ handleKey(event) {
1340
+ switch (event.key) {
1341
+ case "up":
1342
+ this.increment();
1343
+ break;
1344
+ case "down":
1345
+ this.decrement();
1346
+ break;
1347
+ case "backspace":
1348
+ this.deleteBack();
1349
+ break;
1350
+ case "delete":
1351
+ this.deleteForward();
1352
+ break;
1353
+ case "left":
1354
+ this.moveCursorLeft();
1355
+ break;
1356
+ case "right":
1357
+ this.moveCursorRight();
1358
+ break;
1359
+ case "home":
1360
+ this.moveCursorHome();
1361
+ break;
1362
+ case "end":
1363
+ this.moveCursorEnd();
1364
+ break;
1365
+ case "return":
1366
+ case "enter":
1367
+ this.submit();
1368
+ break;
1369
+ default:
1370
+ if (event.key && event.key.length === 1 && !event.ctrl && !event.alt) {
1371
+ this.insertChar(event.key);
1372
+ }
1373
+ }
1374
+ }
1375
+ _renderSelf(screen) {
1376
+ const rect = this._getContentRect();
1377
+ const { x, y, width, height } = rect;
1378
+ if (width <= 0 || height <= 0) return;
1379
+ const attrs = (0, import_core14.styleToCellAttrs)(this._style);
1380
+ if (this._raw.length === 0 && !this.isFocused) {
1381
+ screen.writeString(x, y, (0, import_core14.truncate)(this._placeholder, width), { ...attrs, dim: true });
1382
+ return;
1383
+ }
1384
+ const display = this._raw;
1385
+ const visibleWidth = width - 1;
1386
+ let scrollX = 0;
1387
+ if (this._cursorPos > visibleWidth) {
1388
+ scrollX = this._cursorPos - visibleWidth;
1389
+ }
1390
+ const visibleText = display.slice(scrollX, scrollX + visibleWidth);
1391
+ screen.writeString(x, y, visibleText, attrs);
1392
+ if (this.isFocused) {
1393
+ const cursorScreenPos = x + this._cursorPos - scrollX;
1394
+ if (cursorScreenPos >= x && cursorScreenPos < x + width) {
1395
+ const cursorChar = this._cursorPos < display.length ? display[this._cursorPos] : " ";
1396
+ screen.setCell(cursorScreenPos, y, {
1397
+ char: cursorChar,
1398
+ ...attrs,
1399
+ inverse: true
1400
+ });
1401
+ }
1402
+ }
1403
+ if (this.isFocused && width > 8) {
1404
+ const hint = `\xB1${this._step}`;
1405
+ screen.writeString(x + width - hint.length, y, hint, { ...attrs, dim: true });
1406
+ }
1407
+ }
1408
+ };
1409
+
1410
+ // src/PathInput.ts
1411
+ var fs = __toESM(require("fs"), 1);
1412
+ var path = __toESM(require("path"), 1);
1413
+ var import_widgets15 = require("@termuijs/widgets");
1414
+ var import_core15 = require("@termuijs/core");
1415
+ var PathInput = class extends import_widgets15.Widget {
1416
+ _value = "";
1417
+ _cursorPos = 0;
1418
+ _placeholder;
1419
+ _maxLength;
1420
+ _cwd;
1421
+ _maxCompletions;
1422
+ _completions = [];
1423
+ _completionIndex = -1;
1424
+ // -1 = original value, 0..n = cycling
1425
+ _preCompletionValue = "";
1426
+ // value before Tab was pressed
1427
+ _showCompletions = false;
1428
+ _onChange;
1429
+ _onSubmit;
1430
+ focusable = true;
1431
+ constructor(style = {}, options = {}) {
1432
+ super({ border: "single", height: 3, ...style });
1433
+ this._placeholder = options.placeholder ?? "";
1434
+ this._maxLength = options.maxLength ?? 4096;
1435
+ this._cwd = options.cwd ?? process.cwd();
1436
+ this._maxCompletions = options.maxCompletions ?? 5;
1437
+ this._onChange = options.onChange;
1438
+ this._onSubmit = options.onSubmit;
1439
+ }
1440
+ get value() {
1441
+ return this._value;
1442
+ }
1443
+ set value(v) {
1444
+ this._value = v.slice(0, this._maxLength);
1445
+ this._cursorPos = Math.min(this._cursorPos, this._value.length);
1446
+ this._dismissCompletions();
1447
+ }
1448
+ get completions() {
1449
+ return this._completions;
1450
+ }
1451
+ get isShowingCompletions() {
1452
+ return this._showCompletions && this._completions.length > 0;
1453
+ }
1454
+ _dismissCompletions() {
1455
+ this._completions = [];
1456
+ this._completionIndex = -1;
1457
+ this._showCompletions = false;
1458
+ }
1459
+ /** Compute completions for the current value. Does NOT throw. */
1460
+ _computeCompletions() {
1461
+ try {
1462
+ const raw = this._value;
1463
+ const isAbs = path.isAbsolute(raw);
1464
+ const base = isAbs ? raw : path.join(this._cwd, raw);
1465
+ let dir;
1466
+ let prefix;
1467
+ if (raw === "" || raw.endsWith("/") || raw.endsWith(path.sep)) {
1468
+ dir = isAbs ? raw || "/" : path.join(this._cwd, raw || ".");
1469
+ prefix = "";
1470
+ } else {
1471
+ dir = path.dirname(base);
1472
+ prefix = path.basename(base).toLowerCase();
1473
+ }
1474
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
1475
+ const matches = entries.filter((e) => e.name.toLowerCase().startsWith(prefix)).slice(0, this._maxCompletions).map((e) => {
1476
+ const full = path.join(dir, e.name);
1477
+ const candidate = isAbs ? full + (e.isDirectory() ? path.sep : "") : path.relative(this._cwd, full) + (e.isDirectory() ? path.sep : "");
1478
+ return candidate;
1479
+ });
1480
+ return matches;
1481
+ } catch {
1482
+ return [];
1483
+ }
1484
+ }
1485
+ /** Trigger tab-completion. */
1486
+ triggerCompletion() {
1487
+ if (!this._showCompletions || this._completions.length === 0) {
1488
+ this._preCompletionValue = this._value;
1489
+ this._completions = this._computeCompletions();
1490
+ if (this._completions.length === 0) {
1491
+ this._showCompletions = false;
1492
+ return;
1493
+ }
1494
+ this._showCompletions = true;
1495
+ this._completionIndex = 0;
1496
+ } else {
1497
+ this._completionIndex = (this._completionIndex + 1) % this._completions.length;
1498
+ }
1499
+ this._value = this._completions[this._completionIndex];
1500
+ this._cursorPos = this._value.length;
1501
+ this._onChange?.(this._value);
1502
+ this.markDirty();
1503
+ }
1504
+ insertChar(char) {
1505
+ if (this._value.length >= this._maxLength) return;
1506
+ this._value = this._value.slice(0, this._cursorPos) + char + this._value.slice(this._cursorPos);
1507
+ this._cursorPos++;
1508
+ this._dismissCompletions();
1509
+ this._onChange?.(this._value);
1510
+ this.markDirty();
1511
+ }
1512
+ deleteBack() {
1513
+ if (this._cursorPos > 0) {
1514
+ this._value = this._value.slice(0, this._cursorPos - 1) + this._value.slice(this._cursorPos);
1515
+ this._cursorPos--;
1516
+ this._dismissCompletions();
1517
+ this._onChange?.(this._value);
1518
+ this.markDirty();
1519
+ }
1520
+ }
1521
+ deleteForward() {
1522
+ if (this._cursorPos < this._value.length) {
1523
+ this._value = this._value.slice(0, this._cursorPos) + this._value.slice(this._cursorPos + 1);
1524
+ this._dismissCompletions();
1525
+ this._onChange?.(this._value);
1526
+ this.markDirty();
1527
+ }
1528
+ }
1529
+ moveCursorLeft() {
1530
+ this._cursorPos = Math.max(0, this._cursorPos - 1);
1531
+ this.markDirty();
1532
+ }
1533
+ moveCursorRight() {
1534
+ this._cursorPos = Math.min(this._value.length, this._cursorPos + 1);
1535
+ this.markDirty();
1536
+ }
1537
+ moveCursorHome() {
1538
+ this._cursorPos = 0;
1539
+ this.markDirty();
1540
+ }
1541
+ moveCursorEnd() {
1542
+ this._cursorPos = this._value.length;
1543
+ this.markDirty();
1544
+ }
1545
+ submit() {
1546
+ this._dismissCompletions();
1547
+ this._onSubmit?.(this._value);
1548
+ }
1549
+ clear() {
1550
+ this._value = "";
1551
+ this._cursorPos = 0;
1552
+ this._dismissCompletions();
1553
+ this._onChange?.("");
1554
+ this.markDirty();
1555
+ }
1556
+ /**
1557
+ * Handle key events. Call this from your input loop.
1558
+ * Tab — trigger/cycle completions
1559
+ * Esc — dismiss completions
1560
+ * Enter — submit current value
1561
+ */
1562
+ handleKey(event) {
1563
+ switch (event.key) {
1564
+ case "tab":
1565
+ this.triggerCompletion();
1566
+ break;
1567
+ case "escape":
1568
+ this._dismissCompletions();
1569
+ this.markDirty();
1570
+ break;
1571
+ case "backspace":
1572
+ this.deleteBack();
1573
+ break;
1574
+ case "delete":
1575
+ this.deleteForward();
1576
+ break;
1577
+ case "left":
1578
+ this.moveCursorLeft();
1579
+ break;
1580
+ case "right":
1581
+ this.moveCursorRight();
1582
+ break;
1583
+ case "home":
1584
+ this.moveCursorHome();
1585
+ break;
1586
+ case "end":
1587
+ this.moveCursorEnd();
1588
+ break;
1589
+ case "return":
1590
+ case "enter":
1591
+ this.submit();
1592
+ break;
1593
+ default:
1594
+ if (event.key && event.key.length === 1 && !event.ctrl && !event.alt) {
1595
+ this.insertChar(event.key);
1596
+ }
1597
+ }
1598
+ }
1599
+ _renderSelf(screen) {
1600
+ const rect = this._getContentRect();
1601
+ const { x, y, width, height } = rect;
1602
+ if (width <= 0 || height <= 0) return;
1603
+ const attrs = (0, import_core15.styleToCellAttrs)(this._style);
1604
+ if (height <= 1 && this._showCompletions) {
1605
+ this._showCompletions = false;
1606
+ }
1607
+ if (this._value.length === 0 && !this.isFocused) {
1608
+ screen.writeString(x, y, (0, import_core15.truncate)(this._placeholder, width), { ...attrs, dim: true });
1609
+ } else {
1610
+ const visibleWidth = width - 1;
1611
+ let scrollX = 0;
1612
+ if (this._cursorPos > visibleWidth) {
1613
+ scrollX = this._cursorPos - visibleWidth;
1614
+ }
1615
+ const visibleText = this._value.slice(scrollX, scrollX + visibleWidth);
1616
+ screen.writeString(x, y, visibleText, attrs);
1617
+ if (this.isFocused) {
1618
+ const cursorScreenPos = x + this._cursorPos - scrollX;
1619
+ if (cursorScreenPos >= x && cursorScreenPos < x + width) {
1620
+ const cursorChar = this._cursorPos < this._value.length ? this._value[this._cursorPos] : " ";
1621
+ screen.setCell(cursorScreenPos, y, {
1622
+ char: cursorChar,
1623
+ ...attrs,
1624
+ inverse: true
1625
+ });
1626
+ }
1627
+ }
1628
+ }
1629
+ if (this._showCompletions && this._completions.length > 0 && height > 1) {
1630
+ const maxRows = Math.min(this._completions.length, height - 1);
1631
+ for (let i = 0; i < maxRows; i++) {
1632
+ const row = y + 1 + i;
1633
+ const isSelected = i === this._completionIndex;
1634
+ const prefix = isSelected ? import_core15.caps.unicode ? "\u25B6 " : "> " : " ";
1635
+ const entry = this._completions[i];
1636
+ screen.writeString(x, row, (0, import_core15.truncate)(prefix + entry, width), {
1637
+ ...attrs,
1638
+ bold: isSelected,
1639
+ inverse: isSelected
1640
+ });
1641
+ }
1642
+ }
1643
+ }
1644
+ };
1645
+
1646
+ // src/KeyboardShortcuts.ts
1647
+ var import_widgets16 = require("@termuijs/widgets");
1648
+ var import_core16 = require("@termuijs/core");
1649
+ var KeyboardShortcuts = class extends import_widgets16.Widget {
1650
+ _bindings;
1651
+ _keyColor;
1652
+ _categoryColor;
1653
+ _columns;
1654
+ _showCategories;
1655
+ constructor(bindings, options = {}) {
1656
+ super({});
1657
+ this._bindings = bindings;
1658
+ this._keyColor = options.keyColor ?? { type: "named", name: "cyan" };
1659
+ this._categoryColor = options.categoryColor ?? { type: "named", name: "yellow" };
1660
+ this._columns = Math.max(1, options.columns ?? 2);
1661
+ this._showCategories = options.showCategories ?? true;
1662
+ }
1663
+ /** Replace all bindings and trigger a re-render. */
1664
+ setBindings(bindings) {
1665
+ this._bindings = bindings;
1666
+ this.markDirty();
1667
+ }
1668
+ /** Group bindings by category, preserving insertion order. */
1669
+ _groupBindings() {
1670
+ const groups = [];
1671
+ const indexMap = /* @__PURE__ */ new Map();
1672
+ for (const b of this._bindings) {
1673
+ const cat = b.category ?? "";
1674
+ const key = cat;
1675
+ if (!indexMap.has(key)) {
1676
+ indexMap.set(key, groups.length);
1677
+ groups.push({ category: b.category, bindings: [] });
1678
+ }
1679
+ groups[indexMap.get(key)].bindings.push(b);
1680
+ }
1681
+ return groups;
1682
+ }
1683
+ /**
1684
+ * Render a key label in a bordered box style:
1685
+ * ┌─────┐
1686
+ * │ key │
1687
+ * └─────┘
1688
+ *
1689
+ * We fit it on one line: [ key ] — box drawing characters or ASCII fallback.
1690
+ */
1691
+ _renderKeyLabel(screen, kx, ky, key, attrs) {
1692
+ if (import_core16.caps.unicode) {
1693
+ const label = `[${key}]`;
1694
+ screen.writeString(kx, ky, label, { ...attrs, fg: this._keyColor, bold: true });
1695
+ return label.length;
1696
+ } else {
1697
+ const label = `[${key}]`;
1698
+ screen.writeString(kx, ky, label, { ...attrs, fg: this._keyColor, bold: true });
1699
+ return label.length;
1700
+ }
1701
+ }
1702
+ _renderSelf(screen) {
1703
+ const { x, y, width, height } = this._rect;
1704
+ if (width <= 0 || height <= 0) return;
1705
+ const attrs = (0, import_core16.styleToCellAttrs)(this._style);
1706
+ const groups = this._groupBindings();
1707
+ let row = y;
1708
+ const colWidth = Math.floor(width / this._columns);
1709
+ for (const group of groups) {
1710
+ if (row >= y + height) break;
1711
+ if (this._showCategories && group.category) {
1712
+ const heading = group.category.toUpperCase();
1713
+ const divider = import_core16.caps.unicode ? "\u2500" : "-";
1714
+ const line = heading + " " + divider.repeat(Math.max(0, width - heading.length - 1));
1715
+ screen.writeString(x, row, line.slice(0, width), {
1716
+ ...attrs,
1717
+ fg: this._categoryColor,
1718
+ bold: true
1719
+ });
1720
+ row++;
1721
+ if (row >= y + height) break;
1722
+ }
1723
+ for (let i = 0; i < group.bindings.length; i += this._columns) {
1724
+ if (row >= y + height) break;
1725
+ for (let col = 0; col < this._columns; col++) {
1726
+ const binding = group.bindings[i + col];
1727
+ if (!binding) continue;
1728
+ const cx = x + col * colWidth;
1729
+ const availWidth = colWidth - 1;
1730
+ if (availWidth <= 0) continue;
1731
+ const labelLen = this._renderKeyLabel(screen, cx, row, binding.key, attrs);
1732
+ const descX = cx + labelLen + 1;
1733
+ const descWidth = availWidth - labelLen - 1;
1734
+ if (descWidth > 0) {
1735
+ const desc = binding.description.slice(0, descWidth);
1736
+ screen.writeString(descX, row, desc, attrs);
1737
+ }
1738
+ }
1739
+ row++;
1740
+ }
1741
+ if (this._showCategories && group.category) {
1742
+ row++;
1743
+ }
1744
+ }
1745
+ }
1746
+ };
811
1747
  // Annotate the CommonJS export names for ESM import in node:
812
1748
  0 && (module.exports = {
813
1749
  Box,
@@ -816,10 +1752,17 @@ var CommandPalette = class extends import_widgets11.Widget {
816
1752
  Divider,
817
1753
  Form,
818
1754
  Gauge,
1755
+ KeyboardShortcuts,
819
1756
  List,
820
1757
  LogView,
821
1758
  Modal,
822
1759
  MultiSelect,
1760
+ NonInteractiveError,
1761
+ NotificationCenter,
1762
+ NotificationStore,
1763
+ NumberInput,
1764
+ PasswordInput,
1765
+ PathInput,
823
1766
  ProgressBar,
824
1767
  Select,
825
1768
  Spacer,
@@ -832,6 +1775,9 @@ var CommandPalette = class extends import_widgets11.Widget {
832
1775
  TextInput,
833
1776
  Toast,
834
1777
  Tree,
835
- Widget
1778
+ Widget,
1779
+ notifications,
1780
+ prompt,
1781
+ useNotifications
836
1782
  });
837
1783
  //# sourceMappingURL=index.cjs.map