praxis-kit 6.2.3 → 6.5.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.
@@ -964,7 +964,11 @@ var ATTRIBUTE_IGNORED_CODES = {
964
964
  max: DiagnosticCode3.HtmlInputMaxIgnoredForType,
965
965
  step: DiagnosticCode3.HtmlInputStepIgnoredForType,
966
966
  accept: DiagnosticCode3.HtmlInputAcceptIgnoredForType,
967
- capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType
967
+ capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType,
968
+ size: DiagnosticCode3.HtmlInputSizeIgnoredForType,
969
+ alt: DiagnosticCode3.HtmlInputAltIgnoredForType,
970
+ height: DiagnosticCode3.HtmlInputHeightIgnoredForType,
971
+ width: DiagnosticCode3.HtmlInputWidthIgnoredForType
968
972
  };
969
973
  var HtmlDiagnostics = {
970
974
  emptyRole(tag) {
@@ -1198,8 +1202,132 @@ var InvariantBase = class {
1198
1202
  }
1199
1203
  };
1200
1204
 
1201
- // ../../lib/contract/src/aria/polymorphic-validator.ts
1205
+ // ../../lib/contract/src/aria/spec/roles/required-properties.ts
1206
+ var REQUIRED_ARIA_PROPERTIES = {
1207
+ combobox: ["aria-expanded"],
1208
+ option: ["aria-selected"],
1209
+ slider: ["aria-valuenow"],
1210
+ scrollbar: ["aria-controls", "aria-valuenow"],
1211
+ spinbutton: ["aria-valuenow"]
1212
+ };
1213
+
1214
+ // ../../lib/contract/src/aria/spec/roles/name-required.ts
1215
+ var NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1216
+
1217
+ // ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
1202
1218
  var NO_VIOLATIONS = [{ valid: true }];
1219
+ function requiredAttributeByRole(roles, attribute) {
1220
+ return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
1221
+ }
1222
+ function checkRequiredAttributes(requirement, { props, effectiveRole }) {
1223
+ if (!effectiveRole) return NO_VIOLATIONS;
1224
+ const requiredAttributes = requirement.attributesByRole[effectiveRole];
1225
+ if (!requiredAttributes) return NO_VIOLATIONS;
1226
+ const results = [];
1227
+ for (const attribute of requiredAttributes) {
1228
+ if (attribute in props) continue;
1229
+ results.push({
1230
+ valid: false,
1231
+ fixable: false,
1232
+ severity: "warning",
1233
+ attribute,
1234
+ diagnostic: requirement.diagnosticFor(attribute, effectiveRole)
1235
+ });
1236
+ }
1237
+ return results;
1238
+ }
1239
+
1240
+ // ../../lib/contract/src/aria/spec/roles/live-region.ts
1241
+ var LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
1242
+ ["alert", "assertive"],
1243
+ ["status", "polite"],
1244
+ ["log", "polite"],
1245
+ ["timer", "off"]
1246
+ ]);
1247
+ var ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
1248
+
1249
+ // ../../lib/contract/src/aria/spec/attributes/aria-value-types.ts
1250
+ var ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1251
+ // Boolean (true | false)
1252
+ ["aria-atomic", { kind: "boolean" }],
1253
+ ["aria-busy", { kind: "boolean" }],
1254
+ ["aria-disabled", { kind: "boolean" }],
1255
+ ["aria-expanded", { kind: "boolean" }],
1256
+ ["aria-hidden", { kind: "boolean" }],
1257
+ ["aria-modal", { kind: "boolean" }],
1258
+ ["aria-multiline", { kind: "boolean" }],
1259
+ ["aria-multiselectable", { kind: "boolean" }],
1260
+ ["aria-readonly", { kind: "boolean" }],
1261
+ ["aria-required", { kind: "boolean" }],
1262
+ ["aria-selected", { kind: "boolean" }],
1263
+ // Tristate (true | false | mixed)
1264
+ ["aria-checked", { kind: "tristate" }],
1265
+ ["aria-pressed", { kind: "tristate" }],
1266
+ // Numeric (any finite number)
1267
+ ["aria-valuenow", { kind: "number" }],
1268
+ ["aria-valuemin", { kind: "number" }],
1269
+ ["aria-valuemax", { kind: "number" }],
1270
+ // Integer with optional range
1271
+ ["aria-level", { kind: "integer", min: 1, max: 6 }],
1272
+ ["aria-posinset", { kind: "integer", min: 1 }],
1273
+ ["aria-setsize", { kind: "integer", min: -1 }],
1274
+ ["aria-rowcount", { kind: "integer", min: -1 }],
1275
+ ["aria-colcount", { kind: "integer", min: -1 }],
1276
+ ["aria-rowindex", { kind: "integer", min: 1 }],
1277
+ ["aria-colindex", { kind: "integer", min: 1 }],
1278
+ ["aria-rowspan", { kind: "integer", min: 0 }],
1279
+ ["aria-colspan", { kind: "integer", min: 0 }],
1280
+ // Enum (specific allowed tokens)
1281
+ ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1282
+ [
1283
+ "aria-current",
1284
+ {
1285
+ kind: "enum",
1286
+ values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1287
+ }
1288
+ ],
1289
+ [
1290
+ "aria-haspopup",
1291
+ {
1292
+ kind: "enum",
1293
+ values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1294
+ }
1295
+ ],
1296
+ ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1297
+ ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1298
+ ["aria-orientation", { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }],
1299
+ ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1300
+ ]);
1301
+
1302
+ // ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
1303
+ var VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
1304
+ "additions",
1305
+ "removals",
1306
+ "text",
1307
+ "all"
1308
+ ]);
1309
+
1310
+ // ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
1311
+ var HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1312
+ ["h1", 1],
1313
+ ["h2", 2],
1314
+ ["h3", 3],
1315
+ ["h4", 4],
1316
+ ["h5", 5],
1317
+ ["h6", 6]
1318
+ ]);
1319
+
1320
+ // ../../lib/contract/src/aria/spec/elements/interactive-tags.ts
1321
+ var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1322
+ "a",
1323
+ "button",
1324
+ "input",
1325
+ "select",
1326
+ "textarea"
1327
+ ]);
1328
+
1329
+ // ../../lib/contract/src/aria/polymorphic-validator.ts
1330
+ var NO_VIOLATIONS2 = [{ valid: true }];
1203
1331
  function isIntrinsicTag(tag) {
1204
1332
  return isString(tag);
1205
1333
  }
