@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/host/app.js
CHANGED
|
@@ -34,7 +34,9 @@ import { frameRate, systemClock } from "../core/clock.js";
|
|
|
34
34
|
import { Console } from "../core/console.js";
|
|
35
35
|
import { Segment } from "../core/segment.js";
|
|
36
36
|
import { SurfacePainter } from "../core/paint.js";
|
|
37
|
-
import { fitHeight } from "../core/protocol.js";
|
|
37
|
+
import { fitHeight, render } from "../core/protocol.js";
|
|
38
|
+
import { Timeline } from "../core/timeline.js";
|
|
39
|
+
import { drawView, frameTime, hostView, undrawn } from "../core/view.js";
|
|
38
40
|
import { hostEnvironment } from "./host-environment.js";
|
|
39
41
|
import { InputParser, keyName, parseKeyName } from "./input.js";
|
|
40
42
|
// [LAW:one-source-of-truth] How a frame draws — its glyphs, the style names
|
|
@@ -43,7 +45,7 @@ import { InputParser, keyName, parseKeyName } from "./input.js";
|
|
|
43
45
|
// console declares them. This list is both the type and what is copied: the
|
|
44
46
|
// host alone decides the console's size, colours and sink, so no other
|
|
45
47
|
// property of the options object reaches it, whatever the object carries.
|
|
46
|
-
const DRAW_OPTIONS = ["asciiOnly", "theme", "onStyleError", "markup", "highlight", "highlighter"];
|
|
48
|
+
const DRAW_OPTIONS = ["asciiOnly", "reducedMotion", "theme", "onStyleError", "markup", "highlight", "highlighter"];
|
|
47
49
|
function drawOptions(options) {
|
|
48
50
|
const picked = {};
|
|
49
51
|
const copy = (key) => {
|
|
@@ -71,12 +73,19 @@ export class App {
|
|
|
71
73
|
host;
|
|
72
74
|
surface;
|
|
73
75
|
view;
|
|
74
|
-
|
|
76
|
+
_clock;
|
|
77
|
+
// The clock moment this app began: what its default timeline plays from,
|
|
78
|
+
// and what a renderable view is drawn for the time since (`HostTime`).
|
|
79
|
+
_epoch;
|
|
80
|
+
_timeline;
|
|
75
81
|
_rate;
|
|
76
|
-
// What is animating now: one token per `animate()` not yet released.
|
|
77
|
-
animations = new Set();
|
|
78
82
|
// The timer painting frames, and the rate it was started at.
|
|
79
83
|
ticking = null;
|
|
84
|
+
// What the frame on screen says about when it changes, on the clock.
|
|
85
|
+
// Before a frame, nothing.
|
|
86
|
+
said = undrawn(0);
|
|
87
|
+
// The one wait for the frame's `nextChange`, armed after each frame.
|
|
88
|
+
waking = null;
|
|
80
89
|
// [LAW:one-source-of-truth] The host is the console's whole environment:
|
|
81
90
|
// its size, its colours, where bytes go. Every frame renders with this
|
|
82
91
|
// console's options and is encoded for its destination.
|
|
@@ -98,8 +107,10 @@ export class App {
|
|
|
98
107
|
this.input = new InputParser({ key: (press) => this.key(press), mouse: (event) => this.mouse(event) }, options.host.inputChunks);
|
|
99
108
|
this.surface = options.surface;
|
|
100
109
|
this.painter = new SurfacePainter(options.surface, (bytes) => this.host.write(bytes));
|
|
101
|
-
this.view = options.view;
|
|
102
|
-
this.
|
|
110
|
+
this.view = hostView(options.view);
|
|
111
|
+
this._clock = options.clock ?? systemClock();
|
|
112
|
+
this._epoch = this._clock.now();
|
|
113
|
+
this._timeline = options.timeline ?? Timeline.play(this._epoch);
|
|
103
114
|
this._rate = options.rate ?? DEFAULT_RATE;
|
|
104
115
|
this.quitKeys = new Set((options.quitKeys ?? DEFAULT_QUIT_KEYS).map(parseKeyName));
|
|
105
116
|
this.console = new Console({ ...drawOptions(options), environment: hostEnvironment(options.host) });
|
|
@@ -107,7 +118,25 @@ export class App {
|
|
|
107
118
|
get phase() {
|
|
108
119
|
return this._phase;
|
|
109
120
|
}
|
|
110
|
-
/**
|
|
121
|
+
/** The clock the app reads the time from: where the host time a `Timeline` operation takes is read. */
|
|
122
|
+
get clock() {
|
|
123
|
+
return this._clock;
|
|
124
|
+
}
|
|
125
|
+
/** The map from the clock to the time the view is drawn for. */
|
|
126
|
+
get timeline() {
|
|
127
|
+
return this._timeline;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Replace the timeline and paint the frame for the time it now maps the
|
|
131
|
+
* clock's now to, so a seek shows where it sought, once. Paused, the frame
|
|
132
|
+
* then holds: nothing drawn for a held time changes, so the app waits on
|
|
133
|
+
* nothing until the timeline plays again, and paints when asked.
|
|
134
|
+
*/
|
|
135
|
+
set timeline(timeline) {
|
|
136
|
+
this._timeline = timeline;
|
|
137
|
+
this.refresh();
|
|
138
|
+
}
|
|
139
|
+
/** How often the app paints while what it shows moves every moment. */
|
|
111
140
|
get rate() {
|
|
112
141
|
return this._rate;
|
|
113
142
|
}
|
|
@@ -123,6 +152,18 @@ export class App {
|
|
|
123
152
|
get frame() {
|
|
124
153
|
return this._frame;
|
|
125
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* The time a frame drawn now is drawn for (`RenderOptions.frame`): the
|
|
157
|
+
* clock's now, through the timeline. What a moment heard
|
|
158
|
+
* between frames — a key — is stamped with, so it is on the clock the
|
|
159
|
+
* frame is.
|
|
160
|
+
*/
|
|
161
|
+
get frameTime() {
|
|
162
|
+
return frameTime(this._time());
|
|
163
|
+
}
|
|
164
|
+
_time() {
|
|
165
|
+
return { now: this._clock.now(), epoch: this._epoch, timeline: this._timeline };
|
|
166
|
+
}
|
|
126
167
|
/**
|
|
127
168
|
* Take the terminal, paint the first frame, and resolve when the app stops
|
|
128
169
|
* — or reject with the error a frame threw or `fail` was given, the terminal
|
|
@@ -187,24 +228,6 @@ export class App {
|
|
|
187
228
|
this.paint();
|
|
188
229
|
});
|
|
189
230
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Paint at the app's `rate` until the returned function is called: what an
|
|
192
|
-
* effect sampled at the frame's time asks for while it moves. The app ticks
|
|
193
|
-
* while anything is animating and it holds the terminal, and stops when
|
|
194
|
-
* nothing is, so a still app paints only when asked. The animation's first
|
|
195
|
-
* frame does not wait out an interval: at one frame every two seconds, that
|
|
196
|
-
* would hold its start off screen for two.
|
|
197
|
-
*/
|
|
198
|
-
animate() {
|
|
199
|
-
const animation = {};
|
|
200
|
-
this.animations.add(animation);
|
|
201
|
-
this.tick();
|
|
202
|
-
this.refresh();
|
|
203
|
-
return () => {
|
|
204
|
-
this.animations.delete(animation);
|
|
205
|
-
this.tick();
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
231
|
/**
|
|
209
232
|
* Hand the terminal to whatever launched the program, and take it back and
|
|
210
233
|
* repaint when that resumes it. What sends the app here is the app's own —
|
|
@@ -350,19 +373,27 @@ export class App {
|
|
|
350
373
|
}
|
|
351
374
|
}
|
|
352
375
|
// [LAW:single-enforcer] Whether the clock is ticking, and at what rate,
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
//
|
|
376
|
+
// and whether a wake is armed for the frame's next change, follow from the
|
|
377
|
+
// phase, the rate and what the frame on screen says, and are brought in
|
|
378
|
+
// line with them here alone, after every change to any — so a timer runs
|
|
379
|
+
// exactly while a running app shows a frame that says it moves, at the
|
|
380
|
+
// rate the app has now, a wake is armed exactly while a running app shows
|
|
381
|
+
// a frame held until a moment, and none outlives the app.
|
|
382
|
+
// [LAW:one-source-of-truth] What the frame draws is the only thing that
|
|
383
|
+
// says whether the view moves.
|
|
357
384
|
tick() {
|
|
358
|
-
const
|
|
385
|
+
const running = this._phase === "running";
|
|
386
|
+
const { t, nextChange } = this.said;
|
|
387
|
+
const wanted = running && nextChange === t;
|
|
359
388
|
if (this.ticking !== null && (!wanted || this.ticking.rate.perSecond !== this._rate.perSecond)) {
|
|
360
389
|
this.ticking.stop();
|
|
361
390
|
this.ticking = null;
|
|
362
391
|
}
|
|
363
392
|
if (wanted && this.ticking === null) {
|
|
364
|
-
this.ticking = { rate: this._rate, stop: this.
|
|
393
|
+
this.ticking = { rate: this._rate, stop: this._clock.every(this._rate, () => this.paint()) };
|
|
365
394
|
}
|
|
395
|
+
this.waking?.();
|
|
396
|
+
this.waking = running && t < nextChange && nextChange < Number.POSITIVE_INFINITY ? this._clock.at(nextChange, () => this.paint()) : null;
|
|
366
397
|
}
|
|
367
398
|
// [LAW:no-silent-failure] A frame that throws ends the app with that
|
|
368
399
|
// error: the terminal is handed back, and `run` rejects with it.
|
|
@@ -380,13 +411,16 @@ export class App {
|
|
|
380
411
|
const options = this.console.options;
|
|
381
412
|
const height = this.painter.height(options.height.rows);
|
|
382
413
|
// [LAW:no-ambient-temporal-coupling] The frame owner reads the clock,
|
|
383
|
-
// once a frame; the view is handed the time as
|
|
384
|
-
|
|
385
|
-
// The app set the budget, so the app shapes what comes back: no
|
|
386
|
-
// than the terminal — a taller frame would scroll the rows the
|
|
387
|
-
// goes back over — and, as a region, exactly that deep.
|
|
388
|
-
const
|
|
414
|
+
// once a frame; the view is handed the time the timeline maps it to, as
|
|
415
|
+
// data, and what the frame says about when it changes comes back on the
|
|
416
|
+
// clock. The app set the budget, so the app shapes what comes back: no
|
|
417
|
+
// deeper than the terminal — a taller frame would scroll the rows the
|
|
418
|
+
// painter goes back over — and, as a region, exactly that deep.
|
|
419
|
+
const drawn = drawView(this.view, this._time(), this, { ...options, height }, (renderable, under) => fitHeight(Segment.splitLines(render(renderable, under)).slice(0, height.rows), height));
|
|
420
|
+
const frame = this.painter.paint(() => drawn.lines, { rows: height.rows, cols: options.maxWidth }, this.console.destination);
|
|
389
421
|
this._frame = frame;
|
|
422
|
+
this.said = drawn;
|
|
423
|
+
this.tick();
|
|
390
424
|
for (const handler of [...this.paintHandlers])
|
|
391
425
|
handler(frame);
|
|
392
426
|
}
|
package/dist/host/input.js
CHANGED
|
@@ -146,7 +146,6 @@ const M_LOWER = 0x6d; // m
|
|
|
146
146
|
const UTF8_ENCODER = new TextEncoder();
|
|
147
147
|
const UTF8_DECODER = new TextDecoder("utf-8");
|
|
148
148
|
const ASCII_DECODER = new TextDecoder("ascii");
|
|
149
|
-
const EMPTY_BYTES = new Uint8Array(0);
|
|
150
149
|
/**
|
|
151
150
|
* How long a `"split"` host's parser waits for the rest of an unfinished
|
|
152
151
|
* escape sequence before reading it as the keys it already holds. Textual's
|
|
@@ -195,7 +194,7 @@ export class InputParser {
|
|
|
195
194
|
// `Buffer` — node's Buffer extends Uint8Array, so Buffer chunks from
|
|
196
195
|
// process.stdin satisfy this type, while a browser host can emit native
|
|
197
196
|
// Uint8Array without depending on a Buffer global polyfill.
|
|
198
|
-
buffer =
|
|
197
|
+
buffer = new Uint8Array(0);
|
|
199
198
|
// [LAW:types-are-the-program] `setTimeout`/`clearTimeout` are universal
|
|
200
199
|
// across node and browser; `setImmediate` is node-only.
|
|
201
200
|
escTimer;
|
|
@@ -218,7 +217,7 @@ export class InputParser {
|
|
|
218
217
|
this.cancelEscape();
|
|
219
218
|
// The buffer is settled before the sink hears Escape, so a sink that
|
|
220
219
|
// resets the parser on it (an app stopping) leaves nothing to drain.
|
|
221
|
-
this.buffer = concatBytes(escaped ?
|
|
220
|
+
this.buffer = concatBytes(escaped ? new Uint8Array(0) : this.buffer, next);
|
|
222
221
|
try {
|
|
223
222
|
if (escaped)
|
|
224
223
|
this.sink.key(ESCAPE);
|
|
@@ -292,7 +291,7 @@ export class InputParser {
|
|
|
292
291
|
/** Drop what is buffered and any held escape sequence: the parser as constructed. */
|
|
293
292
|
reset() {
|
|
294
293
|
this.cancelEscape();
|
|
295
|
-
this.buffer =
|
|
294
|
+
this.buffer = new Uint8Array(0);
|
|
296
295
|
}
|
|
297
296
|
/** A lone ESC, the one hold a next chunk can settle before its bytes are read. */
|
|
298
297
|
holdingEscape() {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { cellLen, setCellSize, splitText, chopCells, cellFit, graphemes, asCellCol, asCodePoint, } from "./core/cells.js";
|
|
2
2
|
export type { CellCol, CodeUnit, CodePoint } from "./core/cells.js";
|
|
3
3
|
export { ColorRgba, ColorTable, ColorDepth, ColorSpec, ColorParseError, TerminalTheme, parseRgbHex, parseRgbaHex, parseHexColor, blendRgb, resolveColorSystem, detectColorSystem, resolveDestination, STANDARD_TABLE, EIGHT_BIT_TABLE, WINDOWS_TABLE, ANSI_COLOR_NAMES, } from "./core/color.js";
|
|
4
|
-
export type { ColorSystemName, DetectColorOptions, Destination } from "./core/color.js";
|
|
4
|
+
export type { ColorSystemName, DetectColorOptions, Destination, DestinationOptions } from "./core/color.js";
|
|
5
5
|
export { Oklch, IDENTITY, INVERT_LIGHTNESS, isIdentityKey, } from "./core/oklch.js";
|
|
6
6
|
export type { ThemeKey, OklchWeights } from "./core/oklch.js";
|
|
7
7
|
export { Palette } from "./themes/palette.js";
|
|
@@ -14,21 +14,26 @@ export type { ThemeName } from "./themes/registry.js";
|
|
|
14
14
|
export { transposePalette, themeKeyForRoot, isAnchored, ANCHORED_ROOTS, } from "./themes/transpose.js";
|
|
15
15
|
export { lighten, darken, relativeLuminance, contrastRatio, contrastFor, ensureContrast, ensureDrawn, drawnColour, } from "./themes/colorMath.js";
|
|
16
16
|
export { ColorRamp } from "./themes/ramp.js";
|
|
17
|
-
export type { ColorStop } from "./themes/ramp.js";
|
|
18
|
-
export { EASES, Phase, beat, cubicBezier, parseEase, steps } from "./core/easing.js";
|
|
19
|
-
export type { Beat, Ease, StepPosition } from "./core/easing.js";
|
|
17
|
+
export type { ColorStop, RampMotion } from "./themes/ramp.js";
|
|
18
|
+
export { EASES, Phase, beat, cubicBezier, parseEase, spring, steps } from "./core/easing.js";
|
|
19
|
+
export type { Beat, Ease, SpringOptions, StepPosition, Timing } from "./core/easing.js";
|
|
20
|
+
export { Animation } from "./core/animation.js";
|
|
21
|
+
export type { Timed } from "./core/animation.js";
|
|
22
|
+
export { tween } from "./core/tween.js";
|
|
23
|
+
export { Timeline } from "./core/timeline.js";
|
|
24
|
+
export type { View } from "./core/view.js";
|
|
20
25
|
export { frameRate, systemClock } from "./core/clock.js";
|
|
21
26
|
export type { Clock, FrameRate } from "./core/clock.js";
|
|
22
27
|
export { Style, StyleSyntaxError, StyleStack, Theme, NULL_STYLE, DEFAULT_STYLES, } from "./core/style.js";
|
|
23
|
-
export type { StyleOptions, TextStyle, LayeredStyle } from "./core/style.js";
|
|
28
|
+
export type { Attributes, Hold, StyleOptions, TextStyle, LayeredStyle } from "./core/style.js";
|
|
24
29
|
export { Segment, ControlType, } from "./core/segment.js";
|
|
25
30
|
export type { ControlCode } from "./core/segment.js";
|
|
26
31
|
export type { Anchor } from "./core/anchor.js";
|
|
27
32
|
export { Box } from "./core/box.js";
|
|
28
33
|
export type { EdgeChars, ContentChars, RowLevel, SubstituteOptions } from "./core/box.js";
|
|
29
34
|
export { ASCII, ASCII2, ASCII_DOUBLE_HEAD, SQUARE, SQUARE_DOUBLE_HEAD, MINIMAL, MINIMAL_HEAVY_HEAD, MINIMAL_DOUBLE_HEAD, SIMPLE, SIMPLE_HEAD, SIMPLE_HEAVY, HORIZONTALS, ROUNDED, HEAVY, HEAVY_EDGE, HEAVY_HEAD, DOUBLE, DOUBLE_EDGE, MARKDOWN, } from "./core/box.js";
|
|
30
|
-
export { isRenderable, isMeasurable, withCellWidth, withBoundedWidth, insetHeight, stackedHeight, regionRows, fitHeight, getStyle, } from "./core/protocol.js";
|
|
31
|
-
export type { RenderOptions, OverflowMethod, Height, Renderable, Measurable, StyleErrorHandler, } from "./core/protocol.js";
|
|
35
|
+
export { render, isRenderable, isMeasurable, withCellWidth, withBoundedWidth, insetHeight, stackedHeight, regionRows, fitHeight, getStyle, } from "./core/protocol.js";
|
|
36
|
+
export type { RenderOptions, OverflowMethod, Height, Renderable, Measurable, Presence, StyleErrorHandler, FrameHost, } from "./core/protocol.js";
|
|
32
37
|
export type { Unsubscribe } from "./core/subscription.js";
|
|
33
38
|
export { Measurement, measureRenderables } from "./core/measure.js";
|
|
34
39
|
export { Span, RichText } from "./core/text.js";
|
|
@@ -55,10 +60,20 @@ export { Console } from "./core/console.js";
|
|
|
55
60
|
export type { ConsoleOptions, ConsoleSink, ConsoleStream, ConsoleEnvironment, LiveRegion, PrintOptions, } from "./core/console.js";
|
|
56
61
|
export type { Env } from "./core/env.js";
|
|
57
62
|
export { Constrain } from "./renderables/constrain.js";
|
|
58
|
-
export { Effected, confined, drawnOf
|
|
59
|
-
export type { CellColors, Drawn, Effect, EffectCell, EffectedOptions, Pair, Placed } from "./renderables/effect.js";
|
|
60
|
-
export { EFFECT_CATALOGUE, EFFECT_CURVES, EFFECT_LIGHTS, dissolveOut, fadeIn, onColors, pulse, shimmer, sparkle, steppedInk, wheel, } from "./renderables/effects.js";
|
|
61
|
-
export type { ColorStep, Curve, EffectTarget, Field, Loop, LoopName, Touch, Transition, TransitionName } from "./renderables/effects.js";
|
|
63
|
+
export { Effected, confined, drawnOf } from "./renderables/effect.js";
|
|
64
|
+
export type { CellAttributes, CellColors, CellLook, Drawn, Effect, EffectCell, EffectedOptions, EffectFrame, Pair, Placed } from "./renderables/effect.js";
|
|
65
|
+
export { ATTRIBUTE_DEFAULTS, EFFECT_CATALOGUE, EFFECT_CURVES, EFFECT_LIGHTS, blink, dissolveOut, fadeIn, gradient, onBeat, onColors, pulse, shimmer, sparkle, steppedInk, wheel, } from "./renderables/effects.js";
|
|
66
|
+
export type { AttributeLoopName, Blink, ColorStep, Curve, EffectTarget, Field, Loop, LoopName, Touch, Transition, TransitionName } from "./renderables/effects.js";
|
|
67
|
+
export { crossfade, wipe } from "./renderables/change.js";
|
|
68
|
+
export type { Between, Change } from "./renderables/change.js";
|
|
69
|
+
export { lifecycle, throughColors, throughGlyphs } from "./renderables/lifecycle.js";
|
|
70
|
+
export type { Lifecycle, LifecycleOptions, Veil } from "./renderables/lifecycle.js";
|
|
71
|
+
export { scroll } from "./renderables/scroll.js";
|
|
72
|
+
export type { ScrollOptions } from "./renderables/scroll.js";
|
|
73
|
+
export { GlyphEffected } from "./renderables/glyph-effect.js";
|
|
74
|
+
export type { DrawnGlyphs, GlyphCell, GlyphEffect, GlyphEffectedOptions, GlyphFrame } from "./renderables/glyph-effect.js";
|
|
75
|
+
export { GLYPH_DEFAULTS, GLYPH_EFFECT_CATALOGUE, backspace, caseWave, particles, scramble, scrambleOut, typewriter } from "./renderables/glyph-effects.js";
|
|
76
|
+
export type { CaseWave, GlyphLoopName, GlyphTransition, GlyphTransitionName, Particles } from "./renderables/glyph-effects.js";
|
|
62
77
|
export { Align } from "./renderables/align.js";
|
|
63
78
|
export type { Alignment } from "./core/place.js";
|
|
64
79
|
export { Padding } from "./renderables/padding.js";
|
|
@@ -77,9 +92,9 @@ export { ProgressBar } from "./renderables/progressBar.js";
|
|
|
77
92
|
export type { ProgressBarOptions } from "./renderables/progressBar.js";
|
|
78
93
|
export { Spinner } from "./renderables/spinner.js";
|
|
79
94
|
export type { SpinnerOptions } from "./renderables/spinner.js";
|
|
80
|
-
export { FrameSequence
|
|
81
|
-
export type { Frame
|
|
82
|
-
export { Table, Column } from "./renderables/table.js";
|
|
95
|
+
export { FrameSequence } from "./renderables/frames.js";
|
|
96
|
+
export type { Frame } from "./renderables/frames.js";
|
|
97
|
+
export { Table, type Column } from "./renderables/table.js";
|
|
83
98
|
export type { TableOptions, ColumnOptions } from "./renderables/table.js";
|
|
84
99
|
export { Tree } from "./renderables/tree.js";
|
|
85
100
|
export type { TreeOptions } from "./renderables/tree.js";
|
|
@@ -88,7 +103,7 @@ export type { ColumnsOptions } from "./renderables/columns.js";
|
|
|
88
103
|
export { FlexStrip } from "./renderables/flexStrip.js";
|
|
89
104
|
export type { FlexStripOptions, FlexAlign } from "./renderables/flexStrip.js";
|
|
90
105
|
export { Live } from "./renderables/live.js";
|
|
91
|
-
export type { LiveOptions
|
|
106
|
+
export type { LiveOptions } from "./renderables/live.js";
|
|
92
107
|
export { Status } from "./renderables/status.js";
|
|
93
108
|
export type { StatusOptions } from "./renderables/status.js";
|
|
94
109
|
export { Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn, SpinnerColumn, MofNCompleteColumn, track, } from "./renderables/progress.js";
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,16 @@ export { lighten, darken, relativeLuminance, contrastRatio, contrastFor, ensureC
|
|
|
29
29
|
export { ColorRamp } from "./themes/ramp.js";
|
|
30
30
|
// Progress in [0, 1]: phases turn seconds into it, eases reshape it. One
|
|
31
31
|
// vocabulary for ramps and time-based effects alike, CSS's names throughout.
|
|
32
|
-
export { EASES, Phase, beat, cubicBezier, parseEase, steps } from "./core/easing.js";
|
|
32
|
+
export { EASES, Phase, beat, cubicBezier, parseEase, spring, steps } from "./core/easing.js";
|
|
33
|
+
// A value for a time, and when it next changes: the one type every kind of
|
|
34
|
+
// motion is an instance of — beats, frame sequences, spinners, effects.
|
|
35
|
+
export { Animation } from "./core/animation.js";
|
|
36
|
+
// A number eased from one value to another over seconds, then held: the
|
|
37
|
+
// value animation a fill, a counter or a width moves by instead of jumping.
|
|
38
|
+
export { tween } from "./core/tween.js";
|
|
39
|
+
// The map from the host's clock to the time an animation is asked for:
|
|
40
|
+
// pause, reverse, scrub and speed, once, above every kind of motion.
|
|
41
|
+
export { Timeline } from "./core/timeline.js";
|
|
33
42
|
// The time source and timer whoever draws frames is handed, and the one
|
|
34
43
|
// parser of the rate it ticks at.
|
|
35
44
|
export { frameRate, systemClock } from "./core/clock.js";
|
|
@@ -38,7 +47,7 @@ export { Segment, ControlType, } from "./core/segment.js";
|
|
|
38
47
|
export { Box } from "./core/box.js";
|
|
39
48
|
export { ASCII, ASCII2, ASCII_DOUBLE_HEAD, SQUARE, SQUARE_DOUBLE_HEAD, MINIMAL, MINIMAL_HEAVY_HEAD, MINIMAL_DOUBLE_HEAD, SIMPLE, SIMPLE_HEAD, SIMPLE_HEAVY, HORIZONTALS, ROUNDED, HEAVY, HEAVY_EDGE, HEAVY_HEAD, DOUBLE, DOUBLE_EDGE, MARKDOWN, } from "./core/box.js";
|
|
40
49
|
// Protocol
|
|
41
|
-
export { isRenderable, isMeasurable, withCellWidth, withBoundedWidth, insetHeight, stackedHeight, regionRows, fitHeight, getStyle, } from "./core/protocol.js";
|
|
50
|
+
export { render, isRenderable, isMeasurable, withCellWidth, withBoundedWidth, insetHeight, stackedHeight, regionRows, fitHeight, getStyle, } from "./core/protocol.js";
|
|
42
51
|
// Measurement
|
|
43
52
|
export { Measurement, measureRenderables } from "./core/measure.js";
|
|
44
53
|
// Text
|
|
@@ -69,8 +78,13 @@ export { SPINNERS, DEFAULT_SPINNER } from "./core/spinnerData.js";
|
|
|
69
78
|
export { Console } from "./core/console.js";
|
|
70
79
|
// Renderables
|
|
71
80
|
export { Constrain } from "./renderables/constrain.js";
|
|
72
|
-
export { Effected, confined, drawnOf
|
|
73
|
-
export { EFFECT_CATALOGUE, EFFECT_CURVES, EFFECT_LIGHTS, dissolveOut, fadeIn, onColors, pulse, shimmer, sparkle, steppedInk, wheel, } from "./renderables/effects.js";
|
|
81
|
+
export { Effected, confined, drawnOf } from "./renderables/effect.js";
|
|
82
|
+
export { ATTRIBUTE_DEFAULTS, EFFECT_CATALOGUE, EFFECT_CURVES, EFFECT_LIGHTS, blink, dissolveOut, fadeIn, gradient, onBeat, onColors, pulse, shimmer, sparkle, steppedInk, wheel, } from "./renderables/effects.js";
|
|
83
|
+
export { crossfade, wipe } from "./renderables/change.js";
|
|
84
|
+
export { lifecycle, throughColors, throughGlyphs } from "./renderables/lifecycle.js";
|
|
85
|
+
export { scroll } from "./renderables/scroll.js";
|
|
86
|
+
export { GlyphEffected } from "./renderables/glyph-effect.js";
|
|
87
|
+
export { GLYPH_DEFAULTS, GLYPH_EFFECT_CATALOGUE, backspace, caseWave, particles, scramble, scrambleOut, typewriter } from "./renderables/glyph-effects.js";
|
|
74
88
|
export { Align } from "./renderables/align.js";
|
|
75
89
|
export { Padding } from "./renderables/padding.js";
|
|
76
90
|
export { Viewport, ViewportPerKey, SCROLLBAR } from "./renderables/viewport.js";
|
|
@@ -81,8 +95,8 @@ export { Panel } from "./renderables/panel.js";
|
|
|
81
95
|
export { Group } from "./renderables/group.js";
|
|
82
96
|
export { ProgressBar } from "./renderables/progressBar.js";
|
|
83
97
|
export { Spinner } from "./renderables/spinner.js";
|
|
84
|
-
export { FrameSequence
|
|
85
|
-
export { Table
|
|
98
|
+
export { FrameSequence } from "./renderables/frames.js";
|
|
99
|
+
export { Table } from "./renderables/table.js";
|
|
86
100
|
export { Tree } from "./renderables/tree.js";
|
|
87
101
|
export { Columns } from "./renderables/columns.js";
|
|
88
102
|
export { FlexStrip } from "./renderables/flexStrip.js";
|
package/dist/node/traceback.js
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { Console } from "../core/console.js";
|
|
31
31
|
import { Traceback } from "../renderables/traceback.js";
|
|
32
|
+
import { State } from "../core/state.js";
|
|
32
33
|
/**
|
|
33
34
|
* The handler currently registered, or a no-op standing in for "none yet".
|
|
34
35
|
*
|
|
@@ -41,7 +42,7 @@ import { Traceback } from "../renderables/traceback.js";
|
|
|
41
42
|
* unregistered listener does nothing, so the first call needs no null check
|
|
42
43
|
* and no "have we installed yet" branch. There is no absent case to handle.
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
|
+
const installed = new State(() => { });
|
|
45
46
|
/**
|
|
46
47
|
* An unhandled rejection, raised as the uncaught exception it becomes when
|
|
47
48
|
* nobody listens — its reason unwrapped, which node's own conversion would
|
|
@@ -90,9 +91,9 @@ export function installTraceback(options) {
|
|
|
90
91
|
process.exit(1);
|
|
91
92
|
});
|
|
92
93
|
};
|
|
93
|
-
process.off("uncaughtException", installed);
|
|
94
|
+
process.off("uncaughtException", installed.get());
|
|
94
95
|
process.off("unhandledRejection", escalate);
|
|
95
96
|
process.on("uncaughtException", report);
|
|
96
97
|
process.on("unhandledRejection", escalate);
|
|
97
|
-
installed
|
|
98
|
+
installed.set(report);
|
|
98
99
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A change from one renderable to another in the same slot — a status that
|
|
3
|
+
* goes from "building" to "done", a number that becomes a different number —
|
|
4
|
+
* drawn as a crossfade or a wipe instead of a cut.
|
|
5
|
+
*
|
|
6
|
+
* Both are one shape [LAW:one-type-per-behavior]: how far each cell is through
|
|
7
|
+
* the change at `t`, from 0, the old renderable as drawn, to 1, the new one as
|
|
8
|
+
* drawn. A cell under a half shows the old one and from a half the new one,
|
|
9
|
+
* veiled toward the terminal's ground by how near the half it is (`veiled`,
|
|
10
|
+
* `./effects.ts`), so every cell passes through the ground and none jumps from
|
|
11
|
+
* one glyph to another. A crossfade has every cell at one place in the change;
|
|
12
|
+
* a wipe sends a front across the element's columns with the new renderable
|
|
13
|
+
* behind it.
|
|
14
|
+
*
|
|
15
|
+
* The change is drawn at the new renderable's size from its first frame: the
|
|
16
|
+
* old one is cut or padded to the new one's rows, so what sits beside the
|
|
17
|
+
* element moves once, at the cut, and never while the change runs. Once done
|
|
18
|
+
* it is the new renderable itself, byte for byte, and never changes again.
|
|
19
|
+
*
|
|
20
|
+
* [LAW:no-ambient-temporal-coupling] Pure in `t`: nothing is kept from one
|
|
21
|
+
* frame to the next, so the same `t` draws the same bytes at any frame rate.
|
|
22
|
+
*/
|
|
23
|
+
import { Animation } from "../core/animation.js";
|
|
24
|
+
import type { TerminalTheme } from "../core/color.js";
|
|
25
|
+
import type { Renderable } from "../core/protocol.js";
|
|
26
|
+
import { type Curve, type Transition } from "./effects.js";
|
|
27
|
+
/** What a change is between: the renderable drawn until now, the one drawn from now on, and the terminal whose ground the change passes through. */
|
|
28
|
+
export interface Between {
|
|
29
|
+
readonly from: Renderable;
|
|
30
|
+
readonly to: Renderable;
|
|
31
|
+
readonly theme: TerminalTheme;
|
|
32
|
+
}
|
|
33
|
+
/** A change from one renderable to another: what it draws at each moment, from `t = 0` on its own clock. */
|
|
34
|
+
export type Change = (between: Between) => Animation<Renderable>;
|
|
35
|
+
/** A crossfade: the old renderable fades to the terminal's ground and the new one rises from it, every cell together, over `curve`. */
|
|
36
|
+
export declare function crossfade(curve: Curve): Transition<Change>;
|
|
37
|
+
/**
|
|
38
|
+
* A wipe: a front crossing the element's columns from left to right over
|
|
39
|
+
* `curve`, the new renderable behind it, the old one ahead of it, and the
|
|
40
|
+
* cells within `edge` columns of it passing through the terminal's ground.
|
|
41
|
+
*/
|
|
42
|
+
export declare function wipe(curve: Curve, edge?: number): Transition<Change>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A change from one renderable to another in the same slot — a status that
|
|
3
|
+
* goes from "building" to "done", a number that becomes a different number —
|
|
4
|
+
* drawn as a crossfade or a wipe instead of a cut.
|
|
5
|
+
*
|
|
6
|
+
* Both are one shape [LAW:one-type-per-behavior]: how far each cell is through
|
|
7
|
+
* the change at `t`, from 0, the old renderable as drawn, to 1, the new one as
|
|
8
|
+
* drawn. A cell under a half shows the old one and from a half the new one,
|
|
9
|
+
* veiled toward the terminal's ground by how near the half it is (`veiled`,
|
|
10
|
+
* `./effects.ts`), so every cell passes through the ground and none jumps from
|
|
11
|
+
* one glyph to another. A crossfade has every cell at one place in the change;
|
|
12
|
+
* a wipe sends a front across the element's columns with the new renderable
|
|
13
|
+
* behind it.
|
|
14
|
+
*
|
|
15
|
+
* The change is drawn at the new renderable's size from its first frame: the
|
|
16
|
+
* old one is cut or padded to the new one's rows, so what sits beside the
|
|
17
|
+
* element moves once, at the cut, and never while the change runs. Once done
|
|
18
|
+
* it is the new renderable itself, byte for byte, and never changes again.
|
|
19
|
+
*
|
|
20
|
+
* [LAW:no-ambient-temporal-coupling] Pure in `t`: nothing is kept from one
|
|
21
|
+
* frame to the next, so the same `t` draws the same bytes at any frame rate.
|
|
22
|
+
*/
|
|
23
|
+
import { Animation } from "../core/animation.js";
|
|
24
|
+
import { Measurement } from "../core/measure.js";
|
|
25
|
+
import { render } from "../core/protocol.js";
|
|
26
|
+
import { Segment } from "../core/segment.js";
|
|
27
|
+
import { Recolored } from "./effect.js";
|
|
28
|
+
import { requireCurve, transition, veiled } from "./effects.js";
|
|
29
|
+
const clamp01 = (x) => Math.min(1, Math.max(0, x));
|
|
30
|
+
/** How much of a cell `p` of the way through a change shows: all of it at either end, none at the half, where the old gives way to the new. */
|
|
31
|
+
const shows = (p) => Math.abs(2 * p - 1);
|
|
32
|
+
/** The change over `curve`, each cell as far through it as `progress` says. */
|
|
33
|
+
function change(curve, progress) {
|
|
34
|
+
requireCurve(curve);
|
|
35
|
+
return transition(curve.seconds, ({ from, to, theme }) => Animation.sequence(Animation.continuous((t) => new ChangeFrame(from, to, theme, progress, t, curve.swing)), curve.seconds, Animation.constant(to)));
|
|
36
|
+
}
|
|
37
|
+
/** A crossfade: the old renderable fades to the terminal's ground and the new one rises from it, every cell together, over `curve`. */
|
|
38
|
+
export function crossfade(curve) {
|
|
39
|
+
return change(curve, (t) => {
|
|
40
|
+
const p = clamp01(curve.ease(clamp01(t / curve.seconds)));
|
|
41
|
+
return () => p;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** How many columns a wipe's front is soft over at its default: each cell passes through the ground as the front crosses it. */
|
|
45
|
+
const WIPE_EDGE = 6;
|
|
46
|
+
/**
|
|
47
|
+
* A wipe: a front crossing the element's columns from left to right over
|
|
48
|
+
* `curve`, the new renderable behind it, the old one ahead of it, and the
|
|
49
|
+
* cells within `edge` columns of it passing through the terminal's ground.
|
|
50
|
+
*/
|
|
51
|
+
export function wipe(curve, edge = WIPE_EDGE) {
|
|
52
|
+
if (!(Number.isFinite(edge) && edge > 0))
|
|
53
|
+
throw new RangeError(`wipe: edge must be a positive number of columns, got ${edge}`);
|
|
54
|
+
return change(curve, (t, width) => {
|
|
55
|
+
// The front starts `edge` columns before the first cell turns and ends with the last one turned.
|
|
56
|
+
const front = curve.ease(clamp01(t / curve.seconds)) * (width + edge);
|
|
57
|
+
return (_row, col) => clamp01((front - col) / edge);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/** One frame of a change at `t`: `from` and `to` spliced cell by cell, each veiled by how near the half its cell is. */
|
|
61
|
+
class ChangeFrame {
|
|
62
|
+
from;
|
|
63
|
+
to;
|
|
64
|
+
theme;
|
|
65
|
+
progress;
|
|
66
|
+
t;
|
|
67
|
+
swing;
|
|
68
|
+
constructor(from, to, theme, progress, t, swing) {
|
|
69
|
+
this.from = from;
|
|
70
|
+
this.to = to;
|
|
71
|
+
this.theme = theme;
|
|
72
|
+
this.progress = progress;
|
|
73
|
+
this.t = t;
|
|
74
|
+
this.swing = swing;
|
|
75
|
+
}
|
|
76
|
+
render(options) {
|
|
77
|
+
const before = Segment.splitLines(render(this.from, options));
|
|
78
|
+
const drawn = [...render(this.to, options)];
|
|
79
|
+
const after = Segment.splitLines(drawn);
|
|
80
|
+
// [LAW:one-source-of-truth] The new renderable's rows are the shape of every frame, its last row ending as it ends.
|
|
81
|
+
const lengths = after.map((line) => Segment.getLineLength(line));
|
|
82
|
+
const ended = drawn.filter((segment) => !segment.isControl).at(-1)?.text.endsWith("\n") ?? false;
|
|
83
|
+
const width = Math.max(0, ...lengths);
|
|
84
|
+
const at = this.progress(this.t, width);
|
|
85
|
+
const rows = after.flatMap((line, row) => [
|
|
86
|
+
...splice(Segment.adjustLineLength(before[row] ?? [], lengths[row]), line, (col) => at(row, col) >= 0.5),
|
|
87
|
+
...(row < after.length - 1 || ended ? [Segment.line()] : []),
|
|
88
|
+
]);
|
|
89
|
+
// The frame says nothing of when it changes: the change's own animation says it moves every frame.
|
|
90
|
+
const veil = veiled(() => (cell) => shows(at(cell.row, cell.col)), this.swing);
|
|
91
|
+
return render(new Recolored({ render: () => rows }, veil, { t: this.t, key: "change", theme: this.theme }), options);
|
|
92
|
+
}
|
|
93
|
+
measure(options) {
|
|
94
|
+
return Measurement.get(options, this.to);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* One row from two of the same width, each column from `after` where `isAfter`
|
|
99
|
+
* says and from `before` elsewhere. Cut at every column the side changes, so
|
|
100
|
+
* a wide glyph a cut falls in is blanked (`Segment.divide`), never halved.
|
|
101
|
+
*/
|
|
102
|
+
function splice(before, after, isAfter) {
|
|
103
|
+
const width = Segment.getLineLength(after);
|
|
104
|
+
const cuts = [];
|
|
105
|
+
for (let col = 1; col < width; col++)
|
|
106
|
+
if (isAfter(col) !== isAfter(col - 1))
|
|
107
|
+
cuts.push(col);
|
|
108
|
+
const from = Segment.divide(before, cuts);
|
|
109
|
+
const to = Segment.divide(after, cuts);
|
|
110
|
+
const starts = [0, ...cuts];
|
|
111
|
+
return starts.flatMap((start, i) => (isAfter(start) ? (to[i] ?? []) : (from[i] ?? [])));
|
|
112
|
+
}
|
|
@@ -19,7 +19,7 @@ export interface ColumnsOptions {
|
|
|
19
19
|
columnFirst?: boolean;
|
|
20
20
|
}
|
|
21
21
|
export declare class Columns implements Renderable, Measurable {
|
|
22
|
-
renderables: (Renderable & Partial<Measurable>)[];
|
|
22
|
+
readonly renderables: readonly (Renderable & Partial<Measurable>)[];
|
|
23
23
|
readonly expand: boolean;
|
|
24
24
|
readonly equal: boolean;
|
|
25
25
|
readonly colWidth: number | undefined;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { Measurement } from "../core/measure.js";
|
|
12
12
|
import { normalizePadding } from "./padding.js";
|
|
13
|
-
import { withBoundedWidth, withCellWidth } from "../core/protocol.js";
|
|
13
|
+
import { measure, render, withBoundedWidth, withCellWidth } from "../core/protocol.js";
|
|
14
14
|
import { cellCount } from "../core/cells.js";
|
|
15
15
|
import { EmbeddedText, embed } from "./embed.js";
|
|
16
16
|
import { Constrain } from "./constrain.js";
|
|
@@ -68,7 +68,7 @@ export class Columns {
|
|
|
68
68
|
// single column is laid out. An unbounded width reaches the same place by
|
|
69
69
|
// the same route, which is why the parse here is the bounded one.
|
|
70
70
|
const options = withBoundedWidth(rawOptions, this);
|
|
71
|
-
yield* this._grid(options)
|
|
71
|
+
yield* render(this._grid(options), options);
|
|
72
72
|
}
|
|
73
73
|
measure(rawOptions) {
|
|
74
74
|
// The maximum is the grid's, which reports its width before `expand`: a
|
|
@@ -84,7 +84,7 @@ export class Columns {
|
|
|
84
84
|
const parsed = withCellWidth(rawOptions);
|
|
85
85
|
if (this.renderables.length === 0)
|
|
86
86
|
return { minimum: 0, maximum: 0 };
|
|
87
|
-
const { maximum } = this._grid(parsed)
|
|
87
|
+
const { maximum } = measure(this._grid(parsed), parsed);
|
|
88
88
|
return { minimum: Math.min(1, maximum), maximum };
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Constrain — wraps a renderable and constrains its maximum width.
|
|
3
3
|
*/
|
|
4
4
|
import { Measurement } from "../core/measure.js";
|
|
5
|
+
import { render } from "../core/protocol.js";
|
|
5
6
|
export class Constrain {
|
|
6
7
|
renderable;
|
|
7
8
|
width;
|
|
@@ -18,7 +19,7 @@ export class Constrain {
|
|
|
18
19
|
...options,
|
|
19
20
|
maxWidth: constrainedWidth,
|
|
20
21
|
};
|
|
21
|
-
yield* this.renderable
|
|
22
|
+
yield* render(this.renderable, innerOptions);
|
|
22
23
|
}
|
|
23
24
|
measure(options) {
|
|
24
25
|
// Measured at the width it will be drawn at, as Rich's `update_width` does;
|