@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/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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
|
-
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";
|
|
3
|
+
export { ColorRgba, ColorTable, ColorDepth, ColorSpec, ColorParseError, TerminalTheme, type TerminalColors, parseRgbHex, parseRgbaHex, parseHexColor, blendRgb, resolveColorSystem, detectColorSystem, resolveDestination, STANDARD_TABLE, EIGHT_BIT_TABLE, WINDOWS_TABLE, ANSI_COLOR_NAMES, } from "./core/color.js";
|
|
4
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";
|
|
8
|
+
export type { AccentRole, BaseRole, PaletteRole, PaletteRoles, ShadedRole } from "./themes/palette.js";
|
|
8
9
|
export { resolveColorRef, ColorRefError } from "./themes/colorRef.js";
|
|
9
10
|
export { buildPalette } from "./themes/buildPalette.js";
|
|
10
|
-
export type { BaseColors } from "./themes/buildPalette.js";
|
|
11
|
+
export type { BaseColors, StatedRoles } from "./themes/buildPalette.js";
|
|
11
12
|
export { DEFAULT_TERMINAL_THEME, MONOKAI, SVG_EXPORT_THEME, NORD, GRUVBOX, DRACULA, TOKYO_NIGHT, FLEXOKI, CYBERPUNK, CATPPUCCIN_MOCHA, CATPPUCCIN_LATTE, CATPPUCCIN_FRAPPE, CATPPUCCIN_MACCHIATO, SOLARIZED_DARK, SOLARIZED_LIGHT, ROSE_PINE, ROSE_PINE_MOON, ROSE_PINE_DAWN, ATOM_ONE_DARK, ATOM_ONE_LIGHT, TEXTUAL_DARK, TEXTUAL_LIGHT, TEXTUAL_ANSI, } from "./themes/terminalThemes.js";
|
|
12
13
|
export { getThemePalette, listThemePalettes } from "./themes/registry.js";
|
|
13
14
|
export type { ThemeName } from "./themes/registry.js";
|
|
@@ -33,7 +34,7 @@ export { Box } from "./core/box.js";
|
|
|
33
34
|
export type { EdgeChars, ContentChars, RowLevel, SubstituteOptions } from "./core/box.js";
|
|
34
35
|
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";
|
|
35
36
|
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";
|
|
37
|
+
export type { RenderOptions, OverflowMethod, Height, Renderable, Measurable, Presence, StyleErrorHandler, FrameHost, HostFrame, } from "./core/protocol.js";
|
|
37
38
|
export type { Unsubscribe } from "./core/subscription.js";
|
|
38
39
|
export { Measurement, measureRenderables } from "./core/measure.js";
|
|
39
40
|
export { Span, RichText } from "./core/text.js";
|
|
@@ -67,7 +68,7 @@ export type { AttributeLoopName, Blink, ColorStep, Curve, EffectTarget, Field, L
|
|
|
67
68
|
export { crossfade, wipe } from "./renderables/change.js";
|
|
68
69
|
export type { Between, Change } from "./renderables/change.js";
|
|
69
70
|
export { lifecycle, throughColors, throughGlyphs } from "./renderables/lifecycle.js";
|
|
70
|
-
export type { Lifecycle, LifecycleOptions
|
|
71
|
+
export type { Half, Lifecycle, LifecycleOptions } from "./renderables/lifecycle.js";
|
|
71
72
|
export { scroll } from "./renderables/scroll.js";
|
|
72
73
|
export type { ScrollOptions } from "./renderables/scroll.js";
|
|
73
74
|
export { GlyphEffected } from "./renderables/glyph-effect.js";
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
import { type Anchor } from "../core/anchor.js";
|
|
72
72
|
import { Animation } from "../core/animation.js";
|
|
73
73
|
import type { Hold } from "../core/style.js";
|
|
74
|
-
import { ColorDepth, type ColorRgba, type
|
|
74
|
+
import { ColorDepth, type ColorRgba, type TerminalColors } from "../core/color.js";
|
|
75
75
|
import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
|
|
76
76
|
import { Segment } from "../core/segment.js";
|
|
77
77
|
import { type Attributes } from "../core/style.js";
|
|
@@ -194,7 +194,7 @@ export interface Drawn {
|
|
|
194
194
|
/** The depth the frame is written at: below truecolor a moved colour lands on a palette colour. */
|
|
195
195
|
readonly depth: ColorDepth;
|
|
196
196
|
/** The terminal the frame is drawn on. */
|
|
197
|
-
readonly theme:
|
|
197
|
+
readonly theme: TerminalColors;
|
|
198
198
|
}
|
|
199
199
|
/** What an effect does to the cells of one frame: each cell's look and where it is in, its look out. Return `look` to leave a cell be. */
|
|
200
200
|
export type EffectFrame = (look: CellLook, cell: EffectCell) => CellLook;
|
|
@@ -224,7 +224,7 @@ export interface EffectedOptions {
|
|
|
224
224
|
* drawn in, and the sixteen an ANSI colour names. The terminal's own palette
|
|
225
225
|
* is never queried, so the caller says what it is.
|
|
226
226
|
*/
|
|
227
|
-
readonly theme:
|
|
227
|
+
readonly theme: TerminalColors;
|
|
228
228
|
}
|
|
229
229
|
/** A frame an effect drew at a moment, and the hold the effect says it is in there. */
|
|
230
230
|
export interface Moved {
|
|
@@ -243,7 +243,7 @@ export declare class Recolored implements Renderable, Measurable {
|
|
|
243
243
|
readonly effect: Effect;
|
|
244
244
|
readonly t: number;
|
|
245
245
|
readonly key: string;
|
|
246
|
-
readonly theme:
|
|
246
|
+
readonly theme: TerminalColors;
|
|
247
247
|
constructor(renderable: Renderable, effect: Effect, options: EffectedOptions & {
|
|
248
248
|
readonly t: number;
|
|
249
249
|
});
|
|
@@ -287,7 +287,7 @@ export declare class Effected implements Animation<Renderable> {
|
|
|
287
287
|
readonly renderable: Renderable;
|
|
288
288
|
readonly effect: Effect;
|
|
289
289
|
readonly key: string;
|
|
290
|
-
readonly theme:
|
|
290
|
+
readonly theme: TerminalColors;
|
|
291
291
|
constructor(renderable: Renderable, effect: Effect, options: EffectedOptions);
|
|
292
292
|
/** The element through the effect at `t`, unstamped. */
|
|
293
293
|
at(t: number): Recolored;
|
|
@@ -308,7 +308,7 @@ export declare class Effected implements Animation<Renderable> {
|
|
|
308
308
|
* [LAW:one-source-of-truth] Read through `movedSpecs`, the one writer a
|
|
309
309
|
* moved slot is written with.
|
|
310
310
|
*/
|
|
311
|
-
static shows(pair: Pair, to: CellColors, depth: ColorDepth, theme:
|
|
311
|
+
static shows(pair: Pair, to: CellColors, depth: ColorDepth, theme: TerminalColors): CellColors;
|
|
312
312
|
}
|
|
313
313
|
/**
|
|
314
314
|
* A cell's seed: FNV-1a of the element's key and the cell's position, scaled
|
|
@@ -355,7 +355,7 @@ export declare function confined(effect: Effect, ...owners: readonly object[]):
|
|
|
355
355
|
* as `Effected` measures its child for every frame. Measure an element's
|
|
356
356
|
* output under an effect to read the contrast its words are left at.
|
|
357
357
|
*/
|
|
358
|
-
export declare function drawnOf(segments: Iterable<Segment>, depth: ColorDepth, theme:
|
|
358
|
+
export declare function drawnOf(segments: Iterable<Segment>, depth: ColorDepth, theme: TerminalColors): Drawn;
|
|
359
359
|
/**
|
|
360
360
|
* The attributes a look carries, read off anything that sets them — a
|
|
361
361
|
* `Style`, or a look a frame returned with more on it than `CellAttributes`
|
|
@@ -675,7 +675,7 @@ export class Transition {
|
|
|
675
675
|
this.schedule = schedule;
|
|
676
676
|
}
|
|
677
677
|
done(t) {
|
|
678
|
-
return this.schedule
|
|
678
|
+
return Animation.done(this.schedule, t);
|
|
679
679
|
}
|
|
680
680
|
}
|
|
681
681
|
/**
|
|
@@ -685,8 +685,13 @@ export class Transition {
|
|
|
685
685
|
* glyph effect (`./glyph-effects.ts`) alike.
|
|
686
686
|
*/
|
|
687
687
|
export function transition(seconds, effect) {
|
|
688
|
-
// Moving every frame until `seconds`, then never: the sequence carries the switch.
|
|
689
|
-
|
|
688
|
+
// Moving every frame until `seconds`, then never: the sequence carries the switch. [LAW:one-source-of-truth]
|
|
689
|
+
// Reduced, a one-shot cuts from its start to its end at 0, and its schedule says so too, the one word on
|
|
690
|
+
// when the reduced frames change, so a half that lends this schedule to its frames tells the same hold.
|
|
691
|
+
const schedule = Animation.of({
|
|
692
|
+
...Animation.sequence(Animation.continuous(() => undefined), seconds, Animation.constant(undefined)),
|
|
693
|
+
reduced: () => Animation.cut(undefined, undefined),
|
|
694
|
+
});
|
|
690
695
|
const ran = new Transition((drawn) => {
|
|
691
696
|
const moving = effect(drawn);
|
|
692
697
|
return Animation.of({
|
|
@@ -10,27 +10,32 @@
|
|
|
10
10
|
* part of the drawing asks whether it is leaving. Telling it is a new value
|
|
11
11
|
* (`leave`), as every `Timeline` operation is. [LAW:no-ambient-temporal-coupling]
|
|
12
12
|
*
|
|
13
|
-
* Each half is a `
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
13
|
+
* Each half is a `Half`: handed the element, an `Animation<Renderable>` of
|
|
14
|
+
* it on the half's own clock from 0, in the shape of the library's other
|
|
15
|
+
* one-shot from renderables to an animation (`Change`, `./change.ts`). One
|
|
16
|
+
* value carries the half's frames and its holds, so neither is kept in
|
|
17
|
+
* agreement with the other by hand, and nothing here measures progress
|
|
18
|
+
* itself: a half's schedule carried onto the host's clock by `Timeline.run`
|
|
19
|
+
* is that half's hold — every frame for a fade, once a hold for one on a
|
|
20
|
+
* beat — and the moment it says it never changes again (`Animation.done`)
|
|
21
|
+
* is where the arrival ends and where the element is gone. The frames carry
|
|
22
|
+
* no word of their own on when they change: placed, the lifecycle stamps
|
|
23
|
+
* them with its hold at the frame's time (`placedRender`). The exit is
|
|
24
|
+
* drawn over whatever the arrival draws, so an element told to leave while
|
|
25
|
+
* it is still arriving leaves from where it is, never shown whole first —
|
|
26
|
+
* though a colour exit is spread over the cells each frame shows, so a cell
|
|
27
|
+
* the arrival adds can move one already leaving back toward whole
|
|
28
|
+
* (`ownChange`, `./effects.ts`). [LAW:dataflow-not-control-flow]
|
|
26
29
|
*
|
|
27
30
|
* A half draws the element through a colour transition (`throughColors`, a
|
|
28
|
-
* `fadeIn`) or a glyph one (`throughGlyphs`, a `typewriter`): each
|
|
29
|
-
*
|
|
31
|
+
* `fadeIn`) or a glyph one (`throughGlyphs`, a `typewriter`): each binds its
|
|
32
|
+
* transition to the one wrapper that draws it, and to what that wrapper
|
|
30
33
|
* needs — a theme for colours, nothing for glyphs — so nothing here asks which
|
|
31
|
-
* kind a half is, and a line can type itself in and dissolve out.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* kind a half is, and a line can type itself in and dissolve out. A half
|
|
35
|
+
* written by hand is any function of that shape — an arrival that slides the
|
|
36
|
+
* element in, which no effect draws. An exit is a half that ends with nothing
|
|
37
|
+
* drawn — `dissolveOut`, `backspace`, `scrambleOut` — so the element has
|
|
38
|
+
* already gone from sight when it is gone.
|
|
34
39
|
*
|
|
35
40
|
* Gone is a fact the host reads (`gone(t)`) to drop the element, and from then
|
|
36
41
|
* the lifecycle draws nothing and never changes, so a host still holding it
|
|
@@ -40,25 +45,30 @@
|
|
|
40
45
|
import { Animation } from "../core/animation.js";
|
|
41
46
|
import type { TerminalTheme } from "../core/color.js";
|
|
42
47
|
import type { Renderable } from "../core/protocol.js";
|
|
43
|
-
import { Transition } from "./effects.js";
|
|
48
|
+
import type { Transition } from "./effects.js";
|
|
44
49
|
import type { GlyphTransition } from "./glyph-effects.js";
|
|
45
50
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
51
|
+
* One half of an element's lifecycle: handed the element and `key`, which
|
|
52
|
+
* names it for the half's seeds, the element as the half draws it from
|
|
53
|
+
* `t = 0`, the moment the half began, on its own clock. Its holds are the
|
|
54
|
+
* half's own, whatever element it is handed, and it is done from the first
|
|
55
|
+
* moment it says it never changes again (`Animation.done`): an arrival is
|
|
56
|
+
* the element from then, and an exit is gone. A half that never ends is
|
|
57
|
+
* refused when the lifecycle is made: an `Effected` or `GlyphEffected`
|
|
58
|
+
* handed in bare is one, since its own word is "now" at every time;
|
|
59
|
+
* `throughColors` and `throughGlyphs` lend one the transition's schedule.
|
|
50
60
|
*/
|
|
51
|
-
export type
|
|
61
|
+
export type Half = (element: Renderable, key: string) => Animation<Renderable>;
|
|
52
62
|
/** `transition`'s colours drawn over an element on `theme`, whose ground it arrives from and leaves to. */
|
|
53
|
-
export declare function throughColors(transition: Transition, theme: TerminalTheme):
|
|
63
|
+
export declare function throughColors(transition: Transition, theme: TerminalTheme): Half;
|
|
54
64
|
/** `transition`'s glyphs drawn over an element, at every depth, with no colour too. */
|
|
55
|
-
export declare function throughGlyphs(transition: GlyphTransition):
|
|
65
|
+
export declare function throughGlyphs(transition: GlyphTransition): Half;
|
|
56
66
|
/** How an element arrives and leaves, and what it is named for their seeds. */
|
|
57
67
|
export interface LifecycleOptions {
|
|
58
68
|
/** The half it arrives through — `throughColors(fadeIn(curve, z), theme)`. */
|
|
59
|
-
readonly enter:
|
|
69
|
+
readonly enter: Half;
|
|
60
70
|
/** The half it leaves through — `throughGlyphs(scrambleOut(timing, z))`. */
|
|
61
|
-
readonly exit:
|
|
71
|
+
readonly exit: Half;
|
|
62
72
|
/** Names the element for both halves' seeds, as `Effected`'s and `GlyphEffected`'s key does. */
|
|
63
73
|
readonly key: string;
|
|
64
74
|
}
|
|
@@ -10,27 +10,32 @@
|
|
|
10
10
|
* part of the drawing asks whether it is leaving. Telling it is a new value
|
|
11
11
|
* (`leave`), as every `Timeline` operation is. [LAW:no-ambient-temporal-coupling]
|
|
12
12
|
*
|
|
13
|
-
* Each half is a `
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
13
|
+
* Each half is a `Half`: handed the element, an `Animation<Renderable>` of
|
|
14
|
+
* it on the half's own clock from 0, in the shape of the library's other
|
|
15
|
+
* one-shot from renderables to an animation (`Change`, `./change.ts`). One
|
|
16
|
+
* value carries the half's frames and its holds, so neither is kept in
|
|
17
|
+
* agreement with the other by hand, and nothing here measures progress
|
|
18
|
+
* itself: a half's schedule carried onto the host's clock by `Timeline.run`
|
|
19
|
+
* is that half's hold — every frame for a fade, once a hold for one on a
|
|
20
|
+
* beat — and the moment it says it never changes again (`Animation.done`)
|
|
21
|
+
* is where the arrival ends and where the element is gone. The frames carry
|
|
22
|
+
* no word of their own on when they change: placed, the lifecycle stamps
|
|
23
|
+
* them with its hold at the frame's time (`placedRender`). The exit is
|
|
24
|
+
* drawn over whatever the arrival draws, so an element told to leave while
|
|
25
|
+
* it is still arriving leaves from where it is, never shown whole first —
|
|
26
|
+
* though a colour exit is spread over the cells each frame shows, so a cell
|
|
27
|
+
* the arrival adds can move one already leaving back toward whole
|
|
28
|
+
* (`ownChange`, `./effects.ts`). [LAW:dataflow-not-control-flow]
|
|
26
29
|
*
|
|
27
30
|
* A half draws the element through a colour transition (`throughColors`, a
|
|
28
|
-
* `fadeIn`) or a glyph one (`throughGlyphs`, a `typewriter`): each
|
|
29
|
-
*
|
|
31
|
+
* `fadeIn`) or a glyph one (`throughGlyphs`, a `typewriter`): each binds its
|
|
32
|
+
* transition to the one wrapper that draws it, and to what that wrapper
|
|
30
33
|
* needs — a theme for colours, nothing for glyphs — so nothing here asks which
|
|
31
|
-
* kind a half is, and a line can type itself in and dissolve out.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* kind a half is, and a line can type itself in and dissolve out. A half
|
|
35
|
+
* written by hand is any function of that shape — an arrival that slides the
|
|
36
|
+
* element in, which no effect draws. An exit is a half that ends with nothing
|
|
37
|
+
* drawn — `dissolveOut`, `backspace`, `scrambleOut` — so the element has
|
|
38
|
+
* already gone from sight when it is gone.
|
|
34
39
|
*
|
|
35
40
|
* Gone is a fact the host reads (`gone(t)`) to drop the element, and from then
|
|
36
41
|
* the lifecycle draws nothing and never changes, so a host still holding it
|
|
@@ -40,20 +45,31 @@
|
|
|
40
45
|
import { Animation } from "../core/animation.js";
|
|
41
46
|
import { firstReaching } from "../core/easing.js";
|
|
42
47
|
import { Timeline } from "../core/timeline.js";
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import { Reglyphed } from "./glyph-effect.js";
|
|
48
|
+
import { Effected } from "./effect.js";
|
|
49
|
+
import { GlyphEffected } from "./glyph-effect.js";
|
|
46
50
|
/** `transition`'s colours drawn over an element on `theme`, whose ground it arrives from and leaves to. */
|
|
47
51
|
export function throughColors(transition, theme) {
|
|
48
|
-
return
|
|
52
|
+
return (element, key) => scheduled(new Effected(element, transition.effect, { key, theme }), transition.schedule);
|
|
49
53
|
}
|
|
50
54
|
/** `transition`'s glyphs drawn over an element, at every depth, with no colour too. */
|
|
51
55
|
export function throughGlyphs(transition) {
|
|
52
|
-
return
|
|
56
|
+
return (element, key) => scheduled(new GlyphEffected(element, transition.effect, { key }), transition.schedule);
|
|
53
57
|
}
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
/**
|
|
59
|
+
* `placed` — an element under a transition's effect — changing when
|
|
60
|
+
* `schedule`, the transition's own, says: its frames with the one word on
|
|
61
|
+
* when they change that the transition has and the wrapper lacks, whose own
|
|
62
|
+
* answer is "now" until it is drawn. [LAW:one-source-of-truth] Reduced,
|
|
63
|
+
* both are reduced together, as `onBeat` steps both: a one-shot's effect
|
|
64
|
+
* and its schedule each reduce to a cut at 0 (`transition`, `./effects.ts`).
|
|
65
|
+
*/
|
|
66
|
+
function scheduled(placed, schedule) {
|
|
67
|
+
return Animation.of({
|
|
68
|
+
at: (t) => placed.at(t),
|
|
69
|
+
nextChange: (t) => schedule.nextChange(t),
|
|
70
|
+
lastChange: (t) => schedule.lastChange(t),
|
|
71
|
+
reduced: () => scheduled(placed.reduced(), schedule.reduced()),
|
|
72
|
+
});
|
|
57
73
|
}
|
|
58
74
|
/** What an element draws before it entered and once it is gone: no cells, and no width. */
|
|
59
75
|
const NOTHING = { render: () => [], measure: () => ({ minimum: 0, maximum: 0 }) };
|
|
@@ -61,26 +77,50 @@ const NOTHING = { render: () => [], measure: () => ({ minimum: 0, maximum: 0 })
|
|
|
61
77
|
export function lifecycle(element, options, entered) {
|
|
62
78
|
if (!Number.isFinite(entered))
|
|
63
79
|
throw new RangeError(`lifecycle: entered must be a finite time, got ${entered}`);
|
|
64
|
-
|
|
80
|
+
const { enter, exit, key } = options;
|
|
81
|
+
const arrival = ending(enter(element, key), "enter", key);
|
|
82
|
+
const departure = ending(exit(element, key), "exit", key);
|
|
83
|
+
return life(element, options, { arrival, arrived: doneAt(arrival, entered), departure }, entered, Number.POSITIVE_INFINITY);
|
|
65
84
|
}
|
|
66
85
|
/**
|
|
67
|
-
* The first host moment `
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* [LAW:single-enforcer] Since `x - start` never falls as `x` rises, a host
|
|
71
|
-
* is at or past this moment exactly when `done` holds there.
|
|
86
|
+
* The first host moment `half`, begun at host time `start`, is done: its own
|
|
87
|
+
* answer read on host time, never a sum `start + seconds`, which can round
|
|
88
|
+
* to either side of it, as `Animation.sequence` carries its switch.
|
|
89
|
+
* [LAW:single-enforcer] Since `x - start` never falls as `x` rises, a host
|
|
90
|
+
* time is at or past this moment exactly when `done` holds there. Done is
|
|
91
|
+
* for good, so a half done as it begins — the element at once — is done at
|
|
92
|
+
* `start`, and from a start it is not done at the walk is upward only: no
|
|
93
|
+
* half is asked about a time before it began.
|
|
72
94
|
*/
|
|
73
|
-
function doneAt(
|
|
74
|
-
|
|
95
|
+
function doneAt(half, start) {
|
|
96
|
+
if (!Number.isFinite(start) || Animation.done(half, 0))
|
|
97
|
+
return start;
|
|
98
|
+
return firstReaching(start, (x) => Animation.done(half, x - start));
|
|
75
99
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
100
|
+
/**
|
|
101
|
+
* `half` over the element, asked where it ends on its own clock, or refused
|
|
102
|
+
* by its `role` and the element's `key` when it never does. [LAW:no-silent-failure]
|
|
103
|
+
* Kept, it would never arrive, or never be gone, and wake the host every frame
|
|
104
|
+
* for good; asked here, the refusal lands where the options were written and
|
|
105
|
+
* not at the first `leave`. A half on a beat that never ends is refused by the
|
|
106
|
+
* beat instead, where the walk asks it past what its holds resolve.
|
|
107
|
+
*/
|
|
108
|
+
function ending(half, role, key) {
|
|
109
|
+
if (doneAt(half, 0) === Number.POSITIVE_INFINITY) {
|
|
110
|
+
throw new RangeError(`lifecycle "${key}": the ${role} half never ends: its animation never says it has stopped changing (Animation.done). An Effected or GlyphEffected on its own does not; throughColors(transition, theme) and throughGlyphs(transition) lend one the transition's schedule`);
|
|
111
|
+
}
|
|
112
|
+
return half;
|
|
113
|
+
}
|
|
114
|
+
function life(element, options, halves, entered, left) {
|
|
115
|
+
const { exit, key } = options;
|
|
116
|
+
const { arrival, arrived, departure } = halves;
|
|
117
|
+
// Where the exit is gone, and the exit's hold, are read off the exit over the element; the frame while
|
|
118
|
+
// leaving is the exit over what is shown, whose holds are the same by `Half`'s contract.
|
|
119
|
+
const goneAt = doneAt(departure, left);
|
|
120
|
+
// The arrival on the host's clock: when its frame next changes, and since when it has been what it is.
|
|
121
|
+
const arriving = Timeline.run(Timeline.play(entered), arrival);
|
|
82
122
|
// What the element draws by `t` if it is not leaving: arriving through `enter`, then itself.
|
|
83
|
-
const shown = (t) => (t < arrived ?
|
|
123
|
+
const shown = (t) => (t < arrived ? arrival.at(t - entered) : element);
|
|
84
124
|
const held = (schedule, t) => ({ last: schedule.lastChange(t), next: schedule.nextChange(t) });
|
|
85
125
|
// [LAW:one-source-of-truth] Each phase's frame and its hold, side by side, so the two cannot disagree.
|
|
86
126
|
// The frames say nothing of when they change — the hold does, stamped where the lifecycle is placed.
|
|
@@ -89,10 +129,10 @@ function life(element, options, entered, left) {
|
|
|
89
129
|
return { frame: NOTHING, last: Number.NEGATIVE_INFINITY, next: entered };
|
|
90
130
|
if (t >= goneAt)
|
|
91
131
|
return { frame: NOTHING, last: goneAt, next: Number.POSITIVE_INFINITY };
|
|
92
|
-
// Leaving
|
|
132
|
+
// Leaving is drawn over whatever arriving draws, so both schedules count; once arrived, the arrival's never changes again.
|
|
93
133
|
if (t >= left) {
|
|
94
|
-
const leaving = Animation.all([arriving, Timeline.run(Timeline.play(left),
|
|
95
|
-
return { frame: exit
|
|
134
|
+
const leaving = Animation.all([arriving, Timeline.run(Timeline.play(left), departure)]);
|
|
135
|
+
return { frame: exit(shown(t), key).at(t - left), ...held(leaving, t) };
|
|
96
136
|
}
|
|
97
137
|
if (t < arrived)
|
|
98
138
|
return { frame: shown(t), ...held(arriving, t) };
|
|
@@ -126,7 +166,7 @@ function life(element, options, entered, left) {
|
|
|
126
166
|
throw new RangeError(`lifecycle: already told to leave at ${left}, told again at ${at}`);
|
|
127
167
|
if (!(Number.isFinite(at) && at >= entered))
|
|
128
168
|
throw new RangeError(`lifecycle: leave must be a finite time from entered (${entered}) on, got ${at}`);
|
|
129
|
-
return life(element, options, entered, at);
|
|
169
|
+
return life(element, options, halves, entered, at);
|
|
130
170
|
},
|
|
131
171
|
});
|
|
132
172
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { type Clock } from "../core/clock.js";
|
|
28
28
|
import { Console } from "../core/console.js";
|
|
29
|
-
import { type FrameHost } from "../core/protocol.js";
|
|
29
|
+
import { type HostFrame, type FrameHost } from "../core/protocol.js";
|
|
30
30
|
import { Timeline } from "../core/timeline.js";
|
|
31
31
|
import { type View } from "../core/view.js";
|
|
32
32
|
export interface LiveOptions {
|
|
@@ -79,8 +79,8 @@ export declare class Live implements FrameHost {
|
|
|
79
79
|
get clock(): Clock;
|
|
80
80
|
/** The map from the clock to the time the view is drawn for. */
|
|
81
81
|
get timeline(): Timeline;
|
|
82
|
-
/** The
|
|
83
|
-
|
|
82
|
+
/** The frame this Live draws now (`FrameHost`): the clock's now, through the timeline, on a frame it is the host of. */
|
|
83
|
+
frameNow(): HostFrame;
|
|
84
84
|
private _time;
|
|
85
85
|
/**
|
|
86
86
|
* Replace the timeline and draw the frame for the time it now maps the
|
package/dist/renderables/live.js
CHANGED
|
@@ -30,7 +30,7 @@ import { Segment } from "../core/segment.js";
|
|
|
30
30
|
import { FinalFramePainter, SurfacePainter } from "../core/paint.js";
|
|
31
31
|
import { fitHeight, render } from "../core/protocol.js";
|
|
32
32
|
import { Timeline } from "../core/timeline.js";
|
|
33
|
-
import { drawView,
|
|
33
|
+
import { drawView, frameNow, hostView, undrawn } from "../core/view.js";
|
|
34
34
|
import { State } from "../core/state.js";
|
|
35
35
|
// Nothing: what a Live made with no view draws until `update` gives it one.
|
|
36
36
|
const NOTHING = { render: () => [] };
|
|
@@ -89,9 +89,9 @@ export class Live {
|
|
|
89
89
|
get timeline() {
|
|
90
90
|
return this._timeline.get();
|
|
91
91
|
}
|
|
92
|
-
/** The
|
|
93
|
-
|
|
94
|
-
return
|
|
92
|
+
/** The frame this Live draws now (`FrameHost`): the clock's now, through the timeline, on a frame it is the host of. */
|
|
93
|
+
frameNow() {
|
|
94
|
+
return frameNow(this, this._time());
|
|
95
95
|
}
|
|
96
96
|
_time() {
|
|
97
97
|
return { now: this._clock.now(), epoch: this._epoch, timeline: this._timeline.get() };
|
|
@@ -7,7 +7,7 @@ import { Console } from "../core/console.js";
|
|
|
7
7
|
import type { Style } from "../core/style.js";
|
|
8
8
|
import type { Clock } from "../core/clock.js";
|
|
9
9
|
import { type ColumnOptions } from "./table.js";
|
|
10
|
-
import type { FrameHost, Renderable, RenderOptions } from "../core/protocol.js";
|
|
10
|
+
import type { HostFrame, FrameHost, Renderable, RenderOptions } from "../core/protocol.js";
|
|
11
11
|
import { Animation } from "../core/animation.js";
|
|
12
12
|
import type { Timing } from "../core/easing.js";
|
|
13
13
|
export interface TaskOptions {
|
|
@@ -156,7 +156,7 @@ export declare class MofNCompleteColumn implements ProgressColumn {
|
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* How a `Progress` is set up. It is drawn by one host, and every time it
|
|
159
|
-
* keeps or draws at is that host's `
|
|
159
|
+
* keeps or draws at is that host's `frameNow()`: by its own `Live`, which the
|
|
160
160
|
* options for that `Live` configure, or, given `drawnBy`, by another host —
|
|
161
161
|
* which then does all the drawing, so none of them apply.
|
|
162
162
|
*/
|
|
@@ -185,7 +185,7 @@ interface OwnLiveOptions {
|
|
|
185
185
|
interface DrawnByOptions {
|
|
186
186
|
/**
|
|
187
187
|
* The host — a `Live`, an `App` — whose frames this `Progress` is drawn in:
|
|
188
|
-
* tasks are timed by its `
|
|
188
|
+
* tasks are timed by its `frameNow()`, so they hold while its timeline is
|
|
189
189
|
* paused and run back while it is reversed. Drawn in any other host's
|
|
190
190
|
* frame, the `Progress` throws.
|
|
191
191
|
*/
|
|
@@ -207,6 +207,13 @@ export declare class Progress implements Renderable {
|
|
|
207
207
|
constructor(...columns: (ProgressColumn | ProgressOptions)[]);
|
|
208
208
|
/** The console its own `Live` prints above the bars through. */
|
|
209
209
|
get console(): Console;
|
|
210
|
+
/**
|
|
211
|
+
* The frame its host draws now (`FrameHost.frameNow`): what a print of
|
|
212
|
+
* this display is drawn in — `console.print(progress, { frame:
|
|
213
|
+
* progress.frameNow() })` — so a still of it is drawn for a moment on the
|
|
214
|
+
* clock its tasks are timed on, the one the program asked at.
|
|
215
|
+
*/
|
|
216
|
+
frameNow(): HostFrame;
|
|
210
217
|
/** Rich's `Progress.finished`: every task finished, and so true with none. */
|
|
211
218
|
get finished(): boolean;
|
|
212
219
|
static getDefaultColumns(): ProgressColumn[];
|
|
@@ -224,7 +231,7 @@ export declare class Progress implements Renderable {
|
|
|
224
231
|
refresh(): void;
|
|
225
232
|
private _ownLive;
|
|
226
233
|
render(options: RenderOptions): Iterable<Segment>;
|
|
227
|
-
private
|
|
234
|
+
private _ownFrame;
|
|
228
235
|
private _table;
|
|
229
236
|
}
|
|
230
237
|
export declare function track<T>(iterable: Iterable<T>, options?: {
|
|
@@ -321,9 +321,20 @@ export class Progress {
|
|
|
321
321
|
get console() {
|
|
322
322
|
return this._ownLive("console").console;
|
|
323
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* The frame its host draws now (`FrameHost.frameNow`): what a print of
|
|
326
|
+
* this display is drawn in — `console.print(progress, { frame:
|
|
327
|
+
* progress.frameNow() })` — so a still of it is drawn for a moment on the
|
|
328
|
+
* clock its tasks are timed on, the one the program asked at.
|
|
329
|
+
*/
|
|
330
|
+
frameNow() {
|
|
331
|
+
return this._host.frameNow();
|
|
332
|
+
}
|
|
324
333
|
/** Rich's `Progress.finished`: every task finished, and so true with none. */
|
|
325
334
|
get finished() {
|
|
326
|
-
|
|
335
|
+
// [LAW:one-source-of-truth] One moment, so every task is judged at it.
|
|
336
|
+
const now = this._host.frameNow().time;
|
|
337
|
+
return this._tasks.get().every((task) => finished(taskAt(task.get(), now)));
|
|
327
338
|
}
|
|
328
339
|
static getDefaultColumns() {
|
|
329
340
|
return [
|
|
@@ -342,7 +353,7 @@ export class Progress {
|
|
|
342
353
|
completed: 0,
|
|
343
354
|
fill: Animation.constant(0),
|
|
344
355
|
visible: options?.visible !== false,
|
|
345
|
-
startTime: options?.start === false ? undefined : this._host.
|
|
356
|
+
startTime: options?.start === false ? undefined : this._host.frameNow().time,
|
|
346
357
|
finishedAt: undefined,
|
|
347
358
|
samples: [],
|
|
348
359
|
}));
|
|
@@ -364,7 +375,7 @@ export class Progress {
|
|
|
364
375
|
const completed = options.completed === undefined
|
|
365
376
|
? finiteCount("completed + advance", task.completed + advance)
|
|
366
377
|
: finiteCount("completed", options.completed);
|
|
367
|
-
const now = this._host.
|
|
378
|
+
const now = this._host.frameNow().time;
|
|
368
379
|
const reached = task.startTime !== undefined && task.total !== undefined && completed >= task.total;
|
|
369
380
|
held.set({
|
|
370
381
|
...task,
|
|
@@ -385,7 +396,7 @@ export class Progress {
|
|
|
385
396
|
const held = this._task(taskId);
|
|
386
397
|
// Rich's `start_task`: a task already running keeps the time it started.
|
|
387
398
|
if (held)
|
|
388
|
-
held.set({ ...held.get(), startTime: held.get().startTime ?? this._host.
|
|
399
|
+
held.set({ ...held.get(), startTime: held.get().startTime ?? this._host.frameNow().time });
|
|
389
400
|
}
|
|
390
401
|
start() {
|
|
391
402
|
this._ownLive("start").start();
|
|
@@ -410,23 +421,24 @@ export class Progress {
|
|
|
410
421
|
return this._live;
|
|
411
422
|
}
|
|
412
423
|
*render(options) {
|
|
413
|
-
|
|
414
|
-
yield* render(this._table(framed.frame.time), framed);
|
|
424
|
+
yield* render(this._table(this._ownFrame(options).time), options);
|
|
415
425
|
}
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
// for
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
|
|
424
|
-
_framed(options) {
|
|
426
|
+
// The frame this display is drawn in, which is only ever its host's: the
|
|
427
|
+
// tasks were stamped on that host's time, and a frame of any other host is
|
|
428
|
+
// drawn for a moment on a different clock. A render reads no clock, so a
|
|
429
|
+
// print names its frame (`frameNow`, `PrintOptions.frame`): drawn for no
|
|
430
|
+
// moment — 0, as everything else is — every task would read as not yet
|
|
431
|
+
// started, so that print is refused with the call that draws it right.
|
|
432
|
+
// [LAW:parse-dont-validate] [LAW:no-silent-failure]
|
|
433
|
+
_ownFrame(options) {
|
|
425
434
|
const { frame } = options;
|
|
426
|
-
if (frame
|
|
435
|
+
if (frame === undefined) {
|
|
436
|
+
throw new Error("a Progress is drawn for a moment on its host's clock, and this print named none; print it in its frame: console.print(progress, { frame: progress.frameNow() })");
|
|
437
|
+
}
|
|
438
|
+
if (frame.host !== this._host) {
|
|
427
439
|
throw new Error("a Progress was drawn in a frame of a host other than its own; give it that host as `drawnBy`");
|
|
428
440
|
}
|
|
429
|
-
return
|
|
441
|
+
return frame;
|
|
430
442
|
}
|
|
431
443
|
// Rich's `make_tasks_table`: each column laid out as it says, at `now` on
|
|
432
444
|
// this display's clock.
|