@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
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Strip + Joiner — edge-aware horizontal layout primitive.
2
+ * Strip + Separator — edge-aware horizontal layout primitive.
3
3
  *
4
- * A `Strip` renders a horizontal sequence of styled items with a `Joiner`
4
+ * A `Strip` renders a horizontal sequence of styled items with a `Separator`
5
5
  * deciding how each transition between adjacent items looks. The joiner is
6
6
  * a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
7
7
  * so endpoint joins (the start and end of the strip) are explicit positions
@@ -34,22 +34,22 @@ import { fnv1a } from "./fnv1a.js";
34
34
  import { drawable, getStyle, isAscii, render } from "./protocol.js";
35
35
  /**
36
36
  * The owner every cell a strip's joiner draws is stamped with
37
- * (`Segment.anchorLines`), whatever the joiner: a seam is told by what drew
37
+ * (`Segment.anchorLines`), whatever the separator: a seam is told by what drew
38
38
  * it, never by its glyph, which an ASCII joiner draws otherwise and a lead may
39
39
  * not draw at all. An effect reads it to leave a seam out of the words it
40
40
  * keeps legible (`drawnOf`, `../renderables/effect.ts`).
41
41
  *
42
- * Inside it, every cell a `CellJoiner` draws is stamped with what it was
42
+ * Inside it, every cell a `CellSeparator` draws is stamped with what it was
43
43
  * resolved from (`JoinedCell`), so a cell whose neighbours an effect moves is
44
44
  * resolved again from where they moved to.
45
45
  */
46
46
  export const JOIN = Object.freeze({ name: "join" });
47
47
  /**
48
- * [LAW:single-enforcer] What `joiner` draws at one join, every cell stamped
48
+ * [LAW:single-enforcer] What `separator` draws at one join, every cell stamped
49
49
  * as `JOIN`'s: the one way `Strip` and `FlexStrip` draw a join.
50
50
  */
