@promptctl/rich-js 0.26.0 → 0.27.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/dist/core/animation.d.ts +26 -8
- package/dist/core/animation.js +32 -11
- package/dist/core/color.d.ts +20 -11
- package/dist/core/color.js +26 -21
- package/dist/core/console.d.ts +8 -0
- package/dist/core/console.js +2 -1
- package/dist/core/easing.js +6 -1
- package/dist/core/oklch.d.ts +2 -0
- package/dist/core/oklch.js +3 -3
- package/dist/core/protocol.d.ts +26 -16
- package/dist/core/render.d.ts +1 -1
- package/dist/core/render.js +1 -0
- package/dist/core/view.d.ts +22 -8
- package/dist/core/view.js +32 -8
- package/dist/host/app.d.ts +4 -4
- package/dist/host/app.js +5 -5
- package/dist/index.d.ts +5 -4
- package/dist/renderables/effect.d.ts +7 -7
- package/dist/renderables/effects.js +8 -3
- package/dist/renderables/lifecycle.d.ts +38 -28
- package/dist/renderables/lifecycle.js +85 -45
- package/dist/renderables/live.d.ts +3 -3
- package/dist/renderables/live.js +4 -4
- package/dist/renderables/progress.d.ts +11 -4
- package/dist/renderables/progress.js +29 -17
- package/dist/themes/buildPalette.d.ts +14 -39
- package/dist/themes/buildPalette.js +196 -67
- package/dist/themes/colorMath.d.ts +10 -4
- package/dist/themes/colorMath.js +33 -1
- package/dist/themes/data/types.d.ts +3 -1
- package/dist/themes/palette.d.ts +22 -6
- package/dist/themes/palette.js +13 -21
- package/dist/themes/registry.d.ts +2 -3
- package/dist/themes/registry.js +7 -26
- package/dist/themes/terminalThemes.d.ts +6 -5
- package/dist/themes/terminalThemes.js +6 -5
- package/dist/themes/transpose.d.ts +5 -10
- package/dist/themes/transpose.js +13 -24
- package/dist/widgets/event-router.js +2 -2
- package/dist/widgets/ink.d.ts +5 -4
- package/dist/widgets/ink.js +6 -9
- package/dist/widgets/text-input.d.ts +1 -1
- package/dist/widgets/text-input.js +41 -32
- package/dist/widgets/types.d.ts +2 -2
- package/dist/widgets/widget-app.d.ts +3 -3
- package/dist/widgets/widget-app.js +5 -5
- package/package.json +1 -1
package/dist/core/animation.d.ts
CHANGED
|
@@ -137,14 +137,23 @@ export declare function stampFrame(segments: Iterable<Segment>, hold: Hold): Ite
|
|
|
137
137
|
*/
|
|
138
138
|
export declare function frameTimeOf(options: RenderOptions): number;
|
|
139
139
|
/**
|
|
140
|
-
* An animation
|
|
141
|
-
*
|
|
142
|
-
* its hold there under whatever its own cells say, and the hold told to
|
|
143
|
-
* frame (`RenderOptions.onHold`), because a frame of no cells — an
|
|
144
|
-
* not yet entered — may have cells later, and must say when without
|
|
145
|
-
* row to say it in.
|
|
146
|
-
*
|
|
147
|
-
*
|
|
140
|
+
* An animation placed in the frame `options` draws: its value at the frame's
|
|
141
|
+
* time (`frameTimeOf`, `shownAt`), drawn by `draw`, every segment stamped
|
|
142
|
+
* with its hold there under whatever its own cells say, and the hold told to
|
|
143
|
+
* the frame (`RenderOptions.onHold`), because a frame of no cells — an
|
|
144
|
+
* element not yet entered — may have cells later, and must say when without
|
|
145
|
+
* taking a row to say it in. [LAW:single-enforcer] The one placement: an
|
|
146
|
+
* animation of renderables (`placedRender`) and a widget drawing one cell
|
|
147
|
+
* from an animation of its own (a caret's blink) place through it, so how a
|
|
148
|
+
* time reaches an animation and how its hold reaches the frame is written
|
|
149
|
+
* once.
|
|
150
|
+
*/
|
|
151
|
+
export declare function placed<T>(animation: Timed<T>, options: RenderOptions, draw: (value: T) => Iterable<Segment>): Iterable<Segment>;
|
|
152
|
+
/**
|
|
153
|
+
* An animation's face, `render`: `placed`, its value drawn as the renderable
|
|
154
|
+
* it is. A container — the library's or a user's — that draws its children
|
|
155
|
+
* through `render` draws an animation among them with no word about time:
|
|
156
|
+
* the hold goes back the way the time came in. [LAW:composability]
|
|
148
157
|
*/
|
|
149
158
|
export declare function placedRender(animation: Timed<unknown>, options: RenderOptions): Iterable<Segment>;
|
|
150
159
|
/**
|
|
@@ -169,6 +178,15 @@ export declare const Animation: {
|
|
|
169
178
|
* renderables throws when it is drawn.
|
|
170
179
|
*/
|
|
171
180
|
of<X extends Timed<unknown>>(timed: X): Faced<NoInfer<X>>;
|
|
181
|
+
/**
|
|
182
|
+
* Whether `animation` never changes again from `t`: a one-shot that has
|
|
183
|
+
* run, a loop at a depth that shows no motion. [LAW:single-enforcer] The
|
|
184
|
+
* one reading of "never": a `Transition`'s `done` and a lifecycle's
|
|
185
|
+
* arrived and gone moments are this, so what ends a one-shot is written
|
|
186
|
+
* once. An early answer the contract allows is a finite one, so `Infinity`
|
|
187
|
+
* is only ever a true never.
|
|
188
|
+
*/
|
|
189
|
+
done(animation: Timed<unknown>, t: number): boolean;
|
|
172
190
|
/** `value` at every time, never changing. */
|
|
173
191
|
constant<T>(value: T): Animation<T>;
|
|
174
192
|
/**
|
package/dist/core/animation.js
CHANGED
|
@@ -126,22 +126,32 @@ function drawable(value) {
|
|
|
126
126
|
return value;
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
|
-
* An animation
|
|
130
|
-
*
|
|
131
|
-
* its hold there under whatever its own cells say, and the hold told to
|
|
132
|
-
* frame (`RenderOptions.onHold`), because a frame of no cells — an
|
|
133
|
-
* not yet entered — may have cells later, and must say when without
|
|
134
|
-
* row to say it in.
|
|
135
|
-
*
|
|
136
|
-
*
|
|
129
|
+
* An animation placed in the frame `options` draws: its value at the frame's
|
|
130
|
+
* time (`frameTimeOf`, `shownAt`), drawn by `draw`, every segment stamped
|
|
131
|
+
* with its hold there under whatever its own cells say, and the hold told to
|
|
132
|
+
* the frame (`RenderOptions.onHold`), because a frame of no cells — an
|
|
133
|
+
* element not yet entered — may have cells later, and must say when without
|
|
134
|
+
* taking a row to say it in. [LAW:single-enforcer] The one placement: an
|
|
135
|
+
* animation of renderables (`placedRender`) and a widget drawing one cell
|
|
136
|
+
* from an animation of its own (a caret's blink) place through it, so how a
|
|
137
|
+
* time reaches an animation and how its hold reaches the frame is written
|
|
138
|
+
* once.
|
|
137
139
|
*/
|
|
138
|
-
export function*
|
|
140
|
+
export function* placed(animation, options, draw) {
|
|
139
141
|
const t = frameTimeOf(options);
|
|
140
142
|
const shown = shownAt(animation, t, options);
|
|
141
|
-
const value = drawable(shown.value);
|
|
142
143
|
const hold = holdOf(shown, t);
|
|
143
144
|
options.onHold?.(hold);
|
|
144
|
-
yield* stampFrame(
|
|
145
|
+
yield* stampFrame(draw(shown.value), hold);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* An animation's face, `render`: `placed`, its value drawn as the renderable
|
|
149
|
+
* it is. A container — the library's or a user's — that draws its children
|
|
150
|
+
* through `render` draws an animation among them with no word about time:
|
|
151
|
+
* the hold goes back the way the time came in. [LAW:composability]
|
|
152
|
+
*/
|
|
153
|
+
export function placedRender(animation, options) {
|
|
154
|
+
return placed(animation, options, (value) => render(drawable(value), options));
|
|
145
155
|
}
|
|
146
156
|
/**
|
|
147
157
|
* An animation's face, `measure`: what it shows at the frame's time, measured,
|
|
@@ -191,6 +201,17 @@ export const Animation = {
|
|
|
191
201
|
});
|
|
192
202
|
return faced;
|
|
193
203
|
},
|
|
204
|
+
/**
|
|
205
|
+
* Whether `animation` never changes again from `t`: a one-shot that has
|
|
206
|
+
* run, a loop at a depth that shows no motion. [LAW:single-enforcer] The
|
|
207
|
+
* one reading of "never": a `Transition`'s `done` and a lifecycle's
|
|
208
|
+
* arrived and gone moments are this, so what ends a one-shot is written
|
|
209
|
+
* once. An early answer the contract allows is a finite one, so `Infinity`
|
|
210
|
+
* is only ever a true never.
|
|
211
|
+
*/
|
|
212
|
+
done(animation, t) {
|
|
213
|
+
return animation.nextChange(t) === Number.POSITIVE_INFINITY;
|
|
214
|
+
},
|
|
194
215
|
/** `value` at every time, never changing. */
|
|
195
216
|
constant(value) {
|
|
196
217
|
const still = Animation.of({ at: () => value, nextChange: () => Number.POSITIVE_INFINITY, lastChange: () => Number.NEGATIVE_INFINITY, reduced: () => still });
|
package/dist/core/color.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Terminal color representation, parsing, downgrading, and ANSI code generation.
|
|
3
3
|
*/
|
|
4
4
|
import type { Env } from "./env.js";
|
|
5
|
+
import type { Palette } from "../themes/palette.js";
|
|
5
6
|
/**
|
|
6
7
|
* Immutable RGBA color value. Alpha defaults to 1 (fully opaque).
|
|
7
8
|
*
|
|
@@ -244,7 +245,7 @@ export declare class ColorSpec {
|
|
|
244
245
|
/**
|
|
245
246
|
* Resolves to an actual RGB(A) value for any color type.
|
|
246
247
|
*/
|
|
247
|
-
getTruecolor(theme?:
|
|
248
|
+
getTruecolor(theme?: TerminalColors, foreground?: boolean): ColorRgba;
|
|
248
249
|
static default(): ColorSpec;
|
|
249
250
|
static fromAnsi(n: number): ColorSpec;
|
|
250
251
|
static fromRgba(value: ColorRgba): ColorSpec;
|
|
@@ -275,7 +276,7 @@ export declare class ColorSpec {
|
|
|
275
276
|
* `value` is opaque: a translucent colour has no one look until it is laid
|
|
276
277
|
* on a ground (`flattenAlpha`).
|
|
277
278
|
*/
|
|
278
|
-
static matchOn(value: ColorRgba, depth: ColorDepth, theme:
|
|
279
|
+
static matchOn(value: ColorRgba, depth: ColorDepth, theme: TerminalColors, foreground: boolean): ColorSpec;
|
|
279
280
|
/**
|
|
280
281
|
* Every colour `depth` writes by index, each with the colour a terminal
|
|
281
282
|
* known to show `theme` draws it in, lowest index first: the theme's
|
|
@@ -285,7 +286,7 @@ export declare class ColorSpec {
|
|
|
285
286
|
* depth only the default, so neither writes any by index. The colours
|
|
286
287
|
* `matchOn` rounds to, but for the default, read off the same two tables.
|
|
287
288
|
*/
|
|
288
|
-
static indexed(depth: ColorDepth, theme:
|
|
289
|
+
static indexed(depth: ColorDepth, theme: TerminalColors): readonly (readonly [ColorSpec, ColorRgba])[];
|
|
289
290
|
/**
|
|
290
291
|
* The spec a slot is written in once its colour moves from `was`, what its
|
|
291
292
|
* written spec draws on `theme`, to the opaque `now`: `matchOn`'s — or
|
|
@@ -294,7 +295,7 @@ export declare class ColorSpec {
|
|
|
294
295
|
* off any colour the depth can write — a theme slot, the default colour,
|
|
295
296
|
* the cube — keeps the spec it was written in.
|
|
296
297
|
*/
|
|
297
|
-
static matchMove(was: ColorRgba, now: ColorRgba, depth: ColorDepth, theme:
|
|
298
|
+
static matchMove(was: ColorRgba, now: ColorRgba, depth: ColorDepth, theme: TerminalColors, foreground: boolean): ColorSpec | undefined;
|
|
298
299
|
/**
|
|
299
300
|
* Parse a color string. Memoized (`Memo`): a string parsed again while
|
|
300
301
|
* remembered returns the same instance.
|
|
@@ -312,6 +313,17 @@ export declare function parseRgbaHex(hex: string): ColorRgba;
|
|
|
312
313
|
*/
|
|
313
314
|
export declare function parseHexColor(literal: string): ColorRgba;
|
|
314
315
|
export declare function blendRgb(color1: ColorRgba, color2: ColorRgba, crossFade?: number): ColorRgba;
|
|
316
|
+
/**
|
|
317
|
+
* What a terminal draws with: the part of a `TerminalTheme` a colour resolves
|
|
318
|
+
* against.
|
|
319
|
+
*/
|
|
320
|
+
export declare class TerminalColors {
|
|
321
|
+
readonly backgroundColor: ColorRgba;
|
|
322
|
+
readonly foregroundColor: ColorRgba;
|
|
323
|
+
readonly ansiColors: ColorTable;
|
|
324
|
+
private readonly checked;
|
|
325
|
+
constructor(backgroundColor: ColorRgba, foregroundColor: ColorRgba, ansiColors: ColorTable);
|
|
326
|
+
}
|
|
315
327
|
/**
|
|
316
328
|
* A terminal theme — surface/foreground baseline, the sixteen ANSI colours,
|
|
317
329
|
* and a semantic palette.
|
|
@@ -321,12 +333,9 @@ export declare function blendRgb(color1: ColorRgba, color2: ColorRgba, crossFade
|
|
|
321
333
|
* is ANSI colour 1 under every theme; which red that is, is the theme's to say,
|
|
322
334
|
* as it is in Rich, where each `TerminalTheme` carries its own table.
|
|
323
335
|
*/
|
|
324
|
-
export declare class TerminalTheme {
|
|
325
|
-
readonly
|
|
326
|
-
|
|
327
|
-
readonly ansiColors: ColorTable;
|
|
328
|
-
readonly palette: import("../themes/palette.js").Palette;
|
|
329
|
-
constructor(backgroundColor: ColorRgba, foregroundColor: ColorRgba, ansiColors: ColorTable, palette: import("../themes/palette.js").Palette);
|
|
336
|
+
export declare class TerminalTheme extends TerminalColors {
|
|
337
|
+
readonly palette: Palette;
|
|
338
|
+
constructor(backgroundColor: ColorRgba, foregroundColor: ColorRgba, ansiColors: ColorTable, palette: Palette);
|
|
330
339
|
}
|
|
331
340
|
export declare const STANDARD_TABLE: ColorTable;
|
|
332
341
|
export declare const EIGHT_BIT_TABLE: ColorTable;
|
|
@@ -345,7 +354,7 @@ export declare const WINDOWS_TABLE: ColorTable;
|
|
|
345
354
|
* that reads it. (Widgets fall back to `DEFAULT_TERMINAL_THEME`, which carries a
|
|
346
355
|
* palette this does not.)
|
|
347
356
|
*/
|
|
348
|
-
export declare function resolveTerminal(theme:
|
|
357
|
+
export declare function resolveTerminal(theme: TerminalColors | undefined, depth: ColorDepth): TerminalColors;
|
|
349
358
|
/**
|
|
350
359
|
* The table a downgrade to `depth` rounds a fixed colour against.
|
|
351
360
|
* [LAW:one-source-of-truth] `ColorSpec.downgrade` picks the index a colour is
|
package/dist/core/color.js
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Memo, WeakMemo } from "./memo.js";
|
|
5
5
|
import { pattern } from "./pattern.js";
|
|
6
|
-
// Runtime-importing `Palette` from `themes/palette.ts` is safe: that module
|
|
7
|
-
// only `import type`s from `core/color.ts`, so there is no runtime cycle.
|
|
8
|
-
import { Palette } from "../themes/palette.js";
|
|
9
6
|
// --- ColorRgba ---
|
|
10
7
|
function hex2(byte) {
|
|
11
8
|
return byte.toString(16).padStart(2, "0");
|
|
@@ -844,24 +841,17 @@ export function blendRgb(color1, color2, crossFade = 0.5) {
|
|
|
844
841
|
}
|
|
845
842
|
// --- TerminalTheme ---
|
|
846
843
|
/**
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
* **`ansiColors` is the theme's own sixteen colours**, the shades a terminal
|
|
851
|
-
* showing this theme draws `red`, `blue` and the rest in. `ColorSpec.parse("red")`
|
|
852
|
-
* is ANSI colour 1 under every theme; which red that is, is the theme's to say,
|
|
853
|
-
* as it is in Rich, where each `TerminalTheme` carries its own table.
|
|
844
|
+
* What a terminal draws with: the part of a `TerminalTheme` a colour resolves
|
|
845
|
+
* against.
|
|
854
846
|
*/
|
|
855
|
-
export class
|
|
847
|
+
export class TerminalColors {
|
|
856
848
|
backgroundColor;
|
|
857
849
|
foregroundColor;
|
|
858
850
|
ansiColors;
|
|
859
|
-
|
|
860
|
-
constructor(backgroundColor, foregroundColor, ansiColors, palette) {
|
|
851
|
+
constructor(backgroundColor, foregroundColor, ansiColors) {
|
|
861
852
|
this.backgroundColor = backgroundColor;
|
|
862
853
|
this.foregroundColor = foregroundColor;
|
|
863
854
|
this.ansiColors = ansiColors;
|
|
864
|
-
this.palette = palette;
|
|
865
855
|
// [LAW:parse-dont-validate] Every reader indexes `ansiColors` 0–15 as the
|
|
866
856
|
// terminal's sixteen, so a theme is the proof it holds exactly those.
|
|
867
857
|
if (ansiColors.firstIndex !== 0 || ansiColors.size !== 16) {
|
|
@@ -869,6 +859,22 @@ export class TerminalTheme {
|
|
|
869
859
|
}
|
|
870
860
|
}
|
|
871
861
|
}
|
|
862
|
+
/**
|
|
863
|
+
* A terminal theme — surface/foreground baseline, the sixteen ANSI colours,
|
|
864
|
+
* and a semantic palette.
|
|
865
|
+
*
|
|
866
|
+
* **`ansiColors` is the theme's own sixteen colours**, the shades a terminal
|
|
867
|
+
* showing this theme draws `red`, `blue` and the rest in. `ColorSpec.parse("red")`
|
|
868
|
+
* is ANSI colour 1 under every theme; which red that is, is the theme's to say,
|
|
869
|
+
* as it is in Rich, where each `TerminalTheme` carries its own table.
|
|
870
|
+
*/
|
|
871
|
+
export class TerminalTheme extends TerminalColors {
|
|
872
|
+
palette;
|
|
873
|
+
constructor(backgroundColor, foregroundColor, ansiColors, palette) {
|
|
874
|
+
super(backgroundColor, foregroundColor, ansiColors);
|
|
875
|
+
this.palette = palette;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
872
878
|
// --- ColorTable data ---
|
|
873
879
|
function buildStandard16() {
|
|
874
880
|
return [
|
|
@@ -943,7 +949,7 @@ export const EIGHT_BIT_TABLE = new ColorTable(build256Table());
|
|
|
943
949
|
*/
|
|
944
950
|
export const EIGHT_BIT_DOWNGRADE_TABLE = new ColorTable(build256Table().slice(16), 16);
|
|
945
951
|
export const WINDOWS_TABLE = new ColorTable(buildWindowsTable());
|
|
946
|
-
// --- Internal fallback
|
|
952
|
+
// --- Internal fallback terminals ---
|
|
947
953
|
//
|
|
948
954
|
// [LAW:one-way-deps] Preset themes (DEFAULT_TERMINAL_THEME, MONOKAI, NORD, ...)
|
|
949
955
|
// live in `src/themes/terminalThemes.ts` because they need `buildPalette` from
|
|
@@ -951,12 +957,11 @@ export const WINDOWS_TABLE = new ColorTable(buildWindowsTable());
|
|
|
951
957
|
// `themes/* -> core/color`, with no runtime back-edge.
|
|
952
958
|
//
|
|
953
959
|
// `getTruecolor()` retains a fallback for callers that omit `theme`: the
|
|
954
|
-
// terminal a colour's depth assumes,
|
|
955
|
-
//
|
|
956
|
-
|
|
957
|
-
const INTERNAL_DEFAULT_THEME = new TerminalTheme(new ColorRgba(0, 0, 0), new ColorRgba(255, 255, 255), STANDARD_TABLE, new Palette("default", true, new Map()));
|
|
960
|
+
// terminal a colour's depth assumes, its own sixteen and no palette, which the
|
|
961
|
+
// lookups it serves never read.
|
|
962
|
+
const INTERNAL_DEFAULT_TERMINAL = new TerminalColors(new ColorRgba(0, 0, 0), new ColorRgba(255, 255, 255), STANDARD_TABLE);
|
|
958
963
|
/** The Windows console in its default Campbell scheme: a WINDOWS colour's terminal. */
|
|
959
|
-
const
|
|
964
|
+
const WINDOWS_CONSOLE_TERMINAL = new TerminalColors(WINDOWS_TABLE.get(0), WINDOWS_TABLE.get(7), WINDOWS_TABLE);
|
|
960
965
|
/**
|
|
961
966
|
* The terminal a colour at `depth` is drawn by: `theme`, or when a caller names
|
|
962
967
|
* none, the one the depth assumes — the Windows console at WINDOWS, the VGA
|
|
@@ -965,7 +970,7 @@ const WINDOWS_CONSOLE_THEME = new TerminalTheme(WINDOWS_TABLE.get(0), WINDOWS_TA
|
|
|
965
970
|
* palette this does not.)
|
|
966
971
|
*/
|
|
967
972
|
export function resolveTerminal(theme, depth) {
|
|
968
|
-
return theme ?? (depth === ColorDepth.WINDOWS ?
|
|
973
|
+
return theme ?? (depth === ColorDepth.WINDOWS ? WINDOWS_CONSOLE_TERMINAL : INTERNAL_DEFAULT_TERMINAL);
|
|
969
974
|
}
|
|
970
975
|
/**
|
|
971
976
|
* The table a downgrade to `depth` rounds a fixed colour against.
|
package/dist/core/console.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { type JSONOptions } from "./json.js";
|
|
|
10
10
|
import type { Highlighter } from "./highlighter.js";
|
|
11
11
|
import { type RuleOptions } from "../renderables/rule.js";
|
|
12
12
|
import type { Height, OverflowMethod, RenderOptions, StyleErrorHandler } from "./protocol.js";
|
|
13
|
+
import { type HostFrame } from "./protocol.js";
|
|
13
14
|
import type { Unsubscribe } from "./subscription.js";
|
|
14
15
|
export interface ConsoleSink {
|
|
15
16
|
write(chunk: string | Uint8Array): unknown;
|
|
@@ -125,6 +126,13 @@ export interface ConsoleOptions {
|
|
|
125
126
|
}
|
|
126
127
|
export interface PrintOptions {
|
|
127
128
|
style?: string | Style;
|
|
129
|
+
/**
|
|
130
|
+
* The frame this print is drawn in (`RenderOptions.frame`): the moment
|
|
131
|
+
* everything in it that moves is drawn for, named by the caller — a host's
|
|
132
|
+
* `frameNow()`. [LAW:single-enforcer] The one place a print's time is
|
|
133
|
+
* decided; absent, the print is drawn for no moment, 0 (`frameTimeOf`).
|
|
134
|
+
*/
|
|
135
|
+
frame?: HostFrame;
|
|
128
136
|
justify?: "default" | "left" | "center" | "right" | "full";
|
|
129
137
|
overflow?: OverflowMethod;
|
|
130
138
|
highlight?: boolean;
|
package/dist/core/console.js
CHANGED
|
@@ -317,7 +317,7 @@ export class Console {
|
|
|
317
317
|
!isRenderable(lastArg) &&
|
|
318
318
|
("style" in lastArg || "justify" in lastArg || "markup" in lastArg ||
|
|
319
319
|
"highlight" in lastArg || "overflow" in lastArg || "end" in lastArg ||
|
|
320
|
-
"softWrap" in lastArg || "crop" in lastArg || "sep" in lastArg)) {
|
|
320
|
+
"softWrap" in lastArg || "crop" in lastArg || "sep" in lastArg || "frame" in lastArg)) {
|
|
321
321
|
opts = lastArg;
|
|
322
322
|
items = args.slice(0, -1);
|
|
323
323
|
}
|
|
@@ -407,6 +407,7 @@ export class Console {
|
|
|
407
407
|
const renderOpts = {
|
|
408
408
|
...options,
|
|
409
409
|
...strings,
|
|
410
|
+
frame: opts.frame,
|
|
410
411
|
justify: opts.justify === "default" ? undefined : opts.justify,
|
|
411
412
|
overflow: opts.overflow ?? (softWrap ? "ignore" : undefined),
|
|
412
413
|
noWrap: softWrap,
|
package/dist/core/easing.js
CHANGED
|
@@ -379,7 +379,12 @@ export function passAt(what, t, period) {
|
|
|
379
379
|
// takes off; carrying a pass's start out of `t` itself would leave each
|
|
380
380
|
// sample its own rounding. `+ 0` turns the `-0` a small negative `t` rounds
|
|
381
381
|
// to into pass 0, so the pass is a plain integer whoever reads it.
|
|
382
|
-
|
|
382
|
+
const pass = Math.round((t - into) / period) + 0;
|
|
383
|
+
// [LAW:no-silent-failure] Past where a pass is a float, `period` is finer than time resolves: the refusal a
|
|
384
|
+
// boundary walked there gives, said of `t` and not of the infinite sum a pass that overflowed would build.
|
|
385
|
+
if (!Number.isFinite(pass))
|
|
386
|
+
throw new RangeError(`${what}: a period of ${period} s is finer than time resolves near t = ${t}`);
|
|
387
|
+
return { pass, into };
|
|
383
388
|
}
|
|
384
389
|
/** The least normal double, 2^-1022: below it every double is a multiple of `Number.MIN_VALUE`. */
|
|
385
390
|
const MIN_NORMAL = 2 ** -1022;
|
package/dist/core/oklch.d.ts
CHANGED
|
@@ -64,6 +64,8 @@ export declare const INVERT_LIGHTNESS: ThemeKey;
|
|
|
64
64
|
* the predicate lives once, here.
|
|
65
65
|
*/
|
|
66
66
|
export declare function isIdentityKey(k: ThemeKey): boolean;
|
|
67
|
+
export declare function srgbToLinear(v: number): number;
|
|
68
|
+
export declare function linearToSrgb(v: number): number;
|
|
67
69
|
/**
|
|
68
70
|
* Immutable OKLCH color. `l` ∈ [0, 1] (lightness), `c` ≥ 0 (chroma; typical
|
|
69
71
|
* sRGB-representable colors top out near 0.32), `h` ∈ [0, 360) (hue
|
package/dist/core/oklch.js
CHANGED
|
@@ -57,12 +57,12 @@ export function isIdentityKey(k) {
|
|
|
57
57
|
k.lightnessShift === 0);
|
|
58
58
|
}
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
|
-
// Pure conversion helpers
|
|
60
|
+
// Pure conversion helpers.
|
|
61
61
|
// ---------------------------------------------------------------------------
|
|
62
|
-
function srgbToLinear(v) {
|
|
62
|
+
export function srgbToLinear(v) {
|
|
63
63
|
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
64
64
|
}
|
|
65
|
-
function linearToSrgb(v) {
|
|
65
|
+
export function linearToSrgb(v) {
|
|
66
66
|
return v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
|
|
67
67
|
}
|
|
68
68
|
function clamp01(v) {
|
package/dist/core/protocol.d.ts
CHANGED
|
@@ -18,13 +18,27 @@ import type { Highlighter } from "./highlighter.js";
|
|
|
18
18
|
*/
|
|
19
19
|
export type OverflowMethod = "fold" | "crop" | "ellipsis" | "ignore";
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* The frame being drawn, as a value: `time`, the moment it is drawn for, in
|
|
22
|
+
* seconds, on the clock its cells' `nextChange` stamps are read on, and
|
|
23
|
+
* `host`, the identity of what drew it — nothing to read, so what draws in
|
|
24
|
+
* the frame has one time, this one, and cannot ask the host for another.
|
|
25
|
+
* [LAW:types-are-the-program] A `Progress` keeps the identity to refuse a
|
|
26
|
+
* frame of a host other than the one its tasks are timed on.
|
|
27
|
+
*/
|
|
28
|
+
export interface HostFrame {
|
|
29
|
+
readonly time: number;
|
|
30
|
+
readonly host: object;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* What draws frames — a `Live`, an `App` — as what runs between them sees
|
|
34
|
+
* it: the frame it would draw now, its time the host's clock read through
|
|
35
|
+
* its timeline (`frameNow`, `./view.ts`). Not a `Clock`: under a paused
|
|
36
|
+
* timeline it holds, and under a reversed one it runs backwards. Asked
|
|
37
|
+
* inside a render it throws (`RenderClockError`): a frame has the time it was
|
|
38
|
+
* drawn for, and a renderable reads that one.
|
|
25
39
|
*/
|
|
26
40
|
export interface FrameHost {
|
|
27
|
-
|
|
41
|
+
frameNow(): HostFrame;
|
|
28
42
|
}
|
|
29
43
|
export interface RenderOptions {
|
|
30
44
|
/**
|
|
@@ -105,18 +119,14 @@ export interface RenderOptions {
|
|
|
105
119
|
*/
|
|
106
120
|
reducedMotion?: boolean;
|
|
107
121
|
/**
|
|
108
|
-
* The frame being drawn
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* nothing drawn from it moves.
|
|
122
|
+
* The frame being drawn (`HostFrame`): how a renderable that lives across
|
|
123
|
+
* frames — a widget, a `Progress` — draws for the time without being
|
|
124
|
+
* rebuilt each frame with one, and without reading a clock. A host writes
|
|
125
|
+
* it once a frame, and a print writes the one its caller named
|
|
126
|
+
* (`PrintOptions.frame`). Absent, the frame is drawn for no moment, 0
|
|
127
|
+
* (`frameTimeOf`, `./animation.ts`), and nothing drawn from it moves.
|
|
115
128
|
*/
|
|
116
|
-
frame?:
|
|
117
|
-
readonly time: number;
|
|
118
|
-
readonly host: FrameHost;
|
|
119
|
-
};
|
|
129
|
+
frame?: HostFrame;
|
|
120
130
|
/**
|
|
121
131
|
* Told of every renderable `render` is asked for, as it is asked, so the
|
|
122
132
|
* calls arrive in document order: a container before what it holds, what
|
package/dist/core/render.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ import type { ColorSystemName, Destination } from "./color.js";
|
|
|
49
49
|
import type { Env } from "./env.js";
|
|
50
50
|
import { Segment } from "./segment.js";
|
|
51
51
|
import type { Renderable, RenderOptions } from "./protocol.js";
|
|
52
|
-
export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" | "reducedMotion" | "theme" | "onStyleError" | "highlight" | "highlighter"> {
|
|
52
|
+
export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" | "reducedMotion" | "theme" | "onStyleError" | "highlight" | "highlighter" | "frame"> {
|
|
53
53
|
/** Cell width to render into. Default 80. */
|
|
54
54
|
width?: number;
|
|
55
55
|
/**
|
package/dist/core/render.js
CHANGED
|
@@ -118,6 +118,7 @@ export function renderToString(renderable, options) {
|
|
|
118
118
|
onStyleError: options?.onStyleError,
|
|
119
119
|
highlight: options?.highlight,
|
|
120
120
|
highlighter: options?.highlighter,
|
|
121
|
+
frame: options?.frame,
|
|
121
122
|
// [LAW:one-source-of-truth] The depth the segments below are encoded at,
|
|
122
123
|
// so a renderable measures what this very call will draw.
|
|
123
124
|
colorSystem: destination.colorSystem,
|
package/dist/core/view.d.ts
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* `./segment.ts`, `./protocol.ts` and `./style.ts`'s `Hold`, nothing else.
|
|
37
37
|
* [LAW:one-way-deps]
|
|
38
38
|
*/
|
|
39
|
-
import { type
|
|
39
|
+
import { type HostFrame, type Renderable, type RenderOptions } from "./protocol.js";
|
|
40
40
|
import { Segment } from "./segment.js";
|
|
41
41
|
import { Timeline } from "./timeline.js";
|
|
42
42
|
/**
|
|
@@ -61,12 +61,26 @@ export interface HostTime {
|
|
|
61
61
|
/**
|
|
62
62
|
* The time a frame drawn at `time` is drawn for, on the clock its cells are
|
|
63
63
|
* stamped on: the time the timeline maps `now` to. [LAW:single-enforcer]
|
|
64
|
-
* `
|
|
65
|
-
* `
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* `frameNow` puts it on the frame `drawView` draws and on the one a host
|
|
65
|
+
* hands out between frames (`frameNow`) — what a key is stamped with — so a
|
|
66
|
+
* moment a widget keeps and the frame it is compared against are on one
|
|
67
|
+
* clock.
|
|
68
68
|
*/
|
|
69
69
|
export declare function frameTime(time: HostTime): number;
|
|
70
|
+
/** A host's frame was asked for during a render or measure. */
|
|
71
|
+
export declare class RenderClockError extends Error {
|
|
72
|
+
constructor();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The frame `host` draws now, at `time`: what every host hands out as
|
|
76
|
+
* `frameNow()`, and what `drawView` draws. [LAW:single-enforcer] The one
|
|
77
|
+
* place a host's time is read for a frame, so the one place it is refused
|
|
78
|
+
* inside a render or measure (`RenderClockError`): a renderable drawing in a
|
|
79
|
+
* frame has that frame's time and asks nothing else, as `State.set` is
|
|
80
|
+
* refused there (`./state.ts`). A frame is a value with no clock on it, so a
|
|
81
|
+
* renderable handed one cannot read a second, moving time mid-render.
|
|
82
|
+
*/
|
|
83
|
+
export declare function frameNow(host: object, time: HostTime): HostFrame;
|
|
70
84
|
/** What a frame drawn at host time `t` says about when it changes. */
|
|
71
85
|
export interface FrameSays {
|
|
72
86
|
/** The host time the frame was drawn at. */
|
|
@@ -86,7 +100,7 @@ export declare const undrawn: (t: number) => FrameSays;
|
|
|
86
100
|
* overflow — and when the frame changes on the host's clock: the hold its
|
|
87
101
|
* cells say, carried back through the timeline. [LAW:one-source-of-truth]
|
|
88
102
|
* `options` is the one place the frame reads the reader's preference for
|
|
89
|
-
* motion, handed on to `draw` with the frame: the time it is
|
|
90
|
-
*
|
|
103
|
+
* motion, handed on to `draw` with the frame (`frameNow`): the time it is
|
|
104
|
+
* drawn for and `drawnBy`, the host whose time that is.
|
|
91
105
|
*/
|
|
92
|
-
export declare function drawView(view: Renderable, time: HostTime, drawnBy:
|
|
106
|
+
export declare function drawView(view: Renderable, time: HostTime, drawnBy: object, options: RenderOptions, draw: (renderable: Renderable, options: RenderOptions) => Segment[][]): DrawnView;
|
package/dist/core/view.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* `./segment.ts`, `./protocol.ts` and `./style.ts`'s `Hold`, nothing else.
|
|
37
37
|
* [LAW:one-way-deps]
|
|
38
38
|
*/
|
|
39
|
-
import { render } from "./protocol.js";
|
|
39
|
+
import { activePass, render } from "./protocol.js";
|
|
40
40
|
import { Segment } from "./segment.js";
|
|
41
41
|
import { Timeline } from "./timeline.js";
|
|
42
42
|
/** `view` as the renderable a host holds: a function is asked each time it is drawn. */
|
|
@@ -46,14 +46,36 @@ export function hostView(view) {
|
|
|
46
46
|
/**
|
|
47
47
|
* The time a frame drawn at `time` is drawn for, on the clock its cells are
|
|
48
48
|
* stamped on: the time the timeline maps `now` to. [LAW:single-enforcer]
|
|
49
|
-
* `
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
52
|
-
*
|
|
49
|
+
* `frameNow` puts it on the frame `drawView` draws and on the one a host
|
|
50
|
+
* hands out between frames (`frameNow`) — what a key is stamped with — so a
|
|
51
|
+
* moment a widget keeps and the frame it is compared against are on one
|
|
52
|
+
* clock.
|
|
53
53
|
*/
|
|
54
54
|
export function frameTime(time) {
|
|
55
55
|
return Timeline.at(time.timeline, time.now);
|
|
56
56
|
}
|
|
57
|
+
/** A host's frame was asked for during a render or measure. */
|
|
58
|
+
export class RenderClockError extends Error {
|
|
59
|
+
constructor() {
|
|
60
|
+
super("a host's frame was asked for during a render or measure. A frame has one time, the one it is drawn for: " +
|
|
61
|
+
"read it from the render options' `frame`, or ask the host between frames.");
|
|
62
|
+
this.name = "RenderClockError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The frame `host` draws now, at `time`: what every host hands out as
|
|
67
|
+
* `frameNow()`, and what `drawView` draws. [LAW:single-enforcer] The one
|
|
68
|
+
* place a host's time is read for a frame, so the one place it is refused
|
|
69
|
+
* inside a render or measure (`RenderClockError`): a renderable drawing in a
|
|
70
|
+
* frame has that frame's time and asks nothing else, as `State.set` is
|
|
71
|
+
* refused there (`./state.ts`). A frame is a value with no clock on it, so a
|
|
72
|
+
* renderable handed one cannot read a second, moving time mid-render.
|
|
73
|
+
*/
|
|
74
|
+
export function frameNow(host, time) {
|
|
75
|
+
if (activePass() !== undefined)
|
|
76
|
+
throw new RenderClockError();
|
|
77
|
+
return { time: frameTime(time), host };
|
|
78
|
+
}
|
|
57
79
|
/** What a frame not yet drawn at host time `t` says: nothing. */
|
|
58
80
|
export const undrawn = (t) => ({ t, nextChange: Number.POSITIVE_INFINITY });
|
|
59
81
|
/** The hold of the frame `lines` draw, told `told` besides: the intersection of its cells' holds and it. */
|
|
@@ -64,8 +86,8 @@ const frameHold = (lines, told) => lines.reduce((hold, row) => ({ lastChange: Ma
|
|
|
64
86
|
* overflow — and when the frame changes on the host's clock: the hold its
|
|
65
87
|
* cells say, carried back through the timeline. [LAW:one-source-of-truth]
|
|
66
88
|
* `options` is the one place the frame reads the reader's preference for
|
|
67
|
-
* motion, handed on to `draw` with the frame: the time it is
|
|
68
|
-
*
|
|
89
|
+
* motion, handed on to `draw` with the frame (`frameNow`): the time it is
|
|
90
|
+
* drawn for and `drawnBy`, the host whose time that is.
|
|
69
91
|
*/
|
|
70
92
|
export function drawView(view, time, drawnBy, options, draw) {
|
|
71
93
|
const { now: host, timeline } = time;
|
|
@@ -73,7 +95,9 @@ export function drawView(view, time, drawnBy, options, draw) {
|
|
|
73
95
|
const onHold = (hold) => {
|
|
74
96
|
told = { lastChange: Math.max(told.lastChange, hold.lastChange), nextChange: Math.min(told.nextChange, hold.nextChange) };
|
|
75
97
|
};
|
|
76
|
-
|
|
98
|
+
// Made before the render opens: the one time the frame has.
|
|
99
|
+
const frame = frameNow(drawnBy, time);
|
|
100
|
+
const lines = draw(view, { ...options, frame, onHold });
|
|
77
101
|
const hold = frameHold(lines, told);
|
|
78
102
|
// The frame as the sample of the view it is, on the timeline's clock; the
|
|
79
103
|
// timeline says when the host's clock leaves its hold.
|
package/dist/host/app.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ import { type Clock, type FrameRate } from "../core/clock.js";
|
|
|
34
34
|
import { type ConsoleOptions } from "../core/console.js";
|
|
35
35
|
import { Segment } from "../core/segment.js";
|
|
36
36
|
import { type Surface } from "../core/paint.js";
|
|
37
|
-
import { type FrameHost } from "../core/protocol.js";
|
|
37
|
+
import { type HostFrame, type FrameHost } from "../core/protocol.js";
|
|
38
38
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
39
39
|
import { Timeline } from "../core/timeline.js";
|
|
40
40
|
import { type View } from "../core/view.js";
|
|
@@ -149,12 +149,12 @@ export declare class App implements FrameHost {
|
|
|
149
149
|
/** The rows on screen now, as painted: what a pointer event lands on. */
|
|
150
150
|
get frame(): readonly (readonly Segment[])[];
|
|
151
151
|
/**
|
|
152
|
-
* The
|
|
153
|
-
*
|
|
152
|
+
* The frame this app draws now (`FrameHost`): the clock's now, through the
|
|
153
|
+
* timeline, on a frame it is the host of. Its time is what a moment heard
|
|
154
154
|
* between frames — a key — is stamped with, so it is on the clock the
|
|
155
155
|
* frame is.
|
|
156
156
|
*/
|
|
157
|
-
|
|
157
|
+
frameNow(): HostFrame;
|
|
158
158
|
private _time;
|
|
159
159
|
/**
|
|
160
160
|
* Take the terminal, paint the first frame, and resolve when the app stops
|
package/dist/host/app.js
CHANGED
|
@@ -36,7 +36,7 @@ import { Segment } from "../core/segment.js";
|
|
|
36
36
|
import { SurfacePainter } from "../core/paint.js";
|
|
37
37
|
import { fitHeight, render } from "../core/protocol.js";
|
|
38
38
|
import { Timeline } from "../core/timeline.js";
|
|
39
|
-
import { drawView,
|
|
39
|
+
import { drawView, frameNow, hostView, undrawn } from "../core/view.js";
|
|
40
40
|
import { hostEnvironment } from "./host-environment.js";
|
|
41
41
|
import { InputParser, keyName, parseKeyName } from "./input.js";
|
|
42
42
|
// [LAW:one-source-of-truth] How a frame draws — its glyphs, the style names
|
|
@@ -153,13 +153,13 @@ export class App {
|
|
|
153
153
|
return this._frame;
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
* The
|
|
157
|
-
*
|
|
156
|
+
* The frame this app draws now (`FrameHost`): the clock's now, through the
|
|
157
|
+
* timeline, on a frame it is the host of. Its time is what a moment heard
|
|
158
158
|
* between frames — a key — is stamped with, so it is on the clock the
|
|
159
159
|
* frame is.
|
|
160
160
|
*/
|
|
161
|
-
|
|
162
|
-
return
|
|
161
|
+
frameNow() {
|
|
162
|
+
return frameNow(this, this._time());
|
|
163
163
|
}
|
|
164
164
|
_time() {
|
|
165
165
|
return { now: this._clock.now(), epoch: this._epoch, timeline: this._timeline };
|