@promptctl/rich-js 0.1.0 → 0.3.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 (158) hide show
  1. package/README.md +29 -15
  2. package/dist/core/cells.d.ts +83 -3
  3. package/dist/core/cells.d.ts.map +1 -1
  4. package/dist/core/cells.js +113 -1
  5. package/dist/core/cells.js.map +1 -1
  6. package/dist/core/console.d.ts +0 -1
  7. package/dist/core/console.d.ts.map +1 -1
  8. package/dist/core/console.js +20 -16
  9. package/dist/core/console.js.map +1 -1
  10. package/dist/core/highlighter.d.ts.map +1 -1
  11. package/dist/core/highlighter.js.map +1 -1
  12. package/dist/core/oklch.d.ts +106 -0
  13. package/dist/core/oklch.d.ts.map +1 -0
  14. package/dist/core/oklch.js +221 -0
  15. package/dist/core/oklch.js.map +1 -0
  16. package/dist/core/render.d.ts +26 -7
  17. package/dist/core/render.d.ts.map +1 -1
  18. package/dist/core/render.js +83 -15
  19. package/dist/core/render.js.map +1 -1
  20. package/dist/core/segment.d.ts +14 -1
  21. package/dist/core/segment.d.ts.map +1 -1
  22. package/dist/core/segment.js +28 -3
  23. package/dist/core/segment.js.map +1 -1
  24. package/dist/core/style.d.ts +11 -2
  25. package/dist/core/style.d.ts.map +1 -1
  26. package/dist/core/style.js +31 -18
  27. package/dist/core/style.js.map +1 -1
  28. package/dist/core/text.d.ts +20 -0
  29. package/dist/core/text.d.ts.map +1 -1
  30. package/dist/core/text.js +31 -0
  31. package/dist/core/text.js.map +1 -1
  32. package/dist/index.d.ts +11 -4
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +12 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/renderables/columns.d.ts.map +1 -1
  37. package/dist/renderables/columns.js +15 -22
  38. package/dist/renderables/columns.js.map +1 -1
  39. package/dist/renderables/layout.d.ts.map +1 -1
  40. package/dist/renderables/layout.js +8 -29
  41. package/dist/renderables/layout.js.map +1 -1
  42. package/dist/renderables/live.d.ts.map +1 -1
  43. package/dist/renderables/live.js +8 -7
  44. package/dist/renderables/live.js.map +1 -1
  45. package/dist/renderables/panel.d.ts +34 -0
  46. package/dist/renderables/panel.d.ts.map +1 -1
  47. package/dist/renderables/panel.js +66 -23
  48. package/dist/renderables/panel.js.map +1 -1
  49. package/dist/template-bindings/helpers.d.ts +25 -0
  50. package/dist/template-bindings/helpers.d.ts.map +1 -0
  51. package/dist/template-bindings/helpers.js +31 -0
  52. package/dist/template-bindings/helpers.js.map +1 -0
  53. package/dist/template-bindings/index.d.ts +57 -18
  54. package/dist/template-bindings/index.d.ts.map +1 -1
  55. package/dist/template-bindings/index.js +83 -18
  56. package/dist/template-bindings/index.js.map +1 -1
  57. package/dist/template-bindings/palette-funcs.d.ts +76 -0
  58. package/dist/template-bindings/palette-funcs.d.ts.map +1 -0
  59. package/dist/template-bindings/palette-funcs.js +157 -0
  60. package/dist/template-bindings/palette-funcs.js.map +1 -0
  61. package/dist/template-bindings/style-funcs.d.ts.map +1 -1
  62. package/dist/template-bindings/style-funcs.js +33 -27
  63. package/dist/template-bindings/style-funcs.js.map +1 -1
  64. package/dist/themes/colorMath.d.ts +40 -0
  65. package/dist/themes/colorMath.d.ts.map +1 -1
  66. package/dist/themes/colorMath.js +82 -1
  67. package/dist/themes/colorMath.js.map +1 -1
  68. package/dist/themes/data/catppuccin-frappe.d.ts +4 -0
  69. package/dist/themes/data/catppuccin-frappe.d.ts.map +1 -0
  70. package/dist/themes/data/catppuccin-frappe.js +159 -0
  71. package/dist/themes/data/catppuccin-frappe.js.map +1 -0
  72. package/dist/themes/data/catppuccin-macchiato.d.ts +4 -0
  73. package/dist/themes/data/catppuccin-macchiato.d.ts.map +1 -0
  74. package/dist/themes/data/catppuccin-macchiato.js +159 -0
  75. package/dist/themes/data/catppuccin-macchiato.js.map +1 -0
  76. package/dist/themes/data/cyberpunk.d.ts +18 -0
  77. package/dist/themes/data/cyberpunk.d.ts.map +1 -0
  78. package/dist/themes/data/cyberpunk.js +192 -0
  79. package/dist/themes/data/cyberpunk.js.map +1 -0
  80. package/dist/themes/data/default.d.ts +4 -0
  81. package/dist/themes/data/default.d.ts.map +1 -0
  82. package/dist/themes/data/default.js +159 -0
  83. package/dist/themes/data/default.js.map +1 -0
  84. package/dist/themes/data/index.d.ts +10 -3
  85. package/dist/themes/data/index.d.ts.map +1 -1
  86. package/dist/themes/data/index.js +24 -7
  87. package/dist/themes/data/index.js.map +1 -1
  88. package/dist/themes/data/svg-export.d.ts +4 -0
  89. package/dist/themes/data/svg-export.d.ts.map +1 -0
  90. package/dist/themes/data/svg-export.js +159 -0
  91. package/dist/themes/data/svg-export.js.map +1 -0
  92. package/dist/themes/data/types.d.ts +4 -3
  93. package/dist/themes/data/types.d.ts.map +1 -1
  94. package/dist/themes/registry.d.ts +29 -2
  95. package/dist/themes/registry.d.ts.map +1 -1
  96. package/dist/themes/registry.js +62 -12
  97. package/dist/themes/registry.js.map +1 -1
  98. package/dist/themes/terminalThemes.d.ts +29 -20
  99. package/dist/themes/terminalThemes.d.ts.map +1 -1
  100. package/dist/themes/terminalThemes.js +50 -249
  101. package/dist/themes/terminalThemes.js.map +1 -1
  102. package/dist/themes/transpose.d.ts +88 -0
  103. package/dist/themes/transpose.d.ts.map +1 -0
  104. package/dist/themes/transpose.js +139 -0
  105. package/dist/themes/transpose.js.map +1 -0
  106. package/dist/widgets/button.d.ts +8 -5
  107. package/dist/widgets/button.d.ts.map +1 -1
  108. package/dist/widgets/button.js +36 -11
  109. package/dist/widgets/button.js.map +1 -1
  110. package/dist/widgets/checkbox.d.ts +1 -2
  111. package/dist/widgets/checkbox.d.ts.map +1 -1
  112. package/dist/widgets/checkbox.js +20 -7
  113. package/dist/widgets/checkbox.js.map +1 -1
  114. package/dist/widgets/dropdown.d.ts +4 -3
  115. package/dist/widgets/dropdown.d.ts.map +1 -1
  116. package/dist/widgets/dropdown.js +109 -27
  117. package/dist/widgets/dropdown.js.map +1 -1
  118. package/dist/widgets/event-router.d.ts +6 -3
  119. package/dist/widgets/event-router.d.ts.map +1 -1
  120. package/dist/widgets/event-router.js +179 -68
  121. package/dist/widgets/event-router.js.map +1 -1
  122. package/dist/widgets/focus-manager.d.ts +2 -1
  123. package/dist/widgets/focus-manager.d.ts.map +1 -1
  124. package/dist/widgets/focus-manager.js +28 -9
  125. package/dist/widgets/focus-manager.js.map +1 -1
  126. package/dist/widgets/index.d.ts +2 -2
  127. package/dist/widgets/index.d.ts.map +1 -1
  128. package/dist/widgets/index.js +1 -1
  129. package/dist/widgets/index.js.map +1 -1
  130. package/dist/widgets/screen.d.ts +2 -0
  131. package/dist/widgets/screen.d.ts.map +1 -1
  132. package/dist/widgets/screen.js +148 -45
  133. package/dist/widgets/screen.js.map +1 -1
  134. package/dist/widgets/slider.d.ts +6 -3
  135. package/dist/widgets/slider.d.ts.map +1 -1
  136. package/dist/widgets/slider.js +34 -10
  137. package/dist/widgets/slider.js.map +1 -1
  138. package/dist/widgets/static-item.d.ts +1 -1
  139. package/dist/widgets/static-item.d.ts.map +1 -1
  140. package/dist/widgets/static-item.js +12 -13
  141. package/dist/widgets/static-item.js.map +1 -1
  142. package/dist/widgets/text-input.d.ts +239 -13
  143. package/dist/widgets/text-input.d.ts.map +1 -1
  144. package/dist/widgets/text-input.js +1004 -74
  145. package/dist/widgets/text-input.js.map +1 -1
  146. package/dist/widgets/toggle.d.ts +1 -2
  147. package/dist/widgets/toggle.d.ts.map +1 -1
  148. package/dist/widgets/toggle.js +20 -8
  149. package/dist/widgets/toggle.js.map +1 -1
  150. package/dist/widgets/types.d.ts +21 -4
  151. package/dist/widgets/types.d.ts.map +1 -1
  152. package/dist/widgets/types.js +19 -0
  153. package/dist/widgets/types.js.map +1 -1
  154. package/dist/widgets/widget-base.d.ts +1 -0
  155. package/dist/widgets/widget-base.d.ts.map +1 -1
  156. package/dist/widgets/widget-base.js +24 -7
  157. package/dist/widgets/widget-base.js.map +1 -1
  158. package/package.json +5 -3