@@ -1261,6 +1389,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1261
1389
  const violations = [];
1262
1390
  const fixes = [];
1263
1391
  iterate.forEach(rules, (rule) => {
1392
+ if (isNonNull(rule.tags) && !rule.tags.includes(context.tag)) return;
1264
1393
  iterate.forEach(rule(context), (result) => {
1265
1394
  if (result.valid) return;
1266
1395
  const {
@@ -1286,7 +1415,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1286
1415
  return { violations, fixes };
1287
1416
  }
1288
1417
  static #getRules(context) {
1289
- if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1418
+ if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && LIVE_REGION_ROLES.has(context.effectiveRole)) {
1290
1419
  return _AriaPolicyEngine.#pipeline;
1291
1420
  }
1292
1421
  return _AriaPolicyEngine.#implicitOnlyRules;
@@ -1488,7 +1617,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1488
1617
  implicitRole
1489
1618
  }) {
1490
1619
  const role = props.role;
1491
- if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS;
1620
+ if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS2;
1492
1621
  if (isStrongImplicitRole(tag) && role === "region") {
1493
1622
  const diagnostic = HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role);
1494
1623
  return [
@@ -1501,11 +1630,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1501
1630
  }
1502
1631
  ];
1503
1632
  }
1504
- return NO_VIOLATIONS;
1633
+ return NO_VIOLATIONS2;
1505
1634
  }
1506
1635
  static #checkRedundantRole({ tag, props, implicitRole }) {
1507
1636
  const role = props.role;
1508
- if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS;
1637
+ if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS2;
1509
1638
  const diagnostic = HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole);
1510
1639
  return [
1511
1640
  {
@@ -1519,8 +1648,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1519
1648
  }
1520
1649
  static #checkStandaloneRegion({ tag, props, implicitRole }) {
1521
1650
  const role = props.role;
1522
- if (role !== "region") return NO_VIOLATIONS;
1523
- if (!isStandaloneTag(tag)) return NO_VIOLATIONS;
1651
+ if (role !== "region") return NO_VIOLATIONS2;
1652
+ if (!isStandaloneTag(tag)) return NO_VIOLATIONS2;
1524
1653
  const diagnostic = HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag);
1525
1654
  return [
1526
1655
  {
@@ -1537,7 +1666,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1537
1666
  props,
1538
1667
  effectiveRole
1539
1668
  }) {
1540
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1669
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1541
1670
  const results = [];
1542
1671
  iterate.forEachEntry(props, (key) => {
1543
1672
  if (!key.startsWith("aria-")) return;
@@ -1555,62 +1684,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1555
1684
  return results;
1556
1685
  }
1557
1686
  // ─── ARIA attribute value validation ──────────────────────────────────────
1558
- // Accepted value shapes for typed ARIA attributes.
1559
- // Attributes not in this map are unconstrained (arbitrary string values permitted).
1560
- static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1561
- // Boolean (true | false)
1562
- ["aria-atomic", { kind: "boolean" }],
1563
- ["aria-busy", { kind: "boolean" }],
1564
- ["aria-disabled", { kind: "boolean" }],
1565
- ["aria-expanded", { kind: "boolean" }],
1566
- ["aria-hidden", { kind: "boolean" }],
1567
- ["aria-modal", { kind: "boolean" }],
1568
- ["aria-multiline", { kind: "boolean" }],
1569
- ["aria-multiselectable", { kind: "boolean" }],
1570
- ["aria-readonly", { kind: "boolean" }],
1571
- ["aria-required", { kind: "boolean" }],
1572
- ["aria-selected", { kind: "boolean" }],
1573
- // Tristate (true | false | mixed)
1574
- ["aria-checked", { kind: "tristate" }],
1575
- ["aria-pressed", { kind: "tristate" }],
1576
- // Numeric (any finite number)
1577
- ["aria-valuenow", { kind: "number" }],
1578
- ["aria-valuemin", { kind: "number" }],
1579
- ["aria-valuemax", { kind: "number" }],
1580
- // Integer with optional range
1581
- ["aria-level", { kind: "integer", min: 1, max: 6 }],
1582
- ["aria-posinset", { kind: "integer", min: 1 }],
1583
- ["aria-setsize", { kind: "integer", min: -1 }],
1584
- ["aria-rowcount", { kind: "integer", min: -1 }],
1585
- ["aria-colcount", { kind: "integer", min: -1 }],
1586
- ["aria-rowindex", { kind: "integer", min: 1 }],
1587
- ["aria-colindex", { kind: "integer", min: 1 }],
1588
- ["aria-rowspan", { kind: "integer", min: 0 }],
1589
- ["aria-colspan", { kind: "integer", min: 0 }],
1590
- // Enum (specific allowed tokens)
1591
- ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1592
- [
1593
- "aria-current",
1594
- {
1595
- kind: "enum",
1596
- values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1597
- }
1598
- ],
1599
- [
1600
- "aria-haspopup",
1601
- {
1602
- kind: "enum",
1603
- values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1604
- }
1605
- ],
1606
- ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1607
- ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1608
- [
1609
- "aria-orientation",
1610
- { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
1611
- ],
1612
- ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1613
- ]);
1614
1687
  static #isValidAriaValue(value, type) {
1615
1688
  switch (type.kind) {
1616
1689
  case "boolean":
@@ -1655,11 +1728,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1655
1728
  }
1656
1729
  }