51
- export function drawJoin(joiner, left, right, context) {
52
- const join = joiner.join(left, right, context);
51
+ export function drawJoin(separator, left, right, context) {
52
+ const join = separator.join(left, right, context);
53
53
  return { render: (options) => Segment.anchorLines([[...render(join, options)]], JOIN)[0] };
54
54
  }
55
55
  /**
@@ -64,10 +64,10 @@ export function drawItem(item) {
64
64
  // --- Strip ---
65
65
  export class Strip {
66
66
  items;
67
- joiner;
68
- constructor(items, joiner) {
67
+ separator;
68
+ constructor(items, separator) {
69
69
  this.items = items;
70
- this.joiner = joiner;
70
+ this.separator = separator;
71
71
  }
72
72
  *render(options) {
73
73
  const items = this.items;
@@ -82,12 +82,12 @@ export class Strip {
82
82
  // `left` fills the canvas, and the first item would pad over the rest of
83
83
  // the row. Where the row sits in the width is its container's to say.
84
84
  const row = { ...options, justify: undefined };
85
- yield* render(drawJoin(this.joiner, null, items[0], { index: 0 }), row);
85
+ yield* render(drawJoin(this.separator, null, items[0], { index: 0 }), row);
86
86
  for (let i = 0; i < items.length; i++) {
87
87
  const item = items[i];
88
88
  yield* render(drawItem(item), row);
89
89
  const next = i + 1 < items.length ? items[i + 1] : null;
90
- yield* render(drawJoin(this.joiner, item, next, { index: i + 1 }), row);
90
+ yield* render(drawJoin(this.separator, item, next, { index: i + 1 }), row);
91
91
  }
92
92
  // [LAW:one-source-of-truth] `Strip`'s sibling `FlexStrip` ends every line
93
93
  // it emits, including the last, and the other block-level renderables
@@ -144,7 +144,7 @@ const cellWidth = (cell) => cellLen(glyphsOf(cell)[0] ?? "");
144
144
  // name, because the part is also drawn where that neighbour does not exist.
145
145
  function parsePaint(raw, absent, refuse) {
146
146
  if (raw === "ground")
147
- return refuse("mixes ground, whose colour is unknown");
147
+ return refuse("mixes ground, whose color is unknown");
148
148
  const p = (typeof raw === "object" && raw !== null ? raw : {});
149
149
  if ((p.edge === "left" || p.edge === "right") && (p.part === "bg" || p.part === "fg")) {
150
150
  if (p.edge === absent)
@@ -159,7 +159,7 @@ function parsePaint(raw, absent, refuse) {
159
159
  refuse(`mixes at ${String(t)}, outside 0..1`);
160
160
  return Object.freeze({ mix: Object.freeze([parsePaint(from, absent, refuse), parsePaint(to, absent, refuse), t]) });
161
161
  }
162
- return refuse(`has a colour that is not a Paint: ${JSON.stringify(raw)}`);
162
+ return refuse(`has a color that is not a Paint: ${JSON.stringify(raw)}`);
163
163
  }
164
164
  const parseColor = (raw, absent, refuse) => raw === "ground" ? raw : parsePaint(raw, absent, refuse);
165
165
  const ABSENT = { seam: undefined, lead: "left", tail: "right" };
@@ -248,8 +248,8 @@ function formOf(shape) {
248
248
  cells: { seam: cells("seam"), lead: cells("lead"), tail: cells("tail") },
249
249
  };
250
250
  }
251
- // A bg with a real colour to paint. `undefined` (no bg) and the terminal
252
- // DEFAULT colour (transparent — identical to the terminal background) are the
251
+ // A bg with a real color to paint. `undefined` (no bg) and the terminal
252
+ // DEFAULT color (transparent — identical to the terminal background) are the
253
253
  // two representations of "nothing to paint", so an explicit `… on default`
254
254
  // cannot smuggle a seam.
255
255
  function paintableBg(bg) {
@@ -262,13 +262,13 @@ function drawnGround(bg) {
262
262
  return bg.flattenAlpha(SURFACE_BLACK);
263
263
  }
264
264
  // Whether ink stands off its ground, both as a depth draws them, by the floor a
265
- // seam is seen at. A colour whose RGB is the terminal theme's own (ANSI 0–15, a
265
+ // seam is seen at. A color whose RGB is the terminal theme's own (ANSI 0–15, a
266
266
  // blend reaching one) has no value here, so two of them stand apart unless they
267
267
  // are one expression: the same palette slot — its `number`, never the name or
268
268
  // the depth that spells it ("red", "color(1)", an EIGHT_BIT spec on 0–15 are
269
269
  // one slot) — or the same blend, whose name spells each end by its slot for the
270
- // same reason. At sixteen colours, then, the floor is a different slot. The
271
- // terminal's default colour is nobody's to measure, and stands apart.
270
+ // same reason. At sixteen colors, then, the floor is a different slot. The
271
+ // terminal's default color is nobody's to measure, and stands apart.
272
272
  function standsOff(ink, ground) {
273
273
  if (ink.isDefault || ground.isDefault)
274
274
  return true;
@@ -277,7 +277,7 @@ function standsOff(ink, ground) {
277
277
  ? Oklch.fromRgba(a).deltaE(Oklch.fromRgba(b)) >= SEAM_MIN_DELTA_E
278
278
  : ink.number !== undefined ? ink.number !== ground.number : ink.name !== ground.name;
279
279
  }
280
- // A step along a lightness ray: finer than the steps between the colours a
280
+ // A step along a lightness ray: finer than the steps between the colors a
281
281
  // truecolor writer draws, so the walk passes over none of them.
282
282
  const LIFT_STEP = 0.001;
283
283
  // The steps along `origin`'s lightness ray, its chroma and hue held, in the
@@ -292,21 +292,21 @@ function* lightnessRay(origin) {
292
292
  }
293
293
  }
294
294
  /**
295
- * `ink`, a glyph's colour on `ground`, held at least `SEAM_MIN_DELTA_E` off it
295
+ * `ink`, a glyph's color on `ground`, held at least `SEAM_MIN_DELTA_E` off it
296
296
  * as `depth` draws both (`Style.drawnColors`). Ink that already stands off is
297
297
  * returned as it is. Ink that does not becomes the drawn form of the nearest
298
298
  * step along its own OKLCH lightness ray, chroma and hue held, that stands off:
299
299
  * the smaller step, toward white or toward black. Every step is measured as the
300
- * depth draws it, so at 256 colours and at sixteen the candidates are the
300
+ * depth draws it, so at 256 colors and at sixteen the candidates are the
301
301
  * entries the depth draws, and the side the ink moves to can differ between
302
- * depths. A floor measured on rounded colours is not monotone along a ray, so
303
- * the walk enumerates and never bisects. A side with no colour to measure is
302
+ * depths. A floor measured on rounded colors is not monotone along a ray, so
303
+ * the walk enumerates and never bisects. A side with no color to measure is
304
304
  * left alone.
305
305
  *
306
- * [LAW:one-source-of-truth] The colour returned is the one measured — the
306
+ * [LAW:one-source-of-truth] The color returned is the one measured — the
307
307
  * entry the depth draws, not the step that rounds to it — so a reader of the
308
308
  * cell at another depth (an export reads a recording in truecolor) sees the
309
- * colour that cleared the floor, never a step one unit off its ground.
309
+ * color that cleared the floor, never a step one unit off its ground.
310
310
  *
311
311
  * [LAW:single-enforcer] The one place a join cell's visibility is decided:
312
312
  * nothing outside the joiner predicts whether a seam will show.
@@ -319,14 +319,14 @@ function standOff(ink, ground, depth) {
319
319
  if (standsOff(shown, under))
320
320
  return ink;
321
321
  // The ray starts from the ink as it is laid on its ground, before a depth
322
- // rounds it; ink the terminal's theme draws starts from the colour the
322
+ // rounds it; ink the terminal's theme draws starts from the color the
323
323
  // default terminal theme gives it. Ink that vanishes is drawn in the same
324
324
  // kind as its ground — both fixed, or both the theme's — and every step is
325
325
  // drawn in that kind too, so it is measured as the ink was. Ink the depth
326
326
  // draws as the theme's (a slot, or a mix reaching one at truecolor) steps
327
- // between slots: an RGB beside a colour only the terminal knows could be
328
- // that very colour. Ink the depth fixes (that same mix is a cube entry at
329
- // 256) steps between fixed colours, for the same reason turned round.
327
+ // between slots: an RGB beside a color only the terminal knows could be
328
+ // that very color. Ink the depth fixes (that same mix is a cube entry at
329
+ // 256) steps between fixed colors, for the same reason turned round.
330
330
  const laid = drawn(ink).color;
331
331
  const kind = shown.fixedValue === undefined ? ColorDepth.STANDARD : ColorDepth.TRUECOLOR;
332
332
  for (const step of lightnessRay(Oklch.fromRgba(laid.getTruecolor()))) {
@@ -336,7 +336,7 @@ function standOff(ink, ground, depth) {
336
336
  }
337
337
  // [LAW:no-silent-failure] Unreachable: the ray runs out to black and to
338
338
  // white, and no ground lies within the floor of both, nor is one slot both.
339
- throw new Error(`no colour on the lightness ray of ${ink.name} stands off ${ground.name} at depth ${ColorDepth[depth]}`);
339
+ throw new Error(`no color on the lightness ray of ${ink.name} stands off ${ground.name} at depth ${ColorDepth[depth]}`);
340
340
  }
341
341
  function resolvePaint(paint, edges, options) {
342
342
  if ("edge" in paint) {
@@ -351,15 +351,15 @@ function resolvePaint(paint, edges, options) {
351
351
  const [from, to, t] = paint.mix;
352
352
  const a = resolvePaint(from, edges, options);
353
353
  const b = resolvePaint(to, edges, options);
354
- // A mix with no colour at one end has nothing to blend toward.
354
+ // A mix with no color at one end has nothing to blend toward.
355
355
  return a && b && ColorSpec.blend(a, b, t);
356
356
  }
357
357
  // [LAW:single-enforcer] The one resolution of a join cell's paints: at join
358
358
  // time, and again whenever an effect moves the neighbours it reads
359
359
  // (`JoinedCell`).
360
360
  function cellStyle(cell, edges, options) {
361
- // [LAW:dataflow-not-control-flow] "ground" is the absence of a colour on its
362
- // side; as the fg it is reverse video over the bg colour, so the glyph's ink
361
+ // [LAW:dataflow-not-control-flow] "ground" is the absence of a color on its
362
+ // side; as the fg it is reverse video over the bg color, so the glyph's ink
363
363
  // is the terminal's own background.
364
364
  if (cell.fg === "ground")
365
365
  return new Style({ color: cell.bg === "ground" ? undefined : resolvePaint(cell.bg, edges, options), reverse: true });
@@ -369,19 +369,19 @@ function cellStyle(cell, edges, options) {
369
369
  return new Style({ color: standOff(resolvePaint(cell.fg, edges, options), bgcolor, options.colorSystem ?? ColorDepth.TRUECOLOR), bgcolor });
370
370
  }
371
371
  /**
372
- * A cell a `CellJoiner` drew, as what it is: one function of its two
372
+ * A cell a `CellSeparator` drew, as what it is: one function of its two
373
373
  * neighbours' edges. It holds the cell's paints, the neighbour each side of
374
374
  * them reads, and the edges and render it was resolved from, and it is stamped
375
375
  * on the cell as the owner of its innermost anchor level.
376
376
  *
377
- * [LAW:one-source-of-truth] A seam's colours are its neighbours', so nothing
377
+ * [LAW:one-source-of-truth] A seam's colors are its neighbours', so nothing
378
378
  * paints them but this resolution. An effect paints a strip's items and never
379
379
  * a join cell that `follows` them; once the items are painted, each such cell
380
380
  * is handed what moved at the item cells beside it and resolved again through
381
381
  * `cellStyle`, the path the join was drawn by, lift included
382
382
  * (`../renderables/effect.ts`). A seam then follows its neighbours wherever an
383
383
  * effect takes them, a mix of the two included, and an effect that paints
384
- * both one colour leaves the seam's ink lifted off it. A cell painted from
384
+ * both one color leaves the seam's ink lifted off it. A cell painted from
385
385
  * roles and the terminal's ground alone, as `plain`'s separator is, follows
386
386
  * nobody, and an effect paints it as it paints any cell.
387
387
  */
@@ -439,7 +439,7 @@ export class JoinedCell {
439
439
  return { colors: next.style, style: style.withAnchor(style.anchor && restamp(style.anchor)) };
440
440
  }
441
441
  }
