@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
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
* `ThemeKey` to apply (data), not *whether* to apply one (branch).
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] Anchor classification lives only in
|
|
20
|
-
* `ANCHORED_ROOTS` below.
|
|
21
|
-
*
|
|
22
|
-
* (`error`, `error
|
|
23
|
-
* the whole family.
|
|
20
|
+
* `ANCHORED_ROOTS` below. Every variant of a semantic root carries the root
|
|
21
|
+
* as its first hyphen segment (`error`, `error-darken-1`, `error-muted`, ...)
|
|
22
|
+
* or after a `text-` or `on-` that draws on it (`text-error`, `on-error`), so
|
|
23
|
+
* one set covers the whole family.
|
|
24
24
|
*
|
|
25
25
|
* [LAW:one-way-deps] Imports flow `core/oklch → themes/transpose`;
|
|
26
26
|
* nothing in core/ depends back on this file.
|
|
@@ -54,12 +54,7 @@ export declare function isAnchored(varName: string): boolean;
|
|
|
54
54
|
* lightness shifts, mirror-inversions, hue rotations that don't touch L,
|
|
55
55
|
* and combinations of all three. [LAW:types-are-the-program]
|
|
56
56
|
*
|
|
57
|
-
* The
|
|
58
|
-
* `dark`-flag derivation has nothing to read). Failing loudly is preferred
|
|
59
|
-
* over a silent fallback because the alternative — trusting the source
|
|
60
|
-
* `palette.dark` after an arbitrary L-transform — produces flags that lie.
|
|
61
|
-
* The identity fast-path is exempt: it preserves the source `dark` flag
|
|
62
|
-
* verbatim (no derivation), so it needs no `background` and never throws.
|
|
57
|
+
* The identity fast-path preserves the source `dark` flag verbatim.
|
|
63
58
|
*
|
|
64
59
|
* @param name Optional override for the resulting palette name. Defaults
|
|
65
60
|
* to the source palette's name. Callers building a family of transposed
|
package/dist/themes/transpose.js
CHANGED
|
@@ -17,15 +17,16 @@
|
|
|
17
17
|
* `ThemeKey` to apply (data), not *whether* to apply one (branch).
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] Anchor classification lives only in
|
|
20
|
-
* `ANCHORED_ROOTS` below.
|
|
21
|
-
*
|
|
22
|
-
* (`error`, `error
|
|
23
|
-
* the whole family.
|
|
20
|
+
* `ANCHORED_ROOTS` below. Every variant of a semantic root carries the root
|
|
21
|
+
* as its first hyphen segment (`error`, `error-darken-1`, `error-muted`, ...)
|
|
22
|
+
* or after a `text-` or `on-` that draws on it (`text-error`, `on-error`), so
|
|
23
|
+
* one set covers the whole family.
|
|
24
24
|
*
|
|
25
25
|
* [LAW:one-way-deps] Imports flow `core/oklch → themes/transpose`;
|
|
26
26
|
* nothing in core/ depends back on this file.
|
|
27
27
|
*/
|
|
28
28
|
import { Oklch, isIdentityKey } from "../core/oklch.js";
|
|
29
|
+
import { pattern } from "../core/pattern.js";
|
|
29
30
|
import { Palette } from "./palette.js";
|
|
30
31
|
/**
|
|
31
32
|
* Semantic roots whose hue is locked under transposition. `error` must
|
|
@@ -43,9 +44,11 @@ export const ANCHORED_ROOTS = new Set([
|
|
|
43
44
|
"success",
|
|
44
45
|
"warning",
|
|
45
46
|
]);
|
|
47
|
+
const DRAWN_ON = pattern(/^(?:text|on)-/);
|
|
46
48
|
function rootOf(varName) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
+
const role = varName.replace(DRAWN_ON, "");
|
|
50
|
+
const dash = role.indexOf("-");
|
|
51
|
+
return dash === -1 ? role : role.slice(0, dash);
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
51
54
|
* Whether a palette var's hue is locked under transposition. The single
|
|
@@ -68,12 +71,7 @@ export function isAnchored(varName) {
|
|
|
68
71
|
* lightness shifts, mirror-inversions, hue rotations that don't touch L,
|
|
69
72
|
* and combinations of all three. [LAW:types-are-the-program]
|
|
70
73
|
*
|
|
71
|
-
* The
|
|
72
|
-
* `dark`-flag derivation has nothing to read). Failing loudly is preferred
|
|
73
|
-
* over a silent fallback because the alternative — trusting the source
|
|
74
|
-
* `palette.dark` after an arbitrary L-transform — produces flags that lie.
|
|
75
|
-
* The identity fast-path is exempt: it preserves the source `dark` flag
|
|
76
|
-
* verbatim (no derivation), so it needs no `background` and never throws.
|
|
74
|
+
* The identity fast-path preserves the source `dark` flag verbatim.
|
|
77
75
|
*
|
|
78
76
|
* @param name Optional override for the resulting palette name. Defaults
|
|
79
77
|
* to the source palette's name. Callers building a family of transposed
|
|
@@ -81,23 +79,14 @@ export function isAnchored(varName) {
|
|
|
81
79
|
*/
|
|
82
80
|
export function transposePalette(palette, key, name) {
|
|
83
81
|
if (isIdentityKey(key)) {
|
|
84
|
-
return new Palette(name ?? palette.name, palette.dark, palette.
|
|
82
|
+
return new Palette(name ?? palette.name, palette.dark, palette.mapRoles((colour) => colour));
|
|
85
83
|
}
|
|
86
84
|
// Anchors share *everything except* hue with the user's key. They still
|
|
87
85
|
// lightness-invert in a dark↔light flip; they still chroma-scale in a
|
|
88
86
|
// saturation sweep — only their hue is held.
|
|
89
87
|
const anchorKey = { ...key, hueShift: 0 };
|
|
90
|
-
const next =
|
|
91
|
-
|
|
92
|
-
const effective = isAnchored(varName) ? anchorKey : key;
|
|
93
|
-
next.set(varName, Oklch.fromRgba(color).applyKey(effective).toRgba());
|
|
94
|
-
}
|
|
95
|
-
const newBackground = next.get("background");
|
|
96
|
-
if (newBackground === undefined) {
|
|
97
|
-
throw new Error(`transposePalette: palette "${palette.name}" has no "background" ` +
|
|
98
|
-
`var; cannot derive the dark flag without a background color.`);
|
|
99
|
-
}
|
|
100
|
-
const newDark = Oklch.fromRgba(newBackground).l < 0.5;
|
|
88
|
+
const next = palette.mapRoles((colour, role) => Oklch.fromRgba(colour).applyKey(isAnchored(role) ? anchorKey : key).toRgba());
|
|
89
|
+
const newDark = Oklch.fromRgba(next.background).l < 0.5;
|
|
101
90
|
return new Palette(name ?? palette.name, newDark, next);
|
|
102
91
|
}
|
|
103
92
|
/**
|
|
@@ -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, this.source.
|
|
81
|
+
this.dispatchKey(new KeyEvent(press, this.source.frameNow().time));
|
|
82
82
|
}
|
|
83
83
|
/** Route a pointer event the app heard. */
|
|
84
84
|
mouse(event) {
|
|
@@ -173,7 +173,7 @@ export class EventRouter {
|
|
|
173
173
|
y: event.y - target.originY,
|
|
174
174
|
over: drew(frame, target.widget, event.x, event.y),
|
|
175
175
|
cell: cellOf(frame, target.widget, event.x, event.y),
|
|
176
|
-
time: this.source.
|
|
176
|
+
time: this.source.frameNow().time,
|
|
177
177
|
});
|
|
178
178
|
if (event.type === "mouse_down")
|
|
179
179
|
this.captured = target;
|
package/dist/widgets/ink.d.ts
CHANGED
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
*
|
|
12
12
|
* [LAW:types-are-the-program] There is no call that takes a foreground alone,
|
|
13
13
|
* so a widget cannot draw half a pair.
|
|
14
|
-
* [LAW:single-enforcer] Every widget resolves palette
|
|
15
|
-
* where
|
|
16
|
-
*
|
|
14
|
+
* [LAW:single-enforcer] Every widget resolves palette roles here, and this is
|
|
15
|
+
* where one that draws no colour (a theme's fully transparent "no background")
|
|
16
|
+
* is reported.
|
|
17
17
|
*/
|
|
18
18
|
import { ColorSpec, type TerminalTheme } from "../core/color.js";
|
|
19
|
-
|
|
19
|
+
import type { PaletteRole } from "../themes/palette.js";
|
|
20
|
+
export declare function ink(theme: TerminalTheme, fg: PaletteRole, bg: PaletteRole): {
|
|
20
21
|
color: ColorSpec;
|
|
21
22
|
bgcolor: ColorSpec;
|
|
22
23
|
};
|
package/dist/widgets/ink.js
CHANGED
|
@@ -11,21 +11,18 @@
|
|
|
11
11
|
*
|
|
12
12
|
* [LAW:types-are-the-program] There is no call that takes a foreground alone,
|
|
13
13
|
* so a widget cannot draw half a pair.
|
|
14
|
-
* [LAW:single-enforcer] Every widget resolves palette
|
|
15
|
-
* where
|
|
16
|
-
*
|
|
14
|
+
* [LAW:single-enforcer] Every widget resolves palette roles here, and this is
|
|
15
|
+
* where one that draws no colour (a theme's fully transparent "no background")
|
|
16
|
+
* is reported.
|
|
17
17
|
*/
|
|
18
18
|
import { ColorSpec } from "../core/color.js";
|
|
19
19
|
export function ink(theme, fg, bg) {
|
|
20
20
|
return { color: paletteColor(theme, fg), bgcolor: paletteColor(theme, bg) };
|
|
21
21
|
}
|
|
22
|
-
function paletteColor(theme,
|
|
23
|
-
const rgba = theme.palette.get(
|
|
24
|
-
if (rgba === undefined) {
|
|
25
|
-
throw new RangeError(`palette ${JSON.stringify(theme.palette.name)} has no ${JSON.stringify(key)}`);
|
|
26
|
-
}
|
|
22
|
+
function paletteColor(theme, role) {
|
|
23
|
+
const rgba = theme.palette.get(role);
|
|
27
24
|
if (rgba.alpha === 0) {
|
|
28
|
-
throw new RangeError(`palette ${JSON.stringify(theme.palette.name)}: ${JSON.stringify(
|
|
25
|
+
throw new RangeError(`palette ${JSON.stringify(theme.palette.name)}: ${JSON.stringify(role)} is fully transparent, so it cannot be half of a widget's colour pair`);
|
|
29
26
|
}
|
|
30
27
|
return ColorSpec.fromRgba(rgba);
|
|
31
28
|
}
|
|
@@ -198,7 +198,7 @@ export declare class TextInput extends ThemedWidget {
|
|
|
198
198
|
readonly focusable = true;
|
|
199
199
|
private accessor _value;
|
|
200
200
|
private accessor _cursor;
|
|
201
|
-
private accessor
|
|
201
|
+
private accessor _blink;
|
|
202
202
|
get value(): string;
|
|
203
203
|
set value(v: string);
|
|
204
204
|
get cursorPosition(): CodePoint;
|
|
@@ -107,7 +107,7 @@ import { Viewport } from "../renderables/viewport.js";
|
|
|
107
107
|
import { Animation } from "../core/animation.js";
|
|
108
108
|
import { beat } from "../core/easing.js";
|
|
109
109
|
import { Timeline } from "../core/timeline.js";
|
|
110
|
-
import {
|
|
110
|
+
import { placed } from "../core/animation.js";
|
|
111
111
|
import { levelOf } from "../core/anchor.js";
|
|
112
112
|
import { ThemedWidget } from "./themed-widget.js";
|
|
113
113
|
import { ink } from "./ink.js";
|
|
@@ -244,8 +244,24 @@ function wordSpan(clusters, skipped, taken) {
|
|
|
244
244
|
* for the next, on a `beat`. A loop, so with its motion taken out it holds lit.
|
|
245
245
|
*/
|
|
246
246
|
const CARET_BLINK = Animation.map(beat([0.5, 0.5]), (hold) => hold === 0);
|
|
247
|
-
/**
|
|
248
|
-
|
|
247
|
+
/**
|
|
248
|
+
* The caret's blink restarted at `from`, as one animation of the frame's
|
|
249
|
+
* time: `CARET_BLINK` run forward from `from` at and after it, and backward
|
|
250
|
+
* from it before, so a timeline played backwards also finds the caret lit
|
|
251
|
+
* just after a key. Each answer is the run the time falls in, bounded at
|
|
252
|
+
* `from` where the runs meet — early where it must guess, never late. A
|
|
253
|
+
* function of `from` alone, so the frame hands it its time (`placed`).
|
|
254
|
+
*/
|
|
255
|
+
function caretBlink(from) {
|
|
256
|
+
const forward = Timeline.run(Timeline.play(from, 1), CARET_BLINK);
|
|
257
|
+
const backward = Timeline.run(Timeline.play(from, -1), CARET_BLINK);
|
|
258
|
+
return Animation.of({
|
|
259
|
+
at: (t) => (t >= from ? forward : backward).at(t),
|
|
260
|
+
nextChange: (t) => (t >= from ? forward.nextChange(t) : Math.min(backward.nextChange(t), from)),
|
|
261
|
+
lastChange: (t) => (t >= from ? Math.max(forward.lastChange(t), from) : backward.lastChange(t)),
|
|
262
|
+
reduced: () => CARET_BLINK.reduced(),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
249
265
|
let TextInput = (() => {
|
|
250
266
|
let _classSuper = ThemedWidget;
|
|
251
267
|
let _instanceExtraInitializers = [];
|
|
@@ -255,9 +271,9 @@ let TextInput = (() => {
|
|
|
255
271
|
let __cursor_decorators;
|
|
256
272
|
let __cursor_initializers = [];
|
|
257
273
|
let __cursor_extraInitializers = [];
|
|
258
|
-
let
|
|
259
|
-
let
|
|
260
|
-
let
|
|
274
|
+
let __blink_decorators;
|
|
275
|
+
let __blink_initializers = [];
|
|
276
|
+
let __blink_extraInitializers = [];
|
|
261
277
|
let _placeholder_decorators;
|
|
262
278
|
let _placeholder_initializers = [];
|
|
263
279
|
let _placeholder_extraInitializers = [];
|
|
@@ -298,7 +314,7 @@ let TextInput = (() => {
|
|
|
298
314
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
299
315
|
__value_decorators = [observableRef];
|
|
300
316
|
__cursor_decorators = [observableRef];
|
|
301
|
-
|
|
317
|
+
__blink_decorators = [observableRef];
|
|
302
318
|
_placeholder_decorators = [observableRef];
|
|
303
319
|
_indicatorStyleOverride_decorators = [observableRef];
|
|
304
320
|
_cursorStyleOverride_decorators = [observableRef];
|
|
@@ -328,7 +344,7 @@ let TextInput = (() => {
|
|
|
328
344
|
__insertText_decorators = [action];
|
|
329
345
|
__esDecorate(this, null, __value_decorators, { kind: "accessor", name: "_value", static: false, private: false, access: { has: obj => "_value" in obj, get: obj => obj._value, set: (obj, value) => { obj._value = value; } }, metadata: _metadata }, __value_initializers, __value_extraInitializers);
|
|
330
346
|
__esDecorate(this, null, __cursor_decorators, { kind: "accessor", name: "_cursor", static: false, private: false, access: { has: obj => "_cursor" in obj, get: obj => obj._cursor, set: (obj, value) => { obj._cursor = value; } }, metadata: _metadata }, __cursor_initializers, __cursor_extraInitializers);
|
|
331
|
-
__esDecorate(this, null,
|
|
347
|
+
__esDecorate(this, null, __blink_decorators, { kind: "accessor", name: "_blink", static: false, private: false, access: { has: obj => "_blink" in obj, get: obj => obj._blink, set: (obj, value) => { obj._blink = value; } }, metadata: _metadata }, __blink_initializers, __blink_extraInitializers);
|
|
332
348
|
__esDecorate(this, null, _placeholder_decorators, { kind: "accessor", name: "placeholder", static: false, private: false, access: { has: obj => "placeholder" in obj, get: obj => obj.placeholder, set: (obj, value) => { obj.placeholder = value; } }, metadata: _metadata }, _placeholder_initializers, _placeholder_extraInitializers);
|
|
333
349
|
__esDecorate(this, null, _indicatorStyleOverride_decorators, { kind: "accessor", name: "indicatorStyleOverride", static: false, private: false, access: { has: obj => "indicatorStyleOverride" in obj, get: obj => obj.indicatorStyleOverride, set: (obj, value) => { obj.indicatorStyleOverride = value; } }, metadata: _metadata }, _indicatorStyleOverride_initializers, _indicatorStyleOverride_extraInitializers);
|
|
334
350
|
__esDecorate(this, null, _cursorStyleOverride_decorators, { kind: "accessor", name: "cursorStyleOverride", static: false, private: false, access: { has: obj => "cursorStyleOverride" in obj, get: obj => obj.cursorStyleOverride, set: (obj, value) => { obj.cursorStyleOverride = value; } }, metadata: _metadata }, _cursorStyleOverride_initializers, _cursorStyleOverride_extraInitializers);
|
|
@@ -366,13 +382,12 @@ let TextInput = (() => {
|
|
|
366
382
|
#_cursor_accessor_storage = (__runInitializers(this, __value_extraInitializers), __runInitializers(this, __cursor_initializers, void 0));
|
|
367
383
|
get _cursor() { return this.#_cursor_accessor_storage; }
|
|
368
384
|
set _cursor(value) { this.#_cursor_accessor_storage = value; }
|
|
369
|
-
#
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
set _blinkFrom(value) { this.#_blinkFrom_accessor_storage = value; }
|
|
385
|
+
#_blink_accessor_storage = (__runInitializers(this, __cursor_extraInitializers), __runInitializers(this, __blink_initializers, caretBlink(0)));
|
|
386
|
+
// The caret's blink, restarted (`caretBlink`) when the field last took
|
|
387
|
+
// focus, a click, or a key it handled, at that event's `time` on the
|
|
388
|
+
// frame's clock. Built at the event, so a frame only reads it.
|
|
389
|
+
get _blink() { return this.#_blink_accessor_storage; }
|
|
390
|
+
set _blink(value) { this.#_blink_accessor_storage = value; }
|
|
376
391
|
// [LAW:single-enforcer] Every write to either half of the pair passes
|
|
377
392
|
// `graphemeBoundary`, so the cursor is a cluster boundary inside `value`
|
|
378
393
|
// whoever set it last — a caller replacing `value`, a click, an insert that
|
|
@@ -388,7 +403,7 @@ let TextInput = (() => {
|
|
|
388
403
|
}
|
|
389
404
|
get cursorPosition() { return this._cursor; }
|
|
390
405
|
set cursorPosition(p) { this._cursor = graphemeBoundary(this._value, p); }
|
|
391
|
-
#placeholder_accessor_storage = (__runInitializers(this,
|
|
406
|
+
#placeholder_accessor_storage = (__runInitializers(this, __blink_extraInitializers), __runInitializers(this, _placeholder_initializers, void 0));
|
|
392
407
|
get placeholder() { return this.#placeholder_accessor_storage; }
|
|
393
408
|
set placeholder(value) { this.#placeholder_accessor_storage = value; }
|
|
394
409
|
_maxLength = __runInitializers(this, _placeholder_extraInitializers);
|
|
@@ -468,7 +483,7 @@ let TextInput = (() => {
|
|
|
468
483
|
this._edit(event);
|
|
469
484
|
if (!event.stopped)
|
|
470
485
|
return;
|
|
471
|
-
this.
|
|
486
|
+
this._blink = caretBlink(event.time);
|
|
472
487
|
// An edit on the cursor's row moves no followed range, so the row is
|
|
473
488
|
// brought into view here too: typing after the wheel scrolled away scrolls
|
|
474
489
|
// back. The rows are the edited value's, at the width last drawn.
|
|
@@ -479,7 +494,7 @@ let TextInput = (() => {
|
|
|
479
494
|
}
|
|
480
495
|
handleFocus(event) {
|
|
481
496
|
super.handleFocus(event);
|
|
482
|
-
this.
|
|
497
|
+
this._blink = caretBlink(event.time);
|
|
483
498
|
}
|
|
484
499
|
_edit(event) {
|
|
485
500
|
if (this.disabled)
|
|
@@ -653,7 +668,7 @@ let TextInput = (() => {
|
|
|
653
668
|
return;
|
|
654
669
|
if (event.type !== "mouse_down")
|
|
655
670
|
return;
|
|
656
|
-
this.
|
|
671
|
+
this._blink = caretBlink(event.time);
|
|
657
672
|
// [LAW:no-silent-failure] Every cell the field draws carries its frame's
|
|
658
673
|
// layout, so a press without one did not come off a frame it drew.
|
|
659
674
|
const layout = layoutOn(event.cell);
|
|
@@ -1091,20 +1106,14 @@ let TextInput = (() => {
|
|
|
1091
1106
|
return { lines: withArrows, layout: { drawn, kind: "rows", rows: visualRows, offset } };
|
|
1092
1107
|
}
|
|
1093
1108
|
// The caret's cell for the frame `options` draws: the blink restarted at the
|
|
1094
|
-
// last touch,
|
|
1095
|
-
//
|
|
1096
|
-
//
|
|
1097
|
-
//
|
|
1098
|
-
// text around it, since the cursor is a
|
|
1099
|
-
//
|
|
1109
|
+
// last touch, placed as every animation is (`placed`), so it draws at the
|
|
1110
|
+
// frame's time, holds lit under reduced motion, and the cell says when it
|
|
1111
|
+
// next flips, which is when a host draws again. A print, drawn for no
|
|
1112
|
+
// moment, draws it at 0 like any placed animation. Lit, the cell is the
|
|
1113
|
+
// cursor's; dark, it is drawn as the text around it, since the cursor is a
|
|
1114
|
+
// colour pair and no attribute hides it.
|
|
1100
1115
|
_caret(at, cursorStyle, contentStyle, options) {
|
|
1101
|
-
|
|
1102
|
-
const blink = (time) => {
|
|
1103
|
-
const shown = shownAt(Timeline.run(Timeline.play(this._blinkFrom, time < this._blinkFrom ? -1 : 1), CARET_BLINK), time, options);
|
|
1104
|
-
return { lit: shown.value, hold: holdOf(shown, time) };
|
|
1105
|
-
};
|
|
1106
|
-
const { lit, hold } = frame === undefined ? CARET_UNTIMED : blink(frame.time);
|
|
1107
|
-
return stampFrame([new Segment(at, lit ? cursorStyle : contentStyle)], hold);
|
|
1116
|
+
return placed(this._blink, options, (lit) => [new Segment(at, lit ? cursorStyle : contentStyle)]);
|
|
1108
1117
|
}
|
|
1109
1118
|
// Whether `rows` visual rows draw a scroll arrow in the last cell of a row.
|
|
1110
1119
|
_drawsArrows(rows) {
|
package/dist/widgets/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* producing Segment[] from current state. They have no knowledge of stdin,
|
|
6
6
|
* terminal escape sequences, or their host environment.
|
|
7
7
|
*/
|
|
8
|
-
import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
|
|
8
|
+
import type { HostFrame, Renderable, Measurable, RenderOptions } from "../core/protocol.js";
|
|
9
9
|
import type { Segment } from "../core/segment.js";
|
|
10
10
|
import type { Anchor } from "../core/anchor.js";
|
|
11
11
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
@@ -71,6 +71,6 @@ export interface FocusManager {
|
|
|
71
71
|
export interface FrameSource {
|
|
72
72
|
readonly focusManager: FocusManager;
|
|
73
73
|
readonly frame: readonly (readonly Segment[])[];
|
|
74
|
-
|
|
74
|
+
frameNow(): HostFrame;
|
|
75
75
|
refresh(): void;
|
|
76
76
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* hear the input.
|
|
27
27
|
*/
|
|
28
28
|
import { Segment } from "../core/segment.js";
|
|
29
|
-
import type { FrameHost, Presence } from "../core/protocol.js";
|
|
29
|
+
import type { HostFrame, FrameHost, Presence } from "../core/protocol.js";
|
|
30
30
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
31
31
|
import type { Clock, FrameRate } from "../core/clock.js";
|
|
32
32
|
import type { Timeline } from "../core/timeline.js";
|
|
@@ -72,8 +72,8 @@ export declare class WidgetApp implements FrameSource, FrameHost {
|
|
|
72
72
|
private get widgets();
|
|
73
73
|
/** The rows on screen now, as painted: what a pointer event lands on. */
|
|
74
74
|
get frame(): readonly (readonly Segment[])[];
|
|
75
|
-
/** The time a frame
|
|
76
|
-
|
|
75
|
+
/** The frame this app draws now (`FrameHost`): the App's time, on a frame this app is the host of, as its frames say. */
|
|
76
|
+
frameNow(): HostFrame;
|
|
77
77
|
/**
|
|
78
78
|
* Take the terminal, paint the first frame, and route input to its widgets
|
|
79
79
|
* until the app stops — `App.run`, with the input.
|
|
@@ -50,7 +50,7 @@ export class WidgetApp {
|
|
|
50
50
|
// The view is drawn inside `compose`, where what it reads is tracked —
|
|
51
51
|
// a function view asked there too — and when it changes is its own to
|
|
52
52
|
// say, as it would be to the App.
|
|
53
|
-
// Its frames are its own, drawn for its `
|
|
53
|
+
// Its frames are its own, drawn for its `frameNow()`: what draws in them
|
|
54
54
|
// is told this app is the host, not the App it paints through, so
|
|
55
55
|
// `drawnBy: widgetApp` names the host its frames carry.
|
|
56
56
|
this.app = new App({
|
|
@@ -65,7 +65,7 @@ export class WidgetApp {
|
|
|
65
65
|
const owners = ownersOn(this.app.frame);
|
|
66
66
|
return this.widgets.filter((widget) => owners.has(widget));
|
|
67
67
|
},
|
|
68
|
-
frameTime: () => this.
|
|
68
|
+
frameTime: () => this.frameNow().time,
|
|
69
69
|
});
|
|
70
70
|
this.focusManager = this.focus;
|
|
71
71
|
this.router = new EventRouter({ source: this, focusOnClick });
|
|
@@ -118,9 +118,9 @@ export class WidgetApp {
|
|
|
118
118
|
get frame() {
|
|
119
119
|
return this.app.frame;
|
|
120
120
|
}
|
|
121
|
-
/** The time a frame
|
|
122
|
-
|
|
123
|
-
return this.app.
|
|
121
|
+
/** The frame this app draws now (`FrameHost`): the App's time, on a frame this app is the host of, as its frames say. */
|
|
122
|
+
frameNow() {
|
|
123
|
+
return { time: this.app.frameNow().time, host: this };
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Take the terminal, paint the first frame, and route input to its widgets
|