@react-x11/components 0.13.0 → 0.14.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/dist/html/controls.d.ts +29 -2
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +70 -2
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +26 -4
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +18 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +27 -0
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/parse.d.ts +18 -4
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +66 -28
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +128 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +561 -144
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/transform.d.ts +85 -0
- package/dist/html/css/transform.d.ts.map +1 -0
- package/dist/html/css/transform.js +425 -0
- package/dist/html/css/transform.js.map +1 -0
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +14 -2
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +4 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/fonts.d.ts +55 -5
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +284 -23
- package/dist/html/fonts.js.map +1 -1
- package/dist/html/layout/axes.d.ts +14 -0
- package/dist/html/layout/axes.d.ts.map +1 -0
- package/dist/html/layout/axes.js +28 -0
- package/dist/html/layout/axes.js.map +1 -0
- package/dist/html/layout/block.d.ts +93 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +389 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +59 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +22 -2
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +1 -1
- package/dist/html/layout/cache.d.ts.map +1 -1
- package/dist/html/layout/cache.js +6 -0
- package/dist/html/layout/cache.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +90 -18
- package/dist/html/layout/css-grid.js.map +1 -1
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +570 -83
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +3 -0
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +144 -54
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/multicol.d.ts +42 -0
- package/dist/html/layout/multicol.d.ts.map +1 -0
- package/dist/html/layout/multicol.js +897 -0
- package/dist/html/layout/multicol.js.map +1 -0
- package/dist/html/layout/shaping.d.ts +7 -0
- package/dist/html/layout/shaping.d.ts.map +1 -1
- package/dist/html/layout/shaping.js +25 -20
- package/dist/html/layout/shaping.js.map +1 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +62 -18
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +3 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +263 -36
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +79 -4
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1213 -141
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +15 -2
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +249 -17
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.js +87 -7
- package/dist/html/widgets.js.map +1 -1
- package/dist/html/woff2.d.ts +14 -0
- package/dist/html/woff2.d.ts.map +1 -0
- package/dist/html/woff2.js +608 -0
- package/dist/html/woff2.js.map +1 -0
- package/dist/maps/controller.d.ts +17 -1
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +27 -7
- package/dist/maps/controller.js.map +1 -1
- package/dist/richtext/node.d.ts +8 -1
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +5 -1
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +25 -6
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +240 -24
- package/dist/richtext/runs.js.map +1 -1
- package/package.json +1 -1
- package/src/html/controls.ts +85 -2
- package/src/html/css/cascade.ts +23 -0
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +71 -31
- package/src/html/css/style.ts +664 -147
- package/src/html/css/transform.ts +459 -0
- package/src/html/css/ua.ts +15 -2
- package/src/html/css/values.ts +4 -0
- package/src/html/fonts.ts +312 -29
- package/src/html/layout/axes.ts +62 -0
- package/src/html/layout/block.ts +444 -37
- package/src/html/layout/boxes.ts +65 -3
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +95 -22
- package/src/html/layout/flex.ts +671 -77
- package/src/html/layout/inline.ts +149 -55
- package/src/html/layout/multicol.ts +977 -0
- package/src/html/layout/shaping.ts +27 -18
- package/src/html/layout/table.ts +62 -19
- package/src/html/node.ts +300 -37
- package/src/html/paint.ts +1406 -206
- package/src/html/svg.ts +277 -19
- package/src/html/widgets.ts +95 -9
- package/src/html/woff2.ts +612 -0
- package/src/maps/controller.ts +28 -7
- package/src/richtext/node.ts +13 -2
- package/src/richtext/runs.ts +313 -35
package/dist/html/css/style.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { AUTO, alphaOf, fourSides, inkColor, isTransparent, keywordFontSize, parseAlpha, parseColor, isPct, parseLength, parseNumber, parseWeight, resolve, splitCommas, splitValue, } from './values.js';
|
|
16
16
|
import { parseUrl, readIdent, startsIdent } from './parse.js';
|
|
17
17
|
import { DEFAULT_QUOTES, parseContent, parseCounterList, parseListStyleType, parseQuotes, } from './content.js';
|
|
18
|
+
import { parseRotate, parseScale, parseTransform } from './transform.js';
|
|
18
19
|
import { LIGHT_DARK, lightDark, usedColorScheme } from './color.js';
|
|
19
20
|
/** Whether a length is one `padding` takes: not `auto`, not negative. A
|
|
20
21
|
* `calc()` with a percentage in it has no sign until layout, which clamps
|
|
@@ -58,6 +59,93 @@ function parseClip(value, ctx) {
|
|
|
58
59
|
}
|
|
59
60
|
return { top: edges[0], right: edges[1], bottom: edges[2], left: edges[3] };
|
|
60
61
|
}
|
|
62
|
+
/** The boxes `clip-path` names; an SVG one is the CSS box that stands for
|
|
63
|
+
* it on an element with a CSS layout box (5.1). */
|
|
64
|
+
const CLIP_BOXES = {
|
|
65
|
+
'margin-box': 'margin-box',
|
|
66
|
+
'border-box': 'border-box',
|
|
67
|
+
'padding-box': 'padding-box',
|
|
68
|
+
'content-box': 'content-box',
|
|
69
|
+
'fill-box': 'content-box',
|
|
70
|
+
'stroke-box': 'border-box',
|
|
71
|
+
'view-box': 'border-box',
|
|
72
|
+
};
|
|
73
|
+
/** The shapes that are no rectangle, and a reference to a `<clipPath>`
|
|
74
|
+
* element: a value, which sets the property, and none this draws. */
|
|
75
|
+
const UNDRAWN_CLIPS = /^(circle|ellipse|polygon|path|shape|url)\(/i;
|
|
76
|
+
const NO_LENGTHS = [0, 0, 0, 0];
|
|
77
|
+
/**
|
|
78
|
+
* `none`; a rectangle's function, a box, or the two in either order; or a
|
|
79
|
+
* shape that is no rectangle, which is a value and clips nothing here.
|
|
80
|
+
* Undefined for anything else, which leaves the value as it was.
|
|
81
|
+
*/
|
|
82
|
+
function parseClipPath(value, ctx) {
|
|
83
|
+
const v = value.trim();
|
|
84
|
+
if (/^none$/i.test(v))
|
|
85
|
+
return null;
|
|
86
|
+
let box = null;
|
|
87
|
+
let shape;
|
|
88
|
+
for (const part of splitValue(v)) {
|
|
89
|
+
const named = CLIP_BOXES[part.toLowerCase()];
|
|
90
|
+
if (named) {
|
|
91
|
+
if (box)
|
|
92
|
+
return undefined;
|
|
93
|
+
box = named;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (shape !== undefined)
|
|
97
|
+
return undefined;
|
|
98
|
+
if (UNDRAWN_CLIPS.test(part) && part.endsWith(')'))
|
|
99
|
+
shape = null;
|
|
100
|
+
else
|
|
101
|
+
shape = rectShape(part, ctx);
|
|
102
|
+
if (shape === undefined)
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
if (shape === null)
|
|
106
|
+
return null;
|
|
107
|
+
if (shape)
|
|
108
|
+
return { box: box ?? 'border-box', ...shape };
|
|
109
|
+
if (!box)
|
|
110
|
+
return undefined;
|
|
111
|
+
return { box, shape: null, lengths: NO_LENGTHS, radii: null, radiiY: null };
|
|
112
|
+
}
|
|
113
|
+
/** `inset()`, `rect()` or `xywh()`, with the corners it rounds; undefined
|
|
114
|
+
* for anything else. */
|
|
115
|
+
function rectShape(text, ctx) {
|
|
116
|
+
const m = /^(inset|rect|xywh)\((.*)\)$/is.exec(text);
|
|
117
|
+
if (!m)
|
|
118
|
+
return undefined;
|
|
119
|
+
const shape = m[1].toLowerCase();
|
|
120
|
+
const parts = splitValue(m[2].trim());
|
|
121
|
+
const round = parts.findIndex((p) => p.toLowerCase() === 'round');
|
|
122
|
+
const sides = round < 0 ? parts : parts.slice(0, round);
|
|
123
|
+
let radii = null;
|
|
124
|
+
let radiiY = null;
|
|
125
|
+
if (round >= 0) {
|
|
126
|
+
const corners = parseRadii(parts.slice(round + 1).join(' '), ctx);
|
|
127
|
+
if (!corners)
|
|
128
|
+
return undefined;
|
|
129
|
+
[radii, radiiY] = corners;
|
|
130
|
+
}
|
|
131
|
+
// one to four insets, as a margin's sides are written; the other two
|
|
132
|
+
// take all four
|
|
133
|
+
if (shape === 'inset' ? !sides.length || sides.length > 4 : sides.length !== 4)
|
|
134
|
+
return undefined;
|
|
135
|
+
const lengths = [];
|
|
136
|
+
for (let i = 0; i < sides.length; i += 1) {
|
|
137
|
+
const len = parseLength(sides[i], ctx);
|
|
138
|
+
if (len === null)
|
|
139
|
+
return undefined;
|
|
140
|
+
// only `rect()` has an edge that is `auto`, and a width is not negative
|
|
141
|
+
if (len === AUTO && shape !== 'rect')
|
|
142
|
+
return undefined;
|
|
143
|
+
if (shape === 'xywh' && i > 1 && !notNegative(len))
|
|
144
|
+
return undefined;
|
|
145
|
+
lengths.push(len);
|
|
146
|
+
}
|
|
147
|
+
return { shape, lengths: fourSides(lengths), radii, radiiY };
|
|
148
|
+
}
|
|
61
149
|
/** The properties that inherit. Named once, so `inherit()` and the `inherit`
|
|
62
150
|
* keyword cannot disagree about the list. */
|
|
63
151
|
/** The fields a style takes from its parent's (CSS 2.1's "Inherited:
|
|
@@ -92,6 +180,8 @@ export const INHERITED = [
|
|
|
92
180
|
'fontFeatureSettings',
|
|
93
181
|
'tabSize',
|
|
94
182
|
'tabSizeIsLength',
|
|
183
|
+
'orphans',
|
|
184
|
+
'widows',
|
|
95
185
|
'whiteSpace',
|
|
96
186
|
'overflowWrap',
|
|
97
187
|
'wordBreak',
|
|
@@ -103,6 +193,9 @@ export const INHERITED = [
|
|
|
103
193
|
'listStylePosition',
|
|
104
194
|
'listStyleImage',
|
|
105
195
|
'cursor',
|
|
196
|
+
'pointerEvents',
|
|
197
|
+
'fill',
|
|
198
|
+
'stroke',
|
|
106
199
|
'borderCollapse',
|
|
107
200
|
'borderSpacing',
|
|
108
201
|
'borderSpacingY',
|
|
@@ -154,6 +247,9 @@ export function initialStyle(look, scale = 1) {
|
|
|
154
247
|
listStylePosition: 'outside',
|
|
155
248
|
listStyleImage: null,
|
|
156
249
|
cursor: null,
|
|
250
|
+
pointerEvents: 'auto',
|
|
251
|
+
fill: null,
|
|
252
|
+
stroke: null,
|
|
157
253
|
borderCollapse: 'separate',
|
|
158
254
|
// CSS's initial value; a `<table>` gets its 2px from the UA sheet, and
|
|
159
255
|
// an anonymous table, which no sheet names, has none
|
|
@@ -188,6 +284,14 @@ export function initialStyle(look, scale = 1) {
|
|
|
188
284
|
webkitBoxAlign: null,
|
|
189
285
|
webkitBoxFlex: 0,
|
|
190
286
|
columns: 0,
|
|
287
|
+
columnCount: null,
|
|
288
|
+
columnWidth: null,
|
|
289
|
+
columnGapNormal: true,
|
|
290
|
+
orphans: 2,
|
|
291
|
+
widows: 2,
|
|
292
|
+
breakInside: 'auto',
|
|
293
|
+
columnFill: 'balance',
|
|
294
|
+
columnSpan: false,
|
|
191
295
|
textOverflow: 'clip',
|
|
192
296
|
aspectRatio: null,
|
|
193
297
|
objectFit: 'fill',
|
|
@@ -197,9 +301,13 @@ export function initialStyle(look, scale = 1) {
|
|
|
197
301
|
overflowX: 'visible',
|
|
198
302
|
overflowY: 'visible',
|
|
199
303
|
clip: null,
|
|
304
|
+
clipPath: null,
|
|
200
305
|
opacity: 1,
|
|
201
306
|
translate: null,
|
|
202
|
-
|
|
307
|
+
rotate: null,
|
|
308
|
+
scale: null,
|
|
309
|
+
transform: null,
|
|
310
|
+
transformOrigin: [{ pct: 50 }, { pct: 50 }],
|
|
203
311
|
zIndex: AUTO,
|
|
204
312
|
verticalAlign: 'baseline',
|
|
205
313
|
width: AUTO,
|
|
@@ -283,6 +391,8 @@ export function initialStyle(look, scale = 1) {
|
|
|
283
391
|
underlineThickness: null,
|
|
284
392
|
underlineOffset: null,
|
|
285
393
|
lineThrough: null,
|
|
394
|
+
lineThroughStyle: 'solid',
|
|
395
|
+
lineThroughThickness: null,
|
|
286
396
|
flexDirection: 'row',
|
|
287
397
|
flexWrap: 'nowrap',
|
|
288
398
|
justifyContent: 'normal',
|
|
@@ -381,6 +491,8 @@ export function inherit(parent, initial) {
|
|
|
381
491
|
out.fontFeatureSettings = parent.fontFeatureSettings;
|
|
382
492
|
out.tabSize = parent.tabSize;
|
|
383
493
|
out.tabSizeIsLength = parent.tabSizeIsLength;
|
|
494
|
+
out.orphans = parent.orphans;
|
|
495
|
+
out.widows = parent.widows;
|
|
384
496
|
out.whiteSpace = parent.whiteSpace;
|
|
385
497
|
out.overflowWrap = parent.overflowWrap;
|
|
386
498
|
out.wordBreak = parent.wordBreak;
|
|
@@ -392,6 +504,9 @@ export function inherit(parent, initial) {
|
|
|
392
504
|
out.listStylePosition = parent.listStylePosition;
|
|
393
505
|
out.listStyleImage = parent.listStyleImage;
|
|
394
506
|
out.cursor = parent.cursor;
|
|
507
|
+
out.pointerEvents = parent.pointerEvents;
|
|
508
|
+
out.fill = parent.fill;
|
|
509
|
+
out.stroke = parent.stroke;
|
|
395
510
|
out.borderCollapse = parent.borderCollapse;
|
|
396
511
|
out.borderSpacing = parent.borderSpacing;
|
|
397
512
|
out.borderSpacingY = parent.borderSpacingY;
|
|
@@ -411,6 +526,8 @@ export function inherit(parent, initial) {
|
|
|
411
526
|
out.underlineThickness = parent.underlineThickness;
|
|
412
527
|
out.underlineOffset = parent.underlineOffset;
|
|
413
528
|
out.lineThrough = parent.lineThrough;
|
|
529
|
+
out.lineThroughStyle = parent.lineThroughStyle;
|
|
530
|
+
out.lineThroughThickness = parent.lineThroughThickness;
|
|
414
531
|
return out;
|
|
415
532
|
}
|
|
416
533
|
/**
|
|
@@ -444,6 +561,8 @@ export const FIRST_LINE_INHERITED = [
|
|
|
444
561
|
'underlineThickness',
|
|
445
562
|
'underlineOffset',
|
|
446
563
|
'lineThrough',
|
|
564
|
+
'lineThroughStyle',
|
|
565
|
+
'lineThroughThickness',
|
|
447
566
|
];
|
|
448
567
|
/**
|
|
449
568
|
* What a box on its block's first line inherits from: its parent's style,
|
|
@@ -501,6 +620,14 @@ const BORDER_WIDTH_KEYWORDS = {
|
|
|
501
620
|
medium: 3,
|
|
502
621
|
thick: 5,
|
|
503
622
|
};
|
|
623
|
+
/** `-webkit-` names that are the multicol properties' own. */
|
|
624
|
+
const MULTICOL_ALIASES = {
|
|
625
|
+
'-webkit-columns': 'columns',
|
|
626
|
+
'-webkit-column-count': 'column-count',
|
|
627
|
+
'-webkit-column-width': 'column-width',
|
|
628
|
+
'-webkit-column-gap': 'column-gap',
|
|
629
|
+
'-webkit-column-break-inside': 'break-inside',
|
|
630
|
+
};
|
|
504
631
|
/**
|
|
505
632
|
* Apply one declaration to a style, in place.
|
|
506
633
|
*
|
|
@@ -510,7 +637,12 @@ const BORDER_WIDTH_KEYWORDS = {
|
|
|
510
637
|
* correct response to every one of them is to render the rest.
|
|
511
638
|
*/
|
|
512
639
|
export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
513
|
-
const
|
|
640
|
+
const written = prop.toLowerCase();
|
|
641
|
+
// the multicol properties under the names WebKit had them by, which
|
|
642
|
+
// Blink still reads, each an alias of the property (`-webkit-column-
|
|
643
|
+
// count` in its `css_properties.json5`): a page written for it alone
|
|
644
|
+
// names no other
|
|
645
|
+
const name = MULTICOL_ALIASES[written] ?? written;
|
|
514
646
|
let value = rawValue.trim();
|
|
515
647
|
if (!value)
|
|
516
648
|
return;
|
|
@@ -645,21 +777,75 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
645
777
|
case 'column-count':
|
|
646
778
|
case 'column-width':
|
|
647
779
|
case 'columns': {
|
|
648
|
-
// `auto`, or a count, a width or both of them
|
|
780
|
+
// `auto`, or a count, a width or both of them, in either order; what
|
|
781
|
+
// the shorthand leaves out is `auto`
|
|
649
782
|
const bit = name === 'column-count' ? 1 : name === 'column-width' ? 2 : 3;
|
|
650
|
-
let
|
|
783
|
+
let count = null;
|
|
784
|
+
let width = null;
|
|
651
785
|
for (const part of splitValue(value)) {
|
|
652
786
|
const v = part.toLowerCase();
|
|
653
787
|
if (v === 'auto')
|
|
654
788
|
continue;
|
|
655
|
-
if (/^\d+$/.test(v) && Number(v) >= 1)
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
789
|
+
if (/^\d+$/.test(v) && Number(v) >= 1) {
|
|
790
|
+
if (count !== null || !(bit & 1))
|
|
791
|
+
return;
|
|
792
|
+
count = Number(v);
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
const len = parseLength(part, ctx);
|
|
796
|
+
if (typeof len !== 'number' || !(len > 0))
|
|
797
|
+
return;
|
|
798
|
+
if (width !== null || !(bit & 2))
|
|
799
|
+
return;
|
|
800
|
+
width = len;
|
|
801
|
+
}
|
|
802
|
+
if (bit & 1)
|
|
803
|
+
style.columnCount = count;
|
|
804
|
+
if (bit & 2)
|
|
805
|
+
style.columnWidth = width;
|
|
806
|
+
style.columns =
|
|
807
|
+
(style.columnCount !== null ? 1 : 0) |
|
|
808
|
+
(style.columnWidth !== null ? 2 : 0);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
case 'orphans':
|
|
812
|
+
case 'widows': {
|
|
813
|
+
// a whole number of lines, one or more
|
|
814
|
+
const v = value.trim();
|
|
815
|
+
if (!/^\+?\d+$/.test(v) || Number(v) < 1)
|
|
816
|
+
return;
|
|
817
|
+
style[name] = Number(v);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
case '-webkit-column-span':
|
|
821
|
+
case 'column-span': {
|
|
822
|
+
const v = value.trim().toLowerCase();
|
|
823
|
+
if (v === 'all')
|
|
824
|
+
style.columnSpan = true;
|
|
825
|
+
else if (v === 'none')
|
|
826
|
+
style.columnSpan = false;
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
case 'column-fill': {
|
|
830
|
+
const v = value.trim().toLowerCase();
|
|
831
|
+
if (v === 'auto')
|
|
832
|
+
style.columnFill = 'auto';
|
|
833
|
+
else if (v === 'balance' || v === 'balance-all') {
|
|
834
|
+
style.columnFill = 'balance';
|
|
835
|
+
}
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
case 'break-inside':
|
|
839
|
+
case 'page-break-inside': {
|
|
840
|
+
const v = value.trim().toLowerCase();
|
|
841
|
+
if (v === 'auto')
|
|
842
|
+
style.breakInside = 'auto';
|
|
843
|
+
else if (/^avoid(?:-page|-column|-region)?$/.test(v)) {
|
|
844
|
+
// the legacy property knows `avoid` alone
|
|
845
|
+
if (name === 'page-break-inside' && v !== 'avoid')
|
|
660
846
|
return;
|
|
847
|
+
style.breakInside = 'avoid';
|
|
661
848
|
}
|
|
662
|
-
style.columns = (style.columns & ~bit) | (set & bit);
|
|
663
849
|
return;
|
|
664
850
|
}
|
|
665
851
|
case '-webkit-box-flex': {
|
|
@@ -927,6 +1113,13 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
927
1113
|
style.clip = clip;
|
|
928
1114
|
return;
|
|
929
1115
|
}
|
|
1116
|
+
case 'clip-path':
|
|
1117
|
+
case '-webkit-clip-path': {
|
|
1118
|
+
const path = parseClipPath(value, ctx);
|
|
1119
|
+
if (path !== undefined)
|
|
1120
|
+
style.clipPath = path;
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
930
1123
|
case 'opacity': {
|
|
931
1124
|
const a = parseAlpha(value);
|
|
932
1125
|
if (a !== null)
|
|
@@ -950,10 +1143,38 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
950
1143
|
style.translate = [x, y ?? 0];
|
|
951
1144
|
return;
|
|
952
1145
|
}
|
|
953
|
-
case '
|
|
954
|
-
const
|
|
955
|
-
if (
|
|
956
|
-
style.
|
|
1146
|
+
case 'rotate': {
|
|
1147
|
+
const turn = parseRotate(value);
|
|
1148
|
+
if (turn !== undefined)
|
|
1149
|
+
style.rotate = turn;
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
case 'scale': {
|
|
1153
|
+
const factors = parseScale(value);
|
|
1154
|
+
if (factors !== undefined)
|
|
1155
|
+
style.scale = factors;
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
case 'transform':
|
|
1159
|
+
case '-webkit-transform': {
|
|
1160
|
+
const list = parseTransform(value, ctx);
|
|
1161
|
+
if (list !== undefined)
|
|
1162
|
+
style.transform = list;
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
case 'transform-origin':
|
|
1166
|
+
case '-webkit-transform-origin': {
|
|
1167
|
+
// across and down, as a position is, and a depth nothing here has
|
|
1168
|
+
const parts = splitValue(value);
|
|
1169
|
+
if (parts.length === 3) {
|
|
1170
|
+
if (typeof parseLength(parts.pop(), ctx) !== 'number')
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
else if (parts.length > 2)
|
|
1174
|
+
return;
|
|
1175
|
+
const origin = positionPair(parts, ctx);
|
|
1176
|
+
if (origin)
|
|
1177
|
+
style.transformOrigin = origin;
|
|
957
1178
|
return;
|
|
958
1179
|
}
|
|
959
1180
|
case 'visibility': {
|
|
@@ -1242,19 +1463,9 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1242
1463
|
return;
|
|
1243
1464
|
}
|
|
1244
1465
|
case 'border-radius': {
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (halves.length > 2)
|
|
1249
|
-
return;
|
|
1250
|
-
const [horizontal, vertical] = halves.map((half) => splitValue(half).map((p) => radiusOf(p, ctx)));
|
|
1251
|
-
for (const parts of vertical ? [horizontal, vertical] : [horizontal]) {
|
|
1252
|
-
if (!parts.length || parts.length > 4 || parts.includes(null))
|
|
1253
|
-
return;
|
|
1254
|
-
}
|
|
1255
|
-
style.borderRadius = fourSides(horizontal);
|
|
1256
|
-
const y = vertical ? fourSides(vertical) : null;
|
|
1257
|
-
style.borderRadiusY = y && !sameRadii(style.borderRadius, y) ? y : null;
|
|
1466
|
+
const radii = parseRadii(value, ctx);
|
|
1467
|
+
if (radii)
|
|
1468
|
+
[style.borderRadius, style.borderRadiusY] = radii;
|
|
1258
1469
|
return;
|
|
1259
1470
|
}
|
|
1260
1471
|
// --- background ---------------------------------------------------------
|
|
@@ -1509,7 +1720,19 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1509
1720
|
: f.trim().replace(/[ \t\n\r\f]+/g, ' '))
|
|
1510
1721
|
.filter(Boolean)
|
|
1511
1722
|
.join(', ');
|
|
1512
|
-
|
|
1723
|
+
// A list that ends in no generic family ends in the document's own
|
|
1724
|
+
// font: where no face in the list matches, the text is set in the
|
|
1725
|
+
// user agent's default (CSS Fonts 4, 5.1), which for a browser is its
|
|
1726
|
+
// standard font and here is the one the document is set in. The text
|
|
1727
|
+
// engine's own answer for a name nothing has is its platform's pick,
|
|
1728
|
+
// Verdana under fontconfig: the Zen Garden's 216 sets its summary in
|
|
1729
|
+
// Montserrat alone, which no machine here has, and Chrome sets it in
|
|
1730
|
+
// Times where ours was Verdana, a fifth wider
|
|
1731
|
+
const last = names[names.length - 1].trim();
|
|
1732
|
+
const generic = !/^['"]/.test(last) && GENERIC_FAMILY.has(last.toLowerCase());
|
|
1733
|
+
const fallback = generic ? null : (ctx.fallbackFamily?.() ?? null);
|
|
1734
|
+
const full = fallback ? `${list}, ${fallback}` : list;
|
|
1735
|
+
style.fontFamily = ctx.families ? ctx.families(full) : full;
|
|
1513
1736
|
return;
|
|
1514
1737
|
}
|
|
1515
1738
|
case 'font-size': {
|
|
@@ -1933,6 +2156,23 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1933
2156
|
style.cursor = splitCommas(value)[0]?.trim().toLowerCase() || null;
|
|
1934
2157
|
return;
|
|
1935
2158
|
}
|
|
2159
|
+
case 'pointer-events': {
|
|
2160
|
+
// `none`, or one of the values SVG gives it, which are `auto` on
|
|
2161
|
+
// anything that is not SVG's to draw
|
|
2162
|
+
const v = value.trim().toLowerCase();
|
|
2163
|
+
if (v === 'none')
|
|
2164
|
+
style.pointerEvents = 'none';
|
|
2165
|
+
else if (POINTER_EVENTS.has(v))
|
|
2166
|
+
style.pointerEvents = 'auto';
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
case 'fill':
|
|
2170
|
+
case 'stroke': {
|
|
2171
|
+
const paint = svgPaint(value);
|
|
2172
|
+
if (paint !== null)
|
|
2173
|
+
style[name] = paint;
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
1936
2176
|
// --- lists --------------------------------------------------------------
|
|
1937
2177
|
case 'list-style': {
|
|
1938
2178
|
// a type, a position and an image, each at most once and in any
|
|
@@ -2132,8 +2372,11 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
2132
2372
|
return;
|
|
2133
2373
|
if (which !== 'column-gap')
|
|
2134
2374
|
style.rowGap = row;
|
|
2135
|
-
if (which !== 'row-gap')
|
|
2375
|
+
if (which !== 'row-gap') {
|
|
2136
2376
|
style.columnGap = col;
|
|
2377
|
+
const word = parts[parts.length - 1].toLowerCase();
|
|
2378
|
+
style.columnGapNormal = word === 'normal';
|
|
2379
|
+
}
|
|
2137
2380
|
return;
|
|
2138
2381
|
}
|
|
2139
2382
|
case 'grid-template-columns':
|
|
@@ -2605,6 +2848,12 @@ function alignKeyword(value) {
|
|
|
2605
2848
|
return 'flex-end';
|
|
2606
2849
|
case 'first baseline':
|
|
2607
2850
|
return 'baseline';
|
|
2851
|
+
// By last baselines, which nothing here aligns: set where that falls
|
|
2852
|
+
// back to, the end (CSS Box Alignment 3, 4.2). Dropped, a row that asks
|
|
2853
|
+
// for it stretched its items, and a flex box among them was as tall as
|
|
2854
|
+
// the row, its lines spread down it.
|
|
2855
|
+
case 'last baseline':
|
|
2856
|
+
return 'flex-end';
|
|
2608
2857
|
case 'center':
|
|
2609
2858
|
return 'center';
|
|
2610
2859
|
case 'stretch':
|
|
@@ -3226,7 +3475,7 @@ function applyBackgroundShorthand(style, value, ctx) {
|
|
|
3226
3475
|
function backgroundImageOf(text, ctx) {
|
|
3227
3476
|
const v = text.trim();
|
|
3228
3477
|
if (IMAGE_FUNCTION.test(v.toLowerCase()))
|
|
3229
|
-
return
|
|
3478
|
+
return parseGradient(v, ctx);
|
|
3230
3479
|
return parseUrl(v);
|
|
3231
3480
|
}
|
|
3232
3481
|
/** A background property's values, one a comma-separated layer, each read
|
|
@@ -3248,7 +3497,7 @@ function layerValues(value, read) {
|
|
|
3248
3497
|
* is dropped rather than resetting the background it meant to replace
|
|
3249
3498
|
* (CSS 2.1 4.2). What CSS3 adds is read too, so that a declaration a
|
|
3250
3499
|
* browser keeps is kept: `/ cover` after the position, `space` and `round`,
|
|
3251
|
-
* a gradient
|
|
3500
|
+
* and a gradient, over the layer's colour.
|
|
3252
3501
|
*/
|
|
3253
3502
|
function readBackgroundLayer(text, ctx, last) {
|
|
3254
3503
|
const parts = splitValue(text).flatMap(splitSlash);
|
|
@@ -3284,7 +3533,7 @@ function readBackgroundLayer(text, ctx, last) {
|
|
|
3284
3533
|
layer.image = url;
|
|
3285
3534
|
}
|
|
3286
3535
|
else if (v !== 'none')
|
|
3287
|
-
layer.gradient =
|
|
3536
|
+
layer.gradient = parseGradient(part, ctx);
|
|
3288
3537
|
i += 1;
|
|
3289
3538
|
}
|
|
3290
3539
|
else if (v === 'repeat-x' || v === 'repeat-y' || REPEATS.has(v)) {
|
|
@@ -3363,21 +3612,21 @@ function readBackgroundLayer(text, ctx, last) {
|
|
|
3363
3612
|
}
|
|
3364
3613
|
/**
|
|
3365
3614
|
* A `linear-gradient()`, or null for any other image function and for one
|
|
3366
|
-
* that is no gradient: a direction by angle, by side or by corner,
|
|
3367
|
-
* colour
|
|
3368
|
-
* not honoured, and at least two stops, each with no position, one, or two;
|
|
3369
|
-
* a bare percentage between stops, a hint, is passed over.
|
|
3615
|
+
* that is no gradient: a direction by angle, by side or by corner, and its
|
|
3616
|
+
* colour stops.
|
|
3370
3617
|
*/
|
|
3371
3618
|
function parseLinearGradient(text, ctx) {
|
|
3372
3619
|
const m = /^linear-gradient\((.*)\)$/is.exec(text.trim());
|
|
3373
3620
|
if (!m)
|
|
3374
3621
|
return null;
|
|
3375
3622
|
const args = splitCommas(m[1]).map((a) => a.trim());
|
|
3376
|
-
const out = {
|
|
3377
|
-
|
|
3378
|
-
.
|
|
3379
|
-
|
|
3380
|
-
|
|
3623
|
+
const out = {
|
|
3624
|
+
kind: 'linear',
|
|
3625
|
+
angle: Math.PI,
|
|
3626
|
+
corner: null,
|
|
3627
|
+
stops: [],
|
|
3628
|
+
};
|
|
3629
|
+
const first = withoutInterpolation(args[0] ?? '');
|
|
3381
3630
|
let from = 0;
|
|
3382
3631
|
if (!first || first.startsWith('to ')) {
|
|
3383
3632
|
from = 1;
|
|
@@ -3419,7 +3668,124 @@ function parseLinearGradient(text, ctx) {
|
|
|
3419
3668
|
from = 1;
|
|
3420
3669
|
}
|
|
3421
3670
|
}
|
|
3422
|
-
|
|
3671
|
+
const stops = parseStops(args.slice(from), ctx);
|
|
3672
|
+
if (!stops)
|
|
3673
|
+
return null;
|
|
3674
|
+
out.stops = stops;
|
|
3675
|
+
return out;
|
|
3676
|
+
}
|
|
3677
|
+
/**
|
|
3678
|
+
* A `radial-gradient()` (CSS Images 3, 3.2.1), or null for anything else:
|
|
3679
|
+
* an ending shape, `circle` or `ellipse`, and its size, in either order —
|
|
3680
|
+
* a keyword for the side or corner of the box it reaches, one length for a
|
|
3681
|
+
* circle's radius, or two lengths or percentages for an ellipse's — then
|
|
3682
|
+
* `at` and its centre, a position as `background-position` writes one;
|
|
3683
|
+
* each of the three may be left out, for an ellipse through the farthest
|
|
3684
|
+
* corner from the middle of the box. A colour interpolation method is read
|
|
3685
|
+
* and not honoured, and the stops are a linear gradient's, spaced along
|
|
3686
|
+
* the ray from the centre to the shape's edge.
|
|
3687
|
+
*/
|
|
3688
|
+
function parseRadialGradient(text, ctx) {
|
|
3689
|
+
const m = /^radial-gradient\((.*)\)$/is.exec(text.trim());
|
|
3690
|
+
if (!m)
|
|
3691
|
+
return null;
|
|
3692
|
+
const args = splitCommas(m[1]).map((a) => a.trim());
|
|
3693
|
+
const out = {
|
|
3694
|
+
kind: 'radial',
|
|
3695
|
+
circle: false,
|
|
3696
|
+
extent: null,
|
|
3697
|
+
radii: null,
|
|
3698
|
+
at: [{ pct: 50 }, { pct: 50 }],
|
|
3699
|
+
stops: [],
|
|
3700
|
+
};
|
|
3701
|
+
const first = withoutInterpolation(args[0] ?? '');
|
|
3702
|
+
let from = 0;
|
|
3703
|
+
if (!first)
|
|
3704
|
+
from = 1;
|
|
3705
|
+
else if (parseColor(splitValue(first)[0]) === null) {
|
|
3706
|
+
from = 1;
|
|
3707
|
+
const words = splitValue(first);
|
|
3708
|
+
const at = words.indexOf('at');
|
|
3709
|
+
if (at >= 0) {
|
|
3710
|
+
const position = positionPair(words.slice(at + 1), ctx);
|
|
3711
|
+
if (!position)
|
|
3712
|
+
return null;
|
|
3713
|
+
out.at = position;
|
|
3714
|
+
}
|
|
3715
|
+
let shape = null;
|
|
3716
|
+
const sizes = [];
|
|
3717
|
+
// the size is one run of words, the shape's keyword before or after it
|
|
3718
|
+
let sized = false;
|
|
3719
|
+
for (const word of at >= 0 ? words.slice(0, at) : words) {
|
|
3720
|
+
if (word === 'circle' || word === 'ellipse') {
|
|
3721
|
+
if (shape)
|
|
3722
|
+
return null;
|
|
3723
|
+
shape = word;
|
|
3724
|
+
if (sizes.length || out.extent)
|
|
3725
|
+
sized = true;
|
|
3726
|
+
continue;
|
|
3727
|
+
}
|
|
3728
|
+
if (sized || out.extent)
|
|
3729
|
+
return null;
|
|
3730
|
+
if (RADIAL_EXTENTS.has(word)) {
|
|
3731
|
+
if (sizes.length)
|
|
3732
|
+
return null;
|
|
3733
|
+
out.extent = word;
|
|
3734
|
+
continue;
|
|
3735
|
+
}
|
|
3736
|
+
const len = parseLength(word, ctx);
|
|
3737
|
+
if (len === null || len === AUTO || !notNegative(len))
|
|
3738
|
+
return null;
|
|
3739
|
+
sizes.push(len);
|
|
3740
|
+
}
|
|
3741
|
+
if (sizes.length === 1) {
|
|
3742
|
+
// a circle's radius is a length: a percentage of what, the spec asks
|
|
3743
|
+
const [r] = sizes;
|
|
3744
|
+
if (shape === 'ellipse' || typeof r !== 'number') {
|
|
3745
|
+
return null;
|
|
3746
|
+
}
|
|
3747
|
+
out.circle = true;
|
|
3748
|
+
out.radii = [r, r];
|
|
3749
|
+
}
|
|
3750
|
+
else if (sizes.length === 2) {
|
|
3751
|
+
if (shape === 'circle')
|
|
3752
|
+
return null;
|
|
3753
|
+
out.radii = [sizes[0], sizes[1]];
|
|
3754
|
+
}
|
|
3755
|
+
else if (sizes.length)
|
|
3756
|
+
return null;
|
|
3757
|
+
else {
|
|
3758
|
+
out.circle = shape === 'circle';
|
|
3759
|
+
out.extent ??= 'farthest-corner';
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
const stops = parseStops(args.slice(from), ctx);
|
|
3763
|
+
if (!stops)
|
|
3764
|
+
return null;
|
|
3765
|
+
out.stops = stops;
|
|
3766
|
+
return out;
|
|
3767
|
+
}
|
|
3768
|
+
const RADIAL_EXTENTS = new Set([
|
|
3769
|
+
'closest-side',
|
|
3770
|
+
'closest-corner',
|
|
3771
|
+
'farthest-side',
|
|
3772
|
+
'farthest-corner',
|
|
3773
|
+
]);
|
|
3774
|
+
/** A gradient's first argument, lower-cased, without the colour
|
|
3775
|
+
* interpolation method CSS Images 4 adds to it (`in oklab`, which
|
|
3776
|
+
* Tailwind 4 writes): read, and not honoured. */
|
|
3777
|
+
function withoutInterpolation(arg) {
|
|
3778
|
+
return arg
|
|
3779
|
+
.toLowerCase()
|
|
3780
|
+
.replace(/\bin\s+[a-z-]+(?:\s+(?:shorter|longer|increasing|decreasing)\s+hue)?/, '')
|
|
3781
|
+
.trim();
|
|
3782
|
+
}
|
|
3783
|
+
/** A gradient's colour stops, at least two, each with no position, one or
|
|
3784
|
+
* two; a bare length between two stops, a hint, is passed over. Null
|
|
3785
|
+
* where an argument is none of those. */
|
|
3786
|
+
function parseStops(args, ctx) {
|
|
3787
|
+
const stops = [];
|
|
3788
|
+
for (const arg of args) {
|
|
3423
3789
|
const parts = splitValue(arg);
|
|
3424
3790
|
const color = parseColor(parts[0] ?? '');
|
|
3425
3791
|
if (color === null) {
|
|
@@ -3434,14 +3800,18 @@ function parseLinearGradient(text, ctx) {
|
|
|
3434
3800
|
if (at.some((p) => p === null || p === AUTO))
|
|
3435
3801
|
return null;
|
|
3436
3802
|
if (!at.length)
|
|
3437
|
-
|
|
3803
|
+
stops.push({ color, at: null });
|
|
3438
3804
|
for (const p of at)
|
|
3439
|
-
|
|
3805
|
+
stops.push({ color, at: p });
|
|
3440
3806
|
}
|
|
3441
|
-
return
|
|
3807
|
+
return stops.length >= 2 ? stops : null;
|
|
3808
|
+
}
|
|
3809
|
+
/** A gradient function's image, where it is one this draws. */
|
|
3810
|
+
function parseGradient(text, ctx) {
|
|
3811
|
+
return parseLinearGradient(text, ctx) ?? parseRadialGradient(text, ctx);
|
|
3442
3812
|
}
|
|
3443
3813
|
/** The images CSS3 has beyond `url()`, which a layer may name: a linear
|
|
3444
|
-
* gradient
|
|
3814
|
+
* and a radial gradient are drawn, and the rest draw as nothing. */
|
|
3445
3815
|
const IMAGE_FUNCTION = /^(?:-(?:webkit|moz|o|ms)-)?(?:(?:repeating-)?(?:linear|radial|conic)-gradient|gradient|image-set|cross-fade|element|paint)\(/;
|
|
3446
3816
|
function isPositionPart(word, ctx) {
|
|
3447
3817
|
return (word in HORIZONTAL || word in VERTICAL || positionLength(word, ctx) !== null);
|
|
@@ -3474,95 +3844,6 @@ function whiteSpaceOf(collapse, wrap) {
|
|
|
3474
3844
|
return wrap ? 'pre-wrap' : 'pre';
|
|
3475
3845
|
return 'pre-line';
|
|
3476
3846
|
}
|
|
3477
|
-
/**
|
|
3478
|
-
* The translation a `transform` makes: the sum of its translate functions'
|
|
3479
|
-
* and its matrices' — `translate(-50%, -50%)`, Tailwind 3's `translate(
|
|
3480
|
-
* var(--tw-translate-x), var(--tw-translate-y)) rotate(…) skewX(…) …` —
|
|
3481
|
-
* with the functions that rotate, scale, skew or add perspective read and
|
|
3482
|
-
* not drawn. Null for `none`, and undefined for what is no transform list,
|
|
3483
|
-
* which drops the declaration.
|
|
3484
|
-
*/
|
|
3485
|
-
function transformTranslation(value, ctx) {
|
|
3486
|
-
if (value.trim().toLowerCase() === 'none')
|
|
3487
|
-
return null;
|
|
3488
|
-
let x = 0;
|
|
3489
|
-
let y = 0;
|
|
3490
|
-
const parts = splitValue(value);
|
|
3491
|
-
if (!parts.length)
|
|
3492
|
-
return undefined;
|
|
3493
|
-
for (const part of parts) {
|
|
3494
|
-
const m = /^([a-z0-9]+)\((.*)\)$/is.exec(part.trim());
|
|
3495
|
-
if (!m)
|
|
3496
|
-
return undefined;
|
|
3497
|
-
const name = m[1].toLowerCase();
|
|
3498
|
-
const args = splitCommas(m[2]).map((a) => a.trim());
|
|
3499
|
-
let dx = 0;
|
|
3500
|
-
let dy = 0;
|
|
3501
|
-
if (name === 'translate' || name === 'translate3d') {
|
|
3502
|
-
dx = parseLength(args[0] ?? '', ctx);
|
|
3503
|
-
dy = args[1] === undefined ? 0 : parseLength(args[1], ctx);
|
|
3504
|
-
}
|
|
3505
|
-
else if (name === 'translatex')
|
|
3506
|
-
dx = parseLength(args[0] ?? '', ctx);
|
|
3507
|
-
else if (name === 'translatey')
|
|
3508
|
-
dy = parseLength(args[0] ?? '', ctx);
|
|
3509
|
-
else if (name === 'matrix' || name === 'matrix3d') {
|
|
3510
|
-
// the translation is the last column's
|
|
3511
|
-
const n = args.map(Number);
|
|
3512
|
-
if (n.length !== (name === 'matrix' ? 6 : 16) || n.some(isNaN)) {
|
|
3513
|
-
return undefined;
|
|
3514
|
-
}
|
|
3515
|
-
[dx, dy] = name === 'matrix' ? [n[4], n[5]] : [n[12], n[13]];
|
|
3516
|
-
}
|
|
3517
|
-
else if (!TRANSFORMS.has(name))
|
|
3518
|
-
return undefined;
|
|
3519
|
-
if (dx === null || dx === AUTO || dy === null || dy === AUTO) {
|
|
3520
|
-
return undefined;
|
|
3521
|
-
}
|
|
3522
|
-
const sx = addLen(x, dx);
|
|
3523
|
-
const sy = addLen(y, dy);
|
|
3524
|
-
if (sx === null || sy === null)
|
|
3525
|
-
return undefined;
|
|
3526
|
-
x = sx;
|
|
3527
|
-
y = sy;
|
|
3528
|
-
}
|
|
3529
|
-
return [x, y];
|
|
3530
|
-
}
|
|
3531
|
-
/** The transform functions read and not drawn. */
|
|
3532
|
-
const TRANSFORMS = new Set([
|
|
3533
|
-
'translatez',
|
|
3534
|
-
'rotate',
|
|
3535
|
-
'rotatex',
|
|
3536
|
-
'rotatey',
|
|
3537
|
-
'rotatez',
|
|
3538
|
-
'rotate3d',
|
|
3539
|
-
'scale',
|
|
3540
|
-
'scalex',
|
|
3541
|
-
'scaley',
|
|
3542
|
-
'scalez',
|
|
3543
|
-
'scale3d',
|
|
3544
|
-
'skew',
|
|
3545
|
-
'skewx',
|
|
3546
|
-
'skewy',
|
|
3547
|
-
'perspective',
|
|
3548
|
-
]);
|
|
3549
|
-
/** Two lengths added, a percentage and a length kept apart; null where
|
|
3550
|
-
* one is a `min()` or a `max()`, which a sum cannot be kept of. */
|
|
3551
|
-
function addLen(a, b) {
|
|
3552
|
-
if (a === AUTO || b === AUTO)
|
|
3553
|
-
return null;
|
|
3554
|
-
if (typeof a === 'number' && typeof b === 'number')
|
|
3555
|
-
return a + b;
|
|
3556
|
-
if (a === 0)
|
|
3557
|
-
return b;
|
|
3558
|
-
if (b === 0)
|
|
3559
|
-
return a;
|
|
3560
|
-
const pa = typeof a === 'number' ? { pct: 0, px: a } : a;
|
|
3561
|
-
const pb = typeof b === 'number' ? { pct: 0, px: b } : b;
|
|
3562
|
-
if (pa.of || pb.of)
|
|
3563
|
-
return null;
|
|
3564
|
-
return { pct: pa.pct + pb.pct, px: (pa.px ?? 0) + (pb.px ?? 0) };
|
|
3565
|
-
}
|
|
3566
3847
|
/** An intrinsic size keyword, with the prefixes browsers still read, or
|
|
3567
3848
|
* `fit-content()` of a length or a percentage (CSS Sizing 3, 3.1) — a
|
|
3568
3849
|
* width's, where a height's is its content height as the keyword is;
|
|
@@ -4195,6 +4476,34 @@ function splitTopLevelSlash(value) {
|
|
|
4195
4476
|
return out;
|
|
4196
4477
|
}
|
|
4197
4478
|
// --- logical properties ----------------------------------------------------
|
|
4479
|
+
/** `pointer-events`' values besides `none` (CSS UI 4, SVG 2 15.6). */
|
|
4480
|
+
const POINTER_EVENTS = new Set([
|
|
4481
|
+
'auto',
|
|
4482
|
+
'bounding-box',
|
|
4483
|
+
'visiblepainted',
|
|
4484
|
+
'visiblefill',
|
|
4485
|
+
'visiblestroke',
|
|
4486
|
+
'visible',
|
|
4487
|
+
'painted',
|
|
4488
|
+
'fill',
|
|
4489
|
+
'stroke',
|
|
4490
|
+
'all',
|
|
4491
|
+
]);
|
|
4492
|
+
/**
|
|
4493
|
+
* A `fill` or a `stroke` (SVG 2, 13.2): `none`, a colour, or a `url()`
|
|
4494
|
+
* naming a gradient in the drawing, with what follows it, its fallback,
|
|
4495
|
+
* left off. Null for anything else, `context-fill` and `context-stroke`
|
|
4496
|
+
* among it, which only a marker or a `<use>` has a context for.
|
|
4497
|
+
*/
|
|
4498
|
+
function svgPaint(value) {
|
|
4499
|
+
const v = value.trim();
|
|
4500
|
+
if (v.toLowerCase() === 'none')
|
|
4501
|
+
return 'none';
|
|
4502
|
+
const url = /^url\(\s*(['"]?)(#[^'")\s]+)\1\s*\)/i.exec(v);
|
|
4503
|
+
if (url)
|
|
4504
|
+
return `url(${url[2]})`;
|
|
4505
|
+
return parseColor(v);
|
|
4506
|
+
}
|
|
4198
4507
|
const OBJECT_FITS = new Set(['fill', 'contain', 'cover', 'none', 'scale-down']);
|
|
4199
4508
|
/**
|
|
4200
4509
|
* `aspect-ratio` (CSS Sizing 4, 5.1): `auto`, a ratio — one number, or
|
|
@@ -4285,6 +4594,25 @@ function radiusOf(text, ctx) {
|
|
|
4285
4594
|
return len < 0 ? null : len;
|
|
4286
4595
|
return len.pct < 0 && !len.px && !len.of ? null : len;
|
|
4287
4596
|
}
|
|
4597
|
+
/**
|
|
4598
|
+
* `border-radius`'s value: one to four radii, and after a `/` one to four
|
|
4599
|
+
* more for the vertical radii where they differ, elliptical corners — the
|
|
4600
|
+
* radii across, and the ones down, null where they are the same values.
|
|
4601
|
+
* Null for anything else.
|
|
4602
|
+
*/
|
|
4603
|
+
function parseRadii(value, ctx) {
|
|
4604
|
+
const halves = value.split('/');
|
|
4605
|
+
if (halves.length > 2)
|
|
4606
|
+
return null;
|
|
4607
|
+
const [horizontal, vertical] = halves.map((half) => splitValue(half).map((p) => radiusOf(p, ctx)));
|
|
4608
|
+
for (const parts of vertical ? [horizontal, vertical] : [horizontal]) {
|
|
4609
|
+
if (!parts.length || parts.length > 4 || parts.includes(null))
|
|
4610
|
+
return null;
|
|
4611
|
+
}
|
|
4612
|
+
const across = fourSides(horizontal);
|
|
4613
|
+
const down = vertical ? fourSides(vertical) : null;
|
|
4614
|
+
return [across, down && !sameRadii(across, down) ? down : null];
|
|
4615
|
+
}
|
|
4288
4616
|
/** Whether two corners' radii are the same values. */
|
|
4289
4617
|
function sameRadii(a, b) {
|
|
4290
4618
|
for (let i = 0; i < 4; i += 1) {
|
|
@@ -4485,10 +4813,15 @@ const INHERITED_NAMES = new Set([
|
|
|
4485
4813
|
'list-style-position',
|
|
4486
4814
|
'list-style-image',
|
|
4487
4815
|
'cursor',
|
|
4816
|
+
'pointer-events',
|
|
4817
|
+
'fill',
|
|
4818
|
+
'stroke',
|
|
4488
4819
|
'border-collapse',
|
|
4489
4820
|
'border-spacing',
|
|
4490
4821
|
'empty-cells',
|
|
4491
4822
|
'quotes',
|
|
4823
|
+
'orphans',
|
|
4824
|
+
'widows',
|
|
4492
4825
|
]);
|
|
4493
4826
|
export function isInherited(name) {
|
|
4494
4827
|
return INHERITED_NAMES.has(name);
|
|
@@ -4629,6 +4962,9 @@ const INHERIT_TARGETS = {
|
|
|
4629
4962
|
'list-style-position': ['listStylePosition'],
|
|
4630
4963
|
'list-style-image': ['listStyleImage'],
|
|
4631
4964
|
cursor: ['cursor'],
|
|
4965
|
+
'pointer-events': ['pointerEvents'],
|
|
4966
|
+
fill: ['fill'],
|
|
4967
|
+
stroke: ['stroke'],
|
|
4632
4968
|
'border-collapse': ['borderCollapse'],
|
|
4633
4969
|
'caption-side': ['captionSide'],
|
|
4634
4970
|
'empty-cells': ['emptyCells'],
|
|
@@ -4695,9 +5031,16 @@ const INHERIT_TARGETS = {
|
|
|
4695
5031
|
'-webkit-box-pack': ['webkitBoxPack'],
|
|
4696
5032
|
'-webkit-box-align': ['webkitBoxAlign'],
|
|
4697
5033
|
'-webkit-box-flex': ['webkitBoxFlex'],
|
|
4698
|
-
columns: ['columns'],
|
|
4699
|
-
'column-count': ['columns'],
|
|
4700
|
-
'column-width': ['columns'],
|
|
5034
|
+
columns: ['columns', 'columnCount', 'columnWidth'],
|
|
5035
|
+
'column-count': ['columns', 'columnCount'],
|
|
5036
|
+
'column-width': ['columns', 'columnWidth'],
|
|
5037
|
+
orphans: ['orphans'],
|
|
5038
|
+
widows: ['widows'],
|
|
5039
|
+
'break-inside': ['breakInside'],
|
|
5040
|
+
'column-fill': ['columnFill'],
|
|
5041
|
+
'column-span': ['columnSpan'],
|
|
5042
|
+
'-webkit-column-span': ['columnSpan'],
|
|
5043
|
+
'page-break-inside': ['breakInside'],
|
|
4701
5044
|
'text-overflow': ['textOverflow'],
|
|
4702
5045
|
// a flex box's and its items', and a grid's
|
|
4703
5046
|
'flex-direction': ['flexDirection'],
|
|
@@ -4712,12 +5055,12 @@ const INHERIT_TARGETS = {
|
|
|
4712
5055
|
'flex-shrink': ['flexShrink'],
|
|
4713
5056
|
'flex-basis': ['flexBasis'],
|
|
4714
5057
|
order: ['order'],
|
|
4715
|
-
gap: ['rowGap', 'columnGap'],
|
|
5058
|
+
gap: ['rowGap', 'columnGap', 'columnGapNormal'],
|
|
4716
5059
|
'row-gap': ['rowGap'],
|
|
4717
|
-
'column-gap': ['columnGap'],
|
|
4718
|
-
'grid-gap': ['rowGap', 'columnGap'],
|
|
5060
|
+
'column-gap': ['columnGap', 'columnGapNormal'],
|
|
5061
|
+
'grid-gap': ['rowGap', 'columnGap', 'columnGapNormal'],
|
|
4719
5062
|
'grid-row-gap': ['rowGap'],
|
|
4720
|
-
'grid-column-gap': ['columnGap'],
|
|
5063
|
+
'grid-column-gap': ['columnGap', 'columnGapNormal'],
|
|
4721
5064
|
'grid-template-columns': ['gridColumns'],
|
|
4722
5065
|
'grid-template-rows': ['gridRows'],
|
|
4723
5066
|
'grid-auto-rows': ['gridAutoRows'],
|
|
@@ -4812,11 +5155,18 @@ const INHERIT_TARGETS = {
|
|
|
4812
5155
|
clear: ['clear'],
|
|
4813
5156
|
overflow: ['overflowX', 'overflowY'],
|
|
4814
5157
|
clip: ['clip'],
|
|
5158
|
+
'clip-path': ['clipPath'],
|
|
5159
|
+
'-webkit-clip-path': ['clipPath'],
|
|
4815
5160
|
'overflow-x': ['overflowX'],
|
|
4816
5161
|
'overflow-y': ['overflowY'],
|
|
4817
5162
|
opacity: ['opacity'],
|
|
4818
5163
|
translate: ['translate'],
|
|
4819
|
-
|
|
5164
|
+
rotate: ['rotate'],
|
|
5165
|
+
scale: ['scale'],
|
|
5166
|
+
transform: ['transform'],
|
|
5167
|
+
'-webkit-transform': ['transform'],
|
|
5168
|
+
'transform-origin': ['transformOrigin'],
|
|
5169
|
+
'-webkit-transform-origin': ['transformOrigin'],
|
|
4820
5170
|
'z-index': ['zIndex'],
|
|
4821
5171
|
'vertical-align': ['verticalAlign'],
|
|
4822
5172
|
'text-decoration': [
|
|
@@ -4871,13 +5221,30 @@ export function decorate(style) {
|
|
|
4871
5221
|
if (lines.includes('underline')) {
|
|
4872
5222
|
style.underline = inkColor(style.textDecorationColor ?? 'currentColor', style.color);
|
|
4873
5223
|
style.underlineStyle = style.textDecorationStyle;
|
|
4874
|
-
style.underlineThickness = style
|
|
5224
|
+
style.underlineThickness = usedThickness(style);
|
|
4875
5225
|
style.underlineOffset = style.textUnderlineOffset;
|
|
4876
5226
|
}
|
|
4877
5227
|
if (lines.includes('line-through')) {
|
|
4878
5228
|
style.lineThrough = inkColor(style.textDecorationColor ?? 'currentColor', style.color);
|
|
5229
|
+
style.lineThroughStyle = style.textDecorationStyle;
|
|
5230
|
+
style.lineThroughThickness = usedThickness(style);
|
|
4879
5231
|
}
|
|
4880
5232
|
}
|
|
5233
|
+
/**
|
|
5234
|
+
* How thick the lines a box decorates its text with are. `auto` leaves it
|
|
5235
|
+
* to the user agent, which is to take it from the font where the font says
|
|
5236
|
+
* (CSS Text Decoration 4, 2.4.1); neither text engine here reports a face's
|
|
5237
|
+
* underline, so it is a part of the font size, Blink's tenth — of the size
|
|
5238
|
+
* of the box that set the decoration, which draws one line of one thickness
|
|
5239
|
+
* through everything inside it (2.9). A pixel for every size drew the dots
|
|
5240
|
+
* under the `<abbr>` of a 140px title as a hairline. `from-font` is `auto`
|
|
5241
|
+
* for the same want of a metric, a length is itself on whole pixels, and
|
|
5242
|
+
* no line is thinner than one.
|
|
5243
|
+
*/
|
|
5244
|
+
function usedThickness(style) {
|
|
5245
|
+
const length = style.textDecorationThickness;
|
|
5246
|
+
return Math.max(1, length === null ? style.fontSize / 10 : Math.round(length));
|
|
5247
|
+
}
|
|
4881
5248
|
/**
|
|
4882
5249
|
* The absolutely positioned styles that were inline-level before they were
|
|
4883
5250
|
* made blocks: where such a box would have been in flow is on its line,
|
|
@@ -4984,4 +5351,54 @@ export function blockify(style, inFlexContainer) {
|
|
|
4984
5351
|
return;
|
|
4985
5352
|
}
|
|
4986
5353
|
}
|
|
5354
|
+
/**
|
|
5355
|
+
* The `display` a `<button>` is laid out with, which is not always the one
|
|
5356
|
+
* it was given (HTML's rendering section, button layout, 15.5.3): a flex
|
|
5357
|
+
* box or a grid is that, and of the rest, "a value such that the outer
|
|
5358
|
+
* display type is 'inline'" behaves as `inline-block` and anything else as
|
|
5359
|
+
* `flow-root`. Blink computes them so — `inline-block` for `inline` and
|
|
5360
|
+
* `inline-table`, `block` for `table` and `list-item` — and makes the one
|
|
5361
|
+
* block flow of each; the formatting context is the layout's to give every
|
|
5362
|
+
* button that is a block (`establishesBFC`).
|
|
5363
|
+
*
|
|
5364
|
+
* Left an inline box, a button around a block was broken in two around it,
|
|
5365
|
+
* as any inline box is: as wide as the line, its `height` applied to
|
|
5366
|
+
* nothing, and its border and padding drawn above and below the line it
|
|
5367
|
+
* opened. A table's part is left what it is, where the two disagree: a
|
|
5368
|
+
* block to the text, an inline-block in Blink. After `blockify`, since a
|
|
5369
|
+
* float, an absolute box and a flex item are blocks first.
|
|
5370
|
+
*/
|
|
5371
|
+
export function settleButton(style) {
|
|
5372
|
+
switch (style.display) {
|
|
5373
|
+
case 'inline':
|
|
5374
|
+
case 'inline-table':
|
|
5375
|
+
style.display = 'inline-block';
|
|
5376
|
+
return;
|
|
5377
|
+
case 'list-item':
|
|
5378
|
+
case 'table':
|
|
5379
|
+
style.display = 'block';
|
|
5380
|
+
return;
|
|
5381
|
+
default:
|
|
5382
|
+
return;
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
/** The generic font families, which a list ending in one falls back
|
|
5386
|
+
* through already, in the text engine (CSS Fonts 4, 4.2). */
|
|
5387
|
+
const GENERIC_FAMILY = new Set([
|
|
5388
|
+
'serif',
|
|
5389
|
+
'sans-serif',
|
|
5390
|
+
'monospace',
|
|
5391
|
+
'cursive',
|
|
5392
|
+
'fantasy',
|
|
5393
|
+
'system-ui',
|
|
5394
|
+
'ui-serif',
|
|
5395
|
+
'ui-sans-serif',
|
|
5396
|
+
'ui-monospace',
|
|
5397
|
+
'ui-rounded',
|
|
5398
|
+
'math',
|
|
5399
|
+
'emoji',
|
|
5400
|
+
'fangsong',
|
|
5401
|
+
'-apple-system',
|
|
5402
|
+
'blinkmacsystemfont',
|
|
5403
|
+
]);
|
|
4987
5404
|
//# sourceMappingURL=style.js.map
|