@react-x11/components 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/flow/node.d.ts +14 -6
  2. package/dist/flow/node.d.ts.map +1 -1
  3. package/dist/flow/node.js +82 -64
  4. package/dist/flow/node.js.map +1 -1
  5. package/dist/html/controls.d.ts +38 -10
  6. package/dist/html/controls.d.ts.map +1 -1
  7. package/dist/html/controls.js +43 -58
  8. package/dist/html/controls.js.map +1 -1
  9. package/dist/html/css/cascade.d.ts +134 -20
  10. package/dist/html/css/cascade.d.ts.map +1 -1
  11. package/dist/html/css/cascade.js +538 -128
  12. package/dist/html/css/cascade.js.map +1 -1
  13. package/dist/html/css/color.d.ts +19 -0
  14. package/dist/html/css/color.d.ts.map +1 -1
  15. package/dist/html/css/color.js +86 -0
  16. package/dist/html/css/color.js.map +1 -1
  17. package/dist/html/css/parse.d.ts +40 -2
  18. package/dist/html/css/parse.d.ts.map +1 -1
  19. package/dist/html/css/parse.js +391 -13
  20. package/dist/html/css/parse.js.map +1 -1
  21. package/dist/html/css/style.d.ts +52 -1
  22. package/dist/html/css/style.d.ts.map +1 -1
  23. package/dist/html/css/style.js +328 -11
  24. package/dist/html/css/style.js.map +1 -1
  25. package/dist/html/css/ua.d.ts +11 -1
  26. package/dist/html/css/ua.d.ts.map +1 -1
  27. package/dist/html/css/ua.js +73 -7
  28. package/dist/html/css/ua.js.map +1 -1
  29. package/dist/html/css/values.d.ts +10 -1
  30. package/dist/html/css/values.d.ts.map +1 -1
  31. package/dist/html/css/values.js +27 -2
  32. package/dist/html/css/values.js.map +1 -1
  33. package/dist/html/css/vars.d.ts +5 -0
  34. package/dist/html/css/vars.d.ts.map +1 -1
  35. package/dist/html/css/vars.js +2 -2
  36. package/dist/html/css/vars.js.map +1 -1
  37. package/dist/html/dom.d.ts.map +1 -1
  38. package/dist/html/dom.js +38 -3
  39. package/dist/html/dom.js.map +1 -1
  40. package/dist/html/fonts.d.ts +25 -1
  41. package/dist/html/fonts.d.ts.map +1 -1
  42. package/dist/html/fonts.js +99 -6
  43. package/dist/html/fonts.js.map +1 -1
  44. package/dist/html/form.d.ts +200 -0
  45. package/dist/html/form.d.ts.map +1 -0
  46. package/dist/html/form.js +801 -0
  47. package/dist/html/form.js.map +1 -0
  48. package/dist/html/index.d.ts +12 -0
  49. package/dist/html/index.d.ts.map +1 -1
  50. package/dist/html/index.js +30 -264
  51. package/dist/html/index.js.map +1 -1
  52. package/dist/html/layout/block.d.ts +11 -2
  53. package/dist/html/layout/block.d.ts.map +1 -1
  54. package/dist/html/layout/block.js +186 -19
  55. package/dist/html/layout/block.js.map +1 -1
  56. package/dist/html/layout/boxes.d.ts +65 -7
  57. package/dist/html/layout/boxes.d.ts.map +1 -1
  58. package/dist/html/layout/boxes.js +87 -22
  59. package/dist/html/layout/boxes.js.map +1 -1
  60. package/dist/html/layout/cache.d.ts +2 -2
  61. package/dist/html/layout/cache.d.ts.map +1 -1
  62. package/dist/html/layout/cache.js +8 -3
  63. package/dist/html/layout/cache.js.map +1 -1
  64. package/dist/html/layout/flex.js +4 -1
  65. package/dist/html/layout/flex.js.map +1 -1
  66. package/dist/html/layout/floats.d.ts +4 -0
  67. package/dist/html/layout/floats.d.ts.map +1 -1
  68. package/dist/html/layout/floats.js +26 -0
  69. package/dist/html/layout/floats.js.map +1 -1
  70. package/dist/html/layout/inline.d.ts +26 -2
  71. package/dist/html/layout/inline.d.ts.map +1 -1
  72. package/dist/html/layout/inline.js +1232 -115
  73. package/dist/html/layout/inline.js.map +1 -1
  74. package/dist/html/node.d.ts +120 -15
  75. package/dist/html/node.d.ts.map +1 -1
  76. package/dist/html/node.js +993 -174
  77. package/dist/html/node.js.map +1 -1
  78. package/dist/html/paint.d.ts +75 -2
  79. package/dist/html/paint.d.ts.map +1 -1
  80. package/dist/html/paint.js +836 -200
  81. package/dist/html/paint.js.map +1 -1
  82. package/dist/html/surfaces.d.ts +7 -2
  83. package/dist/html/surfaces.d.ts.map +1 -1
  84. package/dist/html/surfaces.js +16 -0
  85. package/dist/html/surfaces.js.map +1 -1
  86. package/dist/html/widgets.d.ts +29 -0
  87. package/dist/html/widgets.d.ts.map +1 -0
  88. package/dist/html/widgets.js +620 -0
  89. package/dist/html/widgets.js.map +1 -0
  90. package/dist/index.d.ts +1 -1
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/internal/window.d.ts +22 -0
  94. package/dist/internal/window.d.ts.map +1 -1
  95. package/dist/internal/window.js +35 -8
  96. package/dist/internal/window.js.map +1 -1
  97. package/dist/richtext/node.d.ts +7 -0
  98. package/dist/richtext/node.d.ts.map +1 -1
  99. package/dist/richtext/node.js.map +1 -1
  100. package/package.json +6 -4
  101. package/src/flow/node.ts +80 -64
  102. package/src/html/controls.ts +79 -58
  103. package/src/html/css/cascade.ts +610 -146
  104. package/src/html/css/color.ts +87 -0
  105. package/src/html/css/parse.ts +431 -13
  106. package/src/html/css/style.ts +367 -11
  107. package/src/html/css/ua.ts +76 -8
  108. package/src/html/css/values.ts +31 -3
  109. package/src/html/css/vars.ts +2 -2
  110. package/src/html/dom.ts +41 -3
  111. package/src/html/fonts.ts +116 -6
  112. package/src/html/form.ts +962 -0
  113. package/src/html/index.ts +49 -300
  114. package/src/html/layout/block.ts +231 -16
  115. package/src/html/layout/boxes.ts +133 -32
  116. package/src/html/layout/cache.ts +8 -3
  117. package/src/html/layout/flex.ts +4 -1
  118. package/src/html/layout/floats.ts +24 -0
  119. package/src/html/layout/inline.ts +1445 -108
  120. package/src/html/node.ts +1010 -166
  121. package/src/html/paint.ts +980 -270
  122. package/src/html/surfaces.ts +21 -1
  123. package/src/html/widgets.ts +735 -0
  124. package/src/index.ts +1 -0
  125. package/src/internal/window.ts +36 -8
  126. package/src/richtext/node.ts +7 -0
