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/vue/index.js
CHANGED
|
@@ -975,7 +975,11 @@ var ATTRIBUTE_IGNORED_CODES = {
|
|
|
975
975
|
max: DiagnosticCode3.HtmlInputMaxIgnoredForType,
|
|
976
976
|
step: DiagnosticCode3.HtmlInputStepIgnoredForType,
|
|
977
977
|
accept: DiagnosticCode3.HtmlInputAcceptIgnoredForType,
|
|
978
|
-
capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType
|
|
978
|
+
capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType,
|
|
979
|
+
size: DiagnosticCode3.HtmlInputSizeIgnoredForType,
|
|
980
|
+
alt: DiagnosticCode3.HtmlInputAltIgnoredForType,
|
|
981
|
+
height: DiagnosticCode3.HtmlInputHeightIgnoredForType,
|
|
982
|
+
width: DiagnosticCode3.HtmlInputWidthIgnoredForType
|
|
979
983
|
};
|
|
980
984
|
var HtmlDiagnostics = {
|
|
981
985
|
emptyRole(tag) {
|
|
@@ -1209,8 +1213,132 @@ var InvariantBase = class {
|
|
|
1209
1213
|
}
|
|
1210
1214
|
};
|
|
1211
1215
|
|
|
1212
|
-
// ../../lib/contract/src/aria/
|
|
1216
|
+
// ../../lib/contract/src/aria/spec/roles/required-properties.ts
|
|
1217
|
+
var REQUIRED_ARIA_PROPERTIES = {
|
|
1218
|
+
combobox: ["aria-expanded"],
|
|
1219
|
+
option: ["aria-selected"],
|
|
1220
|
+
slider: ["aria-valuenow"],
|
|
1221
|
+
scrollbar: ["aria-controls", "aria-valuenow"],
|
|
1222
|
+
spinbutton: ["aria-valuenow"]
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
// ../../lib/contract/src/aria/spec/roles/name-required.ts
|
|
1226
|
+
var NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1227
|
+
|
|
1228
|
+
// ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
|
|
1213
1229
|
var NO_VIOLATIONS = [{ valid: true }];
|
|
1230
|
+
function requiredAttributeByRole(roles, attribute) {
|
|
1231
|
+
return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
|
|
1232
|
+
}
|
|
1233
|
+
function checkRequiredAttributes(requirement, { props, effectiveRole }) {
|
|
1234
|
+
if (!effectiveRole) return NO_VIOLATIONS;
|
|
1235
|
+
const requiredAttributes = requirement.attributesByRole[effectiveRole];
|
|
1236
|
+
if (!requiredAttributes) return NO_VIOLATIONS;
|
|
1237
|
+
const results = [];
|
|
1238
|
+
for (const attribute of requiredAttributes) {
|
|
1239
|
+
if (attribute in props) continue;
|
|
1240
|
+
results.push({
|
|
1241
|
+
valid: false,
|
|
1242
|
+
fixable: false,
|
|
1243
|
+
severity: "warning",
|
|
1244
|
+
attribute,
|
|
1245
|
+
diagnostic: requirement.diagnosticFor(attribute, effectiveRole)
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
return results;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// ../../lib/contract/src/aria/spec/roles/live-region.ts
|
|
1252
|
+
var LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
|
|
1253
|
+
["alert", "assertive"],
|
|
1254
|
+
["status", "polite"],
|
|
1255
|
+
["log", "polite"],
|
|
1256
|
+
["timer", "off"]
|
|
1257
|
+
]);
|
|
1258
|
+
var ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
|
|
1259
|
+
|
|
1260
|
+
// ../../lib/contract/src/aria/spec/attributes/aria-value-types.ts
|
|
1261
|
+
var ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
1262
|
+
// Boolean (true | false)
|
|
1263
|
+
["aria-atomic", { kind: "boolean" }],
|
|
1264
|
+
["aria-busy", { kind: "boolean" }],
|
|
1265
|
+
["aria-disabled", { kind: "boolean" }],
|
|
1266
|
+
["aria-expanded", { kind: "boolean" }],
|
|
1267
|
+
["aria-hidden", { kind: "boolean" }],
|
|
1268
|
+
["aria-modal", { kind: "boolean" }],
|
|
1269
|
+
["aria-multiline", { kind: "boolean" }],
|
|
1270
|
+
["aria-multiselectable", { kind: "boolean" }],
|
|
1271
|
+
["aria-readonly", { kind: "boolean" }],
|
|
1272
|
+
["aria-required", { kind: "boolean" }],
|
|
1273
|
+
["aria-selected", { kind: "boolean" }],
|
|
1274
|
+
// Tristate (true | false | mixed)
|
|
1275
|
+
["aria-checked", { kind: "tristate" }],
|
|
1276
|
+
["aria-pressed", { kind: "tristate" }],
|
|
1277
|
+
// Numeric (any finite number)
|
|
1278
|
+
["aria-valuenow", { kind: "number" }],
|
|
1279
|
+
["aria-valuemin", { kind: "number" }],
|
|
1280
|
+
["aria-valuemax", { kind: "number" }],
|
|
1281
|
+
// Integer with optional range
|
|
1282
|
+
["aria-level", { kind: "integer", min: 1, max: 6 }],
|
|
1283
|
+
["aria-posinset", { kind: "integer", min: 1 }],
|
|
1284
|
+
["aria-setsize", { kind: "integer", min: -1 }],
|
|
1285
|
+
["aria-rowcount", { kind: "integer", min: -1 }],
|
|
1286
|
+
["aria-colcount", { kind: "integer", min: -1 }],
|
|
1287
|
+
["aria-rowindex", { kind: "integer", min: 1 }],
|
|
1288
|
+
["aria-colindex", { kind: "integer", min: 1 }],
|
|
1289
|
+
["aria-rowspan", { kind: "integer", min: 0 }],
|
|
1290
|
+
["aria-colspan", { kind: "integer", min: 0 }],
|
|
1291
|
+
// Enum (specific allowed tokens)
|
|
1292
|
+
["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
|
|
1293
|
+
[
|
|
1294
|
+
"aria-current",
|
|
1295
|
+
{
|
|
1296
|
+
kind: "enum",
|
|
1297
|
+
values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
|
|
1298
|
+
}
|
|
1299
|
+
],
|
|
1300
|
+
[
|
|
1301
|
+
"aria-haspopup",
|
|
1302
|
+
{
|
|
1303
|
+
kind: "enum",
|
|
1304
|
+
values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
|
|
1305
|
+
}
|
|
1306
|
+
],
|
|
1307
|
+
["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
|
|
1308
|
+
["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
|
|
1309
|
+
["aria-orientation", { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }],
|
|
1310
|
+
["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
|
|
1311
|
+
]);
|
|
1312
|
+
|
|
1313
|
+
// ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
|
|
1314
|
+
var VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
|
|
1315
|
+
"additions",
|
|
1316
|
+
"removals",
|
|
1317
|
+
"text",
|
|
1318
|
+
"all"
|
|
1319
|
+
]);
|
|
1320
|
+
|
|
1321
|
+
// ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
|
|
1322
|
+
var HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1323
|
+
["h1", 1],
|
|
1324
|
+
["h2", 2],
|
|
1325
|
+
["h3", 3],
|
|
1326
|
+
["h4", 4],
|
|
1327
|
+
["h5", 5],
|
|
1328
|
+
["h6", 6]
|
|
1329
|
+
]);
|
|
1330
|
+
|
|
1331
|
+
// ../../lib/contract/src/aria/spec/elements/interactive-tags.ts
|
|
1332
|
+
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
1333
|
+
"a",
|
|
1334
|
+
"button",
|
|
1335
|
+
"input",
|
|
1336
|
+
"select",
|
|
1337
|
+
"textarea"
|
|
1338
|
+
]);
|
|
1339
|
+
|
|
1340
|
+
// ../../lib/contract/src/aria/polymorphic-validator.ts
|
|
1341
|
+
var NO_VIOLATIONS2 = [{ valid: true }];
|
|
1214
1342
|
function isIntrinsicTag(tag) {
|
|
1215
1343
|
return isString(tag);
|
|
1216
1344
|
}
|
|
@@ -1272,6 +1400,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1272
1400
|
const violations = [];
|
|
1273
1401
|
const fixes = [];
|
|
1274
1402
|
iterate.forEach(rules, (rule) => {
|
|
1403
|
+
if (isNonNull(rule.tags) && !rule.tags.includes(context.tag)) return;
|
|
1275
1404
|
iterate.forEach(rule(context), (result) => {
|
|
1276
1405
|
if (result.valid) return;
|
|
1277
1406
|
const {
|
|
@@ -1297,7 +1426,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1297
1426
|
return { violations, fixes };
|
|
1298
1427
|
}
|
|
1299
1428
|
static #getRules(context) {
|
|
1300
|
-
if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) &&
|
|
1429
|
+
if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && LIVE_REGION_ROLES.has(context.effectiveRole)) {
|
|
1301
1430
|
return _AriaPolicyEngine.#pipeline;
|
|
1302
1431
|
}
|
|
1303
1432
|
return _AriaPolicyEngine.#implicitOnlyRules;
|
|
@@ -1499,7 +1628,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1499
1628
|
implicitRole
|
|
1500
1629
|
}) {
|
|
1501
1630
|
const role = props.role;
|
|
1502
|
-
if (!implicitRole || !role || role === implicitRole) return
|
|
1631
|
+
if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS2;
|
|
1503
1632
|
if (isStrongImplicitRole(tag) && role === "region") {
|
|
1504
1633
|
const diagnostic = HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role);
|
|
1505
1634
|
return [
|
|
@@ -1512,11 +1641,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1512
1641
|
}
|
|
1513
1642
|
];
|
|
1514
1643
|
}
|
|
1515
|
-
return
|
|
1644
|
+
return NO_VIOLATIONS2;
|
|
1516
1645
|
}
|
|
1517
1646
|
static #checkRedundantRole({ tag, props, implicitRole }) {
|
|
1518
1647
|
const role = props.role;
|
|
1519
|
-
if (!implicitRole || !role || role !== implicitRole) return
|
|
1648
|
+
if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS2;
|
|
1520
1649
|
const diagnostic = HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole);
|
|
1521
1650
|
return [
|
|
1522
1651
|
{
|
|
@@ -1530,8 +1659,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1530
1659
|
}
|
|
1531
1660
|
static #checkStandaloneRegion({ tag, props, implicitRole }) {
|
|
1532
1661
|
const role = props.role;
|
|
1533
|
-
if (role !== "region") return
|
|
1534
|
-
if (!isStandaloneTag(tag)) return
|
|
1662
|
+
if (role !== "region") return NO_VIOLATIONS2;
|
|
1663
|
+
if (!isStandaloneTag(tag)) return NO_VIOLATIONS2;
|
|
1535
1664
|
const diagnostic = HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag);
|
|
1536
1665
|
return [
|
|
1537
1666
|
{
|
|
@@ -1548,7 +1677,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1548
1677
|
props,
|
|
1549
1678
|
effectiveRole
|
|
1550
1679
|
}) {
|
|
1551
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1680
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1552
1681
|
const results = [];
|
|
1553
1682
|
iterate.forEachEntry(props, (key) => {
|
|
1554
1683
|
if (!key.startsWith("aria-")) return;
|
|
@@ -1566,62 +1695,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1566
1695
|
return results;
|
|
1567
1696
|
}
|
|
1568
1697
|
// ─── ARIA attribute value validation ──────────────────────────────────────
|
|
1569
|
-
// Accepted value shapes for typed ARIA attributes.
|
|
1570
|
-
// Attributes not in this map are unconstrained (arbitrary string values permitted).
|
|
1571
|
-
static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
1572
|
-
// Boolean (true | false)
|
|
1573
|
-
["aria-atomic", { kind: "boolean" }],
|
|
1574
|
-
["aria-busy", { kind: "boolean" }],
|
|
1575
|
-
["aria-disabled", { kind: "boolean" }],
|
|
1576
|
-
["aria-expanded", { kind: "boolean" }],
|
|
1577
|
-
["aria-hidden", { kind: "boolean" }],
|
|
1578
|
-
["aria-modal", { kind: "boolean" }],
|
|
1579
|
-
["aria-multiline", { kind: "boolean" }],
|
|
1580
|
-
["aria-multiselectable", { kind: "boolean" }],
|
|
1581
|
-
["aria-readonly", { kind: "boolean" }],
|
|
1582
|
-
["aria-required", { kind: "boolean" }],
|
|
1583
|
-
["aria-selected", { kind: "boolean" }],
|
|
1584
|
-
// Tristate (true | false | mixed)
|
|
1585
|
-
["aria-checked", { kind: "tristate" }],
|
|
1586
|
-
["aria-pressed", { kind: "tristate" }],
|
|
1587
|
-
// Numeric (any finite number)
|
|
1588
|
-
["aria-valuenow", { kind: "number" }],
|
|
1589
|
-
["aria-valuemin", { kind: "number" }],
|
|
1590
|
-
["aria-valuemax", { kind: "number" }],
|
|
1591
|
-
// Integer with optional range
|
|
1592
|
-
["aria-level", { kind: "integer", min: 1, max: 6 }],
|
|
1593
|
-
["aria-posinset", { kind: "integer", min: 1 }],
|
|
1594
|
-
["aria-setsize", { kind: "integer", min: -1 }],
|
|
1595
|
-
["aria-rowcount", { kind: "integer", min: -1 }],
|
|
1596
|
-
["aria-colcount", { kind: "integer", min: -1 }],
|
|
1597
|
-
["aria-rowindex", { kind: "integer", min: 1 }],
|
|
1598
|
-
["aria-colindex", { kind: "integer", min: 1 }],
|
|
1599
|
-
["aria-rowspan", { kind: "integer", min: 0 }],
|
|
1600
|
-
["aria-colspan", { kind: "integer", min: 0 }],
|
|
1601
|
-
// Enum (specific allowed tokens)
|
|
1602
|
-
["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
|
|
1603
|
-
[
|
|
1604
|
-
"aria-current",
|
|
1605
|
-
{
|
|
1606
|
-
kind: "enum",
|
|
1607
|
-
values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
|
|
1608
|
-
}
|
|
1609
|
-
],
|
|
1610
|
-
[
|
|
1611
|
-
"aria-haspopup",
|
|
1612
|
-
{
|
|
1613
|
-
kind: "enum",
|
|
1614
|
-
values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
|
|
1615
|
-
}
|
|
1616
|
-
],
|
|
1617
|
-
["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
|
|
1618
|
-
["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
|
|
1619
|
-
[
|
|
1620
|
-
"aria-orientation",
|
|
1621
|
-
{ kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
|
|
1622
|
-
],
|
|
1623
|
-
["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
|
|
1624
|
-
]);
|
|
1625
1698
|
static #isValidAriaValue(value, type) {
|
|
1626
1699
|
switch (type.kind) {
|
|
1627
1700
|
case "boolean":
|
|
@@ -1666,11 +1739,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1666
1739
|
}
|
|
1667
1740
|
}
|
|
1668
1741
|
static #checkAriaAttributeValues({ props, effectiveRole }) {
|
|
1669
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1742
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1670
1743
|
const results = [];
|
|
1671
1744
|
iterate.forEachEntry(props, (key, value) => {
|
|
1672
1745
|
if (!key.startsWith("aria-")) return;
|
|
1673
|
-
const type =
|
|
1746
|
+
const type = ARIA_VALUE_TYPES.get(key);
|
|
1674
1747
|
if (!isNonNull(type)) return;
|
|
1675
1748
|
if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
|
|
1676
1749
|
results.push({
|
|
@@ -1689,26 +1762,18 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1689
1762
|
return results;
|
|
1690
1763
|
}
|
|
1691
1764
|
// ─── Heading implicit level ────────────────────────────────────────────────
|
|
1692
|
-
static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1693
|
-
["h1", 1],
|
|
1694
|
-
["h2", 2],
|
|
1695
|
-
["h3", 3],
|
|
1696
|
-
["h4", 4],
|
|
1697
|
-
["h5", 5],
|
|
1698
|
-
["h6", 6]
|
|
1699
|
-
]);
|
|
1700
1765
|
static #checkRedundantAriaLevel({
|
|
1701
1766
|
tag,
|
|
1702
1767
|
props,
|
|
1703
1768
|
effectiveRole
|
|
1704
1769
|
}) {
|
|
1705
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1706
|
-
const implicitLevel =
|
|
1707
|
-
if (!isNonNull(implicitLevel)) return
|
|
1770
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1771
|
+
const implicitLevel = HEADING_IMPLICIT_LEVELS.get(tag);
|
|
1772
|
+
if (!isNonNull(implicitLevel)) return NO_VIOLATIONS2;
|
|
1708
1773
|
const raw = props["aria-level"];
|
|
1709
|
-
if (!isNonNull(raw)) return
|
|
1774
|
+
if (!isNonNull(raw)) return NO_VIOLATIONS2;
|
|
1710
1775
|
const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
|
|
1711
|
-
if (!Number.isFinite(n) || n !== implicitLevel) return
|
|
1776
|
+
if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS2;
|
|
1712
1777
|
return [
|
|
1713
1778
|
{
|
|
1714
1779
|
valid: false,
|
|
@@ -1721,20 +1786,14 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1721
1786
|
];
|
|
1722
1787
|
}
|
|
1723
1788
|
// ─── Name-required roles ───────────────────────────────────────────────────
|
|
1724
|
-
// Roles that always require an accessible name per WAI-ARIA APG.
|
|
1725
|
-
// Dialog and landmark names are enforced via contracts (ariaContract) rather than
|
|
1726
|
-
// the built-in pipeline so consumers can opt in; img is built in because role=img
|
|
1727
|
-
// on any element (including bare <img>) is definitionally useless without a name.
|
|
1728
|
-
static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1729
1789
|
static #checkNameRequiredRoles({
|
|
1730
1790
|
tag,
|
|
1731
1791
|
props,
|
|
1732
1792
|
effectiveRole
|
|
1733
1793
|
}) {
|
|
1734
|
-
if (!effectiveRole || !
|
|
1735
|
-
|
|
1736
|
-
if ("
|
|
1737
|
-
if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
|
|
1794
|
+
if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return NO_VIOLATIONS2;
|
|
1795
|
+
if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS2;
|
|
1796
|
+
if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS2;
|
|
1738
1797
|
return [
|
|
1739
1798
|
{
|
|
1740
1799
|
valid: false,
|
|
@@ -1744,51 +1803,21 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1744
1803
|
}
|
|
1745
1804
|
];
|
|
1746
1805
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
["scrollbar", ["aria-controls", "aria-valuenow"]],
|
|
1754
|
-
["spinbutton", ["aria-valuenow"]]
|
|
1755
|
-
]);
|
|
1756
|
-
static #checkRequiredAriaProperties({
|
|
1757
|
-
props,
|
|
1758
|
-
effectiveRole
|
|
1759
|
-
}) {
|
|
1760
|
-
if (!effectiveRole) return NO_VIOLATIONS;
|
|
1761
|
-
const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
|
|
1762
|
-
if (!isNonNull(required)) return NO_VIOLATIONS;
|
|
1763
|
-
const results = [];
|
|
1764
|
-
iterate.forEach(required, (attr) => {
|
|
1765
|
-
if (attr in props) return;
|
|
1766
|
-
results.push({
|
|
1767
|
-
valid: false,
|
|
1768
|
-
fixable: false,
|
|
1769
|
-
severity: "warning",
|
|
1770
|
-
attribute: attr,
|
|
1771
|
-
diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
|
|
1772
|
-
});
|
|
1773
|
-
});
|
|
1774
|
-
return results;
|
|
1806
|
+
static #requiredAriaPropertiesRule = {
|
|
1807
|
+
attributesByRole: REQUIRED_ARIA_PROPERTIES,
|
|
1808
|
+
diagnosticFor: (attribute, role) => AriaDiagnostics.requiredProperty(attribute, role)
|
|
1809
|
+
};
|
|
1810
|
+
static #checkRequiredAriaProperties(context) {
|
|
1811
|
+
return checkRequiredAttributes(_AriaPolicyEngine.#requiredAriaPropertiesRule, context);
|
|
1775
1812
|
}
|
|
1776
|
-
// Natively interactive HTML elements — always keyboard-reachable unless explicitly disabled.
|
|
1777
|
-
static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
1778
|
-
"a",
|
|
1779
|
-
"button",
|
|
1780
|
-
"input",
|
|
1781
|
-
"select",
|
|
1782
|
-
"textarea"
|
|
1783
|
-
]);
|
|
1784
1813
|
// WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
|
|
1785
1814
|
static #checkAriaHiddenOnFocusable({ tag, props }) {
|
|
1786
|
-
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return
|
|
1787
|
-
const isInteractive =
|
|
1815
|
+
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS2;
|
|
1816
|
+
const isInteractive = INTERACTIVE_TAGS.has(tag);
|
|
1788
1817
|
if (!isInteractive) {
|
|
1789
1818
|
const tabindex = props.tabindex;
|
|
1790
1819
|
const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
|
|
1791
|
-
if (!Number.isFinite(n) || n < 0) return
|
|
1820
|
+
if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS2;
|
|
1792
1821
|
}
|
|
1793
1822
|
return [
|
|
1794
1823
|
{
|
|
@@ -1807,7 +1836,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1807
1836
|
props,
|
|
1808
1837
|
effectiveRole
|
|
1809
1838
|
}) {
|
|
1810
|
-
if (effectiveRole !== "none" && effectiveRole !== "presentation") return
|
|
1839
|
+
if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS2;
|
|
1811
1840
|
const results = [];
|
|
1812
1841
|
iterate.forEachEntry(props, (key) => {
|
|
1813
1842
|
if (!key.startsWith("aria-")) return;
|
|
@@ -1823,18 +1852,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1823
1852
|
});
|
|
1824
1853
|
return results;
|
|
1825
1854
|
}
|
|
1826
|
-
// WAI-ARIA live region roles and their implied aria-live politeness values.
|
|
1827
|
-
static #LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
|
|
1828
|
-
["alert", "assertive"],
|
|
1829
|
-
["status", "polite"],
|
|
1830
|
-
["log", "polite"],
|
|
1831
|
-
["timer", "off"]
|
|
1832
|
-
]);
|
|
1833
1855
|
static #checkMissingLiveRegion({ effectiveRole, props }) {
|
|
1834
|
-
if (!effectiveRole) return
|
|
1835
|
-
const impliedLive =
|
|
1836
|
-
if (!impliedLive) return
|
|
1837
|
-
if ("aria-live" in props) return
|
|
1856
|
+
if (!effectiveRole) return NO_VIOLATIONS2;
|
|
1857
|
+
const impliedLive = LIVE_REGION_ROLES.get(effectiveRole);
|
|
1858
|
+
if (!impliedLive) return NO_VIOLATIONS2;
|
|
1859
|
+
if ("aria-live" in props) return NO_VIOLATIONS2;
|
|
1838
1860
|
const injectLive = {
|
|
1839
1861
|
kind: `injectLive:${effectiveRole}`,
|
|
1840
1862
|
apply: (ctx) => ({
|
|
@@ -1853,20 +1875,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1853
1875
|
}
|
|
1854
1876
|
];
|
|
1855
1877
|
}
|
|
1856
|
-
static #
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
valid: false,
|
|
1863
|
-
fixable: false,
|
|
1864
|
-
severity: "warning",
|
|
1865
|
-
diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
|
|
1866
|
-
}
|
|
1867
|
-
];
|
|
1878
|
+
static #missingAtomicRule = {
|
|
1879
|
+
attributesByRole: ATOMIC_REQUIREMENTS,
|
|
1880
|
+
diagnosticFor: (_attribute, role) => AriaDiagnostics.missingAtomic(role)
|
|
1881
|
+
};
|
|
1882
|
+
static #checkMissingAtomic(context) {
|
|
1883
|
+
return checkRequiredAttributes(_AriaPolicyEngine.#missingAtomicRule, context);
|
|
1868
1884
|
}
|
|
1869
|
-
static #VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set(["additions", "removals", "text", "all"]);
|
|
1870
1885
|
// Custom fix rules passed via `options.rules` must be pure functions of (tag, props) — the cache
|
|
1871
1886
|
// replays stored fixes against new prop objects, so fixes that close over external state will
|
|
1872
1887
|
// produce inconsistent results on cache hits.
|
|
@@ -1880,10 +1895,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1880
1895
|
};
|
|
1881
1896
|
static #checkInvalidAriaRelevant({ props }) {
|
|
1882
1897
|
const relevant = props["aria-relevant"];
|
|
1883
|
-
if (relevant === void 0) return
|
|
1884
|
-
if (typeof relevant !== "string") return
|
|
1898
|
+
if (relevant === void 0) return NO_VIOLATIONS2;
|
|
1899
|
+
if (typeof relevant !== "string") return NO_VIOLATIONS2;
|
|
1885
1900
|
const tokens = relevant.trim().split(/\s+/);
|
|
1886
|
-
const invalid = tokens.filter((t) => !
|
|
1901
|
+
const invalid = tokens.filter((t) => !VALID_RELEVANT_TOKENS.has(t));
|
|
1887
1902
|
if (invalid.length > 0) {
|
|
1888
1903
|
return [
|
|
1889
1904
|
{
|
|
@@ -1908,7 +1923,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1908
1923
|
}
|
|
1909
1924
|
];
|
|
1910
1925
|
}
|
|
1911
|
-
return
|
|
1926
|
+
return NO_VIOLATIONS2;
|
|
1912
1927
|
}
|
|
1913
1928
|
};
|
|
1914
1929
|
|
|
@@ -2228,7 +2243,59 @@ var readonlyProps = ({
|
|
|
2228
2243
|
// ../core/src/html/evaluators.ts
|
|
2229
2244
|
import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
|
|
2230
2245
|
|
|
2231
|
-
// ../core/src/html/input
|
|
2246
|
+
// ../core/src/html/spec/vocabulary/input.ts
|
|
2247
|
+
var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
|
|
2248
|
+
var NUMERIC_INPUT_TYPES = [
|
|
2249
|
+
"number",
|
|
2250
|
+
"range",
|
|
2251
|
+
"date",
|
|
2252
|
+
"month",
|
|
2253
|
+
"week",
|
|
2254
|
+
"time",
|
|
2255
|
+
"datetime-local"
|
|
2256
|
+
];
|
|
2257
|
+
var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
2258
|
+
...TEXT_INPUT_TYPES,
|
|
2259
|
+
...NUMERIC_INPUT_TYPES,
|
|
2260
|
+
"checkbox",
|
|
2261
|
+
"radio",
|
|
2262
|
+
"file",
|
|
2263
|
+
"color",
|
|
2264
|
+
"hidden",
|
|
2265
|
+
"button",
|
|
2266
|
+
"submit",
|
|
2267
|
+
"reset",
|
|
2268
|
+
"image"
|
|
2269
|
+
]);
|
|
2270
|
+
|
|
2271
|
+
// ../core/src/html/spec/attributes/input.ts
|
|
2272
|
+
var INPUT_ATTRIBUTE_TYPE_POLICIES = [
|
|
2273
|
+
{ attribute: "checked", allowedTypes: ["checkbox", "radio"] },
|
|
2274
|
+
{ attribute: "multiple", allowedTypes: ["email", "file"] },
|
|
2275
|
+
{ attribute: "maxLength", allowedTypes: TEXT_INPUT_TYPES },
|
|
2276
|
+
{ attribute: "minLength", allowedTypes: TEXT_INPUT_TYPES },
|
|
2277
|
+
{ attribute: "pattern", allowedTypes: TEXT_INPUT_TYPES },
|
|
2278
|
+
{ attribute: "min", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2279
|
+
{ attribute: "max", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2280
|
+
{ attribute: "step", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2281
|
+
{ attribute: "accept", allowedTypes: ["file"] },
|
|
2282
|
+
{ attribute: "capture", allowedTypes: ["file"] },
|
|
2283
|
+
{ attribute: "size", allowedTypes: TEXT_INPUT_TYPES },
|
|
2284
|
+
{ attribute: "alt", allowedTypes: ["image"] },
|
|
2285
|
+
{ attribute: "height", allowedTypes: ["image"] },
|
|
2286
|
+
{ attribute: "width", allowedTypes: ["image"] }
|
|
2287
|
+
];
|
|
2288
|
+
|
|
2289
|
+
// ../core/src/html/spec/constraints/input.ts
|
|
2290
|
+
var REQUIRED_READONLY_CONFLICT = {
|
|
2291
|
+
props: ["required", "readOnly"],
|
|
2292
|
+
diagnostic: () => InputAccessibilityDiagnostics.requiredReadOnlyConflict()
|
|
2293
|
+
};
|
|
2294
|
+
var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
|
|
2295
|
+
REQUIRED_READONLY_CONFLICT
|
|
2296
|
+
];
|
|
2297
|
+
|
|
2298
|
+
// ../core/src/html/spec/validators/attribute-type-validator.ts
|
|
2232
2299
|
var DEFAULT_INPUT_TYPE = "text";
|
|
2233
2300
|
function omit(props, key) {
|
|
2234
2301
|
const next = { ...props };
|
|
@@ -2244,7 +2311,10 @@ function removeAttributeFix(attribute) {
|
|
|
2244
2311
|
}
|
|
2245
2312
|
};
|
|
2246
2313
|
}
|
|
2247
|
-
function
|
|
2314
|
+
function createInputAttributeTypeRule({
|
|
2315
|
+
attribute,
|
|
2316
|
+
allowedTypes
|
|
2317
|
+
}) {
|
|
2248
2318
|
const rule = ({ tag, props }) => {
|
|
2249
2319
|
if (tag !== "input" || !(attribute in props)) return [];
|
|
2250
2320
|
const type = typeof props.type === "string" ? props.type : DEFAULT_INPUT_TYPE;
|
|
@@ -2260,31 +2330,30 @@ function inputAttributeRequiresType(attribute, allowedTypes) {
|
|
|
2260
2330
|
}
|
|
2261
2331
|
];
|
|
2262
2332
|
};
|
|
2263
|
-
return Object.assign(rule, { readsProps: ["type", attribute] });
|
|
2333
|
+
return Object.assign(rule, { readsProps: ["type", attribute], tags: ["input"] });
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
// ../core/src/html/spec/validators/mutually-exclusive-validator.ts
|
|
2337
|
+
function createMutuallyExclusiveRule({
|
|
2338
|
+
props: conflictingProps,
|
|
2339
|
+
diagnostic: createDiagnostic
|
|
2340
|
+
}) {
|
|
2341
|
+
const [first, second] = conflictingProps;
|
|
2342
|
+
const rule = ({ tag, props }) => {
|
|
2343
|
+
if (tag !== "input" || !props[first] || !props[second]) return [];
|
|
2344
|
+
const diagnostic = createDiagnostic();
|
|
2345
|
+
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2346
|
+
};
|
|
2347
|
+
return Object.assign(rule, { readsProps: conflictingProps, tags: ["input"] });
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
// ../core/src/html/input-rules.ts
|
|
2351
|
+
var policyByAttribute = Object.fromEntries(
|
|
2352
|
+
INPUT_ATTRIBUTE_TYPE_POLICIES.map((policy) => [policy.attribute, policy])
|
|
2353
|
+
);
|
|
2354
|
+
function policyFor(attribute) {
|
|
2355
|
+
return policyByAttribute[attribute];
|
|
2264
2356
|
}
|
|
2265
|
-
var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
|
|
2266
|
-
var NUMERIC_INPUT_TYPES = [
|
|
2267
|
-
"number",
|
|
2268
|
-
"range",
|
|
2269
|
-
"date",
|
|
2270
|
-
"month",
|
|
2271
|
-
"week",
|
|
2272
|
-
"time",
|
|
2273
|
-
"datetime-local"
|
|
2274
|
-
];
|
|
2275
|
-
var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
2276
|
-
...TEXT_INPUT_TYPES,
|
|
2277
|
-
...NUMERIC_INPUT_TYPES,
|
|
2278
|
-
"checkbox",
|
|
2279
|
-
"radio",
|
|
2280
|
-
"file",
|
|
2281
|
-
"color",
|
|
2282
|
-
"hidden",
|
|
2283
|
-
"button",
|
|
2284
|
-
"submit",
|
|
2285
|
-
"reset",
|
|
2286
|
-
"image"
|
|
2287
|
-
]);
|
|
2288
2357
|
var supportedInputTypeRule = Object.assign(
|
|
2289
2358
|
({ tag, props }) => {
|
|
2290
2359
|
if (tag !== "input" || typeof props.type !== "string") return [];
|
|
@@ -2300,30 +2369,22 @@ var supportedInputTypeRule = Object.assign(
|
|
|
2300
2369
|
}
|
|
2301
2370
|
];
|
|
2302
2371
|
},
|
|
2303
|
-
{ readsProps: ["type"] }
|
|
2372
|
+
{ readsProps: ["type"], tags: ["input"] }
|
|
2304
2373
|
);
|
|
2305
|
-
var checkedRequiresCheckableTypeRule =
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
var
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
var
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
);
|
|
2317
|
-
var
|
|
2318
|
-
|
|
2319
|
-
TEXT_INPUT_TYPES
|
|
2320
|
-
);
|
|
2321
|
-
var patternRequiresTextTypeRule = inputAttributeRequiresType("pattern", TEXT_INPUT_TYPES);
|
|
2322
|
-
var minRequiresNumericTypeRule = inputAttributeRequiresType("min", NUMERIC_INPUT_TYPES);
|
|
2323
|
-
var maxRequiresNumericTypeRule = inputAttributeRequiresType("max", NUMERIC_INPUT_TYPES);
|
|
2324
|
-
var stepRequiresNumericTypeRule = inputAttributeRequiresType("step", NUMERIC_INPUT_TYPES);
|
|
2325
|
-
var acceptRequiresFileTypeRule = inputAttributeRequiresType("accept", ["file"]);
|
|
2326
|
-
var captureRequiresFileTypeRule = inputAttributeRequiresType("capture", ["file"]);
|
|
2374
|
+
var checkedRequiresCheckableTypeRule = createInputAttributeTypeRule(policyFor("checked"));
|
|
2375
|
+
var multipleRequiresSupportedTypeRule = createInputAttributeTypeRule(policyFor("multiple"));
|
|
2376
|
+
var maxLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("maxLength"));
|
|
2377
|
+
var minLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("minLength"));
|
|
2378
|
+
var patternRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("pattern"));
|
|
2379
|
+
var minRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("min"));
|
|
2380
|
+
var maxRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("max"));
|
|
2381
|
+
var stepRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("step"));
|
|
2382
|
+
var acceptRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("accept"));
|
|
2383
|
+
var captureRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("capture"));
|
|
2384
|
+
var sizeRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("size"));
|
|
2385
|
+
var altRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("alt"));
|
|
2386
|
+
var heightRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("height"));
|
|
2387
|
+
var widthRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("width"));
|
|
2327
2388
|
var inputAccessibleNameRule = Object.assign(
|
|
2328
2389
|
({ tag, props }) => {
|
|
2329
2390
|
if (tag !== "input" || props.type === "hidden") return [];
|
|
@@ -2332,7 +2393,10 @@ var inputAccessibleNameRule = Object.assign(
|
|
|
2332
2393
|
const diagnostic = hasPlaceholder ? InputAccessibilityDiagnostics.placeholderIsNotLabel() : InputAccessibilityDiagnostics.missingAccessibleName();
|
|
2333
2394
|
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2334
2395
|
},
|
|
2335
|
-
{
|
|
2396
|
+
{
|
|
2397
|
+
readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"],
|
|
2398
|
+
tags: ["input"]
|
|
2399
|
+
}
|
|
2336
2400
|
);
|
|
2337
2401
|
var PASSWORD_AUTOCOMPLETE_VALUES = ["current-password", "new-password"];
|
|
2338
2402
|
var passwordAutocompleteRule = Object.assign(
|
|
@@ -2344,16 +2408,9 @@ var passwordAutocompleteRule = Object.assign(
|
|
|
2344
2408
|
const diagnostic = InputAccessibilityDiagnostics.passwordMissingAutocomplete();
|
|
2345
2409
|
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2346
2410
|
},
|
|
2347
|
-
{ readsProps: ["type", "autoComplete"] }
|
|
2348
|
-
);
|
|
2349
|
-
var requiredReadOnlyConflictRule = Object.assign(
|
|
2350
|
-
({ tag, props }) => {
|
|
2351
|
-
if (tag !== "input" || !props.required || !props.readOnly) return [];
|
|
2352
|
-
const diagnostic = InputAccessibilityDiagnostics.requiredReadOnlyConflict();
|
|
2353
|
-
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2354
|
-
},
|
|
2355
|
-
{ readsProps: ["required", "readOnly"] }
|
|
2411
|
+
{ readsProps: ["type", "autoComplete"], tags: ["input"] }
|
|
2356
2412
|
);
|
|
2413
|
+
var requiredReadOnlyConflictRule = createMutuallyExclusiveRule(REQUIRED_READONLY_CONFLICT);
|
|
2357
2414
|
var INPUT_RULES = [
|
|
2358
2415
|
supportedInputTypeRule,
|
|
2359
2416
|
checkedRequiresCheckableTypeRule,
|
|
@@ -2366,11 +2423,132 @@ var INPUT_RULES = [
|
|
|
2366
2423
|
stepRequiresNumericTypeRule,
|
|
2367
2424
|
acceptRequiresFileTypeRule,
|
|
2368
2425
|
captureRequiresFileTypeRule,
|
|
2426
|
+
sizeRequiresTextTypeRule,
|
|
2427
|
+
altRequiresImageTypeRule,
|
|
2428
|
+
heightRequiresImageTypeRule,
|
|
2429
|
+
widthRequiresImageTypeRule,
|
|
2369
2430
|
inputAccessibleNameRule,
|
|
2370
2431
|
passwordAutocompleteRule,
|
|
2371
2432
|
requiredReadOnlyConflictRule
|
|
2372
2433
|
];
|
|
2373
2434
|
|
|
2435
|
+
// ../core/src/html/spec/types.ts
|
|
2436
|
+
function definePropRolePolicy(prop, map2, fallback) {
|
|
2437
|
+
return { kind: "byProp", prop, map: map2, fallback };
|
|
2438
|
+
}
|
|
2439
|
+
function resolveAllowedRoles(spec, props) {
|
|
2440
|
+
const policy = spec.allowedRoles;
|
|
2441
|
+
if (!policy) return void 0;
|
|
2442
|
+
switch (policy.kind) {
|
|
2443
|
+
case "fixed":
|
|
2444
|
+
return policy.roles;
|
|
2445
|
+
case "byProp": {
|
|
2446
|
+
const value = typeof props[policy.prop] === "string" ? props[policy.prop] : policy.fallback;
|
|
2447
|
+
return policy.map[value];
|
|
2448
|
+
}
|
|
2449
|
+
case "dynamic":
|
|
2450
|
+
return policy.resolve({ props });
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
// ../core/src/html/spec/roles/input.ts
|
|
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: []
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2508
|
+
// ../core/src/html/spec/elements/input.ts
|
|
2509
|
+
var inputElementSpec = {
|
|
2510
|
+
tag: "input",
|
|
2511
|
+
allowedRoles: definePropRolePolicy("type", ALLOWED_INPUT_ROLES, "text"),
|
|
2512
|
+
attributes: INPUT_ATTRIBUTE_TYPE_POLICIES,
|
|
2513
|
+
mutuallyExclusive: INPUT_MUTUALLY_EXCLUSIVE_POLICIES
|
|
2514
|
+
};
|
|
2515
|
+
|
|
2516
|
+
// ../core/src/html/spec/roles/img.ts
|
|
2517
|
+
var IMG_NAMED_ROLES = [
|
|
2518
|
+
"button",
|
|
2519
|
+
"checkbox",
|
|
2520
|
+
"link",
|
|
2521
|
+
"menuitem",
|
|
2522
|
+
"menuitemcheckbox",
|
|
2523
|
+
"menuitemradio",
|
|
2524
|
+
"option",
|
|
2525
|
+
"progressbar",
|
|
2526
|
+
"scrollbar",
|
|
2527
|
+
"separator",
|
|
2528
|
+
"slider",
|
|
2529
|
+
"switch",
|
|
2530
|
+
"tab",
|
|
2531
|
+
"treeitem"
|
|
2532
|
+
];
|
|
2533
|
+
|
|
2534
|
+
// ../core/src/html/spec/elements/img.ts
|
|
2535
|
+
var imgElementSpec = {
|
|
2536
|
+
tag: "img",
|
|
2537
|
+
allowedRoles: {
|
|
2538
|
+
kind: "dynamic",
|
|
2539
|
+
resolve: ({ props }) => props.alt === "" ? [] : IMG_NAMED_ROLES
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
|
|
2543
|
+
// ../core/src/html/spec/roles/table.ts
|
|
2544
|
+
var ALLOWED_TABLE_ROLES = ["grid", "treegrid"];
|
|
2545
|
+
|
|
2546
|
+
// ../core/src/html/spec/elements/table.ts
|
|
2547
|
+
var tableElementSpec = {
|
|
2548
|
+
tag: "table",
|
|
2549
|
+
allowedRoles: { kind: "fixed", roles: ALLOWED_TABLE_ROLES }
|
|
2550
|
+
};
|
|
2551
|
+
|
|
2374
2552
|
// ../core/src/html/role-restrictions.ts
|
|
2375
2553
|
var ALLOWED_ROLES = {
|
|
2376
2554
|
article: ["application", "document", "feed", "main", "none", "presentation", "region"],
|
|
@@ -2443,86 +2621,17 @@ var ALLOWED_ROLES = {
|
|
|
2443
2621
|
"tab",
|
|
2444
2622
|
"treeitem"
|
|
2445
2623
|
],
|
|
2446
|
-
table: ["grid", "treegrid"],
|
|
2447
2624
|
dialog: ["alertdialog"],
|
|
2448
2625
|
fieldset: ["none", "presentation", "radiogroup"]
|
|
2449
2626
|
};
|
|
2450
|
-
var
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
"menuitem",
|
|
2455
|
-
"menuitemcheckbox",
|
|
2456
|
-
"menuitemradio",
|
|
2457
|
-
"option",
|
|
2458
|
-
"progressbar",
|
|
2459
|
-
"scrollbar",
|
|
2460
|
-
"separator",
|
|
2461
|
-
"slider",
|
|
2462
|
-
"switch",
|
|
2463
|
-
"tab",
|
|
2464
|
-
"treeitem"
|
|
2465
|
-
];
|
|
2466
|
-
var ALLOWED_INPUT_ROLES = {
|
|
2467
|
-
checkbox: ["menuitemcheckbox", "option", "switch", "button"],
|
|
2468
|
-
radio: ["menuitemradio"],
|
|
2469
|
-
range: [],
|
|
2470
|
-
number: [],
|
|
2471
|
-
search: ["combobox"],
|
|
2472
|
-
text: ["combobox", "searchbox", "spinbutton"],
|
|
2473
|
-
email: ["combobox"],
|
|
2474
|
-
tel: ["combobox"],
|
|
2475
|
-
url: ["combobox"],
|
|
2476
|
-
button: [
|
|
2477
|
-
"link",
|
|
2478
|
-
"menuitem",
|
|
2479
|
-
"menuitemcheckbox",
|
|
2480
|
-
"menuitemradio",
|
|
2481
|
-
"option",
|
|
2482
|
-
"radio",
|
|
2483
|
-
"switch",
|
|
2484
|
-
"tab"
|
|
2485
|
-
],
|
|
2486
|
-
submit: [
|
|
2487
|
-
"link",
|
|
2488
|
-
"menuitem",
|
|
2489
|
-
"menuitemcheckbox",
|
|
2490
|
-
"menuitemradio",
|
|
2491
|
-
"option",
|
|
2492
|
-
"radio",
|
|
2493
|
-
"switch",
|
|
2494
|
-
"tab"
|
|
2495
|
-
],
|
|
2496
|
-
reset: [
|
|
2497
|
-
"link",
|
|
2498
|
-
"menuitem",
|
|
2499
|
-
"menuitemcheckbox",
|
|
2500
|
-
"menuitemradio",
|
|
2501
|
-
"option",
|
|
2502
|
-
"radio",
|
|
2503
|
-
"switch",
|
|
2504
|
-
"tab"
|
|
2505
|
-
],
|
|
2506
|
-
image: [
|
|
2507
|
-
"link",
|
|
2508
|
-
"menuitem",
|
|
2509
|
-
"menuitemcheckbox",
|
|
2510
|
-
"menuitemradio",
|
|
2511
|
-
"option",
|
|
2512
|
-
"radio",
|
|
2513
|
-
"switch",
|
|
2514
|
-
"tab"
|
|
2515
|
-
],
|
|
2516
|
-
hidden: []
|
|
2627
|
+
var ELEMENT_SPECS = {
|
|
2628
|
+
input: inputElementSpec,
|
|
2629
|
+
img: imgElementSpec,
|
|
2630
|
+
table: tableElementSpec
|
|
2517
2631
|
};
|
|
2518
2632
|
function getAllowedRoles(tag, props) {
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
return ALLOWED_INPUT_ROLES[type];
|
|
2522
|
-
}
|
|
2523
|
-
if (tag === "img") {
|
|
2524
|
-
return props.alt === "" ? [] : IMG_NAMED_ROLES;
|
|
2525
|
-
}
|
|
2633
|
+
const spec = ELEMENT_SPECS[tag];
|
|
2634
|
+
if (spec) return resolveAllowedRoles(spec, props);
|
|
2526
2635
|
return ALLOWED_ROLES[tag];
|
|
2527
2636
|
}
|
|
2528
2637
|
var removeRoleFix = {
|
|
@@ -2563,21 +2672,24 @@ var removeLandmarkRoleOverride = {
|
|
|
2563
2672
|
return { applied: true, next: rest, previous: props };
|
|
2564
2673
|
}
|
|
2565
2674
|
};
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2675
|
+
var landmarkRoleRule = Object.assign(
|
|
2676
|
+
({ tag, props, implicitRole }) => {
|
|
2677
|
+
if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
|
|
2678
|
+
const role = props.role;
|
|
2679
|
+
if (!role || role === implicitRole) return [];
|
|
2680
|
+
const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
|
|
2681
|
+
return [
|
|
2682
|
+
{
|
|
2683
|
+
valid: false,
|
|
2684
|
+
fixable: true,
|
|
2685
|
+
severity: diagnostic.severity,
|
|
2686
|
+
fix: removeLandmarkRoleOverride,
|
|
2687
|
+
diagnostic
|
|
2688
|
+
}
|
|
2689
|
+
];
|
|
2690
|
+
},
|
|
2691
|
+
{ tags: [...LANDMARK_TAG_SET] }
|
|
2692
|
+
);
|
|
2581
2693
|
function requireAccessibleName({ tag, props }) {
|
|
2582
2694
|
if ("aria-label" in props || "aria-labelledby" in props) return [];
|
|
2583
2695
|
return [
|
|
@@ -2590,10 +2702,13 @@ function requireAccessibleName({ tag, props }) {
|
|
|
2590
2702
|
];
|
|
2591
2703
|
}
|
|
2592
2704
|
var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2705
|
+
var landmarkNameAdvisory = Object.assign(
|
|
2706
|
+
(ctx) => {
|
|
2707
|
+
if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
|
|
2708
|
+
return requireAccessibleName(ctx);
|
|
2709
|
+
},
|
|
2710
|
+
{ tags: [...NAMED_LANDMARK_TAGS] }
|
|
2711
|
+
);
|
|
2597
2712
|
var HTML_ARIA_RULES = [
|
|
2598
2713
|
landmarkRoleRule,
|
|
2599
2714
|
landmarkNameAdvisory,
|
|
@@ -2694,6 +2809,62 @@ var figureContract = contract([
|
|
|
2694
2809
|
]);
|
|
2695
2810
|
var detailsContract = firstChildContract("summary", "summary");
|
|
2696
2811
|
var fieldsetContract = firstChildContract("legend", "legend");
|
|
2812
|
+
var objectContract = contract([
|
|
2813
|
+
{ name: "param", match: isTag("param") },
|
|
2814
|
+
{ name: "content", match: isOpenContent("param") }
|
|
2815
|
+
]);
|
|
2816
|
+
var INTERACTIVE_CONTENT_TAGS = ["a", "button", "input", "select", "textarea", "label"];
|
|
2817
|
+
var buttonContract = closedContract([
|
|
2818
|
+
{ name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
|
|
2819
|
+
]);
|
|
2820
|
+
var anchorContract = closedContract([
|
|
2821
|
+
{ name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
|
|
2822
|
+
]);
|
|
2823
|
+
var LABELABLE_TAGS = [
|
|
2824
|
+
"button",
|
|
2825
|
+
"input",
|
|
2826
|
+
"meter",
|
|
2827
|
+
"output",
|
|
2828
|
+
"progress",
|
|
2829
|
+
"select",
|
|
2830
|
+
"textarea"
|
|
2831
|
+
];
|
|
2832
|
+
var labelContract = contract([
|
|
2833
|
+
{ name: "control", match: isTag(...LABELABLE_TAGS), cardinality: { max: 1 } }
|
|
2834
|
+
]);
|
|
2835
|
+
var P_BLOCKED_TAGS = [
|
|
2836
|
+
"address",
|
|
2837
|
+
"article",
|
|
2838
|
+
"aside",
|
|
2839
|
+
"blockquote",
|
|
2840
|
+
"details",
|
|
2841
|
+
"dialog",
|
|
2842
|
+
"div",
|
|
2843
|
+
"dl",
|
|
2844
|
+
"fieldset",
|
|
2845
|
+
"figure",
|
|
2846
|
+
"footer",
|
|
2847
|
+
"form",
|
|
2848
|
+
"h1",
|
|
2849
|
+
"h2",
|
|
2850
|
+
"h3",
|
|
2851
|
+
"h4",
|
|
2852
|
+
"h5",
|
|
2853
|
+
"h6",
|
|
2854
|
+
"header",
|
|
2855
|
+
"hr",
|
|
2856
|
+
"main",
|
|
2857
|
+
"nav",
|
|
2858
|
+
"ol",
|
|
2859
|
+
"p",
|
|
2860
|
+
"pre",
|
|
2861
|
+
"section",
|
|
2862
|
+
"table",
|
|
2863
|
+
"ul"
|
|
2864
|
+
];
|
|
2865
|
+
var pContract = closedContract([
|
|
2866
|
+
{ name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
|
|
2867
|
+
]);
|
|
2697
2868
|
var mediaContract = contract([
|
|
2698
2869
|
{ name: "source", match: isTag("source") },
|
|
2699
2870
|
{ name: "track", match: isTag("track") },
|
|
@@ -2748,6 +2919,11 @@ var htmlContracts = {
|
|
|
2748
2919
|
details: detailsContract,
|
|
2749
2920
|
fieldset: fieldsetContract,
|
|
2750
2921
|
dialog: dialogContract,
|
|
2922
|
+
object: objectContract,
|
|
2923
|
+
button: buttonContract,
|
|
2924
|
+
a: anchorContract,
|
|
2925
|
+
label: labelContract,
|
|
2926
|
+
p: pContract,
|
|
2751
2927
|
head: headContract,
|
|
2752
2928
|
html: htmlContract
|
|
2753
2929
|
};
|