@svelterm/core 0.1.0 → 0.23.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 (166) hide show
  1. package/CHANGELOG.md +465 -0
  2. package/README.md +42 -29
  3. package/dist/src/cli/build.d.ts +13 -0
  4. package/dist/src/cli/build.js +119 -0
  5. package/dist/src/cli/bundle.d.ts +25 -0
  6. package/dist/src/cli/bundle.js +61 -0
  7. package/dist/src/cli/dev.d.ts +10 -0
  8. package/dist/src/cli/dev.js +152 -0
  9. package/dist/src/cli/devtools.d.ts +9 -0
  10. package/dist/src/cli/devtools.js +47 -0
  11. package/dist/src/cli/init.d.ts +8 -0
  12. package/dist/src/cli/init.js +153 -0
  13. package/dist/src/cli/main.d.ts +9 -0
  14. package/dist/src/cli/main.js +52 -0
  15. package/dist/src/cli/svt-bin.d.ts +2 -0
  16. package/dist/src/cli/svt-bin.js +6 -0
  17. package/dist/src/cli/svt.d.ts +14 -0
  18. package/dist/src/cli/svt.js +76 -0
  19. package/dist/src/components/text-buffer.js +8 -5
  20. package/dist/src/css/animation-runner.d.ts +15 -6
  21. package/dist/src/css/animation-runner.js +80 -29
  22. package/dist/src/css/animation.d.ts +12 -0
  23. package/dist/src/css/animation.js +21 -0
  24. package/dist/src/css/calc.js +4 -3
  25. package/dist/src/css/color.d.ts +19 -0
  26. package/dist/src/css/color.js +371 -62
  27. package/dist/src/css/compute.d.ts +31 -4
  28. package/dist/src/css/compute.js +273 -34
  29. package/dist/src/css/defaults.d.ts +1 -1
  30. package/dist/src/css/defaults.js +9 -0
  31. package/dist/src/css/easing.d.ts +9 -0
  32. package/dist/src/css/easing.js +95 -0
  33. package/dist/src/css/incremental.d.ts +1 -1
  34. package/dist/src/css/incremental.js +2 -2
  35. package/dist/src/css/interpolate.d.ts +13 -0
  36. package/dist/src/css/interpolate.js +41 -0
  37. package/dist/src/css/parser.js +59 -3
  38. package/dist/src/css/pseudo-elements.d.ts +9 -0
  39. package/dist/src/css/pseudo-elements.js +97 -0
  40. package/dist/src/css/selector.d.ts +17 -2
  41. package/dist/src/css/selector.js +128 -13
  42. package/dist/src/css/specificity.js +17 -6
  43. package/dist/src/css/values.d.ts +6 -1
  44. package/dist/src/css/values.js +13 -6
  45. package/dist/src/debug/context.d.ts +13 -0
  46. package/dist/src/debug/context.js +11 -0
  47. package/dist/src/debug/css.d.ts +12 -0
  48. package/dist/src/debug/css.js +28 -0
  49. package/dist/src/debug/dom.d.ts +17 -0
  50. package/dist/src/debug/dom.js +92 -0
  51. package/dist/src/devtools/DevTools.compiled.js +327 -0
  52. package/dist/src/devtools/DevTools.css.js +1 -0
  53. package/dist/src/devtools/client.d.ts +36 -0
  54. package/dist/src/devtools/client.js +76 -0
  55. package/dist/src/framelog.d.ts +54 -0
  56. package/dist/src/framelog.js +99 -0
  57. package/dist/src/headless.js +12 -4
  58. package/dist/src/index.d.ts +66 -3
  59. package/dist/src/index.js +610 -81
  60. package/dist/src/input/checkable.d.ts +8 -0
  61. package/dist/src/input/checkable.js +66 -0
  62. package/dist/src/input/details.d.ts +6 -0
  63. package/dist/src/input/details.js +34 -0
  64. package/dist/src/input/focus.d.ts +6 -0
  65. package/dist/src/input/focus.js +27 -9
  66. package/dist/src/input/keyboard.d.ts +2 -2
  67. package/dist/src/input/keyboard.js +32 -5
  68. package/dist/src/input/label.d.ts +8 -0
  69. package/dist/src/input/label.js +53 -0
  70. package/dist/src/input/modal.d.ts +9 -0
  71. package/dist/src/input/modal.js +28 -0
  72. package/dist/src/input/mouse.d.ts +2 -2
  73. package/dist/src/input/mouse.js +15 -2
  74. package/dist/src/input/select.d.ts +12 -0
  75. package/dist/src/input/select.js +63 -0
  76. package/dist/src/input/selection.d.ts +48 -0
  77. package/dist/src/input/selection.js +150 -0
  78. package/dist/src/layout/engine.d.ts +2 -0
  79. package/dist/src/layout/engine.js +1092 -142
  80. package/dist/src/layout/flex.js +4 -4
  81. package/dist/src/layout/size.js +3 -2
  82. package/dist/src/layout/text.d.ts +3 -2
  83. package/dist/src/layout/text.js +96 -17
  84. package/dist/src/layout/unicode.d.ts +20 -0
  85. package/dist/src/layout/unicode.js +121 -0
  86. package/dist/src/render/animation-clock.d.ts +57 -0
  87. package/dist/src/render/animation-clock.js +221 -0
  88. package/dist/src/render/ansi-text.d.ts +26 -0
  89. package/dist/src/render/ansi-text.js +131 -0
  90. package/dist/src/render/ansi.d.ts +18 -0
  91. package/dist/src/render/ansi.js +64 -19
  92. package/dist/src/render/border.js +166 -17
  93. package/dist/src/render/buffer.d.ts +1 -0
  94. package/dist/src/render/buffer.js +5 -2
  95. package/dist/src/render/clock.d.ts +35 -0
  96. package/dist/src/render/clock.js +67 -0
  97. package/dist/src/render/color-depth.d.ts +8 -0
  98. package/dist/src/render/color-depth.js +59 -0
  99. package/dist/src/render/context.d.ts +1 -0
  100. package/dist/src/render/context.js +17 -21
  101. package/dist/src/render/cursor-emit.d.ts +18 -0
  102. package/dist/src/render/cursor-emit.js +50 -0
  103. package/dist/src/render/diff.d.ts +12 -0
  104. package/dist/src/render/diff.js +120 -0
  105. package/dist/src/render/generation.d.ts +9 -0
  106. package/dist/src/render/generation.js +14 -0
  107. package/dist/src/render/graphics-layer.d.ts +27 -0
  108. package/dist/src/render/graphics-layer.js +86 -0
  109. package/dist/src/render/image.d.ts +27 -0
  110. package/dist/src/render/image.js +113 -0
  111. package/dist/src/render/incremental-paint.d.ts +7 -3
  112. package/dist/src/render/incremental-paint.js +52 -79
  113. package/dist/src/render/inline.d.ts +59 -0
  114. package/dist/src/render/inline.js +219 -0
  115. package/dist/src/render/kitty-graphics.d.ts +24 -0
  116. package/dist/src/render/kitty-graphics.js +58 -0
  117. package/dist/src/render/paint-text.js +68 -22
  118. package/dist/src/render/paint.d.ts +8 -1
  119. package/dist/src/render/paint.js +358 -31
  120. package/dist/src/render/png.d.ts +13 -0
  121. package/dist/src/render/png.js +145 -0
  122. package/dist/src/render/scrollbar.d.ts +8 -2
  123. package/dist/src/render/scrollbar.js +71 -14
  124. package/dist/src/render/snapshot.js +3 -1
  125. package/dist/src/renderer/default.d.ts +7 -0
  126. package/dist/src/renderer/default.js +11 -0
  127. package/dist/src/renderer/index.d.ts +8 -2
  128. package/dist/src/renderer/index.js +4 -2
  129. package/dist/src/renderer/node.d.ts +109 -0
  130. package/dist/src/renderer/node.js +165 -1
  131. package/dist/src/terminal/capabilities.d.ts +33 -0
  132. package/dist/src/terminal/capabilities.js +66 -0
  133. package/dist/src/terminal/clipboard.d.ts +9 -0
  134. package/dist/src/terminal/clipboard.js +39 -0
  135. package/dist/src/terminal/io.d.ts +82 -0
  136. package/dist/src/terminal/io.js +155 -0
  137. package/dist/src/terminal/screen.d.ts +3 -10
  138. package/dist/src/terminal/screen.js +5 -28
  139. package/dist/src/terminal/stdin-router.d.ts +8 -5
  140. package/dist/src/terminal/stdin-router.js +22 -11
  141. package/dist/src/utils/node-map.d.ts +24 -0
  142. package/dist/src/utils/node-map.js +75 -0
  143. package/dist/src/vite/config.d.ts +62 -0
  144. package/dist/src/vite/config.js +191 -0
  145. package/docs/compatibility.md +67 -0
  146. package/docs/debug/devtools.md +40 -0
  147. package/docs/debug/svt.md +50 -0
  148. package/docs/distribution.md +106 -0
  149. package/docs/elements.md +120 -0
  150. package/docs/getting-started.md +177 -0
  151. package/docs/guide/css.md +187 -0
  152. package/docs/guide/input.md +143 -0
  153. package/docs/guide/layout.md +171 -0
  154. package/docs/guide/theming.md +94 -0
  155. package/docs/how-it-works.md +115 -0
  156. package/docs/inline-mode.md +77 -0
  157. package/docs/layout.md +112 -0
  158. package/docs/motion.md +91 -0
  159. package/docs/reference/README.md +65 -0
  160. package/docs/reference/css/properties/border-corner.md +82 -0
  161. package/docs/reference/css/properties/border-style.md +168 -0
  162. package/docs/reference.md +227 -0
  163. package/docs/selectors.md +80 -0
  164. package/docs/terminal-css.md +149 -0
  165. package/docs/terminals.md +83 -0
  166. package/package.json +28 -7