@@ -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 { LIGHT_DARK, lightDark, usedColorScheme } from './color.js';
18
19
  /** Whether a length is one `padding` takes: not `auto`, not negative. A
19
20
  * `calc()` with a percentage in it has no sign until layout, which clamps
20
21
  * it at zero (CSS Values 4 10.12). */
@@ -64,6 +65,7 @@ function parseClip(value, ctx) {
64
65
  * same list. */
65
66
  export const INHERITED = [
66
67
  'color',
68
+ 'colorScheme',
67
69
  'textFillColor',
68
70
  'fontFamily',
69
71
  'fontSize',
@@ -116,6 +118,7 @@ export function initialStyle(look, scale = 1) {
116
118
  // a copy of the literal, not the literal: see `copyStyle`
117
119
  return copyStyle({
118
120
  color: look.color,
121
+ colorScheme: look.colorScheme,
119
122
  fontFamily: look.fontFamily,
120
123
  fontSize: look.fontSize,
121
124
  fontWeight: 400,
@@ -173,6 +176,7 @@ export function initialStyle(look, scale = 1) {
173
176
  float: 'none',
174
177
  clear: 'none',
175
178
  boxSizing: 'content-box',
179
+ boxDecorationBreak: 'slice',
176
180
  lineClamp: null,
177
181
  maxLines: null,
178
182
  clampContinue: 'auto',
@@ -267,6 +271,7 @@ export function initialStyle(look, scale = 1) {
267
271
  backgroundClips: null,
268
272
  backgroundOrigins: null,
269
273
  borderImage: NO_BORDER_IMAGE,
274
+ mask: NO_MASK,
270
275
  textFillColor: null,
271
276
  textDecorationLine: 'none',
272
277
  textDecorationColor: null,
@@ -350,6 +355,7 @@ export function inherit(parent, initial) {
350
355
  // quarters of the cost of every element's style, a store through a
351
356
  // computed name costing thirty times one through a written one
352
357
  out.color = parent.color;
358
+ out.colorScheme = parent.colorScheme;
353
359
  out.textFillColor = parent.textFillColor;
354
360
  out.fontFamily = parent.fontFamily;
355
361
  out.fontSize = parent.fontSize;
@@ -541,6 +547,16 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
541
547
  if (/!\s*important$/i.test(value)) {
542
548
  value = value.replace(/!\s*important$/i, '').trim();
543
549
  }
550
+ // the branch of each `light-dark()` this element's scheme picks, before
551
+ // anything reads the value: it stands wherever a colour can, in a
552
+ // shorthand, a shadow, a gradient or a mix, and most often arrives
553
+ // through a `var()` from a theme on `:root`
554
+ if (LIGHT_DARK.test(value)) {
555
+ const picked = lightDark(value, style.colorScheme);
556
+ if (picked === null)
557
+ return;
558
+ value = picked;
559
+ }
544
560
  const color = COLOR_PROPS[name];
545
561
  if (color) {
546
562
  const parsed = parseColor(value);
@@ -556,6 +572,12 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
556
572
  return;
557
573
  }
558
574
  switch (name) {
575
+ case 'color-scheme': {
576
+ const scheme = usedColorScheme(value, ctx.initial?.colorScheme);
577
+ if (scheme)
578
+ style.colorScheme = scheme;
579
+ return;
580
+ }
559
581
  // --- box ----------------------------------------------------------------
560
582
  case 'display': {
561
583
  const v = value.toLowerCase();
@@ -775,6 +797,13 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
775
797
  style.boxSizing = v;
776
798
  return;
777
799
  }
800
+ case 'box-decoration-break':
801
+ case '-webkit-box-decoration-break': {
802
+ const v = value.trim().toLowerCase();
803
+ if (v === 'slice' || v === 'clone')
804
+ style.boxDecorationBreak = v;
805
+ return;
806
+ }
778
807
  case 'aspect-ratio': {
779
808
  const parsed = parseAspectRatio(value);
780
809
  if (parsed !== undefined)
@@ -1366,6 +1395,68 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
1366
1395
  style.backgroundPositions = pairs.length > 1 ? pairs : null;
1367
1396
  return;
1368
1397
  }
1398
+ // --- masking --------------------------------------------------------------
1399
+ // Each `-webkit-` name is the same property's (Compatibility, 5): every
1400
+ // engine takes both, and a page writes both — Wikipedia's icons do.
1401
+ case 'mask':
1402
+ case '-webkit-mask': {
1403
+ const mask = readMask(value, ctx);
1404
+ if (mask)
1405
+ style.mask = mask;
1406
+ return;
1407
+ }
1408
+ case 'mask-image':
1409
+ case '-webkit-mask-image': {
1410
+ // `none` a layer as much as an image is; a bad url drops it all
1411
+ const images = [];
1412
+ for (const part of splitCommas(value)) {
1413
+ const image = maskImageOf(part, ctx);
1414
+ if (image === undefined)
1415
+ return;
1416
+ images.push(image);
1417
+ }
1418
+ if (images.length)
1419
+ style.mask = { ...style.mask, images };
1420
+ return;
1421
+ }
1422
+ case 'mask-repeat':
1423
+ case '-webkit-mask-repeat': {
1424
+ const repeats = layerValues(value, (part) => {
1425
+ const words = splitValue(part.toLowerCase());
1426
+ return words.length <= 2 ? readRepeat(words) : null;
1427
+ });
1428
+ if (repeats)
1429
+ style.mask = { ...style.mask, repeats };
1430
+ return;
1431
+ }
1432
+ case 'mask-size':
1433
+ case '-webkit-mask-size': {
1434
+ const sizes = layerValues(value, (part) => backgroundSizeOf(splitValue(part), ctx));
1435
+ if (sizes)
1436
+ style.mask = { ...style.mask, sizes };
1437
+ return;
1438
+ }
1439
+ case 'mask-position':
1440
+ case '-webkit-mask-position': {
1441
+ const positions = layerValues(value, (part) => positionPair(splitValue(part), ctx));
1442
+ if (positions)
1443
+ style.mask = { ...style.mask, positions };
1444
+ return;
1445
+ }
1446
+ case 'mask-origin':
1447
+ case '-webkit-mask-origin': {
1448
+ const origins = layerValues(value, (part) => maskBox(part));
1449
+ if (origins)
1450
+ style.mask = { ...style.mask, origins };
1451
+ return;
1452
+ }
1453
+ case 'mask-clip':
1454
+ case '-webkit-mask-clip': {
1455
+ const clips = layerValues(value, (part) => part.toLowerCase() === 'no-clip' ? 'border-box' : maskBox(part));
1456
+ if (clips)
1457
+ style.mask = { ...style.mask, clips };
1458
+ return;
1459
+ }
1369
1460
  // --- generated content --------------------------------------------------
1370
1461
  case 'content': {
1371
1462
  const parsed = parseContent(value);
@@ -1426,7 +1517,7 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
1426
1517
  // handed a face at a size of millions shapes and caches glyphs that
1427
1518
  // size, and a nest of `larger`s gets there on its own
1428
1519
  const most = MAX_FONT_SIZE * ctx.scale;
1429
- const kw = keywordFontSize(value, parent.fontSize, ctx.rem);
1520
+ const kw = keywordFontSize(value, parent.fontSize, ctx.initial?.fontSize ?? ctx.rem);
1430
1521
  if (kw !== null) {
1431
1522
  style.fontSize = Math.min(kw, most);
1432
1523
  return;
@@ -1483,7 +1574,13 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
1483
1574
  style.lineHeightIsLength = true;
1484
1575
  }
1485
1576
  else if (len && typeof len === 'object') {
1486
- const px = resolve(len, style.fontSize);
1577
+ // a percentage of the element's own font size, the one it is
1578
+ // computed with (CSS 2.1 10.8.1), which `em` already is: not the
1579
+ // size in `style` as this declaration comes up, which a `font`
1580
+ // earlier in the same rule has just set to its own — `p { font:
1581
+ // 12px …; line-height: 100% }` under a `.lead { font-size: 16px }`
1582
+ // set sixteen-pixel text on twelve-pixel lines
1583
+ const px = resolve(len, ctx.em);
1487
1584
  if (px < 0)
1488
1585
  return;
1489
1586
  style.lineHeight = px;
@@ -1964,7 +2061,11 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
1964
2061
  return;
1965
2062
  }
1966
2063
  case 'align-content': {
1967
- const v = alignKeyword(value);
2064
+ // `normal` is `stretch` in a flex and a grid container, the only
2065
+ // boxes it moves anything in (CSS Box Alignment 3, 5.1)
2066
+ const v = value.trim().toLowerCase() === 'normal'
2067
+ ? 'stretch'
2068
+ : alignKeyword(value);
1968
2069
  if (v)
1969
2070
  style.alignContent = v;
1970
2071
  return;
@@ -2220,6 +2321,32 @@ export function applyDeclaration(style, parent, prop, rawValue, ctx) {
2220
2321
  }
2221
2322
  return;
2222
2323
  }
2324
+ case 'place-content': {
2325
+ // `<'align-content'> <'justify-content'>?` (CSS Box Alignment 3,
2326
+ // 5.3), either half one keyword or two — `first baseline`, `safe
2327
+ // center` — and the second the first again where it is left out,
2328
+ // but for a baseline, which is no `justify-content`: `start`
2329
+ const words = value.trim().toLowerCase().split(/\s+/);
2330
+ const span = (at) => /^(?:safe|unsafe|first|last)$/.test(words[at] ?? '') ? 2 : 1;
2331
+ const cut = span(0);
2332
+ const align = words.slice(0, cut).join(' ');
2333
+ const rest = words.slice(cut);
2334
+ if (rest.length && rest.length !== span(cut))
2335
+ return;
2336
+ const justify = rest.length
2337
+ ? rest.join(' ')
2338
+ : /baseline$/.test(align)
2339
+ ? 'start'
2340
+ : align;
2341
+ // a shorthand is one declaration: either half unread drops both
2342
+ if (align !== 'normal' && !alignKeyword(align))
2343
+ return;
2344
+ if (!justifyKeyword(justify))
2345
+ return;
2346
+ applyDeclaration(style, parent, 'align-content', align, ctx);
2347
+ applyDeclaration(style, parent, 'justify-content', justify, ctx);
2348
+ return;
2349
+ }
2223
2350
  case 'place-items':
2224
2351
  case 'place-self': {
2225
2352
  const parts = splitValue(value);
@@ -2621,6 +2748,154 @@ export const NO_BORDER_IMAGE = {
2621
2748
  outset: [0, 0, 0, 0],
2622
2749
  repeat: ['stretch', 'stretch'],
2623
2750
  };
2751
+ /** Whether a style masks its element: a layer of its mask has an image. */
2752
+ export function masked(style) {
2753
+ const mask = style.mask;
2754
+ if (mask === NO_MASK)
2755
+ return false;
2756
+ for (const image of mask.images)
2757
+ if (image !== null)
2758
+ return true;
2759
+ return false;
2760
+ }
2761
+ /**
2762
+ * One layer's `mask-image`: a url, a gradient — or none, for an image
2763
+ * function this does not draw, or a `url(#id)`, which names an SVG
2764
+ * `<mask>` element in the document rather than an image to fetch (7.2):
2765
+ * drawn with no mask rather than as the transparent layer a mask that
2766
+ * cannot be had is, since this draws no `<mask>`. Undefined where it is no
2767
+ * image at all.
2768
+ */
2769
+ function maskImageOf(text, ctx) {
2770
+ const image = backgroundImageOf(text, ctx);
2771
+ return typeof image === 'string' && image[0] === '#' ? null : image;
2772
+ }
2773
+ /** A `<geometry-box>` as an HTML element has it (CSS Masking 1, 7.5): the
2774
+ * SVG boxes are its content box and its border box. */
2775
+ function maskBox(text) {
2776
+ const v = text.trim().toLowerCase();
2777
+ if (isVisualBox(v))
2778
+ return v;
2779
+ if (v === 'fill-box')
2780
+ return 'content-box';
2781
+ if (v === 'stroke-box' || v === 'view-box')
2782
+ return 'border-box';
2783
+ return null;
2784
+ }
2785
+ /**
2786
+ * The `mask` shorthand (CSS Masking 1, 7.10): a layer a comma group, each
2787
+ * an image, a position with a size after a `/`, a repeat, one box for the
2788
+ * origin and the clip or two, `no-clip`, a compositing operator and a
2789
+ * mode, each at most once, in any order. The operator and the mode are
2790
+ * read and not honoured: layers are added, and an image masks by its
2791
+ * alpha, which is what `match-source` makes of one. Null where a layer is
2792
+ * not one, which drops the declaration.
2793
+ */
2794
+ function readMask(value, ctx) {
2795
+ const out = {
2796
+ images: [],
2797
+ repeats: [],
2798
+ sizes: [],
2799
+ positions: [],
2800
+ origins: [],
2801
+ clips: [],
2802
+ };
2803
+ for (const text of splitCommas(value)) {
2804
+ const parts = splitValue(text).flatMap(splitSlash);
2805
+ let image = null;
2806
+ let repeat = NO_MASK.repeats[0];
2807
+ let size = 'auto';
2808
+ let position = [0, 0];
2809
+ const boxes = [];
2810
+ let seen = 0;
2811
+ const once = (bit) => {
2812
+ if (seen & bit)
2813
+ return false;
2814
+ seen |= bit;
2815
+ return true;
2816
+ };
2817
+ for (let i = 0; i < parts.length;) {
2818
+ const part = parts[i];
2819
+ const v = part.toLowerCase();
2820
+ if (v === 'none' || v.startsWith('url(') || IMAGE_FUNCTION.test(v)) {
2821
+ if (!once(1))
2822
+ return null;
2823
+ const read = maskImageOf(part, ctx);
2824
+ if (read === undefined)
2825
+ return null;
2826
+ image = read;
2827
+ i += 1;
2828
+ }
2829
+ else if (v === 'repeat-x' || v === 'repeat-y' || REPEATS.has(v)) {
2830
+ if (!once(2))
2831
+ return null;
2832
+ const pair = REPEATS.has(v) && REPEATS.has(parts[i + 1]?.toLowerCase());
2833
+ const read = readRepeat(pair ? [v, parts[i + 1].toLowerCase()] : [v]);
2834
+ if (!read)
2835
+ return null;
2836
+ repeat = read;
2837
+ i += pair ? 2 : 1;
2838
+ }
2839
+ else if (maskBox(v) || v === 'no-clip') {
2840
+ if (boxes.length === 2 || (v === 'no-clip' && !once(4)))
2841
+ return null;
2842
+ boxes.push(maskBox(v) ?? 'border-box');
2843
+ i += 1;
2844
+ }
2845
+ else if (/^(?:add|subtract|intersect|exclude)$/.test(v)) {
2846
+ if (!once(8))
2847
+ return null;
2848
+ i += 1;
2849
+ }
2850
+ else if (/^(?:alpha|luminance|match-source)$/.test(v)) {
2851
+ if (!once(16))
2852
+ return null;
2853
+ i += 1;
2854
+ }
2855
+ else if (isPositionPart(v, ctx)) {
2856
+ if (!once(32))
2857
+ return null;
2858
+ let end = i;
2859
+ while (end < parts.length &&
2860
+ isPositionPart(parts[end].toLowerCase(), ctx)) {
2861
+ end += 1;
2862
+ }
2863
+ const read = positionPair(parts.slice(i, end), ctx);
2864
+ if (!read)
2865
+ return null;
2866
+ position = read;
2867
+ i = end;
2868
+ if (parts[i] !== '/')
2869
+ continue;
2870
+ const first = parts[i + 1]?.toLowerCase();
2871
+ if (first === 'cover' || first === 'contain') {
2872
+ size = first;
2873
+ i += 2;
2874
+ }
2875
+ else if (first !== undefined && isSizePart(first, ctx)) {
2876
+ const two = i + 2 < parts.length && isSizePart(parts[i + 2].toLowerCase(), ctx);
2877
+ size =
2878
+ backgroundSizeOf(parts.slice(i + 1, i + (two ? 3 : 2)), ctx) ??
2879
+ 'auto';
2880
+ i += two ? 3 : 2;
2881
+ }
2882
+ else {
2883
+ return null;
2884
+ }
2885
+ }
2886
+ else {
2887
+ return null;
2888
+ }
2889
+ }
2890
+ out.images.push(image);
2891
+ out.repeats.push(repeat);
2892
+ out.sizes.push(size);
2893
+ out.positions.push(position);
2894
+ out.origins.push(boxes[0] ?? 'border-box');
2895
+ out.clips.push(boxes[1] ?? boxes[0] ?? 'border-box');
2896
+ }
2897
+ return out.images.length ? out : null;
2898
+ }
2624
2899
  /** One to four values, one a side as `margin` takes them; null where one
2625
2900
  * is not a value. */
2626
2901
  function sidesOf(parts, read) {
@@ -2807,6 +3082,14 @@ function repeatPair(x, y) {
2807
3082
  return pair;
2808
3083
  }
2809
3084
  const REPEAT = repeatPair('repeat', 'repeat');
3085
+ export const NO_MASK = {
3086
+ images: [null],
3087
+ repeats: [REPEAT],
3088
+ sizes: ['auto'],
3089
+ positions: [[0, 0]],
3090
+ origins: ['border-box'],
3091
+ clips: ['border-box'],
3092
+ };
2810
3093
  function applyBorderShorthand(style, name, value, ctx) {
2811
3094
  const sides = name === 'border'
2812
3095
  ? ['Top', 'Right', 'Bottom', 'Left']
@@ -3457,8 +3740,7 @@ function applyFontShorthand(style, parent, value, ctx) {
3457
3740
  // A size and a family, or the value is not a font and the declaration is
3458
3741
  // dropped whole, as CSS drops any value it cannot read — a line height
3459
3742
  // below nought included: `font: 4em/-2em serif` set the text at 4em.
3460
- const size = keywordFontSize(sizeText ?? '', parent.fontSize, ctx.rem) ??
3461
- parseLength(sizeText ?? '', { ...ctx, em: parent.fontSize });
3743
+ const size = keywordFontSize(sizeText ?? '', parent.fontSize, ctx.initial?.fontSize ?? ctx.rem) ?? parseLength(sizeText ?? '', { ...ctx, em: parent.fontSize });
3462
3744
  if (!family || size === null || size === AUTO)
3463
3745
  return;
3464
3746
  if (lineText && negativeLength(lineText, ctx))
@@ -3478,12 +3760,11 @@ function applyFontShorthand(style, parent, value, ctx) {
3478
3760
  style.lineHeight = 'normal';
3479
3761
  style.lineHeightIsLength = false;
3480
3762
  applyDeclaration(style, parent, 'font-size', sizeText, ctx);
3481
- if (lineText) {
3482
- applyDeclaration(style, parent, 'line-height', lineText, {
3483
- ...ctx,
3484
- em: style.fontSize,
3485
- });
3486
- }
3763
+ // against the element's own size, which `ctx.em` is once the cascade has
3764
+ // settled it: a later rule's `font-size` outranks this one's, and
3765
+ // `font: 12px/150%` under a `font-size: 16px` is on 24px lines
3766
+ if (lineText)
3767
+ applyDeclaration(style, parent, 'line-height', lineText, ctx);
3487
3768
  applyDeclaration(style, parent, 'font-family', family, ctx);
3488
3769
  }
3489
3770
  /** Whether a line height is a number or a length below nought. */
@@ -4172,6 +4453,7 @@ function camel(name) {
4172
4453
  }
4173
4454
  const INHERITED_NAMES = new Set([
4174
4455
  'color',
4456
+ 'color-scheme',
4175
4457
  '-webkit-text-fill-color',
4176
4458
  'font',
4177
4459
  'font-family',
@@ -4216,6 +4498,11 @@ export function isInherited(name) {
4216
4498
  /** A property back to its initial value: what a declaration whose `var()`
4217
4499
  * has no value comes to, where the property is not inherited. */
4218
4500
  export function initialOne(style, initial, name) {
4501
+ const list = MASK_LISTS[name];
4502
+ if (list) {
4503
+ style.mask = { ...style.mask, [list]: initial.mask[list] };
4504
+ return;
4505
+ }
4219
4506
  const keys = INHERIT_TARGETS[name];
4220
4507
  if (!keys)
4221
4508
  return;
@@ -4224,6 +4511,11 @@ export function initialOne(style, initial, name) {
4224
4511
  }
4225
4512
  }
4226
4513
  function inheritOne(style, parent, name) {
4514
+ const list = MASK_LISTS[name];
4515
+ if (list) {
4516
+ style.mask = { ...style.mask, [list]: parent.mask[list] };
4517
+ return;
4518
+ }
4227
4519
  const keys = INHERIT_TARGETS[name];
4228
4520
  if (!keys)
4229
4521
  return;
@@ -4236,8 +4528,29 @@ function inheritOne(style, parent, name) {
4236
4528
  }
4237
4529
  const SIDES = ['Top', 'Right', 'Bottom', 'Left'];
4238
4530
  const sides = (make) => SIDES.map(make);
4531
+ /**
4532
+ * The list of the mask's layers each longhand is, which `initial`,
4533
+ * `inherit` and a `var()` that fails reset alone: one field holds them all,
4534
+ * and reset whole, a `mask-size: calc(var(--x) - 4px)` put back the
4535
+ * `mask-repeat: no-repeat` before it, and Wikipedia's chevron repeated.
4536
+ */
4537
+ const MASK_LISTS = {
4538
+ 'mask-image': 'images',
4539
+ '-webkit-mask-image': 'images',
4540
+ 'mask-repeat': 'repeats',
4541
+ '-webkit-mask-repeat': 'repeats',
4542
+ 'mask-size': 'sizes',
4543
+ '-webkit-mask-size': 'sizes',
4544
+ 'mask-position': 'positions',
4545
+ '-webkit-mask-position': 'positions',
4546
+ 'mask-origin': 'origins',
4547
+ '-webkit-mask-origin': 'origins',
4548
+ 'mask-clip': 'clips',
4549
+ '-webkit-mask-clip': 'clips',
4550
+ };
4239
4551
  const INHERIT_TARGETS = {
4240
4552
  color: ['color'],
4553
+ 'color-scheme': ['colorScheme'],
4241
4554
  '-webkit-text-fill-color': ['textFillColor'],
4242
4555
  'background-clip': [
4243
4556
  'backgroundClipText',
@@ -4251,6 +4564,8 @@ const INHERIT_TARGETS = {
4251
4564
  ],
4252
4565
  'background-origin': ['backgroundOrigin', 'backgroundOrigins'],
4253
4566
  'border-image': ['borderImage'],
4567
+ mask: ['mask'],
4568
+ '-webkit-mask': ['mask'],
4254
4569
  'border-image-source': ['borderImage'],
4255
4570
  'border-image-slice': ['borderImage'],
4256
4571
  'border-image-width': ['borderImage'],
@@ -4331,6 +4646,8 @@ const INHERIT_TARGETS = {
4331
4646
  'min-height': ['minHeight', 'minHeightKeyword'],
4332
4647
  'max-height': ['maxHeight', 'maxHeightKeyword'],
4333
4648
  'box-sizing': ['boxSizing'],
4649
+ 'box-decoration-break': ['boxDecorationBreak'],
4650
+ '-webkit-box-decoration-break': ['boxDecorationBreak'],
4334
4651
  margin: sides((s) => `margin${s}`),
4335
4652
  'margin-top': ['marginTop'],
4336
4653
  'margin-right': ['marginRight'],