@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.
Files changed (134) hide show
  1. package/dist/html/controls.d.ts +29 -2
  2. package/dist/html/controls.d.ts.map +1 -1
  3. package/dist/html/controls.js +70 -2
  4. package/dist/html/controls.js.map +1 -1
  5. package/dist/html/css/cascade.d.ts +42 -1
  6. package/dist/html/css/cascade.d.ts.map +1 -1
  7. package/dist/html/css/cascade.js +336 -16
  8. package/dist/html/css/cascade.js.map +1 -1
  9. package/dist/html/css/color.d.ts +18 -0
  10. package/dist/html/css/color.d.ts.map +1 -1
  11. package/dist/html/css/color.js +27 -0
  12. package/dist/html/css/color.js.map +1 -1
  13. package/dist/html/css/parse.d.ts +18 -4
  14. package/dist/html/css/parse.d.ts.map +1 -1
  15. package/dist/html/css/parse.js +66 -28
  16. package/dist/html/css/parse.js.map +1 -1
  17. package/dist/html/css/shapes.d.ts +44 -0
  18. package/dist/html/css/shapes.d.ts.map +1 -0
  19. package/dist/html/css/shapes.js +194 -0
  20. package/dist/html/css/shapes.js.map +1 -0
  21. package/dist/html/css/style.d.ts +128 -15
  22. package/dist/html/css/style.d.ts.map +1 -1
  23. package/dist/html/css/style.js +547 -144
  24. package/dist/html/css/style.js.map +1 -1
  25. package/dist/html/css/transform.d.ts +85 -0
  26. package/dist/html/css/transform.d.ts.map +1 -0
  27. package/dist/html/css/transform.js +425 -0
  28. package/dist/html/css/transform.js.map +1 -0
  29. package/dist/html/css/ua.d.ts.map +1 -1
  30. package/dist/html/css/ua.js +14 -2
  31. package/dist/html/css/ua.js.map +1 -1
  32. package/dist/html/css/values.d.ts +4 -0
  33. package/dist/html/css/values.d.ts.map +1 -1
  34. package/dist/html/css/values.js.map +1 -1
  35. package/dist/html/fonts.d.ts +55 -5
  36. package/dist/html/fonts.d.ts.map +1 -1
  37. package/dist/html/fonts.js +284 -23
  38. package/dist/html/fonts.js.map +1 -1
  39. package/dist/html/layout/axes.d.ts +14 -0
  40. package/dist/html/layout/axes.d.ts.map +1 -0
  41. package/dist/html/layout/axes.js +28 -0
  42. package/dist/html/layout/axes.js.map +1 -0
  43. package/dist/html/layout/block.d.ts +104 -12
  44. package/dist/html/layout/block.d.ts.map +1 -1
  45. package/dist/html/layout/block.js +410 -39
  46. package/dist/html/layout/block.js.map +1 -1
  47. package/dist/html/layout/boxes.d.ts +72 -1
  48. package/dist/html/layout/boxes.d.ts.map +1 -1
  49. package/dist/html/layout/boxes.js +40 -2
  50. package/dist/html/layout/boxes.js.map +1 -1
  51. package/dist/html/layout/cache.d.ts +1 -1
  52. package/dist/html/layout/cache.d.ts.map +1 -1
  53. package/dist/html/layout/cache.js +6 -0
  54. package/dist/html/layout/cache.js.map +1 -1
  55. package/dist/html/layout/css-grid.d.ts.map +1 -1
  56. package/dist/html/layout/css-grid.js +144 -24
  57. package/dist/html/layout/css-grid.js.map +1 -1
  58. package/dist/html/layout/flex.d.ts.map +1 -1
  59. package/dist/html/layout/flex.js +585 -85
  60. package/dist/html/layout/flex.js.map +1 -1
  61. package/dist/html/layout/inline.d.ts +3 -0
  62. package/dist/html/layout/inline.d.ts.map +1 -1
  63. package/dist/html/layout/inline.js +144 -54
  64. package/dist/html/layout/inline.js.map +1 -1
  65. package/dist/html/layout/multicol.d.ts +42 -0
  66. package/dist/html/layout/multicol.d.ts.map +1 -0
  67. package/dist/html/layout/multicol.js +897 -0
  68. package/dist/html/layout/multicol.js.map +1 -0
  69. package/dist/html/layout/shaping.d.ts +7 -0
  70. package/dist/html/layout/shaping.d.ts.map +1 -1
  71. package/dist/html/layout/shaping.js +25 -20
  72. package/dist/html/layout/shaping.js.map +1 -1
  73. package/dist/html/layout/table.d.ts.map +1 -1
  74. package/dist/html/layout/table.js +97 -31
  75. package/dist/html/layout/table.js.map +1 -1
  76. package/dist/html/node.d.ts +4 -0
  77. package/dist/html/node.d.ts.map +1 -1
  78. package/dist/html/node.js +319 -47
  79. package/dist/html/node.js.map +1 -1
  80. package/dist/html/paint.d.ts +83 -5
  81. package/dist/html/paint.d.ts.map +1 -1
  82. package/dist/html/paint.js +1474 -217
  83. package/dist/html/paint.js.map +1 -1
  84. package/dist/html/svg.d.ts +39 -9
  85. package/dist/html/svg.d.ts.map +1 -1
  86. package/dist/html/svg.js +482 -37
  87. package/dist/html/svg.js.map +1 -1
  88. package/dist/html/widgets.js +87 -7
  89. package/dist/html/widgets.js.map +1 -1
  90. package/dist/html/woff2.d.ts +14 -0
  91. package/dist/html/woff2.d.ts.map +1 -0
  92. package/dist/html/woff2.js +608 -0
  93. package/dist/html/woff2.js.map +1 -0
  94. package/dist/maps/controller.d.ts +17 -1
  95. package/dist/maps/controller.d.ts.map +1 -1
  96. package/dist/maps/controller.js +27 -7
  97. package/dist/maps/controller.js.map +1 -1
  98. package/dist/richtext/node.d.ts +8 -1
  99. package/dist/richtext/node.d.ts.map +1 -1
  100. package/dist/richtext/node.js +5 -1
  101. package/dist/richtext/node.js.map +1 -1
  102. package/dist/richtext/runs.d.ts +25 -6
  103. package/dist/richtext/runs.d.ts.map +1 -1
  104. package/dist/richtext/runs.js +240 -24
  105. package/dist/richtext/runs.js.map +1 -1
  106. package/package.json +1 -1
  107. package/src/html/controls.ts +85 -2
  108. package/src/html/css/cascade.ts +366 -8
  109. package/src/html/css/color.ts +29 -0
  110. package/src/html/css/parse.ts +71 -31
  111. package/src/html/css/shapes.ts +239 -0
  112. package/src/html/css/style.ts +652 -147
  113. package/src/html/css/transform.ts +459 -0
  114. package/src/html/css/ua.ts +15 -2
  115. package/src/html/css/values.ts +4 -0
  116. package/src/html/fonts.ts +312 -29
  117. package/src/html/layout/axes.ts +62 -0
  118. package/src/html/layout/block.ts +466 -37
  119. package/src/html/layout/boxes.ts +95 -3
  120. package/src/html/layout/cache.ts +6 -0
  121. package/src/html/layout/css-grid.ts +169 -32
  122. package/src/html/layout/flex.ts +686 -79
  123. package/src/html/layout/inline.ts +149 -55
  124. package/src/html/layout/multicol.ts +977 -0
  125. package/src/html/layout/shaping.ts +27 -18
  126. package/src/html/layout/table.ts +105 -35
  127. package/src/html/node.ts +354 -48
  128. package/src/html/paint.ts +1804 -315
  129. package/src/html/svg.ts +573 -36
  130. package/src/html/widgets.ts +95 -9
  131. package/src/html/woff2.ts +612 -0
  132. package/src/maps/controller.ts +28 -7
  133. package/src/richtext/node.ts +13 -2
  134. package/src/richtext/runs.ts +313 -35