@@ -0,0 +1,76 @@
1
+ /**
2
+ * svt — debug-protocol client. Connects to a `run(App, { debug: true })`
3
+ * app's WebSocket server, sends one request, prints the JSON result.
4
+ *
5
+ * svt tree # DOM.getDocument
6
+ * svt query '.card' # DOM.querySelector
7
+ * svt style <nodeId> # CSS.getComputedStyle
8
+ * svt box <nodeId> # DOM.getBoxModel
9
+ * svt console # Console.getEntries
10
+ * svt raw DOM.getDocument '{}' # any method + JSON params
11
+ *
12
+ * --port <n> debug server port (default 9444)
13
+ */
14
+ import { WebSocket } from 'ws';
15
+ export async function runSvt(argv) {
16
+ const { rest, port } = extractPort(argv);
17
+ const command = buildCommand(rest);
18
+ if (!command) {
19
+ printUsage();
20
+ process.exit(1);
21
+ }
22
+ const result = await request(port, command);
23
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
24
+ }
25
+ function buildCommand(argv) {
26
+ const [verb, ...args] = argv;
27
+ switch (verb) {
28
+ case 'tree': return { method: 'DOM.getDocument', params: {} };
29
+ case 'query': return { method: 'DOM.querySelector', params: { selector: args[0] } };
30
+ case 'style': return { method: 'CSS.getComputedStyle', params: { nodeId: Number(args[0]) } };
31
+ case 'box': return { method: 'DOM.getBoxModel', params: { nodeId: Number(args[0]) } };
32
+ case 'console': return { method: 'Console.getEntries', params: { count: Number(args[0]) || 100 } };
33
+ case 'raw': return { method: args[0], params: args[1] ? JSON.parse(args[1]) : {} };
34
+ default: return null;
35
+ }
36
+ }
37
+ function request(port, command) {
38
+ return new Promise((resolve, reject) => {
39
+ const ws = new WebSocket(`ws://127.0.0.1:${port}`);
40
+ const timer = setTimeout(() => { ws.close(); reject(new Error('timed out')); }, 3000);
41
+ ws.on('open', () => ws.send(JSON.stringify({ id: 1, ...command })));
42
+ ws.on('message', (data) => {
43
+ clearTimeout(timer);
44
+ const msg = JSON.parse(data.toString());
45
+ ws.close();
46
+ if (msg.error)
47
+ reject(new Error(msg.error.message));
48
+ else
49
+ resolve(msg.result);
50
+ });
51
+ ws.on('error', () => {
52
+ clearTimeout(timer);
53
+ reject(new Error(`cannot connect on port ${port} — run the target app with run(App, { debug: true })`));
54
+ });
55
+ });
56
+ }
57
+ function extractPort(argv) {
58
+ const rest = [];
59
+ let port = 9444;
60
+ for (let i = 0; i < argv.length; i++) {
61
+ if (argv[i] === '--port')
62
+ port = Number(argv[++i]) || port;
63
+ else
64
+ rest.push(argv[i]);
65
+ }
66
+ return { rest, port };
67
+ }
68
+ function printUsage() {
69
+ console.error(`Usage: svt <command> [--port <n>]
70
+ tree print the node tree
71
+ query <selector> find a node id by CSS selector
72
+ style <nodeId> computed style for a node
73
+ box <nodeId> layout box for a node
74
+ console [count] recent console entries
75
+ raw <method> [json] any protocol method with JSON params`);
76
+ }
@@ -1,3 +1,4 @@
1
+ import { nextGraphemeBoundary, prevGraphemeBoundary } from '../layout/unicode.js';
1
2
  export class TextBuffer {
2
3
  _text;
3
4
  _cursor;
@@ -18,16 +19,18 @@ export class TextBuffer {
18
19
  delete() {
19
20
  if (this._cursor >= this._text.length)
20
21
  return;
21
- this._text = this._text.substring(0, this._cursor) + this._text.substring(this._cursor + 1);
22
+ const end = nextGraphemeBoundary(this._text, this._cursor);
23
+ this._text = this._text.substring(0, this._cursor) + this._text.substring(end);
22
24
  }
23
25
  backspace() {
24
26
  if (this._cursor <= 0)
25
27
  return;
26
- this._text = this._text.substring(0, this._cursor - 1) + this._text.substring(this._cursor);
27
- this._cursor--;
28
+ const start = prevGraphemeBoundary(this._text, this._cursor);
29
+ this._text = this._text.substring(0, start) + this._text.substring(this._cursor);
30
+ this._cursor = start;
28
31
  }
29
- moveLeft() { this.cursor--; }
30
- moveRight() { this.cursor++; }
32
+ moveLeft() { this._cursor = prevGraphemeBoundary(this._text, this._cursor); }
33
+ moveRight() { this._cursor = nextGraphemeBoundary(this._text, this._cursor); }
31
34
  home() { this._cursor = 0; }
32
35
  end() { this._cursor = this._text.length; }
33
36
  clearToStart() {
@@ -1,17 +1,26 @@
1
1
  import type { KeyframeStop } from './parser.js';
2
- import type { ResolvedStyle } from './compute.js';
2
+ import { type ResolvedStyle } from './compute.js';
3
+ import type { Easing } from './easing.js';
3
4
  /**
4
- * Runs a CSS animation by applying keyframe properties at the current time.
5
- * Terminal animations are discrete (no interpolation between color values).
5
+ * Runs a CSS animation by applying keyframe properties at the current
6
+ * time. Colours interpolate in RGB space between stops; properties that
7
+ * cannot mix (booleans, `default` colours) switch discretely at the
8
+ * segment midpoint, matching CSS's rule for non-interpolable values.
9
+ * The easing function shapes progress within each keyframe segment,
10
+ * as animation-timing-function does in CSS.
6
11
  */
7
12
  export declare class AnimationRunner {
8
13
  private keyframes;
9
14
  private duration;
10
15
  private iterations;
11
- constructor(keyframes: KeyframeStop[], durationMs: number, iterations: number);
12
- /** Apply the appropriate keyframe declarations to a style at the given elapsed time */
16
+ private easing;
17
+ /** True when any keyframe animates a property that affects layout. */
18
+ readonly touchesLayout: boolean;
19
+ constructor(keyframes: KeyframeStop[], durationMs: number, iterations: number, easing?: Easing);
20
+ /** Apply the animation's state at the given elapsed time to a style */
13
21
  apply(style: ResolvedStyle, elapsedMs: number): void;
14
22
  isFinished(elapsedMs: number): boolean;
15
23
  private getProgress;
16
- private getKeyframeAt;
24
+ /** The keyframe pair bracketing `progress`, with position inside that segment. */
25
+ private segmentAt;
17
26
  }
@@ -1,28 +1,58 @@
1
+ import { applyDeclaration } from './compute.js';
1
2
  import { resolveColor } from './color.js';
3
+ import { lerpColor, lerpNumber } from './interpolate.js';
4
+ import { parseCellLength } from './values.js';
5
+ /** Properties whose animation only needs repaint; anything else re-layouts. */
6
+ const PAINT_ONLY_PROPERTIES = new Set([
7
+ 'color', 'background', 'background-color',
8
+ 'font-weight', 'font-style', 'text-decoration',
9
+ 'opacity', 'visibility',
10
+ ]);
2
11
  /**
3
- * Runs a CSS animation by applying keyframe properties at the current time.
4
- * Terminal animations are discrete (no interpolation between color values).
12
+ * Runs a CSS animation by applying keyframe properties at the current
13
+ * time. Colours interpolate in RGB space between stops; properties that
14
+ * cannot mix (booleans, `default` colours) switch discretely at the
15
+ * segment midpoint, matching CSS's rule for non-interpolable values.
16
+ * The easing function shapes progress within each keyframe segment,
17
+ * as animation-timing-function does in CSS.
5
18
  */
6
19
  export class AnimationRunner {
7
20
  keyframes;
8
21
  duration;
9
22
  iterations;
10
- constructor(keyframes, durationMs, iterations) {
23
+ easing;
24
+ /** True when any keyframe animates a property that affects layout. */
25
+ touchesLayout;
26
+ constructor(keyframes, durationMs, iterations, easing = t => t) {
11
27
  this.keyframes = keyframes.sort((a, b) => a.offset - b.offset);
12
28
  this.duration = durationMs;
13
29
  this.iterations = iterations;
30
+ this.easing = easing;
31
+ this.touchesLayout = this.keyframes.some(stop => stop.declarations.some(decl => !PAINT_ONLY_PROPERTIES.has(decl.property)));
14
32
  }
15
- /** Apply the appropriate keyframe declarations to a style at the given elapsed time */
33
+ /** Apply the animation's state at the given elapsed time to a style */
16
34
  apply(style, elapsedMs) {
17
35
  if (this.keyframes.length === 0 || this.duration <= 0)
18
36
  return;
19
37
  const progress = this.getProgress(elapsedMs);
20
- const kf = this.getKeyframeAt(progress);
21
- if (!kf)
22
- return;
23
- for (const decl of kf.declarations) {
38
+ const segment = this.segmentAt(progress);
39
+ const { from, to } = segment;
40
+ const localT = this.easing(segment.localT);
41
+ // Hold the earlier stop's values, then interpolate toward the next
42
+ for (const decl of from.declarations) {
24
43
  applyAnimatedProperty(style, decl);
25
44
  }
45
+ if (!to)
46
+ return;
47
+ for (const decl of to.declarations) {
48
+ const fromDecl = from.declarations.find(d => d.property === decl.property);
49
+ if (fromDecl) {
50
+ applyInterpolatedProperty(style, fromDecl, decl, localT);
51
+ }
52
+ else if (localT >= 0.5) {
53
+ applyAnimatedProperty(style, decl);
54
+ }
55
+ }
26
56
  }
27
57
  isFinished(elapsedMs) {
28
58
  if (this.iterations === Infinity)
@@ -38,35 +68,56 @@ export class AnimationRunner {
38
68
  return 1; // finished — hold at end
39
69
  return (elapsedMs % this.duration) / this.duration;
40
70
  }
41
- getKeyframeAt(progress) {
42
- // Discrete: find the last keyframe whose offset <= progress
43
- let result = null;
44
- for (const kf of this.keyframes) {
45
- if (kf.offset <= progress)
46
- result = kf;
71
+ /** The keyframe pair bracketing `progress`, with position inside that segment. */
72
+ segmentAt(progress) {
73
+ let index = 0;
74
+ for (let i = 0; i < this.keyframes.length; i++) {
75
+ if (this.keyframes[i].offset <= progress)
76
+ index = i;
47
77
  else
48
78
  break;
49
79
  }
50
- return result ?? this.keyframes[0];
80
+ const from = this.keyframes[index];
81
+ const to = this.keyframes[index + 1] ?? null;
82
+ if (!to)
83
+ return { from, to: null, localT: 0 };
84
+ const span = to.offset - from.offset;
85
+ const localT = span > 0 ? (progress - from.offset) / span : 1;
86
+ return { from, to, localT };
51
87
  }
52
88
  }
53
89
  function applyAnimatedProperty(style, decl) {
54
- switch (decl.property) {
55
- case 'color':
56
- style.fg = resolveColor(decl.value);
90
+ applyDeclaration(style, decl.property, decl.value);
91
+ }
92
+ function applyInterpolatedProperty(style, from, to, t) {
93
+ switch (to.property) {
94
+ case 'color': {
95
+ const mixed = lerpColor(resolveColor(from.value), resolveColor(to.value), t);
96
+ if (mixed !== null) {
97
+ style.fg = mixed;
98
+ return;
99
+ }
57
100
  break;
101
+ }
58
102
  case 'background-color':
59
- case 'background':
60
- style.bg = resolveColor(decl.value);
61
- break;
62
- case 'font-weight':
63
- style.bold = decl.value === 'bold' || parseInt(decl.value) >= 700;
64
- break;
65
- case 'font-style':
66
- style.italic = decl.value === 'italic';
67
- break;
68
- case 'opacity':
69
- style.dim = decl.value === 'dim' || (parseFloat(decl.value) < 1);
103
+ case 'background': {
104
+ const mixed = lerpColor(resolveColor(from.value), resolveColor(to.value), t);
105
+ if (mixed !== null) {
106
+ style.bg = mixed;
107
+ return;
108
+ }
70
109
  break;
110
+ }
111
+ default: {
112
+ // Single cell/ch lengths interpolate; everything else is discrete
113
+ const a = parseCellLength(from.value);
114
+ const b = parseCellLength(to.value);
115
+ if (a !== null && b !== null) {
116
+ applyDeclaration(style, to.property, `${lerpNumber(a, b, t)}cell`);
117
+ return;
118
+ }
119
+ }
71
120
  }
121
+ // Non-interpolable (booleans, keywords, default colours): discrete at the midpoint
122
+ applyAnimatedProperty(style, t >= 0.5 ? to : from);
72
123
  }
@@ -3,3 +3,15 @@ import type { CSSStyleSheet, KeyframeStop } from './parser.js';
3
3
  * Extract keyframe definitions from a parsed stylesheet.
4
4
  */
5
5
  export declare function getKeyframes(sheet: CSSStyleSheet): Map<string, KeyframeStop[]>;
6
+ /** Context for resolving var()/light-dark() inside keyframe declarations. */
7
+ export interface KeyframeResolution {
8
+ /** Per-node custom properties, as collectVariables produces. */
9
+ variables: Map<number, Map<string, string>>;
10
+ scheme: 'dark' | 'light';
11
+ }
12
+ /**
13
+ * Resolve var() and light-dark() in keyframe values against the animated
14
+ * element. Resolution happens once when the animation starts; later
15
+ * custom-property changes don't retarget a running animation.
16
+ */
17
+ export declare function resolveKeyframeStops(stops: KeyframeStop[], resolution: KeyframeResolution, nodeId: number): KeyframeStop[];
@@ -1,6 +1,27 @@
1
+ import { expandLightDark } from './color.js';
2
+ import { resolveVar } from './variables.js';
1
3
  /**
2
4
  * Extract keyframe definitions from a parsed stylesheet.
3
5
  */
4
6
  export function getKeyframes(sheet) {
5
7
  return sheet.keyframes;
6
8
  }
9
+ /**
10
+ * Resolve var() and light-dark() in keyframe values against the animated
11
+ * element. Resolution happens once when the animation starts; later
12
+ * custom-property changes don't retarget a running animation.
13
+ */
14
+ export function resolveKeyframeStops(stops, resolution, nodeId) {
15
+ const vars = resolution.variables.get(nodeId) ?? new Map();
16
+ return stops.map(stop => ({
17
+ offset: stop.offset,
18
+ declarations: stop.declarations.map(decl => {
19
+ let value = decl.value;
20
+ if (value.includes('var('))
21
+ value = resolveVar(value, vars);
22
+ if (value.includes('light-dark('))
23
+ value = expandLightDark(value, resolution.scheme);
24
+ return { property: decl.property, value };
25
+ }),
26
+ }));
27
+ }
@@ -1,3 +1,4 @@
1
+ import { parseCellLength } from './values.js';
1
2
  /**
2
3
  * Evaluate CSS math functions: calc(), min(), max(), clamp().
3
4
  * Returns the computed cell value, or null if the input is not a math function.
@@ -100,9 +101,9 @@ function resolveValue(value, available) {
100
101
  if (trimmed.endsWith('%')) {
101
102
  return available * parseFloat(trimmed) / 100;
102
103
  }
103
- if (trimmed.endsWith('cell')) {
104
- return parseFloat(trimmed);
105
- }
104
+ const cellLength = parseCellLength(trimmed);
105
+ if (cellLength !== null)
106
+ return cellLength;
106
107
  // Bare number (for multipliers like * 2)
107
108
  const num = parseFloat(trimmed);
108
109
  return isNaN(num) ? 0 : num;
@@ -1 +1,20 @@
1
+ /**
2
+ * CSS Color Level 4 parser and resolver.
3
+ *
4
+ * Supports: hex (#rgb, #rrggbb, #rrggbbaa), rgb(), hsl(), hwb(),
5
+ * lab(), lch(), oklab(), oklch(), named colours, transparent,
6
+ * light-dark(a, b) (resolved against the active colorScheme).
7
+ * Both legacy comma syntax and modern space + / alpha syntax.
8
+ */
9
+ /**
10
+ * Expand `light-dark(a, b)` to whichever side matches the active scheme.
11
+ * Recursive on the chosen side so `light-dark(light-dark(...), x)` works.
12
+ * Returns the input unchanged when no light-dark() call is present.
13
+ */
14
+ export declare function expandLightDark(value: string, scheme?: 'dark' | 'light'): string;
1
15
  export declare function resolveColor(value: string): string;
16
+ /**
17
+ * Composite an alpha colour (#rrggbbaa) over a base colour, returning
18
+ * opaque #rrggbb. Opaque over-colours return unchanged.
19
+ */
20
+ export declare function blendColor(under: string, over: string): string;