@@ -16,7 +16,7 @@
16
16
  * re-render reactively) or a plain object that returns the same segments
17
17
  * every time.
18
18
  */
19
- import type { Segment } from "../core/segment.js";
19
+ import { Segment } from "../core/segment.js";
20
20
  import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
21
21
  import { WidgetBase } from "./widget-base.js";
22
22
  import type { KeyEvent } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"static-item.d.ts","sourceRoot":"","sources":["../../src/widgets/static-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IAIX,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAIrE,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;CACjC;AAED,qBAAa,UAAW,SAAQ,UAAU;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,SAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgD;IACzE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;gBAElD,OAAO,EAAE,iBAAiB;IAatC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAEjC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;IAIjD,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAgBtE"}
1
+ {"version":3,"file":"static-item.d.ts","sourceRoot":"","sources":["../../src/widgets/static-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IAIX,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAIrE,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;CACjC;AAED,qBAAa,UAAW,SAAQ,UAAU;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,SAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgD;IACzE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;gBAElD,OAAO,EAAE,iBAAiB;IAatC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAEjC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;IAIjD,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAgBtE"}
@@ -16,6 +16,7 @@
16
16
  * re-render reactively) or a plain object that returns the same segments
17
17
  * every time.
18
18
  */
19
+ import { Segment } from "../core/segment.js";
19
20
  import { WidgetBase } from "./widget-base.js";