@@ -19,14 +19,14 @@ import { compile } from 'css-select';
19
19
  import * as DomUtils from 'domutils';
20
20
  import { Element as DomElement, isTag } from 'domhandler';
21
21
  import { attr, tagOf } from '../dom.js';
22
- import { svgSizeHint } from '../svg.js';
23
22
  import { asciiLower, escapeEnd, mediaMatches, readIdent, startsIdent, } from './parse.js';
24
- import { applyDeclaration, blockify, settleContentVisibility, settleOverflow, settleClamp, copyStyle, decorate, inherit, initialOne, initialStyle, isInherited, } from './style.js';
23
+ import { applyDeclaration, blockify, settleButton, settleContentVisibility, settleOverflow, settleClamp, copyStyle, decorate, inherit, initialOne, initialStyle, isInherited, } from './style.js';
25
24
  import { parseDeclarations } from './parse.js';
26
25
  import { CounterStyles, counterStyleRule } from './counter-styles.js';
27
26
  import { PALETTE_CHROME } from './ua.js';
28
27
  import { viewportUnit } from './values.js';
29
28
  import { customProperties, substituteIn } from './vars.js';
29
+ import { ROOT_BOX_PROPS, SHAPE_TAGS, isShapeProp, shapeValue, } from './shapes.js';
30
30
  /** Where a declaration came from. Higher wins before specificity is asked. */
