@promptctl/rich-js 0.24.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/core/anchor.d.ts +5 -0
- package/dist/core/anchor.js +11 -4
- package/dist/core/animation.d.ts +175 -10
- package/dist/core/animation.js +283 -15
- package/dist/core/ansi.js +2 -2
- package/dist/core/box.d.ts +7 -7
- package/dist/core/cells.d.ts +23 -13
- package/dist/core/cells.js +58 -48
- package/dist/core/clock.d.ts +2 -2
- package/dist/core/clock.js +6 -4
- package/dist/core/color.d.ts +27 -10
- package/dist/core/color.js +21 -29
- package/dist/core/console.d.ts +28 -17
- package/dist/core/console.js +44 -39
- package/dist/core/easing.d.ts +30 -0
- package/dist/core/easing.js +65 -20
- package/dist/core/emoji.d.ts +1 -1
- package/dist/core/emoji.js +1 -2
- package/dist/core/export-html.js +2 -1
- package/dist/core/export-lines.js +3 -3
- package/dist/core/highlighter.d.ts +9 -8
- package/dist/core/highlighter.js +3 -2
- package/dist/core/json.js +2 -2
- package/dist/core/markup.js +16 -12
- package/dist/core/measure.js +2 -2
- package/dist/core/memo.d.ts +11 -2
- package/dist/core/memo.js +16 -0
- package/dist/core/oklch.js +17 -6
- package/dist/core/osc8.d.ts +1 -1
- package/dist/core/osc8.js +4 -5
- package/dist/core/paint.d.ts +2 -1
- package/dist/core/paint.js +4 -3
- package/dist/core/pattern.d.ts +21 -0
- package/dist/core/pattern.js +21 -0
- package/dist/core/pretty.js +9 -10
- package/dist/core/protocol.d.ts +100 -39
- package/dist/core/protocol.js +167 -21
- package/dist/core/render.d.ts +15 -2
- package/dist/core/render.js +25 -5
- package/dist/core/segment.d.ts +13 -5
- package/dist/core/segment.js +23 -9
- package/dist/core/spinnerData.d.ts +1 -1
- package/dist/core/state.d.ts +53 -0
- package/dist/core/state.js +82 -0
- package/dist/core/strip.d.ts +13 -16
- package/dist/core/strip.js +119 -110
- package/dist/core/style.d.ts +47 -14
- package/dist/core/style.js +57 -28
- package/dist/core/text.d.ts +5 -8
- package/dist/core/text.js +116 -124
- package/dist/core/timeline.d.ts +30 -5
- package/dist/core/timeline.js +43 -7
- package/dist/core/tween.d.ts +1 -1
- package/dist/core/tween.js +5 -3
- package/dist/core/view.d.ts +92 -0
- package/dist/core/view.js +83 -0
- package/dist/host/app.d.ts +49 -21
- package/dist/host/app.js +71 -37
- package/dist/host/input.js +3 -4
- package/dist/index.d.ts +24 -12
- package/dist/index.js +9 -4
- package/dist/node/traceback.js +4 -3
- package/dist/renderables/align.d.ts +2 -3
- package/dist/renderables/align.js +0 -3
- package/dist/renderables/change.d.ts +42 -0
- package/dist/renderables/change.js +112 -0
- package/dist/renderables/columns.d.ts +3 -4
- package/dist/renderables/columns.js +2 -7
- package/dist/renderables/constrain.d.ts +2 -3
- package/dist/renderables/constrain.js +0 -3
- package/dist/renderables/effect.d.ts +132 -54
- package/dist/renderables/effect.js +188 -115
- package/dist/renderables/effects.d.ts +122 -11
- package/dist/renderables/effects.js +238 -94
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +16 -8
- package/dist/renderables/flexStrip.d.ts +2 -3
- package/dist/renderables/flexStrip.js +0 -4
- package/dist/renderables/frames.d.ts +35 -54
- package/dist/renderables/frames.js +43 -58
- package/dist/renderables/glyph-effect.d.ts +158 -0
- package/dist/renderables/glyph-effect.js +237 -0
- package/dist/renderables/glyph-effects.d.ts +147 -0
- package/dist/renderables/glyph-effects.js +283 -0
- package/dist/renderables/group.d.ts +3 -4
- package/dist/renderables/group.js +0 -3
- package/dist/renderables/layout.d.ts +12 -12
- package/dist/renderables/layout.js +40 -46
- package/dist/renderables/lifecycle.d.ts +77 -0
- package/dist/renderables/lifecycle.js +132 -0
- package/dist/renderables/list-view.d.ts +4 -5
- package/dist/renderables/list-view.js +9 -13
- package/dist/renderables/live.d.ts +36 -21
- package/dist/renderables/live.js +88 -41
- package/dist/renderables/markdown-parse.d.ts +4 -4
- package/dist/renderables/markdown-parse.js +52 -46
- package/dist/renderables/markdown-url.js +11 -11
- package/dist/renderables/padding.d.ts +4 -5
- package/dist/renderables/padding.js +0 -3
- package/dist/renderables/panel.d.ts +14 -16
- package/dist/renderables/panel.js +6 -14
- package/dist/renderables/progress.d.ts +83 -34
- package/dist/renderables/progress.js +182 -95
- package/dist/renderables/progressBar.d.ts +22 -12
- package/dist/renderables/progressBar.js +32 -9
- package/dist/renderables/prompt.js +3 -2
- package/dist/renderables/python-space.js +2 -1
- package/dist/renderables/scroll.d.ts +50 -0
- package/dist/renderables/scroll.js +106 -0
- package/dist/renderables/spinner.d.ts +35 -14
- package/dist/renderables/spinner.js +65 -25
- package/dist/renderables/status.js +1 -1
- package/dist/renderables/syntax.d.ts +10 -9
- package/dist/renderables/syntax.js +3 -2
- package/dist/renderables/table.d.ts +34 -40
- package/dist/renderables/table.js +41 -63
- package/dist/renderables/traceback.d.ts +2 -2
- package/dist/renderables/traceback.js +6 -5
- package/dist/renderables/tree.d.ts +27 -25
- package/dist/renderables/tree.js +104 -58
- package/dist/renderables/viewport.d.ts +75 -44
- package/dist/renderables/viewport.js +145 -82
- package/dist/template-bindings/animation-funcs.d.ts +78 -9
- package/dist/template-bindings/animation-funcs.js +132 -14
- package/dist/template-bindings/index.d.ts +5 -5
- package/dist/template-bindings/index.js +5 -5
- package/dist/themes/ramp.d.ts +46 -3
- package/dist/themes/ramp.js +61 -4
- package/dist/themes/registry.js +5 -7
- package/dist/widgets/button.js +3 -2
- package/dist/widgets/checkbox.js +4 -3
- package/dist/widgets/dropdown.d.ts +3 -1
- package/dist/widgets/dropdown.js +20 -15
- package/dist/widgets/event-router.js +4 -2
- package/dist/widgets/focus-manager.d.ts +2 -0
- package/dist/widgets/focus-manager.js +6 -4
- package/dist/widgets/hit.d.ts +6 -0
- package/dist/widgets/hit.js +8 -1
- package/dist/widgets/observable.d.ts +23 -0
- package/dist/widgets/observable.js +43 -0
- package/dist/widgets/slider.d.ts +1 -1
- package/dist/widgets/slider.js +12 -3
- package/dist/widgets/static-item.d.ts +2 -3
- package/dist/widgets/static-item.js +0 -3
- package/dist/widgets/text-input.d.ts +28 -32
- package/dist/widgets/text-input.js +360 -346
- package/dist/widgets/themed-widget.js +2 -1
- package/dist/widgets/toggle.js +4 -3
- package/dist/widgets/types.d.ts +10 -4
- package/dist/widgets/types.js +8 -2
- package/dist/widgets/widget-app.d.ts +14 -4
- package/dist/widgets/widget-app.js +36 -7
- package/dist/widgets/widget-base.d.ts +2 -2
- package/dist/widgets/widget-base.js +29 -18
- package/package.json +8 -1
|
@@ -4,13 +4,25 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A host that builds its cells in templates — cc-candybar's statusline, say —
|
|
6
6
|
* evaluates each template once per redraw and owns the clock that says when
|
|
7
|
-
* that is. So the
|
|
8
|
-
* `richTextFuncs(drawnAt)` takes the drawn depth: `
|
|
9
|
-
*
|
|
7
|
+
* that is. So the frame is a capability the registration takes, the way
|
|
8
|
+
* `richTextFuncs(drawnAt)` takes the drawn depth: `frame()` is read once per
|
|
9
|
+
* call, when the template is evaluated, and nothing here reads a clock.
|
|
10
10
|
* [LAW:no-ambient-temporal-coupling] A host hands in the same `t` and gets
|
|
11
11
|
* the same fragment back; a host that redraws once a second or sixty times
|
|
12
12
|
* a second registers the same functions.
|
|
13
13
|
*
|
|
14
|
+
* Every function draws its animation on a `Timeline` (`../core/timeline.ts`)
|
|
15
|
+
* the host hands in as a getter beside the time — playing from host time 0
|
|
16
|
+
* at rate 1, the host's own clock, when it hands none — so a daemon pauses,
|
|
17
|
+
* reverses, scrubs or speeds one session's animations by changing one value
|
|
18
|
+
* it holds, with nothing recompiled, as `paletteFuncs` follows a theme
|
|
19
|
+
* through its getter. The timeline is a map the drawing runs through, not a
|
|
20
|
+
* number the time is turned into first: a frame's stamp says when it changes
|
|
21
|
+
* on the host's clock, which only `Timeline.run` can carry it back onto —
|
|
22
|
+
* paused, never; backwards, at the hold it is about to drop under.
|
|
23
|
+
* [LAW:single-enforcer] `drawing` is the one place the time, the timeline
|
|
24
|
+
* and the reader's preference for motion are read, for every function.
|
|
25
|
+
*
|
|
14
26
|
* `frames <seconds> <frame> <seconds> <frame> …` is a `FrameSequence`
|
|
15
27
|
* (`renderables/frames.ts`) in a template: the frame in progress at the
|
|
16
28
|
* moment, as a fragment at the width of the widest. Its frames arrive as
|
|
@@ -25,11 +37,49 @@
|
|
|
25
37
|
* end, so the engine's `alternating` gate types every slot and lifts each
|
|
26
38
|
* string frame to a fragment; the pairing — a trailing hold with no frame or
|
|
27
39
|
* colour — is parsed in `pairs`, once. [LAW:types-are-the-program]
|
|
40
|
+
*
|
|
41
|
+
* The rest start at a moment the template names, on the timeline's clock —
|
|
42
|
+
* a field of the host's state, the moment a value changed — and each is the
|
|
43
|
+
* animation `Timeline.play(start)` runs, so a start is a timeline like any
|
|
44
|
+
* other and nothing here offsets a time by hand. `tween <seconds> <ease>
|
|
45
|
+
* <start> <from> <to>` is a number eased from one value to another and held
|
|
46
|
+
* (`core/tween.ts`), its ease spelled by name (`parseEase`); `loop <seconds>
|
|
47
|
+
* <start>` is the way through a period, 0 to 1 and round again — two
|
|
48
|
+
* cells started a step apart are a stagger. Each is a number, so it goes
|
|
49
|
+
* wherever a number goes: a colour tween is `ramp (tween …) "linear" 0 $from
|
|
50
|
+
* 1 $to` and a ramp scrolling is `ramp (loop …) …`, because `ColorRamp` is
|
|
51
|
+
* the one place two colours are blended and a colour tween is a two-stop
|
|
52
|
+
* ramp read over time (`ColorRamp.over`). [LAW:one-source-of-truth] A
|
|
53
|
+
* second blender here would be a second answer to what lies between two
|
|
54
|
+
* colours. `glyphs <name> <start> <fragment>` is the fragment through a
|
|
55
|
+
* glyph effect from the catalogue (`GLYPH_EFFECT_CATALOGUE`), at its
|
|
56
|
+
* defaults, before any render (`reglyphText`). Every argument list is an
|
|
57
|
+
* exact arity of typed slots, so a slot of the wrong kind fails at the gate.
|
|
58
|
+
*
|
|
59
|
+
* Every function says when what it drew changes, so a host paints a
|
|
60
|
+
* template while it moves and not after. `frames` and `glyphs` stamp the
|
|
61
|
+
* fragment they draw (`textFrameAt`), covering its own glyphs. A number or a
|
|
62
|
+
* colour carries no cells to stamp, so `tween`, `loop` and `stepped` tell
|
|
63
|
+
* their hold to the frame instead (`TemplateFrame.onHold`), as a placed
|
|
64
|
+
* animation of no cells does (`RenderOptions.onHold`). Nothing here claims
|
|
65
|
+
* a moment it does not know.
|
|
28
66
|
*/
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
67
|
+
import { Animation, frameTimeOf, holdOf, shownAt } from "../core/animation.js";
|
|
68
|
+
import { Phase, beat, finiteTime, parseEase } from "../core/easing.js";
|
|
69
|
+
import { Timeline } from "../core/timeline.js";
|
|
70
|
+
import { tween } from "../core/tween.js";
|
|
71
|
+
import { cellSeed } from "../renderables/effect.js";
|
|
72
|
+
import { reglyphText } from "../renderables/glyph-effect.js";
|
|
73
|
+
import { GLYPH_EFFECT_CATALOGUE } from "../renderables/glyph-effects.js";
|
|
74
|
+
import { FrameSequence, textFrameAt } from "../renderables/frames.js";
|
|
31
75
|
import { asColor } from "./color-funcs.js";
|
|
32
76
|
import { asFragment } from "./helpers.js";
|
|
77
|
+
/** The frame a renderable is drawn in, as the frame a template it evaluates there is drawn for. */
|
|
78
|
+
export function templateFrame(options) {
|
|
79
|
+
return { time: frameTimeOf(options), onHold: options.onHold, reducedMotion: options.reducedMotion, asciiOnly: options.asciiOnly };
|
|
80
|
+
}
|
|
81
|
+
/** The host's own clock as a timeline: host time 0 at animation time 0, at rate 1. */
|
|
82
|
+
const HOST_CLOCK = Timeline.play(0);
|
|
33
83
|
/**
|
|
34
84
|
* The `(seconds, value)` pairs a call spells, each value read through
|
|
35
85
|
* `value`. The gate has typed every even slot as a float and every odd one
|
|
@@ -54,17 +104,59 @@ function pairs(what, tail, value) {
|
|
|
54
104
|
return paired;
|
|
55
105
|
}
|
|
56
106
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
|
|
107
|
+
* Every glyph effect in the catalogue by the name a template spells it
|
|
108
|
+
* with, a transition as the effect it runs. [LAW:types-are-the-program]
|
|
109
|
+
* Keyed by both name types, so a name added to the catalogue does not
|
|
110
|
+
* compile until it is spelled here too.
|
|
111
|
+
*/
|
|
112
|
+
const GLYPH_EFFECTS = {
|
|
113
|
+
...GLYPH_EFFECT_CATALOGUE.loops,
|
|
114
|
+
typewriter: (element) => GLYPH_EFFECT_CATALOGUE.transitions.typewriter(element).effect,
|
|
115
|
+
scramble: (element) => GLYPH_EFFECT_CATALOGUE.transitions.scramble(element).effect,
|
|
116
|
+
backspace: (element) => GLYPH_EFFECT_CATALOGUE.transitions.backspace(element).effect,
|
|
117
|
+
scrambleOut: (element) => GLYPH_EFFECT_CATALOGUE.transitions.scrambleOut(element).effect,
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* The gate a spelled glyph effect crosses: the name in, the effect's maker
|
|
121
|
+
* out, or a refusal naming every legal one. [LAW:parse-dont-validate]
|
|
122
|
+
*/
|
|
123
|
+
function glyphEffect(name) {
|
|
124
|
+
if (!Object.hasOwn(GLYPH_EFFECTS, name)) {
|
|
125
|
+
throw new RangeError(`unknown glyph effect ${JSON.stringify(name)}; expected one of ${Object.keys(GLYPH_EFFECTS).map((n) => JSON.stringify(n)).join(", ")}`);
|
|
126
|
+
}
|
|
127
|
+
return GLYPH_EFFECTS[name];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Register `frames`, `stepped`, `tween`, `loop` and `glyphs`, each drawn for
|
|
131
|
+
* the frame `frame` reports when the template is evaluated — its time in
|
|
132
|
+
* seconds, from whatever zero the host counts from — through
|
|
133
|
+
* `options.timeline`, and each telling that frame when what it drew changes.
|
|
134
|
+
* The functions exist whatever `frame` returns, so a template compiles once
|
|
135
|
+
* and is evaluated at every moment the host draws. In a frame that says
|
|
136
|
+
* `reducedMotion` each draws its animation reduced (`Animation.reduced`): a
|
|
137
|
+
* loop at its start, a one-shot cut from where it starts to where it arrives
|
|
138
|
+
* when it starts.
|
|
62
139
|
*/
|
|
63
|
-
export function animationFuncs(
|
|
140
|
+
export function animationFuncs(frame, options = {}) {
|
|
141
|
+
const timeline = options.timeline ?? (() => HOST_CLOCK);
|
|
142
|
+
// `animation` on this call's timeline, and the time of `at`, the frame it
|
|
143
|
+
// is drawn in, read once a call so a value and its hold are one frame's.
|
|
144
|
+
const drawing = (what, animation, at) => [Timeline.run(timeline(), animation), finiteTime(what, at.time)];
|
|
145
|
+
// What a value animation shows now, under the reader's preference, its
|
|
146
|
+
// hold told to the frame: a value has no cells to carry it.
|
|
147
|
+
const now = (what, animation) => {
|
|
148
|
+
const at = frame();
|
|
149
|
+
const [drawn, t] = drawing(what, animation, at);
|
|
150
|
+
const shown = shownAt(drawn, t, at);
|
|
151
|
+
at.onHold?.(holdOf(shown, t));
|
|
152
|
+
return shown.value;
|
|
153
|
+
};
|
|
154
|
+
const startedAt = (start, animation) => Timeline.run(Timeline.play(start), animation);
|
|
64
155
|
const framesFunc = {
|
|
65
156
|
fn: ((...tail) => {
|
|
66
157
|
const frames = pairs("frame", tail, asFragment).map(({ seconds, value }) => ({ seconds, text: value }));
|
|
67
|
-
|
|
158
|
+
const at = frame();
|
|
159
|
+
return textFrameAt(...drawing("frames", new FrameSequence(frames), at), at);
|
|
68
160
|
}),
|
|
69
161
|
argTypes: ["float", "liftable"],
|
|
70
162
|
arity: { kind: "alternating", minimum: 2 },
|
|
@@ -73,11 +165,37 @@ export function animationFuncs(frameTime) {
|
|
|
73
165
|
const steppedFunc = {
|
|
74
166
|
fn: ((...tail) => {
|
|
75
167
|
const steps = pairs("color", tail, (v) => asColor(v, "stepped"));
|
|
76
|
-
return steps[beat(steps.map((step) => step.seconds))
|
|
168
|
+
return steps[now("stepped", beat(steps.map((step) => step.seconds)))].value.hex;
|
|
77
169
|
}),
|
|
78
170
|
argTypes: ["float", "string"],
|
|
79
171
|
arity: { kind: "alternating", minimum: 2 },
|
|
80
172
|
returnType: "string",
|
|
81
173
|
};
|
|
82
|
-
|
|
174
|
+
const tweenFunc = {
|
|
175
|
+
fn: ((seconds, ease, start, from, to) => now("tween", startedAt(start, tween(from, to, { seconds, ease: parseEase(ease) })))),
|
|
176
|
+
argTypes: ["float", "string", "float", "float", "float"],
|
|
177
|
+
arity: { kind: "exact" },
|
|
178
|
+
returnType: "float",
|
|
179
|
+
};
|
|
180
|
+
const loopFunc = {
|
|
181
|
+
fn: ((seconds, start) => now("loop", startedAt(start, Animation.continuous(Phase.loop(seconds))))),
|
|
182
|
+
argTypes: ["float", "float"],
|
|
183
|
+
arity: { kind: "exact" },
|
|
184
|
+
returnType: "float",
|
|
185
|
+
};
|
|
186
|
+
const glyphsFunc = {
|
|
187
|
+
fn: ((name, start, child) => {
|
|
188
|
+
const make = glyphEffect(name);
|
|
189
|
+
const fragment = asFragment(child);
|
|
190
|
+
// One text, one seed: the element is named by what it says.
|
|
191
|
+
const key = fragment.plain;
|
|
192
|
+
const at = frame();
|
|
193
|
+
const reglyphed = reglyphText(fragment, make({ z: cellSeed(key, 0, 0) }), { key, asciiOnly: at.asciiOnly === true });
|
|
194
|
+
return textFrameAt(...drawing("glyphs", startedAt(start, reglyphed), at), at);
|
|
195
|
+
}),
|
|
196
|
+
argTypes: ["string", "float", "liftable"],
|
|
197
|
+
arity: { kind: "exact" },
|
|
198
|
+
returnType: "T",
|
|
199
|
+
};
|
|
200
|
+
return { frames: framesFunc, stepped: steppedFunc, tween: tweenFunc, loop: loopFunc, glyphs: glyphsFunc };
|
|
83
201
|
}
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
* - `paletteFuncs(getPalette)` — `color` and `ramp`, the two functions that
|
|
15
15
|
* resolve a palette name. This is the *only* registration that knows a
|
|
16
16
|
* palette exists. [LAW:one-way-deps]
|
|
17
|
-
* - `animationFuncs(
|
|
18
|
-
*
|
|
19
|
-
* template is evaluated at a time, and the time
|
|
20
|
-
* (`./animation-funcs.ts`).
|
|
17
|
+
* - `animationFuncs(frame)` — `frames`, `stepped`, `tween`, `loop` and
|
|
18
|
+
* `glyphs`, drawn for a moment on a timeline. It is the only registration
|
|
19
|
+
* that knows the template is evaluated at a time, and the time and the
|
|
20
|
+
* timeline are the host's to hand in (`./animation-funcs.ts`).
|
|
21
21
|
*
|
|
22
22
|
* `createRichTextEngine()` wires up `richTextFuncs()` only — it cannot supply a
|
|
23
23
|
* palette. Consumers that name theme colours call `paletteFuncs(getPalette)`
|
|
@@ -43,7 +43,7 @@ import type { RenderOptions } from "../core/protocol.js";
|
|
|
43
43
|
import { type DrawnAt } from "./color-funcs.js";
|
|
44
44
|
export { paletteFuncs } from "./palette-funcs.js";
|
|
45
45
|
export { colorFuncs, readableOnFunc, type DrawnAt } from "./color-funcs.js";
|
|
46
|
-
export { animationFuncs } from "./animation-funcs.js";
|
|
46
|
+
export { animationFuncs, templateFrame, type AnimationFuncsOptions, type TemplateFrame } from "./animation-funcs.js";
|
|
47
47
|
/**
|
|
48
48
|
* Funcs registered by the rich-js binding — the colour sinks, the palette-free
|
|
49
49
|
* colour math, text attributes, and the `link` cell-splitter. Nothing here
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
* - `paletteFuncs(getPalette)` — `color` and `ramp`, the two functions that
|
|
15
15
|
* resolve a palette name. This is the *only* registration that knows a
|
|
16
16
|
* palette exists. [LAW:one-way-deps]
|
|
17
|
-
* - `animationFuncs(
|
|
18
|
-
*
|
|
19
|
-
* template is evaluated at a time, and the time
|
|
20
|
-
* (`./animation-funcs.ts`).
|
|
17
|
+
* - `animationFuncs(frame)` — `frames`, `stepped`, `tween`, `loop` and
|
|
18
|
+
* `glyphs`, drawn for a moment on a timeline. It is the only registration
|
|
19
|
+
* that knows the template is evaluated at a time, and the time and the
|
|
20
|
+
* timeline are the host's to hand in (`./animation-funcs.ts`).
|
|
21
21
|
*
|
|
22
22
|
* `createRichTextEngine()` wires up `richTextFuncs()` only — it cannot supply a
|
|
23
23
|
* palette. Consumers that name theme colours call `paletteFuncs(getPalette)`
|
|
@@ -45,7 +45,7 @@ import { richTextStyleFuncs } from "./style-funcs.js";
|
|
|
45
45
|
import { colorFuncs } from "./color-funcs.js";
|
|
46
46
|
export { paletteFuncs } from "./palette-funcs.js";
|
|
47
47
|
export { colorFuncs, readableOnFunc } from "./color-funcs.js";
|
|
48
|
-
export { animationFuncs } from "./animation-funcs.js";
|
|
48
|
+
export { animationFuncs, templateFrame } from "./animation-funcs.js";
|
|
49
49
|
/**
|
|
50
50
|
* Funcs registered by the rich-js binding — the colour sinks, the palette-free
|
|
51
51
|
* colour math, text attributes, and the `link` cell-splitter. Nothing here
|
package/dist/themes/ramp.d.ts
CHANGED
|
@@ -20,9 +20,15 @@
|
|
|
20
20
|
* theme colors passes through perceptually even steps rather than the muddy
|
|
21
21
|
* midpoints of an sRGB blend.
|
|
22
22
|
*
|
|
23
|
+
* A ramp also carries how far it has been moved: `scroll`, in spans, how
|
|
24
|
+
* far its colours have travelled along it, and `hue`, in turns, how far
|
|
25
|
+
* they are rotated round the OKLCH hue circle. A moved ramp is still a
|
|
26
|
+
* `ColorRamp`, so anything that reads a ramp reads a moving one frame by
|
|
27
|
+
* frame (`moving`) with nothing new to learn. [LAW:one-type-per-behavior]
|
|
28
|
+
*
|
|
23
29
|
* [LAW:one-way-deps] Imports `core/color`, `core/easing`, `core/oklch`,
|
|
24
|
-
*
|
|
25
|
-
* what a palette is. Resolving stop *names* is the template binding's
|
|
30
|
+
* `core/animation` for `over` and `moving`, and `core/tween` for `over`; nothing
|
|
31
|
+
* here knows what a palette is. Resolving stop *names* is the template binding's
|
|
26
32
|
* job (`paletteFuncs`), which hands this module resolved colors.
|
|
27
33
|
*/
|
|
28
34
|
import { Animation } from "../core/animation.js";
|
|
@@ -33,6 +39,19 @@ export interface ColorStop {
|
|
|
33
39
|
readonly at: number;
|
|
34
40
|
readonly color: ColorRgba;
|
|
35
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* How a ramp moves over time, each part an `Animation<number>` that is
|
|
44
|
+
* `Animation.constant(0)` when not given. `scroll` is in spans: at 1 the
|
|
45
|
+
* colours have travelled the whole way from the first stop to the last and
|
|
46
|
+
* wrapped back, so `Animation.continuous(Phase.loop(seconds))` scrolls once
|
|
47
|
+
* every `seconds`. `hue` is in turns, CSS's `turn`: at 1 every hue has gone
|
|
48
|
+
* once round the circle. A one-shot that settles is a `tween` to where it
|
|
49
|
+
* rests.
|
|
50
|
+
*/
|
|
51
|
+
export interface RampMotion {
|
|
52
|
+
readonly scroll?: Animation<number>;
|
|
53
|
+
readonly hue?: Animation<number>;
|
|
54
|
+
}
|
|
36
55
|
/**
|
|
37
56
|
* An immutable ramp over stops sorted by position.
|
|
38
57
|
*
|
|
@@ -51,7 +70,11 @@ export interface ColorStop {
|
|
|
51
70
|
export declare class ColorRamp {
|
|
52
71
|
readonly ease: Ease;
|
|
53
72
|
readonly stops: readonly ColorStop[];
|
|
54
|
-
|
|
73
|
+
/** How far the colours have moved along the span, in spans, in [0, 1). */
|
|
74
|
+
readonly scroll: number;
|
|
75
|
+
/** How far every hue is rotated in OKLCH, in turns, in [0, 1). */
|
|
76
|
+
readonly hue: number;
|
|
77
|
+
constructor(ease: Ease, stops: readonly ColorStop[], scroll?: number, hue?: number);
|
|
55
78
|
/**
|
|
56
79
|
* The color at `value`. Below the first stop it is the first color; at or
|
|
57
80
|
* above the last stop it is the last; between two stops the raw progress
|
|
@@ -67,8 +90,17 @@ export declare class ColorRamp {
|
|
|
67
90
|
* `jump-start`/`jump-both` steps, which jump at the start of the interval as
|
|
68
91
|
* CSS defines them. An ease that overshoots [0, 1] holds the end colors
|
|
69
92
|
* where it does: a ramp never paints outside its stops.
|
|
93
|
+
*
|
|
94
|
+
* A scrolled ramp reads, inside its span, the colour `scroll` spans behind
|
|
95
|
+
* `value`, wrapped back round the span as a repeating gradient does —
|
|
96
|
+
* seamless when the first and last stops are one colour; outside the span
|
|
97
|
+
* its end colours hold, however far it has scrolled. A rotated ramp turns
|
|
98
|
+
* the colour read by `hue` at its own lightness and chroma. Unmoved, every
|
|
99
|
+
* read keeps the exactness above.
|
|
70
100
|
*/
|
|
71
101
|
at(value: number): ColorRgba;
|
|
102
|
+
/** The colour at `value` with the ramp unmoved: the stops and the ease alone. */
|
|
103
|
+
private unmoved;
|
|
72
104
|
/**
|
|
73
105
|
* This ramp read over time: its span of positions, from the first stop's
|
|
74
106
|
* to the last's, crossed at a steady rate in `seconds` and held at the last
|
|
@@ -82,4 +114,15 @@ export declare class ColorRamp {
|
|
|
82
114
|
* for byte where `at` paints them.
|
|
83
115
|
*/
|
|
84
116
|
over(seconds: number): Animation<ColorRgba>;
|
|
117
|
+
/**
|
|
118
|
+
* This ramp moving: at `t`, scrolled by `motion.scroll` and rotated by
|
|
119
|
+
* `motion.hue` at `t`, on top of however far it was already moved, and
|
|
120
|
+
* changing when either does — so a loop moves every frame and a ramp a
|
|
121
|
+
* tween settles never changes again once it arrives.
|
|
122
|
+
* [LAW:one-source-of-truth] When it next changes is `Animation.all`'s
|
|
123
|
+
* answer over the two parts; nothing here says it a second time. Whether
|
|
124
|
+
* the depth it is drawn at can show the move is decided where it is drawn
|
|
125
|
+
* (`gradient`, through `stillOnSlots`).
|
|
126
|
+
*/
|
|
127
|
+
moving(motion: RampMotion): Animation<ColorRamp>;
|
|
85
128
|
}
|
package/dist/themes/ramp.js
CHANGED
|
@@ -20,14 +20,20 @@
|
|
|
20
20
|
* theme colors passes through perceptually even steps rather than the muddy
|
|
21
21
|
* midpoints of an sRGB blend.
|
|
22
22
|
*
|
|
23
|
+
* A ramp also carries how far it has been moved: `scroll`, in spans, how
|
|
24
|
+
* far its colours have travelled along it, and `hue`, in turns, how far
|
|
25
|
+
* they are rotated round the OKLCH hue circle. A moved ramp is still a
|
|
26
|
+
* `ColorRamp`, so anything that reads a ramp reads a moving one frame by
|
|
27
|
+
* frame (`moving`) with nothing new to learn. [LAW:one-type-per-behavior]
|
|
28
|
+
*
|
|
23
29
|
* [LAW:one-way-deps] Imports `core/color`, `core/easing`, `core/oklch`,
|
|
24
|
-
*
|
|
25
|
-
* what a palette is. Resolving stop *names* is the template binding's
|
|
30
|
+
* `core/animation` for `over` and `moving`, and `core/tween` for `over`; nothing
|
|
31
|
+
* here knows what a palette is. Resolving stop *names* is the template binding's
|
|
26
32
|
* job (`paletteFuncs`), which hands this module resolved colors.
|
|
27
33
|
*/
|
|
28
34
|
import { Animation } from "../core/animation.js";
|
|
29
35
|
import { EASES } from "../core/easing.js";
|
|
30
|
-
import { Oklch } from "../core/oklch.js";
|
|
36
|
+
import { IDENTITY, Oklch } from "../core/oklch.js";
|
|
31
37
|
import { tween } from "../core/tween.js";
|
|
32
38
|
/**
|
|
33
39
|
* An immutable ramp over stops sorted by position.
|
|
@@ -47,9 +53,15 @@ import { tween } from "../core/tween.js";
|
|
|
47
53
|
export class ColorRamp {
|
|
48
54
|
ease;
|
|
49
55
|
stops;
|
|
50
|
-
|
|
56
|
+
/** How far the colours have moved along the span, in spans, in [0, 1). */
|
|
57
|
+
scroll;
|
|
58
|
+
/** How far every hue is rotated in OKLCH, in turns, in [0, 1). */
|
|
59
|
+
hue;
|
|
60
|
+
constructor(ease, stops, scroll = 0, hue = 0) {
|
|
51
61
|
this.ease = ease;
|
|
52
62
|
this.stops = stops;
|
|
63
|
+
this.scroll = turnOf("scroll", scroll);
|
|
64
|
+
this.hue = turnOf("hue", hue);
|
|
53
65
|
if (stops.length === 0) {
|
|
54
66
|
throw new RangeError("a ColorRamp needs at least one stop");
|
|
55
67
|
}
|
|
@@ -79,11 +91,29 @@ export class ColorRamp {
|
|
|
79
91
|
* `jump-start`/`jump-both` steps, which jump at the start of the interval as
|
|
80
92
|
* CSS defines them. An ease that overshoots [0, 1] holds the end colors
|
|
81
93
|
* where it does: a ramp never paints outside its stops.
|
|
94
|
+
*
|
|
95
|
+
* A scrolled ramp reads, inside its span, the colour `scroll` spans behind
|
|
96
|
+
* `value`, wrapped back round the span as a repeating gradient does —
|
|
97
|
+
* seamless when the first and last stops are one colour; outside the span
|
|
98
|
+
* its end colours hold, however far it has scrolled. A rotated ramp turns
|
|
99
|
+
* the colour read by `hue` at its own lightness and chroma. Unmoved, every
|
|
100
|
+
* read keeps the exactness above.
|
|
82
101
|
*/
|
|
83
102
|
at(value) {
|
|
84
103
|
if (!Number.isFinite(value)) {
|
|
85
104
|
throw new RangeError(`ColorRamp.at needs a finite value, got ${value}`);
|
|
86
105
|
}
|
|
106
|
+
const first = this.stops[0].at;
|
|
107
|
+
const last = this.stops[this.stops.length - 1].at;
|
|
108
|
+
const span = last - first;
|
|
109
|
+
const inside = first <= value && value <= last;
|
|
110
|
+
const moved = inside ? value - this.scroll * span : value;
|
|
111
|
+
const read = this.unmoved(inside && moved < first ? moved + span : moved);
|
|
112
|
+
// Exact when unrotated: the OKLCH round trip can land a channel one off.
|
|
113
|
+
return this.hue === 0 ? read : Oklch.fromRgba(read).applyKey({ ...IDENTITY, hueShift: 360 * this.hue }).toRgba();
|
|
114
|
+
}
|
|
115
|
+
/** The colour at `value` with the ramp unmoved: the stops and the ease alone. */
|
|
116
|
+
unmoved(value) {
|
|
87
117
|
const stops = this.stops;
|
|
88
118
|
// The last stop at or below `value`; -1 when `value` is below them all.
|
|
89
119
|
let lower = -1;
|
|
@@ -121,4 +151,31 @@ export class ColorRamp {
|
|
|
121
151
|
const last = this.stops[this.stops.length - 1].at;
|
|
122
152
|
return Animation.map(tween(first, last, { seconds, ease: EASES.linear }), (value) => this.at(value));
|
|
123
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* This ramp moving: at `t`, scrolled by `motion.scroll` and rotated by
|
|
156
|
+
* `motion.hue` at `t`, on top of however far it was already moved, and
|
|
157
|
+
* changing when either does — so a loop moves every frame and a ramp a
|
|
158
|
+
* tween settles never changes again once it arrives.
|
|
159
|
+
* [LAW:one-source-of-truth] When it next changes is `Animation.all`'s
|
|
160
|
+
* answer over the two parts; nothing here says it a second time. Whether
|
|
161
|
+
* the depth it is drawn at can show the move is decided where it is drawn
|
|
162
|
+
* (`gradient`, through `stillOnSlots`).
|
|
163
|
+
*/
|
|
164
|
+
moving(motion) {
|
|
165
|
+
const still = Animation.constant(0);
|
|
166
|
+
return Animation.map(Animation.all([motion.scroll ?? still, motion.hue ?? still]), ([scroll, hue]) => new ColorRamp(this.ease, this.stops, this.scroll + scroll, this.hue + hue));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* `v` as a fraction of one turn, in [0, 1): a whole turn is no turn, and a
|
|
171
|
+
* negative one counts back from a whole turn. A value so close under a whole
|
|
172
|
+
* turn that the fraction rounds to it is the turn itself. [LAW:single-enforcer]
|
|
173
|
+
* The constructor reads both moves through here, so a non-finite one fails
|
|
174
|
+
* here, loudly, naming which.
|
|
175
|
+
*/
|
|
176
|
+
function turnOf(what, v) {
|
|
177
|
+
if (!Number.isFinite(v))
|
|
178
|
+
throw new RangeError(`ColorRamp ${what} must be finite, got ${v}`);
|
|
179
|
+
const into = v - Math.floor(v);
|
|
180
|
+
return into < 1 ? into : 0;
|
|
124
181
|
}
|
package/dist/themes/registry.js
CHANGED
|
@@ -3,8 +3,11 @@ import { Palette, drawnOn } from "./palette.js";
|
|
|
3
3
|
import { ACCENT_KEYS, accentText } from "./buildPalette.js";
|
|
4
4
|
import { THEMES } from "./data/index.js";
|
|
5
5
|
import { ANSI_SLOTS } from "./data/types.js";
|
|
6
|
+
import { Memo } from "../core/memo.js";
|
|
6
7
|
const THEME_NAMES = Object.freeze(Object.keys(THEMES).sort());
|
|
7
|
-
|
|
8
|
+
// Fewer themes than a Memo holds, so it never clears and a name keeps one
|
|
9
|
+
// Palette — test/themes/registry.test.ts holds that.
|
|
10
|
+
const cache = new Memo();
|
|
8
11
|
/**
|
|
9
12
|
* Returns the static list of available theme names. Pure and synchronous.
|
|
10
13
|
*/
|
|
@@ -14,12 +17,7 @@ export function listThemePalettes() {
|
|
|
14
17
|
export function getThemePalette(name) {
|
|
15
18
|
if (!isThemeName(name))
|
|
16
19
|
return null;
|
|
17
|
-
|
|
18
|
-
if (cached !== undefined)
|
|
19
|
-
return cached;
|
|
20
|
-
const palette = hydrate(THEMES[name]);
|
|
21
|
-
cache.set(name, palette);
|
|
22
|
-
return palette;
|
|
20
|
+
return cache.get(name, () => hydrate(THEMES[name]));
|
|
23
21
|
}
|
|
24
22
|
function isThemeName(name) {
|
|
25
23
|
return Object.hasOwn(THEMES, name);
|
package/dist/widgets/button.js
CHANGED
|
@@ -49,7 +49,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
49
49
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
50
50
|
done = true;
|
|
51
51
|
};
|
|
52
|
-
import {
|
|
52
|
+
import { action } from "mobx";
|
|
53
|
+
import { observableRef } from "./observable.js";
|
|
53
54
|
import { Segment } from "../core/segment.js";
|
|
54
55
|
import { Style } from "../core/style.js";
|
|
55
56
|
import { cellLen } from "../core/cells.js";
|
|
@@ -83,7 +84,7 @@ let Button = (() => {
|
|
|
83
84
|
return class Button extends _classSuper {
|
|
84
85
|
static {
|
|
85
86
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
86
|
-
_label_decorators = [
|
|
87
|
+
_label_decorators = [observableRef];
|
|
87
88
|
_variant_decorators = [observableRef];
|
|
88
89
|
_handleKey_decorators = [action];
|
|
89
90
|
_handleMouse_decorators = [action];
|
package/dist/widgets/checkbox.js
CHANGED
|
@@ -44,7 +44,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
44
44
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
45
45
|
done = true;
|
|
46
46
|
};
|
|
47
|
-
import {
|
|
47
|
+
import { action } from "mobx";
|
|
48
|
+
import { observableRef } from "./observable.js";
|
|
48
49
|
import { Segment } from "../core/segment.js";
|
|
49
50
|
import { Style } from "../core/style.js";
|
|
50
51
|
import { cellLen } from "../core/cells.js";
|
|
@@ -65,8 +66,8 @@ let Checkbox = (() => {
|
|
|
65
66
|
return class Checkbox extends _classSuper {
|
|
66
67
|
static {
|
|
67
68
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
68
|
-
_label_decorators = [
|
|
69
|
-
_checked_decorators = [
|
|
69
|
+
_label_decorators = [observableRef];
|
|
70
|
+
_checked_decorators = [observableRef];
|
|
70
71
|
_handleKey_decorators = [action];
|
|
71
72
|
_handleMouse_decorators = [action];
|
|
72
73
|
__esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
|
|
@@ -37,7 +37,9 @@ export interface DropdownOptions {
|
|
|
37
37
|
export declare class Dropdown extends ThemedWidget implements OverlayRenderable {
|
|
38
38
|
readonly id: string;
|
|
39
39
|
readonly focusable = true;
|
|
40
|
-
accessor
|
|
40
|
+
private accessor _options;
|
|
41
|
+
get options(): readonly string[];
|
|
42
|
+
set options(options: readonly string[]);
|
|
41
43
|
accessor selectedIndex: number;
|
|
42
44
|
accessor expanded: boolean;
|
|
43
45
|
accessor highlightedIndex: number;
|
package/dist/widgets/dropdown.js
CHANGED
|
@@ -56,7 +56,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
56
56
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
57
57
|
done = true;
|
|
58
58
|
};
|
|
59
|
-
import {
|
|
59
|
+
import { action } from "mobx";
|
|
60
|
+
import { observableRef } from "./observable.js";
|
|
60
61
|
import { Segment } from "../core/segment.js";
|
|
61
62
|
import { Style } from "../core/style.js";
|
|
62
63
|
import { cellLen, setCellSize, splitText, asCellCol } from "../core/cells.js";
|
|
@@ -67,9 +68,9 @@ import { ink } from "./ink.js";
|
|
|
67
68
|
let Dropdown = (() => {
|
|
68
69
|
let _classSuper = ThemedWidget;
|
|
69
70
|
let _instanceExtraInitializers = [];
|
|
70
|
-
let
|
|
71
|
-
let
|
|
72
|
-
let
|
|
71
|
+
let __options_decorators;
|
|
72
|
+
let __options_initializers = [];
|
|
73
|
+
let __options_extraInitializers = [];
|
|
73
74
|
let _selectedIndex_decorators;
|
|
74
75
|
let _selectedIndex_initializers = [];
|
|
75
76
|
let _selectedIndex_extraInitializers = [];
|
|
@@ -88,15 +89,15 @@ let Dropdown = (() => {
|
|
|
88
89
|
return class Dropdown extends _classSuper {
|
|
89
90
|
static {
|
|
90
91
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
91
|
-
|
|
92
|
-
_selectedIndex_decorators = [
|
|
93
|
-
_expanded_decorators = [
|
|
94
|
-
_highlightedIndex_decorators = [
|
|
95
|
-
_filter_decorators = [
|
|
92
|
+
__options_decorators = [observableRef];
|
|
93
|
+
_selectedIndex_decorators = [observableRef];
|
|
94
|
+
_expanded_decorators = [observableRef];
|
|
95
|
+
_highlightedIndex_decorators = [observableRef];
|
|
96
|
+
_filter_decorators = [observableRef];
|
|
96
97
|
_handleKey_decorators = [action];
|
|
97
98
|
_handleMouse_decorators = [action];
|
|
98
99
|
_handleFocus_decorators = [action];
|
|
99
|
-
__esDecorate(this, null,
|
|
100
|
+
__esDecorate(this, null, __options_decorators, { kind: "accessor", name: "_options", static: false, private: false, access: { has: obj => "_options" in obj, get: obj => obj._options, set: (obj, value) => { obj._options = value; } }, metadata: _metadata }, __options_initializers, __options_extraInitializers);
|
|
100
101
|
__esDecorate(this, null, _selectedIndex_decorators, { kind: "accessor", name: "selectedIndex", static: false, private: false, access: { has: obj => "selectedIndex" in obj, get: obj => obj.selectedIndex, set: (obj, value) => { obj.selectedIndex = value; } }, metadata: _metadata }, _selectedIndex_initializers, _selectedIndex_extraInitializers);
|
|
101
102
|
__esDecorate(this, null, _expanded_decorators, { kind: "accessor", name: "expanded", static: false, private: false, access: { has: obj => "expanded" in obj, get: obj => obj.expanded, set: (obj, value) => { obj.expanded = value; } }, metadata: _metadata }, _expanded_initializers, _expanded_extraInitializers);
|
|
102
103
|
__esDecorate(this, null, _highlightedIndex_decorators, { kind: "accessor", name: "highlightedIndex", static: false, private: false, access: { has: obj => "highlightedIndex" in obj, get: obj => obj.highlightedIndex, set: (obj, value) => { obj.highlightedIndex = value; } }, metadata: _metadata }, _highlightedIndex_initializers, _highlightedIndex_extraInitializers);
|
|
@@ -108,10 +109,14 @@ let Dropdown = (() => {
|
|
|
108
109
|
}
|
|
109
110
|
id = __runInitializers(this, _instanceExtraInitializers);
|
|
110
111
|
focusable = true;
|
|
111
|
-
#
|
|
112
|
-
get
|
|
113
|
-
set
|
|
114
|
-
|
|
112
|
+
#_options_accessor_storage = __runInitializers(this, __options_initializers, void 0);
|
|
113
|
+
get _options() { return this.#_options_accessor_storage; }
|
|
114
|
+
set _options(value) { this.#_options_accessor_storage = value; }
|
|
115
|
+
// A copy is held, so the caller changing the array it assigned changes
|
|
116
|
+
// nothing here: the labels change only by assignment, which repaints.
|
|
117
|
+
get options() { return this._options; }
|
|
118
|
+
set options(options) { this._options = [...options]; }
|
|
119
|
+
#selectedIndex_accessor_storage = (__runInitializers(this, __options_extraInitializers), __runInitializers(this, _selectedIndex_initializers, void 0));
|
|
115
120
|
get selectedIndex() { return this.#selectedIndex_accessor_storage; }
|
|
116
121
|
set selectedIndex(value) { this.#selectedIndex_accessor_storage = value; }
|
|
117
122
|
#expanded_accessor_storage = (__runInitializers(this, _selectedIndex_extraInitializers), __runInitializers(this, _expanded_initializers, false));
|
|
@@ -140,7 +145,7 @@ let Dropdown = (() => {
|
|
|
140
145
|
super(options.theme);
|
|
141
146
|
__runInitializers(this, _filter_extraInitializers);
|
|
142
147
|
this.id = options.id ?? `dropdown-${Math.random().toString(36).slice(2, 8)}`;
|
|
143
|
-
this.
|
|
148
|
+
this._options = [...options.options];
|
|
144
149
|
// [LAW:types-are-the-program] selectedIndex must point to a valid
|
|
145
150
|
// option (or be 0 for the empty-options case). Clamp at the trust
|
|
146
151
|
// boundary so headerText / render / commit logic can all assume
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* host's input (`host/input`), and `WidgetApp` hands this what the app hears.
|
|
7
7
|
*/
|
|
8
8
|
import { KeyEvent } from "./types.js";
|
|
9
|
-
import { drew, originOf, scrollTargetAt, widgetAt } from "./hit.js";
|
|
9
|
+
import { cellOf, drew, originOf, scrollTargetAt, widgetAt } from "./hit.js";
|
|
10
10
|
export class EventRouter {
|
|
11
11
|
source;
|
|
12
12
|
focusOnClick;
|
|
@@ -78,7 +78,7 @@ export class EventRouter {
|
|
|
78
78
|
}
|
|
79
79
|
/** Route a key the app heard. */
|
|
80
80
|
key(press) {
|
|
81
|
-
this.dispatchKey(new KeyEvent(press));
|
|
81
|
+
this.dispatchKey(new KeyEvent(press, this.source.frameTime));
|
|
82
82
|
}
|
|
83
83
|
/** Route a pointer event the app heard. */
|
|
84
84
|
mouse(event) {
|
|
@@ -172,6 +172,8 @@ export class EventRouter {
|
|
|
172
172
|
x: event.x - target.originX,
|
|
173
173
|
y: event.y - target.originY,
|
|
174
174
|
over: drew(frame, target.widget, event.x, event.y),
|
|
175
|
+
cell: cellOf(frame, target.widget, event.x, event.y),
|
|
176
|
+
time: this.source.frameTime,
|
|
175
177
|
});
|
|
176
178
|
if (event.type === "mouse_down")
|
|
177
179
|
this.captured = target;
|
|
@@ -12,6 +12,8 @@ export interface FocusView {
|
|
|
12
12
|
present(): readonly InteractiveWidget[];
|
|
13
13
|
/** The widgets with a cell on the frame on screen, in document order. */
|
|
14
14
|
onScreen(): readonly InteractiveWidget[];
|
|
15
|
+
/** The time a frame drawn now is drawn for (`RenderOptions.frame`), which a focus change is stamped with. */
|
|
16
|
+
frameTime(): number;
|
|
15
17
|
}
|
|
16
18
|
export declare class DefaultFocusManager implements FocusManager {
|
|
17
19
|
private readonly view;
|