@promptctl/rich-js 0.24.0 → 0.25.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.
- package/README.md +7 -0
- package/THIRD-PARTY-NOTICES +29 -1
- package/dist/core/anchor.d.ts +5 -0
- package/dist/core/anchor.js +11 -4
- package/dist/core/animation.d.ts +243 -0
- package/dist/core/animation.js +375 -0
- package/dist/core/ansi.js +2 -2
- package/dist/core/box.d.ts +7 -7
- package/dist/core/cell-widths.d.ts +9 -0
- package/dist/core/cell-widths.js +140 -0
- package/dist/core/cells.d.ts +40 -24
- package/dist/core/cells.js +151 -66
- package/dist/core/clock.d.ts +2 -2
- package/dist/core/clock.js +6 -4
- package/dist/core/color.d.ts +27 -10
- package/dist/core/color.js +21 -29
- package/dist/core/console.d.ts +28 -17
- package/dist/core/console.js +48 -43
- package/dist/core/easing.d.ts +140 -10
- package/dist/core/easing.js +328 -50
- package/dist/core/emoji.d.ts +1 -1
- package/dist/core/emoji.js +1 -2
- package/dist/core/export-html.js +2 -1
- package/dist/core/export-lines.js +3 -3
- package/dist/core/highlighter.d.ts +9 -8
- package/dist/core/highlighter.js +3 -2
- package/dist/core/json.js +3 -2
- package/dist/core/markup.js +16 -12
- package/dist/core/measure.js +3 -3
- package/dist/core/memo.d.ts +11 -2
- package/dist/core/memo.js +16 -0
- package/dist/core/oklch.js +17 -6
- package/dist/core/osc8.d.ts +1 -1
- package/dist/core/osc8.js +4 -5
- package/dist/core/paint.d.ts +2 -1
- package/dist/core/paint.js +4 -3
- package/dist/core/pattern.d.ts +21 -0
- package/dist/core/pattern.js +21 -0
- package/dist/core/place.js +2 -1
- package/dist/core/pretty.js +11 -12
- package/dist/core/protocol.d.ts +136 -21
- package/dist/core/protocol.js +203 -16
- package/dist/core/render.d.ts +15 -2
- package/dist/core/render.js +27 -6
- package/dist/core/segment.d.ts +31 -6
- package/dist/core/segment.js +68 -53
- package/dist/core/spinnerData.d.ts +1 -1
- package/dist/core/state.d.ts +53 -0
- package/dist/core/state.js +82 -0
- package/dist/core/strip.d.ts +11 -13
- package/dist/core/strip.js +126 -113
- package/dist/core/style.d.ts +47 -14
- package/dist/core/style.js +74 -34
- package/dist/core/text.d.ts +5 -8
- package/dist/core/text.js +133 -133
- package/dist/core/timeline.d.ts +109 -0
- package/dist/core/timeline.js +180 -0
- package/dist/core/tween.d.ts +49 -0
- package/dist/core/tween.js +71 -0
- package/dist/core/view.d.ts +92 -0
- package/dist/core/view.js +83 -0
- package/dist/host/app.d.ts +49 -21
- package/dist/host/app.js +72 -38
- package/dist/host/input.js +3 -4
- package/dist/index.d.ts +30 -15
- package/dist/index.js +20 -6
- package/dist/node/traceback.js +4 -3
- package/dist/renderables/change.d.ts +42 -0
- package/dist/renderables/change.js +112 -0
- package/dist/renderables/columns.d.ts +1 -1
- package/dist/renderables/columns.js +3 -3
- package/dist/renderables/constrain.js +2 -1
- package/dist/renderables/effect.d.ts +155 -92
- package/dist/renderables/effect.js +203 -136
- package/dist/renderables/effects.d.ts +137 -24
- package/dist/renderables/effects.js +276 -113
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +18 -9
- package/dist/renderables/flexStrip.js +2 -1
- package/dist/renderables/frames.d.ts +45 -43
- package/dist/renderables/frames.js +57 -45
- package/dist/renderables/glyph-effect.d.ts +158 -0
- package/dist/renderables/glyph-effect.js +237 -0
- package/dist/renderables/glyph-effects.d.ts +147 -0
- package/dist/renderables/glyph-effects.js +283 -0
- package/dist/renderables/group.d.ts +1 -1
- package/dist/renderables/group.js +2 -2
- package/dist/renderables/html-entities.d.ts +8 -0
- package/dist/renderables/html-entities.js +386 -0
- package/dist/renderables/layout.d.ts +10 -9
- package/dist/renderables/layout.js +42 -35
- package/dist/renderables/lifecycle.d.ts +77 -0
- package/dist/renderables/lifecycle.js +132 -0
- package/dist/renderables/list-view.d.ts +2 -2
- package/dist/renderables/list-view.js +11 -8
- package/dist/renderables/live.d.ts +36 -21
- package/dist/renderables/live.js +89 -42
- package/dist/renderables/markdown-parse.d.ts +109 -0
- package/dist/renderables/markdown-parse.js +1427 -0
- package/dist/renderables/markdown-url.d.ts +19 -0
- package/dist/renderables/markdown-url.js +314 -0
- package/dist/renderables/markdown.d.ts +5 -7
- package/dist/renderables/markdown.js +356 -683
- package/dist/renderables/padding.d.ts +7 -20
- package/dist/renderables/padding.js +29 -50
- package/dist/renderables/panel.d.ts +30 -32
- package/dist/renderables/panel.js +65 -109
- package/dist/renderables/progress.d.ts +83 -32
- package/dist/renderables/progress.js +186 -90
- package/dist/renderables/progressBar.d.ts +22 -12
- package/dist/renderables/progressBar.js +33 -10
- package/dist/renderables/prompt.js +3 -2
- package/dist/renderables/python-space.d.ts +13 -0
- package/dist/renderables/python-space.js +25 -0
- package/dist/renderables/scroll.d.ts +50 -0
- package/dist/renderables/scroll.js +106 -0
- package/dist/renderables/spinner.d.ts +57 -24
- package/dist/renderables/spinner.js +101 -49
- package/dist/renderables/status.js +1 -1
- package/dist/renderables/syntax.d.ts +10 -9
- package/dist/renderables/syntax.js +5 -3
- package/dist/renderables/table.d.ts +48 -46
- package/dist/renderables/table.js +170 -208
- package/dist/renderables/traceback.d.ts +3 -3
- package/dist/renderables/traceback.js +12 -10
- package/dist/renderables/tree.d.ts +28 -25
- package/dist/renderables/tree.js +108 -58
- package/dist/renderables/viewport.d.ts +77 -38
- package/dist/renderables/viewport.js +156 -72
- package/dist/template-bindings/animation-funcs.d.ts +78 -9
- package/dist/template-bindings/animation-funcs.js +132 -14
- package/dist/template-bindings/index.d.ts +5 -5
- package/dist/template-bindings/index.js +7 -6
- package/dist/themes/ramp.d.ts +62 -4
- package/dist/themes/ramp.js +82 -4
- package/dist/themes/registry.js +5 -7
- package/dist/widgets/button.js +3 -2
- package/dist/widgets/checkbox.js +4 -3
- package/dist/widgets/dropdown.d.ts +3 -1
- package/dist/widgets/dropdown.js +20 -15
- package/dist/widgets/event-router.js +4 -2
- package/dist/widgets/focus-manager.d.ts +23 -14
- package/dist/widgets/focus-manager.js +34 -33
- package/dist/widgets/hit.d.ts +6 -0
- package/dist/widgets/hit.js +8 -1
- package/dist/widgets/index.d.ts +1 -1
- package/dist/widgets/observable.d.ts +23 -0
- package/dist/widgets/observable.js +43 -0
- package/dist/widgets/slider.d.ts +1 -1
- package/dist/widgets/slider.js +12 -3
- package/dist/widgets/static-item.d.ts +1 -1
- package/dist/widgets/static-item.js +6 -7
- package/dist/widgets/text-input.d.ts +53 -47
- package/dist/widgets/text-input.js +456 -399
- package/dist/widgets/themed-widget.js +2 -1
- package/dist/widgets/toggle.js +4 -3
- package/dist/widgets/types.d.ts +10 -4
- package/dist/widgets/types.js +8 -2
- package/dist/widgets/widget-app.d.ts +32 -6
- package/dist/widgets/widget-app.js +74 -27
- package/dist/widgets/widget-base.d.ts +2 -2
- package/dist/widgets/widget-base.js +29 -21
- package/package.json +9 -5
package/dist/core/console.d.ts
CHANGED
|
@@ -59,6 +59,15 @@ export interface ConsoleOptions {
|
|
|
59
59
|
* renderable this console draws. Default false.
|
|
60
60
|
*/
|
|
61
61
|
asciiOnly?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* The reader asked for reduced motion: every animation this console draws
|
|
64
|
+
* — through `print`, a `Live` or an `App` — is drawn with its motion taken
|
|
65
|
+
* out, waking its host only where content changes
|
|
66
|
+
* (`RenderOptions.reducedMotion`). A preference of the
|
|
67
|
+
* person at the terminal, which no terminal reports, so the program hands
|
|
68
|
+
* it in; nothing here reads the environment for it. Default false.
|
|
69
|
+
*/
|
|
70
|
+
reducedMotion?: boolean;
|
|
62
71
|
/**
|
|
63
72
|
* Static width (cells). Ignored when `getSize` is provided. Falls back to
|
|
64
73
|
* the `COLUMNS` env var / the bound stream's `columns` / 80.
|
|
@@ -127,24 +136,25 @@ export interface PrintOptions {
|
|
|
127
136
|
}
|
|
128
137
|
export declare class Console {
|
|
129
138
|
private readonly _destination;
|
|
130
|
-
private _getSize;
|
|
139
|
+
private readonly _getSize;
|
|
131
140
|
private readonly _getDatetime;
|
|
132
|
-
private _lastLogTime;
|
|
133
|
-
private _style;
|
|
134
|
-
private _isTerminal;
|
|
141
|
+
private readonly _lastLogTime;
|
|
142
|
+
private readonly _style;
|
|
143
|
+
private readonly _isTerminal;
|
|
135
144
|
private readonly _interactive;
|
|
136
|
-
private _file;
|
|
137
|
-
private _stream;
|
|
138
|
-
private _record;
|
|
139
|
-
private _markup;
|
|
140
|
-
private _highlight;
|
|
141
|
-
private _theme;
|
|
142
|
-
private _onStyleError;
|
|
145
|
+
private readonly _file;
|
|
146
|
+
private readonly _stream;
|
|
147
|
+
private readonly _record;
|
|
148
|
+
private readonly _markup;
|
|
149
|
+
private readonly _highlight;
|
|
150
|
+
private readonly _theme;
|
|
151
|
+
private readonly _onStyleError;
|
|
143
152
|
private readonly _asciiOnly;
|
|
144
|
-
private _highlighter;
|
|
145
|
-
private _recorded;
|
|
146
|
-
private _capture;
|
|
147
|
-
private _liveRegion;
|
|
153
|
+
private readonly _highlighter;
|
|
154
|
+
private readonly _recorded;
|
|
155
|
+
private readonly _capture;
|
|
156
|
+
private readonly _liveRegion;
|
|
157
|
+
private readonly _madeIn;
|
|
148
158
|
constructor(options?: ConsoleOptions);
|
|
149
159
|
get size(): {
|
|
150
160
|
width: number;
|
|
@@ -156,8 +166,9 @@ export declare class Console {
|
|
|
156
166
|
get isInteractive(): boolean;
|
|
157
167
|
get colorSystem(): ColorDepth | null;
|
|
158
168
|
/**
|
|
159
|
-
* Where this console writes: the colour depth it draws at
|
|
160
|
-
* emits OSC 8 hyperlinks,
|
|
169
|
+
* Where this console writes: the colour depth it draws at, whether it
|
|
170
|
+
* emits OSC 8 hyperlinks, and whether its reader asked for reduced motion,
|
|
171
|
+
* overrides applied — the value its output is
|
|
161
172
|
* encoded for, for anything that encodes on its behalf (`Live`).
|
|
162
173
|
*/
|
|
163
174
|
get destination(): Destination;
|
package/dist/core/console.js
CHANGED
|
@@ -16,9 +16,10 @@ import { ReprHighlighter, NullHighlighter } from "./highlighter.js";
|
|
|
16
16
|
// orchestrator reaching down for `Rule`. `RuleOptions` rides the same edge
|
|
17
17
|
// rather than being restated here; see `rule()`.
|
|
18
18
|
import { Rule } from "../renderables/rule.js";
|
|
19
|
-
import { segmentsToString } from "./render.js";
|
|
19
|
+
import { segmentsToString, shownOn } from "./render.js";
|
|
20
20
|
import { placeBlock } from "./place.js";
|
|
21
|
-
import { isRenderable } from "./protocol.js";
|
|
21
|
+
import { activePass, isRenderable, measure, render } from "./protocol.js";
|
|
22
|
+
import { ListState, State, refuseRenderWrite } from "./state.js";
|
|
22
23
|
// [LAW:dataflow-not-control-flow] With no live region claimed, stepping around
|
|
23
24
|
// it is the text itself: every write takes the same path.
|
|
24
25
|
const NO_LIVE_REGION = { around: (text) => text };
|
|
@@ -67,11 +68,11 @@ class TextRun {
|
|
|
67
68
|
this.text = items.reduce((joined, item) => joined.append(item), new RichText("", { end: "" }));
|
|
68
69
|
}
|
|
69
70
|
*render(options) {
|
|
70
|
-
yield* this.text
|
|
71
|
+
yield* render(this.text, options);
|
|
71
72
|
yield this.end;
|
|
72
73
|
}
|
|
73
74
|
measure(options) {
|
|
74
|
-
return this.text
|
|
75
|
+
return measure(this.text, options);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
// A host with an environment but no streams — what a browser looks like from
|
|
@@ -177,7 +178,7 @@ export class Console {
|
|
|
177
178
|
// compared with: the reference's `LogRender._last_time`, one per console.
|
|
178
179
|
// [LAW:no-ambient-temporal-coupling] "same as the previous row" is a fact
|
|
179
180
|
// about an earlier call, so it is state this console owns, not order luck.
|
|
180
|
-
_lastLogTime = null;
|
|
181
|
+
_lastLogTime = new State(null);
|
|
181
182
|
_style;
|
|
182
183
|
_isTerminal;
|
|
183
184
|
_interactive;
|
|
@@ -193,14 +194,15 @@ export class Console {
|
|
|
193
194
|
_onStyleError;
|
|
194
195
|
_asciiOnly;
|
|
195
196
|
_highlighter;
|
|
196
|
-
_recorded;
|
|
197
|
+
_recorded = new ListState();
|
|
197
198
|
// [LAW:types-are-the-program] The capture state is carried in the *type*
|
|
198
199
|
// of this field, not in a sentinel value. `null` = not capturing; any
|
|
199
200
|
// string (including "") = capturing, this is the buffer. A paired
|
|
200
201
|
// boolean+string would admit the impossible state "not capturing, buffer
|
|
201
202
|
// non-empty" — `string | null` makes that unrepresentable.
|
|
202
|
-
_capture;
|
|
203
|
-
_liveRegion;
|
|
203
|
+
_capture = new State(null);
|
|
204
|
+
_liveRegion = new State(NO_LIVE_REGION);
|
|
205
|
+
_madeIn = activePass();
|
|
204
206
|
constructor(options) {
|
|
205
207
|
const environment = options?.environment ?? ambientEnvironment();
|
|
206
208
|
const stream = boundStream(environment, options?.stderr ?? false);
|
|
@@ -209,14 +211,13 @@ export class Console {
|
|
|
209
211
|
// [LAW:dataflow-not-control-flow] `isTTY` and `env` are forwarded
|
|
210
212
|
// unconditionally, so detection stays inside the console's injected
|
|
211
213
|
// environment rather than the ambient process's.
|
|
212
|
-
const resolved = resolveDestination(options?.colorSystem === undefined ? "auto" : options.colorSystem, { isTTY: this._isTerminal, env: environment.env });
|
|
214
|
+
const resolved = resolveDestination(options?.colorSystem === undefined ? "auto" : options.colorSystem, { isTTY: this._isTerminal, env: environment.env, reducedMotion: options?.reducedMotion });
|
|
213
215
|
// [LAW:single-enforcer] The console's one override, an explicit
|
|
214
216
|
// `hyperlinks`, is applied here and nowhere else; every write encodes for
|
|
215
|
-
// this value whole.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
};
|
|
217
|
+
// this value whole. [LAW:one-source-of-truth] The reader's motion
|
|
218
|
+
// preference lives here too, and `options` reads it back from here, so
|
|
219
|
+
// what is drawn and how it is encoded take one preference.
|
|
220
|
+
this._destination = { ...resolved, hyperlinks: options?.hyperlinks ?? resolved.hyperlinks };
|
|
220
221
|
this._getSize = resolveGetSize(options, environment, stream);
|
|
221
222
|
this._getDatetime = options?.getDatetime ?? (() => new Date());
|
|
222
223
|
// [LAW:no-ambient-temporal-coupling] The theme is assigned before the
|
|
@@ -232,9 +233,6 @@ export class Console {
|
|
|
232
233
|
this._highlighter = options?.highlighter ?? new ReprHighlighter();
|
|
233
234
|
this._onStyleError = options?.onStyleError;
|
|
234
235
|
this._asciiOnly = options?.asciiOnly ?? false;
|
|
235
|
-
this._recorded = [];
|
|
236
|
-
this._capture = null;
|
|
237
|
-
this._liveRegion = NO_LIVE_REGION;
|
|
238
236
|
}
|
|
239
237
|
// --- Properties ---
|
|
240
238
|
get size() {
|
|
@@ -256,8 +254,9 @@ export class Console {
|
|
|
256
254
|
return this._destination.colorSystem;
|
|
257
255
|
}
|
|
258
256
|
/**
|
|
259
|
-
* Where this console writes: the colour depth it draws at
|
|
260
|
-
* emits OSC 8 hyperlinks,
|
|
257
|
+
* Where this console writes: the colour depth it draws at, whether it
|
|
258
|
+
* emits OSC 8 hyperlinks, and whether its reader asked for reduced motion,
|
|
259
|
+
* overrides applied — the value its output is
|
|
261
260
|
* encoded for, for anything that encodes on its behalf (`Live`).
|
|
262
261
|
*/
|
|
263
262
|
get destination() {
|
|
@@ -287,6 +286,7 @@ export class Console {
|
|
|
287
286
|
height: { rows: height, exact: false },
|
|
288
287
|
isTerminal: this.isTerminal,
|
|
289
288
|
asciiOnly: this._asciiOnly,
|
|
289
|
+
reducedMotion: this._destination.reducedMotion,
|
|
290
290
|
theme: this._theme,
|
|
291
291
|
onStyleError: this._onStyleError,
|
|
292
292
|
colorSystem: this._destination.colorSystem,
|
|
@@ -433,7 +433,7 @@ export class Console {
|
|
|
433
433
|
const renderable = block.kind === "text" ? new TextRun(block.items, terminator) : block.renderable;
|
|
434
434
|
if (align)
|
|
435
435
|
return { lines: placeBlock(renderable, align, renderOpts), closed: true };
|
|
436
|
-
const drawn = [...
|
|
436
|
+
const drawn = [...render(renderable, renderOpts)];
|
|
437
437
|
// A text run's last segment is always its `end`, yielded even when
|
|
438
438
|
// empty, and `splitLines` drops the empty line after a final break only
|
|
439
439
|
// when nothing follows it — so the run is closed exactly when `end` is.
|
|
@@ -474,12 +474,12 @@ export class Console {
|
|
|
474
474
|
log(...args) {
|
|
475
475
|
const options = this.options;
|
|
476
476
|
const stamped = logTime(this._getDatetime());
|
|
477
|
-
const repeated = stamped === this._lastLogTime;
|
|
477
|
+
const repeated = stamped === this._lastLogTime.get();
|
|
478
478
|
const time = new RichText(stamped, { end: "" });
|
|
479
479
|
time.stylize("log.time");
|
|
480
480
|
const width = Math.min(time.cellLength, options.maxWidth - 1);
|
|
481
481
|
const { rows, cropWidth } = this._draw(args, { ...options, maxWidth: options.maxWidth - width });
|
|
482
|
-
const [stampLine = []] = Segment.splitLines(
|
|
482
|
+
const [stampLine = []] = Segment.splitLines(render(time, { ...options, maxWidth: time.cellLength }));
|
|
483
483
|
const styled = (cell) => [...Segment.applyStyle(cell, this._style)];
|
|
484
484
|
const stamp = styled(Segment.adjustLineLength(stampLine, width));
|
|
485
485
|
const blank = styled([new Segment(" ".repeat(width))]);
|
|
@@ -492,14 +492,14 @@ export class Console {
|
|
|
492
492
|
this._writeSegments(emit({ rows: grid, closed: true, cropWidth: cropWidth + width }));
|
|
493
493
|
// Remembered only once the row is written: a log that threw printed no
|
|
494
494
|
// stamp, so the next row's must show.
|
|
495
|
-
this._lastLogTime
|
|
495
|
+
this._lastLogTime.set(stamped);
|
|
496
496
|
}
|
|
497
497
|
// [LAW:one-source-of-truth] `RuleOptions` is `Rule`'s, not a restatement of
|
|
498
498
|
// it. `console.ts` used to declare its own copy and field-by-field forward
|
|
499
499
|
// into this constructor, which made a second map of one shape — identical
|
|
500
500
|
// then, free to drift the moment `Rule` grew an option.
|
|
501
501
|
rule(title, options) {
|
|
502
|
-
const segments = [...new Rule(title, options)
|
|
502
|
+
const segments = [...render(new Rule(title, options), this.options)];
|
|
503
503
|
this._writeSegments(segments);
|
|
504
504
|
}
|
|
505
505
|
// [LAW:one-source-of-truth] `JSONRenderable` is the one formatter for JSON and
|
|
@@ -519,15 +519,15 @@ export class Console {
|
|
|
519
519
|
* painted over by the first, so claiming one while another is held throws.
|
|
520
520
|
*/
|
|
521
521
|
claimLiveRegion(region) {
|
|
522
|
-
if (this._liveRegion !== NO_LIVE_REGION) {
|
|
522
|
+
if (this._liveRegion.get() !== NO_LIVE_REGION) {
|
|
523
523
|
throw new Error("A live display is already running on this console; stop it before starting another.");
|
|
524
524
|
}
|
|
525
|
-
this._liveRegion
|
|
525
|
+
this._liveRegion.set(region);
|
|
526
526
|
// Letting go of a region no longer held — a second call, or after another
|
|
527
527
|
// was claimed — leaves the one that is.
|
|
528
528
|
return () => {
|
|
529
|
-
if (this._liveRegion === region)
|
|
530
|
-
this._liveRegion
|
|
529
|
+
if (this._liveRegion.get() === region)
|
|
530
|
+
this._liveRegion.set(NO_LIVE_REGION);
|
|
531
531
|
};
|
|
532
532
|
}
|
|
533
533
|
// --- Capture ---
|
|
@@ -537,60 +537,65 @@ export class Console {
|
|
|
537
537
|
// the full text that would otherwise have been written. This is not a
|
|
538
538
|
// tee — callers wanting both must compose explicitly.
|
|
539
539
|
beginCapture() {
|
|
540
|
-
this._capture
|
|
540
|
+
this._capture.set("");
|
|
541
541
|
}
|
|
542
542
|
endCapture() {
|
|
543
|
-
const result = this._capture ?? "";
|
|
544
|
-
this._capture
|
|
543
|
+
const result = this._capture.get() ?? "";
|
|
544
|
+
this._capture.set(null);
|
|
545
545
|
return result;
|
|
546
546
|
}
|
|
547
547
|
// --- Export (when record:true) ---
|
|
548
548
|
exportText({ clear = true } = {}) {
|
|
549
|
-
const text = this._recorded.map((s) => s.text).join("");
|
|
549
|
+
const text = this._recorded.get().map((s) => s.text).join("");
|
|
550
550
|
if (clear)
|
|
551
|
-
this._recorded
|
|
551
|
+
this._recorded.set([]);
|
|
552
552
|
return text;
|
|
553
553
|
}
|
|
554
554
|
// [LAW:single-enforcer] `encodeHtml` draws the picture `exportLines`
|
|
555
555
|
// resolves; nothing here interprets a `Style`.
|
|
556
556
|
exportHtml({ theme, clear = true } = {}) {
|
|
557
|
-
const html = encodeHtml(this._recorded, theme);
|
|
557
|
+
const html = encodeHtml(this._recorded.get(), theme);
|
|
558
558
|
if (clear)
|
|
559
|
-
this._recorded
|
|
559
|
+
this._recorded.set([]);
|
|
560
560
|
return html;
|
|
561
561
|
}
|
|
562
562
|
// [LAW:single-enforcer] As `exportHtml`: `encodeSvg` draws, this clears.
|
|
563
563
|
exportSvg({ theme, title = "Rich", clear = true } = {}) {
|
|
564
|
-
const svg = encodeSvg(this._recorded, { theme, title, width: this.width });
|
|
564
|
+
const svg = encodeSvg(this._recorded.get(), { theme, title, width: this.width });
|
|
565
565
|
if (clear)
|
|
566
|
-
this._recorded
|
|
566
|
+
this._recorded.set([]);
|
|
567
567
|
return svg;
|
|
568
568
|
}
|
|
569
569
|
// --- Internal ---
|
|
570
570
|
// [LAW:single-enforcer] One encode call per write batch routes through the
|
|
571
571
|
// same `segmentsToString` used by `renderToString`. Recording captures every
|
|
572
|
-
// non-control segment for replay.
|
|
572
|
+
// non-control segment for replay, as its destination shows it.
|
|
573
573
|
_writeSegments(segments) {
|
|
574
|
+
const shown = segments.map((segment) => shownOn(segment, this._destination));
|
|
574
575
|
if (this._record) {
|
|
575
|
-
for (const segment of
|
|
576
|
+
for (const segment of shown) {
|
|
576
577
|
if (!segment.isControl)
|
|
577
578
|
this._recorded.push(segment);
|
|
578
579
|
}
|
|
579
580
|
}
|
|
580
|
-
const encoded = segmentsToString(
|
|
581
|
+
const encoded = segmentsToString(shown, this._destination);
|
|
581
582
|
if (encoded.length > 0)
|
|
582
583
|
this._write(encoded);
|
|
583
584
|
}
|
|
584
585
|
_write(text) {
|
|
586
|
+
// [LAW:single-enforcer] Every write is refused during a render this console was not made in, whatever
|
|
587
|
+
// the console records or captures: output is an effect, and one made mid-frame lands inside the frame.
|
|
588
|
+
refuseRenderWrite(this._madeIn);
|
|
585
589
|
// [LAW:types-are-the-program] `_capture !== null` is a discriminator
|
|
586
590
|
// narrow on `string | null`, not a sentinel comparison — the type
|
|
587
591
|
// carries the active/inactive state. The early return is what makes
|
|
588
592
|
// this a redirect (not a tee); see beginCapture for semantics.
|
|
589
|
-
|
|
590
|
-
|
|
593
|
+
const captured = this._capture.get();
|
|
594
|
+
if (captured !== null) {
|
|
595
|
+
this._capture.set(captured + text);
|
|
591
596
|
return;
|
|
592
597
|
}
|
|
593
598
|
const target = this._file ?? defaultSink(this._stream);
|
|
594
|
-
target.write(this._liveRegion.around(text));
|
|
599
|
+
target.write(this._liveRegion.get().around(text));
|
|
595
600
|
}
|
|
596
601
|
}
|
package/dist/core/easing.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Easing and phase: the one vocabulary for "how far along" —
|
|
3
|
-
*
|
|
2
|
+
* Easing and phase: the one vocabulary for "how far along" — a time in
|
|
3
|
+
* seconds becomes progress in [0, 1], and an ease reshapes that progress,
|
|
4
|
+
* usually but not always within [0, 1].
|
|
4
5
|
*
|
|
5
6
|
* Two kinds of curve, composed as `ease(phase(t))`:
|
|
6
7
|
*
|
|
@@ -13,20 +14,31 @@
|
|
|
13
14
|
* built-ins are CSS's easing functions (CSS Easing Functions Level 1):
|
|
14
15
|
* `linear`, `cubic-bezier()` with its named curves, and `steps()` with its
|
|
15
16
|
* jump terms, plus `sine` for pulses — a half-cosine, so a `pingPong`
|
|
16
|
-
* through it brightens and dims with no corner at either end
|
|
17
|
+
* through it brightens and dims with no corner at either end — and the
|
|
18
|
+
* physics-flavoured curves a cursor snapping, a counter settling or a
|
|
19
|
+
* panel sliding in want: `spring`, a damped harmonic oscillator released
|
|
20
|
+
* toward its rest, which is the one of them with parameters and so the one
|
|
21
|
+
* that also says how long it takes; `bounce`, `back-in`, `back-out` and
|
|
22
|
+
* `elastic`, Robert Penner's curves at the constants every animation
|
|
23
|
+
* library since has shipped. An ease that leaves [0, 1] — a spring or a
|
|
24
|
+
* back curve overshooting its rest — is still an ease: a `ColorRamp` holds
|
|
25
|
+
* its end colours where it does, and an effect's `Curve` saturates at its
|
|
26
|
+
* swing, so the overshoot is read by what can show it (a position, a
|
|
27
|
+
* count) and clipped by what cannot.
|
|
17
28
|
*
|
|
18
29
|
* [LAW:no-ambient-temporal-coupling] Nothing here reads a clock. `t` is an
|
|
19
30
|
* argument; whoever draws frames owns the clock and samples these at
|
|
20
31
|
* whatever rate it likes, so the same `t` always gives the same progress.
|
|
21
32
|
*
|
|
22
33
|
* [LAW:one-type-per-behavior] An ease is a plain function value. CSS's named
|
|
23
|
-
* curves are four instances of `cubicBezier`, not four implementations,
|
|
24
|
-
* `ColorRamp` and every effect take
|
|
34
|
+
* curves are four instances of `cubicBezier`, not four implementations, the
|
|
35
|
+
* spring in `EASES` is one `spring()`, and `ColorRamp` and every effect take
|
|
36
|
+
* the same `Ease`.
|
|
25
37
|
*
|
|
26
38
|
* Tier 0 of `src/core/`: imports nothing, so `themes/` and every later
|
|
27
39
|
* `core/` module reach it downhill. [LAW:one-way-deps]
|
|
28
40
|
*/
|
|
29
|
-
/** Progress in, progress out: a reshaping of [0, 1]. */
|
|
41
|
+
/** Progress in [0, 1] in, progress out: a reshaping of [0, 1] that may leave it, as a spring overshooting its rest does. */
|
|
30
42
|
export type Ease = (x: number) => number;
|
|
31
43
|
/** Time in seconds (plus any per-cell offset) in, progress in [0, 1] out. */
|
|
32
44
|
export type Phase = (t: number) => number;
|
|
@@ -51,11 +63,78 @@ export type StepPosition = "jump-start" | "jump-end" | "jump-none" | "jump-both"
|
|
|
51
63
|
* the very end.
|
|
52
64
|
*/
|
|
53
65
|
export declare function steps(n: number, position?: StepPosition): Ease;
|
|
66
|
+
/**
|
|
67
|
+
* The curve `shape` over [0, 1) as an ease that has arrived: its argument
|
|
68
|
+
* held to [0, 1], and exactly 1 at 1. Every built-in ease is one, so the two
|
|
69
|
+
* halves of the `Ease` contract — an argument in [0, 1], the end landed on —
|
|
70
|
+
* are enforced here and nowhere else. [LAW:single-enforcer] The end matters
|
|
71
|
+
* because a curve is 1 at its end only in the limit or up to a rounding — a
|
|
72
|
+
* spring settles to within `SPRING_REST`, the elastic's ringing never quite
|
|
73
|
+
* stops, a back curve's cubic or a bezier's Newton step lands an ulp off —
|
|
74
|
+
* and a count or a width eased by it must land on its target, not a
|
|
75
|
+
* thousandth or an ulp short.
|
|
76
|
+
*/
|
|
77
|
+
export declare const settled: (shape: (p: number) => number) => Ease;
|
|
78
|
+
/**
|
|
79
|
+
* A spring's physics: the mass on it, the stiffness of its coil and the
|
|
80
|
+
* damping it moves against, in the units every animation library spells them
|
|
81
|
+
* in (React Spring, Framer Motion), whose defaults these are — a spring that
|
|
82
|
+
* overshoots once and settles in about a second and a quarter.
|
|
83
|
+
*/
|
|
84
|
+
export interface SpringOptions {
|
|
85
|
+
/** The restoring force per unit of displacement; stiffer swings faster and settles in about the same time, since the decay is the damping's over the mass's. Positive. Defaults to 100. */
|
|
86
|
+
readonly stiffness?: number;
|
|
87
|
+
/** The force against the motion per unit of velocity; more settles sooner and overshoots less. Positive. Defaults to 10. */
|
|
88
|
+
readonly damping?: number;
|
|
89
|
+
/** What the spring moves; heavier is slower and overshoots further. Positive. Defaults to 1. */
|
|
90
|
+
readonly mass?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* An ease over a duration: CSS's timing function and duration as one value,
|
|
94
|
+
* the whole of what a one-shot move needs to know about time — a tween's
|
|
95
|
+
* (`./tween.ts`), a `spring()`'s, and the part of an effect's `Curve` that
|
|
96
|
+
* is not its swing. `Phase.once(start, seconds)` through `ease` is the move
|
|
97
|
+
* on a timeline. [LAW:one-type-per-behavior] One shape, so a spring is handed
|
|
98
|
+
* to a tween as it is, and a curve written for an effect times a tween.
|
|
99
|
+
*/
|
|
100
|
+
export interface Timing {
|
|
101
|
+
/** How the move is shaped, as progress in to progress out. */
|
|
102
|
+
readonly ease: Ease;
|
|
103
|
+
/** How long the move takes, in seconds. */
|
|
104
|
+
readonly seconds: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* How close to its rest a spring must come to count as settled: one part in a
|
|
108
|
+
* thousand of the way it moves, under a colour channel's step (1/255) and
|
|
109
|
+
* under any cell, so what rounds the spring's value to show it draws the rest
|
|
110
|
+
* from there on.
|
|
111
|
+
*/
|
|
112
|
+
export declare const SPRING_REST = 0.001;
|
|
113
|
+
/**
|
|
114
|
+
* A damped harmonic oscillator, `m·x″ = −k·x − c·x′`, released at rest one
|
|
115
|
+
* unit from its equilibrium: the spring every animation library means. Its
|
|
116
|
+
* progress at `s` seconds is `1 − displacement(s)`, the closed-form solution
|
|
117
|
+
* of that equation in the regime its damping ratio `ζ = c / 2√(k·m)` puts it
|
|
118
|
+
* in — ringing past its rest for `ζ < 1`, creeping up to it for `ζ ≥ 1` — and
|
|
119
|
+
* its `seconds` is its settling time: the first moment after which the
|
|
120
|
+
* displacement stays within `SPRING_REST`, found once here by `crossing` on
|
|
121
|
+
* the bracket each regime knows its last crossing lies in, so a sample costs
|
|
122
|
+
* an exponential and a cosine whatever `x` is. [LAW:no-ambient-temporal-coupling]
|
|
123
|
+
*
|
|
124
|
+
* The ease is exactly 1 at `x = 1` (`settled`): settled means at rest. The
|
|
125
|
+
* `seconds` are the spring's to say, not the caller's: how long it rings is
|
|
126
|
+
* a fact about its physics, which is why this is the one ease that comes as
|
|
127
|
+
* a `Timing` — released at rest a unit from where it is going, at 1 when it
|
|
128
|
+
* has settled there.
|
|
129
|
+
*/
|
|
130
|
+
export declare function spring(options?: SpringOptions): Timing;
|
|
54
131
|
/**
|
|
55
132
|
* Every built-in ease by the name a template spells it with — CSS's keyword
|
|
56
133
|
* names, plus `sine`, plus `step`: the spelling `ColorRamp` used before this
|
|
57
134
|
* vocabulary existed, kept so every template written against it renders the
|
|
58
|
-
* same. It is CSS's `step-end`, the same function value.
|
|
135
|
+
* same. It is CSS's `step-end`, the same function value. Then the
|
|
136
|
+
* physics-flavoured curves: `spring` is the default `spring()`, whose
|
|
137
|
+
* `seconds` are `DEFAULT_SPRING`'s; the rest are Penner's at his constants.
|
|
59
138
|
*/
|
|
60
139
|
export declare const EASES: {
|
|
61
140
|
readonly linear: Ease;
|
|
@@ -67,6 +146,11 @@ export declare const EASES: {
|
|
|
67
146
|
readonly "step-end": Ease;
|
|
68
147
|
readonly step: Ease;
|
|
69
148
|
readonly sine: Ease;
|
|
149
|
+
readonly spring: Ease;
|
|
150
|
+
readonly bounce: Ease;
|
|
151
|
+
readonly "back-in": Ease;
|
|
152
|
+
readonly "back-out": Ease;
|
|
153
|
+
readonly elastic: Ease;
|
|
70
154
|
};
|
|
71
155
|
export type EaseName = keyof typeof EASES;
|
|
72
156
|
/**
|
|
@@ -75,6 +159,8 @@ export type EaseName = keyof typeof EASES;
|
|
|
75
159
|
* Unknown names throw naming every legal one. [LAW:no-silent-failure]
|
|
76
160
|
*/
|
|
77
161
|
export declare function parseEase(name: string): Ease;
|
|
162
|
+
/** Throws, naming `what`, unless `seconds` is a positive, finite number of seconds. */
|
|
163
|
+
export declare function positiveSeconds(what: string, seconds: number): void;
|
|
78
164
|
/**
|
|
79
165
|
* A beat: holds of given lengths in seconds, played in order and looped, the
|
|
80
166
|
* way the frames of an animation are each held and then replaced. `at(t)` is
|
|
@@ -94,16 +180,60 @@ export interface Beat {
|
|
|
94
180
|
* When the hold in progress at `t` began, in seconds on `t`'s own
|
|
95
181
|
* timeline: what a sample-and-hold on this beat reads at `t`. Every `t`
|
|
96
182
|
* inside one hold of one pass answers the same number, to the bit, so an
|
|
97
|
-
* effect handed it draws the same frame throughout.
|
|
183
|
+
* effect handed it draws the same frame throughout. With `nextChange`,
|
|
184
|
+
* the two ends of the hold, as every `Animation` answers them.
|
|
98
185
|
*/
|
|
99
|
-
|
|
186
|
+
lastChange(t: number): number;
|
|
100
187
|
/**
|
|
101
188
|
* When the hold in progress at `t` ends, in seconds on `t`'s own timeline:
|
|
102
189
|
* the start of the next hold, the first moment `at` places in it, so it is
|
|
103
190
|
* always after `t`. What is drawn on this beat at `t` is drawn until then.
|
|
191
|
+
* With `at`, this makes a beat an `Animation` of the hold in progress
|
|
192
|
+
* (`./animation.ts`).
|
|
104
193
|
*/
|
|
105
|
-
|
|
194
|
+
nextChange(t: number): number;
|
|
195
|
+
/** The beat with its motion taken out: its first hold, held for good, as a loop holds its first value. */
|
|
196
|
+
reduced(): Beat;
|
|
106
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* `t`, unless it is not a finite number of seconds, which throws naming
|
|
200
|
+
* `what`. [LAW:single-enforcer] The one refusal of a moment to draw at, for
|
|
201
|
+
* every loop and beat that reads time and every renderable drawn at a time.
|
|
202
|
+
*/
|
|
203
|
+
export declare function finiteTime(what: string, t: number): number;
|
|
204
|
+
/**
|
|
205
|
+
* Which pass of a `period` `t` is in, as a whole number of either sign, and
|
|
206
|
+
* the seconds into it, read through the one wrap: what a `beat` and an
|
|
207
|
+
* `Animation.repeat` (`./animation.ts`) both ask, so the two agree on the
|
|
208
|
+
* pass of every float, a boundary included.
|
|
209
|
+
*/
|
|
210
|
+
export declare function passAt(what: string, t: number, period: number): {
|
|
211
|
+
readonly pass: number;
|
|
212
|
+
readonly into: number;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* The first float from `sum` up at which `reached` holds: a time built as a
|
|
216
|
+
* sum to land on a boundary — where a hold begins, where an animation's next
|
|
217
|
+
* part changes — that rounding put an ulp or two under it, walked up to the
|
|
218
|
+
* first moment on the far side. [LAW:single-enforcer] The one walk, so every
|
|
219
|
+
* boundary a time is carried onto is the moment the change shows, to the
|
|
220
|
+
* float. A walk longer than rounding can cost throws `finer()`'s message: the
|
|
221
|
+
* boundary is narrower than the floats around it are apart.
|
|
222
|
+
*/
|
|
223
|
+
export declare function walkUp(sum: number, reached: (x: number) => boolean, finer: () => string): number;
|
|
224
|
+
/**
|
|
225
|
+
* The least float at which `reached` holds, `reached` being false up to some
|
|
226
|
+
* float and true from it on, found from `near`, a guess at it on either
|
|
227
|
+
* side. Where `walkUp` carries a sum onto a boundary on its own clock, and
|
|
228
|
+
* an ulp or two is all rounding can cost, this carries a moment across
|
|
229
|
+
* clocks (`./timeline.ts`): a host float is a step of `rate` on the
|
|
230
|
+
* animation's clock, so the host floats between the guess and the first one
|
|
231
|
+
* past the boundary are as many as the two clocks' resolutions are apart,
|
|
232
|
+
* which no cap bounds and is no error. The bracket is found by doubling the
|
|
233
|
+
* step out from `near`, and halved to two adjacent floats, so the answer is
|
|
234
|
+
* exact to the float and the cost is logarithmic in that distance.
|
|
235
|
+
*/
|
|
236
|
+
export declare function firstReaching(near: number, reached: (x: number) => boolean): number;
|
|
107
237
|
/** `holds` as a `Beat`; a beat with no hold, or a hold that is not a positive number of seconds, throws. */
|
|
108
238
|
export declare function beat(holds: readonly number[]): Beat;
|
|
109
239
|
/** The three phase shapes. Each takes seconds and returns a `Phase`. */
|