@promptctl/rich-js 0.27.0 → 0.29.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 (185) hide show
  1. package/README.md +7 -6
  2. package/THIRD-PARTY-NOTICES +42 -0
  3. package/dist/core/animation.d.ts +65 -46
  4. package/dist/core/animation.js +91 -67
  5. package/dist/core/ansi.d.ts +19 -12
  6. package/dist/core/ansi.js +114 -36
  7. package/dist/core/bidi-data.d.ts +14 -0
  8. package/dist/core/bidi-data.js +385 -0
  9. package/dist/core/bidi.d.ts +89 -0
  10. package/dist/core/bidi.js +615 -0
  11. package/dist/core/box.d.ts +9 -1
  12. package/dist/core/box.js +11 -0
  13. package/dist/core/cell-widths.d.ts +3 -2
  14. package/dist/core/cell-widths.js +93 -93
  15. package/dist/core/cells.d.ts +20 -0
  16. package/dist/core/cells.js +94 -6
  17. package/dist/core/clock.d.ts +1 -1
  18. package/dist/core/color.d.ts +56 -57
  19. package/dist/core/color.js +79 -81
  20. package/dist/core/console.d.ts +24 -7
  21. package/dist/core/console.js +27 -8
  22. package/dist/core/control-codes.d.ts +61 -0
  23. package/dist/core/control-codes.js +157 -0
  24. package/dist/core/easing.d.ts +40 -40
  25. package/dist/core/easing.js +40 -40
  26. package/dist/core/env.d.ts +6 -0
  27. package/dist/core/env.js +9 -1
  28. package/dist/core/export-html.js +5 -4
  29. package/dist/core/export-lines.d.ts +13 -11
  30. package/dist/core/export-lines.js +19 -15
  31. package/dist/core/export-svg.d.ts +3 -3
  32. package/dist/core/export-svg.js +10 -9
  33. package/dist/core/json.js +9 -2
  34. package/dist/core/markup.js +5 -4
  35. package/dist/core/memo.d.ts +1 -1
  36. package/dist/core/memo.js +1 -1
  37. package/dist/core/oklch.d.ts +14 -14
  38. package/dist/core/oklch.js +10 -10
  39. package/dist/core/orient.d.ts +68 -0
  40. package/dist/core/orient.js +224 -0
  41. package/dist/core/osc8.d.ts +12 -5
  42. package/dist/core/osc8.js +14 -7
  43. package/dist/core/paint.d.ts +9 -9
  44. package/dist/core/paint.js +3 -3
  45. package/dist/core/pretty.d.ts +1 -1
  46. package/dist/core/pretty.js +23 -19
  47. package/dist/core/protocol.d.ts +47 -26
  48. package/dist/core/protocol.js +31 -23
  49. package/dist/core/render.d.ts +19 -14
  50. package/dist/core/render.js +30 -17
  51. package/dist/core/seal.d.ts +26 -0
  52. package/dist/core/seal.js +75 -0
  53. package/dist/core/segment.d.ts +12 -4
  54. package/dist/core/segment.js +16 -6
  55. package/dist/core/strip.d.ts +83 -83
  56. package/dist/core/strip.js +70 -70
  57. package/dist/core/style.d.ts +46 -18
  58. package/dist/core/style.js +92 -56
  59. package/dist/core/text-order.d.ts +51 -0
  60. package/dist/core/text-order.js +50 -0
  61. package/dist/core/text.d.ts +12 -2
  62. package/dist/core/text.js +136 -90
  63. package/dist/core/timeline.d.ts +5 -5
  64. package/dist/core/timeline.js +11 -11
  65. package/dist/core/tween.d.ts +6 -6
  66. package/dist/core/tween.js +10 -10
  67. package/dist/core/view.d.ts +5 -5
  68. package/dist/core/view.js +15 -14
  69. package/dist/core/wrap.d.ts +24 -6
  70. package/dist/core/wrap.js +82 -16
  71. package/dist/host/app.d.ts +50 -9
  72. package/dist/host/app.js +120 -15
  73. package/dist/host/host-environment.d.ts +2 -2
  74. package/dist/host/host-environment.js +2 -2
  75. package/dist/host/index.d.ts +3 -2
  76. package/dist/host/index.js +1 -0
  77. package/dist/host/input.d.ts +42 -9
  78. package/dist/host/input.js +91 -7
  79. package/dist/host/terminal-colors.d.ts +18 -0
  80. package/dist/host/terminal-colors.js +46 -0
  81. package/dist/host/terminal-host.d.ts +4 -3
  82. package/dist/host/terminal-host.js +1 -1
  83. package/dist/index.d.ts +17 -16
  84. package/dist/index.js +11 -11
  85. package/dist/node/prompt.d.ts +1 -1
  86. package/dist/node/prompt.js +1 -1
  87. package/dist/node/terminal-host.d.ts +1 -1
  88. package/dist/node/traceback.js +2 -2
  89. package/dist/renderables/change.d.ts +1 -3
  90. package/dist/renderables/change.js +6 -8
  91. package/dist/renderables/effect.d.ts +88 -87
  92. package/dist/renderables/effect.js +124 -114
  93. package/dist/renderables/effects.d.ts +105 -76
  94. package/dist/renderables/effects.js +309 -176
  95. package/dist/renderables/embed.d.ts +1 -1
  96. package/dist/renderables/embed.js +2 -2
  97. package/dist/renderables/flexStrip.d.ts +7 -7
  98. package/dist/renderables/flexStrip.js +15 -15
  99. package/dist/renderables/frames.d.ts +7 -16
  100. package/dist/renderables/frames.js +12 -27
  101. package/dist/renderables/glyph-effect.d.ts +22 -23
  102. package/dist/renderables/glyph-effect.js +43 -41
  103. package/dist/renderables/glyph-effects.d.ts +33 -14
  104. package/dist/renderables/glyph-effects.js +90 -22
  105. package/dist/renderables/html-entities.d.ts +1 -1
  106. package/dist/renderables/html-entities.js +1 -1
  107. package/dist/renderables/lifecycle.d.ts +8 -10
  108. package/dist/renderables/lifecycle.js +17 -18
  109. package/dist/renderables/live.d.ts +2 -2
  110. package/dist/renderables/live.js +7 -7
  111. package/dist/renderables/markdown-parse.js +3 -3
  112. package/dist/renderables/markdown.js +4 -2
  113. package/dist/renderables/panel.js +7 -5
  114. package/dist/renderables/progress.d.ts +1 -1
  115. package/dist/renderables/progress.js +1 -1
  116. package/dist/renderables/progressBar.d.ts +3 -3
  117. package/dist/renderables/progressBar.js +21 -18
  118. package/dist/renderables/prompt.d.ts +1 -1
  119. package/dist/renderables/scroll.d.ts +1 -1
  120. package/dist/renderables/scroll.js +3 -3
  121. package/dist/renderables/spinner.d.ts +4 -4
  122. package/dist/renderables/spinner.js +10 -10
  123. package/dist/renderables/syntax.d.ts +2 -2
  124. package/dist/renderables/syntax.js +9 -4
  125. package/dist/renderables/table.js +5 -4
  126. package/dist/renderables/traceback.d.ts +1 -1
  127. package/dist/renderables/traceback.js +1 -1
  128. package/dist/renderables/tree.js +3 -3
  129. package/dist/template-bindings/animation-funcs.d.ts +60 -29
  130. package/dist/template-bindings/animation-funcs.js +126 -43
  131. package/dist/template-bindings/color-funcs.d.ts +14 -14
  132. package/dist/template-bindings/color-funcs.js +25 -25
  133. package/dist/template-bindings/index.d.ts +16 -14
  134. package/dist/template-bindings/index.js +17 -14
  135. package/dist/template-bindings/palette-funcs.d.ts +2 -2
  136. package/dist/template-bindings/palette-funcs.js +4 -4
  137. package/dist/template-bindings/style-funcs.d.ts +5 -5
  138. package/dist/template-bindings/style-funcs.js +16 -16
  139. package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
  140. package/dist/themes/{transpose.js → adjust.js} +28 -28
  141. package/dist/themes/buildPalette.d.ts +6 -5
  142. package/dist/themes/buildPalette.js +22 -22
  143. package/dist/themes/colorMath.d.ts +16 -16
  144. package/dist/themes/colorMath.js +32 -32
  145. package/dist/themes/data/ansi-tables.d.ts +2 -2
  146. package/dist/themes/data/ansi-tables.js +2 -2
  147. package/dist/themes/data/index.js +1 -4
  148. package/dist/themes/data/textual-ansi.js +0 -143
  149. package/dist/themes/data/types.d.ts +4 -4
  150. package/dist/themes/data/types.js +2 -2
  151. package/dist/themes/palette.d.ts +12 -12
  152. package/dist/themes/palette.js +16 -16
  153. package/dist/themes/ramp.d.ts +17 -17
  154. package/dist/themes/ramp.js +12 -12
  155. package/dist/themes/registry.d.ts +6 -8
  156. package/dist/themes/registry.js +6 -8
  157. package/dist/themes/terminalThemes.d.ts +4 -11
  158. package/dist/themes/terminalThemes.js +31 -47
  159. package/dist/widgets/button.d.ts +3 -3
  160. package/dist/widgets/button.js +8 -8
  161. package/dist/widgets/checkbox.d.ts +2 -2
  162. package/dist/widgets/checkbox.js +4 -4
  163. package/dist/widgets/dropdown.d.ts +3 -3
  164. package/dist/widgets/dropdown.js +7 -5
  165. package/dist/widgets/event-router.d.ts +6 -6
  166. package/dist/widgets/event-router.js +2 -2
  167. package/dist/widgets/focus-manager.d.ts +3 -3
  168. package/dist/widgets/focus-manager.js +3 -3
  169. package/dist/widgets/index.d.ts +2 -2
  170. package/dist/widgets/index.js +1 -1
  171. package/dist/widgets/ink.d.ts +3 -3
  172. package/dist/widgets/ink.js +4 -4
  173. package/dist/widgets/slider.d.ts +2 -2
  174. package/dist/widgets/static-item.d.ts +2 -2
  175. package/dist/widgets/text-input.d.ts +2 -2
  176. package/dist/widgets/text-input.js +5 -5
  177. package/dist/widgets/themed-widget.js +4 -4
  178. package/dist/widgets/toggle.d.ts +4 -4
  179. package/dist/widgets/toggle.js +6 -6
  180. package/dist/widgets/types.d.ts +6 -6
  181. package/dist/widgets/types.js +2 -2
  182. package/dist/widgets/widget-app.d.ts +10 -10
  183. package/dist/widgets/widget-app.js +8 -8
  184. package/dist/widgets/widget-base.d.ts +2 -2
  185. package/package.json +5 -4