1657
1730
  static #checkAriaAttributeValues({ props, effectiveRole }) {
1658
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1731
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1659
1732
  const results = [];
1660
1733
  iterate.forEachEntry(props, (key, value) => {
1661
1734
  if (!key.startsWith("aria-")) return;
1662
- const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1735
+ const type = ARIA_VALUE_TYPES.get(key);
1663
1736
  if (!isNonNull(type)) return;
1664
1737
  if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1665
1738
  results.push({
@@ -1678,26 +1751,18 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1678
1751
  return results;
1679
1752
  }
1680
1753
  // ─── Heading implicit level ────────────────────────────────────────────────
1681
- static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1682
- ["h1", 1],
1683
- ["h2", 2],
1684
- ["h3", 3],
1685
- ["h4", 4],
1686
- ["h5", 5],
1687
- ["h6", 6]
1688
- ]);
1689
1754
  static #checkRedundantAriaLevel({
1690
1755
  tag,
1691
1756
  props,
1692
1757
  effectiveRole
1693
1758
  }) {
1694
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1695
- const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1696
- if (!isNonNull(implicitLevel)) return NO_VIOLATIONS;
1759
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1760
+ const implicitLevel = HEADING_IMPLICIT_LEVELS.get(tag);
1761
+ if (!isNonNull(implicitLevel)) return NO_VIOLATIONS2;
1697
1762
  const raw = props["aria-level"];
1698
- if (!isNonNull(raw)) return NO_VIOLATIONS;
1763
+ if (!isNonNull(raw)) return NO_VIOLATIONS2;
1699
1764
  const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1700
- if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS;
1765
+ if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS2;
1701
1766
  return [
1702
1767
  {
1703
1768
  valid: false,
@@ -1710,20 +1775,14 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1710
1775
  ];
1711
1776
  }
1712
1777
  // ─── Name-required roles ───────────────────────────────────────────────────
1713
- // Roles that always require an accessible name per WAI-ARIA APG.
1714
- // Dialog and landmark names are enforced via contracts (ariaContract) rather than
1715
- // the built-in pipeline so consumers can opt in; img is built in because role=img
1716
- // on any element (including bare <img>) is definitionally useless without a name.
1717
- static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1718
1778
  static #checkNameRequiredRoles({
1719
1779
  tag,
1720
1780
  props,
1721
1781
  effectiveRole
1722
1782
  }) {
1723
- if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole))
1724
- return NO_VIOLATIONS;
1725
- if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS;
1726
- if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
1783
+ if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return NO_VIOLATIONS2;
1784
+ if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS2;
1785
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS2;
1727
1786
  return [
1728
1787
  {
1729
1788
  valid: false,
@@ -1733,51 +1792,21 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1733
1792
  }
1734
1793
  ];
1735
1794
  }
1736
- // WAI-ARIA 1.2 required states and properties, keyed by role.
1737
- // Source: https://www.w3.org/TR/wai-aria-1.2/#requiredState
1738
- static #REQUIRED_PROPERTIES = /* @__PURE__ */ new Map([
1739
- ["combobox", ["aria-expanded"]],
1740
- ["option", ["aria-selected"]],
1741
- ["slider", ["aria-valuenow"]],
1742
- ["scrollbar", ["aria-controls", "aria-valuenow"]],
1743
- ["spinbutton", ["aria-valuenow"]]
1744
- ]);
1745
- static #checkRequiredAriaProperties({
1746
- props,
1747
- effectiveRole
1748
- }) {
1749
- if (!effectiveRole) return NO_VIOLATIONS;
1750
- const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1751
- if (!isNonNull(required)) return NO_VIOLATIONS;
1752
- const results = [];
1753
- iterate.forEach(required, (attr) => {
1754
- if (attr in props) return;
1755
- results.push({
1756
- valid: false,
1757
- fixable: false,
1758
- severity: "warning",
1759
- attribute: attr,
1760
- diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
1761
- });
1762
- });
1763
- return results;
1795
+ static #requiredAriaPropertiesRule = {
1796
+ attributesByRole: REQUIRED_ARIA_PROPERTIES,
1797
+ diagnosticFor: (attribute, role) => AriaDiagnostics.requiredProperty(attribute, role)
1798
+ };
1799
+ static #checkRequiredAriaProperties(context) {
1800
+ return checkRequiredAttributes(_AriaPolicyEngine.#requiredAriaPropertiesRule, context);
1764
1801
  }
1765
- // Natively interactive HTML elements — always keyboard-reachable unless explicitly disabled.
1766
- static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1767
- "a",
1768
- "button",
1769
- "input",
1770
- "select",
1771
- "textarea"
1772
- ]);
1773
1802
  // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1774
