@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.
Files changed (185) hide show
  1. package/README.md +7 -6
  2. package/THIRD-PARTY-NOTICES +42 -0
  3. package/dist/core/animation.d.ts +65 -46
  4. package/dist/core/animation.js +91 -67
  5. package/dist/core/ansi.d.ts +19 -12
  6. package/dist/core/ansi.js +114 -36
  7. package/dist/core/bidi-data.d.ts +14 -0
  8. package/dist/core/bidi-data.js +385 -0
  9. package/dist/core/bidi.d.ts +89 -0
  10. package/dist/core/bidi.js +615 -0
  11. package/dist/core/box.d.ts +9 -1
  12. package/dist/core/box.js +11 -0
  13. package/dist/core/cell-widths.d.ts +3 -2
  14. package/dist/core/cell-widths.js +93 -93
  15. package/dist/core/cells.d.ts +20 -0
  16. package/dist/core/cells.js +94 -6
  17. package/dist/core/clock.d.ts +1 -1
  18. package/dist/core/color.d.ts +56 -57
  19. package/dist/core/color.js +79 -81
  20. package/dist/core/console.d.ts +24 -7
  21. package/dist/core/console.js +27 -8
  22. package/dist/core/control-codes.d.ts +61 -0
  23. package/dist/core/control-codes.js +157 -0
  24. package/dist/core/easing.d.ts +40 -40
  25. package/dist/core/easing.js +40 -40
  26. package/dist/core/env.d.ts +6 -0
  27. package/dist/core/env.js +9 -1
  28. package/dist/core/export-html.js +5 -4
  29. package/dist/core/export-lines.d.ts +13 -11
  30. package/dist/core/export-lines.js +19 -15
  31. package/dist/core/export-svg.d.ts +3 -3
  32. package/dist/core/export-svg.js +10 -9
  33. package/dist/core/json.js +9 -2
  34. package/dist/core/markup.js +5 -4
  35. package/dist/core/memo.d.ts +1 -1
  36. package/dist/core/memo.js +1 -1
  37. package/dist/core/oklch.d.ts +14 -14
  38. package/dist/core/oklch.js +10 -10
  39. package/dist/core/orient.d.ts +68 -0
  40. package/dist/core/orient.js +224 -0
  41. package/dist/core/osc8.d.ts +12 -5
  42. package/dist/core/osc8.js +14 -7
  43. package/dist/core/paint.d.ts +9 -9
  44. package/dist/core/paint.js +3 -3
  45. package/dist/core/pretty.d.ts +1 -1
  46. package/dist/core/pretty.js +23 -19
  47. package/dist/core/protocol.d.ts +47 -26
  48. package/dist/core/protocol.js +31 -23
  49. package/dist/core/render.d.ts +19 -14
  50. package/dist/core/render.js +30 -17
  51. package/dist/core/seal.d.ts +26 -0
  52. package/dist/core/seal.js +75 -0
  53. package/dist/core/segment.d.ts +12 -4
  54. package/dist/core/segment.js +16 -6
  55. package/dist/core/strip.d.ts +83 -83
  56. package/dist/core/strip.js +70 -70
  57. package/dist/core/style.d.ts +46 -18
  58. package/dist/core/style.js +92 -56
  59. package/dist/core/text-order.d.ts +51 -0
  60. package/dist/core/text-order.js +50 -0
  61. package/dist/core/text.d.ts +12 -2
  62. package/dist/core/text.js +136 -90
  63. package/dist/core/timeline.d.ts +5 -5
  64. package/dist/core/timeline.js +11 -11
  65. package/dist/core/tween.d.ts +6 -6
  66. package/dist/core/tween.js +10 -10
  67. package/dist/core/view.d.ts +5 -5
  68. package/dist/core/view.js +15 -14
  69. package/dist/core/wrap.d.ts +24 -6
  70. package/dist/core/wrap.js +82 -16
  71. package/dist/host/app.d.ts +50 -9
  72. package/dist/host/app.js +120 -15
  73. package/dist/host/host-environment.d.ts +2 -2
  74. package/dist/host/host-environment.js +2 -2
  75. package/dist/host/index.d.ts +3 -2
  76. package/dist/host/index.js +1 -0
  77. package/dist/host/input.d.ts +42 -9
  78. package/dist/host/input.js +91 -7
  79. package/dist/host/terminal-colors.d.ts +18 -0
  80. package/dist/host/terminal-colors.js +46 -0
  81. package/dist/host/terminal-host.d.ts +4 -3
  82. package/dist/host/terminal-host.js +1 -1
  83. package/dist/index.d.ts +17 -16
  84. package/dist/index.js +11 -11
  85. package/dist/node/prompt.d.ts +1 -1
  86. package/dist/node/prompt.js +1 -1
  87. package/dist/node/terminal-host.d.ts +1 -1
  88. package/dist/node/traceback.js +2 -2
  89. package/dist/renderables/change.d.ts +1 -3
  90. package/dist/renderables/change.js +6 -8
  91. package/dist/renderables/effect.d.ts +88 -87
  92. package/dist/renderables/effect.js +124 -114
  93. package/dist/renderables/effects.d.ts +105 -76
  94. package/dist/renderables/effects.js +309 -176
  95. package/dist/renderables/embed.d.ts +1 -1
  96. package/dist/renderables/embed.js +2 -2
  97. package/dist/renderables/flexStrip.d.ts +7 -7
  98. package/dist/renderables/flexStrip.js +15 -15
  99. package/dist/renderables/frames.d.ts +7 -16
  100. package/dist/renderables/frames.js +12 -27
  101. package/dist/renderables/glyph-effect.d.ts +22 -23
  102. package/dist/renderables/glyph-effect.js +43 -41
  103. package/dist/renderables/glyph-effects.d.ts +33 -14
  104. package/dist/renderables/glyph-effects.js +90 -22
  105. package/dist/renderables/html-entities.d.ts +1 -1
  106. package/dist/renderables/html-entities.js +1 -1
  107. package/dist/renderables/lifecycle.d.ts +8 -10
  108. package/dist/renderables/lifecycle.js +17 -18
  109. package/dist/renderables/live.d.ts +2 -2
  110. package/dist/renderables/live.js +7 -7
  111. package/dist/renderables/markdown-parse.js +3 -3
  112. package/dist/renderables/markdown.js +4 -2
  113. package/dist/renderables/panel.js +7 -5
  114. package/dist/renderables/progress.d.ts +1 -1
  115. package/dist/renderables/progress.js +1 -1
  116. package/dist/renderables/progressBar.d.ts +3 -3
  117. package/dist/renderables/progressBar.js +21 -18
  118. package/dist/renderables/prompt.d.ts +1 -1
  119. package/dist/renderables/scroll.d.ts +1 -1
  120. package/dist/renderables/scroll.js +3 -3
  121. package/dist/renderables/spinner.d.ts +4 -4
  122. package/dist/renderables/spinner.js +10 -10
  123. package/dist/renderables/syntax.d.ts +2 -2
  124. package/dist/renderables/syntax.js +9 -4
  125. package/dist/renderables/table.js +5 -4
  126. package/dist/renderables/traceback.d.ts +1 -1
  127. package/dist/renderables/traceback.js +1 -1
  128. package/dist/renderables/tree.js +3 -3
  129. package/dist/template-bindings/animation-funcs.d.ts +60 -29
  130. package/dist/template-bindings/animation-funcs.js +126 -43
  131. package/dist/template-bindings/color-funcs.d.ts +14 -14
  132. package/dist/template-bindings/color-funcs.js +25 -25
  133. package/dist/template-bindings/index.d.ts +16 -14
  134. package/dist/template-bindings/index.js +17 -14
  135. package/dist/template-bindings/palette-funcs.d.ts +2 -2
  136. package/dist/template-bindings/palette-funcs.js +4 -4
  137. package/dist/template-bindings/style-funcs.d.ts +5 -5
  138. package/dist/template-bindings/style-funcs.js +16 -16
  139. package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
  140. package/dist/themes/{transpose.js → adjust.js} +28 -28
  141. package/dist/themes/buildPalette.d.ts +6 -5
  142. package/dist/themes/buildPalette.js +22 -22
  143. package/dist/themes/colorMath.d.ts +16 -16
  144. package/dist/themes/colorMath.js +32 -32
  145. package/dist/themes/data/ansi-tables.d.ts +2 -2
  146. package/dist/themes/data/ansi-tables.js +2 -2
  147. package/dist/themes/data/index.js +1 -4
  148. package/dist/themes/data/textual-ansi.js +0 -143
  149. package/dist/themes/data/types.d.ts +4 -4
  150. package/dist/themes/data/types.js +2 -2
  151. package/dist/themes/palette.d.ts +12 -12
  152. package/dist/themes/palette.js +16 -16
  153. package/dist/themes/ramp.d.ts +17 -17
  154. package/dist/themes/ramp.js +12 -12
  155. package/dist/themes/registry.d.ts +6 -8
  156. package/dist/themes/registry.js +6 -8
  157. package/dist/themes/terminalThemes.d.ts +4 -11
  158. package/dist/themes/terminalThemes.js +31 -47
  159. package/dist/widgets/button.d.ts +3 -3
  160. package/dist/widgets/button.js +8 -8
  161. package/dist/widgets/checkbox.d.ts +2 -2
  162. package/dist/widgets/checkbox.js +4 -4
  163. package/dist/widgets/dropdown.d.ts +3 -3
  164. package/dist/widgets/dropdown.js +7 -5
  165. package/dist/widgets/event-router.d.ts +6 -6
  166. package/dist/widgets/event-router.js +2 -2
  167. package/dist/widgets/focus-manager.d.ts +3 -3
  168. package/dist/widgets/focus-manager.js +3 -3
  169. package/dist/widgets/index.d.ts +2 -2
  170. package/dist/widgets/index.js +1 -1
  171. package/dist/widgets/ink.d.ts +3 -3
  172. package/dist/widgets/ink.js +4 -4
  173. package/dist/widgets/slider.d.ts +2 -2
  174. package/dist/widgets/static-item.d.ts +2 -2
  175. package/dist/widgets/text-input.d.ts +2 -2
  176. package/dist/widgets/text-input.js +5 -5
  177. package/dist/widgets/themed-widget.js +4 -4
  178. package/dist/widgets/toggle.d.ts +4 -4
  179. package/dist/widgets/toggle.js +6 -6
  180. package/dist/widgets/types.d.ts +6 -6
  181. package/dist/widgets/types.js +2 -2
  182. package/dist/widgets/widget-app.d.ts +10 -10
  183. package/dist/widgets/widget-app.js +8 -8
  184. package/dist/widgets/widget-base.d.ts +2 -2
  185. 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