@@ -6,13 +6,13 @@
6
6
  * color, and none takes a *measurement*. Without a ramp the answer gets
7
7
  * computed outside the theme system — a script emits a hex, a template
8
8
  * branches `if ge .pct 80 … else if ge .pct 50 …` — and that color decision
9
- * can no longer transpose with the palette it was meant to belong to. A ramp
9
+ * can no longer adjust with the palette it was meant to belong to. A ramp
10
10
  * is the one function whose input is a number, so the decision stays inside.
11
11
  *
12
12
  * A threshold cascade is a ramp too: the same stops with the `step` ease hold
13
13
  * each color until the next position, which is exactly `≥ threshold → hotter`
14
14
  * written as data. [LAW:one-type-per-behavior] One primitive; the easing is a
15
- * value — any `Ease` from `core/easing`, the vocabulary every effect shares —
15
+ * value — any `Easing` from `core/easing`, the vocabulary every effect shares —
16
16
  * so a gradient and a cascade differ by one word, not by which function was
17
17
  * called. [LAW:dataflow-not-control-flow] `at` applies it unconditionally.
18
18
  *
@@ -21,7 +21,7 @@
21
21
  * midpoints of an sRGB blend.
22
22
  *
23
23
  * A ramp also carries how far it has been moved: `scroll`, in spans, how