442
- /** The record a `CellJoiner` stamped on the cell `anchor` names, or none for a cell no `CellJoiner` drew. */
442
+ /** The record a `CellSeparator` stamped on the cell `anchor` names, or none for a cell no `CellSeparator` drew. */
443
443
  export function joinedCell(anchor) {
444
444
  for (let level = anchor; level; level = level.inner)
445
445
  if (level.owner instanceof JoinedCell)
@@ -448,8 +448,8 @@ export function joinedCell(anchor) {
448
448
  }
449
449
  const shapeGlyphs = (shape) => PARTS.flatMap((part) => shape[part].flatMap(glyphsOf)).join("");
450
450
  /**
451
- * The one joiner: what it draws is a `JoinSeam` between neighbours and a
452
- * `JoinCaps` at the ends of each run, picked independently, so a new joiner is
451
+ * The one separator: what it draws is a `SeparatorSeam` between neighbours and a
452
+ * `EndCaps` at the ends of each run, picked independently, so a new joiner is
453
453
  * a pair of values, never a class.
454
454
  *
455
455
  * Which part a join draws is read off its two neighbours. A neighbour is
@@ -464,7 +464,7 @@ const shapeGlyphs = (shape) => PARTS.flatMap((part) => shape[part].flatMap(glyph
464
464
  *
465
465
  * An ASCII-only output draws the `ascii` form of both, whole.
466
466
  */
467
- export class CellJoiner {
467
+ export class CellSeparator {
468
468
  seam;
469
469
  caps;
470
470
  _forms;
@@ -545,7 +545,7 @@ const rail = (glyph) => ({ glyph, fg: { role: "strip.rail" }, bg: GROUND });
545
545
  * What each draws is `docs/strip.md`'s "Seams"; any of them ends in any of
546
546
  * `CAPS`.
547
547
  */
548
- export const SEAMS = Object.freeze({
548
+ export const SEPARATORS = Object.freeze({
549
549
  powerline: parseSeam(arrowSeam(POWERLINE)),
550
550
  prism: parseSeam(both(prism(POWERLINE.glyph), prism(POWERLINE.ascii))),
551
551
  slant: parseSeam(arrowSeam(SLANT)),
@@ -575,9 +575,9 @@ const FLAT = { lead: [], tail: [] };
575
575
  /**
576
576
  * The bundled caps, by name: what a joiner draws where a run begins and ends.
577
577
  * What each draws is `docs/strip.md`'s "Caps"; any of them ends any of
578
- * `SEAMS`.
578
+ * `SEPARATORS`.
579
579
  */
580
- export const CAPS = Object.freeze({
580
+ export const END_CAPS = Object.freeze({
581
581
  powerline: parseCaps(flowCaps(POWERLINE)),
582
582
  slant: parseCaps(flowCaps(SLANT)),
583
583
  backslant: parseCaps(flowCaps(BACKSLANT)),
@@ -590,37 +590,37 @@ export const CAPS = Object.freeze({
590
590
  flat: parseCaps(both(FLAT, FLAT)),
591
591
  });
592
592
  /**
593
- * The bundled joiners, by name: each a seam from `SEAMS` ended in caps from
593
+ * The bundled joiners, by name: each a seam from `SEPARATORS` ended in caps from
594
594
  * `CAPS`. What each draws is `docs/strip.md`'s "Built-in joiners"; a name from
595
- * config is read with `joinerNamed`.
595
+ * config is read with `separatorNamed`.
596
596
  */
597
- export const JOINERS = Object.freeze({
598
- powerline: new CellJoiner(SEAMS.powerline, CAPS.powerline),
599
- prism: new CellJoiner(SEAMS.prism, CAPS.powerline),
600
- slant: new CellJoiner(SEAMS.slant, CAPS.slant),
601
- backslant: new CellJoiner(SEAMS.backslant, CAPS.backslant),
602
- flame: new CellJoiner(SEAMS.flame, CAPS.flame),
603
- pixel: new CellJoiner(SEAMS.pixel, CAPS.pixel),
604
- ice: new CellJoiner(SEAMS.ice, CAPS.ice),
605
- bubble: new CellJoiner(SEAMS.bubble, CAPS.bubble),
606
- capsule: new CellJoiner(SEAMS.capsule, CAPS.capsule),
607
- wrapper: new CellJoiner(SEAMS.wrapper, CAPS.wrapper),
608
- metro: new CellJoiner(SEAMS.metro, CAPS.capsule),
609
- stitch: new CellJoiner(SEAMS.stitch, CAPS.flat),
610
- torn: new CellJoiner(SEAMS.torn, CAPS.flat),
611
- plain: new CellJoiner(SEAMS.plain, CAPS.flat),
597
+ export const SEPARATOR_STYLES = Object.freeze({
598
+ powerline: new CellSeparator(SEPARATORS.powerline, END_CAPS.powerline),
599
+ prism: new CellSeparator(SEPARATORS.prism, END_CAPS.powerline),
600
+ slant: new CellSeparator(SEPARATORS.slant, END_CAPS.slant),
601
+ backslant: new CellSeparator(SEPARATORS.backslant, END_CAPS.backslant),
602
+ flame: new CellSeparator(SEPARATORS.flame, END_CAPS.flame),
603
+ pixel: new CellSeparator(SEPARATORS.pixel, END_CAPS.pixel),
604
+ ice: new CellSeparator(SEPARATORS.ice, END_CAPS.ice),
605
+ bubble: new CellSeparator(SEPARATORS.bubble, END_CAPS.bubble),
606
+ capsule: new CellSeparator(SEPARATORS.capsule, END_CAPS.capsule),
607
+ wrapper: new CellSeparator(SEPARATORS.wrapper, END_CAPS.wrapper),
608
+ metro: new CellSeparator(SEPARATORS.metro, END_CAPS.capsule),
609
+ stitch: new CellSeparator(SEPARATORS.stitch, END_CAPS.flat),
610
+ torn: new CellSeparator(SEPARATORS.torn, END_CAPS.flat),
611
+ plain: new CellSeparator(SEPARATORS.plain, END_CAPS.flat),
612
612
  });
613
613
  /**
614
614
  * The joiner `spec` names — a joiner read from config, parsed. Throws on a
615
615
  * name its table lacks, naming the ones there are; an own-key test, so
616
616
  * `toString` and the rest of `Object.prototype` are no one's name.
617
617
  */
618
- export function joinerNamed(spec) {
618
+ export function separatorNamed(spec) {
619
619
  if (typeof spec === "string")
620
- return named(JOINERS, "joiner", "joiners", spec);
620
+ return named(SEPARATOR_STYLES, "separator", "separators", spec);
621
621
  if (typeof spec !== "object" || spec === null)
622
- throw new Error(`a joiner is a name or { seam, caps }, not ${JSON.stringify(spec)}`);
623
- return new CellJoiner(named(SEAMS, "seam", "seams", spec.seam), named(CAPS, "caps", "caps", spec.caps));
622
+ throw new Error(`a separator is a name or { seam, caps }, not ${JSON.stringify(spec)}`);
623
+ return new CellSeparator(named(SEPARATORS, "seam", "seams", spec.seam), named(END_CAPS, "caps", "caps", spec.caps));
624
624
  }
625
625
  function named(table, kind, kinds, name) {
626
626
  if (!Object.hasOwn(table, name))
@@ -629,14 +629,14 @@ function named(table, kind, kinds, name) {
629
629
  }
630
630
  /**
631
631
  * A ramp of `steps` cells from the left ground to the right, each cell filled
632
- * with one colour: cell `i` is the colour `(i + 1/2) / steps` of the way
632
+ * with one color: cell `i` is the color `(i + 1/2) / steps` of the way
633
633
  * across, so no cell is either neighbour's ground. A cell is a space whose ink
634
- * is the terminal's ground, so its one colour is its fill, the same in ASCII.
635
- * Beside a neighbour with no ground there is no colour to ramp toward, so that
634
+ * is the terminal's ground, so its one color is its fill, the same in ASCII.
635
+ * Beside a neighbour with no ground there is no color to ramp toward, so that
636
636
  * join draws the caps the ramp is ended in.
637
637
  *
638
638
  * [LAW:dataflow-not-control-flow] A ramp cell is fill alone: a space has no
639
- * ink, and `"ground"` as its `fg` is the absence of a colour on that side
639
+ * ink, and `"ground"` as its `fg` is the absence of a color on that side
640
640
  * (`cellStyle`). So the lift, the path every seam cell is drawn by, has no ink
641
641
  * to hold off its ground, and the ramp is the blend, monotone however close
642
642
  * its grounds or however many its steps. Two samples to a cell, ink over
@@ -647,7 +647,7 @@ function named(table, kind, kinds, name) {
647
647
  export function gradientSeam(steps = 4) {
648
648
  // [LAW:no-silent-failure] A count that is no whole number of cells would draw
649
649
  // a lopsided ramp without a word, and no cells is no ramp: a seam that reads
650
- // neither ground, joining a colourless neighbour where a ramp draws the caps.
650
+ // neither ground, joining a colorless neighbour where a ramp draws the caps.
651
651
  if (!(Number.isInteger(steps) && steps > 0))
652
652
  throw new RangeError(`gradientSeam steps must be a positive whole number of cells, got ${steps}`);
653
653
  const ramp = {
@@ -3,13 +3,14 @@
3
3
  */
4
4
  import { ColorSpec, ColorDepth } from "./color.js";
5
5
  import { type Anchor } from "./anchor.js";
6
+ import type { BidiStamp } from "./text-order.js";
6
7
  /**
7
8
  * Canonical text-attribute inventory. Single source of truth consumed by
8
9
  * `Style.parse` / `Style.toString` and the template bindings — adding an
9
10
  * attribute here propagates to every styling surface without a second
10
11
  * list to keep in sync. [LAW:one-source-of-truth]
11
12
  */
12
- export declare const ATTRIBUTE_NAMES: readonly ["bold", "dim", "italic", "underline", "blink", "blink2", "reverse", "conceal", "strike", "underline2", "frame", "encircle", "overline"];
13
+ export declare const ATTRIBUTE_NAMES: readonly ["bold", "dim", "italic", "underline", "blink", "rapidBlink", "reverse", "conceal", "strike", "doubleUnderline", "frame", "encircle", "overline"];
13
14
  export type AttributeName = (typeof ATTRIBUTE_NAMES)[number];
14
15
  /**
15
16
  * Each text attribute as a style sets it: on, off, or unset — and an unset
@@ -34,30 +35,36 @@ export interface StyleOptions {
34
35
  italic?: boolean;
35
36
  underline?: boolean;
36
37
  blink?: boolean;
37
- blink2?: boolean;
38
+ rapidBlink?: boolean;
38
39
  reverse?: boolean;
39
40
  conceal?: boolean;
40
41
  strike?: boolean;
41
- underline2?: boolean;
42
+ doubleUnderline?: boolean;
42
43
  frame?: boolean;
43
44
  encircle?: boolean;
44
45
  overline?: boolean;
45
46
  link?: string;
46
47
  meta?: Record<string, unknown>;
47
48
  anchor?: Anchor;
49
+ boxFrame?: object;
50
+ bidi?: BidiStamp;
48
51
  /**
49
52
  * The hold the style's cells are in, both ends or neither: a cell saying
50
53
  * only when it next changes would claim, by default, that it always was,
51
54
  * and a timeline run backwards past its change would never wake for it.
52
55
  * [LAW:types-are-the-program] Absent, the cells never change.
53
56
  */
54
- hold?: Hold;
57
+ validity?: ValidityInterval;
55
58
  }
56
59
  /** A hold: since when a sample has been what it is, and until when it stays so, on one clock. */
57
- export interface Hold {
58
- readonly lastChange: number;
59
- readonly nextChange: number;
60
+ export interface ValidityInterval {
61
+ readonly validFrom: number;
62
+ readonly validUntil: number;
60
63
  }
64
+ /** The hold of a cell that never changes: always was, and always will be. */
65
+ export declare const NEVER_CHANGES: ValidityInterval;
66
+ /** The moments both `a` and `b` hold through: the later `validFrom` and the sooner `validUntil`. */
67
+ export declare function intersection(a: ValidityInterval, b: ValidityInterval): ValidityInterval;
61
68
  export declare class StyleSyntaxError extends Error {
62
69
  constructor(message: string, options?: ErrorOptions);
63
70
  }
@@ -69,11 +76,11 @@ export declare class Style {
69
76
  readonly italic: boolean | undefined;
70
77
  readonly underline: boolean | undefined;
71
78
  readonly blink: boolean | undefined;
72
- readonly blink2: boolean | undefined;
79
+ readonly rapidBlink: boolean | undefined;
73
80
  readonly reverse: boolean | undefined;
74
81
  readonly conceal: boolean | undefined;
75
82
  readonly strike: boolean | undefined;
76
- readonly underline2: boolean | undefined;
83
+ readonly doubleUnderline: boolean | undefined;
77
84
  readonly frame: boolean | undefined;
78
85
  readonly encircle: boolean | undefined;
79
86
  readonly overline: boolean | undefined;
@@ -85,20 +92,37 @@ export declare class Style {
85
92
  * unequal, because they came from different places.
86
93
  */
87
94
  readonly anchor: Anchor | undefined;
95
+ /**
96
+ * The drawing of a box these cells are the frame of (`Box.frame`), compared
97
+ * by identity. A frame is told by what drew it, never by its glyphs, as a
98
+ * strip's seam is (`JOIN`, `./strip.ts`): a box may draw its frame in blanks,
99
+ * and what it draws in ink an element's own content may draw too. It is a
100
+ * drawing and not a box, so two panels of one `ROUNDED` are two frames, and
101
+ * it is no `Anchor`: a frame's cells say whose they are and not where, since
102
+ * a table draws its top rule before it knows its height. It draws nothing.
103
+ */
104
+ readonly boxFrame: object | undefined;
105
+ /**
106
+ * What drawing said of these cells' direction, compared by identity, as a
107
+ * link is a fact the encoder turns into bytes: `Segment` never holds a control
108
+ * the library wrote, so no cut of a row can unbalance one, and what survives a
109
+ * cut still names its stamp (`./seal.ts`). It draws nothing.
110
+ */
111
+ readonly bidi: BidiStamp | undefined;
88
112
  /**
89
113
  * The hold this style's cells are in, on the timeline of whoever drew the
90
- * frame: since when what they show has been what it is (`lastChange`), and
91
- * when it next changes (`nextChange`) — both `t` for a cell drawn by
114
+ * frame: since when what they show has been what it is (`validFrom`), and
115
+ * when it next changes (`validUntil`) — both `t` for a cell drawn by
92
116
  * something that moves every frame, and `-Infinity`/`Infinity` for one
93
117
  * that never changes. It draws nothing. Whatever draws for a handed time
94
118
  * stamps its cells with it (`placedRender`, `Effected`), the stamp rides up
95
119
  * through every container as the anchor does (`./anchor.ts`), and whoever
96
- * holds the composed frame reads it off (`Segment.nextChange`, and
97
- * `Segment.lastChange` for a host running its timeline backwards), so a
120
+ * holds the composed frame reads it off (`Segment.validUntil`, and
121
+ * `Segment.validFrom` for a host running its timeline backwards), so a
98
122
  * host knows when to draw again without asking each container. Two styles
99
123
  * laid together are in the intersection of their holds.
100
124
  */
101
- readonly hold: Hold;
125
+ readonly validity: ValidityInterval;
102
126
  constructor(options?: StyleOptions);
103
127
  get isNull(): boolean;
104
128
  get transparentBackground(): boolean;
@@ -117,6 +141,10 @@ export declare class Style {
117
141
  * The same look, drawn from the place `anchor` names, or from nowhere.
118
142
  */
119
143
  withAnchor(anchor: Anchor | undefined): Style;
144
+ /** The same look, as the frame of the drawing `boxFrame` names, or of none. */
145
+ withBoxFrame(boxFrame: object | undefined): Style;
146
+ /** The same look, its cells' direction as `bidi` says. */
147
+ withBidi(bidi: BidiStamp | undefined): Style;
120
148
  /** The style's text attributes, each as it sets it. */
121
149
  get attributes(): Attributes;
122
150
  /**
@@ -126,7 +154,7 @@ export declare class Style {
126
154
  withAttributes(attributes: Partial<Attributes>): Style;
127
155
  /**
128
156
  * This style with its motion taken out, what reduced motion draws: `blink`
129
- * and `blink2`, the motion a terminal makes on its own, unset, and every
157
+ * and `rapidBlink`, the motion a terminal makes on its own, unset, and every
130
158
  * other field as it was. A style that does not blink is its own.
131
159
  */
132
160
  reduced(): Style;
@@ -141,7 +169,7 @@ export declare class Style {
141
169
  add(other: Style | undefined): Style;
142
170
  equals(other: Style): boolean;
143
171
  /**
144
- * The colours this style puts on screen at `colorSystem`: each flattened
172
+ * The colors this style puts on screen at `colorSystem`: each flattened
145
173
  * onto what lies beneath it — the background onto the terminal's black, the
146
174
  * foreground onto that background — then downgraded to the depth. The one
147
175
  * account of what a style draws: `toSgrCodes` encodes exactly these, and a
@@ -162,8 +190,8 @@ export declare class Style {
162
190
  toSgrCodes(colorSystem: ColorDepth): string;
163
191
  /**
164
192
  * The look as a canonical string that round-trips through `Style.parse()`:
165
- * colours, attributes and the link, which is all a style string can spell.
166
- * What a style carries beyond its look — `meta`, `anchor`, `hold` —
193
+ * colors, attributes and the link, which is all a style string can spell.
194
+ * What a style carries beyond its look — `meta`, `anchor`, `boxFrame`, `bidi`, `hold` —
167
195
  * has no spelling and is not here, so two styles that differ only there
168
196
  * read alike; `equals` tells them apart.
169
197
  */