20
21
  export class StaticItem extends WidgetBase {
21
22
  id;
@@ -41,21 +42,19 @@ export class StaticItem extends WidgetBase {
41
42
  measure(options) {
42
43
  if (this.measureFn)
43
44
  return this.measureFn(options);
44
- // Render once and use the resulting line width as both min and max.
45
+ // [LAW:one-source-of-truth] Segment.splitLines is the line-break
46
+ // authority — it handles newlines embedded inside longer segment.text
47
+ // values too, not just the "\n" sentinel segment. Walking segments and
48
+ // testing `seg.text === "\n"` miscounts widths for any renderable
49
+ // that emits "a\nb" as a single segment.
50
+ const segments = Array.from(this.renderFn(options));
51
+ const lines = Segment.splitLines(segments);
45
52
  let max = 0;
46
- let cur = 0;
47
- for (const seg of this.renderFn(options)) {
48
- if (seg.text === "\n") {
49
- if (cur > max)
50
- max = cur;
51
- cur = 0;
52
- }
53
- else {
54
- cur += seg.cellLength;
55
- }
53
+ for (const line of lines) {
54
+ const w = Segment.getLineLength(line);
55
+ if (w > max)
56
+ max = w;
56
57
  }
57
- if (cur > max)
58
- max = cur;
59
58
  return { minimum: max, maximum: max };
60
59
  }
61
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"static-item.js","sourceRoot":"","sources":["../../src/widgets/static-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAe9C,MAAM,OAAO,UAAW,SAAQ,UAAU;IAC/B,EAAE,CAAS;IACX,SAAS,GAAG,KAAK,CAAC;IAEV,QAAQ,CAAgD;IACxD,SAAS,CAAoC;IAE9D,YAAY,OAA0B;QACpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,QAAQ;YACX,OAAO,CAAC,KAAK,UAAU;gBACrB,CAAC,CAAC,CAAC,IAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAClC,CAAC,CAAC,CAAC,IAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IACnC,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,SAAS,CAAC,MAAgB,IAAS,CAAC;IAEpC,MAAM,CAAC,OAAsB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,OAAsB;QAC5B,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnD,oEAAoE;QACpE,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBACtB,IAAI,GAAG,GAAG,GAAG;oBAAE,GAAG,GAAG,GAAG,CAAC;gBACzB,GAAG,GAAG,CAAC,CAAC;YACV,CAAC;iBAAM,CAAC;gBACN,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,GAAG,GAAG,GAAG;YAAE,GAAG,GAAG,GAAG,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IACxC,CAAC;CACF"}
1
+ {"version":3,"file":"static-item.js","sourceRoot":"","sources":["../../src/widgets/static-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAe9C,MAAM,OAAO,UAAW,SAAQ,UAAU;IAC/B,EAAE,CAAS;IACX,SAAS,GAAG,KAAK,CAAC;IAEV,QAAQ,CAAgD;IACxD,SAAS,CAAoC;IAE9D,YAAY,OAA0B;QACpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,QAAQ;YACX,OAAO,CAAC,KAAK,UAAU;gBACrB,CAAC,CAAC,CAAC,IAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAClC,CAAC,CAAC,CAAC,IAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IACnC,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,SAAS,CAAC,MAAgB,IAAS,CAAC;IAEpC,MAAM,CAAC,OAAsB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,OAAsB;QAC5B,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnD,iEAAiE;QACjE,sEAAsE;QACtE,uEAAuE;QACvE,kEAAkE;QAClE,yCAAyC;QACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,GAAG;gBAAE,GAAG,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IACxC,CAAC;CACF"}
@@ -1,22 +1,110 @@
1
1
  /**
2
- * TextInput widget — single-line editable text field with cursor.
3
- * [LAW:dataflow-not-control-flow] cursor is a data position; when focused,
4
- * exactly one cell is rendered with reverse-video styling on every frame.
5
- * [LAW:one-type-per-behavior] shared infrastructure inherited from WidgetBase.
6
- *
7
- * Visual states:
8
- * normal — "[value______]" with brackets bracketing fixed-width content
9
- * focused — same width with cursor cell (reverse video) at cursorPosition
10
- * placeholder — focused + empty value: dimmed placeholder text shown,
11
- * cursor at position 0
12
- * password — every value char rendered as "•"
13
- * disabled — entire segment dimmed
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.
14
57
  */
15
58
  import { Segment } from "../core/segment.js";
59
+ import { Style } from "../core/style.js";
60
+ import { type CellCol, type CodePoint } from "../core/cells.js";
16
61
  import type { RenderOptions } from "../core/protocol.js";
17
62
  import type { TerminalTheme } from "../core/color.js";
18
63
  import { WidgetBase } from "./widget-base.js";
19
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. When the
104
+ * budget is too narrow to fit even one character, that character is
105
+ * force-taken to guarantee progress (avoids an infinite loop).
106
+ */
107
+ export declare const charGreedyWrap: WrapStrategy;
20
108
  export interface TextInputOptions {
21
109
  value?: string;
22
110
  placeholder?: string;
@@ -25,26 +113,164 @@ export interface TextInputOptions {
25
113
  theme?: TerminalTheme;
26
114
  maxLength?: number;
27
115
  password?: boolean;
116
+ /**
117
+ * When true, Enter inserts a `\n` into `value` instead of emitting submit,
118
+ * and Up/Down arrows + Ctrl+P/N navigate between visual rows.
119
+ * Single-line mode (the default) leaves Enter as submit and Up/Down as
120
+ * no-ops, which matches the conventional one-line-input widget shape.
121
+ */
122
+ multiline?: boolean;
123
+ /**
124
+ * Soft-wrap strategy. When set (multiline mode only), each logical line
125
+ * is wrapped to fit available width using this strategy; the widget
126
+ * renders one visual row per wrap row and Up/Down move across *visual*
127
+ * rows, not logical ones. When unset, multiline rendering emits each
128
+ * logical line as one (potentially overflowing) visual row.
129
+ *
130
+ * Pass `charGreedyWrap` for the conventional textarea wrap, or supply
131
+ * a custom strategy that understands the value's domain syntax (e.g. a
132
+ * tokenizer that breaks at expression boundaries instead of mid-token).
133
+ */
134
+ wrap?: WrapStrategy;
135
+ /**
136
+ * Continuation marker rendered at the start of each non-first visual row
137
+ * when a logical line wraps. Defaults to `"↳ "` (2 cells wide). The
138
+ * widget subtracts this marker's display width from the strategy's
139
+ * `continuationWidth` budget so wrapped content fits the available area.
140
+ */
141
+ continuationMarker?: string;
142
+ /**
143
+ * Maximum visible visual rows. When set and the wrapped value exceeds
144
+ * this many rows, the widget scrolls the visible window to keep the
145
+ * cursor row in view. Unset → render every row (let the host bound the
146
+ * pane).
147
+ */
148
+ maxRows?: number;
149
+ /**
150
+ * Minimum visible visual rows. When set and the wrapped value has fewer
151
+ * rows than this, the widget pads with empty rows so the rendered area
152
+ * occupies at least `minRows` lines (useful for stable layouts).
153
+ */
154
+ minRows?: number;
155
+ /**
156
+ * Scroll-state indicator style.
157
+ *
158
+ * - `"arrows"` (default): the widget renders ▲/▼ inside its own content
159
+ * area on the first/last visible row when scroll is possible in that
160
+ * direction. Fully self-contained — host needs no wiring.
161
+ * - `"indices"`: the widget suppresses in-content arrows and instead
162
+ * publishes `scrollIndicatorText` (e.g. `"[14/102]"`) for the host
163
+ * (typically a `Panel`'s `bottomRightAccessory`) to display in the
164
+ * border. Useful when the surrounding chrome should carry the
165
+ * indicator so widget content area stays untouched.
166
+ * - `"none"`: no indicator at all.
167
+ */
168
+ scrollIndicator?: "arrows" | "indices" | "none";
169
+ /**
170
+ * Style override for the in-content scroll arrows (▲/▼). Defaults to the
171
+ * widget's `primary` palette color. Has no effect outside `"arrows"` mode.
172
+ */
173
+ indicatorStyle?: Style;
174
+ /**
175
+ * Style override for the cursor cell. Defaults to
176
+ * `bgcolor: primary, color: on-primary` (the WCAG-correct combination
177
+ * derived from the active theme).
178
+ */
179
+ cursorStyle?: Style;
180
+ /**
181
+ * Style override for the rendered content text. Defaults to the
182
+ * theme's `foreground` palette color.
183
+ */
184
+ contentStyle?: Style;
28
185
  }
29
186
  export declare class TextInput extends WidgetBase {
30
187
  readonly id: string;
31
188
  readonly focusable = true;
32
189
  accessor value: string;
33
- accessor cursorPosition: number;
190
+ accessor cursorPosition: CodePoint;
34
191
  accessor placeholder: string;
35
192
  private _theme;
36
193
  private readonly _maxLength;
37
194
  private readonly _password;
195
+ private readonly _multiline;
196
+ private readonly _wrap;
197
+ private readonly _continuationMarker;
198
+ private readonly _markerWidth;
199
+ private readonly _maxRows;
200
+ private readonly _minRows;
201
+ private readonly _scrollIndicator;
202
+ accessor indicatorStyleOverride: Style | undefined;
203
+ accessor cursorStyleOverride: Style | undefined;
204
+ accessor contentStyleOverride: Style | undefined;
205
+ /**
206
+ * Last computed visual-row decomposition. Cached at the end of `render()`
207
+ * so vertical motion (Up/Down) can step row-by-row without re-running the
208
+ * wrap strategy. Null before the first render — vertical motion falls
209
+ * back to logical-line motion in that case.
210
+ *
211
+ * [LAW:dataflow-not-control-flow] One source of truth for "what does Up
212
+ * mean right now": the row table the renderer just produced. No parallel
213
+ * "where would the cursor go" math; both the renderer and the keymap
214
+ * read from the same array.
215
+ */
216
+ private _visualRows;
217
+ private _preferredColumn;
218
+ private _killBuffer;
219
+ private _scrollStart;
220
+ private _singleLineViewportStart;
221
+ readonly multiline: boolean;
38
222
  constructor(options?: TextInputOptions);
39
223
  setTheme(theme: TerminalTheme): void;
40
224
  handleKey(event: KeyEvent): void;
41
225
  handleMouse(event: WidgetMouseEvent): void;
42
226
  setHovered(value: boolean): void;
227
+ moveCharLeft(): void;
228
+ moveCharRight(): void;
229
+ moveLineUp(): void;
230
+ moveLineDown(): void;
231
+ private _clampColForRow;
232
+ private _cursorVisualRow;
233
+ private _cursorVisualCol;
234
+ moveLineStart(): void;
235
+ moveLineEnd(): void;
236
+ moveDocStart(): void;
237
+ moveDocEnd(): void;
238
+ moveWordLeft(): void;
239
+ moveWordRight(): void;
240
+ deleteCharBack(): void;
241
+ deleteCharForward(): void;
242
+ deleteWordBack(): void;
243
+ deleteWordForward(): void;
244
+ killLineBack(): void;
245
+ killLineForward(): void;
246
+ yank(): void;
247
+ transposeChars(): void;
248
+ private _lineStart;
249
+ private _lineEnd;
250
+ private _insertText;
43
251
  render(options: RenderOptions): Iterable<Segment>;
252
+ private _renderSingleLine;
253
+ private _renderMultiline;
254
+ private _emitRowContent;
255
+ private _computeVisualRows;
44
256
  measure(_options: RenderOptions): {
45
257
  minimum: number;
46
258
  maximum: number;
47
259
  };
260
+ /**
261
+ * `[X/Y]` scroll-position string when there's actually something to
262
+ * scroll, else `undefined`. X is the cursor's 1-indexed visual row; Y is
263
+ * the total visual row count. Reads cached state populated by the most
264
+ * recent `render()` — call from a `Panel.bottomRightAccessory` thunk so
265
+ * it evaluates after content has been rendered for the current frame.
266
+ *
267
+ * Returns `undefined` when:
268
+ * - `scrollIndicator` is not `"indices"`, or
269
+ * - `maxRows` is unset, or total visual rows ≤ maxRows (nothing to
270
+ * scroll), or
271
+ * - no render has happened yet (cache is empty).
272
+ */
273
+ get scrollIndicatorText(): string | undefined;
48
274
  private resolvePalette;
49
275
  }
50
276
  //# sourceMappingURL=text-input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-input.d.ts","sourceRoot":"","sources":["../../src/widgets/text-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAID,qBAAa,SAAU,SAAQ,UAAU;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,QAAQ;IAEd,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;gBAExB,OAAO,GAAE,gBAAqB;IAY1C,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAKpC,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAqDvB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAcnD,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAIhC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;IAuDjD,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAQtE,OAAO,CAAC,cAAc;CAKvB"}
1
+ {"version":3,"file":"text-input.d.ts","sourceRoot":"","sources":["../../src/widgets/text-input.ts"],"names":[],"mappings":"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"}