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.
- package/dist/_shared/diagnostics.d.ts +4 -0
- package/dist/_shared/diagnostics.js +4 -0
- package/dist/{chunk-H3D2JA3J.js → chunk-AM5J6PY3.js} +486 -310
- package/dist/contract/index.d.ts +1 -0
- package/dist/lit/index.d.ts +1 -0
- package/dist/lit/index.js +486 -310
- package/dist/preact/index.d.ts +1 -0
- package/dist/preact/index.js +486 -310
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/react/legacy.d.ts +2 -2
- package/dist/react/legacy.js +1 -1
- package/dist/{react-options-DQTX4YS_.d.ts → react-options-DoFNqNdY.d.ts} +1 -0
- package/dist/solid/index.d.ts +1 -0
- package/dist/solid/index.js +486 -310
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +486 -310
- package/dist/vite-plugin/index.d.ts +4 -0
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.js +486 -310
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +486 -310
- package/package.json +5 -5
package/dist/solid/index.js
CHANGED
|
@@ -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/
|
|
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) &&
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1523
|
-
if (!isStandaloneTag(tag)) return
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
1695
|
-
const implicitLevel =
|
|
1696
|
-
if (!isNonNull(implicitLevel)) return
|
|
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
|
|
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
|
|
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 || !
|
|
1724
|
-
|
|
1725
|
-
if ("
|
|
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
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
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
|
|
1776
|
-
const isInteractive =
|
|
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
|
|
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
|
|
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
|
|
1824
|
-
const impliedLive =
|
|
1825
|
-
if (!impliedLive) return
|
|
1826
|
-
if ("aria-live" in props) return
|
|
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 #
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
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
|
|
1873
|
-
if (typeof relevant !== "string") return
|
|
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) => !
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
var
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
var
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
);
|
|
2306
|
-
var
|
|
2307
|
-
|
|
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
|
-
{
|
|
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
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
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
|
-
|
|
2509
|
-
|
|
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
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
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
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
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
|
};
|