24
- * far its colours have travelled along it, and `hue`, in turns, how far
24
+ * far its colors have travelled along it, and `hue`, in turns, how far
25
25
  * they are rotated round the OKLCH hue circle. A moved ramp is still a
26
26
  * `ColorRamp`, so anything that reads a ramp reads a moving one frame by
27
27
  * frame (`moving`) with nothing new to learn. [LAW:one-type-per-behavior]
@@ -53,7 +53,7 @@ import { tween } from "../core/tween.js";
53
53
  export class ColorRamp {
54
54
  ease;
55
55
  stops;
56
- /** How far the colours have moved along the span, in spans, in [0, 1). */
56
+ /** How far the colors have moved along the span, in spans, in [0, 1). */
57
57
  scroll;
58
58
  /** How far every hue is rotated in OKLCH, in turns, in [0, 1). */
59
59
  hue;
@@ -92,11 +92,11 @@ export class ColorRamp {
92
92
  * CSS defines them. An ease that overshoots [0, 1] holds the end colors
93
93
  * where it does: a ramp never paints outside its stops.
94
94
  *
95
- * A scrolled ramp reads, inside its span, the colour `scroll` spans behind
95
+ * A scrolled ramp reads, inside its span, the color `scroll` spans behind
96
96
  * `value`, wrapped back round the span as a repeating gradient does —
97
- * seamless when the first and last stops are one colour; outside the span
98
- * its end colours hold, however far it has scrolled. A rotated ramp turns
99
- * the colour read by `hue` at its own lightness and chroma. Unmoved, every
97
+ * seamless when the first and last stops are one color; outside the span
98
+ * its end colors hold, however far it has scrolled. A rotated ramp turns
99
+ * the color read by `hue` at its own lightness and chroma. Unmoved, every
100
100
  * read keeps the exactness above.
101
101
  */
102
102
  at(value) {
@@ -112,7 +112,7 @@ export class ColorRamp {
112
112
  // Exact when unrotated: the OKLCH round trip can land a channel one off.
113
113
  return this.hue === 0 ? read : Oklch.fromRgba(read).applyKey({ ...IDENTITY, hueShift: 360 * this.hue }).toRgba();
114
114
  }
115
- /** The colour at `value` with the ramp unmoved: the stops and the ease alone. */
115
+ /** The color at `value` with the ramp unmoved: the stops and the ease alone. */
116
116
  unmoved(value) {
117
117
  const stops = this.stops;
118
118
  // The last stop at or below `value`; -1 when `value` is below them all.
@@ -137,13 +137,13 @@ export class ColorRamp {
137
137
  /**
138
138
  * This ramp read over time: its span of positions, from the first stop's
139
139
  * to the last's, crossed at a steady rate in `seconds` and held at the last
140
- * stop from then on, each colour along the way the ramp's own. A colour
140
+ * stop from then on, each color along the way the ramp's own. A color
141
141
  * tween is a two-stop ramp over its seconds — the ramp's ease shaping the
142
142
  * move, so `new ColorRamp(ease, [{ at: 0, color: a }, { at: 1, color: b
143
143
  * }]).over(seconds)` is `a` eased to `b` — and a ramp of more stops over
144
144
  * time is a sweep through all of them. [LAW:one-source-of-truth] The
145
145
  * blending is `at`'s; what time adds is `tween`'s (`core/tween.ts`), so a
146
- * host sampling once a second or sixty times reads the stop colours byte
146
+ * host sampling once a second or sixty times reads the stop colors byte
147
147
  * for byte where `at` paints them.
148
148
  */
149
149
  over(seconds) {
@@ -159,7 +159,7 @@ export class ColorRamp {
159
159
  * [LAW:one-source-of-truth] When it next changes is `Animation.all`'s
160
160
  * answer over the two parts; nothing here says it a second time. Whether
161
161
  * the depth it is drawn at can show the move is decided where it is drawn
162
- * (`gradient`, through `stillOnSlots`).
162
+ * (`gradient`, through `staticWhereUnchanged`).
163
163
  */
164
164
  moving(motion) {
165
165
  const still = Animation.constant(0);
@@ -11,15 +11,15 @@ export declare function listThemePalettes(): readonly ThemeName[];
11
11
  *
12
12
  * Synchronous: theme data is bundled at compile time via the data barrel,
13
13
  * so no I/O happens here. The Palette itself (which requires hex-parsing
14
- * ~150 vars into ColorRgba values) is constructed lazily on first request
15
- * and cached — subsequent calls for the same name return the same instance.
14
+ * ~150 vars into ColorRgba values) is cached on first request — subsequent
15
+ * calls for the same name return the same instance. `terminalThemes.ts` makes
16
+ * that request for every theme, on import.
16
17
  */
17
18
  export declare function getThemePalette(name: ThemeName): Palette;
18
19
  export declare function getThemePalette(name: string): Palette | null;
19
20
  /**
20
21
  * The eight base colors every theme must declare, and its ANSI table. Returned by
21
- * `getThemeBaseColors` for callers (notably `terminalThemes.ts`) that only
22
- * need the substrate and would otherwise fill the registry cache.
22
+ * `getThemeBaseColors` for callers that only need the substrate.
23
23
  */
24
24
  export interface ThemeBaseColors {
25
25
  readonly name: string;
@@ -35,9 +35,7 @@ export interface ThemeBaseColors {
35
35
  readonly ansi: ColorTable;
36
36
  }
37
37
  /**
38
- * Read just the eight base colors from a theme's data file. Cheap — parses
39
- * 8 hex strings, allocates no Palette, touches no cache. Use this when you
40
- * want a `TerminalTheme`-shaped substrate without forcing the full ~150-var
41
- * palette through the registry's hydration path.
38
+ * Read just the eight base colors and the ANSI table from a theme's data file.
39
+ * Parses 8 hex strings, allocates no Palette, touches no cache.
42
40
  */
43
41
  export declare function getThemeBaseColors(name: ThemeName): ThemeBaseColors;
@@ -23,16 +23,14 @@ function isThemeName(name) {
23
23
  return Object.hasOwn(THEMES, name);
24
24
  }
25
25
  /**
26
- * Read just the eight base colors from a theme's data file. Cheap — parses
27
- * 8 hex strings, allocates no Palette, touches no cache. Use this when you
28
- * want a `TerminalTheme`-shaped substrate without forcing the full ~150-var
29
- * palette through the registry's hydration path.
26
+ * Read just the eight base colors and the ANSI table from a theme's data file.
27
+ * Parses 8 hex strings, allocates no Palette, touches no cache.
30
28
  */
31
29
  export function getThemeBaseColors(name) {
32
30
  const data = THEMES[name];
33
31
  const bg = parseHex(data.vars.background, data.name, "background");
34
- // The colours `getThemePalette(name)` hands out for the same names: drawn on
35
- // the theme's own background, as a Palette draws every colour it holds.
32
+ // The colors `getThemePalette(name)` hands out for the same names: drawn on
33
+ // the theme's own background, as a Palette draws every color it holds.
36
34
  const draw = drawnOn(data.name, bg);
37
35
  const base = (key) => draw(parseHex(data.vars[key], data.name, key));
38
36
  return {
@@ -59,7 +57,7 @@ function hydrate(data) {
59
57
  const stated = Object.entries(data.vars).map(([role, hex]) => [role, parseHex(hex, data.name, `var ${role}`)]);
60
58
  return buildPalette(data.name, data.dark, Object.fromEntries(stated));
61
59
  }
62
- // Theme data is authored, so a malformed colour names the theme and the key it
60
+ // Theme data is authored, so a malformed color names the theme and the key it
63
61
  // sits under; the grammar itself is `parseHexColor`'s.
64
62
  function parseHex(value, theme, key) {
65
63
  try {
@@ -72,7 +70,7 @@ function parseHex(value, theme, key) {
72
70
  }
73
71
  }
74
72
  /**
75
- * An ANSI slot is a colour a terminal paints, never a blend, so it takes no
73
+ * An ANSI slot is a color a terminal paints, never a blend, so it takes no
76
74
  * alpha: `flattenAlpha` leaves a STANDARD spec alone and would pass one through.
77
75
  */
78
76
  function parseOpaqueHex(value, theme, key) {
@@ -3,17 +3,10 @@
3
3
  * matching `<NAME>` export here. There is no inline-only theme; the data
4
4
  * file is the single source of truth for every theme's hex values.
5
5
  *
6
- * Editing `data/<name>.ts` updates both the registry's palette (via
7
- * `getThemePalette(name)`) AND the matching `TerminalTheme` constant exported
8
- * below (via `getThemeBaseColors(name)`, which pulls just the 8 substrate
9
- * keys). The two views agree on those eight. Every other role of a
10
- * `TerminalTheme`'s palette is derived from them, so it is not the colour the
11
- * theme authored: read `getThemePalette` for that.
12
- *
13
- * [LAW:one-source-of-truth] Hex values live in `data/<name>.ts`. This
14
- * module is a derived view that builds a `TerminalTheme` from each
15
- * theme's eight base colors via `buildPalette` for the substrate palette,
16
- * and from the theme's own ANSI table for the sixteen named colours.
6
+ * [LAW:one-source-of-truth] Hex values live in `data/<name>.ts`, and a theme's
7
+ * name means one palette: a constant here holds the very `Palette`
8
+ * `getThemePalette(name)` returns, and takes the background and foreground off
9
+ * it, with the theme's sixteen named colors beside it.
17
10
  *
18
11
  * [LAW:one-type-per-behavior] Every theme has the same shape — name,
19
12
  * `dark` flag, full Palette in the registry, `TerminalTheme` constant
@@ -3,17 +3,10 @@
3
3
  * matching `<NAME>` export here. There is no inline-only theme; the data
4
4
  * file is the single source of truth for every theme's hex values.
5
5
  *
6
- * Editing `data/<name>.ts` updates both the registry's palette (via
7
- * `getThemePalette(name)`) AND the matching `TerminalTheme` constant exported
8
- * below (via `getThemeBaseColors(name)`, which pulls just the 8 substrate
9
- * keys). The two views agree on those eight. Every other role of a
10
- * `TerminalTheme`'s palette is derived from them, so it is not the colour the
11
- * theme authored: read `getThemePalette` for that.
12
- *
13
- * [LAW:one-source-of-truth] Hex values live in `data/<name>.ts`. This
14
- * module is a derived view that builds a `TerminalTheme` from each
15
- * theme's eight base colors via `buildPalette` for the substrate palette,
16
- * and from the theme's own ANSI table for the sixteen named colours.
6
+ * [LAW:one-source-of-truth] Hex values live in `data/<name>.ts`, and a theme's
7
+ * name means one palette: a constant here holds the very `Palette`
8
+ * `getThemePalette(name)` returns, and takes the background and foreground off
9
+ * it, with the theme's sixteen named colors beside it.
17
10
  *
18
11
  * [LAW:one-type-per-behavior] Every theme has the same shape — name,
19
12
  * `dark` flag, full Palette in the registry, `TerminalTheme` constant
@@ -25,40 +18,31 @@
25
18
  * color primitives; nothing in `core/` imports back.
26
19
  */
27
20
  import { TerminalTheme } from "../core/color.js";
28
- import { buildPalette } from "./buildPalette.js";
29
- import { getThemeBaseColors } from "./registry.js";
30
- function defineTheme(d) {
31
- return new TerminalTheme(d.bg, d.fg, d.ansi, buildPalette(d.name, d.dark, {
32
- primary: d.primary,
33
- secondary: d.secondary,
34
- accent: d.accent,
35
- success: d.success,
36
- warning: d.warning,
37
- error: d.error,
38
- background: d.bg,
39
- foreground: d.fg,
40
- }));
21
+ import { getThemeBaseColors, getThemePalette } from "./registry.js";
22
+ function defineTheme(name) {
23
+ const palette = getThemePalette(name);
24
+ return new TerminalTheme(palette.get("background"), palette.get("foreground"), getThemeBaseColors(name).ansi, palette);
41
25
  }
42
- export const DEFAULT_TERMINAL_THEME = defineTheme(getThemeBaseColors("default"));
43
- export const SVG_EXPORT_THEME = defineTheme(getThemeBaseColors("svg-export"));
44
- export const MONOKAI = defineTheme(getThemeBaseColors("monokai"));
45
- export const NORD = defineTheme(getThemeBaseColors("nord"));
46
- export const GRUVBOX = defineTheme(getThemeBaseColors("gruvbox"));
47
- export const DRACULA = defineTheme(getThemeBaseColors("dracula"));
48
- export const TOKYO_NIGHT = defineTheme(getThemeBaseColors("tokyo-night"));
49
- export const FLEXOKI = defineTheme(getThemeBaseColors("flexoki"));
50
- export const CYBERPUNK = defineTheme(getThemeBaseColors("cyberpunk"));
51
- export const CATPPUCCIN_MOCHA = defineTheme(getThemeBaseColors("catppuccin-mocha"));
52
- export const CATPPUCCIN_LATTE = defineTheme(getThemeBaseColors("catppuccin-latte"));
53
- export const CATPPUCCIN_FRAPPE = defineTheme(getThemeBaseColors("catppuccin-frappe"));
54
- export const CATPPUCCIN_MACCHIATO = defineTheme(getThemeBaseColors("catppuccin-macchiato"));
55
- export const SOLARIZED_DARK = defineTheme(getThemeBaseColors("solarized-dark"));
56
- export const SOLARIZED_LIGHT = defineTheme(getThemeBaseColors("solarized-light"));
57
- export const ROSE_PINE = defineTheme(getThemeBaseColors("rose-pine"));
58
- export const ROSE_PINE_MOON = defineTheme(getThemeBaseColors("rose-pine-moon"));
59
- export const ROSE_PINE_DAWN = defineTheme(getThemeBaseColors("rose-pine-dawn"));
60
- export const ATOM_ONE_DARK = defineTheme(getThemeBaseColors("atom-one-dark"));
61
- export const ATOM_ONE_LIGHT = defineTheme(getThemeBaseColors("atom-one-light"));
62
- export const TEXTUAL_DARK = defineTheme(getThemeBaseColors("textual-dark"));
63
- export const TEXTUAL_LIGHT = defineTheme(getThemeBaseColors("textual-light"));
64
- export const TEXTUAL_ANSI = defineTheme(getThemeBaseColors("textual-ansi"));
26
+ export const DEFAULT_TERMINAL_THEME = defineTheme("default");
27
+ export const SVG_EXPORT_THEME = defineTheme("svg-export");
28
+ export const MONOKAI = defineTheme("monokai");
29
+ export const NORD = defineTheme("nord");
30
+ export const GRUVBOX = defineTheme("gruvbox");
31
+ export const DRACULA = defineTheme("dracula");
32
+ export const TOKYO_NIGHT = defineTheme("tokyo-night");
33
+ export const FLEXOKI = defineTheme("flexoki");
34
+ export const CYBERPUNK = defineTheme("cyberpunk");
35
+ export const CATPPUCCIN_MOCHA = defineTheme("catppuccin-mocha");
36
+ export const CATPPUCCIN_LATTE = defineTheme("catppuccin-latte");
37
+ export const CATPPUCCIN_FRAPPE = defineTheme("catppuccin-frappe");
38
+ export const CATPPUCCIN_MACCHIATO = defineTheme("catppuccin-macchiato");
39
+ export const SOLARIZED_DARK = defineTheme("solarized-dark");
40
+ export const SOLARIZED_LIGHT = defineTheme("solarized-light");
41
+ export const ROSE_PINE = defineTheme("rose-pine");
42
+ export const ROSE_PINE_MOON = defineTheme("rose-pine-moon");
43
+ export const ROSE_PINE_DAWN = defineTheme("rose-pine-dawn");
44
+ export const ATOM_ONE_DARK = defineTheme("atom-one-dark");
45
+ export const ATOM_ONE_LIGHT = defineTheme("atom-one-light");
46
+ export const TEXTUAL_DARK = defineTheme("textual-dark");
47
+ export const TEXTUAL_LIGHT = defineTheme("textual-light");
48
+ export const TEXTUAL_ANSI = defineTheme("textual-ansi");
@@ -19,7 +19,7 @@ import { Segment } from "../core/segment.js";
19
19
  import type { RenderOptions } from "../core/protocol.js";
20
20
  import type { TerminalTheme } from "../core/color.js";
21
21
  import { ThemedWidget } from "./themed-widget.js";
22
- import type { KeyEvent, WidgetMouseEvent } from "./types.js";
22
+ import type { WidgetKeyEvent, WidgetMouseEvent } from "./types.js";
23
23
  export type ButtonVariant = "default" | "primary" | "success" | "warning" | "danger";
24
24
  export interface ButtonOptions {
25
25
  label: string;
@@ -34,10 +34,10 @@ export declare class Button extends ThemedWidget {
34
34
  accessor label: string;
35
35
  accessor variant: ButtonVariant;
36
36
  constructor(options: ButtonOptions);
37
- handleKey(event: KeyEvent): void;
37
+ handleKey(event: WidgetKeyEvent): void;
38
38
  handleMouse(event: WidgetMouseEvent): void;
39
39
  setActive(value: boolean): void;
40
- protected draw(_options: RenderOptions): Iterable<Segment>;
40
+ protected draw(options: RenderOptions): Iterable<Segment>;
41
41
  measure(_options: RenderOptions): {
42
42
  minimum: number;
43
43
  maximum: number;
@@ -49,9 +49,9 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
49
49
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
50
50
  done = true;
51
51
  };
52
+ import { labeled } from "../core/orient.js";
52
53
  import { action } from "mobx";
53
54
  import { observableRef } from "./observable.js";
54
- import { Segment } from "../core/segment.js";
55
55
  import { Style } from "../core/style.js";
56
56
  import { cellLen } from "../core/cells.js";
57
57
  import { ThemedWidget } from "./themed-widget.js";
@@ -61,7 +61,7 @@ import { ink } from "./ink.js";
61
61
  // hover — full accent bg; pair with hoverFg, NOT with `fg`. The
62
62
  // text-* keys are mostly-accent and would clash on a full
63
63
  // accent bg.
64
- // hoverFg — WCAG-correct contrast colour (on-${accent}) for full bg.
64
+ // hoverFg — WCAG-correct contrast color (on-${accent}) for full bg.
65
65
  const VARIANT_KEYS = {
66
66
  default: { bg: "surface", fg: "foreground", hover: "primary", hoverFg: "on-primary" },
67
67
  primary: { bg: "primary-muted", fg: "text-primary", hover: "primary", hoverFg: "on-primary" },
@@ -148,24 +148,24 @@ let Button = (() => {
148
148
  // --- Active mutator (the keyboard-activation microtask uses this) ---
149
149
  setActive(value) { this.active = value; }
150
150
  // --- Rendering ---
151
- draw(_options) {
151
+ draw(options) {
152
152
  // [LAW:dataflow-not-control-flow] same segment count and width every state
153
153
  const focused = this.focused;
154
154
  const left = focused ? "[" : " ";
155
155
  const right = focused ? "]" : " ";
156
- const text = `${left} ${this.label} ${right}`;
156
+ const drawn = (style) => labeled(`${left} `, this.label, ` ${right}`, style, options.textOrder);
157
157
  if (this.disabled) {
158
- return [new Segment(text, new Style(this.disabledInk))];
158
+ return drawn(new Style(this.disabledInk));
159
159
  }
160
- // Active and hover share the same colour pair (full accent bg + on-accent fg).
160
+ // Active and hover share the same color pair (full accent bg + on-accent fg).
161
161
  // Active is differentiated by bold, not by inverting fg/bg — inversion gives
162
162
  // mostly-accent text on mostly-bg-tinted background, which is unreadable for
163
163
  // accents whose contrast partner depends on luminance.
164
164
  const keys = VARIANT_KEYS[this.variant];
165
165
  if (this.active || this.hovered) {
166
- return [new Segment(text, new Style({ ...ink(this.theme, keys.hoverFg, keys.hover), bold: this.active }))];
166
+ return drawn(new Style({ ...ink(this.theme, keys.hoverFg, keys.hover), bold: this.active }));
167
167
  }
168
- return [new Segment(text, new Style(ink(this.theme, keys.fg, keys.bg)))];
168
+ return drawn(new Style(ink(this.theme, keys.fg, keys.bg)));
169
169
  }
170
170
  measure(_options) {
171
171
  // [LAW:one-source-of-truth] cellLen is the cell-width authority; .length
@@ -14,7 +14,7 @@ import { Segment } from "../core/segment.js";
14
14
  import { type RenderOptions } from "../core/protocol.js";
15
15
  import type { TerminalTheme } from "../core/color.js";
16
16
  import { ThemedWidget } from "./themed-widget.js";
17
- import type { KeyEvent, WidgetMouseEvent } from "./types.js";
17
+ import type { WidgetKeyEvent, WidgetMouseEvent } from "./types.js";
18
18
  export interface CheckboxOptions {
19
19
  label: string;
20
20
  checked?: boolean;
@@ -28,7 +28,7 @@ export declare class Checkbox extends ThemedWidget {
28
28
  accessor label: string;
29
29
  accessor checked: boolean;
30
30
  constructor(options: CheckboxOptions);
31
- handleKey(event: KeyEvent): void;
31
+ handleKey(event: WidgetKeyEvent): void;
32
32
  handleMouse(event: WidgetMouseEvent): void;
33
33
  protected draw(options: RenderOptions): Iterable<Segment>;
34
34
  measure(_options: RenderOptions): {
@@ -44,9 +44,9 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
44
44
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
45
45
  done = true;
46
46
  };
47
+ import { labeled } from "../core/orient.js";
47
48
  import { action } from "mobx";
48
49
  import { observableRef } from "./observable.js";
49
- import { Segment } from "../core/segment.js";
50
50
  import { Style } from "../core/style.js";
51
51
  import { cellLen } from "../core/cells.js";
52
52
  import { drawable } from "../core/protocol.js";
@@ -119,12 +119,12 @@ let Checkbox = (() => {
119
119
  // --- Rendering ---
120
120
  draw(options) {
121
121
  const indicator = this.checked ? drawable(options, "✓", "x") : " ";
122
- const text = `[${indicator}] ${this.label}`;
122
+ const drawn = (style) => labeled(`[${indicator}] `, this.label, "", style, options.textOrder);
123
123
  if (this.disabled) {
124
- return [new Segment(text, new Style(this.disabledInk))];
124
+ return drawn(new Style(this.disabledInk));
125
125
  }
126
126
  const colors = ink(this.theme, this.checked ? "text-primary" : "foreground", "background");
127
- return [new Segment(text, new Style({ ...colors, underline: this.focused }))];
127
+ return drawn(new Style({ ...colors, underline: this.focused }));
128
128
  }
129
129
  measure(_options) {
130
130
  // [LAW:one-source-of-truth] cellLen — see button.ts.
@@ -26,7 +26,7 @@ import { Segment } from "../core/segment.js";
26
26
  import { type RenderOptions } from "../core/protocol.js";
27
27
  import type { TerminalTheme } from "../core/color.js";
28
28
  import { ThemedWidget } from "./themed-widget.js";
29
- import type { KeyEvent, WidgetMouseEvent, WidgetFocusEvent, OverlayRenderable } from "./types.js";
29
+ import type { WidgetKeyEvent, WidgetMouseEvent, WidgetFocusEvent, OverlayRenderable } from "./types.js";
30
30
  export interface DropdownOptions {
31
31
  options: string[];
32
32
  selectedIndex?: number;
@@ -50,12 +50,12 @@ export declare class Dropdown extends ThemedWidget implements OverlayRenderable
50
50
  }[];
51
51
  constructor(options: DropdownOptions);
52
52
  private clampIndex;
53
- handleKey(event: KeyEvent): void;
53
+ handleKey(event: WidgetKeyEvent): void;
54
54
  handleMouse(event: WidgetMouseEvent): void;
55
55
  handleFocus(event: WidgetFocusEvent): void;
56
56
  protected draw(options: RenderOptions): Iterable<Segment>;
57
57
  private headerText;
58
- renderOverlay(_options: RenderOptions): Iterable<Segment> | null;
58
+ renderOverlay(options: RenderOptions): Iterable<Segment> | null;
59
59
  private renderNoMatchRow;
60
60
  private renderOptionRow;
61
61
  private maxLabelLen;
@@ -56,6 +56,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
56
56
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
57
57
  done = true;
58
58
  };
59
+ import { labeled } from "../core/orient.js";
59
60
  import { action } from "mobx";
60
61
  import { observableRef } from "./observable.js";
61
62
  import { Segment } from "../core/segment.js";
@@ -318,7 +319,7 @@ let Dropdown = (() => {
318
319
  const headerLabel = this.headerText(maxLabelLen, caret);
319
320
  return [
320
321
  new Segment("[", baseStyle),
321
- new Segment(`${headerLabel} ${arrowChar}`, baseStyle),
322
+ ...labeled("", headerLabel, ` ${arrowChar}`, baseStyle, options.textOrder),
322
323
  new Segment("]", baseStyle),
323
324
  ];
324
325
  }
@@ -348,18 +349,19 @@ let Dropdown = (() => {
348
349
  const [filterText] = splitText(this.filter, asCellCol(filterRoom));
349
350
  return setCellSize(" " + filterText + caret, asCellCol(maxLabelLen));
350
351
  }
351
- renderOverlay(_options) {
352
+ renderOverlay(options) {
352
353
  if (!this.expanded)
353
354
  return null;
354
355
  const maxLabelLen = this.maxLabelLen();
355
356
  const fopts = this.filteredOptions;
356
357
  if (fopts.length === 0)
357
358
  return this.renderNoMatchRow(maxLabelLen);
359
+ const order = options.textOrder;
358
360
  const segments = [];
359
361
  for (let i = 0; i < fopts.length; i++) {
360
362
  if (i > 0)
361
363
  segments.push(new Segment("\n"));
362
- segments.push(...this.renderOptionRow(fopts[i], i, maxLabelLen));
364
+ segments.push(...this.renderOptionRow(fopts[i], i, maxLabelLen, order));
363
365
  }
364
366
  return segments;
365
367
  }
@@ -379,7 +381,7 @@ let Dropdown = (() => {
379
381
  new Segment(" ", style),
380
382
  ];
381
383
  }
382
- renderOptionRow(entry, fpos, maxLabelLen) {
384
+ renderOptionRow(entry, fpos, maxLabelLen, order) {
383
385
  // Row: " " + label.padEnd(maxLabelLen) + " "
384
386
  // Width = 1 + 1 + maxLabelLen + 1 + 1 = maxLabelLen + 4.
385
387
  // Overlay rows are unbracketed — selection/highlight are conveyed by bg
@@ -399,7 +401,7 @@ let Dropdown = (() => {
399
401
  : new Style(ink(this.theme, "foreground", "surface"));
400
402
  return [
401
403
  new Segment(" ", rowStyle),
402
- new Segment(inner, rowStyle),
404
+ ...labeled("", inner, "", rowStyle, order),
403
405
  new Segment(" ", rowStyle),
404
406
  ];
405
407
  }
@@ -5,13 +5,13 @@
5
5
  * It parses nothing and reads no terminal: `App` owns the one parser over its
6
6
  * host's input (`host/input`), and `WidgetApp` hands this what the app hears.
7
7
  */
8
- import { KeyEvent } from "./types.js";
8
+ import { WidgetKeyEvent } from "./types.js";
9
9
  import type { FrameSource, KeyHandlerOptions } from "./types.js";
10
10
  import type { Unsubscribe } from "../core/subscription.js";
11
- import type { KeyPress } from "../host/input.js";
11
+ import type { KeyEvent } from "../host/input.js";
12
12
  import type { AppMouseEvent } from "../host/app.js";
13
- import type { Wheel } from "../host/app.js";
14
- type KeyHandler = (event: KeyEvent) => void;
13
+ import type { WheelEvent } from "../host/app.js";
14
+ type KeyHandler = (event: WidgetKeyEvent) => void;
15
15
  export interface EventRouterOptions {
16
16
  source: FrameSource;
17
17
  /** Whether a left-button press focuses the widget under it before it hears the press. */
@@ -44,7 +44,7 @@ export declare class EventRouter {
44
44
  onKey(handler: KeyHandler, options?: KeyHandlerOptions): Unsubscribe;
45
45
  onMouse(handler: (event: AppMouseEvent) => void): Unsubscribe;
46
46
  /** Route a key the app heard. */
47
- key(press: KeyPress): void;
47
+ key(press: KeyEvent): void;
48
48
  /** Route a pointer event the app heard. */
49
49
  mouse(event: AppMouseEvent): void;
50
50
  /**
@@ -53,7 +53,7 @@ export declare class EventRouter {
53
53
  * Whether one moved is the answer: with none, the app passes the wheel
54
54
  * outward.
55
55
  */
56
- wheel({ x, y, lines }: Wheel): boolean;
56
+ wheel({ x, y, lines }: WheelEvent): boolean;
57
57
  private point;
58
58
  private dispatchKey;
59
59
  private dispatchMouse;
@@ -5,7 +5,7 @@
5
5
  * It parses nothing and reads no terminal: `App` owns the one parser over its
6
6
  * host's input (`host/input`), and `WidgetApp` hands this what the app hears.
7
7
  */
8
- import { KeyEvent } from "./types.js";
8
+ import { WidgetKeyEvent } from "./types.js";
9
9
  import { cellOf, drew, originOf, scrollTargetAt, widgetAt } from "./hit.js";
10
10
  export class EventRouter {
11
11
  source;
@@ -78,7 +78,7 @@ export class EventRouter {
78
78
  }
79
79
  /** Route a key the app heard. */
80
80
  key(press) {
81
- this.dispatchKey(new KeyEvent(press, this.source.frameNow().time));
81
+ this.dispatchKey(new WidgetKeyEvent(press, this.source.frameNow().time));
82
82
  }
83
83
  /** Route a pointer event the app heard. */
84
84
  mouse(event) {
@@ -4,12 +4,12 @@
4
4
  * [LAW:dataflow-not-control-flow] focus transitions are observable state;
5
5
  * widgets react to focus/blur events, the manager never skips dispatch.
6
6
  */
7
- import type { InteractiveWidget, FocusManager, KeyEvent } from "./types.js";
7
+ import type { InteractiveWidget, FocusManager, WidgetKeyEvent } from "./types.js";
8
8
  import type { Unsubscribe } from "../core/subscription.js";
9
9
  /** What focus follows: the frame a `WidgetApp` just painted. */
10
10
  export interface FocusView {
11
11
  /** Every widget the view holds, in document order, whether or not it has a cell on screen. */
12
- present(): readonly InteractiveWidget[];
12
+ mounted(): readonly InteractiveWidget[];
13
13
  /** The widgets with a cell on the frame on screen, in document order. */
14
14
  onScreen(): readonly InteractiveWidget[];
15
15
  /** The time a frame drawn now is drawn for (`RenderOptions.frame`), which a focus change is stamped with. */
@@ -46,7 +46,7 @@ export declare class DefaultFocusManager implements FocusManager {
46
46
  */
47
47
  settle(): void;
48
48
  onChange(handler: (current: InteractiveWidget | null) => void): Unsubscribe;
49
- handleKey(event: KeyEvent): void;
49
+ handleKey(event: WidgetKeyEvent): void;
50
50
  private step;
51
51
  private clear;
52
52
  private setFocus;
@@ -90,10 +90,10 @@ let DefaultFocusManager = (() => {
90
90
  return this.view.onScreen().filter(takesFocus);
91
91
  }
92
92
  next() {
93
- this.step(this.view.present());
93
+ this.step(this.view.mounted());
94
94
  }
95
95
  prev() {
96
- this.step([...this.view.present()].reverse());
96
+ this.step([...this.view.mounted()].reverse());
97
97
  }
98
98
  // A widget not on screen yet can take focus: an app that is about to show
99
99
  // it focuses it first, and the frame that shows it keeps it (`settle`).
@@ -118,7 +118,7 @@ let DefaultFocusManager = (() => {
118
118
  */
119
119
  settle() {
120
120
  const current = this.currentWidget;
121
- if (current && takesFocus(current) && this.view.present().includes(current))
121
+ if (current && takesFocus(current) && this.view.mounted().includes(current))
122
122
  return;
123
123
  const first = this.widgets[0];
124
124
  if (first)
@@ -1,10 +1,10 @@
1
1
  export type { KeyHandlerPriority, KeyHandlerOptions, WidgetMouseEvent, WidgetFocusEvent, InteractiveWidget, OverlayRenderable, FocusManager, } from "./types.js";
2
- export { hasOverlay, KeyEvent } from "./types.js";
2
+ export { hasOverlay, WidgetKeyEvent } from "./types.js";
3
3
  export { StaticItem } from "./static-item.js";
4
4
  export type { StaticItemOptions } from "./static-item.js";
5
5
  export { WidgetBase } from "./widget-base.js";
6
6
  export { WidgetApp } from "./widget-app.js";
7
- export type { WidgetAppOptions, WidgetPresence } from "./widget-app.js";
7
+ export type { WidgetAppOptions, WidgetVisibility } from "./widget-app.js";
8
8
  export { Button } from "./button.js";
9
9
  export type { ButtonVariant, ButtonOptions } from "./button.js";
10
10
  export { Checkbox } from "./checkbox.js";
@@ -1,4 +1,4 @@
1
- export { hasOverlay, KeyEvent } from "./types.js";
1
+ export { hasOverlay, WidgetKeyEvent } from "./types.js";
2
2
  export { StaticItem } from "./static-item.js";
3
3
  export { WidgetBase } from "./widget-base.js";
4
4
  export { WidgetApp } from "./widget-app.js";
@@ -1,8 +1,8 @@
1
1
  /**
2
- * ink — the colour pair a widget cell is drawn in: a foreground and the ground
2
+ * ink — the color pair a widget cell is drawn in: a foreground and the ground
3
3
  * it stands on, both from one theme's palette.
4
4
  *
5
- * A palette's colours are chosen against that palette's own background. A
5
+ * A palette's colors are chosen against that palette's own background. A
6
6
  * foreground drawn over whatever the terminal shows is readable only when the
7
7
  * terminal happens to match the theme — the default theme's white text
8
8
  * vanished into a light terminal. With both halves taken from the palette, a
@@ -12,7 +12,7 @@
12
12
  * [LAW:types-are-the-program] There is no call that takes a foreground alone,
13
13
  * so a widget cannot draw half a pair.
14
14
  * [LAW:single-enforcer] Every widget resolves palette roles here, and this is
15
- * where one that draws no colour (a theme's fully transparent "no background")
15
+ * where one that draws no color (a theme's fully transparent "no background")
16
16
  * is reported.
17
17
  */
18
18
  import { ColorSpec, type TerminalTheme } from "../core/color.js";