@promptctl/rich-js 0.23.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/THIRD-PARTY-NOTICES +29 -1
  2. package/dist/core/animation.d.ts +78 -0
  3. package/dist/core/animation.js +107 -0
  4. package/dist/core/cell-widths.d.ts +9 -0
  5. package/dist/core/cell-widths.js +140 -0
  6. package/dist/core/cells.d.ts +17 -11
  7. package/dist/core/cells.js +100 -25
  8. package/dist/core/clock.d.ts +9 -1
  9. package/dist/core/clock.js +22 -2
  10. package/dist/core/color.d.ts +10 -0
  11. package/dist/core/color.js +36 -1
  12. package/dist/core/console.js +5 -5
  13. package/dist/core/easing.d.ts +138 -7
  14. package/dist/core/easing.js +355 -17
  15. package/dist/core/json.js +2 -1
  16. package/dist/core/measure.js +2 -2
  17. package/dist/core/place.js +2 -1
  18. package/dist/core/pretty.js +2 -2
  19. package/dist/core/protocol.d.ts +73 -19
  20. package/dist/core/protocol.js +56 -15
  21. package/dist/core/render.js +2 -1
  22. package/dist/core/segment.d.ts +28 -1
  23. package/dist/core/segment.js +60 -44
  24. package/dist/core/strip.d.ts +107 -29
  25. package/dist/core/strip.js +242 -131
  26. package/dist/core/style.d.ts +18 -1
  27. package/dist/core/style.js +49 -9
  28. package/dist/core/text.js +26 -15
  29. package/dist/core/timeline.d.ts +84 -0
  30. package/dist/core/timeline.js +144 -0
  31. package/dist/core/tween.d.ts +49 -0
  32. package/dist/core/tween.js +69 -0
  33. package/dist/host/app.js +4 -6
  34. package/dist/host/index.d.ts +1 -1
  35. package/dist/host/input.d.ts +37 -13
  36. package/dist/host/input.js +146 -56
  37. package/dist/host/terminal-host.d.ts +16 -0
  38. package/dist/host/terminal-host.js +1 -0
  39. package/dist/index.d.ts +16 -11
  40. package/dist/index.js +15 -5
  41. package/dist/node/terminal-host.d.ts +8 -1
  42. package/dist/node/terminal-host.js +2 -0
  43. package/dist/renderables/align.d.ts +3 -2
  44. package/dist/renderables/align.js +3 -0
  45. package/dist/renderables/columns.d.ts +3 -2
  46. package/dist/renderables/columns.js +7 -2
  47. package/dist/renderables/constrain.d.ts +3 -2
  48. package/dist/renderables/constrain.js +5 -1
  49. package/dist/renderables/effect.d.ts +83 -30
  50. package/dist/renderables/effect.js +155 -57
  51. package/dist/renderables/effects.d.ts +88 -39
  52. package/dist/renderables/effects.js +444 -105
  53. package/dist/renderables/embed.d.ts +10 -0
  54. package/dist/renderables/embed.js +18 -9
  55. package/dist/renderables/flexStrip.d.ts +3 -2
  56. package/dist/renderables/flexStrip.js +6 -1
  57. package/dist/renderables/frames.d.ts +116 -0
  58. package/dist/renderables/frames.js +133 -0
  59. package/dist/renderables/group.d.ts +3 -2
  60. package/dist/renderables/group.js +5 -2
  61. package/dist/renderables/html-entities.d.ts +8 -0
  62. package/dist/renderables/html-entities.js +386 -0
  63. package/dist/renderables/layout.d.ts +3 -2
  64. package/dist/renderables/layout.js +15 -2
  65. package/dist/renderables/list-view.d.ts +3 -2
  66. package/dist/renderables/list-view.js +12 -5
  67. package/dist/renderables/live.d.ts +23 -7
  68. package/dist/renderables/live.js +69 -35
  69. package/dist/renderables/markdown-parse.d.ts +109 -0
  70. package/dist/renderables/markdown-parse.js +1421 -0
  71. package/dist/renderables/markdown-url.d.ts +19 -0
  72. package/dist/renderables/markdown-url.js +314 -0
  73. package/dist/renderables/markdown.d.ts +7 -6
  74. package/dist/renderables/markdown.js +363 -499
  75. package/dist/renderables/padding.d.ts +8 -20
  76. package/dist/renderables/padding.js +32 -50
  77. package/dist/renderables/panel.d.ts +26 -26
  78. package/dist/renderables/panel.js +67 -103
  79. package/dist/renderables/progress.d.ts +5 -3
  80. package/dist/renderables/progress.js +14 -3
  81. package/dist/renderables/progressBar.js +4 -4
  82. package/dist/renderables/python-space.d.ts +13 -0
  83. package/dist/renderables/python-space.js +24 -0
  84. package/dist/renderables/spinner.d.ts +73 -27
  85. package/dist/renderables/spinner.js +110 -51
  86. package/dist/renderables/status.d.ts +8 -3
  87. package/dist/renderables/status.js +8 -5
  88. package/dist/renderables/syntax.js +2 -1
  89. package/dist/renderables/table.d.ts +19 -11
  90. package/dist/renderables/table.js +140 -156
  91. package/dist/renderables/traceback.d.ts +1 -1
  92. package/dist/renderables/traceback.js +6 -5
  93. package/dist/renderables/tree.d.ts +6 -5
  94. package/dist/renderables/tree.js +11 -7
  95. package/dist/renderables/viewport.d.ts +13 -5
  96. package/dist/renderables/viewport.js +41 -20
  97. package/dist/template-bindings/animation-funcs.d.ts +37 -0
  98. package/dist/template-bindings/animation-funcs.js +83 -0
  99. package/dist/template-bindings/color-funcs.d.ts +13 -0
  100. package/dist/template-bindings/color-funcs.js +1 -1
  101. package/dist/template-bindings/helpers.d.ts +6 -0
  102. package/dist/template-bindings/helpers.js +12 -3
  103. package/dist/template-bindings/index.d.ts +6 -2
  104. package/dist/template-bindings/index.js +8 -3
  105. package/dist/themes/ramp.d.ts +18 -3
  106. package/dist/themes/ramp.js +23 -2
  107. package/dist/widgets/focus-manager.d.ts +21 -14
  108. package/dist/widgets/focus-manager.js +28 -29
  109. package/dist/widgets/index.d.ts +1 -1
  110. package/dist/widgets/static-item.d.ts +4 -3
  111. package/dist/widgets/static-item.js +9 -7
  112. package/dist/widgets/text-input.d.ts +28 -18
  113. package/dist/widgets/text-input.js +144 -101
  114. package/dist/widgets/widget-app.d.ts +19 -3
  115. package/dist/widgets/widget-app.js +39 -21
  116. package/dist/widgets/widget-base.js +0 -3
  117. package/package.json +2 -5