+ }
@@ -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 colours where it does, and an effect's `Curve` saturates at its
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 `Ease`.
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 Ease = (x: number) => number;
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 Phase = (t: number) => number;
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): Ease;
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): Ease;
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 `Ease` contract — an argument in [0, 1], the end landed on —
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 settled: (shape: (p: number) => number) => Ease;
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. `Phase.once(start, seconds)` through `ease` is the move
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: 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 colour channel's step (1/255) and
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: Ease;
141
- readonly ease: Ease;
142
- readonly "ease-in": Ease;
143
- readonly "ease-out": Ease;
144
- readonly "ease-in-out": Ease;
145
- readonly "step-start": Ease;
146
- readonly "step-end": Ease;
147
- readonly step: Ease;
148
- readonly sine: Ease;
149
- readonly spring: Ease;
150
- readonly bounce: Ease;
151
- readonly "back-in": Ease;
152
- readonly "back-out": Ease;
153
- readonly elastic: Ease;
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 EaseName = keyof typeof EASES;
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 parseEase(name: string): Ease;
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 `Phase.loop` wraps. With equal holds `at` is `steps(n)` read as an
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 Beat {
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 `nextChange`,
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
- lastChange(t: number): number;
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
- nextChange(t: number): number;
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(): Beat;
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 `Beat`; a beat with no hold, or a hold that is not a positive number of seconds, throws. */
238
- export declare function beat(holds: readonly number[]): Beat;
239
- /** The three phase shapes. Each takes seconds and returns a `Phase`. */
240
- export declare const Phase: {
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): Phase;
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): Phase;
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): Phase;
246
+ pingPong(period: number): WrapMode;
247
247
  };
