@promptctl/rich-js 0.18.0 → 0.19.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 (244) hide show
  1. package/README.md +9 -7
  2. package/dist/core/anchor.d.ts +45 -0
  3. package/dist/core/anchor.js +39 -0
  4. package/dist/core/ansi.d.ts +65 -0
  5. package/dist/core/ansi.js +231 -0
  6. package/dist/core/box.d.ts +145 -0
  7. package/dist/core/box.js +372 -0
  8. package/dist/core/cells.d.ts +192 -0
  9. package/dist/core/cells.js +334 -0
  10. package/dist/core/clock.d.ts +48 -0
  11. package/dist/core/clock.js +42 -0
  12. package/dist/core/color.d.ts +326 -0
  13. package/dist/core/color.js +1225 -0
  14. package/dist/core/console.d.ts +196 -0
  15. package/dist/core/console.js +596 -0
  16. package/dist/core/easing.d.ts +86 -0
  17. package/dist/core/easing.js +171 -0
  18. package/dist/core/emoji.d.ts +24 -0
  19. package/dist/core/emoji.js +391 -0
  20. package/dist/core/env.d.ts +16 -0
  21. package/dist/core/env.js +16 -0
  22. package/dist/core/export-html.d.ts +59 -0
  23. package/dist/core/export-html.js +197 -0
  24. package/dist/core/export-lines.d.ts +130 -0
  25. package/dist/core/export-lines.js +159 -0
  26. package/dist/core/export-svg.d.ts +49 -0
  27. package/dist/core/export-svg.js +213 -0
  28. package/dist/core/fnv1a.d.ts +10 -0
  29. package/dist/core/fnv1a.js +17 -0
  30. package/dist/core/highlighter.d.ts +33 -0
  31. package/dist/core/highlighter.js +190 -0
  32. package/dist/core/json.d.ts +27 -0
  33. package/dist/core/json.js +53 -0
  34. package/dist/core/markup.d.ts +140 -0
  35. package/dist/core/markup.js +654 -0
  36. package/dist/core/measure.d.ts +27 -0
  37. package/dist/core/measure.js +67 -0
  38. package/dist/core/memo.d.ts +19 -0
  39. package/dist/core/memo.js +34 -0
  40. package/dist/core/oklch.d.ts +161 -0
  41. package/dist/core/oklch.js +312 -0
  42. package/dist/core/osc8.d.ts +68 -0
  43. package/dist/core/osc8.js +78 -0
  44. package/dist/core/paint.d.ts +107 -0
  45. package/dist/core/paint.js +150 -0
  46. package/dist/core/place.d.ts +30 -0
  47. package/dist/core/place.js +49 -0
  48. package/dist/core/pretty.d.ts +247 -0
  49. package/dist/core/pretty.js +906 -0
  50. package/dist/core/protocol.d.ts +305 -0
  51. package/dist/core/protocol.js +183 -0
  52. package/dist/core/render.d.ts +87 -0
  53. package/dist/core/render.js +105 -0
  54. package/dist/core/segment.d.ts +162 -0
  55. package/dist/core/segment.js +488 -0
  56. package/dist/core/spinnerData.d.ts +12 -0
  57. package/dist/core/spinnerData.js +117 -0
  58. package/dist/core/strip.d.ts +152 -0
  59. package/dist/core/strip.js +326 -0
  60. package/dist/core/style.d.ts +189 -0
  61. package/dist/core/style.js +758 -0
  62. package/dist/core/subscription.d.ts +12 -0
  63. package/dist/core/subscription.js +12 -0
  64. package/dist/core/text.d.ts +283 -0
  65. package/dist/core/text.js +1097 -0
  66. package/dist/core/wrap.d.ts +46 -0
  67. package/dist/core/wrap.js +140 -0
  68. package/dist/host/app.d.ts +133 -0
  69. package/dist/host/app.js +285 -0
  70. package/dist/host/host-environment.d.ts +26 -0
  71. package/dist/host/host-environment.js +44 -0
  72. package/dist/host/index.d.ts +6 -0
  73. package/dist/host/index.js +3 -0
  74. package/dist/host/terminal-host.d.ts +180 -0
  75. package/dist/host/terminal-host.js +186 -0
  76. package/dist/index.d.ts +98 -0
  77. package/dist/index.js +114 -0
  78. package/dist/node/prompt.d.ts +34 -0
  79. package/dist/node/prompt.js +51 -0
  80. package/dist/node/save.d.ts +18 -0
  81. package/dist/node/save.js +24 -0
  82. package/dist/node/terminal-host.d.ts +114 -0
  83. package/dist/node/terminal-host.js +227 -0
  84. package/dist/node/traceback.d.ts +38 -0
  85. package/dist/node/traceback.js +98 -0
  86. package/dist/renderables/align.d.ts +16 -0
  87. package/dist/renderables/align.js +26 -0
  88. package/dist/renderables/columns.d.ts +77 -0
  89. package/dist/renderables/columns.js +191 -0
  90. package/dist/renderables/constrain.d.ts +15 -0
  91. package/dist/renderables/constrain.js +31 -0
  92. package/dist/renderables/effect.d.ts +98 -0
  93. package/dist/renderables/effect.js +160 -0
  94. package/dist/renderables/embed.d.ts +107 -0
  95. package/dist/renderables/embed.js +160 -0
  96. package/dist/renderables/flexStrip.d.ts +41 -0
  97. package/dist/renderables/flexStrip.js +200 -0
  98. package/dist/renderables/group.d.ts +14 -0
  99. package/dist/renderables/group.js +22 -0
  100. package/dist/renderables/layout.d.ts +75 -0
  101. package/dist/renderables/layout.js +223 -0
  102. package/dist/renderables/live.d.ts +74 -0
  103. package/dist/renderables/live.js +188 -0
  104. package/dist/renderables/markdown.d.ts +38 -0
  105. package/dist/renderables/markdown.js +587 -0
  106. package/dist/renderables/padding.d.ts +59 -0
  107. package/dist/renderables/padding.js +147 -0
  108. package/dist/renderables/panel.d.ts +114 -0
  109. package/dist/renderables/panel.js +303 -0
  110. package/dist/renderables/progress.d.ts +178 -0
  111. package/dist/renderables/progress.js +362 -0
  112. package/dist/renderables/progressBar.d.ts +31 -0
  113. package/dist/renderables/progressBar.js +64 -0
  114. package/dist/renderables/prompt.d.ts +71 -0
  115. package/dist/renderables/prompt.js +165 -0
  116. package/dist/renderables/ratio.d.ts +123 -0
  117. package/dist/renderables/ratio.js +213 -0
  118. package/dist/renderables/rule.d.ts +26 -0
  119. package/dist/renderables/rule.js +86 -0
  120. package/dist/renderables/spinner.d.ts +57 -0
  121. package/dist/renderables/spinner.js +103 -0
  122. package/dist/renderables/status.d.ts +29 -0
  123. package/dist/renderables/status.js +46 -0
  124. package/dist/renderables/syntax.d.ts +65 -0
  125. package/dist/renderables/syntax.js +166 -0
  126. package/dist/renderables/table.d.ts +232 -0
  127. package/dist/renderables/table.js +973 -0
  128. package/dist/renderables/traceback.d.ts +32 -0
  129. package/dist/renderables/traceback.js +279 -0
  130. package/dist/renderables/tree.d.ts +76 -0
  131. package/dist/renderables/tree.js +177 -0
  132. package/dist/renderables/viewport.d.ts +114 -0
  133. package/dist/renderables/viewport.js +196 -0
  134. package/dist/template-bindings/color-funcs.d.ts +109 -0
  135. package/dist/template-bindings/color-funcs.js +243 -0
  136. package/dist/template-bindings/helpers.d.ts +26 -0
  137. package/dist/template-bindings/helpers.js +33 -0
  138. package/dist/template-bindings/index.d.ts +119 -0
  139. package/dist/template-bindings/index.js +162 -0
  140. package/dist/template-bindings/palette-funcs.d.ts +96 -0
  141. package/dist/template-bindings/palette-funcs.js +145 -0
  142. package/dist/template-bindings/style-funcs.d.ts +28 -0
  143. package/dist/template-bindings/style-funcs.js +157 -0
  144. package/dist/themes/buildPalette.d.ts +57 -0
  145. package/dist/themes/buildPalette.js +100 -0
  146. package/dist/themes/colorMath.d.ts +94 -0
  147. package/dist/themes/colorMath.js +280 -0
  148. package/dist/themes/colorRef.d.ts +36 -0
  149. package/dist/themes/colorRef.js +78 -0
  150. package/dist/themes/data/ansi-tables.d.ts +14 -0
  151. package/dist/themes/data/ansi-tables.js +49 -0
  152. package/dist/themes/data/atom-one-dark.d.ts +3 -0
  153. package/dist/themes/data/atom-one-dark.js +177 -0
  154. package/dist/themes/data/atom-one-light.d.ts +3 -0
  155. package/dist/themes/data/atom-one-light.js +177 -0
  156. package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
  157. package/dist/themes/data/catppuccin-frappe.js +177 -0
  158. package/dist/themes/data/catppuccin-latte.d.ts +3 -0
  159. package/dist/themes/data/catppuccin-latte.js +177 -0
  160. package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
  161. package/dist/themes/data/catppuccin-macchiato.js +177 -0
  162. package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
  163. package/dist/themes/data/catppuccin-mocha.js +177 -0
  164. package/dist/themes/data/cyberpunk.d.ts +17 -0
  165. package/dist/themes/data/cyberpunk.js +193 -0
  166. package/dist/themes/data/default.d.ts +3 -0
  167. package/dist/themes/data/default.js +160 -0
  168. package/dist/themes/data/dracula.d.ts +3 -0
  169. package/dist/themes/data/dracula.js +177 -0
  170. package/dist/themes/data/flexoki.d.ts +3 -0
  171. package/dist/themes/data/flexoki.js +177 -0
  172. package/dist/themes/data/gruvbox.d.ts +3 -0
  173. package/dist/themes/data/gruvbox.js +177 -0
  174. package/dist/themes/data/index.d.ts +35 -0
  175. package/dist/themes/data/index.js +64 -0
  176. package/dist/themes/data/monokai.d.ts +3 -0
  177. package/dist/themes/data/monokai.js +177 -0
  178. package/dist/themes/data/nord.d.ts +3 -0
  179. package/dist/themes/data/nord.js +177 -0
  180. package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
  181. package/dist/themes/data/rose-pine-dawn.js +177 -0
  182. package/dist/themes/data/rose-pine-moon.d.ts +3 -0
  183. package/dist/themes/data/rose-pine-moon.js +177 -0
  184. package/dist/themes/data/rose-pine.d.ts +3 -0
  185. package/dist/themes/data/rose-pine.js +177 -0
  186. package/dist/themes/data/solarized-dark.d.ts +3 -0
  187. package/dist/themes/data/solarized-dark.js +177 -0
  188. package/dist/themes/data/solarized-light.d.ts +3 -0
  189. package/dist/themes/data/solarized-light.js +177 -0
  190. package/dist/themes/data/svg-export.d.ts +3 -0
  191. package/dist/themes/data/svg-export.js +177 -0
  192. package/dist/themes/data/textual-ansi.d.ts +3 -0
  193. package/dist/themes/data/textual-ansi.js +160 -0
  194. package/dist/themes/data/textual-dark.d.ts +3 -0
  195. package/dist/themes/data/textual-dark.js +160 -0
  196. package/dist/themes/data/textual-light.d.ts +3 -0
  197. package/dist/themes/data/textual-light.js +160 -0
  198. package/dist/themes/data/tokyo-night.d.ts +3 -0
  199. package/dist/themes/data/tokyo-night.js +177 -0
  200. package/dist/themes/data/types.d.ts +31 -0
  201. package/dist/themes/data/types.js +10 -0
  202. package/dist/themes/palette.d.ts +45 -0
  203. package/dist/themes/palette.js +71 -0
  204. package/dist/themes/ramp.d.ts +70 -0
  205. package/dist/themes/ramp.js +103 -0
  206. package/dist/themes/registry.d.ts +44 -0
  207. package/dist/themes/registry.js +105 -0
  208. package/dist/themes/terminalThemes.d.ts +49 -0
  209. package/dist/themes/terminalThemes.js +63 -0
  210. package/dist/themes/transpose.d.ts +87 -0
  211. package/dist/themes/transpose.js +138 -0
  212. package/dist/widgets/button.d.ts +45 -0
  213. package/dist/widgets/button.js +177 -0
  214. package/dist/widgets/checkbox.d.ts +38 -0
  215. package/dist/widgets/checkbox.js +135 -0
  216. package/dist/widgets/dropdown.d.ts +64 -0
  217. package/dist/widgets/dropdown.js +416 -0
  218. package/dist/widgets/event-router.d.ts +71 -0
  219. package/dist/widgets/event-router.js +629 -0
  220. package/dist/widgets/focus-manager.d.ts +45 -0
  221. package/dist/widgets/focus-manager.js +191 -0
  222. package/dist/widgets/hit.d.ts +64 -0
  223. package/dist/widgets/hit.js +113 -0
  224. package/dist/widgets/index.d.ts +20 -0
  225. package/dist/widgets/index.js +14 -0
  226. package/dist/widgets/ink.d.ts +22 -0
  227. package/dist/widgets/ink.js +31 -0
  228. package/dist/widgets/slider.d.ts +54 -0
  229. package/dist/widgets/slider.js +247 -0
  230. package/dist/widgets/static-item.d.ts +34 -0
  231. package/dist/widgets/static-item.js +54 -0
  232. package/dist/widgets/text-input.d.ts +283 -0
  233. package/dist/widgets/text-input.js +1174 -0
  234. package/dist/widgets/themed-widget.d.ts +20 -0
  235. package/dist/widgets/themed-widget.js +89 -0
  236. package/dist/widgets/toggle.d.ts +41 -0
  237. package/dist/widgets/toggle.js +157 -0
  238. package/dist/widgets/types.d.ts +87 -0
  239. package/dist/widgets/types.js +30 -0
  240. package/dist/widgets/widget-app.d.ts +65 -0
  241. package/dist/widgets/widget-app.js +206 -0
  242. package/dist/widgets/widget-base.d.ts +42 -0
  243. package/dist/widgets/widget-base.js +172 -0
  244. package/package.json +16 -2
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Easing and phase: the one vocabulary for "how far along" — every function
3
+ * here returns progress in [0, 1].
4
+ *
5
+ * Two kinds of curve, composed as `ease(phase(t))`:
6
+ *
7
+ * - A **phase** turns a time `t` (seconds) into raw progress: `once` runs
8
+ * 0 → 1 over a span and holds, `loop` wraps 0 → 1 every period,
9
+ * `pingPong` goes 0 → 1 → 0 every period. A per-cell offset is added to `t`
10
+ * before the phase sees it — `phase(t + offset)` — so the cells of one
11
+ * effect run the same curve shifted in time.
12
+ * - An **ease** reshapes that progress: any `(x) => y` on [0, 1]. The
13
+ * built-ins are CSS's easing functions (CSS Easing Functions Level 1):
14
+ * `linear`, `cubic-bezier()` with its named curves, and `steps()` with its
15
+ * jump terms, plus `sine` for pulses — a half-cosine, so a `pingPong`
16
+ * through it brightens and dims with no corner at either end.
17
+ *
18
+ * [LAW:no-ambient-temporal-coupling] Nothing here reads a clock. `t` is an
19
+ * argument; whoever draws frames owns the clock and samples these at
20
+ * whatever rate it likes, so the same `t` always gives the same progress.
21
+ *
22
+ * [LAW:one-type-per-behavior] An ease is a plain function value. CSS's named
23
+ * curves are four instances of `cubicBezier`, not four implementations, and
24
+ * `ColorRamp` and every effect take the same `Ease`.
25
+ *
26
+ * Tier 0 of `src/core/`: imports nothing, so `themes/` and every later
27
+ * `core/` module reach it downhill. [LAW:one-way-deps]
28
+ */
29
+ /** Progress in, progress out: a reshaping of [0, 1]. */
30
+ export type Ease = (x: number) => number;
31
+ /** Time in seconds (plus any per-cell offset) in, progress in [0, 1] out. */
32
+ export type Phase = (t: number) => number;
33
+ /**
34
+ * CSS `cubic-bezier(x1, y1, x2, y2)`: the curve from (0, 0) to (1, 1) with
35
+ * those two control points, read as y at a given x. `x1` and `x2` must lie in
36
+ * [0, 1] — as in CSS — which keeps x monotonic in the curve parameter, so
37
+ * every input has exactly one output. `y1` and `y2` may leave [0, 1]; the
38
+ * curve then overshoots, as a CSS "back" curve does.
39
+ */
40
+ export declare function cubicBezier(x1: number, y1: number, x2: number, y2: number): Ease;
41
+ /**
42
+ * Where a `steps()` curve jumps, in CSS's terms. `jump-start` jumps at 0,
43
+ * `jump-end` at 1, `jump-both` at both, `jump-none` at neither; `start` and
44
+ * `end` are CSS's older spellings of the first two.
45
+ */
46
+ export type StepPosition = "jump-start" | "jump-end" | "jump-none" | "jump-both" | "start" | "end";
47
+ /**
48
+ * CSS `steps(n, position)`: progress held flat in `n` equal intervals, jumping
49
+ * between them. The output takes `n` distinct values between the jumps
50
+ * `position` names — CSS's step algorithm, so `steps(1, "end")` is 0 until
51
+ * the very end.
52
+ */
53
+ export declare function steps(n: number, position?: StepPosition): Ease;
54
+ /**
55
+ * Every built-in ease by the name a template spells it with — CSS's keyword
56
+ * names, plus `sine`, plus `step`: the spelling `ColorRamp` used before this
57
+ * vocabulary existed, kept so every template written against it renders the
58
+ * same. It is CSS's `step-end`, the same function value.
59
+ */
60
+ export declare const EASES: {
61
+ readonly linear: Ease;
62
+ readonly ease: Ease;
63
+ readonly "ease-in": Ease;
64
+ readonly "ease-out": Ease;
65
+ readonly "ease-in-out": Ease;
66
+ readonly "step-start": Ease;
67
+ readonly "step-end": Ease;
68
+ readonly step: Ease;
69
+ readonly sine: Ease;
70
+ };
71
+ export type EaseName = keyof typeof EASES;
72
+ /**
73
+ * The gate a spelled ease crosses. [LAW:parse-dont-validate] — a name in, the
74
+ * function out, so nothing downstream holds a string it must check again.
75
+ * Unknown names throw naming every legal one. [LAW:no-silent-failure]
76
+ */
77
+ export declare function parseEase(name: string): Ease;
78
+ /** The three phase shapes. Each takes seconds and returns a `Phase`. */
79
+ export declare const Phase: {
80
+ /** 0 before `start`, rising to 1 over `duration` seconds, then held at 1. */
81
+ once(start: number, duration: number): Phase;
82
+ /** 0 → 1 every `period` seconds, wrapping back to 0; negative `t` wraps too. */
83
+ loop(period: number): Phase;
84
+ /** 0 → 1 → 0 every `period` seconds: there in the first half, back in the second. */
85
+ pingPong(period: number): Phase;
86
+ };
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Easing and phase: the one vocabulary for "how far along" — every function
3
+ * here returns progress in [0, 1].
4
+ *
5
+ * Two kinds of curve, composed as `ease(phase(t))`:
6
+ *
7
+ * - A **phase** turns a time `t` (seconds) into raw progress: `once` runs
8
+ * 0 → 1 over a span and holds, `loop` wraps 0 → 1 every period,
9
+ * `pingPong` goes 0 → 1 → 0 every period. A per-cell offset is added to `t`
10
+ * before the phase sees it — `phase(t + offset)` — so the cells of one
11
+ * effect run the same curve shifted in time.
12
+ * - An **ease** reshapes that progress: any `(x) => y` on [0, 1]. The
13
+ * built-ins are CSS's easing functions (CSS Easing Functions Level 1):
14
+ * `linear`, `cubic-bezier()` with its named curves, and `steps()` with its
15
+ * jump terms, plus `sine` for pulses — a half-cosine, so a `pingPong`
16
+ * through it brightens and dims with no corner at either end.
17
+ *
18
+ * [LAW:no-ambient-temporal-coupling] Nothing here reads a clock. `t` is an
19
+ * argument; whoever draws frames owns the clock and samples these at
20
+ * whatever rate it likes, so the same `t` always gives the same progress.
21
+ *
22
+ * [LAW:one-type-per-behavior] An ease is a plain function value. CSS's named
23
+ * curves are four instances of `cubicBezier`, not four implementations, and
24
+ * `ColorRamp` and every effect take the same `Ease`.
25
+ *
26
+ * Tier 0 of `src/core/`: imports nothing, so `themes/` and every later
27
+ * `core/` module reach it downhill. [LAW:one-way-deps]
28
+ */
29
+ /**
30
+ * CSS `cubic-bezier(x1, y1, x2, y2)`: the curve from (0, 0) to (1, 1) with
31
+ * those two control points, read as y at a given x. `x1` and `x2` must lie in
32
+ * [0, 1] — as in CSS — which keeps x monotonic in the curve parameter, so
33
+ * every input has exactly one output. `y1` and `y2` may leave [0, 1]; the
34
+ * curve then overshoots, as a CSS "back" curve does.
35
+ */
36
+ export function cubicBezier(x1, y1, x2, y2) {
37
+ for (const [name, v] of [["x1", x1], ["y1", y1], ["x2", x2], ["y2", y2]]) {
38
+ if (!Number.isFinite(v))
39
+ throw new RangeError(`cubicBezier ${name} must be finite, got ${v}`);
40
+ }
41
+ if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) {
42
+ throw new RangeError(`cubicBezier x1 and x2 must lie in [0, 1], got ${x1} and ${x2}`);
43
+ }
44
+ // The Bernstein form in power basis: x(s) = ((ax·s + bx)·s + cx)·s, same for y.
45
+ const cx = 3 * x1;
46
+ const bx = 3 * (x2 - x1) - cx;
47
+ const ax = 1 - cx - bx;
48
+ const cy = 3 * y1;
49
+ const by = 3 * (y2 - y1) - cy;
50
+ const ay = 1 - cy - by;
51
+ const xAt = (s) => ((ax * s + bx) * s + cx) * s;
52
+ const yAt = (s) => ((ay * s + by) * s + cy) * s;
53
+ const dxAt = (s) => (3 * ax * s + 2 * bx) * s + cx;
54
+ const EPSILON = 1e-9;
55
+ // The parameter s with x(s) = x: Newton's method from s = x, which converges
56
+ // in a few steps on every curve CSS names; bisection when the slope is too
57
+ // flat for Newton to trust. x(s) is monotonic on [0, 1], so bisection always
58
+ // lands.
59
+ const solve = (x) => {
60
+ let s = x;
61
+ for (let i = 0; i < 8; i++) {
62
+ const err = xAt(s) - x;
63
+ if (Math.abs(err) < EPSILON)
64
+ return s;
65
+ const slope = dxAt(s);
66
+ if (Math.abs(slope) < 1e-6)
67
+ break;
68
+ s -= err / slope;
69
+ }
70
+ let lo = 0;
71
+ let hi = 1;
72
+ s = x;
73
+ while (hi - lo > EPSILON) {
74
+ if (xAt(s) < x)
75
+ lo = s;
76
+ else
77
+ hi = s;
78
+ s = (lo + hi) / 2;
79
+ }
80
+ return s;
81
+ };
82
+ return (x) => yAt(solve(Math.min(1, Math.max(0, x))));
83
+ }
84
+ /**
85
+ * CSS `steps(n, position)`: progress held flat in `n` equal intervals, jumping
86
+ * between them. The output takes `n` distinct values between the jumps
87
+ * `position` names — CSS's step algorithm, so `steps(1, "end")` is 0 until
88
+ * the very end.
89
+ */
90
+ export function steps(n, position = "jump-end") {
91
+ const minimum = position === "jump-none" ? 2 : 1;
92
+ if (!Number.isInteger(n) || n < minimum) {
93
+ throw new RangeError(`steps(${n}, "${position}") needs a whole number of steps ≥ ${minimum}`);
94
+ }
95
+ const jumpsAtStart = position === "jump-start" || position === "start" || position === "jump-both";
96
+ // How many jumps the curve makes in all, which is what each step is a fraction of.
97
+ const jumps = {
98
+ "jump-start": n,
99
+ start: n,
100
+ "jump-end": n,
101
+ end: n,
102
+ "jump-both": n + 1,
103
+ "jump-none": n - 1,
104
+ }[position];
105
+ const lift = jumpsAtStart ? 1 : 0;
106
+ return (x) => {
107
+ const p = Math.min(1, Math.max(0, x));
108
+ return Math.min(jumps, Math.floor(p * n) + lift) / jumps;
109
+ };
110
+ }
111
+ /** The identity ease: progress unchanged. */
112
+ const linear = (x) => x;
113
+ /** CSS `step-end`: 0 until the very end. */
114
+ const stepEnd = steps(1, "jump-end");
115
+ /** A half-cosine, flat at both ends: the curve a breathing pulse wants. */
116
+ const sine = (x) => (1 - Math.cos(Math.PI * x)) / 2;
117
+ /**
118
+ * Every built-in ease by the name a template spells it with — CSS's keyword
119
+ * names, plus `sine`, plus `step`: the spelling `ColorRamp` used before this
120
+ * vocabulary existed, kept so every template written against it renders the
121
+ * same. It is CSS's `step-end`, the same function value.
122
+ */
123
+ export const EASES = {
124
+ linear,
125
+ ease: cubicBezier(0.25, 0.1, 0.25, 1),
126
+ "ease-in": cubicBezier(0.42, 0, 1, 1),
127
+ "ease-out": cubicBezier(0, 0, 0.58, 1),
128
+ "ease-in-out": cubicBezier(0.42, 0, 0.58, 1),
129
+ "step-start": steps(1, "jump-start"),
130
+ "step-end": stepEnd,
131
+ step: stepEnd,
132
+ sine,
133
+ };
134
+ /**
135
+ * The gate a spelled ease crosses. [LAW:parse-dont-validate] — a name in, the
136
+ * function out, so nothing downstream holds a string it must check again.
137
+ * Unknown names throw naming every legal one. [LAW:no-silent-failure]
138
+ */
139
+ export function parseEase(name) {
140
+ if (!Object.hasOwn(EASES, name)) {
141
+ throw new RangeError(`unknown ease ${JSON.stringify(name)}; expected one of ` +
142
+ Object.keys(EASES).map((n) => JSON.stringify(n)).join(", "));
143
+ }
144
+ return EASES[name];
145
+ }
146
+ function positiveSeconds(what, seconds) {
147
+ if (!Number.isFinite(seconds) || seconds <= 0) {
148
+ throw new RangeError(`${what} must be a positive number of seconds, got ${seconds}`);
149
+ }
150
+ }
151
+ /** The three phase shapes. Each takes seconds and returns a `Phase`. */
152
+ export const Phase = {
153
+ /** 0 before `start`, rising to 1 over `duration` seconds, then held at 1. */
154
+ once(start, duration) {
155
+ if (!Number.isFinite(start))
156
+ throw new RangeError(`Phase.once start must be finite, got ${start}`);
157
+ positiveSeconds("Phase.once duration", duration);
158
+ return (t) => Math.min(1, Math.max(0, (t - start) / duration));
159
+ },
160
+ /** 0 → 1 every `period` seconds, wrapping back to 0; negative `t` wraps too. */
161
+ loop(period) {
162
+ positiveSeconds("Phase.loop period", period);
163
+ return (t) => (((t % period) + period) % period) / period;
164
+ },
165
+ /** 0 → 1 → 0 every `period` seconds: there in the first half, back in the second. */
166
+ pingPong(period) {
167
+ positiveSeconds("Phase.pingPong period", period);
168
+ const wrap = Phase.loop(period);
169
+ return (t) => 1 - Math.abs(2 * wrap(t) - 1);
170
+ },
171
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Emoji shortcode support — dictionary, replacement, and renderable.
3
+ */
4
+ import { Segment } from "./segment.js";
5
+ import type { Style } from "./style.js";
6
+ import type { Renderable, RenderOptions } from "./protocol.js";
7
+ export declare const EMOJI: Record<string, string>;
8
+ /**
9
+ * Replaces :shortcode: patterns in text with emoji characters.
10
+ */
11
+ export declare function emojiReplace(text: string, defaultVariant?: "emoji" | "text"): string;
12
+ export declare class NoEmoji extends Error {
13
+ constructor(name: string);
14
+ }
15
+ export declare class Emoji implements Renderable {
16
+ readonly name: string;
17
+ private readonly _char;
18
+ private readonly _style;
19
+ private readonly _variant;
20
+ constructor(name: string, style?: Style, variant?: "emoji" | "text");
21
+ toString(): string;
22
+ render(_options: RenderOptions): Iterable<Segment>;
23
+ static replace(text: string): string;
24
+ }
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Emoji shortcode support — dictionary, replacement, and renderable.
3
+ */
4
+ import { Segment } from "./segment.js";
5
+ // [LAW:one-source-of-truth] Single emoji dictionary for all shortcode lookups
6
+ export const EMOJI = {
7
+ // Faces
8
+ smile: "😄",
9
+ laugh: "😂",
10
+ grinning: "😀",
11
+ wink: "😉",
12
+ blush: "😊",
13
+ innocent: "😇",
14
+ heart_eyes: "😍",
15
+ kissing: "😘",
16
+ thinking: "🤔",
17
+ shushing: "🤫",
18
+ zipper_mouth: "🤐",
19
+ raised_eyebrow: "🤨",
20
+ neutral: "😐",
21
+ expressionless: "😑",
22
+ unamused: "😒",
23
+ rolling_eyes: "🙄",
24
+ grimacing: "😬",
25
+ lying: "🤥",
26
+ relieved: "😌",
27
+ pensive: "😔",
28
+ sleepy: "😪",
29
+ sleeping: "😴",
30
+ mask: "😷",
31
+ thermometer_face: "🤒",
32
+ bandage_face: "🤕",
33
+ nauseated: "🤢",
34
+ sneezing: "🤧",
35
+ cold_face: "🥶",
36
+ hot_face: "🥵",
37
+ dizzy_face: "😵",
38
+ exploding_head: "🤯",
39
+ cowboy: "🤠",
40
+ party_face: "🥳",
41
+ sunglasses: "😎",
42
+ nerd: "🤓",
43
+ monocle: "🧐",
44
+ confused: "😕",
45
+ worried: "😟",
46
+ frowning: "☹",
47
+ open_mouth: "😮",
48
+ hushed: "😯",
49
+ astonished: "😲",
50
+ flushed: "😳",
51
+ pleading: "🥺",
52
+ cry: "😢",
53
+ sob: "😭",
54
+ scream: "😱",
55
+ sweat: "😰",
56
+ angry: "😡",
57
+ rage: "🤬",
58
+ devil: "😈",
59
+ skull: "💀",
60
+ poop: "💩",
61
+ clown: "🤡",
62
+ ghost: "👻",
63
+ alien: "👽",
64
+ robot: "🤖",
65
+ // Hands
66
+ wave: "👋",
67
+ raised_hand: "✋",
68
+ ok_hand: "👌",
69
+ pinching: "🤏",
70
+ victory: "✌",
71
+ crossed_fingers: "🤞",
72
+ love_you: "🤟",
73
+ rock_on: "🤘",
74
+ thumbs_up: "👍",
75
+ thumbs_down: "👎",
76
+ fist: "✊",
77
+ punch: "👊",
78
+ left_fist: "🤛",
79
+ right_fist: "🤜",
80
+ clap: "👏",
81
+ raised_hands: "🙌",
82
+ open_hands: "👐",
83
+ palms_up: "🤲",
84
+ handshake: "🤝",
85
+ pray: "🙏",
86
+ writing_hand: "✍",
87
+ nail_polish: "💅",
88
+ muscle: "💪",
89
+ point_up: "☝",
90
+ point_up_2: "👆",
91
+ point_down: "👇",
92
+ point_left: "👈",
93
+ point_right: "👉",
94
+ middle_finger: "🖕",
95
+ // Hearts
96
+ heart: "❤",
97
+ orange_heart: "🧡",
98
+ yellow_heart: "💛",
99
+ green_heart: "💚",
100
+ blue_heart: "💙",
101
+ purple_heart: "💜",
102
+ black_heart: "🖤",
103
+ white_heart: "🤍",
104
+ brown_heart: "🤎",
105
+ broken_heart: "💔",
106
+ heart_exclamation: "❣",
107
+ two_hearts: "💕",
108
+ revolving_hearts: "💞",
109
+ heartbeat: "💓",
110
+ heartpulse: "💗",
111
+ sparkling_heart: "💖",
112
+ growing_heart: "💗",
113
+ cupid: "💘",
114
+ gift_heart: "💝",
115
+ // Objects & Symbols
116
+ fire: "🔥",
117
+ star: "⭐",
118
+ star2: "🌟",
119
+ sparkles: "✨",
120
+ zap: "⚡",
121
+ boom: "💥",
122
+ droplet: "💧",
123
+ rainbow: "🌈",
124
+ sun: "☀",
125
+ moon: "🌙",
126
+ cloud: "☁",
127
+ snowflake: "❄",
128
+ umbrella: "☂",
129
+ // Status
130
+ check: "✅",
131
+ check_mark: "✔",
132
+ cross_mark: "❌",
133
+ warning: "⚠",
134
+ info: "ℹ",
135
+ question: "❓",
136
+ exclamation: "❗",
137
+ no_entry: "⛔",
138
+ prohibited: "🚫",
139
+ stop_sign: "🛑",
140
+ // Arrows
141
+ arrow_up: "⬆",
142
+ arrow_down: "⬇",
143
+ arrow_left: "⬅",
144
+ arrow_right: "➡",
145
+ arrow_upper_left: "↖",
146
+ arrow_upper_right: "↗",
147
+ arrow_lower_left: "↙",
148
+ arrow_lower_right: "↘",
149
+ left_right_arrow: "↔",
150
+ up_down_arrow: "↕",
151
+ arrows_clockwise: "🔃",
152
+ arrows_counterclockwise: "🔄",
153
+ // Tech
154
+ computer: "💻",
155
+ keyboard: "⌨",
156
+ desktop: "🖥",
157
+ printer: "🖨",
158
+ mouse: "🖱",
159
+ cd: "💿",
160
+ dvd: "📀",
161
+ floppy: "💾",
162
+ battery: "🔋",
163
+ plug: "🔌",
164
+ bulb: "💡",
165
+ flashlight: "🔦",
166
+ gear: "⚙",
167
+ wrench: "🔧",
168
+ hammer: "🔨",
169
+ nut_and_bolt: "🔩",
170
+ link: "🔗",
171
+ chains: "⛓",
172
+ lock: "🔒",
173
+ unlock: "🔓",
174
+ key: "🔑",
175
+ shield: "🛡",
176
+ bug: "🐛",
177
+ magnifying_glass: "🔍",
178
+ // Communication
179
+ speech_balloon: "💬",
180
+ thought_balloon: "💭",
181
+ megaphone: "📣",
182
+ loudspeaker: "📢",
183
+ bell: "🔔",
184
+ no_bell: "🔕",
185
+ envelope: "✉",
186
+ email: "📧",
187
+ inbox: "📥",
188
+ outbox: "📤",
189
+ package: "📦",
190
+ clipboard: "📋",
191
+ memo: "📝",
192
+ page: "📄",
193
+ bookmark: "🔖",
194
+ label: "🏷",
195
+ // Time
196
+ hourglass: "⌛",
197
+ hourglass_flowing: "⏳",
198
+ watch: "⌚",
199
+ alarm_clock: "⏰",
200
+ stopwatch: "⏱",
201
+ timer: "⏲",
202
+ clock: "🕐",
203
+ // Numbers
204
+ zero: "0️⃣",
205
+ one: "1️⃣",
206
+ two: "2️⃣",
207
+ three: "3️⃣",
208
+ four: "4️⃣",
209
+ five: "5️⃣",
210
+ six: "6️⃣",
211
+ seven: "7️⃣",
212
+ eight: "8️⃣",
213
+ nine: "9️⃣",
214
+ ten: "🔟",
215
+ hash: "#️⃣",
216
+ // Food & Drink
217
+ coffee: "☕",
218
+ tea: "🍵",
219
+ beer: "🍺",
220
+ wine: "🍷",
221
+ cocktail: "🍸",
222
+ pizza: "🍕",
223
+ hamburger: "🍔",
224
+ fries: "🍟",
225
+ hotdog: "🌭",
226
+ taco: "🌮",
227
+ cake: "🎂",
228
+ cookie: "🍪",
229
+ chocolate: "🍫",
230
+ candy: "🍬",
231
+ apple: "🍎",
232
+ banana: "🍌",
233
+ // Nature & Animals
234
+ dog: "🐕",
235
+ cat: "🐈",
236
+ snake: "🐍",
237
+ turtle: "🐢",
238
+ whale: "🐳",
239
+ dolphin: "🐬",
240
+ fish: "🐟",
241
+ butterfly: "🦋",
242
+ bee: "🐝",
243
+ ladybug: "🐞",
244
+ spider: "🕷",
245
+ tree: "🌲",
246
+ flower: "🌸",
247
+ rose: "🌹",
248
+ sunflower: "🌻",
249
+ cactus: "🌵",
250
+ // Activities
251
+ trophy: "🏆",
252
+ medal: "🏅",
253
+ crown: "👑",
254
+ gem: "💎",
255
+ money_bag: "💰",
256
+ dollar: "💵",
257
+ rocket: "🚀",
258
+ airplane: "✈",
259
+ car: "🚗",
260
+ bicycle: "🚲",
261
+ house: "🏠",
262
+ building: "🏢",
263
+ globe: "🌍",
264
+ world_map: "🗺",
265
+ flag: "🏁",
266
+ party: "🎉",
267
+ confetti: "🎊",
268
+ balloon: "🎈",
269
+ gift: "🎁",
270
+ art: "🎨",
271
+ music: "🎵",
272
+ notes: "🎶",
273
+ microphone: "🎤",
274
+ headphones: "🎧",
275
+ movie: "🎬",
276
+ camera: "📷",
277
+ book: "📖",
278
+ books: "📚",
279
+ scroll: "📜",
280
+ newspaper: "📰",
281
+ // People
282
+ person: "🧑",
283
+ man: "👨",
284
+ woman: "👩",
285
+ child: "🧒",
286
+ baby: "👶",
287
+ eyes: "👀",
288
+ eye: "👁",
289
+ brain: "🧠",
290
+ tongue: "👅",
291
+ ear: "👂",
292
+ nose: "👃",
293
+ foot: "🦶",
294
+ hand: "🤚",
295
+ // Misc
296
+ red_circle: "🔴",
297
+ orange_circle: "🟠",
298
+ yellow_circle: "🟡",
299
+ green_circle: "🟢",
300
+ blue_circle: "🔵",
301
+ purple_circle: "🟣",
302
+ black_circle: "⚫",
303
+ white_circle: "⚪",
304
+ red_square: "🟥",
305
+ orange_square: "🟧",
306
+ yellow_square: "🟨",
307
+ green_square: "🟩",
308
+ blue_square: "🟦",
309
+ purple_square: "🟪",
310
+ black_square: "⬛",
311
+ white_square: "⬜",
312
+ checkered_flag: "🏁",
313
+ triangular_flag: "🚩",
314
+ crossed_flags: "🎌",
315
+ pirate_flag: "🏴‍☠️",
316
+ white_flag: "🏳",
317
+ 100: "💯",
318
+ infinity: "♾",
319
+ recycle: "♻",
320
+ peace: "☮",
321
+ yin_yang: "☯",
322
+ cross: "✝",
323
+ atom: "⚛",
324
+ radioactive: "☢",
325
+ biohazard: "☣",
326
+ };
327
+ const EMOJI_PATTERN = /:([a-z0-9_]+(?:-(?:emoji|text))?):/g;
328
+ /**
329
+ * Replaces :shortcode: patterns in text with emoji characters.
330
+ */
331
+ export function emojiReplace(text, defaultVariant) {
332
+ return text.replace(EMOJI_PATTERN, (_match, code) => {
333
+ let variant = defaultVariant;
334
+ let name = code;
335
+ // Check for inline variant suffix
336
+ if (name.endsWith("-emoji")) {
337
+ variant = "emoji";
338
+ name = name.slice(0, -6);
339
+ }
340
+ else if (name.endsWith("-text")) {
341
+ variant = "text";
342
+ name = name.slice(0, -5);
343
+ }
344
+ const emoji = EMOJI[name];
345
+ if (emoji === undefined)
346
+ return _match; // Not found, leave unchanged
347
+ // Apply variant selector
348
+ // [LAW:dataflow-not-control-flow] Always compute suffix, let the value decide
349
+ const suffix = variant === "emoji"
350
+ ? "\uFE0F"
351
+ : variant === "text"
352
+ ? "\uFE0E"
353
+ : "";
354
+ return emoji + suffix;
355
+ });
356
+ }
357
+ export class NoEmoji extends Error {
358
+ constructor(name) {
359
+ super(`No emoji with name: "${name}"`);
360
+ this.name = "NoEmoji";
361
+ }
362
+ }
363
+ export class Emoji {
364
+ name;
365
+ _char;
366
+ _style;
367
+ _variant;
368
+ constructor(name, style, variant) {
369
+ const emoji = EMOJI[name];
370
+ if (emoji === undefined)
371
+ throw new NoEmoji(name);
372
+ this.name = name;
373
+ this._char = emoji;
374
+ this._style = style;
375
+ this._variant = variant;
376
+ }
377
+ toString() {
378
+ const suffix = this._variant === "emoji"
379
+ ? "\uFE0F"
380
+ : this._variant === "text"
381
+ ? "\uFE0E"
382
+ : "";
383
+ return this._char + suffix;
384
+ }
385
+ *render(_options) {
386
+ yield new Segment(this.toString(), this._style);
387
+ }
388
+ static replace(text) {
389
+ return emojiReplace(text);
390
+ }
391
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Env — the environment variables a program running on a terminal sees, as
3
+ * every public type that carries them names it.
4
+ *
5
+ * [LAW:types-are-the-program] The strongest true theorem about what this
6
+ * library does with an environment is "reads a variable by name, which may be
7
+ * unset." It never writes one, and it never touches the rest of node's
8
+ * `NodeJS.ProcessEnv`. Node's `process.env` satisfies this as-is, and so does
9
+ * a frozen literal in a browser, where there is no `process` at all.
10
+ *
11
+ * It lives here rather than being spelled `NodeJS.ProcessEnv` because a public
12
+ * signature is emitted into the `.d.ts` verbatim, and a TypeScript project
13
+ * without `@types/node` — the ordinary browser project — cannot resolve the
14
+ * `NodeJS` namespace. `test/seam/browser-types.test.ts` holds that line.
15
+ */
16
+ export type Env = Readonly<Record<string, string | undefined>>;