@@ -82,6 +82,16 @@ export declare class InlineLabel {
82
82
  */
83
83
  text(options: RenderOptions, base?: TextStyle): RichText;
84
84
  }
85
+ /**
86
+ * `text`, changed in place into a fragment of a line it shares, as Rich's
87
+ * `_title` reads one: its own end is not drawn, newlines become spaces so it
88
+ * stays on its line, and tabs are widened to their stops before anything
89
+ * measures it, so a cut to a border and the width a label asks for count
90
+ * the cells it will draw. [LAW:single-enforcer] The one reading of "set into
91
+ * a line", for a label read through the crossing above and for text a
92
+ * caller hands over already read (`Frames`).
93
+ */
94
+ export declare function setIntoLine(text: RichText): RichText;
85
95
  /**
86
96
  * A label cut to `width` cells as Rich's `Text.truncate` cuts one: its plain
87
97
  * text set to the width less `marker` — a wide character the cut splits leaves
@@ -23,6 +23,7 @@
23
23
  */
24
24
  import { cellCount, cellLen, setCellSize } from "../core/cells.js";
25
25
  import { activeHighlighter, readStr } from "../core/markup.js";
26
+ import { render } from "../core/protocol.js";
26
27
  import { Segment } from "../core/segment.js";
27
28
  import { RichText } from "../core/text.js";