@@ -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 colours where it does, and an effect's `Curve` saturates at its
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 `Ease`.
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 settled((p) => yAt(solve(p)));
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 settled((p) => Math.min(jumps, Math.floor(p * n) + lift) / jumps);
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 `Ease` contract — an argument in [0, 1], the end landed on —
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 settled = (shape) => (x) => {
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 = settled((p) => p);
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 = settled((p) => (1 - Math.cos(Math.PI * p)) / 2);
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 colour channel's step (1/255) and
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: settled((p) => 1 - displacement(p * seconds)) };
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 = settled((p) => {
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 = settled((p) => p ** 3 + BACK_OVERSHOOT * p ** 2 * (p - 1));
276
- const backOut = settled((p) => {
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 = settled((p) => 2 ** (-10 * p) * Math.sin((10 * p - 0.75) * ELASTIC_PERIOD) + 1);
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 parseEase(name) {
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
- lastChange: () => Number.NEGATIVE_INFINITY,
339
- nextChange: () => Number.POSITIVE_INFINITY,
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 `Phase.loop` and `beat` both read time through, so a `t` that is
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 `Beat`; a beat with no hold, or a hold that is not a positive number of seconds, throws. */
478
- export function beat(holds) {
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 beat needs at least one hold");
481
- holds.forEach((hold, i) => positiveSeconds(`beat hold ${i}`, hold));
482
- const period = holds.reduce((sum, hold) => sum + hold, 0);
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 hold of holds) {
489
+ for (const validity of holds) {
490
490
  starts.push(elapsed);
491
- elapsed += hold;
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("Beat.at", t, period));
523
+ return index(wrapSeconds("StepSequence.at", t, period));
524
524
  },
525
- lastChange(t) {
526
- const { pass, into } = passAt("Beat.lastChange", t, period);
527
- return boundary("Beat.lastChange", pass, index(into), t);
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
- nextChange(t) {
531
- const { pass, into } = passAt("Beat.nextChange", t, period);
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("Beat.nextChange", pass + (last ? 1 : 0), last ? 0 : i + 1, t);
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 `Phase`. */
540
- export const Phase = {
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(`Phase.once start must be finite, got ${start}`);
545
- positiveSeconds("Phase.once duration", duration);
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("Phase.loop period", period);
551
- return (t) => wrapSeconds("Phase.loop", t, period) / period;
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("Phase.pingPong period", period);
556
- const wrap = Phase.loop(period);
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
  };
@@ -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
- export {};
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
+ }