@promptctl/rich-js 0.27.0 → 0.29.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 -6
- package/THIRD-PARTY-NOTICES +42 -0
- package/dist/core/animation.d.ts +65 -46
- package/dist/core/animation.js +91 -67
- package/dist/core/ansi.d.ts +19 -12
- package/dist/core/ansi.js +114 -36
- package/dist/core/bidi-data.d.ts +14 -0
- package/dist/core/bidi-data.js +385 -0
- package/dist/core/bidi.d.ts +89 -0
- package/dist/core/bidi.js +615 -0
- package/dist/core/box.d.ts +9 -1
- package/dist/core/box.js +11 -0
- package/dist/core/cell-widths.d.ts +3 -2
- package/dist/core/cell-widths.js +93 -93
- package/dist/core/cells.d.ts +20 -0
- package/dist/core/cells.js +94 -6
- package/dist/core/clock.d.ts +1 -1
- package/dist/core/color.d.ts +56 -57
- package/dist/core/color.js +79 -81
- package/dist/core/console.d.ts +24 -7
- package/dist/core/console.js +27 -8
- package/dist/core/control-codes.d.ts +61 -0
- package/dist/core/control-codes.js +157 -0
- package/dist/core/easing.d.ts +40 -40
- package/dist/core/easing.js +40 -40
- package/dist/core/env.d.ts +6 -0
- package/dist/core/env.js +9 -1
- package/dist/core/export-html.js +5 -4
- package/dist/core/export-lines.d.ts +13 -11
- package/dist/core/export-lines.js +19 -15
- package/dist/core/export-svg.d.ts +3 -3
- package/dist/core/export-svg.js +10 -9
- package/dist/core/json.js +9 -2
- package/dist/core/markup.js +5 -4
- package/dist/core/memo.d.ts +1 -1
- package/dist/core/memo.js +1 -1
- package/dist/core/oklch.d.ts +14 -14
- package/dist/core/oklch.js +10 -10
- package/dist/core/orient.d.ts +68 -0
- package/dist/core/orient.js +224 -0
- package/dist/core/osc8.d.ts +12 -5
- package/dist/core/osc8.js +14 -7
- package/dist/core/paint.d.ts +9 -9
- package/dist/core/paint.js +3 -3
- package/dist/core/pretty.d.ts +1 -1
- package/dist/core/pretty.js +23 -19
- package/dist/core/protocol.d.ts +47 -26
- package/dist/core/protocol.js +31 -23
- package/dist/core/render.d.ts +19 -14
- package/dist/core/render.js +30 -17
- package/dist/core/seal.d.ts +26 -0
- package/dist/core/seal.js +75 -0
- package/dist/core/segment.d.ts +12 -4
- package/dist/core/segment.js +16 -6
- package/dist/core/strip.d.ts +83 -83
- package/dist/core/strip.js +70 -70
- package/dist/core/style.d.ts +46 -18
- package/dist/core/style.js +92 -56
- package/dist/core/text-order.d.ts +51 -0
- package/dist/core/text-order.js +50 -0
- package/dist/core/text.d.ts +12 -2
- package/dist/core/text.js +136 -90
- package/dist/core/timeline.d.ts +5 -5
- package/dist/core/timeline.js +11 -11
- package/dist/core/tween.d.ts +6 -6
- package/dist/core/tween.js +10 -10
- package/dist/core/view.d.ts +5 -5
- package/dist/core/view.js +15 -14
- package/dist/core/wrap.d.ts +24 -6
- package/dist/core/wrap.js +82 -16
- package/dist/host/app.d.ts +50 -9
- package/dist/host/app.js +120 -15
- package/dist/host/host-environment.d.ts +2 -2
- package/dist/host/host-environment.js +2 -2
- package/dist/host/index.d.ts +3 -2
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +42 -9
- package/dist/host/input.js +91 -7
- package/dist/host/terminal-colors.d.ts +18 -0
- package/dist/host/terminal-colors.js +46 -0
- package/dist/host/terminal-host.d.ts +4 -3
- package/dist/host/terminal-host.js +1 -1
- package/dist/index.d.ts +17 -16
- package/dist/index.js +11 -11
- package/dist/node/prompt.d.ts +1 -1
- package/dist/node/prompt.js +1 -1
- package/dist/node/terminal-host.d.ts +1 -1
- package/dist/node/traceback.js +2 -2
- package/dist/renderables/change.d.ts +1 -3
- package/dist/renderables/change.js +6 -8
- package/dist/renderables/effect.d.ts +88 -87
- package/dist/renderables/effect.js +124 -114
- package/dist/renderables/effects.d.ts +105 -76
- package/dist/renderables/effects.js +309 -176
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +2 -2
- package/dist/renderables/flexStrip.d.ts +7 -7
- package/dist/renderables/flexStrip.js +15 -15
- package/dist/renderables/frames.d.ts +7 -16
- package/dist/renderables/frames.js +12 -27
- package/dist/renderables/glyph-effect.d.ts +22 -23
- package/dist/renderables/glyph-effect.js +43 -41
- package/dist/renderables/glyph-effects.d.ts +33 -14
- package/dist/renderables/glyph-effects.js +90 -22
- package/dist/renderables/html-entities.d.ts +1 -1
- package/dist/renderables/html-entities.js +1 -1
- package/dist/renderables/lifecycle.d.ts +8 -10
- package/dist/renderables/lifecycle.js +17 -18
- package/dist/renderables/live.d.ts +2 -2
- package/dist/renderables/live.js +7 -7
- package/dist/renderables/markdown-parse.js +3 -3
- package/dist/renderables/markdown.js +4 -2
- package/dist/renderables/panel.js +7 -5
- package/dist/renderables/progress.d.ts +1 -1
- package/dist/renderables/progress.js +1 -1
- package/dist/renderables/progressBar.d.ts +3 -3
- package/dist/renderables/progressBar.js +21 -18
- package/dist/renderables/prompt.d.ts +1 -1
- package/dist/renderables/scroll.d.ts +1 -1
- package/dist/renderables/scroll.js +3 -3
- package/dist/renderables/spinner.d.ts +4 -4
- package/dist/renderables/spinner.js +10 -10
- package/dist/renderables/syntax.d.ts +2 -2
- package/dist/renderables/syntax.js +9 -4
- package/dist/renderables/table.js +5 -4
- package/dist/renderables/traceback.d.ts +1 -1
- package/dist/renderables/traceback.js +1 -1
- package/dist/renderables/tree.js +3 -3
- package/dist/template-bindings/animation-funcs.d.ts +60 -29
- package/dist/template-bindings/animation-funcs.js +126 -43
- package/dist/template-bindings/color-funcs.d.ts +14 -14
- package/dist/template-bindings/color-funcs.js +25 -25
- package/dist/template-bindings/index.d.ts +16 -14
- package/dist/template-bindings/index.js +17 -14
- package/dist/template-bindings/palette-funcs.d.ts +2 -2
- package/dist/template-bindings/palette-funcs.js +4 -4
- package/dist/template-bindings/style-funcs.d.ts +5 -5
- package/dist/template-bindings/style-funcs.js +16 -16
- package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
- package/dist/themes/{transpose.js → adjust.js} +28 -28
- package/dist/themes/buildPalette.d.ts +6 -5
- package/dist/themes/buildPalette.js +22 -22
- package/dist/themes/colorMath.d.ts +16 -16
- package/dist/themes/colorMath.js +32 -32
- package/dist/themes/data/ansi-tables.d.ts +2 -2
- package/dist/themes/data/ansi-tables.js +2 -2
- package/dist/themes/data/index.js +1 -4
- package/dist/themes/data/textual-ansi.js +0 -143
- package/dist/themes/data/types.d.ts +4 -4
- package/dist/themes/data/types.js +2 -2
- package/dist/themes/palette.d.ts +12 -12
- package/dist/themes/palette.js +16 -16
- package/dist/themes/ramp.d.ts +17 -17
- package/dist/themes/ramp.js +12 -12
- package/dist/themes/registry.d.ts +6 -8
- package/dist/themes/registry.js +6 -8
- package/dist/themes/terminalThemes.d.ts +4 -11
- package/dist/themes/terminalThemes.js +31 -47
- package/dist/widgets/button.d.ts +3 -3
- package/dist/widgets/button.js +8 -8
- package/dist/widgets/checkbox.d.ts +2 -2
- package/dist/widgets/checkbox.js +4 -4
- package/dist/widgets/dropdown.d.ts +3 -3
- package/dist/widgets/dropdown.js +7 -5
- package/dist/widgets/event-router.d.ts +6 -6
- package/dist/widgets/event-router.js +2 -2
- package/dist/widgets/focus-manager.d.ts +3 -3
- package/dist/widgets/focus-manager.js +3 -3
- package/dist/widgets/index.d.ts +2 -2
- package/dist/widgets/index.js +1 -1
- package/dist/widgets/ink.d.ts +3 -3
- package/dist/widgets/ink.js +4 -4
- package/dist/widgets/slider.d.ts +2 -2
- package/dist/widgets/static-item.d.ts +2 -2
- package/dist/widgets/text-input.d.ts +2 -2
- package/dist/widgets/text-input.js +5 -5
- package/dist/widgets/themed-widget.js +4 -4
- package/dist/widgets/toggle.d.ts +4 -4
- package/dist/widgets/toggle.js +6 -6
- package/dist/widgets/types.d.ts +6 -6
- package/dist/widgets/types.js +2 -2
- package/dist/widgets/widget-app.d.ts +10 -10
- package/dist/widgets/widget-app.js +8 -8
- package/dist/widgets/widget-base.d.ts +2 -2
- package/package.json +5 -4
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The census of code points that do not print: every one in Unicode's general
|
|
3
|
+
* categories Cc, Cf, Zl and Zp, and the variation selectors, with what `RichText`
|
|
4
|
+
* does when content carries it. [LAW:one-source-of-truth] The sanitizer
|
|
5
|
+
* (`sanitized`), the wire (`wireText`) and the cell-width measure
|
|
6
|
+
* (`cellLen`) all read this table, so whether content keeps a code point has one
|
|
7
|
+
* statement. `docs/control-codes.md` is each family's use and harm, and what real
|
|
8
|
+
* terminals were measured doing with it.
|
|
9
|
+
*
|
|
10
|
+
* A row does not carry a width. A kept code point takes the cells Rich's table
|
|
11
|
+
* gives it (`cell-widths.ts`), and a second statement of them here would be one
|
|
12
|
+
* that could drift.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* What `RichText` does with a code point. `strip` deletes it from content. `keep`
|
|
16
|
+
* holds it as a character. `line-break` is a line ending, so content holds an LF
|
|
17
|
+
* in its place. `pictured` means nothing inside a span, so content holds the
|
|
18
|
+
* stand-in `pictureOf` gives in its place and the reader sees something was there.
|
|
19
|
+
* `zeroWidth` is held in content and measured as nothing, and `wireText` decides
|
|
20
|
+
* from its neighbours whether it is written.
|
|
21
|
+
*
|
|
22
|
+
* Only `keep`, and a `zeroWidth` code point `wireText` lets by, reaches the wire. A
|
|
23
|
+
* raw `Segment` is not content, so what it holds of the others is deleted there.
|
|
24
|
+
*/
|
|
25
|
+
export type Disposition = "strip" | "keep" | "line-break" | "pictured" | "zeroWidth";
|
|
26
|
+
/**
|
|
27
|
+
* The code points `first` to `last`, inclusive, and what is done with each. A
|
|
28
|
+
* `pictured` row carries what content shows in place of each of its code points.
|
|
29
|
+
*/
|
|
30
|
+
export type ControlCodeRow = {
|
|
31
|
+
readonly first: number;
|
|
32
|
+
readonly last: number;
|
|
33
|
+
readonly disposition: Exclude<Disposition, "pictured">;
|
|
34
|
+
} | {
|
|
35
|
+
readonly first: number;
|
|
36
|
+
readonly last: number;
|
|
37
|
+
readonly disposition: "pictured";
|
|
38
|
+
readonly picture: (codePoint: number) => string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Ascending and disjoint, every Cc, Cf, Zl, Zp and Variation_Selector code point
|
|
42
|
+
* in exactly one row (`test/core/control-codes.test.ts`).
|
|
43
|
+
*
|
|
44
|
+
* Rich's `Text` strips only `STRIP_CONTROL_CODES` (BEL, BS, VT, FF, CR) and writes
|
|
45
|
+
* every other code point to the wire. Here a directive reaches the wire only
|
|
46
|
+
* through the library's own constructs: `Style`, a link, `Console.bell`, the paint
|
|
47
|
+
* layer.
|
|
48
|
+
*/
|
|
49
|
+
export declare const CONTROL_CODES: readonly ControlCodeRow[];
|
|
50
|
+
/** What content shows in place of `codePoint`, whose disposition is `pictured`. */
|
|
51
|
+
export declare function pictureOf(codePoint: number): string;
|
|
52
|
+
/** A regular expression class of the code points in rows `chosen` picks, for `u`. */
|
|
53
|
+
export declare function controlClass(chosen: (disposition: Disposition) => boolean): string;
|
|
54
|
+
/**
|
|
55
|
+
* UTS #51's subdivision flag, as a `u` source: the black flag, a CLDR subdivision
|
|
56
|
+
* spelled in tag letters and digits, and CANCEL TAG. The one sequence tag
|
|
57
|
+
* characters have a reader for.
|
|
58
|
+
*/
|
|
59
|
+
export declare const SUBDIVISION_FLAG = "\uD83C\uDFF4[\uDB40\uDC30-\uDB40\uDC39\uDB40\uDC61-\uDB40\uDC7A]{3,6}\uDB40\uDC7F";
|
|
60
|
+
/** What happens to `codePoint`. One in no row is kept. */
|
|
61
|
+
export declare function dispositionOf(codePoint: number): Disposition;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The census of code points that do not print: every one in Unicode's general
|
|
3
|
+
* categories Cc, Cf, Zl and Zp, and the variation selectors, with what `RichText`
|
|
4
|
+
* does when content carries it. [LAW:one-source-of-truth] The sanitizer
|
|
5
|
+
* (`sanitized`), the wire (`wireText`) and the cell-width measure
|
|
6
|
+
* (`cellLen`) all read this table, so whether content keeps a code point has one
|
|
7
|
+
* statement. `docs/control-codes.md` is each family's use and harm, and what real
|
|
8
|
+
* terminals were measured doing with it.
|
|
9
|
+
*
|
|
10
|
+
* A row does not carry a width. A kept code point takes the cells Rich's table
|
|
11
|
+
* gives it (`cell-widths.ts`), and a second statement of them here would be one
|
|
12
|
+
* that could drift.
|
|
13
|
+
*/
|
|
14
|
+
const strip = (first, last) => ({ first, last, disposition: "strip" });
|
|
15
|
+
const keep = (first, last) => ({ first, last, disposition: "keep" });
|
|
16
|
+
const lineBreak = (first, last) => ({ first, last, disposition: "line-break" });
|
|
17
|
+
const pictured = (first, last, picture) => ({ first, last, disposition: "pictured", picture });
|
|
18
|
+
/**
|
|
19
|
+
* The stand-ins. A C0 control's Control Pictures symbol is U+2400 up, DEL's is
|
|
20
|
+
* U+2421. Unicode gives C1 no pictures, so each shows U+2426 SYMBOL FOR SUBSTITUTE:
|
|
21
|
+
* one cell under every East Asian width setting, which U+FFFD is not, and apart
|
|
22
|
+
* from a real decoding error. Each is one code unit, so offsets hold.
|
|
23
|
+
*/
|
|
24
|
+
const controlPicture = (codePoint) => String.fromCharCode(0x2400 + codePoint);
|
|
25
|
+
const deletePicture = () => "\u2421";
|
|
26
|
+
const substitute = () => "\u2426";
|
|
27
|
+
const zeroWidth = (first, last) => ({ first, last, disposition: "zeroWidth" });
|
|
28
|
+
/**
|
|
29
|
+
* Ascending and disjoint, every Cc, Cf, Zl, Zp and Variation_Selector code point
|
|
30
|
+
* in exactly one row (`test/core/control-codes.test.ts`).
|
|
31
|
+
*
|
|
32
|
+
* Rich's `Text` strips only `STRIP_CONTROL_CODES` (BEL, BS, VT, FF, CR) and writes
|
|
33
|
+
* every other code point to the wire. Here a directive reaches the wire only
|
|
34
|
+
* through the library's own constructs: `Style`, a link, `Console.bell`, the paint
|
|
35
|
+
* layer.
|
|
36
|
+
*/
|
|
37
|
+
export const CONTROL_CODES = [
|
|
38
|
+
// NUL to BS. BEL's alert is `Console.bell`, and BS's overstrike, bold and
|
|
39
|
+
// underline in nroff output, is `decodeAnsi`: taken a code point at a time, text
|
|
40
|
+
// can turn neither into what it means.
|
|
41
|
+
pictured(0x00, 0x08, controlPicture),
|
|
42
|
+
keep(0x09, 0x0a),
|
|
43
|
+
// VT and FF, mandatory breaks in UAX #14 as LS and PS are.
|
|
44
|
+
lineBreak(0x0b, 0x0c),
|
|
45
|
+
// CR. A CRLF's LF ends its line however the two were chunked, and a CR's
|
|
46
|
+
// overwrite is `decodeAnsi`'s. What is given up is a classic Mac file's lines.
|
|
47
|
+
strip(0x0d, 0x0d),
|
|
48
|
+
// SO and SI switch the terminal's character set; DLE to SUB are transmission
|
|
49
|
+
// controls, and CAN and SUB abort a sequence; ESC begins one, and content that
|
|
50
|
+
// means styling says so with `decodeAnsi`; FS to US are data separators.
|
|
51
|
+
pictured(0x0e, 0x1f, controlPicture),
|
|
52
|
+
// DEL.
|
|
53
|
+
pictured(0x7f, 0x7f, deletePicture),
|
|
54
|
+
// The C1 controls. VTE, WezTerm and xterm.js read U+009B as CSI and U+009D as
|
|
55
|
+
// OSC; xterm, kitty and others ignore them. None has a meaning in text but NEL,
|
|
56
|
+
// which Unicode treats as CR, LF and CRLF are treated (§5.8). A stray one is
|
|
57
|
+
// often windows-1252 decoded as Latin-1, but which, a code point alone cannot
|
|
58
|
+
// say, so mojibake is the caller's to repair. `TextInput` refuses them as keys.
|
|
59
|
+
pictured(0x80, 0x84, substitute),
|
|
60
|
+
lineBreak(0x85, 0x85),
|
|
61
|
+
pictured(0x86, 0x9f, substitute),
|
|
62
|
+
// SOFT HYPHEN: a place a word may break, drawn as a hyphen only where one does.
|
|
63
|
+
// Terminals disagree on its cell, so it never reaches them.
|
|
64
|
+
zeroWidth(0xad, 0xad),
|
|
65
|
+
// The Arabic and Syriac number signs and other prepended concatenation marks,
|
|
66
|
+
// which draw a glyph.
|
|
67
|
+
keep(0x600, 0x605),
|
|
68
|
+
// ARABIC LETTER MARK, a bidi mark like LRM and RLM below: it holds no state,
|
|
69
|
+
// so right-to-left text can use it.
|
|
70
|
+
keep(0x61c, 0x61c),
|
|
71
|
+
// More prepended concatenation marks.
|
|
72
|
+
keep(0x6dd, 0x6dd),
|
|
73
|
+
keep(0x70f, 0x70f),
|
|
74
|
+
keep(0x890, 0x891),
|
|
75
|
+
keep(0x8e2, 0x8e2),
|
|
76
|
+
// The Mongolian free variation selectors.
|
|
77
|
+
zeroWidth(0x180b, 0x180d),
|
|
78
|
+
// MONGOLIAN VOWEL SEPARATOR, which shapes the vowel after it.
|
|
79
|
+
keep(0x180e, 0x180e),
|
|
80
|
+
zeroWidth(0x180f, 0x180f),
|
|
81
|
+
// ZWSP, a place a line may break (`wrap.ts`); ZWNJ, which Persian and Urdu spell
|
|
82
|
+
// with; ZWJ, for emoji and conjuncts; and the bidi marks LRM and RLM, which hold
|
|
83
|
+
// no state, so right-to-left text can use them. ZWJ's joining is Rich's width
|
|
84
|
+
// rule, which `cells.ts` holds apart from this row.
|
|
85
|
+
keep(0x200b, 0x200f),
|
|
86
|
+
// LINE SEPARATOR and PARAGRAPH SEPARATOR.
|
|
87
|
+
lineBreak(0x2028, 0x2029),
|
|
88
|
+
// The bidi embeddings and overrides with their closer PDF, and the isolates
|
|
89
|
+
// below. Content holds them; what reaches the wire is `sealed`'s to decide.
|
|
90
|
+
keep(0x202a, 0x202e),
|
|
91
|
+
// WORD JOINER, which only asks that nothing break here, and the invisible
|
|
92
|
+
// mathematical operators.
|
|
93
|
+
keep(0x2060, 0x2064),
|
|
94
|
+
// The bidi isolates with their closer PDI.
|
|
95
|
+
keep(0x2066, 0x2069),
|
|
96
|
+
// The deprecated shaping and swapping switches. Each holds state to the end of
|
|
97
|
+
// the text, Unicode deprecates them, and no terminal was found honouring one.
|
|
98
|
+
strip(0x206a, 0x206f),
|
|
99
|
+
// VARIATION SELECTOR-1 to 16: glyph variants, and text or emoji presentation.
|
|
100
|
+
zeroWidth(0xfe00, 0xfe0f),
|
|
101
|
+
// ZERO WIDTH NO-BREAK SPACE, the byte order mark, as a word joiner.
|
|
102
|
+
keep(0xfeff, 0xfeff),
|
|
103
|
+
// Interlinear annotation. No terminal draws ruby, the annotating text stays
|
|
104
|
+
// visible, and the anchors hold no state, so there is nothing to contain.
|
|
105
|
+
keep(0xfff9, 0xfffb),
|
|
106
|
+
// The Kaithi number signs, which draw a glyph.
|
|
107
|
+
keep(0x110bd, 0x110bd),
|
|
108
|
+
keep(0x110cd, 0x110cd),
|
|
109
|
+
// Egyptian hieroglyph, shorthand and musical format controls.
|
|
110
|
+
keep(0x13430, 0x1343f),
|
|
111
|
+
keep(0x1bca0, 0x1bca3),
|
|
112
|
+
keep(0x1d173, 0x1d17a),
|
|
113
|
+
// LANGUAGE TAG, deprecated.
|
|
114
|
+
strip(0xe0001, 0xe0001),
|
|
115
|
+
// The tag characters: an emoji subdivision flag, or text no reader can see.
|
|
116
|
+
zeroWidth(0xe0020, 0xe007f),
|
|
117
|
+
// The ideographic variation selectors: Japanese and Chinese glyph variants.
|
|
118
|
+
zeroWidth(0xe0100, 0xe01ef),
|
|
119
|
+
];
|
|
120
|
+
/** What content shows in place of `codePoint`, whose disposition is `pictured`. */
|
|
121
|
+
export function pictureOf(codePoint) {
|
|
122
|
+
const row = rowOf(codePoint);
|
|
123
|
+
if (row?.disposition !== "pictured")
|
|
124
|
+
throw new RangeError(`U+${codePoint.toString(16).padStart(4, "0")} is not pictured`);
|
|
125
|
+
return row.picture(codePoint);
|
|
126
|
+
}
|
|
127
|
+
/** A regular expression class of the code points in rows `chosen` picks, for `u`. */
|
|
128
|
+
export function controlClass(chosen) {
|
|
129
|
+
const hex = (codePoint) => `\\u{${codePoint.toString(16)}}`;
|
|
130
|
+
return `[${CONTROL_CODES.filter((row) => chosen(row.disposition)).map((row) => `${hex(row.first)}-${hex(row.last)}`).join("")}]`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* UTS #51's subdivision flag, as a `u` source: the black flag, a CLDR subdivision
|
|
134
|
+
* spelled in tag letters and digits, and CANCEL TAG. The one sequence tag
|
|
135
|
+
* characters have a reader for.
|
|
136
|
+
*/
|
|
137
|
+
export const SUBDIVISION_FLAG = "\u{1f3f4}[\u{e0030}-\u{e0039}\u{e0061}-\u{e007a}]{3,6}\u{e007f}";
|
|
138
|
+
/** What happens to `codePoint`. One in no row is kept. */
|
|
139
|
+
export function dispositionOf(codePoint) {
|
|
140
|
+
return rowOf(codePoint)?.disposition ?? "keep";
|
|
141
|
+
}
|
|
142
|
+
/** The row holding `codePoint`, if any. */
|
|
143
|
+
function rowOf(codePoint) {
|
|
144
|
+
let low = 0;
|
|
145
|
+
let high = CONTROL_CODES.length - 1;
|
|
146
|
+
while (low <= high) {
|
|
147
|
+
const mid = (low + high) >> 1;
|
|
148
|
+
const row = CONTROL_CODES[mid];
|
|
149
|
+
if (codePoint < row.first)
|
|
150
|
+
high = mid - 1;
|
|
151
|
+
else if (codePoint > row.last)
|
|
152
|
+
low = mid + 1;
|
|
153
|
+
else
|
|
154
|
+
return row;
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
package/dist/core/easing.d.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* `elastic`, Robert Penner's curves at the constants every animation
|
|
23
23
|
* library since has shipped. An ease that leaves [0, 1] — a spring or a
|
|
24
24
|
* back curve overshooting its rest — is still an ease: a `ColorRamp` holds
|
|
25
|
-
* its end
|
|
25
|
+
* its end colors where it does, and an effect's `Curve` saturates at its
|
|
26
26
|
* swing, so the overshoot is read by what can show it (a position, a
|
|
27
27
|
* count) and clipped by what cannot.
|
|
28
28
|
*
|
|
@@ -33,15 +33,15 @@
|
|
|
33
33
|
* [LAW:one-type-per-behavior] An ease is a plain function value. CSS's named
|
|
34
34
|
* curves are four instances of `cubicBezier`, not four implementations, the
|
|
35
35
|
* spring in `EASES` is one `spring()`, and `ColorRamp` and every effect take
|
|
36
|
-
* the same `
|
|
36
|
+
* the same `Easing`.
|
|
37
37
|
*
|
|
38
38
|
* Tier 0 of `src/core/`: imports nothing, so `themes/` and every later
|
|
39
39
|
* `core/` module reach it downhill. [LAW:one-way-deps]
|
|
40
40
|
*/
|
|
41
41
|
/** Progress in [0, 1] in, progress out: a reshaping of [0, 1] that may leave it, as a spring overshooting its rest does. */
|
|
42
|
-
export type
|
|
42
|
+
export type Easing = (x: number) => number;
|
|
43
43
|
/** Time in seconds (plus any per-cell offset) in, progress in [0, 1] out. */
|
|
44
|
-
export type
|
|
44
|
+
export type WrapMode = (t: number) => number;
|
|
45
45
|
/**
|
|
46
46
|
* CSS `cubic-bezier(x1, y1, x2, y2)`: the curve from (0, 0) to (1, 1) with
|
|
47
47
|
* those two control points, read as y at a given x. `x1` and `x2` must lie in
|
|
@@ -49,7 +49,7 @@ export type Phase = (t: number) => number;
|
|
|
49
49
|
* every input has exactly one output. `y1` and `y2` may leave [0, 1]; the
|
|
50
50
|
* curve then overshoots, as a CSS "back" curve does.
|
|
51
51
|
*/
|
|
52
|
-
export declare function cubicBezier(x1: number, y1: number, x2: number, y2: number):
|
|
52
|
+
export declare function cubicBezier(x1: number, y1: number, x2: number, y2: number): Easing;
|
|
53
53
|
/**
|
|
54
54
|
* Where a `steps()` curve jumps, in CSS's terms. `jump-start` jumps at 0,
|
|
55
55
|
* `jump-end` at 1, `jump-both` at both, `jump-none` at neither; `start` and
|
|
@@ -62,11 +62,11 @@ export type StepPosition = "jump-start" | "jump-end" | "jump-none" | "jump-both"
|
|
|
62
62
|
* `position` names — CSS's step algorithm, so `steps(1, "end")` is 0 until
|
|
63
63
|
* the very end.
|
|
64
64
|
*/
|
|
65
|
-
export declare function steps(n: number, position?: StepPosition):
|
|
65
|
+
export declare function steps(n: number, position?: StepPosition): Easing;
|
|
66
66
|
/**
|
|
67
67
|
* The curve `shape` over [0, 1) as an ease that has arrived: its argument
|
|
68
68
|
* held to [0, 1], and exactly 1 at 1. Every built-in ease is one, so the two
|
|
69
|
-
* halves of the `
|
|
69
|
+
* halves of the `Easing` contract — an argument in [0, 1], the end landed on —
|
|
70
70
|
* are enforced here and nowhere else. [LAW:single-enforcer] The end matters
|
|
71
71
|
* because a curve is 1 at its end only in the limit or up to a rounding — a
|
|
72
72
|
* spring settles to within `SPRING_REST`, the elastic's ringing never quite
|
|
@@ -74,7 +74,7 @@ export declare function steps(n: number, position?: StepPosition): Ease;
|
|
|
74
74
|
* and a count or a width eased by it must land on its target, not a
|
|
75
75
|
* thousandth or an ulp short.
|
|
76
76
|
*/
|
|
77
|
-
export declare const
|
|
77
|
+
export declare const withSettlingTime: (shape: (p: number) => number) => Easing;
|
|
78
78
|
/**
|
|
79
79
|
* A spring's physics: the mass on it, the stiffness of its coil and the
|
|
80
80
|
* damping it moves against, in the units every animation library spells them
|
|
@@ -93,19 +93,19 @@ export interface SpringOptions {
|
|
|
93
93
|
* An ease over a duration: CSS's timing function and duration as one value,
|
|
94
94
|
* the whole of what a one-shot move needs to know about time — a tween's
|
|
95
95
|
* (`./tween.ts`), a `spring()`'s, and the part of an effect's `Curve` that
|
|
96
|
-
* is not its swing. `
|
|
96
|
+
* is not its swing. `WrapMode.once(start, seconds)` through `ease` is the move
|
|
97
97
|
* on a timeline. [LAW:one-type-per-behavior] One shape, so a spring is handed
|
|
98
98
|
* to a tween as it is, and a curve written for an effect times a tween.
|
|
99
99
|
*/
|
|
100
100
|
export interface Timing {
|
|
101
101
|
/** How the move is shaped, as progress in to progress out. */
|
|
102
|
-
readonly ease:
|
|
102
|
+
readonly ease: Easing;
|
|
103
103
|
/** How long the move takes, in seconds. */
|
|
104
104
|
readonly seconds: number;
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
107
|
* How close to its rest a spring must come to count as settled: one part in a
|
|
108
|
-
* thousand of the way it moves, under a
|
|
108
|
+
* thousand of the way it moves, under a color channel's step (1/255) and
|
|
109
109
|
* under any cell, so what rounds the spring's value to show it draws the rest
|
|
110
110
|
* from there on.
|
|
111
111
|
*/
|
|
@@ -137,28 +137,28 @@ export declare function spring(options?: SpringOptions): Timing;
|
|
|
137
137
|
* `seconds` are `DEFAULT_SPRING`'s; the rest are Penner's at his constants.
|
|
138
138
|
*/
|
|
139
139
|
export declare const EASES: {
|
|
140
|
-
readonly linear:
|
|
141
|
-
readonly ease:
|
|
142
|
-
readonly "ease-in":
|
|
143
|
-
readonly "ease-out":
|
|
144
|
-
readonly "ease-in-out":
|
|
145
|
-
readonly "step-start":
|
|
146
|
-
readonly "step-end":
|
|
147
|
-
readonly step:
|
|
148
|
-
readonly sine:
|
|
149
|
-
readonly spring:
|
|
150
|
-
readonly bounce:
|
|
151
|
-
readonly "back-in":
|
|
152
|
-
readonly "back-out":
|
|
153
|
-
readonly elastic:
|
|
140
|
+
readonly linear: Easing;
|
|
141
|
+
readonly ease: Easing;
|
|
142
|
+
readonly "ease-in": Easing;
|
|
143
|
+
readonly "ease-out": Easing;
|
|
144
|
+
readonly "ease-in-out": Easing;
|
|
145
|
+
readonly "step-start": Easing;
|
|
146
|
+
readonly "step-end": Easing;
|
|
147
|
+
readonly step: Easing;
|
|
148
|
+
readonly sine: Easing;
|
|
149
|
+
readonly spring: Easing;
|
|
150
|
+
readonly bounce: Easing;
|
|
151
|
+
readonly "back-in": Easing;
|
|
152
|
+
readonly "back-out": Easing;
|
|
153
|
+
readonly elastic: Easing;
|
|
154
154
|
};
|
|
155
|
-
export type
|
|
155
|
+
export type EasingName = keyof typeof EASES;
|
|
156
156
|
/**
|
|
157
157
|
* The gate a spelled ease crosses. [LAW:parse-dont-validate] — a name in, the
|
|
158
158
|
* function out, so nothing downstream holds a string it must check again.
|
|
159
159
|
* Unknown names throw naming every legal one. [LAW:no-silent-failure]
|
|
160
160
|
*/
|
|
161
|
-
export declare function
|
|
161
|
+
export declare function parseEasing(name: string): Easing;
|
|
162
162
|
/** Throws, naming `what`, unless `seconds` is a positive, finite number of seconds. */
|
|
163
163
|
export declare function positiveSeconds(what: string, seconds: number): void;
|
|
164
164
|
/**
|
|
@@ -166,11 +166,11 @@ export declare function positiveSeconds(what: string, seconds: number): void;
|
|
|
166
166
|
* way the frames of an animation are each held and then replaced. `at(t)` is
|
|
167
167
|
* the index of the hold in progress at `t`, counted from the first hold at
|
|
168
168
|
* `t = 0`, and the sequence wraps every `period` seconds, before zero too,
|
|
169
|
-
* as `
|
|
169
|
+
* as `WrapMode.loop` wraps. With equal holds `at` is `steps(n)` read as an
|
|
170
170
|
* index; the holds here may differ, which `steps` cannot say, so a frame
|
|
171
171
|
* held for a second and the next for a quarter are one beat.
|
|
172
172
|
*/
|
|
173
|
-
export interface
|
|
173
|
+
export interface StepSequence {
|
|
174
174
|
readonly holds: readonly number[];
|
|
175
175
|
/** The sum of the holds: how long one pass takes, in seconds. */
|
|
176
176
|
readonly period: number;
|
|
@@ -180,10 +180,10 @@ export interface Beat {
|
|
|
180
180
|
* When the hold in progress at `t` began, in seconds on `t`'s own
|
|
181
181
|
* timeline: what a sample-and-hold on this beat reads at `t`. Every `t`
|
|
182
182
|
* inside one hold of one pass answers the same number, to the bit, so an
|
|
183
|
-
* effect handed it draws the same frame throughout. With `
|
|
183
|
+
* effect handed it draws the same frame throughout. With `validUntil`,
|
|
184
184
|
* the two ends of the hold, as every `Animation` answers them.
|
|
185
185
|
*/
|
|
186
|
-
|
|
186
|
+
validFrom(t: number): number;
|
|
187
187
|
/**
|
|
188
188
|
* When the hold in progress at `t` ends, in seconds on `t`'s own timeline:
|
|
189
189
|
* the start of the next hold, the first moment `at` places in it, so it is
|
|
@@ -191,9 +191,9 @@ export interface Beat {
|
|
|
191
191
|
* With `at`, this makes a beat an `Animation` of the hold in progress
|
|
192
192
|
* (`./animation.ts`).
|
|
193
193
|
*/
|
|
194
|
-
|
|
194
|
+
validUntil(t: number): number;
|
|
195
195
|
/** The beat with its motion taken out: its first hold, held for good, as a loop holds its first value. */
|
|
196
|
-
reduced():
|
|
196
|
+
reduced(): StepSequence;
|
|
197
197
|
}
|
|
198
198
|
/**
|
|
199
199
|
* `t`, unless it is not a finite number of seconds, which throws naming
|
|
@@ -234,14 +234,14 @@ export declare function walkUp(sum: number, reached: (x: number) => boolean, fin
|
|
|
234
234
|
* exact to the float and the cost is logarithmic in that distance.
|
|
235
235
|
*/
|
|
236
236
|
export declare function firstReaching(near: number, reached: (x: number) => boolean): number;
|
|
237
|
-
/** `holds` as a `
|
|
238
|
-
export declare function
|
|
239
|
-
/** The three phase shapes. Each takes seconds and returns a `
|
|
240
|
-
export declare const
|
|
237
|
+
/** `holds` as a `StepSequence`; a beat with no hold, or a hold that is not a positive number of seconds, throws. */
|
|
238
|
+
export declare function stepSequence(holds: readonly number[]): StepSequence;
|
|
239
|
+
/** The three phase shapes. Each takes seconds and returns a `WrapMode`. */
|
|
240
|
+
export declare const WrapMode: {
|
|
241
241
|
/** 0 before `start`, rising to 1 over `duration` seconds, then held at 1. */
|
|
242
|
-
once(start: number, duration: number):
|
|
242
|
+
once(start: number, duration: number): WrapMode;
|
|
243
243
|
/** 0 → 1 every `period` seconds, wrapping back to 0; negative `t` wraps too. */
|
|
244
|
-
loop(period: number):
|
|
244
|
+
loop(period: number): WrapMode;
|
|
245
245
|
/** 0 → 1 → 0 every `period` seconds: there in the first half, back in the second. */
|
|
246
|
-
pingPong(period: number):
|
|
246
|
+
pingPong(period: number): WrapMode;
|
|
247
247
|
};
|
package/dist/core/easing.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* `elastic`, Robert Penner's curves at the constants every animation
|
|
23
23
|
* library since has shipped. An ease that leaves [0, 1] — a spring or a
|
|
24
24
|
* back curve overshooting its rest — is still an ease: a `ColorRamp` holds
|
|
25
|
-
* its end
|
|
25
|
+
* its end colors where it does, and an effect's `Curve` saturates at its
|
|
26
26
|
* swing, so the overshoot is read by what can show it (a position, a
|
|
27
27
|
* count) and clipped by what cannot.
|
|
28
28
|
*
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* [LAW:one-type-per-behavior] An ease is a plain function value. CSS's named
|
|
34
34
|
* curves are four instances of `cubicBezier`, not four implementations, the
|
|
35
35
|
* spring in `EASES` is one `spring()`, and `ColorRamp` and every effect take
|
|
36
|
-
* the same `
|
|
36
|
+
* the same `Easing`.
|
|
37
37
|
*
|
|
38
38
|
* Tier 0 of `src/core/`: imports nothing, so `themes/` and every later
|
|
39
39
|
* `core/` module reach it downhill. [LAW:one-way-deps]
|
|
@@ -91,7 +91,7 @@ export function cubicBezier(x1, y1, x2, y2) {
|
|
|
91
91
|
}
|
|
92
92
|
return s;
|
|
93
93
|
};
|
|
94
|
-
return
|
|
94
|
+
return withSettlingTime((p) => yAt(solve(p)));
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* CSS `steps(n, position)`: progress held flat in `n` equal intervals, jumping
|
|
@@ -115,12 +115,12 @@ export function steps(n, position = "jump-end") {
|
|
|
115
115
|
"jump-none": n - 1,
|
|
116
116
|
}[position];
|
|
117
117
|
const lift = jumpsAtStart ? 1 : 0;
|
|
118
|
-
return
|
|
118
|
+
return withSettlingTime((p) => Math.min(jumps, Math.floor(p * n) + lift) / jumps);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
121
|
* The curve `shape` over [0, 1) as an ease that has arrived: its argument
|
|
122
122
|
* held to [0, 1], and exactly 1 at 1. Every built-in ease is one, so the two
|
|
123
|
-
* halves of the `
|
|
123
|
+
* halves of the `Easing` contract — an argument in [0, 1], the end landed on —
|
|
124
124
|
* are enforced here and nowhere else. [LAW:single-enforcer] The end matters
|
|
125
125
|
* because a curve is 1 at its end only in the limit or up to a rounding — a
|
|
126
126
|
* spring settles to within `SPRING_REST`, the elastic's ringing never quite
|
|
@@ -128,19 +128,19 @@ export function steps(n, position = "jump-end") {
|
|
|
128
128
|
* and a count or a width eased by it must land on its target, not a
|
|
129
129
|
* thousandth or an ulp short.
|
|
130
130
|
*/
|
|
131
|
-
export const
|
|
131
|
+
export const withSettlingTime = (shape) => (x) => {
|
|
132
132
|
const p = Math.min(1, Math.max(0, x));
|
|
133
133
|
return p === 1 ? 1 : shape(p);
|
|
134
134
|
};
|
|
135
135
|
/** The identity ease: progress unchanged. */
|
|
136
|
-
const linear =
|
|
136
|
+
const linear = withSettlingTime((p) => p);
|
|
137
137
|
/** CSS `step-end`: 0 until the very end. */
|
|
138
138
|
const stepEnd = steps(1, "jump-end");
|
|
139
139
|
/** A half-cosine, flat at both ends: the curve a breathing pulse wants. */
|
|
140
|
-
const sine =
|
|
140
|
+
const sine = withSettlingTime((p) => (1 - Math.cos(Math.PI * p)) / 2);
|
|
141
141
|
/**
|
|
142
142
|
* How close to its rest a spring must come to count as settled: one part in a
|
|
143
|
-
* thousand of the way it moves, under a
|
|
143
|
+
* thousand of the way it moves, under a color channel's step (1/255) and
|
|
144
144
|
* under any cell, so what rounds the spring's value to show it draws the rest
|
|
145
145
|
* from there on.
|
|
146
146
|
*/
|
|
@@ -171,7 +171,7 @@ export function spring(options = {}) {
|
|
|
171
171
|
const zeta = damping / (2 * Math.sqrt(stiffness * mass));
|
|
172
172
|
const decay = zeta * w0;
|
|
173
173
|
const { displacement, seconds } = zeta < 1 ? ringing(w0, zeta, decay) : creeping(w0, zeta, decay);
|
|
174
|
-
return { seconds, ease:
|
|
174
|
+
return { seconds, ease: withSettlingTime((p) => 1 - displacement(p * seconds)) };
|
|
175
175
|
}
|
|
176
176
|
/**
|
|
177
177
|
* Where `|displacement|` falls through `SPRING_REST` between `lo` and `hi`,
|
|
@@ -258,7 +258,7 @@ const BOUNCE_ARCS = [
|
|
|
258
258
|
{ until: 2.5 / 2.75, centre: 2.25 / 2.75, floor: 0.9375 },
|
|
259
259
|
{ until: Number.POSITIVE_INFINITY, centre: 2.625 / 2.75, floor: 0.984375 },
|
|
260
260
|
];
|
|
261
|
-
const bounce =
|
|
261
|
+
const bounce = withSettlingTime((p) => {
|
|
262
262
|
// The last arc's `until` is unbounded, so an arc is always found.
|
|
263
263
|
const arc = BOUNCE_ARCS.find(({ until }) => p < until);
|
|
264
264
|
return 7.5625 * (p - arc.centre) ** 2 + arc.floor;
|
|
@@ -272,8 +272,8 @@ const bounce = settled((p) => {
|
|
|
272
272
|
* and lands on 1 to the bit.
|
|
273
273
|
*/
|
|
274
274
|
const BACK_OVERSHOOT = 1.70158;
|
|
275
|
-
const backIn =
|
|
276
|
-
const backOut =
|
|
275
|
+
const backIn = withSettlingTime((p) => p ** 3 + BACK_OVERSHOOT * p ** 2 * (p - 1));
|
|
276
|
+
const backOut = withSettlingTime((p) => {
|
|
277
277
|
const q = p - 1;
|
|
278
278
|
return 1 + q ** 3 + BACK_OVERSHOOT * q ** 2 * (q + 1);
|
|
279
279
|
});
|
|
@@ -284,7 +284,7 @@ const backOut = settled((p) => {
|
|
|
284
284
|
* last — `2^(−10x)·sin((10x − 0.75)·2π/3) + 1`.
|
|
285
285
|
*/
|
|
286
286
|
const ELASTIC_PERIOD = (2 * Math.PI) / 3;
|
|
287
|
-
const elastic =
|
|
287
|
+
const elastic = withSettlingTime((p) => 2 ** (-10 * p) * Math.sin((10 * p - 0.75) * ELASTIC_PERIOD) + 1);
|
|
288
288
|
/**
|
|
289
289
|
* Every built-in ease by the name a template spells it with — CSS's keyword
|
|
290
290
|
* names, plus `sine`, plus `step`: the spelling `ColorRamp` used before this
|
|
@@ -314,7 +314,7 @@ export const EASES = {
|
|
|
314
314
|
* function out, so nothing downstream holds a string it must check again.
|
|
315
315
|
* Unknown names throw naming every legal one. [LAW:no-silent-failure]
|
|
316
316
|
*/
|
|
317
|
-
export function
|
|
317
|
+
export function parseEasing(name) {
|
|
318
318
|
if (!Object.hasOwn(EASES, name)) {
|
|
319
319
|
throw new RangeError(`unknown ease ${JSON.stringify(name)}; expected one of ` +
|
|
320
320
|
Object.keys(EASES).map((n) => JSON.stringify(n)).join(", "));
|
|
@@ -335,8 +335,8 @@ const STILL = {
|
|
|
335
335
|
holds: [Number.POSITIVE_INFINITY],
|
|
336
336
|
period: Number.POSITIVE_INFINITY,
|
|
337
337
|
at: () => 0,
|
|
338
|
-
|
|
339
|
-
|
|
338
|
+
validFrom: () => Number.NEGATIVE_INFINITY,
|
|
339
|
+
validUntil: () => Number.POSITIVE_INFINITY,
|
|
340
340
|
reduced: () => STILL,
|
|
341
341
|
};
|
|
342
342
|
/**
|
|
@@ -352,7 +352,7 @@ export function finiteTime(what, t) {
|
|
|
352
352
|
/**
|
|
353
353
|
* The seconds into the current pass of a `period` at `t`: `t` taken modulo
|
|
354
354
|
* the period, into [0, period), before zero too. [LAW:single-enforcer] The
|
|
355
|
-
* one wrap `
|
|
355
|
+
* one wrap `WrapMode.loop` and `beat` both read time through, so a `t` that is
|
|
356
356
|
* not a finite number of seconds fails here, loudly, and nowhere else. A
|
|
357
357
|
* `t` at or past zero is `t % period` alone, which is exact; only a negative
|
|
358
358
|
* `t` is carried up by a period, so a boundary a host samples exactly lands
|
|
@@ -474,21 +474,21 @@ export function firstReaching(near, reached) {
|
|
|
474
474
|
lo = mid;
|
|
475
475
|
}
|
|
476
476
|
}
|
|
477
|
-
/** `holds` as a `
|
|
478
|
-
export function
|
|
477
|
+
/** `holds` as a `StepSequence`; a beat with no hold, or a hold that is not a positive number of seconds, throws. */
|
|
478
|
+
export function stepSequence(holds) {
|
|
479
479
|
if (holds.length === 0)
|
|
480
|
-
throw new RangeError("a
|
|
481
|
-
holds.forEach((
|
|
482
|
-
const period = holds.reduce((sum,
|
|
480
|
+
throw new RangeError("a step sequence needs at least one step");
|
|
481
|
+
holds.forEach((validity, i) => positiveSeconds(`step ${i}`, validity));
|
|
482
|
+
const period = holds.reduce((sum, validity) => sum + validity, 0);
|
|
483
483
|
// Where each hold begins, in seconds into the period: the unit
|
|
484
484
|
// `wrapSeconds` answers in, so the sum a boundary sits at is the number
|
|
485
485
|
// the wrap of a `t` on that boundary produces, and the hold that begins
|
|
486
486
|
// there is the one in progress, at any rate the host samples.
|
|
487
487
|
const starts = [];
|
|
488
488
|
let elapsed = 0;
|
|
489
|
-
for (const
|
|
489
|
+
for (const validity of holds) {
|
|
490
490
|
starts.push(elapsed);
|
|
491
|
-
elapsed +=
|
|
491
|
+
elapsed += validity;
|
|
492
492
|
}
|
|
493
493
|
// A copy, and the one `at` walks: what `at` and `period` were built from
|
|
494
494
|
// stays what `holds` says whatever the caller does to its array.
|
|
@@ -520,40 +520,40 @@ export function beat(holds) {
|
|
|
520
520
|
holds: own,
|
|
521
521
|
period,
|
|
522
522
|
at(t) {
|
|
523
|
-
return index(wrapSeconds("
|
|
523
|
+
return index(wrapSeconds("StepSequence.at", t, period));
|
|
524
524
|
},
|
|
525
|
-
|
|
526
|
-
const { pass, into } = passAt("
|
|
527
|
-
return boundary("
|
|
525
|
+
validFrom(t) {
|
|
526
|
+
const { pass, into } = passAt("StepSequence.validFrom", t, period);
|
|
527
|
+
return boundary("StepSequence.validFrom", pass, index(into), t);
|
|
528
528
|
},
|
|
529
529
|
// The next hold's start, in the next pass when this hold is the last.
|
|
530
|
-
|
|
531
|
-
const { pass, into } = passAt("
|
|
530
|
+
validUntil(t) {
|
|
531
|
+
const { pass, into } = passAt("StepSequence.validUntil", t, period);
|
|
532
532
|
const i = index(into);
|
|
533
533
|
const last = i === own.length - 1;
|
|
534
|
-
return boundary("
|
|
534
|
+
return boundary("StepSequence.validUntil", pass + (last ? 1 : 0), last ? 0 : i + 1, t);
|
|
535
535
|
},
|
|
536
536
|
reduced: () => STILL,
|
|
537
537
|
};
|
|
538
538
|
}
|
|
539
|
-
/** The three phase shapes. Each takes seconds and returns a `
|
|
540
|
-
export const
|
|
539
|
+
/** The three phase shapes. Each takes seconds and returns a `WrapMode`. */
|
|
540
|
+
export const WrapMode = {
|
|
541
541
|
/** 0 before `start`, rising to 1 over `duration` seconds, then held at 1. */
|
|
542
542
|
once(start, duration) {
|
|
543
543
|
if (!Number.isFinite(start))
|
|
544
|
-
throw new RangeError(`
|
|
545
|
-
positiveSeconds("
|
|
544
|
+
throw new RangeError(`WrapMode.once start must be finite, got ${start}`);
|
|
545
|
+
positiveSeconds("WrapMode.once duration", duration);
|
|
546
546
|
return (t) => Math.min(1, Math.max(0, (t - start) / duration));
|
|
547
547
|
},
|
|
548
548
|
/** 0 → 1 every `period` seconds, wrapping back to 0; negative `t` wraps too. */
|
|
549
549
|
loop(period) {
|
|
550
|
-
positiveSeconds("
|
|
551
|
-
return (t) => wrapSeconds("
|
|
550
|
+
positiveSeconds("WrapMode.loop period", period);
|
|
551
|
+
return (t) => wrapSeconds("WrapMode.loop", t, period) / period;
|
|
552
552
|
},
|
|
553
553
|
/** 0 → 1 → 0 every `period` seconds: there in the first half, back in the second. */
|
|
554
554
|
pingPong(period) {
|
|
555
|
-
positiveSeconds("
|
|
556
|
-
const wrap =
|
|
555
|
+
positiveSeconds("WrapMode.pingPong period", period);
|
|
556
|
+
const wrap = WrapMode.loop(period);
|
|
557
557
|
return (t) => 1 - Math.abs(2 * wrap(t) - 1);
|
|
558
558
|
},
|
|
559
559
|
};
|
package/dist/core/env.d.ts
CHANGED
|
@@ -14,3 +14,9 @@
|
|
|
14
14
|
* `NodeJS` namespace. `test/seam/browser-types.test.ts` holds that line.
|
|
15
15
|
*/
|
|
16
16
|
export type Env = Readonly<Record<string, string | undefined>>;
|
|
17
|
+
/**
|
|
18
|
+
* A terminal that says it cannot be drawn on: `TERM` is `dumb` or `unknown`,
|
|
19
|
+
* as Emacs' shell mode sets it. It takes no color and nothing that moves the
|
|
20
|
+
* cursor.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isDumbTerminal(env: Env): boolean;
|
package/dist/core/env.js
CHANGED
|
@@ -13,4 +13,12 @@
|
|
|
13
13
|
* without `@types/node` — the ordinary browser project — cannot resolve the
|
|
14
14
|
* `NodeJS` namespace. `test/seam/browser-types.test.ts` holds that line.
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* A terminal that says it cannot be drawn on: `TERM` is `dumb` or `unknown`,
|
|
18
|
+
* as Emacs' shell mode sets it. It takes no color and nothing that moves the
|
|
19
|
+
* cursor.
|
|
20
|
+
*/
|
|
21
|
+
export function isDumbTerminal(env) {
|
|
22
|
+
const term = env["TERM"];
|
|
23
|
+
return term === "dumb" || term === "unknown";
|
|
24
|
+
}
|