@promptctl/rich-js 0.18.0 → 0.18.1

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.
Files changed (221) hide show
  1. package/dist/core/anchor.d.ts +45 -0
  2. package/dist/core/anchor.js +39 -0
  3. package/dist/core/ansi.d.ts +65 -0
  4. package/dist/core/ansi.js +231 -0
  5. package/dist/core/box.d.ts +143 -0
  6. package/dist/core/box.js +379 -0
  7. package/dist/core/cells.d.ts +159 -0
  8. package/dist/core/cells.js +287 -0
  9. package/dist/core/color.d.ts +246 -0
  10. package/dist/core/color.js +1038 -0
  11. package/dist/core/console.d.ts +165 -0
  12. package/dist/core/console.js +527 -0
  13. package/dist/core/emoji.d.ts +24 -0
  14. package/dist/core/emoji.js +391 -0
  15. package/dist/core/export-html.d.ts +59 -0
  16. package/dist/core/export-html.js +200 -0
  17. package/dist/core/export-lines.d.ts +121 -0
  18. package/dist/core/export-lines.js +141 -0
  19. package/dist/core/highlighter.d.ts +33 -0
  20. package/dist/core/highlighter.js +124 -0
  21. package/dist/core/json.d.ts +27 -0
  22. package/dist/core/json.js +53 -0
  23. package/dist/core/markup.d.ts +119 -0
  24. package/dist/core/markup.js +731 -0
  25. package/dist/core/measure.d.ts +27 -0
  26. package/dist/core/measure.js +62 -0
  27. package/dist/core/oklch.d.ts +161 -0
  28. package/dist/core/oklch.js +312 -0
  29. package/dist/core/osc8.d.ts +68 -0
  30. package/dist/core/osc8.js +90 -0
  31. package/dist/core/place.d.ts +30 -0
  32. package/dist/core/place.js +51 -0
  33. package/dist/core/pretty.d.ts +144 -0
  34. package/dist/core/pretty.js +476 -0
  35. package/dist/core/protocol.d.ts +267 -0
  36. package/dist/core/protocol.js +163 -0
  37. package/dist/core/render.d.ts +84 -0
  38. package/dist/core/render.js +145 -0
  39. package/dist/core/segment.d.ts +161 -0
  40. package/dist/core/segment.js +492 -0
  41. package/dist/core/spinnerData.d.ts +12 -0
  42. package/dist/core/spinnerData.js +117 -0
  43. package/dist/core/strip.d.ts +141 -0
  44. package/dist/core/strip.js +305 -0
  45. package/dist/core/style.d.ts +169 -0
  46. package/dist/core/style.js +695 -0
  47. package/dist/core/subscription.d.ts +12 -0
  48. package/dist/core/subscription.js +12 -0
  49. package/dist/core/text.d.ts +256 -0
  50. package/dist/core/text.js +976 -0
  51. package/dist/core/wrap.d.ts +41 -0
  52. package/dist/core/wrap.js +127 -0
  53. package/dist/host/app.d.ts +121 -0
  54. package/dist/host/app.js +255 -0
  55. package/dist/host/host-environment.d.ts +26 -0
  56. package/dist/host/host-environment.js +44 -0
  57. package/dist/host/index.d.ts +5 -0
  58. package/dist/host/index.js +3 -0
  59. package/dist/host/terminal-host.d.ts +179 -0
  60. package/dist/host/terminal-host.js +186 -0
  61. package/dist/index.d.ts +91 -0
  62. package/dist/index.js +107 -0
  63. package/dist/node/prompt.d.ts +21 -0
  64. package/dist/node/prompt.js +30 -0
  65. package/dist/node/save.d.ts +17 -0
  66. package/dist/node/save.js +21 -0
  67. package/dist/node/terminal-host.d.ts +113 -0
  68. package/dist/node/terminal-host.js +227 -0
  69. package/dist/node/traceback.d.ts +37 -0
  70. package/dist/node/traceback.js +134 -0
  71. package/dist/renderables/align.d.ts +16 -0
  72. package/dist/renderables/align.js +33 -0
  73. package/dist/renderables/columns.d.ts +61 -0
  74. package/dist/renderables/columns.js +152 -0
  75. package/dist/renderables/constrain.d.ts +15 -0
  76. package/dist/renderables/constrain.js +37 -0
  77. package/dist/renderables/embed.d.ts +50 -0
  78. package/dist/renderables/embed.js +71 -0
  79. package/dist/renderables/flexStrip.d.ts +41 -0
  80. package/dist/renderables/flexStrip.js +200 -0
  81. package/dist/renderables/group.d.ts +11 -0
  82. package/dist/renderables/group.js +17 -0
  83. package/dist/renderables/layout.d.ts +92 -0
  84. package/dist/renderables/layout.js +312 -0
  85. package/dist/renderables/live.d.ts +50 -0
  86. package/dist/renderables/live.js +175 -0
  87. package/dist/renderables/markdown.d.ts +24 -0
  88. package/dist/renderables/markdown.js +184 -0
  89. package/dist/renderables/padding.d.ts +38 -0
  90. package/dist/renderables/padding.js +141 -0
  91. package/dist/renderables/panel.d.ts +116 -0
  92. package/dist/renderables/panel.js +307 -0
  93. package/dist/renderables/progress.d.ts +90 -0
  94. package/dist/renderables/progress.js +238 -0
  95. package/dist/renderables/progressBar.d.ts +31 -0
  96. package/dist/renderables/progressBar.js +53 -0
  97. package/dist/renderables/prompt.d.ts +49 -0
  98. package/dist/renderables/prompt.js +125 -0
  99. package/dist/renderables/rule.d.ts +25 -0
  100. package/dist/renderables/rule.js +90 -0
  101. package/dist/renderables/spinner.d.ts +31 -0
  102. package/dist/renderables/spinner.js +70 -0
  103. package/dist/renderables/status.d.ts +23 -0
  104. package/dist/renderables/status.js +60 -0
  105. package/dist/renderables/syntax.d.ts +35 -0
  106. package/dist/renderables/syntax.js +115 -0
  107. package/dist/renderables/table.d.ts +194 -0
  108. package/dist/renderables/table.js +795 -0
  109. package/dist/renderables/traceback.d.ts +31 -0
  110. package/dist/renderables/traceback.js +108 -0
  111. package/dist/renderables/tree.d.ts +68 -0
  112. package/dist/renderables/tree.js +150 -0
  113. package/dist/renderables/viewport.d.ts +114 -0
  114. package/dist/renderables/viewport.js +198 -0
  115. package/dist/template-bindings/color-funcs.d.ts +87 -0
  116. package/dist/template-bindings/color-funcs.js +217 -0
  117. package/dist/template-bindings/helpers.d.ts +24 -0
  118. package/dist/template-bindings/helpers.js +48 -0
  119. package/dist/template-bindings/index.d.ts +107 -0
  120. package/dist/template-bindings/index.js +146 -0
  121. package/dist/template-bindings/palette-funcs.d.ts +94 -0
  122. package/dist/template-bindings/palette-funcs.js +141 -0
  123. package/dist/template-bindings/style-funcs.d.ts +28 -0
  124. package/dist/template-bindings/style-funcs.js +155 -0
  125. package/dist/themes/buildPalette.d.ts +36 -0
  126. package/dist/themes/buildPalette.js +56 -0
  127. package/dist/themes/colorMath.d.ts +82 -0
  128. package/dist/themes/colorMath.js +254 -0
  129. package/dist/themes/colorRef.d.ts +51 -0
  130. package/dist/themes/colorRef.js +96 -0
  131. package/dist/themes/data/ansi-tables.d.ts +14 -0
  132. package/dist/themes/data/ansi-tables.js +49 -0
  133. package/dist/themes/data/atom-one-dark.d.ts +3 -0
  134. package/dist/themes/data/atom-one-dark.js +177 -0
  135. package/dist/themes/data/atom-one-light.d.ts +3 -0
  136. package/dist/themes/data/atom-one-light.js +177 -0
  137. package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
  138. package/dist/themes/data/catppuccin-frappe.js +177 -0
  139. package/dist/themes/data/catppuccin-latte.d.ts +3 -0
  140. package/dist/themes/data/catppuccin-latte.js +177 -0
  141. package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
  142. package/dist/themes/data/catppuccin-macchiato.js +177 -0
  143. package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
  144. package/dist/themes/data/catppuccin-mocha.js +177 -0
  145. package/dist/themes/data/cyberpunk.d.ts +17 -0
  146. package/dist/themes/data/cyberpunk.js +193 -0
  147. package/dist/themes/data/default.d.ts +3 -0
  148. package/dist/themes/data/default.js +160 -0
  149. package/dist/themes/data/dracula.d.ts +3 -0
  150. package/dist/themes/data/dracula.js +177 -0
  151. package/dist/themes/data/flexoki.d.ts +3 -0
  152. package/dist/themes/data/flexoki.js +177 -0
  153. package/dist/themes/data/gruvbox.d.ts +3 -0
  154. package/dist/themes/data/gruvbox.js +177 -0
  155. package/dist/themes/data/index.d.ts +35 -0
  156. package/dist/themes/data/index.js +64 -0
  157. package/dist/themes/data/monokai.d.ts +3 -0
  158. package/dist/themes/data/monokai.js +177 -0
  159. package/dist/themes/data/nord.d.ts +3 -0
  160. package/dist/themes/data/nord.js +177 -0
  161. package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
  162. package/dist/themes/data/rose-pine-dawn.js +177 -0
  163. package/dist/themes/data/rose-pine-moon.d.ts +3 -0
  164. package/dist/themes/data/rose-pine-moon.js +177 -0
  165. package/dist/themes/data/rose-pine.d.ts +3 -0
  166. package/dist/themes/data/rose-pine.js +177 -0
  167. package/dist/themes/data/solarized-dark.d.ts +3 -0
  168. package/dist/themes/data/solarized-dark.js +177 -0
  169. package/dist/themes/data/solarized-light.d.ts +3 -0
  170. package/dist/themes/data/solarized-light.js +177 -0
  171. package/dist/themes/data/svg-export.d.ts +3 -0
  172. package/dist/themes/data/svg-export.js +177 -0
  173. package/dist/themes/data/textual-ansi.d.ts +3 -0
  174. package/dist/themes/data/textual-ansi.js +160 -0
  175. package/dist/themes/data/textual-dark.d.ts +3 -0
  176. package/dist/themes/data/textual-dark.js +160 -0
  177. package/dist/themes/data/textual-light.d.ts +3 -0
  178. package/dist/themes/data/textual-light.js +160 -0
  179. package/dist/themes/data/tokyo-night.d.ts +3 -0
  180. package/dist/themes/data/tokyo-night.js +177 -0
  181. package/dist/themes/data/types.d.ts +31 -0
  182. package/dist/themes/data/types.js +10 -0
  183. package/dist/themes/palette.d.ts +21 -0
  184. package/dist/themes/palette.js +28 -0
  185. package/dist/themes/ramp.d.ts +83 -0
  186. package/dist/themes/ramp.js +122 -0
  187. package/dist/themes/registry.d.ts +44 -0
  188. package/dist/themes/registry.js +94 -0
  189. package/dist/themes/terminalThemes.d.ts +49 -0
  190. package/dist/themes/terminalThemes.js +63 -0
  191. package/dist/themes/transpose.d.ts +87 -0
  192. package/dist/themes/transpose.js +138 -0
  193. package/dist/widgets/button.d.ts +49 -0
  194. package/dist/widgets/button.js +208 -0
  195. package/dist/widgets/checkbox.d.ts +41 -0
  196. package/dist/widgets/checkbox.js +157 -0
  197. package/dist/widgets/dropdown.d.ts +67 -0
  198. package/dist/widgets/dropdown.js +450 -0
  199. package/dist/widgets/event-router.d.ts +71 -0
  200. package/dist/widgets/event-router.js +629 -0
  201. package/dist/widgets/focus-manager.d.ts +45 -0
  202. package/dist/widgets/focus-manager.js +191 -0
  203. package/dist/widgets/hit.d.ts +64 -0
  204. package/dist/widgets/hit.js +113 -0
  205. package/dist/widgets/index.d.ts +20 -0
  206. package/dist/widgets/index.js +14 -0
  207. package/dist/widgets/slider.d.ts +57 -0
  208. package/dist/widgets/slider.js +270 -0
  209. package/dist/widgets/static-item.d.ts +34 -0
  210. package/dist/widgets/static-item.js +54 -0
  211. package/dist/widgets/text-input.d.ts +274 -0
  212. package/dist/widgets/text-input.js +1165 -0
  213. package/dist/widgets/toggle.d.ts +44 -0
  214. package/dist/widgets/toggle.js +180 -0
  215. package/dist/widgets/types.d.ts +87 -0
  216. package/dist/widgets/types.js +30 -0
  217. package/dist/widgets/widget-app.d.ts +63 -0
  218. package/dist/widgets/widget-app.js +199 -0
  219. package/dist/widgets/widget-base.d.ts +40 -0
  220. package/dist/widgets/widget-base.js +165 -0
  221. package/package.json +6 -2
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Slider widget — numeric value within [min, max] with step increments.
3
+ * [LAW:dataflow-not-control-flow] every render emits exactly `width`
4
+ * track cells; the marker cell index is data, not a branch.
5
+ * [LAW:one-type-per-behavior] shared infrastructure inherited from
6
+ * WidgetBase.
7
+ *
8
+ * Visual:
9
+ * track — `width` cells of "─" (ASCII fallback "-")
10
+ * marker — "●" (ASCII fallback "*") at round((value - min) / range * (width - 1))
11
+ * filled — cells left of and including the marker use primary fg
12
+ * on the default terminal bg
13
+ * unfilled — cells right of the marker use surface fg on the default
14
+ * terminal bg (no explicit bgcolor — the unfilled track
15
+ * should sit transparently against whatever the panel /
16
+ * parent paints underneath)
17
+ * focused — underline on the segments
18
+ * disabled — dim
19
+ */
20
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
21
+ var useValue = arguments.length > 2;
22
+ for (var i = 0; i < initializers.length; i++) {
23
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
24
+ }
25
+ return useValue ? value : void 0;
26
+ };
27
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
28
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
29
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
30
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
31
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
32
+ var _, done = false;
33
+ for (var i = decorators.length - 1; i >= 0; i--) {
34
+ var context = {};
35
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
36
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
37
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
38
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
39
+ if (kind === "accessor") {
40
+ if (result === void 0) continue;
41
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
42
+ if (_ = accept(result.get)) descriptor.get = _;
43
+ if (_ = accept(result.set)) descriptor.set = _;
44
+ if (_ = accept(result.init)) initializers.unshift(_);
45
+ }
46
+ else if (_ = accept(result)) {
47
+ if (kind === "field") initializers.unshift(_);
48
+ else descriptor[key] = _;
49
+ }
50
+ }
51
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
52
+ done = true;
53
+ };
54
+ import { observable, action, observableRef } from "mobx";
55
+ import { Segment } from "../core/segment.js";
56
+ import { Style } from "../core/style.js";
57
+ import { ColorSpec } from "../core/color.js";
58
+ import { DEFAULT_TERMINAL_THEME } from "../themes/terminalThemes.js";
59
+ import { drawable } from "../core/protocol.js";
60
+ import { WidgetBase } from "./widget-base.js";
61
+ const DEFAULT_WIDTH = 20;
62
+ let Slider = (() => {
63
+ let _classSuper = WidgetBase;
64
+ let _instanceExtraInitializers = [];
65
+ let _value_decorators;
66
+ let _value_initializers = [];
67
+ let _value_extraInitializers = [];
68
+ let _min_decorators;
69
+ let _min_initializers = [];
70
+ let _min_extraInitializers = [];
71
+ let _max_decorators;
72
+ let _max_initializers = [];
73
+ let _max_extraInitializers = [];
74
+ let _step_decorators;
75
+ let _step_initializers = [];
76
+ let _step_extraInitializers = [];
77
+ let _width_decorators;
78
+ let _width_initializers = [];
79
+ let _width_extraInitializers = [];
80
+ let __theme_decorators;
81
+ let __theme_initializers = [];
82
+ let __theme_extraInitializers = [];
83
+ let _setTheme_decorators;
84
+ let _handleKey_decorators;
85
+ let _handleMouse_decorators;
86
+ let _setValue_decorators;
87
+ return class Slider extends _classSuper {
88
+ static {
89
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
90
+ _value_decorators = [observable];
91
+ _min_decorators = [observableRef];
92
+ _max_decorators = [observableRef];
93
+ _step_decorators = [observableRef];
94
+ _width_decorators = [observableRef];
95
+ __theme_decorators = [observableRef];
96
+ _setTheme_decorators = [action];
97
+ _handleKey_decorators = [action];
98
+ _handleMouse_decorators = [action];
99
+ _setValue_decorators = [action];
100
+ __esDecorate(this, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
101
+ __esDecorate(this, null, _min_decorators, { kind: "accessor", name: "min", static: false, private: false, access: { has: obj => "min" in obj, get: obj => obj.min, set: (obj, value) => { obj.min = value; } }, metadata: _metadata }, _min_initializers, _min_extraInitializers);
102
+ __esDecorate(this, null, _max_decorators, { kind: "accessor", name: "max", static: false, private: false, access: { has: obj => "max" in obj, get: obj => obj.max, set: (obj, value) => { obj.max = value; } }, metadata: _metadata }, _max_initializers, _max_extraInitializers);
103
+ __esDecorate(this, null, _step_decorators, { kind: "accessor", name: "step", static: false, private: false, access: { has: obj => "step" in obj, get: obj => obj.step, set: (obj, value) => { obj.step = value; } }, metadata: _metadata }, _step_initializers, _step_extraInitializers);
104
+ __esDecorate(this, null, _width_decorators, { kind: "accessor", name: "width", static: false, private: false, access: { has: obj => "width" in obj, get: obj => obj.width, set: (obj, value) => { obj.width = value; } }, metadata: _metadata }, _width_initializers, _width_extraInitializers);
105
+ __esDecorate(this, null, __theme_decorators, { kind: "accessor", name: "_theme", static: false, private: false, access: { has: obj => "_theme" in obj, get: obj => obj._theme, set: (obj, value) => { obj._theme = value; } }, metadata: _metadata }, __theme_initializers, __theme_extraInitializers);
106
+ __esDecorate(this, null, _setTheme_decorators, { kind: "method", name: "setTheme", static: false, private: false, access: { has: obj => "setTheme" in obj, get: obj => obj.setTheme }, metadata: _metadata }, null, _instanceExtraInitializers);
107
+ __esDecorate(this, null, _handleKey_decorators, { kind: "method", name: "handleKey", static: false, private: false, access: { has: obj => "handleKey" in obj, get: obj => obj.handleKey }, metadata: _metadata }, null, _instanceExtraInitializers);
108
+ __esDecorate(this, null, _handleMouse_decorators, { kind: "method", name: "handleMouse", static: false, private: false, access: { has: obj => "handleMouse" in obj, get: obj => obj.handleMouse }, metadata: _metadata }, null, _instanceExtraInitializers);
109
+ __esDecorate(this, null, _setValue_decorators, { kind: "method", name: "setValue", static: false, private: false, access: { has: obj => "setValue" in obj, get: obj => obj.setValue }, metadata: _metadata }, null, _instanceExtraInitializers);
110
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
111
+ }
112
+ id = __runInitializers(this, _instanceExtraInitializers);
113
+ focusable = true;
114
+ #value_accessor_storage = __runInitializers(this, _value_initializers, void 0);
115
+ get value() { return this.#value_accessor_storage; }
116
+ set value(value) { this.#value_accessor_storage = value; }
117
+ #min_accessor_storage = (__runInitializers(this, _value_extraInitializers), __runInitializers(this, _min_initializers, void 0));
118
+ get min() { return this.#min_accessor_storage; }
119
+ set min(value) { this.#min_accessor_storage = value; }
120
+ #max_accessor_storage = (__runInitializers(this, _min_extraInitializers), __runInitializers(this, _max_initializers, void 0));
121
+ get max() { return this.#max_accessor_storage; }
122
+ set max(value) { this.#max_accessor_storage = value; }
123
+ #step_accessor_storage = (__runInitializers(this, _max_extraInitializers), __runInitializers(this, _step_initializers, void 0));
124
+ get step() { return this.#step_accessor_storage; }
125
+ set step(value) { this.#step_accessor_storage = value; }
126
+ #width_accessor_storage = (__runInitializers(this, _step_extraInitializers), __runInitializers(this, _width_initializers, void 0));
127
+ get width() { return this.#width_accessor_storage; }
128
+ set width(value) { this.#width_accessor_storage = value; }
129
+ #_theme_accessor_storage = (__runInitializers(this, _width_extraInitializers), __runInitializers(this, __theme_initializers, void 0));
130
+ // [LAW:types-are-the-program] @observableRef so setTheme() triggers a
131
+ // re-render — render() reads _theme.palette, so the theme reference must
132
+ // participate in MobX reactivity for Screen's autorun to fire on swap.
133
+ get _theme() { return this.#_theme_accessor_storage; }
134
+ set _theme(value) { this.#_theme_accessor_storage = value; }
135
+ _dragging = (__runInitializers(this, __theme_extraInitializers), false);
136
+ constructor(options = {}) {
137
+ super();
138
+ this.id = options.id ?? `slider-${Math.random().toString(36).slice(2, 8)}`;
139
+ this.min = options.min ?? 0;
140
+ this.max = options.max ?? 100;
141
+ this.step = options.step ?? 1;
142
+ // [LAW:types-are-the-program] `width` is a `number` in the option shape,
143
+ // but rendering and mouse math require a positive integer. This is a
144
+ // construction-time trust boundary — guard once so every downstream call
145
+ // (`trackChar.repeat(width)`, `width - 1` denominator) can assume validity.
146
+ const width = options.width ?? DEFAULT_WIDTH;
147
+ if (!Number.isInteger(width) || width < 1) {
148
+ throw new RangeError(`Slider width must be a positive integer; got ${width}`);
149
+ }
150
+ this.width = width;
151
+ this.value = clampSnap(options.value ?? this.min, this.min, this.max, this.step);
152
+ this.disabled = options.disabled ?? false;
153
+ this._theme = options.theme ?? DEFAULT_TERMINAL_THEME;
154
+ }
155
+ setTheme(theme) { this._theme = theme; }
156
+ // --- Event handlers ---
157
+ handleKey(event) {
158
+ if (this.disabled)
159
+ return;
160
+ switch (event.key) {
161
+ case "left":
162
+ this.setValue(this.value - this.step);
163
+ event.stop();
164
+ return;
165
+ case "right":
166
+ this.setValue(this.value + this.step);
167
+ event.stop();
168
+ return;
169
+ case "home":
170
+ this.setValue(this.min);
171
+ event.stop();
172
+ return;
173
+ case "end":
174
+ this.setValue(this.max);
175
+ event.stop();
176
+ return;
177
+ }
178
+ }
179
+ handleMouse(event) {
180
+ if (this.disabled)
181
+ return;
182
+ if (event.type === "mouse_down") {
183
+ this._dragging = true;
184
+ this.setValueFromMouseX(event.x);
185
+ return;
186
+ }
187
+ if (event.type === "mouse_move") {
188
+ if (this._dragging)
189
+ this.setValueFromMouseX(event.x);
190
+ return;
191
+ }
192
+ if (event.type === "mouse_up") {
193
+ const wasDragging = this._dragging;
194
+ this._dragging = false;
195
+ if (wasDragging) {
196
+ this.setValueFromMouseX(event.x);
197
+ this.emitSubmit();
198
+ }
199
+ return;
200
+ }
201
+ }
202
+ // --- Value mutation ---
203
+ setValue(next) {
204
+ const snapped = clampSnap(next, this.min, this.max, this.step);
205
+ if (snapped === this.value)
206
+ return;
207
+ this.value = snapped;
208
+ this.emitChange();
209
+ }
210
+ // `x` is a column of this slider's own track, and runs outside 0..width
211
+ // when a drag carries the pointer past either end.
212
+ setValueFromMouseX(x) {
213
+ const cellsAvailable = Math.max(1, this.width - 1);
214
+ const clamped = Math.max(0, Math.min(this.width - 1, x));
215
+ const fraction = clamped / cellsAvailable;
216
+ const next = this.min + fraction * (this.max - this.min);
217
+ this.setValue(next);
218
+ }
219
+ // --- Rendering ---
220
+ draw(options) {
221
+ const trackChar = drawable(options, "─", "-");
222
+ const markerChar = drawable(options, "●", "*");
223
+ const range = this.max - this.min;
224
+ const fraction = range === 0 ? 0 : (this.value - this.min) / range;
225
+ const markerIdx = Math.round(fraction * (this.width - 1));
226
+ const baseAttrs = { underline: this.focused };
227
+ const filledStyle = this.disabled
228
+ ? new Style({ color: "#666666", bgcolor: "#333333", dim: true, ...baseAttrs })
229
+ : new Style({ color: this.resolvePalette("primary"), ...baseAttrs });
230
+ const unfilledStyle = this.disabled
231
+ ? new Style({ color: "#666666", bgcolor: "#333333", dim: true, ...baseAttrs })
232
+ : new Style({ color: this.resolvePalette("surface"), ...baseAttrs });
233
+ const markerStyle = this.disabled
234
+ ? new Style({ color: "#666666", bgcolor: "#333333", dim: true, bold: true, ...baseAttrs })
235
+ : new Style({ color: this.resolvePalette("primary"), bold: true, ...baseAttrs });
236
+ const segments = [];
237
+ if (markerIdx > 0) {
238
+ segments.push(new Segment(trackChar.repeat(markerIdx), filledStyle));
239
+ }
240
+ segments.push(new Segment(markerChar, markerStyle));
241
+ const tail = this.width - markerIdx - 1;
242
+ if (tail > 0) {
243
+ segments.push(new Segment(trackChar.repeat(tail), unfilledStyle));
244
+ }
245
+ return segments;
246
+ }
247
+ measure(_options) {
248
+ return { minimum: this.width, maximum: this.width };
249
+ }
250
+ // --- Palette resolution ---
251
+ resolvePalette(key) {
252
+ const rgba = this._theme.palette.get(key);
253
+ // [LAW:no-defensive-null-guards] palette must contain all keys.
254
+ return ColorSpec.fromRgba(rgba);
255
+ }
256
+ };
257
+ })();
258
+ export { Slider };
259
+ // [LAW:single-enforcer] Single function clamps a numeric value into the
260
+ // [min, max] range and snaps to the nearest step boundary. All value
261
+ // mutations route through this; min/max/step never produce out-of-bounds
262
+ // observable state.
263
+ function clampSnap(value, min, max, step) {
264
+ const clamped = Math.max(min, Math.min(max, value));
265
+ if (step <= 0)
266
+ return clamped;
267
+ const snapped = min + Math.round((clamped - min) / step) * step;
268
+ // Floating-point cleanup: re-clamp in case rounding nudged past max.
269
+ return Math.max(min, Math.min(max, snapped));
270
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * StaticItem — a renderable on the widget surface: it takes no focus and
3
+ * ignores keys, and it stamps its cells like any widget.
4
+ *
5
+ * [LAW:one-type-per-behavior] Display-only content is a `WidgetBase` with
6
+ * `focusable: false` and the no-op handlers the base already provides, not a
7
+ * second type.
8
+ *
9
+ * The wrapped renderable can be a function that re-evaluates each frame — it
10
+ * reads MobX observables, and the app repaints when they change — or a plain
11
+ * renderable.
12
+ */
13
+ import { Segment } from "../core/segment.js";
14
+ import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
15
+ import { WidgetBase } from "./widget-base.js";
16
+ import type { KeyEvent } from "./types.js";
17
+ export interface StaticItemOptions {
18
+ id: string;
19
+ render: Renderable | ((options: RenderOptions) => Iterable<Segment>);
20
+ measure?: Measurable["measure"];
21
+ }
22
+ export declare class StaticItem extends WidgetBase {
23
+ readonly id: string;
24
+ readonly focusable = false;
25
+ private readonly renderFn;
26
+ private readonly measureFn;
27
+ constructor(options: StaticItemOptions);
28
+ handleKey(_event: KeyEvent): void;
29
+ protected draw(options: RenderOptions): Iterable<Segment>;
30
+ measure(options: RenderOptions): {
31
+ minimum: number;
32
+ maximum: number;
33
+ };
34
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * StaticItem — a renderable on the widget surface: it takes no focus and
3
+ * ignores keys, and it stamps its cells like any widget.
4
+ *
5
+ * [LAW:one-type-per-behavior] Display-only content is a `WidgetBase` with
6
+ * `focusable: false` and the no-op handlers the base already provides, not a
7
+ * second type.
8
+ *
9
+ * The wrapped renderable can be a function that re-evaluates each frame — it
10
+ * reads MobX observables, and the app repaints when they change — or a plain
11
+ * renderable.
12
+ */
13
+ import { Segment } from "../core/segment.js";
14
+ import { WidgetBase } from "./widget-base.js";
15
+ export class StaticItem extends WidgetBase {
16
+ id;
17
+ focusable = false;
18
+ renderFn;
19
+ measureFn;
20
+ constructor(options) {
21
+ super();
22
+ this.id = options.id;
23
+ const r = options.render;
24
+ this.renderFn =
25
+ typeof r === "function"
26
+ ? (opts) => r(opts)
27
+ : (opts) => r.render(opts);
28
+ this.measureFn = options.measure;
29
+ }
30
+ // Static items don't respond to keys. WidgetBase.handleMouse / handleFocus
31
+ // are already no-ops, so we only need to satisfy the abstract handleKey.
32
+ handleKey(_event) { }
33
+ draw(options) {
34
+ return this.renderFn(options);
35
+ }
36
+ measure(options) {
37
+ if (this.measureFn)
38
+ return this.measureFn(options);
39
+ // [LAW:one-source-of-truth] Segment.splitLines is the line-break
40
+ // authority — it handles newlines embedded inside longer segment.text
41
+ // values too, not just the "\n" sentinel segment. Walking segments and
42
+ // testing `seg.text === "\n"` miscounts widths for any renderable
43
+ // that emits "a\nb" as a single segment.
44
+ const segments = Array.from(this.renderFn(options));
45
+ const lines = Segment.splitLines(segments);
46
+ let max = 0;
47
+ for (const line of lines) {
48
+ const w = Segment.getLineLength(line);
49
+ if (w > max)
50
+ max = w;
51
+ }
52
+ return { minimum: max, maximum: max };
53
+ }
54
+ }
@@ -0,0 +1,274 @@
1
+ /**
2
+ * TextInput widget — editable text field with cursor.
3
+ *
4
+ * Two modes:
5
+ * - single-line (default): Enter submits; newlines in value are rendered
6
+ * as a literal `↵` glyph if they ever appear.
7
+ * - multi-line (`multiline: true`): Enter inserts a `\n`; `value` may
8
+ * contain logical line breaks; Up/Down navigate
9
+ * between logical lines preserving column intent.
10
+ *
11
+ * [LAW:dataflow-not-control-flow] cursor and value are observable data; the
12
+ * keymap dispatches to small `@action` mutators that all flow through the
13
+ * same value/cursor update path. There is no per-key bespoke branch in the
14
+ * render loop or the change-emit path.
15
+ *
16
+ * [LAW:one-source-of-truth] The cursor's logical line — and therefore "what
17
+ * Home/End/Up/Down mean" — is derived from `value` and `cursorPosition` via
18
+ * `_lineStart()` / `_lineEnd()`. Multi-line behavior is the same code path
19
+ * as single-line; with no `\n` in `value`, line bounds collapse to value
20
+ * bounds, so single-line semantics are recovered without a special case.
21
+ *
22
+ * [LAW:types-are-the-program] Three integer spaces coexist: `CellCol` (terminal
23
+ * cell columns), `CodeUnit` (JS UTF-16 indices), and `CodePoint` (code-unit
24
+ * offsets that are additionally on a Unicode code-point boundary — a subtype of
25
+ * `CodeUnit`). `cursorPosition` is `CodePoint`; it is never inside a surrogate
26
+ * pair by construction. Visual positions are `CellCol`. The three are never
27
+ * interchangeable — the type system enforces this at every crossing point.
28
+ *
29
+ * Keymap (readline / emacs compatible):
30
+ *
31
+ * ─── motion ───
32
+ * left | Ctrl+B char left
33
+ * right | Ctrl+F char right
34
+ * up | Ctrl+P line up (preserves preferred column)
35
+ * down | Ctrl+N line down (preserves preferred column)
36
+ * home | Ctrl+A line start
37
+ * end | Ctrl+E line end
38
+ * Ctrl+Home document start
39
+ * Ctrl+End document end
40
+ * Ctrl+Left | Alt+Left | Alt+B word left
41
+ * Ctrl+Right | Alt+Right | Alt+F word right
42
+ *
43
+ * ─── editing ───
44
+ * backspace | Ctrl+H delete char back
45
+ * delete | Ctrl+D delete char forward
46
+ * Ctrl+W | Alt+Backspace delete word back (whitespace-bounded; readline parity)
47
+ * Alt+D delete word forward
48
+ * Ctrl+U kill to line start (stores in kill buffer)
49
+ * Ctrl+K kill to line end (stores in kill buffer)
50
+ * Ctrl+Y yank kill buffer at cursor
51
+ * Ctrl+T transpose chars (swap pre-cursor/at-cursor, advance)
52
+ * enter submit (single-line) or insert `\n` (multiline)
53
+ *
54
+ * Motion and editing primitives are also exposed as public methods
55
+ * (`moveCharLeft`, `killLineForward`, etc.) so a host can bind custom keys
56
+ * or invoke them programmatically.
57
+ */
58
+ import { Segment } from "../core/segment.js";
59
+ import { Style } from "../core/style.js";
60
+ import { type CellCol, type CodePoint } from "../core/cells.js";
61
+ import { type RenderOptions } from "../core/protocol.js";
62
+ import type { TerminalTheme } from "../core/color.js";
63
+ import { WidgetBase } from "./widget-base.js";
64
+ import type { KeyEvent, WidgetMouseEvent } from "./types.js";
65
+ /**
66
+ * A soft-wrap strategy. Given one logical line of text and cell-width budgets,
67
+ * return the visual sub-rows that line wraps into. The first sub-row uses
68
+ * `firstWidth` as its capacity; every subsequent (continuation) sub-row uses
69
+ * `continuationWidth` (typically `firstWidth - cellLen(continuationMarker)`).
70
+ *
71
+ * Each returned row carries:
72
+ * - `content` — the displayed text for that visual row (the widget prepends
73
+ * the continuation marker itself; the strategy never includes it).
74
+ * - `start` — code-unit offset into the *logical line* where `content`
75
+ * begins, so the widget can map visual positions back to absolute `value`
76
+ * offsets for cursor projection.
77
+ *
78
+ * [LAW:types-are-the-program] Budget params are `CellCol`; `start` is
79
+ * `CodePoint` (a `CodeUnit` on a code-point boundary) — the type system
80
+ * prevents mixing these integer spaces inside a custom strategy.
81
+ *
82
+ * Built-in: `charGreedyWrap` (break at any character at the width limit).
83
+ * Custom: any function matching this signature. Template-aware wrapping
84
+ * (break at `{{ }}` atoms, e.g.) is provided by consumers that know the
85
+ * value's domain syntax — the widget stays domain-neutral.
86
+ */
87
+ export type WrapStrategy = (logicalLine: string, budget: {
88
+ firstWidth: CellCol;
89
+ continuationWidth: CellCol;
90
+ }) => readonly WrapRow[];
91
+ export interface WrapRow {
92
+ readonly content: string;
93
+ /** Code-point offset into the logical line where `content` begins. */
94
+ readonly start: CodePoint;
95
+ }
96
+ /**
97
+ * Character-greedy soft wrap. Breaks at any character once `firstWidth`
98
+ * (or `continuationWidth` for continuation rows) cells are exhausted. The
99
+ * textarea default when a consumer says "wrap, I don't care how" — no syntax
100
+ * awareness, just fits the line to the width.
101
+ *
102
+ * Wide characters (CJK, emoji) are treated as atomic: a char that would
103
+ * straddle the budget is moved to the next row rather than split, and one too
104
+ * wide for the whole budget is force-taken — see `cellStepFrom`.
105
+ */
106
+ export declare const charGreedyWrap: WrapStrategy;
107
+ export interface TextInputOptions {
108
+ value?: string;
109
+ placeholder?: string;
110
+ id?: string;
111
+ disabled?: boolean;
112
+ theme?: TerminalTheme;
113
+ maxLength?: number;
114
+ password?: boolean;
115
+ /**
116
+ * When true, Enter inserts a `\n` into `value` instead of emitting submit,
117
+ * and Up/Down arrows + Ctrl+P/N navigate between visual rows.
118
+ * Single-line mode (the default) leaves Enter as submit and Up/Down as
119
+ * no-ops, which matches the conventional one-line-input widget shape.
120
+ */
121
+ multiline?: boolean;
122
+ /**
123
+ * Soft-wrap strategy. When set (multiline mode only), each logical line
124
+ * is wrapped to fit available width using this strategy; the widget
125
+ * renders one visual row per wrap row and Up/Down move across *visual*
126
+ * rows, not logical ones. When unset, multiline rendering emits each
127
+ * logical line as one (potentially overflowing) visual row.
128
+ *
129
+ * Pass `charGreedyWrap` for the conventional textarea wrap, or supply
130
+ * a custom strategy that understands the value's domain syntax (e.g. a
131
+ * tokenizer that breaks at expression boundaries instead of mid-token).
132
+ */
133
+ wrap?: WrapStrategy;
134
+ /**
135
+ * Continuation marker rendered at the start of each non-first visual row
136
+ * when a logical line wraps. Defaults to `"↳ "` (2 cells wide). The
137
+ * widget subtracts this marker's display width from the strategy's
138
+ * `continuationWidth` budget so wrapped content fits the available area.
139
+ */
140
+ continuationMarker?: string;
141
+ /**
142
+ * Maximum visible visual rows. When set and the wrapped value exceeds
143
+ * this many rows, the widget scrolls the visible window to keep the
144
+ * cursor row in view. Unset → render every row (let the host bound the
145
+ * pane).
146
+ */
147
+ maxRows?: number;
148
+ /**
149
+ * Minimum visible visual rows. When set and the wrapped value has fewer
150
+ * rows than this, the widget pads with empty rows so the rendered area
151
+ * occupies at least `minRows` lines (useful for stable layouts).
152
+ */
153
+ minRows?: number;
154
+ /**
155
+ * Scroll-state indicator style.
156
+ *
157
+ * - `"arrows"` (default): the widget renders ▲/▼ inside its own content
158
+ * area on the first/last visible row when scroll is possible in that
159
+ * direction. Fully self-contained — host needs no wiring.
160
+ * - `"indices"`: the widget suppresses in-content arrows and instead
161
+ * publishes `scrollIndicatorText` (e.g. `"[14/102]"`) for the host
162
+ * (typically a `Panel`'s `bottomRightAccessory`) to display in the
163
+ * border. Useful when the surrounding chrome should carry the
164
+ * indicator so widget content area stays untouched.
165
+ * - `"none"`: no indicator at all.
166
+ */
167
+ scrollIndicator?: "arrows" | "indices" | "none";
168
+ /**
169
+ * Style override for the in-content scroll arrows (▲/▼). Defaults to the
170
+ * widget's `primary` palette color. Has no effect outside `"arrows"` mode.
171
+ */
172
+ indicatorStyle?: Style;
173
+ /**
174
+ * Style override for the cursor cell. Defaults to
175
+ * `bgcolor: primary, color: on-primary` (the WCAG-correct combination
176
+ * derived from the active theme).
177
+ */
178
+ cursorStyle?: Style;
179
+ /**
180
+ * Style override for the rendered content text. Defaults to the
181
+ * theme's `foreground` palette color.
182
+ */
183
+ contentStyle?: Style;
184
+ }
185
+ export declare class TextInput extends WidgetBase {
186
+ readonly id: string;
187
+ readonly focusable = true;
188
+ accessor value: string;
189
+ accessor cursorPosition: CodePoint;
190
+ accessor placeholder: string;
191
+ private _theme;
192
+ private readonly _maxLength;
193
+ private readonly _password;
194
+ private readonly _multiline;
195
+ private readonly _wrap;
196
+ private readonly _continuationMarker;
197
+ private readonly _markerWidth;
198
+ private readonly _maxRows;
199
+ private readonly _minRows;
200
+ private readonly _scrollIndicator;
201
+ accessor indicatorStyleOverride: Style | undefined;
202
+ accessor cursorStyleOverride: Style | undefined;
203
+ accessor contentStyleOverride: Style | undefined;
204
+ /**
205
+ * Last computed visual-row decomposition. Cached at the end of `render()`
206
+ * so vertical motion (Up/Down) can step row-by-row without re-running the
207
+ * wrap strategy. Null before the first render — vertical motion falls
208
+ * back to logical-line motion in that case.
209
+ *
210
+ * [LAW:dataflow-not-control-flow] One source of truth for "what does Up
211
+ * mean right now": the row table the renderer just produced. No parallel
212
+ * "where would the cursor go" math; both the renderer and the keymap
213
+ * read from the same array.
214
+ */
215
+ private _visualRows;
216
+ private _preferredColumn;
217
+ private _killBuffer;
218
+ private _scrollStart;
219
+ private _singleLineViewportStart;
220
+ readonly multiline: boolean;
221
+ constructor(options?: TextInputOptions);
222
+ setTheme(theme: TerminalTheme): void;
223
+ handleKey(event: KeyEvent): void;
224
+ handleMouse(event: WidgetMouseEvent): void;
225
+ setHovered(value: boolean): void;
226
+ moveCharLeft(): void;
227
+ moveCharRight(): void;
228
+ moveLineUp(): void;
229
+ moveLineDown(): void;
230
+ private _clampColForRow;
231
+ private _cursorVisualRow;
232
+ private _cursorVisualCol;
233
+ moveLineStart(): void;
234
+ moveLineEnd(): void;
235
+ moveDocStart(): void;
236
+ moveDocEnd(): void;
237
+ moveWordLeft(): void;
238
+ moveWordRight(): void;
239
+ deleteCharBack(): void;
240
+ deleteCharForward(): void;
241
+ deleteWordBack(): void;
242
+ deleteWordForward(): void;
243
+ killLineBack(): void;
244
+ killLineForward(): void;
245
+ yank(): void;
246
+ transposeChars(): void;
247
+ private _lineStart;
248
+ private _lineEnd;
249
+ private _insertText;
250
+ protected draw(options: RenderOptions): Iterable<Segment>;
251
+ private _renderSingleLine;
252
+ private _renderMultiline;
253
+ private _emitRowContent;
254
+ private _computeVisualRows;
255
+ measure(_options: RenderOptions): {
256
+ minimum: number;
257
+ maximum: number;
258
+ };
259
+ /**
260
+ * `[X/Y]` scroll-position string when there's actually something to
261
+ * scroll, else `undefined`. X is the cursor's 1-indexed visual row; Y is
262
+ * the total visual row count. Reads cached state populated by the most
263
+ * recent `render()` — call from a `Panel.bottomRightAccessory` thunk so
264
+ * it evaluates after content has been rendered for the current frame.
265
+ *
266
+ * Returns `undefined` when:
267
+ * - `scrollIndicator` is not `"indices"`, or
268
+ * - `maxRows` is unset, or total visual rows ≤ maxRows (nothing to
269
+ * scroll), or
270
+ * - no render has happened yet (cache is empty).
271
+ */
272
+ get scrollIndicatorText(): string | undefined;
273
+ private resolvePalette;
274
+ }