1803
  static #checkAriaHiddenOnFocusable({ tag, props }) {
1775
- if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS;
1776
- const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1804
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS2;
1805
+ const isInteractive = INTERACTIVE_TAGS.has(tag);
1777
1806
  if (!isInteractive) {
1778
1807
  const tabindex = props.tabindex;
1779
1808
  const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1780
- if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS;
1809
+ if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS2;
1781
1810
  }
1782
1811
  return [
1783
1812
  {
@@ -1796,7 +1825,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1796
1825
  props,
1797
1826
  effectiveRole
1798
1827
  }) {
1799
- if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS;
1828
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS2;
1800
1829
  const results = [];
1801
1830
  iterate.forEachEntry(props, (key) => {
1802
1831
  if (!key.startsWith("aria-")) return;
@@ -1812,18 +1841,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1812
1841
  });
1813
1842
  return results;
1814
1843
  }
1815
- // WAI-ARIA live region roles and their implied aria-live politeness values.
1816
- static #LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
1817
- ["alert", "assertive"],
1818
- ["status", "polite"],
1819
- ["log", "polite"],
1820
- ["timer", "off"]
1821
- ]);
1822
1844
  static #checkMissingLiveRegion({ effectiveRole, props }) {
1823
- if (!effectiveRole) return NO_VIOLATIONS;
1824
- const impliedLive = _AriaPolicyEngine.#LIVE_REGION_ROLES.get(effectiveRole);
1825
- if (!impliedLive) return NO_VIOLATIONS;
1826
- if ("aria-live" in props) return NO_VIOLATIONS;
1845
+ if (!effectiveRole) return NO_VIOLATIONS2;
1846
+ const impliedLive = LIVE_REGION_ROLES.get(effectiveRole);
1847
+ if (!impliedLive) return NO_VIOLATIONS2;
1848
+ if ("aria-live" in props) return NO_VIOLATIONS2;
1827
1849
  const injectLive = {
1828
1850
  kind: `injectLive:${effectiveRole}`,
1829
1851
  apply: (ctx) => ({
@@ -1842,20 +1864,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1842
1864
  }
1843
1865
  ];
1844
1866
  }
1845
- static #checkMissingAtomic({ effectiveRole, props }) {
1846
- if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole))
1847
- return NO_VIOLATIONS;
1848
- if ("aria-atomic" in props) return NO_VIOLATIONS;
1849
- return [
1850
- {
1851
- valid: false,
1852
- fixable: false,
1853
- severity: "warning",
1854
- diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
1855
- }
1856
- ];
1867
+ static #missingAtomicRule = {
1868
+ attributesByRole: ATOMIC_REQUIREMENTS,
1869
+ diagnosticFor: (_attribute, role) => AriaDiagnostics.missingAtomic(role)
1870
+ };
1871
+ static #checkMissingAtomic(context) {
1872
+ return checkRequiredAttributes(_AriaPolicyEngine.#missingAtomicRule, context);
1857
1873
  }
1858
- static #VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set(["additions", "removals", "text", "all"]);
1859
1874
  // Custom fix rules passed via `options.rules` must be pure functions of (tag, props) — the cache
1860
1875
  // replays stored fixes against new prop objects, so fixes that close over external state will
1861
1876
  // produce inconsistent results on cache hits.
@@ -1869,10 +1884,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1869
1884
  };
1870
1885
  static #checkInvalidAriaRelevant({ props }) {
1871
1886
  const relevant = props["aria-relevant"];
1872
- if (relevant === void 0) return NO_VIOLATIONS;
1873
- if (typeof relevant !== "string") return NO_VIOLATIONS;
1887
+ if (relevant === void 0) return NO_VIOLATIONS2;
1888
+ if (typeof relevant !== "string") return NO_VIOLATIONS2;
1874
1889
  const tokens = relevant.trim().split(/\s+/);
1875
- const invalid = tokens.filter((t) => !_AriaPolicyEngine.#VALID_RELEVANT_TOKENS.has(t));
1890
+ const invalid = tokens.filter((t) => !VALID_RELEVANT_TOKENS.has(t));
1876
1891
  if (invalid.length > 0) {
1877
1892
  return [
1878
1893
  {
@@ -1897,7 +1912,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1897
1912
  }
1898
1913
  ];
1899
1914
  }
1900
- return NO_VIOLATIONS;
1915
+ return NO_VIOLATIONS2;
1901
1916
  }
1902
1917
  };
1903
1918
 
