@react-x11/components 0.13.0 → 0.14.1
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 +42 -1
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +336 -16
- 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/shapes.d.ts +44 -0
- package/dist/html/css/shapes.d.ts.map +1 -0
- package/dist/html/css/shapes.js +194 -0
- package/dist/html/css/shapes.js.map +1 -0
- 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 +547 -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 +104 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +410 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +72 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +40 -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 +144 -24
- 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 +585 -85
- 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 +97 -31
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +4 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +319 -47
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +83 -5
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1474 -217
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +39 -9
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +482 -37
- 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 +366 -8
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +71 -31
- package/src/html/css/shapes.ts +239 -0
- package/src/html/css/style.ts +652 -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 +466 -37
- package/src/html/layout/boxes.ts +95 -3
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +169 -32
- package/src/html/layout/flex.ts +686 -79
- 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 +105 -35
- package/src/html/node.ts +354 -48
- package/src/html/paint.ts +1804 -315
- package/src/html/svg.ts +573 -36
- 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,7 +15,9 @@
|
|
|
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';
|
|
20
|
+
import { svgPaint } from './shapes.js';
|
|
19
21
|
/** Whether a length is one `padding` takes: not `auto`, not negative. A
|
|
20
22
|
* `calc()` with a percentage in it has no sign until layout, which clamps
|
|
21
23
|
* it at zero (CSS Values 4 10.12). */
|
|
@@ -58,6 +60,93 @@ function parseClip(value, ctx) {
|
|
|
58
60
|
}
|
|
59
61
|
return { top: edges[0], right: edges[1], bottom: edges[2], left: edges[3] };
|
|
60
62
|
}
|
|
63
|
+
/** The boxes `clip-path` names; an SVG one is the CSS box that stands for
|
|
64
|
+
* it on an element with a CSS layout box (5.1). */
|
|
65
|
+
const CLIP_BOXES = {
|
|
66
|
+
'margin-box': 'margin-box',
|
|
67
|
+
'border-box': 'border-box',
|
|
68
|
+
'padding-box': 'padding-box',
|
|
69
|
+
'content-box': 'content-box',
|
|
70
|
+
'fill-box': 'content-box',
|
|
71
|
+
'stroke-box': 'border-box',
|
|
72
|
+
'view-box': 'border-box',
|
|
73
|
+
};
|
|
74
|
+
/** The shapes that are no rectangle, and a reference to a `<clipPath>`
|
|
75
|
+
* element: a value, which sets the property, and none this draws. */
|
|
76
|
+
const UNDRAWN_CLIPS = /^(circle|ellipse|polygon|path|shape|url)\(/i;
|
|
77
|
+
const NO_LENGTHS = [0, 0, 0, 0];
|
|
78
|
+
/**
|
|
79
|
+
* `none`; a rectangle's function, a box, or the two in either order; or a
|
|
80
|
+
* shape that is no rectangle, which is a value and clips nothing here.
|
|
81
|
+
* Undefined for anything else, which leaves the value as it was.
|
|
82
|
+
*/
|
|
83
|
+
function parseClipPath(value, ctx) {
|
|
84
|
+
const v = value.trim();
|
|
85
|
+
if (/^none$/i.test(v))
|
|
86
|
+
return null;
|
|
87
|
+
let box = null;
|
|
88
|
+
let shape;
|
|
89
|
+
for (const part of splitValue(v)) {
|
|
90
|
+
const named = CLIP_BOXES[part.toLowerCase()];
|
|
91
|
+
if (named) {
|
|
92
|
+
if (box)
|
|
93
|
+
return undefined;
|
|
94
|
+
box = named;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (shape !== undefined)
|
|
98
|
+
return undefined;
|
|
99
|
+
if (UNDRAWN_CLIPS.test(part) && part.endsWith(')'))
|
|
100
|
+
shape = null;
|
|
101
|
+
else
|
|
102
|
+
shape = rectShape(part, ctx);
|
|
103
|
+
if (shape === undefined)
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
if (shape === null)
|
|
107
|
+
return null;
|
|
108
|
+
if (shape)
|
|
109
|
+
return { box: box ?? 'border-box', ...shape };
|
|
110
|
+
if (!box)
|
|
111
|
+
return undefined;
|
|
112
|
+
return { box, shape: null, lengths: NO_LENGTHS, radii: null, radiiY: null };
|
|
113
|
+
}
|
|
114
|
+
/** `inset()`, `rect()` or `xywh()`, with the corners it rounds; undefined
|
|
115
|
+
* for anything else. */
|
|
116
|
+
function rectShape(text, ctx) {
|
|
117
|
+
const m = /^(inset|rect|xywh)\((.*)\)$/is.exec(text);
|
|
118
|
+
if (!m)
|
|
119
|
+
return undefined;
|
|
120
|
+
const shape = m[1].toLowerCase();
|
|
121
|
+
const parts = splitValue(m[2].trim());
|
|
122
|
+
const round = parts.findIndex((p) => p.toLowerCase() === 'round');
|
|
123
|
+
const sides = round < 0 ? parts : parts.slice(0, round);
|
|
124
|
+
let radii = null;
|
|
125
|
+
let radiiY = null;
|
|
126
|
+
if (round >= 0) {
|
|
127
|
+
const corners = parseRadii(parts.slice(round + 1).join(' '), ctx);
|
|
128
|
+
if (!corners)
|
|
129
|
+
return undefined;
|
|
130
|
+
[radii, radiiY] = corners;
|
|
131
|
+
}
|
|
132
|
+
// one to four insets, as a margin's sides are written; the other two
|
|
133
|
+
// take all four
|
|
134
|
+
if (shape === 'inset' ? !sides.length || sides.length > 4 : sides.length !== 4)
|
|
135
|
+
return undefined;
|
|
136
|
+
const lengths = [];
|
|
137
|
+
for (let i = 0; i < sides.length; i += 1) {
|
|
138
|
+
const len = parseLength(sides[i], ctx);
|
|
139
|
+
if (len === null)
|
|
140
|
+
return undefined;
|
|
141
|
+
// only `rect()` has an edge that is `auto`, and a width is not negative
|
|
142
|
+
if (len === AUTO && shape !== 'rect')
|
|
143
|
+
return undefined;
|
|
144
|
+
if (shape === 'xywh' && i > 1 && !notNegative(len))
|
|
145
|
+
return undefined;
|
|
146
|
+
lengths.push(len);
|
|
147
|
+
}
|
|
148
|
+
return { shape, lengths: fourSides(lengths), radii, radiiY };
|
|
149
|
+
}
|
|
61
150
|
/** The properties that inherit. Named once, so `inherit()` and the `inherit`
|
|
62
151
|
* keyword cannot disagree about the list. */
|
|
63
152
|
/** The fields a style takes from its parent's (CSS 2.1's "Inherited:
|
|
@@ -92,6 +181,8 @@ export const INHERITED = [
|
|
|
92
181
|
'fontFeatureSettings',
|
|
93
182
|
'tabSize',
|
|
94
183
|
'tabSizeIsLength',
|
|
184
|
+
'orphans',
|
|
185
|
+
'widows',
|
|
95
186
|
'whiteSpace',
|
|
96
187
|
'overflowWrap',
|
|
97
188
|
'wordBreak',
|
|
@@ -103,6 +194,9 @@ export const INHERITED = [
|
|
|
103
194
|
'listStylePosition',
|
|
104
195
|
'listStyleImage',
|
|
105
196
|
'cursor',
|
|
197
|
+
'pointerEvents',
|
|
198
|
+
'fill',
|
|
199
|
+
'stroke',
|
|
106
200
|
'borderCollapse',
|
|
107
201
|
'borderSpacing',
|
|
108
202
|
'borderSpacingY',
|
|
@@ -154,6 +248,9 @@ export function initialStyle(look, scale = 1) {
|
|
|
154
248
|
listStylePosition: 'outside',
|
|
155
249
|
listStyleImage: null,
|
|
156
250
|
cursor: null,
|
|
251
|
+
pointerEvents: 'auto',
|
|
252
|
+
fill: null,
|
|
253
|
+
stroke: null,
|
|
157
254
|
borderCollapse: 'separate',
|
|
158
255
|
// CSS's initial value; a `<table>` gets its 2px from the UA sheet, and
|
|
159
256
|
// an anonymous table, which no sheet names, has none
|
|
@@ -188,6 +285,14 @@ export function initialStyle(look, scale = 1) {
|
|
|
188
285
|
webkitBoxAlign: null,
|
|
189
286
|
webkitBoxFlex: 0,
|
|
190
287
|
columns: 0,
|
|
288
|
+
columnCount: null,
|
|
289
|
+
columnWidth: null,
|
|
290
|
+
columnGapNormal: true,
|
|
291
|
+
orphans: 2,
|
|
292
|
+
widows: 2,
|
|
293
|
+
breakInside: 'auto',
|
|
294
|
+
columnFill: 'balance',
|
|
295
|
+
columnSpan: false,
|
|
191
296
|
textOverflow: 'clip',
|
|
192
297
|
aspectRatio: null,
|
|
193
298
|
objectFit: 'fill',
|
|
@@ -197,9 +302,13 @@ export function initialStyle(look, scale = 1) {
|
|
|
197
302
|
overflowX: 'visible',
|
|
198
303
|
overflowY: 'visible',
|
|
199
304
|
clip: null,
|
|
305
|
+
clipPath: null,
|
|
200
306
|
opacity: 1,
|
|
201
307
|
translate: null,
|
|
202
|
-
|
|
308
|
+
rotate: null,
|
|
309
|
+
scale: null,
|
|
310
|
+
transform: null,
|
|
311
|
+
transformOrigin: [{ pct: 50 }, { pct: 50 }],
|
|
203
312
|
zIndex: AUTO,
|
|
204
313
|
verticalAlign: 'baseline',
|
|
205
314
|
width: AUTO,
|
|
@@ -283,6 +392,8 @@ export function initialStyle(look, scale = 1) {
|
|
|
283
392
|
underlineThickness: null,
|
|
284
393
|
underlineOffset: null,
|
|
285
394
|
lineThrough: null,
|
|
395
|
+
lineThroughStyle: 'solid',
|
|
396
|
+
lineThroughThickness: null,
|
|
286
397
|
flexDirection: 'row',
|
|
287
398
|
flexWrap: 'nowrap',
|
|
288
399
|
justifyContent: 'normal',
|
|
@@ -381,6 +492,8 @@ export function inherit(parent, initial) {
|
|
|
381
492
|
out.fontFeatureSettings = parent.fontFeatureSettings;
|
|
382
493
|
out.tabSize = parent.tabSize;
|
|
383
494
|
out.tabSizeIsLength = parent.tabSizeIsLength;
|
|
495
|
+
out.orphans = parent.orphans;
|
|
496
|
+
out.widows = parent.widows;
|
|
384
497
|
out.whiteSpace = parent.whiteSpace;
|
|
385
498
|
out.overflowWrap = parent.overflowWrap;
|
|
386
499
|
out.wordBreak = parent.wordBreak;
|
|
@@ -392,6 +505,9 @@ export function inherit(parent, initial) {
|
|
|
392
505
|
out.listStylePosition = parent.listStylePosition;
|
|
393
506
|
out.listStyleImage = parent.listStyleImage;
|
|
394
507
|
out.cursor = parent.cursor;
|
|
508
|
+
out.pointerEvents = parent.pointerEvents;
|
|
509
|
+
out.fill = parent.fill;
|
|
510
|
+
out.stroke = parent.stroke;
|
|
395
511
|
out.borderCollapse = parent.borderCollapse;
|
|
396
512
|
out.borderSpacing = parent.borderSpacing;
|
|
397
513
|
out.borderSpacingY = parent.borderSpacingY;
|
|
@@ -411,6 +527,8 @@ export function inherit(parent, initial) {
|
|
|
411
527
|
out.underlineThickness = parent.underlineThickness;
|
|
412
528
|
out.underlineOffset = parent.underlineOffset;
|
|
413
529
|
out.lineThrough = parent.lineThrough;
|
|
530
|
+
out.lineThroughStyle = parent.lineThroughStyle;
|
|
531
|
+
out.lineThroughThickness = parent.lineThroughThickness;
|
|
414
532
|
return out;
|
|
415
533
|
}
|
|
416
534
|
/**
|
|
@@ -444,6 +562,8 @@ export const FIRST_LINE_INHERITED = [
|
|
|
444
562
|
'underlineThickness',
|
|
445
563
|
'underlineOffset',
|
|
446
564
|
'lineThrough',
|
|
565
|
+
'lineThroughStyle',
|
|
566
|
+
'lineThroughThickness',
|
|
447
567
|
];
|
|
448
568
|
/**
|
|
449
569
|
* What a box on its block's first line inherits from: its parent's style,
|
|
@@ -501,6 +621,14 @@ const BORDER_WIDTH_KEYWORDS = {
|
|
|
501
621
|
medium: 3,
|
|
502
622
|
thick: 5,
|
|
503
623
|
};
|
|
624
|
+
/** `-webkit-` names that are the multicol properties' own. */
|
|
625
|
+
const MULTICOL_ALIASES = {
|
|
626
|
+
'-webkit-columns': 'columns',
|
|
627
|
+
'-webkit-column-count': 'column-count',
|
|
628
|
+
'-webkit-column-width': 'column-width',
|
|
629
|
+
'-webkit-column-gap': 'column-gap',
|
|
630
|
+
'-webkit-column-break-inside': 'break-inside',
|
|
631
|
+
};
|
|
504
632
|
/**
|
|
505
633
|
* Apply one declaration to a style, in place.
|
|
506
634
|
*
|
|
@@ -510,7 +638,12 @@ const BORDER_WIDTH_KEYWORDS = {
|
|
|
510
638
|
* correct response to every one of them is to render the rest.
|
|
511
639
|
*/
|
|
512
640
|
export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
513
|
-
const
|
|
641
|
+
const written = prop.toLowerCase();
|
|
642
|
+
// the multicol properties under the names WebKit had them by, which
|
|
643
|
+
// Blink still reads, each an alias of the property (`-webkit-column-
|
|
644
|
+
// count` in its `css_properties.json5`): a page written for it alone
|
|
645
|
+
// names no other
|
|
646
|
+
const name = MULTICOL_ALIASES[written] ?? written;
|
|
514
647
|
let value = rawValue.trim();
|
|
515
648
|
if (!value)
|
|
516
649
|
return;
|
|
@@ -645,21 +778,75 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
645
778
|
case 'column-count':
|
|
646
779
|
case 'column-width':
|
|
647
780
|
case 'columns': {
|
|
648
|
-
// `auto`, or a count, a width or both of them
|
|
781
|
+
// `auto`, or a count, a width or both of them, in either order; what
|
|
782
|
+
// the shorthand leaves out is `auto`
|
|
649
783
|
const bit = name === 'column-count' ? 1 : name === 'column-width' ? 2 : 3;
|
|
650
|
-
let
|
|
784
|
+
let count = null;
|
|
785
|
+
let width = null;
|
|
651
786
|
for (const part of splitValue(value)) {
|
|
652
787
|
const v = part.toLowerCase();
|
|
653
788
|
if (v === 'auto')
|
|
654
789
|
continue;
|
|
655
|
-
if (/^\d+$/.test(v) && Number(v) >= 1)
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
790
|
+
if (/^\d+$/.test(v) && Number(v) >= 1) {
|
|
791
|
+
if (count !== null || !(bit & 1))
|
|
792
|
+
return;
|
|
793
|
+
count = Number(v);
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
const len = parseLength(part, ctx);
|
|
797
|
+
if (typeof len !== 'number' || !(len > 0))
|
|
798
|
+
return;
|
|
799
|
+
if (width !== null || !(bit & 2))
|
|
800
|
+
return;
|
|
801
|
+
width = len;
|
|
802
|
+
}
|
|
803
|
+
if (bit & 1)
|
|
804
|
+
style.columnCount = count;
|
|
805
|
+
if (bit & 2)
|
|
806
|
+
style.columnWidth = width;
|
|
807
|
+
style.columns =
|
|
808
|
+
(style.columnCount !== null ? 1 : 0) |
|
|
809
|
+
(style.columnWidth !== null ? 2 : 0);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
case 'orphans':
|
|
813
|
+
case 'widows': {
|
|
814
|
+
// a whole number of lines, one or more
|
|
815
|
+
const v = value.trim();
|
|
816
|
+
if (!/^\+?\d+$/.test(v) || Number(v) < 1)
|
|
817
|
+
return;
|
|
818
|
+
style[name] = Number(v);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
case '-webkit-column-span':
|
|
822
|
+
case 'column-span': {
|
|
823
|
+
const v = value.trim().toLowerCase();
|
|
824
|
+
if (v === 'all')
|
|
825
|
+
style.columnSpan = true;
|
|
826
|
+
else if (v === 'none')
|
|
827
|
+
style.columnSpan = false;
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
case 'column-fill': {
|
|
831
|
+
const v = value.trim().toLowerCase();
|
|
832
|
+
if (v === 'auto')
|
|
833
|
+
style.columnFill = 'auto';
|
|
834
|
+
else if (v === 'balance' || v === 'balance-all') {
|
|
835
|
+
style.columnFill = 'balance';
|
|
836
|
+
}
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
case 'break-inside':
|
|
840
|
+
case 'page-break-inside': {
|
|
841
|
+
const v = value.trim().toLowerCase();
|
|
842
|
+
if (v === 'auto')
|
|
843
|
+
style.breakInside = 'auto';
|
|
844
|
+
else if (/^avoid(?:-page|-column|-region)?$/.test(v)) {
|
|
845
|
+
// the legacy property knows `avoid` alone
|
|
846
|
+
if (name === 'page-break-inside' && v !== 'avoid')
|
|
660
847
|
return;
|
|
848
|
+
style.breakInside = 'avoid';
|
|
661
849
|
}
|
|
662
|
-
style.columns = (style.columns & ~bit) | (set & bit);
|
|
663
850
|
return;
|
|
664
851
|
}
|
|
665
852
|
case '-webkit-box-flex': {
|
|
@@ -927,6 +1114,13 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
927
1114
|
style.clip = clip;
|
|
928
1115
|
return;
|
|
929
1116
|
}
|
|
1117
|
+
case 'clip-path':
|
|
1118
|
+
case '-webkit-clip-path': {
|
|
1119
|
+
const path = parseClipPath(value, ctx);
|
|
1120
|
+
if (path !== undefined)
|
|
1121
|
+
style.clipPath = path;
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
930
1124
|
case 'opacity': {
|
|
931
1125
|
const a = parseAlpha(value);
|
|
932
1126
|
if (a !== null)
|
|
@@ -950,10 +1144,38 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
950
1144
|
style.translate = [x, y ?? 0];
|
|
951
1145
|
return;
|
|
952
1146
|
}
|
|
953
|
-
case '
|
|
954
|
-
const
|
|
955
|
-
if (
|
|
956
|
-
style.
|
|
1147
|
+
case 'rotate': {
|
|
1148
|
+
const turn = parseRotate(value);
|
|
1149
|
+
if (turn !== undefined)
|
|
1150
|
+
style.rotate = turn;
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
case 'scale': {
|
|
1154
|
+
const factors = parseScale(value);
|
|
1155
|
+
if (factors !== undefined)
|
|
1156
|
+
style.scale = factors;
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
case 'transform':
|
|
1160
|
+
case '-webkit-transform': {
|
|
1161
|
+
const list = parseTransform(value, ctx);
|
|
1162
|
+
if (list !== undefined)
|
|
1163
|
+
style.transform = list;
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
case 'transform-origin':
|
|
1167
|
+
case '-webkit-transform-origin': {
|
|
1168
|
+
// across and down, as a position is, and a depth nothing here has
|
|
1169
|
+
const parts = splitValue(value);
|
|
1170
|
+
if (parts.length === 3) {
|
|
1171
|
+
if (typeof parseLength(parts.pop(), ctx) !== 'number')
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
else if (parts.length > 2)
|
|
1175
|
+
return;
|
|
1176
|
+
const origin = positionPair(parts, ctx);
|
|
1177
|
+
if (origin)
|
|
1178
|
+
style.transformOrigin = origin;
|
|
957
1179
|
return;
|
|
958
1180
|
}
|
|
959
1181
|
case 'visibility': {
|
|
@@ -1242,19 +1464,9 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1242
1464
|
return;
|
|
1243
1465
|
}
|
|
1244
1466
|
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;
|
|
1467
|
+
const radii = parseRadii(value, ctx);
|
|
1468
|
+
if (radii)
|
|
1469
|
+
[style.borderRadius, style.borderRadiusY] = radii;
|
|
1258
1470
|
return;
|
|
1259
1471
|
}
|
|
1260
1472
|
// --- background ---------------------------------------------------------
|
|
@@ -1509,7 +1721,19 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1509
1721
|
: f.trim().replace(/[ \t\n\r\f]+/g, ' '))
|
|
1510
1722
|
.filter(Boolean)
|
|
1511
1723
|
.join(', ');
|
|
1512
|
-
|
|
1724
|
+
// A list that ends in no generic family ends in the document's own
|
|
1725
|
+
// font: where no face in the list matches, the text is set in the
|
|
1726
|
+
// user agent's default (CSS Fonts 4, 5.1), which for a browser is its
|
|
1727
|
+
// standard font and here is the one the document is set in. The text
|
|
1728
|
+
// engine's own answer for a name nothing has is its platform's pick,
|
|
1729
|
+
// Verdana under fontconfig: the Zen Garden's 216 sets its summary in
|
|
1730
|
+
// Montserrat alone, which no machine here has, and Chrome sets it in
|
|
1731
|
+
// Times where ours was Verdana, a fifth wider
|
|
1732
|
+
const last = names[names.length - 1].trim();
|
|
1733
|
+
const generic = !/^['"]/.test(last) && GENERIC_FAMILY.has(last.toLowerCase());
|
|
1734
|
+
const fallback = generic ? null : (ctx.fallbackFamily?.() ?? null);
|
|
1735
|
+
const full = fallback ? `${list}, ${fallback}` : list;
|
|
1736
|
+
style.fontFamily = ctx.families ? ctx.families(full) : full;
|
|
1513
1737
|
return;
|
|
1514
1738
|
}
|
|
1515
1739
|
case 'font-size': {
|
|
@@ -1933,6 +2157,23 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
1933
2157
|
style.cursor = splitCommas(value)[0]?.trim().toLowerCase() || null;
|
|
1934
2158
|
return;
|
|
1935
2159
|
}
|
|
2160
|
+
case 'pointer-events': {
|
|
2161
|
+
// `none`, or one of the values SVG gives it, which are `auto` on
|
|
2162
|
+
// anything that is not SVG's to draw
|
|
2163
|
+
const v = value.trim().toLowerCase();
|
|
2164
|
+
if (v === 'none')
|
|
2165
|
+
style.pointerEvents = 'none';
|
|
2166
|
+
else if (POINTER_EVENTS.has(v))
|
|
2167
|
+
style.pointerEvents = 'auto';
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
2170
|
+
case 'fill':
|
|
2171
|
+
case 'stroke': {
|
|
2172
|
+
const paint = svgPaint(value);
|
|
2173
|
+
if (paint !== null)
|
|
2174
|
+
style[name] = paint;
|
|
2175
|
+
return;
|
|
2176
|
+
}
|
|
1936
2177
|
// --- lists --------------------------------------------------------------
|
|
1937
2178
|
case 'list-style': {
|
|
1938
2179
|
// a type, a position and an image, each at most once and in any
|
|
@@ -2132,8 +2373,11 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
|
|
|
2132
2373
|
return;
|
|
2133
2374
|
if (which !== 'column-gap')
|
|
2134
2375
|
style.rowGap = row;
|
|
2135
|
-
if (which !== 'row-gap')
|
|
2376
|
+
if (which !== 'row-gap') {
|
|
2136
2377
|
style.columnGap = col;
|
|
2378
|
+
const word = parts[parts.length - 1].toLowerCase();
|
|
2379
|
+
style.columnGapNormal = word === 'normal';
|
|
2380
|
+
}
|
|
2137
2381
|
return;
|
|
2138
2382
|
}
|
|
2139
2383
|
case 'grid-template-columns':
|
|
@@ -2605,6 +2849,12 @@ function alignKeyword(value) {
|
|
|
2605
2849
|
return 'flex-end';
|
|
2606
2850
|
case 'first baseline':
|
|
2607
2851
|
return 'baseline';
|
|
2852
|
+
// By last baselines, which nothing here aligns: set where that falls
|
|
2853
|
+
// back to, the end (CSS Box Alignment 3, 4.2). Dropped, a row that asks
|
|
2854
|
+
// for it stretched its items, and a flex box among them was as tall as
|
|
2855
|
+
// the row, its lines spread down it.
|
|
2856
|
+
case 'last baseline':
|
|
2857
|
+
return 'flex-end';
|
|
2608
2858
|
case 'center':
|
|
2609
2859
|
return 'center';
|
|
2610
2860
|
case 'stretch':
|
|
@@ -3226,7 +3476,7 @@ function applyBackgroundShorthand(style, value, ctx) {
|
|
|
3226
3476
|
function backgroundImageOf(text, ctx) {
|
|
3227
3477
|
const v = text.trim();
|
|
3228
3478
|
if (IMAGE_FUNCTION.test(v.toLowerCase()))
|
|
3229
|
-
return
|
|
3479
|
+
return parseGradient(v, ctx);
|
|
3230
3480
|
return parseUrl(v);
|
|
3231
3481
|
}
|
|
3232
3482
|
/** A background property's values, one a comma-separated layer, each read
|
|
@@ -3248,7 +3498,7 @@ function layerValues(value, read) {
|
|
|
3248
3498
|
* is dropped rather than resetting the background it meant to replace
|
|
3249
3499
|
* (CSS 2.1 4.2). What CSS3 adds is read too, so that a declaration a
|
|
3250
3500
|
* browser keeps is kept: `/ cover` after the position, `space` and `round`,
|
|
3251
|
-
* a gradient
|
|
3501
|
+
* and a gradient, over the layer's colour.
|
|
3252
3502
|
*/
|
|
3253
3503
|
function readBackgroundLayer(text, ctx, last) {
|
|
3254
3504
|
const parts = splitValue(text).flatMap(splitSlash);
|
|
@@ -3284,7 +3534,7 @@ function readBackgroundLayer(text, ctx, last) {
|
|
|
3284
3534
|
layer.image = url;
|
|
3285
3535
|
}
|
|
3286
3536
|
else if (v !== 'none')
|
|
3287
|
-
layer.gradient =
|
|
3537
|
+
layer.gradient = parseGradient(part, ctx);
|
|
3288
3538
|
i += 1;
|
|
3289
3539
|
}
|
|
3290
3540
|
else if (v === 'repeat-x' || v === 'repeat-y' || REPEATS.has(v)) {
|
|
@@ -3363,21 +3613,21 @@ function readBackgroundLayer(text, ctx, last) {
|
|
|
3363
3613
|
}
|
|
3364
3614
|
/**
|
|
3365
3615
|
* 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.
|
|
3616
|
+
* that is no gradient: a direction by angle, by side or by corner, and its
|
|
3617
|
+
* colour stops.
|
|
3370
3618
|
*/
|
|
3371
3619
|
function parseLinearGradient(text, ctx) {
|
|
3372
3620
|
const m = /^linear-gradient\((.*)\)$/is.exec(text.trim());
|
|
3373
3621
|
if (!m)
|
|
3374
3622
|
return null;
|
|
3375
3623
|
const args = splitCommas(m[1]).map((a) => a.trim());
|
|
3376
|
-
const out = {
|
|
3377
|
-
|
|
3378
|
-
.
|
|
3379
|
-
|
|
3380
|
-
|
|
3624
|
+
const out = {
|
|
3625
|
+
kind: 'linear',
|
|
3626
|
+
angle: Math.PI,
|
|
3627
|
+
corner: null,
|
|
3628
|
+
stops: [],
|
|
3629
|
+
};
|
|
3630
|
+
const first = withoutInterpolation(args[0] ?? '');
|
|
3381
3631
|
let from = 0;
|
|
3382
3632
|
if (!first || first.startsWith('to ')) {
|
|
3383
3633
|
from = 1;
|
|
@@ -3419,7 +3669,124 @@ function parseLinearGradient(text, ctx) {
|
|
|
3419
3669
|
from = 1;
|
|
3420
3670
|
}
|
|
3421
3671
|
}
|
|
3422
|
-
|
|
3672
|
+
const stops = parseStops(args.slice(from), ctx);
|
|
3673
|
+
if (!stops)
|
|
3674
|
+
return null;
|
|
3675
|
+
out.stops = stops;
|
|
3676
|
+
return out;
|
|
3677
|
+
}
|
|
3678
|
+
/**
|
|
3679
|
+
* A `radial-gradient()` (CSS Images 3, 3.2.1), or null for anything else:
|
|
3680
|
+
* an ending shape, `circle` or `ellipse`, and its size, in either order —
|
|
3681
|
+
* a keyword for the side or corner of the box it reaches, one length for a
|
|
3682
|
+
* circle's radius, or two lengths or percentages for an ellipse's — then
|
|
3683
|
+
* `at` and its centre, a position as `background-position` writes one;
|
|
3684
|
+
* each of the three may be left out, for an ellipse through the farthest
|
|
3685
|
+
* corner from the middle of the box. A colour interpolation method is read
|
|
3686
|
+
* and not honoured, and the stops are a linear gradient's, spaced along
|
|
3687
|
+
* the ray from the centre to the shape's edge.
|
|
3688
|
+
*/
|
|
3689
|
+
function parseRadialGradient(text, ctx) {
|
|
3690
|
+
const m = /^radial-gradient\((.*)\)$/is.exec(text.trim());
|
|
3691
|
+
if (!m)
|
|
3692
|
+
return null;
|
|
3693
|
+
const args = splitCommas(m[1]).map((a) => a.trim());
|
|
3694
|
+
const out = {
|
|
3695
|
+
kind: 'radial',
|
|
3696
|
+
circle: false,
|
|
3697
|
+
extent: null,
|
|
3698
|
+
radii: null,
|
|
3699
|
+
at: [{ pct: 50 }, { pct: 50 }],
|
|
3700
|
+
stops: [],
|
|
3701
|
+
};
|
|
3702
|
+
const first = withoutInterpolation(args[0] ?? '');
|
|
3703
|
+
let from = 0;
|
|
3704
|
+
if (!first)
|
|
3705
|
+
from = 1;
|
|
3706
|
+
else if (parseColor(splitValue(first)[0]) === null) {
|
|
3707
|
+
from = 1;
|
|
3708
|
+
const words = splitValue(first);
|
|
3709
|
+
const at = words.indexOf('at');
|
|
3710
|
+
if (at >= 0) {
|
|
3711
|
+
const position = positionPair(words.slice(at + 1), ctx);
|
|
3712
|
+
if (!position)
|
|
3713
|
+
return null;
|
|
3714
|
+
out.at = position;
|
|
3715
|
+
}
|
|
3716
|
+
let shape = null;
|
|
3717
|
+
const sizes = [];
|
|
3718
|
+
// the size is one run of words, the shape's keyword before or after it
|
|
3719
|
+
let sized = false;
|
|
3720
|
+
for (const word of at >= 0 ? words.slice(0, at) : words) {
|
|
3721
|
+
if (word === 'circle' || word === 'ellipse') {
|
|
3722
|
+
if (shape)
|
|
3723
|
+
return null;
|
|
3724
|
+
shape = word;
|
|
3725
|
+
if (sizes.length || out.extent)
|
|
3726
|
+
sized = true;
|
|
3727
|
+
continue;
|
|
3728
|
+
}
|
|
3729
|
+
if (sized || out.extent)
|
|
3730
|
+
return null;
|
|
3731
|
+
if (RADIAL_EXTENTS.has(word)) {
|
|
3732
|
+
if (sizes.length)
|
|
3733
|
+
return null;
|
|
3734
|
+
out.extent = word;
|
|
3735
|
+
continue;
|
|
3736
|
+
}
|
|
3737
|
+
const len = parseLength(word, ctx);
|
|
3738
|
+
if (len === null || len === AUTO || !notNegative(len))
|
|
3739
|
+
return null;
|
|
3740
|
+
sizes.push(len);
|
|
3741
|
+
}
|
|
3742
|
+
if (sizes.length === 1) {
|
|
3743
|
+
// a circle's radius is a length: a percentage of what, the spec asks
|
|
3744
|
+
const [r] = sizes;
|
|
3745
|
+
if (shape === 'ellipse' || typeof r !== 'number') {
|
|
3746
|
+
return null;
|
|
3747
|
+
}
|
|
3748
|
+
out.circle = true;
|
|
3749
|
+
out.radii = [r, r];
|
|
3750
|
+
}
|
|
3751
|
+
else if (sizes.length === 2) {
|
|
3752
|
+
if (shape === 'circle')
|
|
3753
|
+
return null;
|
|
3754
|
+
out.radii = [sizes[0], sizes[1]];
|
|
3755
|
+
}
|
|
3756
|
+
else if (sizes.length)
|
|
3757
|
+
return null;
|
|
3758
|
+
else {
|
|
3759
|
+
out.circle = shape === 'circle';
|
|
3760
|
+
out.extent ??= 'farthest-corner';
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
const stops = parseStops(args.slice(from), ctx);
|
|
3764
|
+
if (!stops)
|
|
3765
|
+
return null;
|
|
3766
|
+
out.stops = stops;
|
|
3767
|
+
return out;
|
|
3768
|
+
}
|
|
3769
|
+
const RADIAL_EXTENTS = new Set([
|
|
3770
|
+
'closest-side',
|
|
3771
|
+
'closest-corner',
|
|
3772
|
+
'farthest-side',
|
|
3773
|
+
'farthest-corner',
|
|
3774
|
+
]);
|
|
3775
|
+
/** A gradient's first argument, lower-cased, without the colour
|
|
3776
|
+
* interpolation method CSS Images 4 adds to it (`in oklab`, which
|
|
3777
|
+
* Tailwind 4 writes): read, and not honoured. */
|
|
3778
|
+
function withoutInterpolation(arg) {
|
|
3779
|
+
return arg
|
|
3780
|
+
.toLowerCase()
|
|
3781
|
+
.replace(/\bin\s+[a-z-]+(?:\s+(?:shorter|longer|increasing|decreasing)\s+hue)?/, '')
|
|
3782
|
+
.trim();
|
|
3783
|
+
}
|
|
3784
|
+
/** A gradient's colour stops, at least two, each with no position, one or
|
|
3785
|
+
* two; a bare length between two stops, a hint, is passed over. Null
|
|
3786
|
+
* where an argument is none of those. */
|
|
3787
|
+
function parseStops(args, ctx) {
|
|
3788
|
+
const stops = [];
|
|
3789
|
+
for (const arg of args) {
|
|
3423
3790
|
const parts = splitValue(arg);
|
|
3424
3791
|
const color = parseColor(parts[0] ?? '');
|
|
3425
3792
|
if (color === null) {
|
|
@@ -3434,14 +3801,18 @@ function parseLinearGradient(text, ctx) {
|
|
|
3434
3801
|
if (at.some((p) => p === null || p === AUTO))
|
|
3435
3802
|
return null;
|
|
3436
3803
|
if (!at.length)
|
|
3437
|
-
|
|
3804
|
+
stops.push({ color, at: null });
|
|
3438
3805
|
for (const p of at)
|
|
3439
|
-
|
|
3806
|
+
stops.push({ color, at: p });
|
|
3440
3807
|
}
|
|
3441
|
-
return
|
|
3808
|
+
return stops.length >= 2 ? stops : null;
|
|
3809
|
+
}
|
|
3810
|
+
/** A gradient function's image, where it is one this draws. */
|
|
3811
|
+
function parseGradient(text, ctx) {
|
|
3812
|
+
return parseLinearGradient(text, ctx) ?? parseRadialGradient(text, ctx);
|
|
3442
3813
|
}
|
|
3443
3814
|
/** The images CSS3 has beyond `url()`, which a layer may name: a linear
|
|
3444
|
-
* gradient
|
|
3815
|
+
* and a radial gradient are drawn, and the rest draw as nothing. */
|
|
3445
3816
|
const IMAGE_FUNCTION = /^(?:-(?:webkit|moz|o|ms)-)?(?:(?:repeating-)?(?:linear|radial|conic)-gradient|gradient|image-set|cross-fade|element|paint)\(/;
|
|
3446
3817
|
function isPositionPart(word, ctx) {
|
|
3447
3818
|
return (word in HORIZONTAL || word in VERTICAL || positionLength(word, ctx) !== null);
|
|
@@ -3474,95 +3845,6 @@ function whiteSpaceOf(collapse, wrap) {
|
|
|
3474
3845
|
return wrap ? 'pre-wrap' : 'pre';
|
|
3475
3846
|
return 'pre-line';
|
|
3476
3847
|
}
|
|
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
3848
|
/** An intrinsic size keyword, with the prefixes browsers still read, or
|
|
3567
3849
|
* `fit-content()` of a length or a percentage (CSS Sizing 3, 3.1) — a
|
|
3568
3850
|
* width's, where a height's is its content height as the keyword is;
|
|
@@ -4195,6 +4477,19 @@ function splitTopLevelSlash(value) {
|
|
|
4195
4477
|
return out;
|
|
4196
4478
|
}
|
|
4197
4479
|
// --- logical properties ----------------------------------------------------
|
|
4480
|
+
/** `pointer-events`' values besides `none` (CSS UI 4, SVG 2 15.6). */
|
|
4481
|
+
const POINTER_EVENTS = new Set([
|
|
4482
|
+
'auto',
|
|
4483
|
+
'bounding-box',
|
|
4484
|
+
'visiblepainted',
|
|
4485
|
+
'visiblefill',
|
|
4486
|
+
'visiblestroke',
|
|
4487
|
+
'visible',
|
|
4488
|
+
'painted',
|
|
4489
|
+
'fill',
|
|
4490
|
+
'stroke',
|
|
4491
|
+
'all',
|
|
4492
|
+
]);
|
|
4198
4493
|
const OBJECT_FITS = new Set(['fill', 'contain', 'cover', 'none', 'scale-down']);
|
|
4199
4494
|
/**
|
|
4200
4495
|
* `aspect-ratio` (CSS Sizing 4, 5.1): `auto`, a ratio — one number, or
|
|
@@ -4285,6 +4580,25 @@ function radiusOf(text, ctx) {
|
|
|
4285
4580
|
return len < 0 ? null : len;
|
|
4286
4581
|
return len.pct < 0 && !len.px && !len.of ? null : len;
|
|
4287
4582
|
}
|
|
4583
|
+
/**
|
|
4584
|
+
* `border-radius`'s value: one to four radii, and after a `/` one to four
|
|
4585
|
+
* more for the vertical radii where they differ, elliptical corners — the
|
|
4586
|
+
* radii across, and the ones down, null where they are the same values.
|
|
4587
|
+
* Null for anything else.
|
|
4588
|
+
*/
|
|
4589
|
+
function parseRadii(value, ctx) {
|
|
4590
|
+
const halves = value.split('/');
|
|
4591
|
+
if (halves.length > 2)
|
|
4592
|
+
return null;
|
|
4593
|
+
const [horizontal, vertical] = halves.map((half) => splitValue(half).map((p) => radiusOf(p, ctx)));
|
|
4594
|
+
for (const parts of vertical ? [horizontal, vertical] : [horizontal]) {
|
|
4595
|
+
if (!parts.length || parts.length > 4 || parts.includes(null))
|
|
4596
|
+
return null;
|
|
4597
|
+
}
|
|
4598
|
+
const across = fourSides(horizontal);
|
|
4599
|
+
const down = vertical ? fourSides(vertical) : null;
|
|
4600
|
+
return [across, down && !sameRadii(across, down) ? down : null];
|
|
4601
|
+
}
|
|
4288
4602
|
/** Whether two corners' radii are the same values. */
|
|
4289
4603
|
function sameRadii(a, b) {
|
|
4290
4604
|
for (let i = 0; i < 4; i += 1) {
|
|
@@ -4485,10 +4799,15 @@ const INHERITED_NAMES = new Set([
|
|
|
4485
4799
|
'list-style-position',
|
|
4486
4800
|
'list-style-image',
|
|
4487
4801
|
'cursor',
|
|
4802
|
+
'pointer-events',
|
|
4803
|
+
'fill',
|
|
4804
|
+
'stroke',
|
|
4488
4805
|
'border-collapse',
|
|
4489
4806
|
'border-spacing',
|
|
4490
4807
|
'empty-cells',
|
|
4491
4808
|
'quotes',
|
|
4809
|
+
'orphans',
|
|
4810
|
+
'widows',
|
|
4492
4811
|
]);
|
|
4493
4812
|
export function isInherited(name) {
|
|
4494
4813
|
return INHERITED_NAMES.has(name);
|
|
@@ -4629,6 +4948,9 @@ const INHERIT_TARGETS = {
|
|
|
4629
4948
|
'list-style-position': ['listStylePosition'],
|
|
4630
4949
|
'list-style-image': ['listStyleImage'],
|
|
4631
4950
|
cursor: ['cursor'],
|
|
4951
|
+
'pointer-events': ['pointerEvents'],
|
|
4952
|
+
fill: ['fill'],
|
|
4953
|
+
stroke: ['stroke'],
|
|
4632
4954
|
'border-collapse': ['borderCollapse'],
|
|
4633
4955
|
'caption-side': ['captionSide'],
|
|
4634
4956
|
'empty-cells': ['emptyCells'],
|
|
@@ -4695,9 +5017,16 @@ const INHERIT_TARGETS = {
|
|
|
4695
5017
|
'-webkit-box-pack': ['webkitBoxPack'],
|
|
4696
5018
|
'-webkit-box-align': ['webkitBoxAlign'],
|
|
4697
5019
|
'-webkit-box-flex': ['webkitBoxFlex'],
|
|
4698
|
-
columns: ['columns'],
|
|
4699
|
-
'column-count': ['columns'],
|
|
4700
|
-
'column-width': ['columns'],
|
|
5020
|
+
columns: ['columns', 'columnCount', 'columnWidth'],
|
|
5021
|
+
'column-count': ['columns', 'columnCount'],
|
|
5022
|
+
'column-width': ['columns', 'columnWidth'],
|
|
5023
|
+
orphans: ['orphans'],
|
|
5024
|
+
widows: ['widows'],
|
|
5025
|
+
'break-inside': ['breakInside'],
|
|
5026
|
+
'column-fill': ['columnFill'],
|
|
5027
|
+
'column-span': ['columnSpan'],
|
|
5028
|
+
'-webkit-column-span': ['columnSpan'],
|
|
5029
|
+
'page-break-inside': ['breakInside'],
|
|
4701
5030
|
'text-overflow': ['textOverflow'],
|
|
4702
5031
|
// a flex box's and its items', and a grid's
|
|
4703
5032
|
'flex-direction': ['flexDirection'],
|
|
@@ -4712,12 +5041,12 @@ const INHERIT_TARGETS = {
|
|
|
4712
5041
|
'flex-shrink': ['flexShrink'],
|
|
4713
5042
|
'flex-basis': ['flexBasis'],
|
|
4714
5043
|
order: ['order'],
|
|
4715
|
-
gap: ['rowGap', 'columnGap'],
|
|
5044
|
+
gap: ['rowGap', 'columnGap', 'columnGapNormal'],
|
|
4716
5045
|
'row-gap': ['rowGap'],
|
|
4717
|
-
'column-gap': ['columnGap'],
|
|
4718
|
-
'grid-gap': ['rowGap', 'columnGap'],
|
|
5046
|
+
'column-gap': ['columnGap', 'columnGapNormal'],
|
|
5047
|
+
'grid-gap': ['rowGap', 'columnGap', 'columnGapNormal'],
|
|
4719
5048
|
'grid-row-gap': ['rowGap'],
|
|
4720
|
-
'grid-column-gap': ['columnGap'],
|
|
5049
|
+
'grid-column-gap': ['columnGap', 'columnGapNormal'],
|
|
4721
5050
|
'grid-template-columns': ['gridColumns'],
|
|
4722
5051
|
'grid-template-rows': ['gridRows'],
|
|
4723
5052
|
'grid-auto-rows': ['gridAutoRows'],
|
|
@@ -4812,11 +5141,18 @@ const INHERIT_TARGETS = {
|
|
|
4812
5141
|
clear: ['clear'],
|
|
4813
5142
|
overflow: ['overflowX', 'overflowY'],
|
|
4814
5143
|
clip: ['clip'],
|
|
5144
|
+
'clip-path': ['clipPath'],
|
|
5145
|
+
'-webkit-clip-path': ['clipPath'],
|
|
4815
5146
|
'overflow-x': ['overflowX'],
|
|
4816
5147
|
'overflow-y': ['overflowY'],
|
|
4817
5148
|
opacity: ['opacity'],
|
|
4818
5149
|
translate: ['translate'],
|
|
4819
|
-
|
|
5150
|
+
rotate: ['rotate'],
|
|
5151
|
+
scale: ['scale'],
|
|
5152
|
+
transform: ['transform'],
|
|
5153
|
+
'-webkit-transform': ['transform'],
|
|
5154
|
+
'transform-origin': ['transformOrigin'],
|
|
5155
|
+
'-webkit-transform-origin': ['transformOrigin'],
|
|
4820
5156
|
'z-index': ['zIndex'],
|
|
4821
5157
|
'vertical-align': ['verticalAlign'],
|
|
4822
5158
|
'text-decoration': [
|
|
@@ -4871,13 +5207,30 @@ export function decorate(style) {
|
|
|
4871
5207
|
if (lines.includes('underline')) {
|
|
4872
5208
|
style.underline = inkColor(style.textDecorationColor ?? 'currentColor', style.color);
|
|
4873
5209
|
style.underlineStyle = style.textDecorationStyle;
|
|
4874
|
-
style.underlineThickness = style
|
|
5210
|
+
style.underlineThickness = usedThickness(style);
|
|
4875
5211
|
style.underlineOffset = style.textUnderlineOffset;
|
|
4876
5212
|
}
|
|
4877
5213
|
if (lines.includes('line-through')) {
|
|
4878
5214
|
style.lineThrough = inkColor(style.textDecorationColor ?? 'currentColor', style.color);
|
|
5215
|
+
style.lineThroughStyle = style.textDecorationStyle;
|
|
5216
|
+
style.lineThroughThickness = usedThickness(style);
|
|
4879
5217
|
}
|
|
4880
5218
|
}
|
|
5219
|
+
/**
|
|
5220
|
+
* How thick the lines a box decorates its text with are. `auto` leaves it
|
|
5221
|
+
* to the user agent, which is to take it from the font where the font says
|
|
5222
|
+
* (CSS Text Decoration 4, 2.4.1); neither text engine here reports a face's
|
|
5223
|
+
* underline, so it is a part of the font size, Blink's tenth — of the size
|
|
5224
|
+
* of the box that set the decoration, which draws one line of one thickness
|
|
5225
|
+
* through everything inside it (2.9). A pixel for every size drew the dots
|
|
5226
|
+
* under the `<abbr>` of a 140px title as a hairline. `from-font` is `auto`
|
|
5227
|
+
* for the same want of a metric, a length is itself on whole pixels, and
|
|
5228
|
+
* no line is thinner than one.
|
|
5229
|
+
*/
|
|
5230
|
+
function usedThickness(style) {
|
|
5231
|
+
const length = style.textDecorationThickness;
|
|
5232
|
+
return Math.max(1, length === null ? style.fontSize / 10 : Math.round(length));
|
|
5233
|
+
}
|
|
4881
5234
|
/**
|
|
4882
5235
|
* The absolutely positioned styles that were inline-level before they were
|
|
4883
5236
|
* made blocks: where such a box would have been in flow is on its line,
|
|
@@ -4984,4 +5337,54 @@ export function blockify(style, inFlexContainer) {
|
|
|
4984
5337
|
return;
|
|
4985
5338
|
}
|
|
4986
5339
|
}
|
|
5340
|
+
/**
|
|
5341
|
+
* The `display` a `<button>` is laid out with, which is not always the one
|
|
5342
|
+
* it was given (HTML's rendering section, button layout, 15.5.3): a flex
|
|
5343
|
+
* box or a grid is that, and of the rest, "a value such that the outer
|
|
5344
|
+
* display type is 'inline'" behaves as `inline-block` and anything else as
|
|
5345
|
+
* `flow-root`. Blink computes them so — `inline-block` for `inline` and
|
|
5346
|
+
* `inline-table`, `block` for `table` and `list-item` — and makes the one
|
|
5347
|
+
* block flow of each; the formatting context is the layout's to give every
|
|
5348
|
+
* button that is a block (`establishesBFC`).
|
|
5349
|
+
*
|
|
5350
|
+
* Left an inline box, a button around a block was broken in two around it,
|
|
5351
|
+
* as any inline box is: as wide as the line, its `height` applied to
|
|
5352
|
+
* nothing, and its border and padding drawn above and below the line it
|
|
5353
|
+
* opened. A table's part is left what it is, where the two disagree: a
|
|
5354
|
+
* block to the text, an inline-block in Blink. After `blockify`, since a
|
|
5355
|
+
* float, an absolute box and a flex item are blocks first.
|
|
5356
|
+
*/
|
|
5357
|
+
export function settleButton(style) {
|
|
5358
|
+
switch (style.display) {
|
|
5359
|
+
case 'inline':
|
|
5360
|
+
case 'inline-table':
|
|
5361
|
+
style.display = 'inline-block';
|
|
5362
|
+
return;
|
|
5363
|
+
case 'list-item':
|
|
5364
|
+
case 'table':
|
|
5365
|
+
style.display = 'block';
|
|
5366
|
+
return;
|
|
5367
|
+
default:
|
|
5368
|
+
return;
|
|
5369
|
+
}
|
|
5370
|
+
}
|
|
5371
|
+
/** The generic font families, which a list ending in one falls back
|
|
5372
|
+
* through already, in the text engine (CSS Fonts 4, 4.2). */
|
|
5373
|
+
const GENERIC_FAMILY = new Set([
|
|
5374
|
+
'serif',
|
|
5375
|
+
'sans-serif',
|
|
5376
|
+
'monospace',
|
|
5377
|
+
'cursive',
|
|
5378
|
+
'fantasy',
|
|
5379
|
+
'system-ui',
|
|
5380
|
+
'ui-serif',
|
|
5381
|
+
'ui-sans-serif',
|
|
5382
|
+
'ui-monospace',
|
|
5383
|
+
'ui-rounded',
|
|
5384
|
+
'math',
|
|
5385
|
+
'emoji',
|
|
5386
|
+
'fangsong',
|
|
5387
|
+
'-apple-system',
|
|
5388
|
+
'blinkmacsystemfont',
|
|
5389
|
+
]);
|
|
4987
5390
|
//# sourceMappingURL=style.js.map
|