@svelterm/core 0.1.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +425 -0
- package/README.md +42 -29
- package/dist/src/cli/build.d.ts +13 -0
- package/dist/src/cli/build.js +119 -0
- package/dist/src/cli/bundle.d.ts +25 -0
- package/dist/src/cli/bundle.js +61 -0
- package/dist/src/cli/dev.d.ts +10 -0
- package/dist/src/cli/dev.js +152 -0
- package/dist/src/cli/devtools.d.ts +9 -0
- package/dist/src/cli/devtools.js +47 -0
- package/dist/src/cli/init.d.ts +8 -0
- package/dist/src/cli/init.js +153 -0
- package/dist/src/cli/main.d.ts +9 -0
- package/dist/src/cli/main.js +52 -0
- package/dist/src/cli/svt-bin.d.ts +2 -0
- package/dist/src/cli/svt-bin.js +6 -0
- package/dist/src/cli/svt.d.ts +14 -0
- package/dist/src/cli/svt.js +76 -0
- package/dist/src/components/text-buffer.js +8 -5
- package/dist/src/css/animation-runner.d.ts +15 -6
- package/dist/src/css/animation-runner.js +80 -29
- package/dist/src/css/animation.d.ts +12 -0
- package/dist/src/css/animation.js +21 -0
- package/dist/src/css/calc.js +4 -3
- package/dist/src/css/color.d.ts +19 -0
- package/dist/src/css/color.js +371 -62
- package/dist/src/css/compute.d.ts +30 -3
- package/dist/src/css/compute.js +272 -33
- package/dist/src/css/defaults.d.ts +1 -1
- package/dist/src/css/defaults.js +9 -0
- package/dist/src/css/easing.d.ts +9 -0
- package/dist/src/css/easing.js +95 -0
- package/dist/src/css/incremental.d.ts +1 -1
- package/dist/src/css/incremental.js +2 -2
- package/dist/src/css/interpolate.d.ts +13 -0
- package/dist/src/css/interpolate.js +41 -0
- package/dist/src/css/parser.js +59 -3
- package/dist/src/css/pseudo-elements.d.ts +9 -0
- package/dist/src/css/pseudo-elements.js +97 -0
- package/dist/src/css/selector.d.ts +17 -2
- package/dist/src/css/selector.js +128 -13
- package/dist/src/css/specificity.js +17 -6
- package/dist/src/css/values.d.ts +6 -1
- package/dist/src/css/values.js +13 -6
- package/dist/src/debug/context.d.ts +13 -0
- package/dist/src/debug/context.js +11 -0
- package/dist/src/debug/css.d.ts +12 -0
- package/dist/src/debug/css.js +28 -0
- package/dist/src/debug/dom.d.ts +17 -0
- package/dist/src/debug/dom.js +92 -0
- package/dist/src/devtools/DevTools.compiled.js +327 -0
- package/dist/src/devtools/DevTools.css.js +1 -0
- package/dist/src/devtools/client.d.ts +36 -0
- package/dist/src/devtools/client.js +76 -0
- package/dist/src/framelog.d.ts +54 -0
- package/dist/src/framelog.js +99 -0
- package/dist/src/headless.js +12 -4
- package/dist/src/index.d.ts +65 -3
- package/dist/src/index.js +609 -81
- package/dist/src/input/checkable.d.ts +8 -0
- package/dist/src/input/checkable.js +66 -0
- package/dist/src/input/details.d.ts +6 -0
- package/dist/src/input/details.js +34 -0
- package/dist/src/input/focus.d.ts +6 -0
- package/dist/src/input/focus.js +27 -9
- package/dist/src/input/keyboard.d.ts +2 -2
- package/dist/src/input/keyboard.js +32 -5
- package/dist/src/input/label.d.ts +8 -0
- package/dist/src/input/label.js +53 -0
- package/dist/src/input/modal.d.ts +9 -0
- package/dist/src/input/modal.js +28 -0
- package/dist/src/input/mouse.d.ts +2 -2
- package/dist/src/input/mouse.js +15 -2
- package/dist/src/input/select.d.ts +12 -0
- package/dist/src/input/select.js +63 -0
- package/dist/src/input/selection.d.ts +48 -0
- package/dist/src/input/selection.js +150 -0
- package/dist/src/layout/engine.d.ts +2 -0
- package/dist/src/layout/engine.js +1084 -142
- package/dist/src/layout/flex.js +4 -4
- package/dist/src/layout/size.js +3 -2
- package/dist/src/layout/text.d.ts +3 -2
- package/dist/src/layout/text.js +96 -17
- package/dist/src/layout/unicode.d.ts +20 -0
- package/dist/src/layout/unicode.js +121 -0
- package/dist/src/render/animation-clock.d.ts +51 -0
- package/dist/src/render/animation-clock.js +213 -0
- package/dist/src/render/ansi-text.d.ts +26 -0
- package/dist/src/render/ansi-text.js +131 -0
- package/dist/src/render/ansi.d.ts +18 -0
- package/dist/src/render/ansi.js +64 -19
- package/dist/src/render/border.js +166 -17
- package/dist/src/render/buffer.d.ts +1 -0
- package/dist/src/render/buffer.js +5 -2
- package/dist/src/render/color-depth.d.ts +8 -0
- package/dist/src/render/color-depth.js +59 -0
- package/dist/src/render/context.d.ts +1 -0
- package/dist/src/render/context.js +17 -21
- package/dist/src/render/cursor-emit.d.ts +18 -0
- package/dist/src/render/cursor-emit.js +50 -0
- package/dist/src/render/diff.d.ts +12 -0
- package/dist/src/render/diff.js +120 -0
- package/dist/src/render/generation.d.ts +9 -0
- package/dist/src/render/generation.js +14 -0
- package/dist/src/render/graphics-layer.d.ts +27 -0
- package/dist/src/render/graphics-layer.js +86 -0
- package/dist/src/render/image.d.ts +27 -0
- package/dist/src/render/image.js +113 -0
- package/dist/src/render/incremental-paint.d.ts +7 -3
- package/dist/src/render/incremental-paint.js +52 -79
- package/dist/src/render/inline.d.ts +59 -0
- package/dist/src/render/inline.js +219 -0
- package/dist/src/render/kitty-graphics.d.ts +24 -0
- package/dist/src/render/kitty-graphics.js +58 -0
- package/dist/src/render/paint-text.js +68 -22
- package/dist/src/render/paint.d.ts +8 -1
- package/dist/src/render/paint.js +328 -30
- package/dist/src/render/png.d.ts +13 -0
- package/dist/src/render/png.js +145 -0
- package/dist/src/render/scrollbar.d.ts +8 -2
- package/dist/src/render/scrollbar.js +71 -14
- package/dist/src/render/snapshot.js +3 -1
- package/dist/src/renderer/default.d.ts +7 -0
- package/dist/src/renderer/default.js +11 -0
- package/dist/src/renderer/index.d.ts +8 -2
- package/dist/src/renderer/index.js +4 -2
- package/dist/src/renderer/node.d.ts +109 -0
- package/dist/src/renderer/node.js +165 -1
- package/dist/src/terminal/capabilities.d.ts +33 -0
- package/dist/src/terminal/capabilities.js +66 -0
- package/dist/src/terminal/clipboard.d.ts +9 -0
- package/dist/src/terminal/clipboard.js +39 -0
- package/dist/src/terminal/io.d.ts +82 -0
- package/dist/src/terminal/io.js +155 -0
- package/dist/src/terminal/screen.d.ts +3 -10
- package/dist/src/terminal/screen.js +5 -28
- package/dist/src/terminal/stdin-router.d.ts +8 -5
- package/dist/src/terminal/stdin-router.js +22 -11
- package/dist/src/utils/node-map.d.ts +24 -0
- package/dist/src/utils/node-map.js +75 -0
- package/dist/src/vite/config.d.ts +62 -0
- package/dist/src/vite/config.js +191 -0
- package/docs/compatibility.md +67 -0
- package/docs/debug/devtools.md +40 -0
- package/docs/debug/svt.md +50 -0
- package/docs/distribution.md +106 -0
- package/docs/elements.md +120 -0
- package/docs/getting-started.md +177 -0
- package/docs/guide/css.md +187 -0
- package/docs/guide/input.md +143 -0
- package/docs/guide/layout.md +171 -0
- package/docs/guide/theming.md +94 -0
- package/docs/how-it-works.md +115 -0
- package/docs/inline-mode.md +77 -0
- package/docs/layout.md +106 -0
- package/docs/motion.md +91 -0
- package/docs/reference/README.md +65 -0
- package/docs/reference/css/properties/border-corner.md +82 -0
- package/docs/reference/css/properties/border-style.md +168 -0
- package/docs/reference.md +226 -0
- package/docs/selectors.md +80 -0
- package/docs/terminal-css.md +149 -0
- package/docs/terminals.md +83 -0
- package/package.json +28 -7
package/dist/src/css/compute.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { NodeMap } from '../utils/node-map.js';
|
|
2
|
+
import { resolvePseudoElements } from './pseudo-elements.js';
|
|
1
3
|
import { matchesSelector } from './selector.js';
|
|
2
|
-
import { resolveColor } from './color.js';
|
|
4
|
+
import { resolveColor, expandLightDark } from './color.js';
|
|
3
5
|
import { parseCellValue, parseSizeValue, parseJustify, parseAlign } from './values.js';
|
|
4
6
|
import { collectVariables, resolveVar } from './variables.js';
|
|
5
7
|
import { computeSpecificity, compareSpecificity } from './specificity.js';
|
|
@@ -13,7 +15,15 @@ const DEFAULT_MEDIA = {
|
|
|
13
15
|
};
|
|
14
16
|
const INLINE_ELEMENTS = new Set(['span', 'a', 'strong', 'em', 'b', 'i', 'u', 'code', 'small', 'sub', 'sup']);
|
|
15
17
|
const TABLE_ELEMENTS = {
|
|
16
|
-
table: 'table',
|
|
18
|
+
table: 'table',
|
|
19
|
+
tr: 'table-row',
|
|
20
|
+
td: 'table-cell', th: 'table-cell',
|
|
21
|
+
thead: 'table-header-group',
|
|
22
|
+
tbody: 'table-row-group',
|
|
23
|
+
tfoot: 'table-footer-group',
|
|
24
|
+
caption: 'table-caption',
|
|
25
|
+
colgroup: 'table-column-group',
|
|
26
|
+
col: 'table-column',
|
|
17
27
|
};
|
|
18
28
|
function defaultDisplay(tag) {
|
|
19
29
|
if (!tag)
|
|
@@ -25,49 +35,68 @@ function defaultDisplay(tag) {
|
|
|
25
35
|
return 'block';
|
|
26
36
|
}
|
|
27
37
|
export function defaultStyle(tag) {
|
|
38
|
+
const defaultPaddingLeft = tag === 'ul' ? 2 : tag === 'ol' ? 4 : 0;
|
|
28
39
|
return {
|
|
29
40
|
fg: 'default', bg: 'default',
|
|
30
41
|
bold: false, italic: false, underline: false, strikethrough: false, dim: false,
|
|
31
42
|
display: defaultDisplay(tag),
|
|
32
43
|
flexDirection: 'row',
|
|
33
|
-
justifyContent: 'start', alignItems: '
|
|
44
|
+
justifyContent: 'start', alignItems: 'stretch', alignSelf: 'auto',
|
|
34
45
|
gap: 0,
|
|
35
|
-
paddingTop: 0, paddingRight: 0, paddingBottom: 0, paddingLeft:
|
|
46
|
+
paddingTop: 0, paddingRight: 0, paddingBottom: 0, paddingLeft: defaultPaddingLeft,
|
|
36
47
|
width: null, height: null,
|
|
37
48
|
minWidth: null, minHeight: null, maxWidth: null, maxHeight: null,
|
|
38
49
|
marginTop: 0, marginRight: 0, marginBottom: 0, marginLeft: 0,
|
|
39
50
|
flexGrow: 0, flexShrink: 1, flexBasis: 'auto', flexWrap: 'nowrap', order: 0,
|
|
40
51
|
gridTemplateColumns: null, gridTemplateRows: null,
|
|
52
|
+
gridColumnStart: null, gridColumnEnd: null, gridColumnSpan: null,
|
|
53
|
+
gridRowStart: null, gridRowEnd: null, gridRowSpan: null,
|
|
54
|
+
gridTemplateAreas: null, gridArea: null,
|
|
41
55
|
animationName: null, animationDuration: 0, animationIterationCount: 1,
|
|
42
|
-
|
|
56
|
+
animationTimingFunction: 'ease',
|
|
57
|
+
transitionProperty: null, transitionDuration: 0,
|
|
58
|
+
transitionTimingFunction: 'ease',
|
|
59
|
+
borderStyle: 'none', borderColor: 'default', borderCorner: 'none',
|
|
43
60
|
borderTop: true, borderRight: true, borderBottom: true, borderLeft: true,
|
|
61
|
+
boxSizing: 'border-box',
|
|
44
62
|
overflow: 'visible',
|
|
45
63
|
textOverflow: 'clip',
|
|
46
64
|
whiteSpace: 'normal',
|
|
47
|
-
|
|
65
|
+
wordBreak: 'normal',
|
|
66
|
+
opacity: 1,
|
|
67
|
+
textAlign: tag === 'button' ? 'center' : 'left',
|
|
68
|
+
textTransform: 'none',
|
|
48
69
|
position: 'static',
|
|
49
70
|
top: null, right: null, bottom: null, left: null,
|
|
50
71
|
zIndex: 0,
|
|
51
72
|
visibility: 'visible',
|
|
73
|
+
captionSide: 'top',
|
|
74
|
+
tableLayout: 'auto',
|
|
75
|
+
verticalAlign: 'top',
|
|
76
|
+
borderCollapse: 'separate',
|
|
77
|
+
borderSpacingH: 0,
|
|
78
|
+
borderSpacingV: 0,
|
|
79
|
+
emptyCells: 'show',
|
|
52
80
|
};
|
|
53
81
|
}
|
|
54
82
|
export function resolveStyles(root, stylesheet, media, availWidth, availHeight) {
|
|
55
83
|
const hasContainerRules = stylesheet.rules.some(r => r.container);
|
|
56
84
|
// Filter by media if context provided; always filter @supports
|
|
57
85
|
const filtered = media ? filterByMedia(stylesheet, media) : filterSupports(stylesheet);
|
|
86
|
+
const scheme = media?.colorScheme ?? 'dark';
|
|
58
87
|
if (!hasContainerRules) {
|
|
59
88
|
// Simple path: no container queries
|
|
60
89
|
const variables = collectVariables(root, filtered);
|
|
61
|
-
const styles = new
|
|
62
|
-
resolveNode(root, filtered, styles, variables);
|
|
90
|
+
const styles = new NodeMap();
|
|
91
|
+
resolveNode(root, filtered, styles, variables, scheme);
|
|
63
92
|
return styles;
|
|
64
93
|
}
|
|
65
94
|
// Two-pass for container queries:
|
|
66
95
|
// Pass 1: resolve without @container rules to get initial layout
|
|
67
96
|
const withoutContainer = filterContainerRules(filtered, false);
|
|
68
97
|
const variables1 = collectVariables(root, withoutContainer);
|
|
69
|
-
const styles1 = new
|
|
70
|
-
resolveNode(root, withoutContainer, styles1, variables1);
|
|
98
|
+
const styles1 = new NodeMap();
|
|
99
|
+
resolveNode(root, withoutContainer, styles1, variables1, scheme);
|
|
71
100
|
// Compute layout to get container dimensions
|
|
72
101
|
const layout = computeLayout(root, styles1, availWidth ?? media?.width ?? 80, availHeight ?? media?.height ?? 24);
|
|
73
102
|
// Pass 2: evaluate container rules against computed layout
|
|
@@ -81,8 +110,8 @@ export function resolveStyles(root, stylesheet, media, availWidth, availHeight)
|
|
|
81
110
|
keyframes: filtered.keyframes,
|
|
82
111
|
};
|
|
83
112
|
const variables2 = collectVariables(root, withMatchingContainers);
|
|
84
|
-
const styles2 = new
|
|
85
|
-
resolveNode(root, withMatchingContainers, styles2, variables2);
|
|
113
|
+
const styles2 = new NodeMap();
|
|
114
|
+
resolveNode(root, withMatchingContainers, styles2, variables2, scheme);
|
|
86
115
|
return styles2;
|
|
87
116
|
}
|
|
88
117
|
function filterSupports(stylesheet) {
|
|
@@ -106,14 +135,15 @@ export function filterByMedia(stylesheet, context) {
|
|
|
106
135
|
const SUPPORTED_PROPERTIES = new Set([
|
|
107
136
|
'display', 'flex-direction', 'justify-content', 'align-items', 'align-self',
|
|
108
137
|
'gap', 'flex-grow', 'flex-shrink', 'flex-wrap', 'flex', 'order',
|
|
109
|
-
'grid-template-columns',
|
|
138
|
+
'grid-template-columns', 'grid-column',
|
|
110
139
|
'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
|
|
111
140
|
'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
|
|
112
141
|
'width', 'height', 'min-width', 'min-height', 'max-width', 'max-height',
|
|
113
142
|
'color', 'background-color', 'background',
|
|
114
|
-
'font-weight', 'font-style', 'text-decoration', 'text-align', 'text-overflow',
|
|
115
|
-
'white-space', 'overflow', 'visibility', 'opacity',
|
|
116
|
-
'border', 'border-style', 'border-color',
|
|
143
|
+
'font-weight', 'font-style', 'text-decoration', 'text-align', 'text-overflow', 'text-transform',
|
|
144
|
+
'white-space', 'word-break', 'overflow', 'visibility', 'opacity',
|
|
145
|
+
'border', 'border-style', 'border-color', 'border-corner',
|
|
146
|
+
'box-sizing',
|
|
117
147
|
'position', 'top', 'right', 'bottom', 'left', 'z-index',
|
|
118
148
|
]);
|
|
119
149
|
function filterContainerRules(stylesheet, include) {
|
|
@@ -174,20 +204,21 @@ function evaluateSupports(condition) {
|
|
|
174
204
|
const property = condition.substring(0, colonIdx).trim();
|
|
175
205
|
return SUPPORTED_PROPERTIES.has(property);
|
|
176
206
|
}
|
|
177
|
-
export function resolveNode(node, stylesheet, styles, variables) {
|
|
207
|
+
export function resolveNode(node, stylesheet, styles, variables, scheme = 'dark') {
|
|
178
208
|
if (node.nodeType === 'element') {
|
|
179
209
|
const vars = variables.get(node.id) ?? new Map();
|
|
180
210
|
const parentStyle = node.parent ? styles.get(node.parent.id) : undefined;
|
|
181
|
-
const resolved = computeStyle(node, stylesheet, vars, parentStyle);
|
|
211
|
+
const resolved = computeStyle(node, stylesheet, vars, parentStyle, scheme);
|
|
182
212
|
styles.set(node.id, resolved);
|
|
183
213
|
node.cache.resolvedStyle = resolved;
|
|
184
214
|
node.cache.classAttr = node.attributes.get('class') ?? '';
|
|
215
|
+
resolvePseudoElements(node, stylesheet, styles, vars, scheme);
|
|
185
216
|
}
|
|
186
217
|
for (const child of node.children) {
|
|
187
|
-
resolveNode(child, stylesheet, styles, variables);
|
|
218
|
+
resolveNode(child, stylesheet, styles, variables, scheme);
|
|
188
219
|
}
|
|
189
220
|
}
|
|
190
|
-
function computeStyle(node, stylesheet, vars, parentStyle) {
|
|
221
|
+
function computeStyle(node, stylesheet, vars, parentStyle, scheme = 'dark') {
|
|
191
222
|
const style = defaultStyle(node.tag);
|
|
192
223
|
// Collect all matching declarations with specificity
|
|
193
224
|
const scored = [];
|
|
@@ -231,14 +262,34 @@ function computeStyle(node, stylesheet, vars, parentStyle) {
|
|
|
231
262
|
}
|
|
232
263
|
}
|
|
233
264
|
else {
|
|
234
|
-
applyDeclaration(style, decl.property, decl.value);
|
|
265
|
+
applyDeclaration(style, decl.property, decl.value, scheme);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Inline style="..." attribute — applied last (higher than any selector specificity)
|
|
269
|
+
const inline = node.attributes?.get('style');
|
|
270
|
+
if (inline) {
|
|
271
|
+
for (const decl of parseInlineStyle(inline)) {
|
|
272
|
+
applyDeclaration(style, decl.property, resolveVar(decl.value, vars), scheme);
|
|
235
273
|
}
|
|
236
274
|
}
|
|
237
275
|
return style;
|
|
238
276
|
}
|
|
277
|
+
function parseInlineStyle(text) {
|
|
278
|
+
const result = [];
|
|
279
|
+
for (const part of text.split(';')) {
|
|
280
|
+
const colon = part.indexOf(':');
|
|
281
|
+
if (colon < 0)
|
|
282
|
+
continue;
|
|
283
|
+
const property = part.slice(0, colon).trim().toLowerCase();
|
|
284
|
+
const value = part.slice(colon + 1).trim();
|
|
285
|
+
if (property && value)
|
|
286
|
+
result.push({ property, value });
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
239
290
|
const INHERITABLE_PROPERTIES = new Set([
|
|
240
291
|
'color', 'font-weight', 'font-style', 'text-decoration',
|
|
241
|
-
'white-space', 'text-align', 'visibility', 'opacity',
|
|
292
|
+
'white-space', 'word-break', 'text-align', 'visibility', 'opacity',
|
|
242
293
|
]);
|
|
243
294
|
function applyInherit(style, property, parentStyle) {
|
|
244
295
|
switch (property) {
|
|
@@ -262,14 +313,21 @@ function applyInherit(style, property, parentStyle) {
|
|
|
262
313
|
case 'white-space':
|
|
263
314
|
style.whiteSpace = parentStyle.whiteSpace;
|
|
264
315
|
break;
|
|
316
|
+
case 'word-break':
|
|
317
|
+
style.wordBreak = parentStyle.wordBreak;
|
|
318
|
+
break;
|
|
265
319
|
case 'text-align':
|
|
266
320
|
style.textAlign = parentStyle.textAlign;
|
|
267
321
|
break;
|
|
322
|
+
case 'text-transform':
|
|
323
|
+
style.textTransform = parentStyle.textTransform;
|
|
324
|
+
break;
|
|
268
325
|
case 'visibility':
|
|
269
326
|
style.visibility = parentStyle.visibility;
|
|
270
327
|
break;
|
|
271
328
|
case 'opacity':
|
|
272
329
|
style.dim = parentStyle.dim;
|
|
330
|
+
style.opacity = parentStyle.opacity;
|
|
273
331
|
break;
|
|
274
332
|
}
|
|
275
333
|
}
|
|
@@ -295,14 +353,17 @@ function applyInitial(style, property, tag) {
|
|
|
295
353
|
break;
|
|
296
354
|
}
|
|
297
355
|
}
|
|
298
|
-
function applyDeclaration(style, property, value) {
|
|
356
|
+
export function applyDeclaration(style, property, value, scheme = 'dark') {
|
|
357
|
+
// light-dark(a, b) is valid wherever a colour is — expand once at the
|
|
358
|
+
// top so the property-specific branches don't each have to know about it.
|
|
359
|
+
const v = value.includes('light-dark(') ? expandLightDark(value, scheme) : value;
|
|
299
360
|
switch (property) {
|
|
300
361
|
case 'color':
|
|
301
|
-
style.fg = resolveColor(
|
|
362
|
+
style.fg = resolveColor(v);
|
|
302
363
|
break;
|
|
303
364
|
case 'background-color':
|
|
304
365
|
case 'background':
|
|
305
|
-
style.bg = resolveColor(
|
|
366
|
+
style.bg = resolveColor(v);
|
|
306
367
|
break;
|
|
307
368
|
case 'font-weight':
|
|
308
369
|
style.bold = value === 'bold' || parseInt(value) >= 700;
|
|
@@ -317,7 +378,14 @@ function applyDeclaration(style, property, value) {
|
|
|
317
378
|
style.strikethrough = true;
|
|
318
379
|
break;
|
|
319
380
|
case 'display':
|
|
320
|
-
if ([
|
|
381
|
+
if ([
|
|
382
|
+
'block', 'inline', 'inline-block', 'flex', 'grid',
|
|
383
|
+
'table', 'inline-table',
|
|
384
|
+
'table-row', 'table-cell',
|
|
385
|
+
'table-row-group', 'table-header-group', 'table-footer-group',
|
|
386
|
+
'table-caption', 'table-column-group', 'table-column',
|
|
387
|
+
'none', 'contents',
|
|
388
|
+
].includes(value)) {
|
|
321
389
|
style.display = value;
|
|
322
390
|
}
|
|
323
391
|
break;
|
|
@@ -416,6 +484,10 @@ function applyDeclaration(style, property, value) {
|
|
|
416
484
|
}
|
|
417
485
|
break;
|
|
418
486
|
}
|
|
487
|
+
case 'box-sizing':
|
|
488
|
+
if (value === 'border-box' || value === 'content-box')
|
|
489
|
+
style.boxSizing = value;
|
|
490
|
+
break;
|
|
419
491
|
case 'margin-top':
|
|
420
492
|
style.marginTop = value === 'auto' ? -1 : parseSizeOrCell(value);
|
|
421
493
|
break;
|
|
@@ -459,15 +531,52 @@ function applyDeclaration(style, property, value) {
|
|
|
459
531
|
case 'grid-template-rows':
|
|
460
532
|
style.gridTemplateRows = value;
|
|
461
533
|
break;
|
|
534
|
+
case 'grid-column': {
|
|
535
|
+
const line = parseGridLine(value);
|
|
536
|
+
style.gridColumnStart = line.start;
|
|
537
|
+
style.gridColumnEnd = line.end;
|
|
538
|
+
if (line.span !== null)
|
|
539
|
+
style.gridColumnSpan = line.span;
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
case 'grid-row': {
|
|
543
|
+
const line = parseGridLine(value);
|
|
544
|
+
style.gridRowStart = line.start;
|
|
545
|
+
style.gridRowEnd = line.end;
|
|
546
|
+
if (line.span !== null)
|
|
547
|
+
style.gridRowSpan = line.span;
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case 'grid-template-areas':
|
|
551
|
+
style.gridTemplateAreas = value === 'none' ? null : value;
|
|
552
|
+
break;
|
|
553
|
+
case 'grid-area':
|
|
554
|
+
parseGridArea(style, value);
|
|
555
|
+
break;
|
|
462
556
|
case 'animation':
|
|
463
557
|
parseAnimationShorthand(style, value);
|
|
464
558
|
break;
|
|
559
|
+
case 'transition':
|
|
560
|
+
parseTransitionShorthand(style, value);
|
|
561
|
+
break;
|
|
562
|
+
case 'transition-property':
|
|
563
|
+
style.transitionProperty = value === 'none' ? null : value;
|
|
564
|
+
break;
|
|
565
|
+
case 'transition-duration':
|
|
566
|
+
style.transitionDuration = parseDuration(value);
|
|
567
|
+
break;
|
|
568
|
+
case 'transition-timing-function':
|
|
569
|
+
style.transitionTimingFunction = value;
|
|
570
|
+
break;
|
|
465
571
|
case 'animation-name':
|
|
466
572
|
style.animationName = value === 'none' ? null : value;
|
|
467
573
|
break;
|
|
468
574
|
case 'animation-duration':
|
|
469
575
|
style.animationDuration = parseDuration(value);
|
|
470
576
|
break;
|
|
577
|
+
case 'animation-timing-function':
|
|
578
|
+
style.animationTimingFunction = value;
|
|
579
|
+
break;
|
|
471
580
|
case 'animation-iteration-count':
|
|
472
581
|
style.animationIterationCount = value === 'infinite' ? Infinity : (parseInt(value) || 1);
|
|
473
582
|
break;
|
|
@@ -480,7 +589,11 @@ function applyDeclaration(style, property, value) {
|
|
|
480
589
|
style.borderStyle = value;
|
|
481
590
|
break;
|
|
482
591
|
case 'border-color':
|
|
483
|
-
style.borderColor = value === 'currentColor' ? style.fg : resolveColor(
|
|
592
|
+
style.borderColor = value === 'currentColor' ? style.fg : resolveColor(v);
|
|
593
|
+
break;
|
|
594
|
+
case 'border-corner':
|
|
595
|
+
if (value === 'h' || value === 'v' || value === 'none')
|
|
596
|
+
style.borderCorner = value;
|
|
484
597
|
break;
|
|
485
598
|
case 'border-top':
|
|
486
599
|
setIndividualBorderSide(style, 'borderTop', value);
|
|
@@ -510,12 +623,21 @@ function applyDeclaration(style, property, value) {
|
|
|
510
623
|
else
|
|
511
624
|
style.whiteSpace = 'normal';
|
|
512
625
|
break;
|
|
626
|
+
case 'word-break':
|
|
627
|
+
style.wordBreak = value === 'break-all' ? 'break-all' : 'normal';
|
|
628
|
+
break;
|
|
513
629
|
case 'text-align':
|
|
514
630
|
if (value === 'center' || value === 'right')
|
|
515
631
|
style.textAlign = value;
|
|
516
632
|
else
|
|
517
633
|
style.textAlign = 'left';
|
|
518
634
|
break;
|
|
635
|
+
case 'text-transform':
|
|
636
|
+
if (value === 'uppercase' || value === 'lowercase' || value === 'capitalize')
|
|
637
|
+
style.textTransform = value;
|
|
638
|
+
else
|
|
639
|
+
style.textTransform = 'none';
|
|
640
|
+
break;
|
|
519
641
|
case 'position':
|
|
520
642
|
if (value === 'relative' || value === 'absolute' || value === 'fixed')
|
|
521
643
|
style.position = value;
|
|
@@ -540,18 +662,48 @@ function applyDeclaration(style, property, value) {
|
|
|
540
662
|
case 'visibility':
|
|
541
663
|
style.visibility = value === 'hidden' ? 'hidden' : 'visible';
|
|
542
664
|
break;
|
|
665
|
+
case 'caption-side':
|
|
666
|
+
style.captionSide = value === 'bottom' ? 'bottom' : 'top';
|
|
667
|
+
break;
|
|
668
|
+
case 'table-layout':
|
|
669
|
+
style.tableLayout = value === 'fixed' ? 'fixed' : 'auto';
|
|
670
|
+
break;
|
|
671
|
+
case 'border-collapse':
|
|
672
|
+
style.borderCollapse = value === 'collapse' ? 'collapse' : 'separate';
|
|
673
|
+
break;
|
|
674
|
+
case 'empty-cells':
|
|
675
|
+
style.emptyCells = value === 'hide' ? 'hide' : 'show';
|
|
676
|
+
break;
|
|
677
|
+
case 'border-spacing': {
|
|
678
|
+
// One value applies to both axes; two values are horizontal then vertical.
|
|
679
|
+
const parts = value.split(/\s+/).map(parseCellValue);
|
|
680
|
+
style.borderSpacingH = parts[0] ?? 0;
|
|
681
|
+
style.borderSpacingV = (parts.length > 1 ? parts[1] : parts[0]) ?? 0;
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
case 'vertical-align':
|
|
685
|
+
if (value === 'top' || value === 'middle' || value === 'bottom' || value === 'baseline') {
|
|
686
|
+
style.verticalAlign = value;
|
|
687
|
+
}
|
|
688
|
+
break;
|
|
543
689
|
case 'opacity':
|
|
544
690
|
if (value === 'dim') {
|
|
545
691
|
style.dim = true;
|
|
546
692
|
}
|
|
547
693
|
else {
|
|
548
694
|
const num = parseFloat(value);
|
|
549
|
-
|
|
695
|
+
if (!isNaN(num))
|
|
696
|
+
style.opacity = Math.max(0, Math.min(1, num));
|
|
550
697
|
}
|
|
551
698
|
break;
|
|
552
699
|
}
|
|
553
700
|
}
|
|
554
|
-
const BORDER_STYLES = new Set([
|
|
701
|
+
const BORDER_STYLES = new Set([
|
|
702
|
+
'none', 'single', 'double', 'rounded', 'heavy', 'ascii',
|
|
703
|
+
'eighth-cell-inner', 'eighth-cell-outer',
|
|
704
|
+
'half-cell-inner', 'half-cell-outer',
|
|
705
|
+
'full-cell',
|
|
706
|
+
]);
|
|
555
707
|
function setIndividualBorderSide(style, side, value) {
|
|
556
708
|
const enabled = value === 'true' || value === '1';
|
|
557
709
|
// When setting individual sides, disable all others first (if this is the first individual side set)
|
|
@@ -576,14 +728,71 @@ function parseSizeOrCell(value) {
|
|
|
576
728
|
return value;
|
|
577
729
|
return parseCellValue(value);
|
|
578
730
|
}
|
|
731
|
+
/** Parse grid-area: an area name, or numeric row-start / col-start / row-end / col-end lines. */
|
|
732
|
+
function parseGridArea(style, value) {
|
|
733
|
+
const trimmed = value.trim();
|
|
734
|
+
if (trimmed.includes('/')) {
|
|
735
|
+
const parts = trimmed.split('/').map(s => s.trim());
|
|
736
|
+
style.gridRowStart = parseIntOrNull(parts[0]);
|
|
737
|
+
if (parts.length > 1)
|
|
738
|
+
style.gridColumnStart = parseIntOrNull(parts[1]);
|
|
739
|
+
if (parts.length > 2)
|
|
740
|
+
style.gridRowEnd = parseIntOrNull(parts[2]);
|
|
741
|
+
if (parts.length > 3)
|
|
742
|
+
style.gridColumnEnd = parseIntOrNull(parts[3]);
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (/^\d+$/.test(trimmed)) {
|
|
746
|
+
style.gridRowStart = parseInt(trimmed);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
style.gridArea = trimmed;
|
|
750
|
+
}
|
|
751
|
+
/** Parse a grid line value (grid-column/grid-row): span N | start / end | start */
|
|
752
|
+
function parseGridLine(value) {
|
|
753
|
+
const trimmed = value.trim();
|
|
754
|
+
if (trimmed.startsWith('span')) {
|
|
755
|
+
return { start: null, end: null, span: parseInt(trimmed.replace('span', '').trim()) || 1 };
|
|
756
|
+
}
|
|
757
|
+
const parts = trimmed.split('/').map(s => s.trim());
|
|
758
|
+
return {
|
|
759
|
+
start: parseIntOrNull(parts[0]),
|
|
760
|
+
end: parts.length === 2 ? parseIntOrNull(parts[1]) : null,
|
|
761
|
+
span: null,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function parseIntOrNull(s) {
|
|
765
|
+
const n = parseInt(s);
|
|
766
|
+
return isNaN(n) ? null : n;
|
|
767
|
+
}
|
|
768
|
+
const TIMING_KEYWORDS = new Set([
|
|
769
|
+
'ease', 'linear', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end',
|
|
770
|
+
]);
|
|
771
|
+
const EASING_FUNCTION_PATTERN = /(?:cubic-bezier|steps)\([^)]*\)/;
|
|
772
|
+
/**
|
|
773
|
+
* Pull an easing function token (`cubic-bezier(...)`/`steps(...)`) out of a
|
|
774
|
+
* shorthand value so the remainder can be split on whitespace and commas
|
|
775
|
+
* without breaking inside the function's arguments.
|
|
776
|
+
*/
|
|
777
|
+
function extractEasingFunction(value) {
|
|
778
|
+
const match = EASING_FUNCTION_PATTERN.exec(value);
|
|
779
|
+
if (!match)
|
|
780
|
+
return { easing: null, rest: value };
|
|
781
|
+
return { easing: match[0], rest: value.replace(match[0], ' ') };
|
|
782
|
+
}
|
|
579
783
|
function parseAnimationShorthand(style, value) {
|
|
580
784
|
if (value === 'none') {
|
|
581
785
|
style.animationName = null;
|
|
582
786
|
return;
|
|
583
787
|
}
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
788
|
+
const { easing, rest } = extractEasingFunction(value);
|
|
789
|
+
if (easing)
|
|
790
|
+
style.animationTimingFunction = easing;
|
|
791
|
+
for (const part of rest.split(/\s+/)) {
|
|
792
|
+
if (TIMING_KEYWORDS.has(part)) {
|
|
793
|
+
style.animationTimingFunction = part;
|
|
794
|
+
}
|
|
795
|
+
else if (part.endsWith('s') && !part.endsWith('ss')) {
|
|
587
796
|
style.animationDuration = parseDuration(part);
|
|
588
797
|
}
|
|
589
798
|
else if (part === 'infinite') {
|
|
@@ -592,11 +801,41 @@ function parseAnimationShorthand(style, value) {
|
|
|
592
801
|
else if (/^\d+$/.test(part)) {
|
|
593
802
|
style.animationIterationCount = parseInt(part);
|
|
594
803
|
}
|
|
595
|
-
else if (!['
|
|
804
|
+
else if (part && !['normal', 'reverse', 'alternate', 'forwards', 'backwards', 'both', 'running', 'paused'].includes(part)) {
|
|
596
805
|
style.animationName = part;
|
|
597
806
|
}
|
|
598
807
|
}
|
|
599
808
|
}
|
|
809
|
+
/** Parse `transition: <property> <duration> [...]`, comma-separated groups. */
|
|
810
|
+
function parseTransitionShorthand(style, value) {
|
|
811
|
+
const trimmed = value.trim();
|
|
812
|
+
if (trimmed === 'none') {
|
|
813
|
+
style.transitionProperty = null;
|
|
814
|
+
style.transitionDuration = 0;
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const { easing, rest } = extractEasingFunction(trimmed);
|
|
818
|
+
if (easing)
|
|
819
|
+
style.transitionTimingFunction = easing;
|
|
820
|
+
const properties = [];
|
|
821
|
+
let duration = 0;
|
|
822
|
+
for (const group of rest.split(',')) {
|
|
823
|
+
for (const token of group.trim().split(/\s+/)) {
|
|
824
|
+
if (/^\d*\.?\d+(ms|s)$/.test(token)) {
|
|
825
|
+
if (duration === 0)
|
|
826
|
+
duration = parseDuration(token);
|
|
827
|
+
}
|
|
828
|
+
else if (TIMING_KEYWORDS.has(token)) {
|
|
829
|
+
style.transitionTimingFunction = token;
|
|
830
|
+
}
|
|
831
|
+
else if (token) {
|
|
832
|
+
properties.push(token);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
style.transitionProperty = properties.length > 0 ? properties.join(',') : 'all';
|
|
837
|
+
style.transitionDuration = duration;
|
|
838
|
+
}
|
|
600
839
|
function parseDuration(value) {
|
|
601
840
|
if (value.endsWith('ms'))
|
|
602
841
|
return parseFloat(value);
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Adapts to dark/light mode via @media (prefers-color-scheme).
|
|
7
7
|
*/
|
|
8
|
-
export declare const DEFAULT_STYLESHEET = "\nh1, h2, h3, h4, h5, h6 { font-weight: bold; }\nstrong, b { font-weight: bold; }\nem, i { font-style: italic; }\nu { text-decoration: underline; }\ns, del, strike { text-decoration: line-through; }\na { text-decoration: underline; }\npre { display: flex; }\np { margin-top: 1cell; margin-bottom: 1cell; }\nh1 { margin-top: 1cell; margin-bottom: 1cell; }\nh2 { margin-top: 1cell; margin-bottom: 1cell; }\nh3, h4, h5, h6 { margin-top: 1cell; margin-bottom: 1cell; }\nhr { height: 1cell; width: 100%; margin-top: 1cell; margin-bottom: 1cell; }\nblockquote { margin-left: 2cell; border-left: true; border-style: single; border-color: gray; padding-left: 1cell; }\nli { padding-left: 3cell; }\nul, ol { margin-top: 1cell; margin-bottom: 1cell; }\nmark { background-color: yellow; color: black; }\nkbd { border: single; border-color: gray; padding: 0 1cell; }\nabbr { text-decoration: underline; }\nsamp { color: cyan; }\nvar { font-style: italic; }\ndt { font-weight: bold; }\ndd { margin-left: 2cell; }\nfigure { margin-left: 2cell; margin-right: 2cell; margin-top: 1cell; margin-bottom: 1cell; }\nfigcaption { font-style: italic; }\n\n@media (prefers-color-scheme: dark) {\n code { color: cyan; }\n a { color: #5599ff; }\n mark { background-color: #666600; color: white; }\n}\n\n@media (prefers-color-scheme: light) {\n code { color: #8800cc; }\n a { color: #0044cc; }\n}\n";
|
|
8
|
+
export declare const DEFAULT_STYLESHEET = "\nh1, h2, h3, h4, h5, h6 { font-weight: bold; }\nstrong, b { font-weight: bold; }\nem, i { font-style: italic; }\nu { text-decoration: underline; }\ns, del, strike { text-decoration: line-through; }\na { text-decoration: underline; }\npre { display: flex; }\np { margin-top: 1cell; margin-bottom: 1cell; }\nh1 { margin-top: 1cell; margin-bottom: 1cell; }\nh2 { margin-top: 1cell; margin-bottom: 1cell; }\nh3, h4, h5, h6 { margin-top: 1cell; margin-bottom: 1cell; }\nhr { height: 1cell; width: 100%; margin-top: 1cell; margin-bottom: 1cell; }\nblockquote { margin-left: 2cell; border-left: true; border-style: single; border-color: gray; padding-left: 1cell; }\nli { padding-left: 3cell; }\nul, ol { margin-top: 1cell; margin-bottom: 1cell; }\nmark { background-color: yellow; color: black; }\nkbd { border: single; border-color: gray; padding: 0 1cell; }\nprogress, meter { display: inline-block; width: 20cell; height: 1cell; }\ninput[type=\"checkbox\"], input[type=\"radio\"] { display: inline-block; width: 3cell; height: 1cell; }\ndetails:not([open]) > :not(summary) { display: none; }\nsummary { padding-left: 2cell; }\nselect { display: inline-block; height: 1cell; }\nselect option, select optgroup { display: none; }\nabbr { text-decoration: underline; }\nsamp { color: cyan; }\nvar { font-style: italic; }\ndt { font-weight: bold; }\ndd { margin-left: 2cell; }\ntable { border-spacing: 2cell 0; }\nth { font-weight: bold; text-align: center; }\ncaption { text-align: center; }\nfigure { margin-left: 2cell; margin-right: 2cell; margin-top: 1cell; margin-bottom: 1cell; }\nfigcaption { font-style: italic; }\n\n@media (prefers-color-scheme: dark) {\n code { color: cyan; }\n a { color: #5599ff; }\n mark { background-color: #666600; color: white; }\n}\n\n@media (prefers-color-scheme: light) {\n code { color: #8800cc; }\n a { color: #0044cc; }\n}\n";
|
package/dist/src/css/defaults.js
CHANGED
|
@@ -23,11 +23,20 @@ li { padding-left: 3cell; }
|
|
|
23
23
|
ul, ol { margin-top: 1cell; margin-bottom: 1cell; }
|
|
24
24
|
mark { background-color: yellow; color: black; }
|
|
25
25
|
kbd { border: single; border-color: gray; padding: 0 1cell; }
|
|
26
|
+
progress, meter { display: inline-block; width: 20cell; height: 1cell; }
|
|
27
|
+
input[type="checkbox"], input[type="radio"] { display: inline-block; width: 3cell; height: 1cell; }
|
|
28
|
+
details:not([open]) > :not(summary) { display: none; }
|
|
29
|
+
summary { padding-left: 2cell; }
|
|
30
|
+
select { display: inline-block; height: 1cell; }
|
|
31
|
+
select option, select optgroup { display: none; }
|
|
26
32
|
abbr { text-decoration: underline; }
|
|
27
33
|
samp { color: cyan; }
|
|
28
34
|
var { font-style: italic; }
|
|
29
35
|
dt { font-weight: bold; }
|
|
30
36
|
dd { margin-left: 2cell; }
|
|
37
|
+
table { border-spacing: 2cell 0; }
|
|
38
|
+
th { font-weight: bold; text-align: center; }
|
|
39
|
+
caption { text-align: center; }
|
|
31
40
|
figure { margin-left: 2cell; margin-right: 2cell; margin-top: 1cell; margin-bottom: 1cell; }
|
|
32
41
|
figcaption { font-style: italic; }
|
|
33
42
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS easing functions: keywords, cubic-bezier(), and steps().
|
|
3
|
+
*
|
|
4
|
+
* An easing maps segment progress t ∈ [0, 1] to eased progress. Keyframe
|
|
5
|
+
* animations apply it per segment; transitions over their single segment.
|
|
6
|
+
*/
|
|
7
|
+
export type Easing = (t: number) => number;
|
|
8
|
+
/** Parse a CSS easing value; null when the value is not a valid easing. */
|
|
9
|
+
export declare function parseEasing(value: string): Easing | null;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS easing functions: keywords, cubic-bezier(), and steps().
|
|
3
|
+
*
|
|
4
|
+
* An easing maps segment progress t ∈ [0, 1] to eased progress. Keyframe
|
|
5
|
+
* animations apply it per segment; transitions over their single segment.
|
|
6
|
+
*/
|
|
7
|
+
const KEYWORD_CONTROL_POINTS = {
|
|
8
|
+
'ease': [0.25, 0.1, 0.25, 1],
|
|
9
|
+
'ease-in': [0.42, 0, 1, 1],
|
|
10
|
+
'ease-out': [0, 0, 0.58, 1],
|
|
11
|
+
'ease-in-out': [0.42, 0, 0.58, 1],
|
|
12
|
+
};
|
|
13
|
+
/** Parse a CSS easing value; null when the value is not a valid easing. */
|
|
14
|
+
export function parseEasing(value) {
|
|
15
|
+
const trimmed = value.trim();
|
|
16
|
+
if (trimmed === 'linear')
|
|
17
|
+
return t => t;
|
|
18
|
+
if (trimmed === 'step-start')
|
|
19
|
+
return steps(1, 'start');
|
|
20
|
+
if (trimmed === 'step-end')
|
|
21
|
+
return steps(1, 'end');
|
|
22
|
+
const preset = KEYWORD_CONTROL_POINTS[trimmed];
|
|
23
|
+
if (preset)
|
|
24
|
+
return cubicBezier(...preset);
|
|
25
|
+
if (trimmed.startsWith('cubic-bezier('))
|
|
26
|
+
return parseCubicBezier(trimmed);
|
|
27
|
+
if (trimmed.startsWith('steps('))
|
|
28
|
+
return parseSteps(trimmed);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function parseCubicBezier(value) {
|
|
32
|
+
const args = functionArguments(value, 'cubic-bezier');
|
|
33
|
+
if (args === null || args.length !== 4)
|
|
34
|
+
return null;
|
|
35
|
+
const numbers = args.map(Number);
|
|
36
|
+
if (numbers.some(isNaN))
|
|
37
|
+
return null;
|
|
38
|
+
const [x1, y1, x2, y2] = numbers;
|
|
39
|
+
if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1)
|
|
40
|
+
return null;
|
|
41
|
+
return cubicBezier(x1, y1, x2, y2);
|
|
42
|
+
}
|
|
43
|
+
function parseSteps(value) {
|
|
44
|
+
const args = functionArguments(value, 'steps');
|
|
45
|
+
if (args === null || args.length < 1 || args.length > 2)
|
|
46
|
+
return null;
|
|
47
|
+
const count = parseInt(args[0], 10);
|
|
48
|
+
if (isNaN(count) || count <= 0 || String(count) !== args[0])
|
|
49
|
+
return null;
|
|
50
|
+
const position = args[1] ?? 'end';
|
|
51
|
+
if (!['start', 'end', 'jump-start', 'jump-end'].includes(position))
|
|
52
|
+
return null;
|
|
53
|
+
return steps(count, position.endsWith('start') ? 'start' : 'end');
|
|
54
|
+
}
|
|
55
|
+
/** The comma-separated arguments of `name(...)`, or null if malformed. */
|
|
56
|
+
function functionArguments(value, name) {
|
|
57
|
+
if (!value.startsWith(`${name}(`) || !value.endsWith(')'))
|
|
58
|
+
return null;
|
|
59
|
+
return value.slice(name.length + 1, -1).split(',').map(s => s.trim());
|
|
60
|
+
}
|
|
61
|
+
function steps(count, position) {
|
|
62
|
+
return t => {
|
|
63
|
+
if (t >= 1)
|
|
64
|
+
return 1;
|
|
65
|
+
const step = position === 'start' ? Math.ceil(t * count) : Math.floor(t * count);
|
|
66
|
+
return Math.min(step / count, 1);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A CSS cubic bezier: fixed endpoints (0,0) and (1,1) with the given
|
|
71
|
+
* control points. Evaluated by solving x(s) = t for the curve parameter s
|
|
72
|
+
* (bisection — x is monotone since x1, x2 ∈ [0, 1]), then reading y(s).
|
|
73
|
+
*/
|
|
74
|
+
function cubicBezier(x1, y1, x2, y2) {
|
|
75
|
+
const sample = (p1, p2, s) => {
|
|
76
|
+
const inv = 1 - s;
|
|
77
|
+
return 3 * inv * inv * s * p1 + 3 * inv * s * s * p2 + s * s * s;
|
|
78
|
+
};
|
|
79
|
+
return t => {
|
|
80
|
+
if (t <= 0)
|
|
81
|
+
return 0;
|
|
82
|
+
if (t >= 1)
|
|
83
|
+
return 1;
|
|
84
|
+
let low = 0;
|
|
85
|
+
let high = 1;
|
|
86
|
+
for (let i = 0; i < 32; i++) {
|
|
87
|
+
const mid = (low + high) / 2;
|
|
88
|
+
if (sample(x1, x2, mid) < t)
|
|
89
|
+
low = mid;
|
|
90
|
+
else
|
|
91
|
+
high = mid;
|
|
92
|
+
}
|
|
93
|
+
return sample(y1, y2, (low + high) / 2);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -6,4 +6,4 @@ import { type ResolvedStyle } from './compute.js';
|
|
|
6
6
|
* descendants using the same resolveNode function as full resolution.
|
|
7
7
|
* Variables are collected once from the full tree for consistency.
|
|
8
8
|
*/
|
|
9
|
-
export declare function resolveStylesIncremental(root: TermNode, stylesheet: CSSStyleSheet, existingStyles: Map<number, ResolvedStyle>, dirtyNodes: Set<TermNode>, onResolve?: (nodeId: number) => void, onLayoutAffected?: (node: TermNode) => void): Map<number, ResolvedStyle>;
|
|
9
|
+
export declare function resolveStylesIncremental(root: TermNode, stylesheet: CSSStyleSheet, existingStyles: Map<number, ResolvedStyle>, dirtyNodes: Set<TermNode>, onResolve?: (nodeId: number) => void, onLayoutAffected?: (node: TermNode) => void, scheme?: 'dark' | 'light'): Map<number, ResolvedStyle>;
|