@@ -2217,7 +2232,59 @@ var readonlyProps = ({
2217
2232
  // ../core/src/html/evaluators.ts
2218
2233
  import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2219
2234
 
2220
- // ../core/src/html/input-rules.ts
2235
+ // ../core/src/html/spec/vocabulary/input.ts
2236
+ var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2237
+ var NUMERIC_INPUT_TYPES = [
2238
+ "number",
2239
+ "range",
2240
+ "date",
2241
+ "month",
2242
+ "week",
2243
+ "time",
2244
+ "datetime-local"
2245
+ ];
2246
+ var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
2247
+ ...TEXT_INPUT_TYPES,
2248
+ ...NUMERIC_INPUT_TYPES,
2249
+ "checkbox",
2250
+ "radio",
2251
+ "file",
2252
+ "color",
2253
+ "hidden",
2254
+ "button",
2255
+ "submit",
2256
+ "reset",
2257
+ "image"
2258
+ ]);
2259
+
2260
+ // ../core/src/html/spec/attributes/input.ts
2261
+ var INPUT_ATTRIBUTE_TYPE_POLICIES = [
2262
+ { attribute: "checked", allowedTypes: ["checkbox", "radio"] },
2263
+ { attribute: "multiple", allowedTypes: ["email", "file"] },
2264
+ { attribute: "maxLength", allowedTypes: TEXT_INPUT_TYPES },
2265
+ { attribute: "minLength", allowedTypes: TEXT_INPUT_TYPES },
2266
+ { attribute: "pattern", allowedTypes: TEXT_INPUT_TYPES },
2267
+ { attribute: "min", allowedTypes: NUMERIC_INPUT_TYPES },
2268
+ { attribute: "max", allowedTypes: NUMERIC_INPUT_TYPES },
2269
+ { attribute: "step", allowedTypes: NUMERIC_INPUT_TYPES },
2270
+ { attribute: "accept", allowedTypes: ["file"] },
2271
+ { attribute: "capture", allowedTypes: ["file"] },
2272
+ { attribute: "size", allowedTypes: TEXT_INPUT_TYPES },
2273
+ { attribute: "alt", allowedTypes: ["image"] },
2274
+ { attribute: "height", allowedTypes: ["image"] },
2275
+ { attribute: "width", allowedTypes: ["image"] }
2276
+ ];
2277
+
2278
+ // ../core/src/html/spec/constraints/input.ts
2279
+ var REQUIRED_READONLY_CONFLICT = {
2280
+ props: ["required", "readOnly"],
2281
+ diagnostic: () => InputAccessibilityDiagnostics.requiredReadOnlyConflict()
2282
+ };
2283
+ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2284
+ REQUIRED_READONLY_CONFLICT
2285
+ ];
2286
+
2287
+ // ../core/src/html/spec/validators/attribute-type-validator.ts
2221
2288
  var DEFAULT_INPUT_TYPE = "text";
2222
2289
  function omit(props, key) {
2223
2290
  const next = { ...props };
@@ -2233,7 +2300,10 @@ function removeAttributeFix(attribute) {
2233
2300
  }
2234
2301
  };
2235
2302
  }
2236
- function inputAttributeRequiresType(attribute, allowedTypes) {
2303
+ function createInputAttributeTypeRule({
2304
+ attribute,
2305
+ allowedTypes
2306
+ }) {
2237
2307
  const rule = ({ tag, props }) => {
2238
2308
  if (tag !== "input" || !(attribute in props)) return [];
2239
2309
  const type = typeof props.type === "string" ? props.type : DEFAULT_INPUT_TYPE;
@@ -2249,31 +2319,30 @@ function inputAttributeRequiresType(attribute, allowedTypes) {
2249
2319
  }
2250
2320
  ];
2251
2321
  };
2252
- return Object.assign(rule, { readsProps: ["type", attribute] });
2322
+ return Object.assign(rule, { readsProps: ["type", attribute], tags: ["input"] });
2323
+ }
2324
+
2325
+ // ../core/src/html/spec/validators/mutually-exclusive-validator.ts
2326
+ function createMutuallyExclusiveRule({
2327
+ props: conflictingProps,
2328
+ diagnostic: createDiagnostic
2329
+ }) {
2330
+ const [first, second] = conflictingProps;
2331
+ const rule = ({ tag, props }) => {
2332
+ if (tag !== "input" || !props[first] || !props[second]) return [];
2333
+ const diagnostic = createDiagnostic();
2334
+ return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2335
+ };
2336
+ return Object.assign(rule, { readsProps: conflictingProps, tags: ["input"] });
2337
+ }
2338
+
2339
+ // ../core/src/html/input-rules.ts
2340
+ var policyByAttribute = Object.fromEntries(
2341
+ INPUT_ATTRIBUTE_TYPE_POLICIES.map((policy) => [policy.attribute, policy])
2342
+ );
2343
+ function policyFor(attribute) {
2344
+ return policyByAttribute[attribute];
2253
2345
  }
2254
- var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2255
- var NUMERIC_INPUT_TYPES = [
2256
- "number",
2257
- "range",
2258
- "date",
2259
- "month",
2260
- "week",
2261
- "time",
2262
- "datetime-local"
2263
- ];
2264
- var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
2265
- ...TEXT_INPUT_TYPES,
2266
- ...NUMERIC_INPUT_TYPES,
2267
- "checkbox",
2268
- "radio",
2269
- "file",
2270
- "color",
2271
- "hidden",
2272
- "button",
2273
- "submit",
2274
- "reset",
2275
- "image"
2276
- ]);
2277
2346
  var supportedInputTypeRule = Object.assign(
2278
2347
  ({ tag, props }) => {
2279
2348
  if (tag !== "input" || typeof props.type !== "string") return [];
@@ -2289,30 +2358,22 @@ var supportedInputTypeRule = Object.assign(
2289
2358
  }
2290
2359
  ];
2291
2360
  },
2292
- { readsProps: ["type"] }
2361
+ { readsProps: ["type"], tags: ["input"] }
2293
2362
  );