28
29
  /**
@@ -71,7 +72,7 @@ export class EmbeddedText {
71
72
  return text;
72
73
  }
73
74
  render(options) {
74
- return this.text(options).render(options);
75
+ return render(this.text(options), options);
75
76
  }
76
77
  /**
77
78
  * Measured unhighlighted, as Rich's `Measurement.get` reads a string with
@@ -114,15 +115,23 @@ export class InlineLabel {
114
115
  * caller's cut. A string reads with `base` as its style, as `EmbeddedText.text` reads one.
115
116
  */
116
117
  text(options, base) {
117
- const text = this._content.text(options, base);
118
- // A fragment of the line, so its own end is not drawn, as Rich's `_title` clears it.
119
- text.end = "";
120
- text.plain = text.plain.replaceAll("\n", " ");
121
- // Tabs widened before anything measures it, so a cut to the border and
122
- // the width a title asks for count the cells the label will draw.
123
- return text.expandTabs();
118
+ return setIntoLine(this._content.text(options, base));
124
119
  }
125
120
  }
121
+ /**
122
+ * `text`, changed in place into a fragment of a line it shares, as Rich's
123
+ * `_title` reads one: its own end is not drawn, newlines become spaces so it
124
+ * stays on its line, and tabs are widened to their stops before anything
125
+ * measures it, so a cut to a border and the width a label asks for count
126
+ * the cells it will draw. [LAW:single-enforcer] The one reading of "set into
127
+ * a line", for a label read through the crossing above and for text a
128
+ * caller hands over already read (`Frames`).
129
+ */
130
+ export function setIntoLine(text) {
131
+ text.end = "";
132
+ text.plain = text.plain.replaceAll("\n", " ");
133
+ return text.expandTabs();
134
+ }
126
135
  /**
127
136
  * A label cut to `width` cells as Rich's `Text.truncate` cuts one: its plain
128
137
  * text set to the width less `marker` — a wide character the cut splits leaves
@@ -155,7 +164,7 @@ export function present(content) {
155
164
  */
156
165
  export function drawLabel(text, options, base) {
157
166
  text.overflow = "ignore";
158
- return [...Segment.applyStyle(text.render(options), base)];
167
+ return [...Segment.applyStyle(render(text, options), base)];
159
168
  }
160
169
  /**
161
170
  * Caller content as a label, or no label at all: content that is not
@@ -16,7 +16,7 @@
16
16
  * FlexStrip reuses it verbatim. There is no second concept of "join."
17
17
  */
18
18
  import { Segment } from "../core/segment.js";
19
- import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
19
+ import type { Composite, Renderable, Measurable, RenderOptions } from "../core/protocol.js";
20
20
  import { type Joiner, type StyledRenderable } from "../core/strip.js";
21
21
  export type FlexAlign = "left" | "center" | "right" | "justify";
