@promptctl/rich-js 0.25.2 → 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 +6 -5
- package/dist/renderables/effect.d.ts +44 -19
- package/dist/renderables/effect.js +20 -13
- package/dist/renderables/effects.d.ts +15 -9
- package/dist/renderables/effects.js +166 -34
- 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
|
@@ -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.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ColorRgba } from "../core/color.js";
|
|
2
|
-
import { Palette } from "./palette.js";
|
|
2
|
+
import { Palette, type PaletteRole, type PaletteRoles } from "./palette.js";
|
|
3
3
|
/**
|
|
4
4
|
* Base colors required to build a full semantic palette.
|
|
5
5
|
* All are ColorRgba — callers construct from whatever source (hex, HSL, etc.).
|
|
@@ -14,44 +14,19 @@ export interface BaseColors {
|
|
|
14
14
|
background: ColorRgba;
|
|
15
15
|
foreground: ColorRgba;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
export
|
|
17
|
+
/** The eight roles every palette is given, and every role it may also state. */
|
|
18
|
+
export type StatedRoles = BaseColors & Partial<PaletteRoles>;
|
|
19
|
+
/** Every role of every palette, read off the rules. */
|
|
20
|
+
export declare const PALETTE_ROLES: readonly PaletteRole[];
|
|
19
21
|
/**
|
|
20
|
-
* Build a full semantic palette from base colors
|
|
22
|
+
* Build a full semantic palette from its base colors and any other role it
|
|
23
|
+
* states: a stated role keeps its colour, and everything derived from it
|
|
24
|
+
* follows it, but for `text-*`, which is held to read on its `*-muted`. An
|
|
25
|
+
* authored theme is this with most roles stated; see `RULES` for what a role
|
|
26
|
+
* not stated becomes.
|
|
21
27
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* (`foreground-muted` blends toward `background`,
|
|
26
|
-
* `background-muted` blends toward `foreground`) — a caller
|
|
27
|
-
* de-emphasizing body/structural text reaches for
|
|
28
|
-
* `foreground-muted` the same way it reaches for
|
|
29
|
-
* `primary-muted` to de-emphasize an accent.
|
|
30
|
-
* - `text-*` = contrast text tinted 66% with the accent color, then held
|
|
31
|
-
* to WCAG AA (4.5:1) on `*-muted` — the foreground for a
|
|
32
|
-
* `*-muted` ground
|
|
33
|
-
* - `on-*` = WCAG-correct contrast colour (black or white) for use as
|
|
34
|
-
* foreground when the FULL accent is the background. Picked
|
|
35
|
-
* by relative luminance — single source of truth so widgets
|
|
36
|
-
* never need to invert / reverse fg/bg to get readable text.
|
|
37
|
-
* - `surface` = background blended 5% toward foreground
|
|
38
|
-
*
|
|
39
|
-
* A translucent base colour is drawn onto `background` before anything is
|
|
40
|
-
* derived from it, so `on-*` is chosen against the colour the accent is drawn
|
|
41
|
-
* as and every derived entry is opaque.
|
|
42
|
-
*/
|
|
43
|
-
export declare function buildPalette(name: string, dark: boolean, given: BaseColors): Palette;
|
|
44
|
-
/**
|
|
45
|
-
* A palette's `text-*`: its tint held to WCAG AA on `*-muted`, moved toward
|
|
46
|
-
* the palette's own text side so it also reads on `background`, where widgets
|
|
47
|
-
* draw it too. The muted floor is the promise: where no lightness on the text
|
|
48
|
-
* side clears it, the colour that does is on the other side, and the
|
|
49
|
-
* background pair is the one given up. Every bundled palette clears both
|
|
50
|
-
* (test/themes/text-on-muted.test.ts).
|
|
51
|
-
*
|
|
52
|
-
* [LAW:single-enforcer] The one rule for the pair, for the palettes derived
|
|
53
|
-
* here and the authored ones the registry hydrates: the tint is the theme's,
|
|
54
|
-
* whether it reads is decided here.
|
|
28
|
+
* A translucent colour is drawn onto `background` before anything is derived
|
|
29
|
+
* from it, so `on-*` is chosen against the colour the accent is drawn as.
|
|
30
|
+
* `boost` alone stays a layer: it is what `panel` composites.
|
|
55
31
|
*/
|
|
56
|
-
export declare function
|
|
57
|
-
export {};
|
|
32
|
+
export declare function buildPalette(name: string, dark: boolean, given: StatedRoles): Palette;
|