2294
- var checkedRequiresCheckableTypeRule = inputAttributeRequiresType("checked", [
2295
- "checkbox",
2296
- "radio"
2297
- ]);
2298
- var multipleRequiresSupportedTypeRule = inputAttributeRequiresType("multiple", [
2299
- "email",
2300
- "file"
2301
- ]);
2302
- var maxLengthRequiresTextTypeRule = inputAttributeRequiresType(
2303
- "maxLength",
2304
- TEXT_INPUT_TYPES
2305
- );
2306
- var minLengthRequiresTextTypeRule = inputAttributeRequiresType(
2307
- "minLength",
2308
- TEXT_INPUT_TYPES
2309
- );
2310
- var patternRequiresTextTypeRule = inputAttributeRequiresType("pattern", TEXT_INPUT_TYPES);
2311
- var minRequiresNumericTypeRule = inputAttributeRequiresType("min", NUMERIC_INPUT_TYPES);
2312
- var maxRequiresNumericTypeRule = inputAttributeRequiresType("max", NUMERIC_INPUT_TYPES);
2313
- var stepRequiresNumericTypeRule = inputAttributeRequiresType("step", NUMERIC_INPUT_TYPES);
2314
- var acceptRequiresFileTypeRule = inputAttributeRequiresType("accept", ["file"]);
2315
- var captureRequiresFileTypeRule = inputAttributeRequiresType("capture", ["file"]);
2363
+ var checkedRequiresCheckableTypeRule = createInputAttributeTypeRule(policyFor("checked"));
2364
+ var multipleRequiresSupportedTypeRule = createInputAttributeTypeRule(policyFor("multiple"));
2365
+ var maxLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("maxLength"));
2366
+ var minLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("minLength"));
2367
+ var patternRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("pattern"));
2368
+ var minRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("min"));
2369
+ var maxRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("max"));
2370
+ var stepRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("step"));
2371
+ var acceptRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("accept"));
2372
+ var captureRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("capture"));
2373
+ var sizeRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("size"));
2374
+ var altRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("alt"));
2375
+ var heightRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("height"));
2376
+ var widthRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("width"));
2316
2377
  var inputAccessibleNameRule = Object.assign(
2317
2378
  ({ tag, props }) => {
2318
2379
  if (tag !== "input" || props.type === "hidden") return [];
@@ -2321,7 +2382,10 @@ var inputAccessibleNameRule = Object.assign(
2321
2382
  const diagnostic = hasPlaceholder ? InputAccessibilityDiagnostics.placeholderIsNotLabel() : InputAccessibilityDiagnostics.missingAccessibleName();
2322
2383
  return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2323
2384
  },
2324
- { readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"] }
2385
+ {
2386
+ readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"],
2387
+ tags: ["input"]
2388
+ }
2325
2389
  );
2326
2390
  var PASSWORD_AUTOCOMPLETE_VALUES = ["current-password", "new-password"];
2327
2391
  var passwordAutocompleteRule = Object.assign(
@@ -2333,16 +2397,9 @@ var passwordAutocompleteRule = Object.assign(
2333
2397
  const diagnostic = InputAccessibilityDiagnostics.passwordMissingAutocomplete();
2334
2398
  return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2335
2399
  },
2336
- { readsProps: ["type", "autoComplete"] }
2337
- );
2338
- var requiredReadOnlyConflictRule = Object.assign(
2339
- ({ tag, props }) => {
2340
- if (tag !== "input" || !props.required || !props.readOnly) return [];
2341
- const diagnostic = InputAccessibilityDiagnostics.requiredReadOnlyConflict();
2342
- return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2343
- },
2344
- { readsProps: ["required", "readOnly"] }
2400
+ { readsProps: ["type", "autoComplete"], tags: ["input"] }
2345
2401
  );
2402
+ var requiredReadOnlyConflictRule = createMutuallyExclusiveRule(REQUIRED_READONLY_CONFLICT);
2346
2403
  var INPUT_RULES = [
2347
2404
  supportedInputTypeRule,
2348
2405
  checkedRequiresCheckableTypeRule,
@@ -2355,11 +2412,132 @@ var INPUT_RULES = [
2355
2412
  stepRequiresNumericTypeRule,
2356
2413
  acceptRequiresFileTypeRule,
2357
2414
  captureRequiresFileTypeRule,
2415
+ sizeRequiresTextTypeRule,
2416
+ altRequiresImageTypeRule,
2417
+ heightRequiresImageTypeRule,
2418
+ widthRequiresImageTypeRule,
2358
2419
  inputAccessibleNameRule,
2359
2420
  passwordAutocompleteRule,
2360
2421
  requiredReadOnlyConflictRule
2361
2422
  ];
2362
2423
 
2424
+ // ../core/src/html/spec/types.ts
2425
+ function definePropRolePolicy(prop, map2, fallback) {
2426
+ return { kind: "byProp", prop, map: map2, fallback };
2427
+ }
2428
+ function resolveAllowedRoles(spec, props) {
2429
+ const policy = spec.allowedRoles;
2430
+ if (!policy) return void 0;
2431
+ switch (policy.kind) {
2432
+ case "fixed":
2433
+ return policy.roles;
2434
+ case "byProp": {
2435
+ const value = typeof props[policy.prop] === "string" ? props[policy.prop] : policy.fallback;
2436
+ return policy.map[value];
2437
+ }
2438
+ case "dynamic":
2439
+ return policy.resolve({ props });
2440
+ }
2441
+ }
2442
+
2443
+ // ../core/src/html/spec/roles/input.ts
2444
+ var ALLOWED_INPUT_ROLES = {
2445
+ checkbox: ["menuitemcheckbox", "option", "switch", "button"],
2446
+ radio: ["menuitemradio"],
2447
+ range: [],
2448
+ number: [],
2449
+ search: ["combobox"],
2450
+ text: ["combobox", "searchbox", "spinbutton"],
2451
+ email: ["combobox"],
2452
+ tel: ["combobox"],
2453
+ url: ["combobox"],
2454
+ button: [
2455
+ "link",
2456
+ "menuitem",
2457
+ "menuitemcheckbox",
2458
+ "menuitemradio",
2459
+ "option",
2460
+ "radio",
2461
+ "switch",
2462
+ "tab"
2463
+ ],
2464
+ submit: [
2465
+ "link",
2466
+ "menuitem",
2467
+ "menuitemcheckbox",
2468
+ "menuitemradio",
2469
+ "option",
2470
+ "radio",
2471
+ "switch",
2472
+ "tab"
2473
+ ],
2474
+ reset: [
2475
+ "link",
2476
+ "menuitem",
2477
+ "menuitemcheckbox",
2478
+ "menuitemradio",
2479
+ "option",
2480
+ "radio",
2481
+ "switch",
2482
+ "tab"
2483
+ ],
2484
+ image: [
2485
+ "link",
2486
+ "menuitem",
2487
+ "menuitemcheckbox",
2488
+ "menuitemradio",
2489
+ "option",
2490
+ "radio",
2491
+ "switch",
2492
+ "tab"
2493
+ ],
2494
+ hidden: []
2495
+ };
2496
+
2497
+ // ../core/src/html/spec/elements/input.ts
2498
+ var inputElementSpec = {
2499
+ tag: "input",
2500
+ allowedRoles: definePropRolePolicy("type", ALLOWED_INPUT_ROLES, "text"),
2501
+ attributes: INPUT_ATTRIBUTE_TYPE_POLICIES,
2502
+ mutuallyExclusive: INPUT_MUTUALLY_EXCLUSIVE_POLICIES
2503
+ };
2504
+
2505
+ // ../core/src/html/spec/roles/img.ts
2506
+ var IMG_NAMED_ROLES = [
2507
+ "button",
2508
+ "checkbox",
2509
+ "link",
2510
+ "menuitem",
2511
+ "menuitemcheckbox",
2512
+ "menuitemradio",
2513
+ "option",
2514
+ "progressbar",
2515
+ "scrollbar",
2516
+ "separator",
2517
+ "slider",
2518
+ "switch",
2519
+ "tab",
2520
+ "treeitem"
2521
+ ];
2522
+
2523
+ // ../core/src/html/spec/elements/img.ts
2524
+ var imgElementSpec = {
2525
+ tag: "img",
2526
+ allowedRoles: {
2527
+ kind: "dynamic",
2528
+ resolve: ({ props }) => props.alt === "" ? [] : IMG_NAMED_ROLES
2529
+ }
2530
+ };
2531
+
2532
+ // ../core/src/html/spec/roles/table.ts
2533
+ var ALLOWED_TABLE_ROLES = ["grid", "treegrid"];
2534
+
2535
+ // ../core/src/html/spec/elements/table.ts
2536
+ var tableElementSpec = {
2537
+ tag: "table",
2538
+ allowedRoles: { kind: "fixed", roles: ALLOWED_TABLE_ROLES }
2539
+ };
2540
+
2363
2541
  // ../core/src/html/role-restrictions.ts
2364
2542
  var ALLOWED_ROLES = {
2365
2543
  article: ["application", "document", "feed", "main", "none", "presentation", "region"],
@@ -2432,86 +2610,17 @@ var ALLOWED_ROLES = {
2432
2610
  "tab",
2433
2611
  "treeitem"
2434
2612
  ],
2435
- table: ["grid", "treegrid"],
2436
2613
  dialog: ["alertdialog"],
2437
2614
  fieldset: ["none", "presentation", "radiogroup"]
2438
2615
  };
2439
- var IMG_NAMED_ROLES = [
2440
- "button",
2441
- "checkbox",
2442
- "link",
2443
- "menuitem",
2444
- "menuitemcheckbox",
2445
- "menuitemradio",
2446
- "option",
2447
- "progressbar",
2448
- "scrollbar",
2449
- "separator",
2450
- "slider",
2451
- "switch",
2452
- "tab",
2453
- "treeitem"
2454
- ];
2455
- var ALLOWED_INPUT_ROLES = {
2456
- checkbox: ["menuitemcheckbox", "option", "switch", "button"],
2457
- radio: ["menuitemradio"],
2458
- range: [],
2459
- number: [],
2460
- search: ["combobox"],
2461
- text: ["combobox", "searchbox", "spinbutton"],
2462
- email: ["combobox"],
2463
- tel: ["combobox"],
2464
- url: ["combobox"],
2465
- button: [
2466
- "link",
2467
- "menuitem",
2468
- "menuitemcheckbox",
2469
- "menuitemradio",
2470
- "option",
2471
- "radio",
2472
- "switch",
2473
- "tab"
2474
- ],
2475
- submit: [
2476
- "link",
2477
- "menuitem",
2478
- "menuitemcheckbox",
2479
- "menuitemradio",
2480
- "option",
2481
- "radio",
2482
- "switch",
2483
- "tab"
2484
- ],
2485
- reset: [
2486
- "link",
2487
- "menuitem",
2488
- "menuitemcheckbox",
2489
- "menuitemradio",
2490
- "option",
2491
- "radio",
2492
- "switch",
2493
- "tab"
2494
- ],
2495
- image: [
2496
- "link",
2497
- "menuitem",
2498
- "menuitemcheckbox",
2499
- "menuitemradio",
2500
- "option",
2501
- "radio",
2502
- "switch",
2503
- "tab"
2504
- ],
2505
- hidden: []
2616
+ var ELEMENT_SPECS = {
2617
+ input: inputElementSpec,
2618
+ img: imgElementSpec,
2619
+ table: tableElementSpec
2506
2620
  };
2507
2621
  function getAllowedRoles(tag, props) {
2508
- if (tag === "input") {
2509
- const type = typeof props.type === "string" ? props.type : "text";
2510
- return ALLOWED_INPUT_ROLES[type];
2511
- }
2512
- if (tag === "img") {
2513
- return props.alt === "" ? [] : IMG_NAMED_ROLES;
2514
- }
2622
+ const spec = ELEMENT_SPECS[tag];
2623
+ if (spec) return resolveAllowedRoles(spec, props);
2515
2624
  return ALLOWED_ROLES[tag];
2516
2625
  }
2517
2626
  var removeRoleFix = {
@@ -2552,21 +2661,24 @@ var removeLandmarkRoleOverride = {
2552
2661
  return { applied: true, next: rest, previous: props };
2553
2662
  }
2554
2663
  };
2555
- function landmarkRoleRule({ tag, props, implicitRole }) {
2556
- if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
2557
- const role = props.role;
2558
- if (!role || role === implicitRole) return [];
2559
- const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
2560
- return [
2561
- {
2562
- valid: false,
2563
- fixable: true,
2564
- severity: diagnostic.severity,
2565
- fix: removeLandmarkRoleOverride,
2566
- diagnostic
2567
- }
2568
- ];
2569
- }
2664
+ var landmarkRoleRule = Object.assign(
2665
+ ({ tag, props, implicitRole }) => {
2666
+ if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
2667
+ const role = props.role;
2668
+ if (!role || role === implicitRole) return [];
2669
+ const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
2670
+ return [
2671
+ {
2672
+ valid: false,
2673
+ fixable: true,
2674
+ severity: diagnostic.severity,
2675
+ fix: removeLandmarkRoleOverride,
2676
+ diagnostic
2677
+ }
2678
+ ];
2679
+ },
2680
+ { tags: [...LANDMARK_TAG_SET] }
2681
+ );
2570
2682
  function requireAccessibleName({ tag, props }) {
2571
2683
  if ("aria-label" in props || "aria-labelledby" in props) return [];
2572
2684
  return [
@@ -2579,10 +2691,13 @@ function requireAccessibleName({ tag, props }) {
2579
2691
  ];
2580
2692
  }
2581
2693
  var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
2582
- function landmarkNameAdvisory(ctx) {
2583
- if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2584
- return requireAccessibleName(ctx);
2585
- }
2694
+ var landmarkNameAdvisory = Object.assign(
2695
+ (ctx) => {
2696
+ if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2697
+ return requireAccessibleName(ctx);
2698
+ },
2699
+ { tags: [...NAMED_LANDMARK_TAGS] }
2700
+ );
2586
2701
  var HTML_ARIA_RULES = [
2587
2702
  landmarkRoleRule,
2588
2703
  landmarkNameAdvisory,
@@ -2683,6 +2798,62 @@ var figureContract = contract([
2683
2798
  ]);
2684
2799
  var detailsContract = firstChildContract("summary", "summary");
2685
2800
  var fieldsetContract = firstChildContract("legend", "legend");
2801
+ var objectContract = contract([
2802
+ { name: "param", match: isTag("param") },
2803
+ { name: "content", match: isOpenContent("param") }
2804
+ ]);
2805
+ var INTERACTIVE_CONTENT_TAGS = ["a", "button", "input", "select", "textarea", "label"];
2806
+ var buttonContract = closedContract([
2807
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2808
+ ]);
2809
+ var anchorContract = closedContract([
2810
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2811
+ ]);
2812
+ var LABELABLE_TAGS = [
2813
+ "button",
2814
+ "input",
2815
+ "meter",
2816
+ "output",
2817
+ "progress",
2818
+ "select",
2819
+ "textarea"
2820
+ ];
2821
+ var labelContract = contract([
2822
+ { name: "control", match: isTag(...LABELABLE_TAGS), cardinality: { max: 1 } }
2823
+ ]);
2824
+ var P_BLOCKED_TAGS = [
2825
+ "address",
2826
+ "article",
2827
+ "aside",
2828
+ "blockquote",
2829
+ "details",
2830
+ "dialog",
2831
+ "div",
2832
+ "dl",
2833
+ "fieldset",
2834
+ "figure",
2835
+ "footer",
2836
+ "form",
2837
+ "h1",
2838
+ "h2",
2839
+ "h3",
2840
+ "h4",
2841
+ "h5",
2842
+ "h6",
2843
+ "header",
2844
+ "hr",
2845
+ "main",
2846
+ "nav",
2847
+ "ol",
2848
+ "p",
2849
+ "pre",
2850
+ "section",
2851
+ "table",
2852
+ "ul"
2853
+ ];
2854
+ var pContract = closedContract([
2855
+ { name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
2856
+ ]);
2686
2857
  var mediaContract = contract([
2687
2858
  { name: "source", match: isTag("source") },
2688
2859
  { name: "track", match: isTag("track") },
@@ -2737,6 +2908,11 @@ var htmlContracts = {
2737
2908
  details: detailsContract,
2738
2909
  fieldset: fieldsetContract,
2739
2910
  dialog: dialogContract,
2911
+ object: objectContract,
2912
+ button: buttonContract,
2913
+ a: anchorContract,
2914
+ label: labelContract,
2915
+ p: pContract,
2740
2916
  head: headContract,
2741
2917
  html: htmlContract
2742
2918
  };