22
22
  export interface FlexStripOptions<T extends StyledRenderable> {
@@ -27,12 +27,13 @@ export interface FlexStripOptions<T extends StyledRenderable> {
27
27
  /** Line alignment when packed items don't fill the available width (default "left"). */
28
28
  align?: FlexAlign;
29
29
  }
30
- export declare class FlexStrip<T extends StyledRenderable = StyledRenderable> implements Renderable, Measurable {
30
+ export declare class FlexStrip<T extends StyledRenderable = StyledRenderable> implements Renderable, Measurable, Composite {
31
31
  readonly items: readonly T[];
32
32
  readonly joiner: Joiner<T> | undefined;
33
33
  readonly gap: number;
34
34
  readonly align: FlexAlign;
35
35
  constructor(items: readonly T[], options?: FlexStripOptions<T>);
36
+ contents(): Iterable<Renderable>;
36
37
  render(options: RenderOptions): Iterable<Segment>;
37
38
  measure(options: RenderOptions): {
38
39
  minimum: number;
@@ -16,9 +16,10 @@
16
16
  * FlexStrip reuses it verbatim. There is no second concept of "join."
17
17
  */
18
18
  import { Segment } from "../core/segment.js";
19
+ import { render } from "../core/protocol.js";
19
20
  import { drawItem, drawJoin } from "../core/strip.js";
20
21
  function renderToBlock(r, options) {
21
- const segments = [...r.render(options)];
22
+ const segments = [...render(r, options)];
22
23
  let width = 0;
23
24
  for (const s of segments)
24
25
  width += s.cellLength;
@@ -55,6 +56,10 @@ export class FlexStrip {
55
56
  this.gap = options?.gap ?? 0;
56
57
  this.align = options?.align ?? "left";
57
58
  }
59
+ // The items; a join is drawn from what the joiner emits for it, not held.
60
+ contents() {
61
+ return this.items;
62
+ }
58
63
  *render(options) {
59
64
  const items = this.items;
60
65
  if (items.length === 0)
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Frames — content that changes on a beat: a sequence of frames, each held
3
+ * for its own seconds and looping, drawn as the one in progress at a time
4
+ * the host hands in.
5
+ *
6
+ * An effect moves a cell's colours and may never change a glyph
7
+ * (`./effect.ts`: "It changes how cells look, never which cells exist or who
8
+ * drew them"). A frame is the other kind of motion — what the element shows
9
+ * changes — so it is its own primitive and not a wider `Effect`, and the two
10
+ * compose by nesting: `new Effected(new Frames(…), …)` lights whichever frame
11
+ * is up.
12
+ *
13
+ * [LAW:no-ambient-temporal-coupling] `t` is an argument, as
14
+ * `Effected`'s is, never a clock read: whoever draws frames hands each one
15
+ * its time (`core/clock.ts`), so the same `t` draws the same bytes at one
16
+ * redraw a second or sixty. The host's rate is the host's. At sixty a frame
17
+ * shows for exactly its hold; at one a second a hold shorter than a second is
18
+ * skipped and a period of whole seconds freezes on one frame, and nothing
19
+ * here adapts to that — the beat is `core/easing.ts`'s, the one timing
20
+ * vocabulary, and a draw costs the same at `t = 0` and `t = 10⁶`.
21
+ *
22
+ * The sequence and the moment are two values, because only one of them
23
+ * changes from frame to frame. A `FrameSequence` is the frames prepared once
24
+ * — the beat, the one width, each frame set into a line and padded — and an
25
+ * `Animation` of the frame shown (`core/animation.ts`); a `Frames` is that
26
+ * sequence at a `t`, whose work is one frame's — finding which, and copying
27
+ * it: a host holds the sequence and asks it for a frame, as `Spinner` holds
28
+ * its two, so a draw costs the same over ninety frames as over one. The
29
+ * sequence is a value the host keeps, not a memo here: nothing is looked up
30
+ * by key.
31
+ *
32
+ * The frame drawn is drawn until the next begins, and its cells say so: they
33
+ * are stamped with the sequence's `nextChange` (`Style.nextChange`), which
34
+ * rides up through every container to whoever holds the composed frame
35
+ * (`Segment.nextChange`), so a host drawing at `t` knows when to draw again,
36
+ * and one drawing slower than the frames turn can see that it is skipping
37
+ * them. The stamp is put on by whoever draws the frame at a host time
38
+ * (`frameAt`) — a `Frames`, a `Spinner`, the template `frames` function —
39
+ * and the sequence's `at` hands over the frame alone, because the time a
40
+ * sequence is asked for may be one a `Timeline` mapped from the host's.
41
+ *
42
+ * Every frame is drawn at one width, the widest frame's, each padded on the
43
+ * right to it, so whatever sits beside the frames never moves as they turn;
44
+ * and the frame is a fragment of a line (`setIntoLine`), ending no line of
45
+ * its own, so it sits among other cells. Frames are `RichText`, each free to
46
+ * carry its own style, and read once, here: markup is a string's reading
47
+ * under the console that draws it, which a frame handed to a template
48
+ * binding has no console for, so the frame arrives read, as a `Group`'s
49
+ * children do.
50
+ */
51
+ import type { Animation } from "../core/animation.js";
52
+ import { type Beat } from "../core/easing.js";
53
+ import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
54
+ import type { Segment } from "../core/segment.js";
55
+ import type { RichText } from "../core/text.js";
56
+ /** One frame: what it shows, and how long it is held, in seconds. */
57
+ export interface Frame {
58
+ readonly text: RichText;
59
+ readonly seconds: number;
60
+ }
61
+ /** A sequence of frames prepared to be drawn: built once, asked for the frame at a time. */
62
+ export declare class FrameSequence implements Animation<RichText> {
63
+ /** Which frame is in progress when: the holds are the frames' seconds, in order. */
64
+ readonly beat: Beat;
65
+ /** The width every frame draws at: the widest frame's, in cells. */
66
+ readonly width: number;
67
+ private readonly _shown;
68
+ constructor(frames: readonly Frame[]);
69
+ /**
70
+ * The frame in progress at `t`, at `width` cells, ending no line: a copy,
71
+ * the caller's to change, carrying no word on when it changes — that is
72
+ * `frameAt`'s, stamped by whoever draws it at a host time. `beat.at`
73
+ * refuses a `t` that is not finite.
74
+ */
75
+ at(t: number): RichText;
76
+ /** When the frame in progress at `t` gives way to the next: the beat's answer, its holds being the frames'. */
77
+ nextChange(t: number): number;
78
+ /** When the frame in progress at `t` began: the beat's answer. */
79
+ lastChange(t: number): number;
80
+ }
81
+ /**
82
+ * The frame `animation` shows at host time `t`, its every cell — padding
83
+ * included, so a blank frame among drawn ones still turns — stamped with when
84
+ * it gives way to the next, `animation.nextChange(t)`. [LAW:one-source-of-truth]
85
+ * The stamp is that one answer carried on the cells (`Segment.nextChange`),
86
+ * so a container holding the frame passes it up without asking the
87
+ * animation; and it is put on here, where the host's time is known, and not
88
+ * in the animation's `at`, whose own time a `Timeline` or an
89
+ * `Animation.sequence` may have mapped from the host's — a stamp made there
90
+ * would be a moment on a clock the host cannot read. A copy is stamped, the
91
+ * caller's to change: an animation may hand back the one `RichText` it
92
+ * holds, as `Animation.constant` does, and a stamp on that would outlive
93
+ * the draw it was true for.
94
+ */
95
+ export declare function frameAt(animation: Animation<RichText>, t: number): RichText;
96
+ export interface FramesOptions {
97
+ /** The moment to draw, in seconds. */
98
+ readonly t: number;
99
+ }
100
+ /** A sequence's frame in progress at one moment, as a renderable. */
101
+ export declare class Frames implements Renderable, Measurable {
102
+ readonly sequence: FrameSequence;
103
+ readonly t: number;
104
+ private readonly _shown;
105
+ constructor(sequence: FrameSequence, options: FramesOptions);
106
+ render(options: RenderOptions): Iterable<Segment>;
107
+ /**
108
+ * One width both ways: a frame is one picture, never wrapped apart at a
109
+ * space or narrowed as the frames turn. Fitting it to the room is
110
+ * `Measurement.get`'s, as for every measurable.
111
+ */
112
+ measure(): {
113
+ minimum: number;
114
+ maximum: number;
115
+ };
116
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Frames — content that changes on a beat: a sequence of frames, each held
3
+ * for its own seconds and looping, drawn as the one in progress at a time
4
+ * the host hands in.
5
+ *
6
+ * An effect moves a cell's colours and may never change a glyph
7
+ * (`./effect.ts`: "It changes how cells look, never which cells exist or who
8
+ * drew them"). A frame is the other kind of motion — what the element shows
9
+ * changes — so it is its own primitive and not a wider `Effect`, and the two
10
+ * compose by nesting: `new Effected(new Frames(…), …)` lights whichever frame
11
+ * is up.
12
+ *
13
+ * [LAW:no-ambient-temporal-coupling] `t` is an argument, as
14
+ * `Effected`'s is, never a clock read: whoever draws frames hands each one
15
+ * its time (`core/clock.ts`), so the same `t` draws the same bytes at one
16
+ * redraw a second or sixty. The host's rate is the host's. At sixty a frame
17
+ * shows for exactly its hold; at one a second a hold shorter than a second is
18
+ * skipped and a period of whole seconds freezes on one frame, and nothing
19
+ * here adapts to that — the beat is `core/easing.ts`'s, the one timing
20
+ * vocabulary, and a draw costs the same at `t = 0` and `t = 10⁶`.
21
+ *
22
+ * The sequence and the moment are two values, because only one of them
23
+ * changes from frame to frame. A `FrameSequence` is the frames prepared once
24
+ * — the beat, the one width, each frame set into a line and padded — and an
25
+ * `Animation` of the frame shown (`core/animation.ts`); a `Frames` is that
26
+ * sequence at a `t`, whose work is one frame's — finding which, and copying
27
+ * it: a host holds the sequence and asks it for a frame, as `Spinner` holds
28
+ * its two, so a draw costs the same over ninety frames as over one. The
29
+ * sequence is a value the host keeps, not a memo here: nothing is looked up
30
+ * by key.
31
+ *
32
+ * The frame drawn is drawn until the next begins, and its cells say so: they
33
+ * are stamped with the sequence's `nextChange` (`Style.nextChange`), which
34
+ * rides up through every container to whoever holds the composed frame
35
+ * (`Segment.nextChange`), so a host drawing at `t` knows when to draw again,
36
+ * and one drawing slower than the frames turn can see that it is skipping
37
+ * them. The stamp is put on by whoever draws the frame at a host time
38
+ * (`frameAt`) — a `Frames`, a `Spinner`, the template `frames` function —
39
+ * and the sequence's `at` hands over the frame alone, because the time a
40
+ * sequence is asked for may be one a `Timeline` mapped from the host's.
41
+ *
42
+ * Every frame is drawn at one width, the widest frame's, each padded on the
43
+ * right to it, so whatever sits beside the frames never moves as they turn;
44
+ * and the frame is a fragment of a line (`setIntoLine`), ending no line of
45
+ * its own, so it sits among other cells. Frames are `RichText`, each free to
46
+ * carry its own style, and read once, here: markup is a string's reading
47
+ * under the console that draws it, which a frame handed to a template
48
+ * binding has no console for, so the frame arrives read, as a `Group`'s
49
+ * children do.
50
+ */
51
+ import { beat } from "../core/easing.js";
52
+ import { render } from "../core/protocol.js";
53
+ import { Style } from "../core/style.js";
54
+ import { setIntoLine } from "./embed.js";
55
+ /** A sequence of frames prepared to be drawn: built once, asked for the frame at a time. */
56
+ export class FrameSequence {
57
+ /** Which frame is in progress when: the holds are the frames' seconds, in order. */
58
+ beat;
59
+ /** The width every frame draws at: the widest frame's, in cells. */
60
+ width;
61
+ // Each frame as it draws: a line fragment padded to `width`, made once.
62
+ _shown;
63
+ constructor(frames) {
64
+ this.beat = beat(frames.map((frame) => frame.seconds));
65
+ const texts = frames.map((frame) => setIntoLine(frame.text.copy()));
66
+ const widths = texts.map((text) => text.cellLength);
67
+ this.width = Math.max(...widths);
68
+ this._shown = texts.map((text, i) => {
69
+ // One picture: a slot narrower than the frame crops it, never folds
70
+ // or wraps it onto a second line, which `Frames.measure` says it cannot take.
71
+ text.noWrap = true;
72
+ text.overflow = "crop";
73
+ return text.padRight(this.width - widths[i]);
74
+ });
75
+ }
76
+ /**
77
+ * The frame in progress at `t`, at `width` cells, ending no line: a copy,
78
+ * the caller's to change, carrying no word on when it changes — that is
79
+ * `frameAt`'s, stamped by whoever draws it at a host time. `beat.at`
80
+ * refuses a `t` that is not finite.
81
+ */
82
+ at(t) {
83
+ return this._shown[this.beat.at(t)].copy();
84
+ }
85
+ /** When the frame in progress at `t` gives way to the next: the beat's answer, its holds being the frames'. */
86
+ nextChange(t) {
87
+ return this.beat.nextChange(t);
88
+ }
89
+ /** When the frame in progress at `t` began: the beat's answer. */
90
+ lastChange(t) {
91
+ return this.beat.lastChange(t);
92
+ }
93
+ }
94
+ /**
95
+ * The frame `animation` shows at host time `t`, its every cell — padding
96
+ * included, so a blank frame among drawn ones still turns — stamped with when
97
+ * it gives way to the next, `animation.nextChange(t)`. [LAW:one-source-of-truth]
98
+ * The stamp is that one answer carried on the cells (`Segment.nextChange`),
99
+ * so a container holding the frame passes it up without asking the
100
+ * animation; and it is put on here, where the host's time is known, and not
101
+ * in the animation's `at`, whose own time a `Timeline` or an
102
+ * `Animation.sequence` may have mapped from the host's — a stamp made there
103
+ * would be a moment on a clock the host cannot read. A copy is stamped, the
104
+ * caller's to change: an animation may hand back the one `RichText` it
105
+ * holds, as `Animation.constant` does, and a stamp on that would outlive
106
+ * the draw it was true for.
107
+ */
108
+ export function frameAt(animation, t) {
109
+ return animation.at(t).copy().stylize(new Style({ nextChange: animation.nextChange(t) }));
110
+ }
111
+ /** A sequence's frame in progress at one moment, as a renderable. */
112
+ export class Frames {
113
+ sequence;
114
+ t;
115
+ // The frame `t` lands on, found once, here, so a bad time fails at construction.
116
+ _shown;
117
+ constructor(sequence, options) {
118
+ this.sequence = sequence;
119
+ this.t = options.t;
120
+ this._shown = frameAt(sequence, options.t);
121
+ }
122
+ render(options) {
123
+ return render(this._shown, options);
124
+ }
125
+ /**
126
+ * One width both ways: a frame is one picture, never wrapped apart at a
127
+ * space or narrowed as the frames turn. Fitting it to the room is
128
+ * `Measurement.get`'s, as for every measurable.
129
+ */
130
+ measure() {
131
+ return { minimum: this.sequence.width, maximum: this.sequence.width };
132
+ }
133
+ }
@@ -4,11 +4,12 @@
4
4
  */
5
5
  import type { Segment } from "../core/segment.js";
6
6
  import { type Measurement } from "../core/measure.js";
7
- import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
8
- export declare class Group implements Renderable, Measurable {
7
+ import type { Composite, Measurable, Renderable, RenderOptions } from "../core/protocol.js";
8
+ export declare class Group implements Renderable, Measurable, Composite {
9
9
  readonly renderables: Renderable[];
10
10
  constructor(...renderables: Renderable[]);
11
11
  render(options: RenderOptions): Iterable<Segment>;
12
12
  /** As wide as its widest member: the reference's `measure_renderables`. */
13
13
  measure(options: RenderOptions): Measurement;
14
+ contents(): Iterable<Renderable>;
14
15
  }
@@ -3,7 +3,7 @@
3
3
  * No visual chrome — purely a container.
4
4
  */
5
5
  import { measureRenderables } from "../core/measure.js";
6
- import { stackedHeight } from "../core/protocol.js";
6
+ import { render, stackedHeight } from "../core/protocol.js";
7
7
  export class Group {
8
8
  renderables;
9
9
  constructor(...renderables) {
@@ -12,11 +12,14 @@ export class Group {
12
12
  *render(options) {
13
13
  const memberOptions = { ...options, height: stackedHeight(options.height) };
14
14
  for (const renderable of this.renderables) {
15
- yield* renderable.render(memberOptions);
15
+ yield* render(renderable, memberOptions);
16
16
  }
17
17
  }
18
18
  /** As wide as its widest member: the reference's `measure_renderables`. */
19
19
  measure(options) {
20
20
  return measureRenderables(options, this.renderables);
21
21
  }
22
+ contents() {
23
+ return this.renderables;
24
+ }
22
25
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * HTML's named character references, each name without its `;`, to the
3
+ * characters it stands for — the table markdown-it-py, Rich's parser, decodes
4
+ * with. Generated by scripts/html-entities.py from Python's
5
+ * `html.entities.html5`; regenerate rather than edit.
6
+ */
7
+ /** The characters `name`, a reference's name without its `&` and `;`, stands for, if it names any. */
8
+ export declare function namedReference(name: string): string | undefined;