31
31
  var Origin;
32
32
  (function (Origin) {
@@ -104,6 +104,10 @@ class RuleIndex {
104
104
  reaches(el) {
105
105
  if (this.universal.length || this.byTag.has(tagOf(el)))
106
106
  return true;
107
+ return this.names(el);
108
+ }
109
+ /** Whether a bucket here is for `el`'s id, or for a class of its. */
110
+ names(el) {
107
111
  if (this.byId.size) {
108
112
  const id = attr(el, 'id');
109
113
  if (id && this.byId.has(id))
@@ -120,18 +124,19 @@ class RuleIndex {
120
124
  }
121
125
  return false;
122
126
  }
123
- add(rule) {
127
+ add(rule, key = rightmostKey(rule.selector)) {
124
128
  this.size += 1;
125
129
  const indexed = {
126
130
  rule,
127
131
  match: null,
128
132
  compiled: false,
129
133
  id: this._nextId++,
134
+ needs: null,
135
+ root: null,
130
136
  };
131
137
  if (rule.selector.includes(':hover') || rule.selector.includes(':active')) {
132
138
  this.hoverSensitive = true;
133
139
  }
134
- const key = rightmostKey(rule.selector);
135
140
  if (UNSHAREABLE.test(rule.selector)) {
136
141
  if (key.kind === 'id')
137
142
  this.ownStyleIds.add(key.name);
@@ -476,11 +481,11 @@ const POINTER_PSEUDO = /:(?:hover|active)(?![\w-])/i;
476
481
  * `#box:has(a:hover) .m` answered what it did before the first move, for
477
482
  * good.
478
483
  */
479
- function compileSelector(selector, adapter) {
484
+ function compileSelector(selector, adapter, pseudos = PSEUDOS) {
480
485
  return compile(noEmptyWords(selector), {
481
486
  adapter,
482
487
  xmlMode: false,
483
- pseudos: PSEUDOS,
488
+ pseudos,
484
489
  cacheResults: !POINTER_PSEUDO.test(selector),
485
490
  });
486
491
  }
@@ -534,7 +539,10 @@ function rightmostKey(selector) {
534
539
  start = i + 1;
535
540
  }
536
541
  }
537
- const compound = selector.slice(start);
542
+ return compoundKey(selector.slice(start));
543
+ }
544
+ /** A compound selector's most selective key (`rightmostKey`). */
545
+ function compoundKey(compound) {
538
546
  let id = null;
539
547
  let cls = null;
540
548
  let tag = null;
@@ -577,6 +585,29 @@ function rightmostKey(selector) {
577
585
  return { kind: 'tag', name: tag };
578
586
  return { kind: 'any', name: '' };
579
587
  }
588
+ /**
589
+ * The ids and classes a selector asks of its subject's ancestors: for each
590
+ * compound a descendant or a child combinator follows, its id, or else its
591
+ * first class, as `#name` or `.name`. Such a compound is an ancestor of
592
+ * the subject — one a sibling combinator follows is a sibling of one — so
593
+ * an element with no ancestor of some such name is not the rule's, which
594
+ * is known without matching it. A compound with neither asks nothing.
595
+ */
596
+ function ancestorKeys(selector) {
597
+ const keys = [];
598
+ const compounds = compoundsOf(selector);
599
+ for (let i = 0; i < compounds.length - 1; i += 1) {
600
+ const { text, next } = compounds[i];
601
+ if (next !== ' ' && next !== '>')
602
+ continue;
603
+ const key = compoundKey(text);
604
+ if (key.kind === 'id')
605
+ keys.push(`#${key.name}`);
606
+ else if (key.kind === 'class')
607
+ keys.push(`.${key.name}`);
608
+ }
609
+ return keys;
610
+ }
580
611
  function balancedEnd(text, from, open, close) {
581
612
  let depth = 0;
582
613
  for (let i = from; i < text.length; i += 1) {
@@ -618,6 +649,13 @@ export class Cascade {
618
649
  marker: new RuleIndex(),
619
650
  selection: new RuleIndex(),
620
651
  };
652
+ /** The author's rules that could style a shape in a drawing: the ones
653
+ * that declare a property a shape has (`shapes.ts`) and whose subject
654
+ * is no element of HTML's alone. They are in `_index` too, for the
655
+ * elements that have boxes; these are asked of the ones in an inline
656
+ * `<svg>`, which have none (`shapeStyles`). */
657
+ _shapes = new RuleIndex();
658
+ _shapeNeeds = null;
621
659
  _adapter;
622
660
  /** The compounds of the selectors that test the pointer, each without
623
661
  * its `:hover` or `:active` (`pointerCompounds`), and their matchers,
@@ -681,7 +719,15 @@ export class Cascade {
681
719
  /** Whether any declaration has a length in `lh` or `rlh`: only then is
682
720
  * the line height settled ahead of the declarations that read it. */
683
721
  _lh = false;
684
- constructor(sheets, look, viewportWidth, viewportHeight, scale = 1, xHeight = null, zeroWidth = null, normalLine = null, families = null) {
722
+ /** The pseudo-classes css-select is handed, `:root` this cascade's. */
723
+ _pseudos;
724
+ constructor(sheets, look, viewportWidth, viewportHeight, scale = 1, xHeight = null, zeroWidth = null, normalLine = null, families = null,
725
+ /** The document's element where it is not an `<html>`: an SVG image's
726
+ * `<svg>`, which is `:root` there (Selectors 4, 14.1). */
727
+ documentElement = null) {
728
+ this._pseudos = documentElement
729
+ ? { ...PSEUDOS, root: (el) => el === documentElement }
730
+ : PSEUDOS;
685
731
  this._xHeightOf = xHeight;
686
732
  this._zeroWidthOf = zeroWidth;
687
733
  this._normalLineOf = normalLine;
@@ -712,8 +758,15 @@ export class Cascade {
712
758
  const pseudo = splitPseudoElement(rule);
713
759
  if (pseudo)
714
760
  this._pseudo[pseudo.which].add(pseudo.rule);
715
- else
716
- this._index.add(rule);
761
+ else {
762
+ const key = rightmostKey(rule.selector);
763
+ this._index.add(rule, key);
764
+ if (rule.order >= 0 &&
765
+ (key.kind !== 'tag' || SHAPE_TAGS.has(key.name)) &&
766
+ declaresShape(rule.declarations)) {
767
+ this._shapes.add(rule, key);
768
+ }
769
+ }
717
770
  this._noteHover((pseudo?.rule ?? rule).selector);
718
771
  }
719
772
  for (const bp of sheet.breakpoints)
@@ -888,7 +941,7 @@ export class Cascade {
888
941
  * it, as a rule it refuses drops out of the cascade. */
889
942
  _compile(selector) {
890
943
  try {
891
- return compileSelector(selector, this._adapter);
944
+ return compileSelector(selector, this._adapter, this._pseudos);
892
945
  }
893
946
  catch {
894
947
  return null;
@@ -1065,7 +1118,7 @@ export class Cascade {
1065
1118
  let shared = this._sharedByMatch.get(key);
1066
1119
  if (shared === undefined) {
1067
1120
  shared = {
1068
- style: this._computeStyle(el, parentStyle, inFlexContainer, candidates),
1121
+ style: this._computeStyle(el, parentStyle, inFlexContainer, candidates, true),
1069
1122
  key: this._nextShareKey++,
1070
1123
  };
1071
1124
  this._sharedByMatch.set(key, shared);
@@ -1113,7 +1166,7 @@ export class Cascade {
1113
1166
  * a style is computed only for the elements with none to share.
1114
1167
  */
1115
1168
  styleFor(el, parentStyle, inFlexContainer) {
1116
- return this._computeStyle(el, parentStyle, inFlexContainer, this._candidates(el));
1169
+ return this._computeStyle(el, parentStyle, inFlexContainer, this._candidates(el), true);
1117
1170
  }
1118
1171
  /**
1119
1172
  * The style of an element's `::before` or `::after`, or null when it has
@@ -1305,7 +1358,10 @@ export class Cascade {
1305
1358
  return line;
1306
1359
  }
1307
1360
  /** `styleFor`, from the rules and hints already gathered for `el`. */
1308
- _computeStyle(el, parentStyle, inFlexContainer, candidates) {
1361
+ _computeStyle(el, parentStyle, inFlexContainer, candidates,
1362
+ /** Whether the style is the element's own, and not that of one of its
1363
+ * pseudo-elements. */
1364
+ own = false) {
1309
1365
  const style = inherit(parentStyle, this.initial);
1310
1366
  // custom properties first, in cascade order, so every `var()` in the
1311
1367
  // declarations below finds the one that wins
@@ -1317,10 +1373,14 @@ export class Cascade {
1317
1373
  // em-relative length in the same rule resolves against this element's.
1318
1374
  const root = isRootElement(el);
1319
1375
  const rootStyle = root ? this.initial : (this._root ?? this.initial);
1376
+ // whose declaration is being applied: the UA sheet's families are the
1377
+ // host's own faces, and its lists end where they end
1378
+ let authored = true;
1320
1379
  const ctxParent = {
1321
1380
  em: parentStyle.fontSize,
1322
1381
  rem: rootStyle.fontSize,
1323
1382
  initial: this.initial,
1383
+ fallbackFamily: () => (authored ? this.initial.fontFamily : null),
1324
1384
  vw: this.viewportWidth,
1325
1385
  vh: this.viewportHeight,
1326
1386
  scale: this.scale,
@@ -1339,6 +1399,7 @@ export class Cascade {
1339
1399
  let sized = false;
1340
1400
  let keyword = false;
1341
1401
  for (const c of candidates) {
1402
+ authored = c.origin !== Origin.UserAgent;
1342
1403
  for (const d of pick(c)) {
1343
1404
  if (d.prop === 'font-family' ||
1344
1405
  d.prop === 'font-weight' ||
@@ -1401,6 +1462,7 @@ export class Cascade {
1401
1462
  // them. A `font` sets the size as well, which the first pass settled.
1402
1463
  if (this._lh) {
1403
1464
  for (const c of candidates) {
1465
+ authored = c.origin !== Origin.UserAgent;
1404
1466
  for (const d of pick(c)) {
1405
1467
  if (d.prop === 'line-height' || d.prop === 'font') {
1406
1468
  this._apply(style, parentStyle, d, ctx);
@@ -1416,6 +1478,7 @@ export class Cascade {
1416
1478
  }
1417
1479
  const settled = style.fontSize;
1418
1480
  for (const c of candidates) {
1481
+ authored = c.origin !== Origin.UserAgent;
1419
1482
  for (const d of pick(c)) {
1420
1483
  if (d.prop === 'font-size' || d.custom)
1421
1484
  continue;
@@ -1443,6 +1506,10 @@ export class Cascade {
1443
1506
  settleOverflow(style);
1444
1507
  settleContentVisibility(style);
1445
1508
  blockify(style, inFlexContainer);
1509
+ // a button is laid out as one, whatever `display` it was given
1510
+ if (own && el.name.length === 6 && tagOf(el) === 'button') {
1511
+ settleButton(style);
1512
+ }
1446
1513
  decorate(style);
1447
1514
  // which faces of the document's own families this family, weight and
1448
1515
  // slant ask for — known only now, with all three computed
@@ -1513,6 +1580,187 @@ export class Cascade {
1513
1580
  // the root is still the initial containing block.
1514
1581
  return { style: asRoot(this.styleFor(synthetic, parent, false)), html };
1515
1582
  }
1583
+ /** Whether any rule could style a shape in a drawing: a document with
1584
+ * none asks nothing of its drawings (`shapeStyles`). */
1585
+ get stylesShapes() {
1586
+ return this._shapes.size > 0;
1587
+ }
1588
+ /** Whether a pointer move can change what a rule gives a shape in a
1589
+ * drawing. */
1590
+ get shapesFollowPointer() {
1591
+ return this._shapes.hoverSensitive;
1592
+ }
1593
+ /**
1594
+ * What the rules give the elements of an inline drawing, `root` and what
1595
+ * is in it, or null where none reaches one: the narrow cascade of
1596
+ * `shapes.ts`. `style` is the root's computed style — its `color`, its
1597
+ * custom properties and its font size are what a value in the drawing is
1598
+ * read against, as though every element in it had inherited them, which
1599
+ * all but one a rule gives its own has.
1600
+ *
1601
+ * An element's rules and its `style` attribute are put in cascade order,
1602
+ * and each property is the last valid declaration's. The presentation
1603
+ * attributes are below them all (SVG 2, 6.2), and `SvgView` reads those
1604
+ * itself. The root's box has its paint, its opacity and whether it is
1605
+ * shown from its computed style, so those are left out for it.
1606
+ *
1607
+ * Asked as a drawing is first painted (`BoxTree.shapeStyler`), of the
1608
+ * rules in `_shapes` alone: a page of hundreds of icons pays for the ones
1609
+ * it shows, a look in the buckets for each of their elements where no
1610
+ * rule reaches them, and a document with no such rule nothing.
1611
+ */
1612
+ shapeStyles(root, style) {
1613
+ const index = this._shapes;
1614
+ if (!index.size)
1615
+ return null;
1616
+ // The rules kept by a class or an id are asked of the elements with
1617
+ // that name. The rest — `.dark .logo path`, `.menu [aria-hidden]` — are
1618
+ // asked of every `<path>`, or of every element, and nearly all of them
1619
+ // are for some other part of the page: each says so by the class or the
1620
+ // id it asks of an ancestor, which is looked for once for the drawing,
1621
+ // around it and in it, where matching the rule would look for it from
1622
+ // each of its elements. On a page with none of them around a drawing,
1623
+ // nothing is matched at all.
1624
+ const needs = (this._shapeNeeds ??= this._needsOfShapes());
1625
+ const found = new Set();
1626
+ const asks = needs.classes.size > 0 || needs.ids.size > 0;
1627
+ const note = (el) => {
1628
+ if (needs.ids.size) {
1629
+ const id = attr(el, 'id');
1630
+ if (id && needs.ids.has(id))
1631
+ found.add(`#${id}`);
1632
+ }
1633
+ if (needs.classes.size) {
1634
+ const className = attr(el, 'class');
1635
+ if (className) {
1636
+ for (const name of className.split(/\s+/)) {
1637
+ if (needs.classes.has(name))
1638
+ found.add(`.${name}`);
1639
+ }
1640
+ }
1641
+ }
1642
+ };
1643
+ if (asks) {
1644
+ let at = root.parent;
1645
+ while (at && at.type === 'tag') {
1646
+ note(at);
1647
+ at = at.parent;
1648
+ }
1649
+ }
1650
+ const live = (indexed) => {
1651
+ const keys = indexed.needs;
1652
+ if (keys)
1653
+ for (const key of keys)
1654
+ if (!found.has(key))
1655
+ return false;
1656
+ return true;
1657
+ };
1658
+ // The root's box has its paint from its computed style, so most of the
1659
+ // rules that name a drawing by its class — an icon set's — have
1660
+ // nothing else to say of it.
1661
+ const liveForRoot = (indexed) => (indexed.root ??= declaresRootShape(indexed.rule.declarations)) &&
1662
+ live(indexed);
1663
+ let of = null;
1664
+ let key = '';
1665
+ let ctx = null;
1666
+ // in document order, the root first: an element's place in it is what
1667
+ // the key names it by, and its ancestors in the drawing are noted
1668
+ // before it is asked of
1669
+ const stack = [root];
1670
+ let place = -1;
1671
+ while (stack.length) {
1672
+ const el = stack.pop();
1673
+ place += 1;
1674
+ // what is in a `<foreignObject>` is not the drawing's to draw
1675
+ if (el.name !== 'foreignobject' && el.name !== 'foreignObject') {
1676
+ const children = el.children;
1677
+ for (let i = children.length - 1; i >= 0; i -= 1) {
1678
+ const child = children[i];
1679
+ if (child.type === 'tag')
1680
+ stack.push(child);
1681
+ }
1682
+ }
1683
+ if (asks)
1684
+ note(el);
1685
+ const tag = tagOf(el);
1686
+ const asked = found.size
1687
+ ? index.universal.length > 0 || index.byTag.has(tag)
1688
+ : needs.universal || needs.tags.has(tag);
1689
+ if (!asked && !index.names(el))
1690
+ continue;
1691
+ const candidates = [];
1692
+ this._matchInto(index, el, candidates, undefined, el === root ? liveForRoot : live);
1693
+ if (!candidates.length)
1694
+ continue;
1695
+ const inline = attr(el, 'style');
1696
+ if (inline)
1697
+ pushInlineShapes(candidates, inline);
1698
+ candidates.sort(byCascade);
1699
+ ctx ??= {
1700
+ color: style.color,
1701
+ scheme: style.colorScheme,
1702
+ units: {
1703
+ em: style.fontSize,
1704
+ rem: (this._root ?? this.initial).fontSize,
1705
+ vw: this.viewportWidth,
1706
+ vh: this.viewportHeight,
1707
+ scale: this.scale,
1708
+ initial: this.initial,
1709
+ },
1710
+ };
1711
+ let own = null;
1712
+ for (const c of candidates) {
1713
+ for (const d of pick(c)) {
1714
+ if (!isShapeProp(d.prop))
1715
+ continue;
1716
+ if (el === root && ROOT_BOX_PROPS.has(d.prop))
1717
+ continue;
1718
+ // a `var()` with nothing to stand for it is invalid at
1719
+ // computed-value time, and the property as though `unset`
1720
+ const value = shapeValue(d.prop, d.vars ? (substituteIn(d.value, style.custom) ?? 'unset') : d.value, ctx);
1721
+ if (value !== null)
1722
+ (own ??= {})[d.prop] = value;
1723
+ }
1724
+ }
1725
+ if (!own)
1726
+ continue;
1727
+ (of ??= new Map()).set(el, own);
1728
+ key += `${place}{`;
1729
+ for (const prop in own)
1730
+ key += `${prop}:${own[prop]};`;
1731
+ key += '}';
1732
+ }
1733
+ return of ? { of, key } : null;
1734
+ }
1735
+ /** `ShapeNeeds`, and each such rule's own (`IndexedRule.needs`). */
1736
+ _needsOfShapes() {
1737
+ const index = this._shapes;
1738
+ const needs = {
1739
+ classes: new Set(),
1740
+ ids: new Set(),
1741
+ universal: false,
1742
+ tags: new Set(),
1743
+ };
1744
+ const read = (bucket) => {
1745
+ let free = false;
1746
+ for (const indexed of bucket) {
1747
+ const keys = ancestorKeys(indexed.rule.selector);
1748
+ indexed.needs = keys;
1749
+ if (!keys.length)
1750
+ free = true;
1751
+ for (const key of keys) {
1752
+ (key[0] === '#' ? needs.ids : needs.classes).add(key.slice(1));
1753
+ }
1754
+ }
1755
+ return free;
1756
+ };
1757
+ needs.universal = read(index.universal);
1758
+ for (const [tag, bucket] of index.byTag) {
1759
+ if (read(bucket))
1760
+ needs.tags.add(tag);
1761
+ }
1762
+ return needs;
1763
+ }
1516
1764
  /**
1517
1765
  * Whether the pointer's move from `was` to where it is changed which
1518
1766
  * rules match `el`, or its `::before`, `::after` or another of its
@@ -1550,7 +1798,9 @@ export class Cascade {
1550
1798
  }
1551
1799
  /** The rules of `index` that match `el`, pushed onto `out` as candidates,
1552
1800
  * and their ids onto `matched` in the order they were tried. */
1553
- _matchInto(index, el, out, matched) {
1801
+ _matchInto(index, el, out, matched,
1802
+ /** The rules to try, where some are known not to match without it. */
1803
+ live) {
1554
1804
  // A media query's width is CSS pixels; the viewport is kept in device.
1555
1805
  const width = this.viewportWidth / this.scale;
1556
1806
  const height = this.viewportHeight / this.scale;
@@ -1558,6 +1808,8 @@ export class Cascade {
1558
1808
  if (!bucket)
1559
1809
  return;
1560
1810
  for (const indexed of bucket) {
1811
+ if (live !== undefined && !live(indexed))
1812
+ continue;
1561
1813
  const rule = indexed.rule;
1562
1814
  if (!mediaMatches(rule.media, width, this.look.colorScheme, height, this.scale)) {
1563
1815
  continue;
@@ -1565,7 +1817,7 @@ export class Cascade {
1565
1817
  if (!indexed.compiled) {
1566
1818
  indexed.compiled = true;
1567
1819
  try {
1568
- indexed.match = compileSelector(rule.selector, this._adapter);
1820
+ indexed.match = compileSelector(rule.selector, this._adapter, this._pseudos);
1569
1821
  }
1570
1822
  catch {
1571
1823
  // A selector this matcher does not know (`::-moz-…`, a CSS4 form
@@ -1844,6 +2096,49 @@ function setsContent(c) {
1844
2096
  }
1845
2097
  /** Whether a rule's declarations set a custom property, by the array. */
1846
2098
  const CUSTOM_IN = new WeakMap();
2099
+ /** Whether declarations set a property a shape in a drawing has. */
2100
+ function declaresShape(declarations) {
2101
+ for (const d of declarations)
2102
+ if (isShapeProp(d.prop))
2103
+ return true;
2104
+ return false;
2105
+ }
2106
+ /** Whether declarations set one a drawing's root does not have from its
2107
+ * box's style (`ROOT_BOX_PROPS`). */
2108
+ function declaresRootShape(declarations) {
2109
+ for (const d of declarations) {
2110
+ if (isShapeProp(d.prop) && !ROOT_BOX_PROPS.has(d.prop))
2111
+ return true;
2112
+ }
2113
+ return false;
2114
+ }
2115
+ /** A `style` attribute's declarations of a shape's properties, as
2116
+ * candidates: over every rule, and its `!important` ones over theirs. */
2117
+ function pushInlineShapes(out, inline) {
2118
+ const declarations = parseDeclarations(inline).filter((d) => isShapeProp(d.prop));
2119
+ const normal = declarations.filter((d) => !d.important);
2120
+ const important = declarations.filter((d) => d.important);
2121
+ if (normal.length) {
2122
+ out.push({
2123
+ origin: Origin.Inline,
2124
+ layer: null,
2125
+ specificity: 0,
2126
+ order: 0,
2127
+ declarations: normal,
2128
+ only: -1,
2129
+ });
2130
+ }
2131
+ if (important.length) {
2132
+ out.push({
2133
+ origin: Origin.InlineImportant,
2134
+ layer: null,
2135
+ specificity: 0,
2136
+ order: 0,
2137
+ declarations: important,
2138
+ only: -1,
2139
+ });
2140
+ }
2141
+ }
1847
2142
  function pick(c) {
1848
2143
  return c.only < 0 ? c.declarations : [c.declarations[c.only]];
1849
2144
  }
@@ -2058,6 +2353,14 @@ function presentationHints(el) {
2058
2353
  const h = height ? svgSizeHint(height) : null;
2059
2354
  if (h)
2060
2355
  push('height', h);
2356
+ // and its paint is its `fill` and `stroke` properties' (13.2), which a
2357
+ // rule of the document's then sets over the attribute
2358
+ const fill = attr(el, 'fill');
2359
+ if (fill)
2360
+ push('fill', fill);
2361
+ const stroke = attr(el, 'stroke');
2362
+ if (stroke)
2363
+ push('stroke', stroke);
2061
2364
  }
2062
2365
  if (tag === 'table') {
2063
2366
  const border = attr(el, 'border');
@@ -2230,6 +2533,23 @@ function lengthAttr(value) {
2230
2533
  const n = parseFloat(v);
2231
2534
  return Number.isFinite(n) ? `${n}px` : v;
2232
2535
  }
2536
+ /** A number and a unit, as an SVG's `width` and `height` are written. */
2537
+ const SVG_LENGTH = /^\s*([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*([a-z]*)\s*$/i;
2538
+ /**
2539
+ * The `width`/`height` of an inline `<svg>` as CSS: they are presentation
2540
+ * attributes for the properties of the same names (SVG 2, 5.1.1), so
2541
+ * `height="50%"` is a percentage of the containing block like a style's.
2542
+ * A bare number is pixels; null for what CSS would not parse.
2543
+ */
2544
+ function svgSizeHint(value) {
2545
+ const v = value.trim();
2546
+ if (/^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?%$/i.test(v))
2547
+ return v;
2548
+ const m = SVG_LENGTH.exec(v);
2549
+ if (!m)
2550
+ return null;
2551
+ return m[2] ? v : `${parseFloat(m[1])}px`;
2552
+ }
2233
2553
  function closestTable(el) {
2234
2554
  let node = el.parent;
2235
2555
  while (node) {