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