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/svelte/index.js
CHANGED
|
@@ -868,7 +868,11 @@ var ATTRIBUTE_IGNORED_CODES = {
|
|
|
868
868
|
max: DiagnosticCode3.HtmlInputMaxIgnoredForType,
|
|
869
869
|
step: DiagnosticCode3.HtmlInputStepIgnoredForType,
|
|
870
870
|
accept: DiagnosticCode3.HtmlInputAcceptIgnoredForType,
|
|
871
|
-
capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType
|
|
871
|
+
capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType,
|
|
872
|
+
size: DiagnosticCode3.HtmlInputSizeIgnoredForType,
|
|
873
|
+
alt: DiagnosticCode3.HtmlInputAltIgnoredForType,
|
|
874
|
+
height: DiagnosticCode3.HtmlInputHeightIgnoredForType,
|
|
875
|
+
width: DiagnosticCode3.HtmlInputWidthIgnoredForType
|
|
872
876
|
};
|
|
873
877
|
var HtmlDiagnostics = {
|
|
874
878
|
emptyRole(tag) {
|
|
@@ -1102,8 +1106,132 @@ var InvariantBase = class {
|
|
|
1102
1106
|
}
|
|
1103
1107
|
};
|
|
1104
1108
|
|
|
1105
|
-
// ../../lib/contract/src/aria/
|
|
1109
|
+
// ../../lib/contract/src/aria/spec/roles/required-properties.ts
|
|
1110
|
+
var REQUIRED_ARIA_PROPERTIES = {
|
|
1111
|
+
combobox: ["aria-expanded"],
|
|
1112
|
+
option: ["aria-selected"],
|
|
1113
|
+
slider: ["aria-valuenow"],
|
|
1114
|
+
scrollbar: ["aria-controls", "aria-valuenow"],
|
|
1115
|
+
spinbutton: ["aria-valuenow"]
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// ../../lib/contract/src/aria/spec/roles/name-required.ts
|
|
1119
|
+
var NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1120
|
+
|
|
1121
|
+
// ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
|
|
1106
1122
|
var NO_VIOLATIONS = [{ valid: true }];
|
|
1123
|
+
function requiredAttributeByRole(roles, attribute) {
|
|
1124
|
+
return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
|
|
1125
|
+
}
|
|
1126
|
+
function checkRequiredAttributes(requirement, { props, effectiveRole }) {
|
|
1127
|
+
if (!effectiveRole) return NO_VIOLATIONS;
|
|
1128
|
+
const requiredAttributes = requirement.attributesByRole[effectiveRole];
|
|
1129
|
+
if (!requiredAttributes) return NO_VIOLATIONS;
|
|
1130
|
+
const results = [];
|
|
1131
|
+
for (const attribute of requiredAttributes) {
|
|
1132
|
+
if (attribute in props) continue;
|
|
1133
|
+
results.push({
|
|
1134
|
+
valid: false,
|
|
1135
|
+
fixable: false,
|
|
1136
|
+
severity: "warning",
|
|
1137
|
+
attribute,
|
|
1138
|
+
diagnostic: requirement.diagnosticFor(attribute, effectiveRole)
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
return results;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// ../../lib/contract/src/aria/spec/roles/live-region.ts
|
|
1145
|
+
var LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
|
|
1146
|
+
["alert", "assertive"],
|
|
1147
|
+
["status", "polite"],
|
|
1148
|
+
["log", "polite"],
|
|
1149
|
+
["timer", "off"]
|
|
1150
|
+
]);
|
|
1151
|
+
var ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
|
|
1152
|
+
|
|
1153
|
+
// ../../lib/contract/src/aria/spec/attributes/aria-value-types.ts
|
|
1154
|
+
var ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
1155
|
+
// Boolean (true | false)
|
|
1156
|
+
["aria-atomic", { kind: "boolean" }],
|
|
1157
|
+
["aria-busy", { kind: "boolean" }],
|
|
1158
|
+
["aria-disabled", { kind: "boolean" }],
|
|
1159
|
+
["aria-expanded", { kind: "boolean" }],
|
|
1160
|
+
["aria-hidden", { kind: "boolean" }],
|
|
1161
|
+
["aria-modal", { kind: "boolean" }],
|
|
1162
|
+
["aria-multiline", { kind: "boolean" }],
|
|
1163
|
+
["aria-multiselectable", { kind: "boolean" }],
|
|
1164
|
+
["aria-readonly", { kind: "boolean" }],
|
|
1165
|
+
["aria-required", { kind: "boolean" }],
|
|
1166
|
+
["aria-selected", { kind: "boolean" }],
|
|
1167
|
+
// Tristate (true | false | mixed)
|
|
1168
|
+
["aria-checked", { kind: "tristate" }],
|
|
1169
|
+
["aria-pressed", { kind: "tristate" }],
|
|
1170
|
+
// Numeric (any finite number)
|
|
1171
|
+
["aria-valuenow", { kind: "number" }],
|
|
1172
|
+
["aria-valuemin", { kind: "number" }],
|
|
1173
|
+
["aria-valuemax", { kind: "number" }],
|
|
1174
|
+
// Integer with optional range
|
|
1175
|
+
["aria-level", { kind: "integer", min: 1, max: 6 }],
|
|
1176
|
+
["aria-posinset", { kind: "integer", min: 1 }],
|
|
1177
|
+
["aria-setsize", { kind: "integer", min: -1 }],
|
|
1178
|
+
["aria-rowcount", { kind: "integer", min: -1 }],
|
|
1179
|
+
["aria-colcount", { kind: "integer", min: -1 }],
|
|
1180
|
+
["aria-rowindex", { kind: "integer", min: 1 }],
|
|
1181
|
+
["aria-colindex", { kind: "integer", min: 1 }],
|
|
1182
|
+
["aria-rowspan", { kind: "integer", min: 0 }],
|
|
1183
|
+
["aria-colspan", { kind: "integer", min: 0 }],
|
|
1184
|
+
// Enum (specific allowed tokens)
|
|
1185
|
+
["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
|
|
1186
|
+
[
|
|
1187
|
+
"aria-current",
|
|
1188
|
+
{
|
|
1189
|
+
kind: "enum",
|
|
1190
|
+
values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
|
|
1191
|
+
}
|
|
1192
|
+
],
|
|
1193
|
+
[
|
|
1194
|
+
"aria-haspopup",
|
|
1195
|
+
{
|
|
1196
|
+
kind: "enum",
|
|
1197
|
+
values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
|
|
1198
|
+
}
|
|
1199
|
+
],
|
|
1200
|
+
["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
|
|
1201
|
+
["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
|
|
1202
|
+
["aria-orientation", { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }],
|
|
1203
|
+
["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
|
|
1204
|
+
]);
|
|
1205
|
+
|
|
1206
|
+
// ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
|
|
1207
|
+
var VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
|
|
1208
|
+
"additions",
|
|
1209
|
+
"removals",
|
|
1210
|
+
"text",
|
|
1211
|
+
"all"
|
|
1212
|
+
]);
|
|
1213
|
+
|
|
1214
|
+
// ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
|
|
1215
|
+
var HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1216
|
+
["h1", 1],
|
|
1217
|
+
["h2", 2],
|
|
1218
|
+
["h3", 3],
|
|
1219
|
+
["h4", 4],
|
|
1220
|
+
["h5", 5],
|
|
1221
|
+
["h6", 6]
|
|
1222
|
+
]);
|
|
1223
|
+
|
|
1224
|
+
// ../../lib/contract/src/aria/spec/elements/interactive-tags.ts
|
|
1225
|
+
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
1226
|
+
"a",
|
|
1227
|
+
"button",
|
|
1228
|
+
"input",
|
|
1229
|
+
"select",
|
|
1230
|
+
"textarea"
|
|
1231
|
+
]);
|
|
1232
|
+
|
|
1233
|
+
// ../../lib/contract/src/aria/polymorphic-validator.ts
|
|
1234
|
+
var NO_VIOLATIONS2 = [{ valid: true }];
|
|
1107
1235
|
function isIntrinsicTag(tag) {
|
|
1108
1236
|
return isString(tag);
|
|
1109
1237
|
}
|
|
@@ -1165,6 +1293,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1165
1293
|
const violations = [];
|
|
1166
1294
|
const fixes = [];
|
|
1167
1295
|
iterate.forEach(rules, (rule) => {
|
|
1296
|
+
if (isNonNull(rule.tags) && !rule.tags.includes(context.tag)) return;
|
|
1168
1297
|
iterate.forEach(rule(context), (result) => {
|
|
1169
1298
|
if (result.valid) return;
|
|
1170
1299
|
const {
|
|
@@ -1190,7 +1319,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1190
1319
|
return { violations, fixes };
|
|
1191
1320
|
}
|
|
1192
1321
|
static #getRules(context) {
|
|
1193
|
-
if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) &&
|
|
1322
|
+
if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && LIVE_REGION_ROLES.has(context.effectiveRole)) {
|
|
1194
1323
|
return _AriaPolicyEngine.#pipeline;
|
|
1195
1324
|
}
|
|
1196
1325
|
return _AriaPolicyEngine.#implicitOnlyRules;
|
|
@@ -1392,7 +1521,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1392
1521
|
implicitRole
|
|
1393
1522
|
}) {
|
|
1394
1523
|
const role = props.role;
|
|
1395
|
-
if (!implicitRole || !role || role === implicitRole) return
|
|
1524
|
+
if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS2;
|
|
1396
1525
|
if (isStrongImplicitRole(tag) && role === "region") {
|
|
1397
1526
|
const diagnostic = HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role);
|
|
1398
1527
|
return [
|
|
@@ -1405,11 +1534,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1405
1534
|
}
|
|
1406
1535
|
];
|
|
1407
1536
|
}
|
|
1408
|
-
return
|
|
1537
|
+
return NO_VIOLATIONS2;
|
|
1409
1538
|
}
|
|
1410
1539
|
static #checkRedundantRole({ tag, props, implicitRole }) {
|
|
1411
1540
|
const role = props.role;
|
|
1412
|
-
if (!implicitRole || !role || role !== implicitRole) return
|
|
1541
|
+
if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS2;
|
|
1413
1542
|
const diagnostic = HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole);
|
|
1414
1543
|
return [
|
|
1415
1544
|
{
|
|
@@ -1423,8 +1552,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1423
1552
|
}
|
|
1424
1553
|
static #checkStandaloneRegion({ tag, props, implicitRole }) {
|
|
1425
1554
|
const role = props.role;
|
|
1426
|
-
if (role !== "region") return
|
|
1427
|
-
if (!isStandaloneTag(tag)) return
|
|
1555
|
+
if (role !== "region") return NO_VIOLATIONS2;
|
|
1556
|
+
if (!isStandaloneTag(tag)) return NO_VIOLATIONS2;
|
|
1428
1557
|
const diagnostic = HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag);
|
|
1429
1558
|
return [
|
|
1430
1559
|
{
|
|
@@ -1441,7 +1570,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1441
1570
|
props,
|
|
1442
1571
|
effectiveRole
|
|
1443
1572
|
}) {
|
|
1444
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1573
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1445
1574
|
const results = [];
|
|
1446
1575
|
iterate.forEachEntry(props, (key) => {
|
|
1447
1576
|
if (!key.startsWith("aria-")) return;
|
|
@@ -1459,62 +1588,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1459
1588
|
return results;
|
|
1460
1589
|
}
|
|
1461
1590
|
// ─── ARIA attribute value validation ──────────────────────────────────────
|
|
1462
|
-
// Accepted value shapes for typed ARIA attributes.
|
|
1463
|
-
// Attributes not in this map are unconstrained (arbitrary string values permitted).
|
|
1464
|
-
static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
1465
|
-
// Boolean (true | false)
|
|
1466
|
-
["aria-atomic", { kind: "boolean" }],
|
|
1467
|
-
["aria-busy", { kind: "boolean" }],
|
|
1468
|
-
["aria-disabled", { kind: "boolean" }],
|
|
1469
|
-
["aria-expanded", { kind: "boolean" }],
|
|
1470
|
-
["aria-hidden", { kind: "boolean" }],
|
|
1471
|
-
["aria-modal", { kind: "boolean" }],
|
|
1472
|
-
["aria-multiline", { kind: "boolean" }],
|
|
1473
|
-
["aria-multiselectable", { kind: "boolean" }],
|
|
1474
|
-
["aria-readonly", { kind: "boolean" }],
|
|
1475
|
-
["aria-required", { kind: "boolean" }],
|
|
1476
|
-
["aria-selected", { kind: "boolean" }],
|
|
1477
|
-
// Tristate (true | false | mixed)
|
|
1478
|
-
["aria-checked", { kind: "tristate" }],
|
|
1479
|
-
["aria-pressed", { kind: "tristate" }],
|
|
1480
|
-
// Numeric (any finite number)
|
|
1481
|
-
["aria-valuenow", { kind: "number" }],
|
|
1482
|
-
["aria-valuemin", { kind: "number" }],
|
|
1483
|
-
["aria-valuemax", { kind: "number" }],
|
|
1484
|
-
// Integer with optional range
|
|
1485
|
-
["aria-level", { kind: "integer", min: 1, max: 6 }],
|
|
1486
|
-
["aria-posinset", { kind: "integer", min: 1 }],
|
|
1487
|
-
["aria-setsize", { kind: "integer", min: -1 }],
|
|
1488
|
-
["aria-rowcount", { kind: "integer", min: -1 }],
|
|
1489
|
-
["aria-colcount", { kind: "integer", min: -1 }],
|
|
1490
|
-
["aria-rowindex", { kind: "integer", min: 1 }],
|
|
1491
|
-
["aria-colindex", { kind: "integer", min: 1 }],
|
|
1492
|
-
["aria-rowspan", { kind: "integer", min: 0 }],
|
|
1493
|
-
["aria-colspan", { kind: "integer", min: 0 }],
|
|
1494
|
-
// Enum (specific allowed tokens)
|
|
1495
|
-
["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
|
|
1496
|
-
[
|
|
1497
|
-
"aria-current",
|
|
1498
|
-
{
|
|
1499
|
-
kind: "enum",
|
|
1500
|
-
values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
|
|
1501
|
-
}
|
|
1502
|
-
],
|
|
1503
|
-
[
|
|
1504
|
-
"aria-haspopup",
|
|
1505
|
-
{
|
|
1506
|
-
kind: "enum",
|
|
1507
|
-
values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
|
|
1508
|
-
}
|
|
1509
|
-
],
|
|
1510
|
-
["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
|
|
1511
|
-
["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
|
|
1512
|
-
[
|
|
1513
|
-
"aria-orientation",
|
|
1514
|
-
{ kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
|
|
1515
|
-
],
|
|
1516
|
-
["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
|
|
1517
|
-
]);
|
|
1518
1591
|
static #isValidAriaValue(value, type) {
|
|
1519
1592
|
switch (type.kind) {
|
|
1520
1593
|
case "boolean":
|
|
@@ -1559,11 +1632,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1559
1632
|
}
|
|
1560
1633
|
}
|
|
1561
1634
|
static #checkAriaAttributeValues({ props, effectiveRole }) {
|
|
1562
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1635
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1563
1636
|
const results = [];
|
|
1564
1637
|
iterate.forEachEntry(props, (key, value) => {
|
|
1565
1638
|
if (!key.startsWith("aria-")) return;
|
|
1566
|
-
const type =
|
|
1639
|
+
const type = ARIA_VALUE_TYPES.get(key);
|
|
1567
1640
|
if (!isNonNull(type)) return;
|
|
1568
1641
|
if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
|
|
1569
1642
|
results.push({
|
|
@@ -1582,26 +1655,18 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1582
1655
|
return results;
|
|
1583
1656
|
}
|
|
1584
1657
|
// ─── Heading implicit level ────────────────────────────────────────────────
|
|
1585
|
-
static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1586
|
-
["h1", 1],
|
|
1587
|
-
["h2", 2],
|
|
1588
|
-
["h3", 3],
|
|
1589
|
-
["h4", 4],
|
|
1590
|
-
["h5", 5],
|
|
1591
|
-
["h6", 6]
|
|
1592
|
-
]);
|
|
1593
1658
|
static #checkRedundantAriaLevel({
|
|
1594
1659
|
tag,
|
|
1595
1660
|
props,
|
|
1596
1661
|
effectiveRole
|
|
1597
1662
|
}) {
|
|
1598
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
1599
|
-
const implicitLevel =
|
|
1600
|
-
if (!isNonNull(implicitLevel)) return
|
|
1663
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
|
|
1664
|
+
const implicitLevel = HEADING_IMPLICIT_LEVELS.get(tag);
|
|
1665
|
+
if (!isNonNull(implicitLevel)) return NO_VIOLATIONS2;
|
|
1601
1666
|
const raw = props["aria-level"];
|
|
1602
|
-
if (!isNonNull(raw)) return
|
|
1667
|
+
if (!isNonNull(raw)) return NO_VIOLATIONS2;
|
|
1603
1668
|
const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
|
|
1604
|
-
if (!Number.isFinite(n) || n !== implicitLevel) return
|
|
1669
|
+
if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS2;
|
|
1605
1670
|
return [
|
|
1606
1671
|
{
|
|
1607
1672
|
valid: false,
|
|
@@ -1614,20 +1679,14 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1614
1679
|
];
|
|
1615
1680
|
}
|
|
1616
1681
|
// ─── Name-required roles ───────────────────────────────────────────────────
|
|
1617
|
-
// Roles that always require an accessible name per WAI-ARIA APG.
|
|
1618
|
-
// Dialog and landmark names are enforced via contracts (ariaContract) rather than
|
|
1619
|
-
// the built-in pipeline so consumers can opt in; img is built in because role=img
|
|
1620
|
-
// on any element (including bare <img>) is definitionally useless without a name.
|
|
1621
|
-
static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1622
1682
|
static #checkNameRequiredRoles({
|
|
1623
1683
|
tag,
|
|
1624
1684
|
props,
|
|
1625
1685
|
effectiveRole
|
|
1626
1686
|
}) {
|
|
1627
|
-
if (!effectiveRole || !
|
|
1628
|
-
|
|
1629
|
-
if ("
|
|
1630
|
-
if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
|
|
1687
|
+
if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return NO_VIOLATIONS2;
|
|
1688
|
+
if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS2;
|
|
1689
|
+
if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS2;
|
|
1631
1690
|
return [
|
|
1632
1691
|
{
|
|
1633
1692
|
valid: false,
|
|
@@ -1637,51 +1696,21 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1637
1696
|
}
|
|
1638
1697
|
];
|
|
1639
1698
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
["scrollbar", ["aria-controls", "aria-valuenow"]],
|
|
1647
|
-
["spinbutton", ["aria-valuenow"]]
|
|
1648
|
-
]);
|
|
1649
|
-
static #checkRequiredAriaProperties({
|
|
1650
|
-
props,
|
|
1651
|
-
effectiveRole
|
|
1652
|
-
}) {
|
|
1653
|
-
if (!effectiveRole) return NO_VIOLATIONS;
|
|
1654
|
-
const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
|
|
1655
|
-
if (!isNonNull(required)) return NO_VIOLATIONS;
|
|
1656
|
-
const results = [];
|
|
1657
|
-
iterate.forEach(required, (attr) => {
|
|
1658
|
-
if (attr in props) return;
|
|
1659
|
-
results.push({
|
|
1660
|
-
valid: false,
|
|
1661
|
-
fixable: false,
|
|
1662
|
-
severity: "warning",
|
|
1663
|
-
attribute: attr,
|
|
1664
|
-
diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
|
|
1665
|
-
});
|
|
1666
|
-
});
|
|
1667
|
-
return results;
|
|
1699
|
+
static #requiredAriaPropertiesRule = {
|
|
1700
|
+
attributesByRole: REQUIRED_ARIA_PROPERTIES,
|
|
1701
|
+
diagnosticFor: (attribute, role) => AriaDiagnostics.requiredProperty(attribute, role)
|
|
1702
|
+
};
|
|
1703
|
+
static #checkRequiredAriaProperties(context) {
|
|
1704
|
+
return checkRequiredAttributes(_AriaPolicyEngine.#requiredAriaPropertiesRule, context);
|
|
1668
1705
|
}
|
|
1669
|
-
// Natively interactive HTML elements — always keyboard-reachable unless explicitly disabled.
|
|
1670
|
-
static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
1671
|
-
"a",
|
|
1672
|
-
"button",
|
|
1673
|
-
"input",
|
|
1674
|
-
"select",
|
|
1675
|
-
"textarea"
|
|
1676
|
-
]);
|
|
1677
1706
|
// WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
|
|
1678
1707
|
static #checkAriaHiddenOnFocusable({ tag, props }) {
|
|
1679
|
-
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return
|
|
1680
|
-
const isInteractive =
|
|
1708
|
+
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS2;
|
|
1709
|
+
const isInteractive = INTERACTIVE_TAGS.has(tag);
|
|
1681
1710
|
if (!isInteractive) {
|
|
1682
1711
|
const tabindex = props.tabindex;
|
|
1683
1712
|
const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
|
|
1684
|
-
if (!Number.isFinite(n) || n < 0) return
|
|
1713
|
+
if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS2;
|
|
1685
1714
|
}
|
|
1686
1715
|
return [
|
|
1687
1716
|
{
|
|
@@ -1700,7 +1729,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1700
1729
|
props,
|
|
1701
1730
|
effectiveRole
|
|
1702
1731
|
}) {
|
|
1703
|
-
if (effectiveRole !== "none" && effectiveRole !== "presentation") return
|
|
1732
|
+
if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS2;
|
|
1704
1733
|
const results = [];
|
|
1705
1734
|
iterate.forEachEntry(props, (key) => {
|
|
1706
1735
|
if (!key.startsWith("aria-")) return;
|
|
@@ -1716,18 +1745,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1716
1745
|
});
|
|
1717
1746
|
return results;
|
|
1718
1747
|
}
|
|
1719
|
-
// WAI-ARIA live region roles and their implied aria-live politeness values.
|
|
1720
|
-
static #LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
|
|
1721
|
-
["alert", "assertive"],
|
|
1722
|
-
["status", "polite"],
|
|
1723
|
-
["log", "polite"],
|
|
1724
|
-
["timer", "off"]
|
|
1725
|
-
]);
|
|
1726
1748
|
static #checkMissingLiveRegion({ effectiveRole, props }) {
|
|
1727
|
-
if (!effectiveRole) return
|
|
1728
|
-
const impliedLive =
|
|
1729
|
-
if (!impliedLive) return
|
|
1730
|
-
if ("aria-live" in props) return
|
|
1749
|
+
if (!effectiveRole) return NO_VIOLATIONS2;
|
|
1750
|
+
const impliedLive = LIVE_REGION_ROLES.get(effectiveRole);
|
|
1751
|
+
if (!impliedLive) return NO_VIOLATIONS2;
|
|
1752
|
+
if ("aria-live" in props) return NO_VIOLATIONS2;
|
|
1731
1753
|
const injectLive = {
|
|
1732
1754
|
kind: `injectLive:${effectiveRole}`,
|
|
1733
1755
|
apply: (ctx) => ({
|
|
@@ -1746,20 +1768,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1746
1768
|
}
|
|
1747
1769
|
];
|
|
1748
1770
|
}
|
|
1749
|
-
static #
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
valid: false,
|
|
1756
|
-
fixable: false,
|
|
1757
|
-
severity: "warning",
|
|
1758
|
-
diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
|
|
1759
|
-
}
|
|
1760
|
-
];
|
|
1771
|
+
static #missingAtomicRule = {
|
|
1772
|
+
attributesByRole: ATOMIC_REQUIREMENTS,
|
|
1773
|
+
diagnosticFor: (_attribute, role) => AriaDiagnostics.missingAtomic(role)
|
|
1774
|
+
};
|
|
1775
|
+
static #checkMissingAtomic(context) {
|
|
1776
|
+
return checkRequiredAttributes(_AriaPolicyEngine.#missingAtomicRule, context);
|
|
1761
1777
|
}
|
|
1762
|
-
static #VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set(["additions", "removals", "text", "all"]);
|
|
1763
1778
|
// Custom fix rules passed via `options.rules` must be pure functions of (tag, props) — the cache
|
|
1764
1779
|
// replays stored fixes against new prop objects, so fixes that close over external state will
|
|
1765
1780
|
// produce inconsistent results on cache hits.
|
|
@@ -1773,10 +1788,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1773
1788
|
};
|
|
1774
1789
|
static #checkInvalidAriaRelevant({ props }) {
|
|
1775
1790
|
const relevant = props["aria-relevant"];
|
|
1776
|
-
if (relevant === void 0) return
|
|
1777
|
-
if (typeof relevant !== "string") return
|
|
1791
|
+
if (relevant === void 0) return NO_VIOLATIONS2;
|
|
1792
|
+
if (typeof relevant !== "string") return NO_VIOLATIONS2;
|
|
1778
1793
|
const tokens = relevant.trim().split(/\s+/);
|
|
1779
|
-
const invalid = tokens.filter((t) => !
|
|
1794
|
+
const invalid = tokens.filter((t) => !VALID_RELEVANT_TOKENS.has(t));
|
|
1780
1795
|
if (invalid.length > 0) {
|
|
1781
1796
|
return [
|
|
1782
1797
|
{
|
|
@@ -1801,7 +1816,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
|
1801
1816
|
}
|
|
1802
1817
|
];
|
|
1803
1818
|
}
|
|
1804
|
-
return
|
|
1819
|
+
return NO_VIOLATIONS2;
|
|
1805
1820
|
}
|
|
1806
1821
|
};
|
|
1807
1822
|
|
|
@@ -2121,7 +2136,59 @@ var readonlyProps = ({
|
|
|
2121
2136
|
// ../core/src/html/evaluators.ts
|
|
2122
2137
|
import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
|
|
2123
2138
|
|
|
2124
|
-
// ../core/src/html/input
|
|
2139
|
+
// ../core/src/html/spec/vocabulary/input.ts
|
|
2140
|
+
var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
|
|
2141
|
+
var NUMERIC_INPUT_TYPES = [
|
|
2142
|
+
"number",
|
|
2143
|
+
"range",
|
|
2144
|
+
"date",
|
|
2145
|
+
"month",
|
|
2146
|
+
"week",
|
|
2147
|
+
"time",
|
|
2148
|
+
"datetime-local"
|
|
2149
|
+
];
|
|
2150
|
+
var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
2151
|
+
...TEXT_INPUT_TYPES,
|
|
2152
|
+
...NUMERIC_INPUT_TYPES,
|
|
2153
|
+
"checkbox",
|
|
2154
|
+
"radio",
|
|
2155
|
+
"file",
|
|
2156
|
+
"color",
|
|
2157
|
+
"hidden",
|
|
2158
|
+
"button",
|
|
2159
|
+
"submit",
|
|
2160
|
+
"reset",
|
|
2161
|
+
"image"
|
|
2162
|
+
]);
|
|
2163
|
+
|
|
2164
|
+
// ../core/src/html/spec/attributes/input.ts
|
|
2165
|
+
var INPUT_ATTRIBUTE_TYPE_POLICIES = [
|
|
2166
|
+
{ attribute: "checked", allowedTypes: ["checkbox", "radio"] },
|
|
2167
|
+
{ attribute: "multiple", allowedTypes: ["email", "file"] },
|
|
2168
|
+
{ attribute: "maxLength", allowedTypes: TEXT_INPUT_TYPES },
|
|
2169
|
+
{ attribute: "minLength", allowedTypes: TEXT_INPUT_TYPES },
|
|
2170
|
+
{ attribute: "pattern", allowedTypes: TEXT_INPUT_TYPES },
|
|
2171
|
+
{ attribute: "min", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2172
|
+
{ attribute: "max", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2173
|
+
{ attribute: "step", allowedTypes: NUMERIC_INPUT_TYPES },
|
|
2174
|
+
{ attribute: "accept", allowedTypes: ["file"] },
|
|
2175
|
+
{ attribute: "capture", allowedTypes: ["file"] },
|
|
2176
|
+
{ attribute: "size", allowedTypes: TEXT_INPUT_TYPES },
|
|
2177
|
+
{ attribute: "alt", allowedTypes: ["image"] },
|
|
2178
|
+
{ attribute: "height", allowedTypes: ["image"] },
|
|
2179
|
+
{ attribute: "width", allowedTypes: ["image"] }
|
|
2180
|
+
];
|
|
2181
|
+
|
|
2182
|
+
// ../core/src/html/spec/constraints/input.ts
|
|
2183
|
+
var REQUIRED_READONLY_CONFLICT = {
|
|
2184
|
+
props: ["required", "readOnly"],
|
|
2185
|
+
diagnostic: () => InputAccessibilityDiagnostics.requiredReadOnlyConflict()
|
|
2186
|
+
};
|
|
2187
|
+
var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
|
|
2188
|
+
REQUIRED_READONLY_CONFLICT
|
|
2189
|
+
];
|
|
2190
|
+
|
|
2191
|
+
// ../core/src/html/spec/validators/attribute-type-validator.ts
|
|
2125
2192
|
var DEFAULT_INPUT_TYPE = "text";
|
|
2126
2193
|
function omit(props, key) {
|
|
2127
2194
|
const next = { ...props };
|
|
@@ -2137,7 +2204,10 @@ function removeAttributeFix(attribute) {
|
|
|
2137
2204
|
}
|
|
2138
2205
|
};
|
|
2139
2206
|
}
|
|
2140
|
-
function
|
|
2207
|
+
function createInputAttributeTypeRule({
|
|
2208
|
+
attribute,
|
|
2209
|
+
allowedTypes
|
|
2210
|
+
}) {
|
|
2141
2211
|
const rule = ({ tag, props }) => {
|
|
2142
2212
|
if (tag !== "input" || !(attribute in props)) return [];
|
|
2143
2213
|
const type = typeof props.type === "string" ? props.type : DEFAULT_INPUT_TYPE;
|
|
@@ -2153,31 +2223,30 @@ function inputAttributeRequiresType(attribute, allowedTypes) {
|
|
|
2153
2223
|
}
|
|
2154
2224
|
];
|
|
2155
2225
|
};
|
|
2156
|
-
return Object.assign(rule, { readsProps: ["type", attribute] });
|
|
2226
|
+
return Object.assign(rule, { readsProps: ["type", attribute], tags: ["input"] });
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
// ../core/src/html/spec/validators/mutually-exclusive-validator.ts
|
|
2230
|
+
function createMutuallyExclusiveRule({
|
|
2231
|
+
props: conflictingProps,
|
|
2232
|
+
diagnostic: createDiagnostic
|
|
2233
|
+
}) {
|
|
2234
|
+
const [first, second] = conflictingProps;
|
|
2235
|
+
const rule = ({ tag, props }) => {
|
|
2236
|
+
if (tag !== "input" || !props[first] || !props[second]) return [];
|
|
2237
|
+
const diagnostic = createDiagnostic();
|
|
2238
|
+
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2239
|
+
};
|
|
2240
|
+
return Object.assign(rule, { readsProps: conflictingProps, tags: ["input"] });
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
// ../core/src/html/input-rules.ts
|
|
2244
|
+
var policyByAttribute = Object.fromEntries(
|
|
2245
|
+
INPUT_ATTRIBUTE_TYPE_POLICIES.map((policy) => [policy.attribute, policy])
|
|
2246
|
+
);
|
|
2247
|
+
function policyFor(attribute) {
|
|
2248
|
+
return policyByAttribute[attribute];
|
|
2157
2249
|
}
|
|
2158
|
-
var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
|
|
2159
|
-
var NUMERIC_INPUT_TYPES = [
|
|
2160
|
-
"number",
|
|
2161
|
-
"range",
|
|
2162
|
-
"date",
|
|
2163
|
-
"month",
|
|
2164
|
-
"week",
|
|
2165
|
-
"time",
|
|
2166
|
-
"datetime-local"
|
|
2167
|
-
];
|
|
2168
|
-
var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
2169
|
-
...TEXT_INPUT_TYPES,
|
|
2170
|
-
...NUMERIC_INPUT_TYPES,
|
|
2171
|
-
"checkbox",
|
|
2172
|
-
"radio",
|
|
2173
|
-
"file",
|
|
2174
|
-
"color",
|
|
2175
|
-
"hidden",
|
|
2176
|
-
"button",
|
|
2177
|
-
"submit",
|
|
2178
|
-
"reset",
|
|
2179
|
-
"image"
|
|
2180
|
-
]);
|
|
2181
2250
|
var supportedInputTypeRule = Object.assign(
|
|
2182
2251
|
({ tag, props }) => {
|
|
2183
2252
|
if (tag !== "input" || typeof props.type !== "string") return [];
|
|
@@ -2193,30 +2262,22 @@ var supportedInputTypeRule = Object.assign(
|
|
|
2193
2262
|
}
|
|
2194
2263
|
];
|
|
2195
2264
|
},
|
|
2196
|
-
{ readsProps: ["type"] }
|
|
2197
|
-
);
|
|
2198
|
-
var checkedRequiresCheckableTypeRule = inputAttributeRequiresType("checked", [
|
|
2199
|
-
"checkbox",
|
|
2200
|
-
"radio"
|
|
2201
|
-
]);
|
|
2202
|
-
var multipleRequiresSupportedTypeRule = inputAttributeRequiresType("multiple", [
|
|
2203
|
-
"email",
|
|
2204
|
-
"file"
|
|
2205
|
-
]);
|
|
2206
|
-
var maxLengthRequiresTextTypeRule = inputAttributeRequiresType(
|
|
2207
|
-
"maxLength",
|
|
2208
|
-
TEXT_INPUT_TYPES
|
|
2209
|
-
);
|
|
2210
|
-
var minLengthRequiresTextTypeRule = inputAttributeRequiresType(
|
|
2211
|
-
"minLength",
|
|
2212
|
-
TEXT_INPUT_TYPES
|
|
2265
|
+
{ readsProps: ["type"], tags: ["input"] }
|
|
2213
2266
|
);
|
|
2214
|
-
var
|
|
2215
|
-
var
|
|
2216
|
-
var
|
|
2217
|
-
var
|
|
2218
|
-
var
|
|
2219
|
-
var
|
|
2267
|
+
var checkedRequiresCheckableTypeRule = createInputAttributeTypeRule(policyFor("checked"));
|
|
2268
|
+
var multipleRequiresSupportedTypeRule = createInputAttributeTypeRule(policyFor("multiple"));
|
|
2269
|
+
var maxLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("maxLength"));
|
|
2270
|
+
var minLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("minLength"));
|
|
2271
|
+
var patternRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("pattern"));
|
|
2272
|
+
var minRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("min"));
|
|
2273
|
+
var maxRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("max"));
|
|
2274
|
+
var stepRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("step"));
|
|
2275
|
+
var acceptRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("accept"));
|
|
2276
|
+
var captureRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("capture"));
|
|
2277
|
+
var sizeRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("size"));
|
|
2278
|
+
var altRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("alt"));
|
|
2279
|
+
var heightRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("height"));
|
|
2280
|
+
var widthRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("width"));
|
|
2220
2281
|
var inputAccessibleNameRule = Object.assign(
|
|
2221
2282
|
({ tag, props }) => {
|
|
2222
2283
|
if (tag !== "input" || props.type === "hidden") return [];
|
|
@@ -2225,7 +2286,10 @@ var inputAccessibleNameRule = Object.assign(
|
|
|
2225
2286
|
const diagnostic = hasPlaceholder ? InputAccessibilityDiagnostics.placeholderIsNotLabel() : InputAccessibilityDiagnostics.missingAccessibleName();
|
|
2226
2287
|
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2227
2288
|
},
|
|
2228
|
-
{
|
|
2289
|
+
{
|
|
2290
|
+
readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"],
|
|
2291
|
+
tags: ["input"]
|
|
2292
|
+
}
|
|
2229
2293
|
);
|
|
2230
2294
|
var PASSWORD_AUTOCOMPLETE_VALUES = ["current-password", "new-password"];
|
|
2231
2295
|
var passwordAutocompleteRule = Object.assign(
|
|
@@ -2237,16 +2301,9 @@ var passwordAutocompleteRule = Object.assign(
|
|
|
2237
2301
|
const diagnostic = InputAccessibilityDiagnostics.passwordMissingAutocomplete();
|
|
2238
2302
|
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2239
2303
|
},
|
|
2240
|
-
{ readsProps: ["type", "autoComplete"] }
|
|
2241
|
-
);
|
|
2242
|
-
var requiredReadOnlyConflictRule = Object.assign(
|
|
2243
|
-
({ tag, props }) => {
|
|
2244
|
-
if (tag !== "input" || !props.required || !props.readOnly) return [];
|
|
2245
|
-
const diagnostic = InputAccessibilityDiagnostics.requiredReadOnlyConflict();
|
|
2246
|
-
return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
|
|
2247
|
-
},
|
|
2248
|
-
{ readsProps: ["required", "readOnly"] }
|
|
2304
|
+
{ readsProps: ["type", "autoComplete"], tags: ["input"] }
|
|
2249
2305
|
);
|
|
2306
|
+
var requiredReadOnlyConflictRule = createMutuallyExclusiveRule(REQUIRED_READONLY_CONFLICT);
|
|
2250
2307
|
var INPUT_RULES = [
|
|
2251
2308
|
supportedInputTypeRule,
|
|
2252
2309
|
checkedRequiresCheckableTypeRule,
|
|
@@ -2259,11 +2316,132 @@ var INPUT_RULES = [
|
|
|
2259
2316
|
stepRequiresNumericTypeRule,
|
|
2260
2317
|
acceptRequiresFileTypeRule,
|
|
2261
2318
|
captureRequiresFileTypeRule,
|
|
2319
|
+
sizeRequiresTextTypeRule,
|
|
2320
|
+
altRequiresImageTypeRule,
|
|
2321
|
+
heightRequiresImageTypeRule,
|
|
2322
|
+
widthRequiresImageTypeRule,
|
|
2262
2323
|
inputAccessibleNameRule,
|
|
2263
2324
|
passwordAutocompleteRule,
|
|
2264
2325
|
requiredReadOnlyConflictRule
|
|
2265
2326
|
];
|
|
2266
2327
|
|
|
2328
|
+
// ../core/src/html/spec/types.ts
|
|
2329
|
+
function definePropRolePolicy(prop, map2, fallback) {
|
|
2330
|
+
return { kind: "byProp", prop, map: map2, fallback };
|
|
2331
|
+
}
|
|
2332
|
+
function resolveAllowedRoles(spec, props) {
|
|
2333
|
+
const policy = spec.allowedRoles;
|
|
2334
|
+
if (!policy) return void 0;
|
|
2335
|
+
switch (policy.kind) {
|
|
2336
|
+
case "fixed":
|
|
2337
|
+
return policy.roles;
|
|
2338
|
+
case "byProp": {
|
|
2339
|
+
const value = typeof props[policy.prop] === "string" ? props[policy.prop] : policy.fallback;
|
|
2340
|
+
return policy.map[value];
|
|
2341
|
+
}
|
|
2342
|
+
case "dynamic":
|
|
2343
|
+
return policy.resolve({ props });
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
// ../core/src/html/spec/roles/input.ts
|
|
2348
|
+
var ALLOWED_INPUT_ROLES = {
|
|
2349
|
+
checkbox: ["menuitemcheckbox", "option", "switch", "button"],
|
|
2350
|
+
radio: ["menuitemradio"],
|
|
2351
|
+
range: [],
|
|
2352
|
+
number: [],
|
|
2353
|
+
search: ["combobox"],
|
|
2354
|
+
text: ["combobox", "searchbox", "spinbutton"],
|
|
2355
|
+
email: ["combobox"],
|
|
2356
|
+
tel: ["combobox"],
|
|
2357
|
+
url: ["combobox"],
|
|
2358
|
+
button: [
|
|
2359
|
+
"link",
|
|
2360
|
+
"menuitem",
|
|
2361
|
+
"menuitemcheckbox",
|
|
2362
|
+
"menuitemradio",
|
|
2363
|
+
"option",
|
|
2364
|
+
"radio",
|
|
2365
|
+
"switch",
|
|
2366
|
+
"tab"
|
|
2367
|
+
],
|
|
2368
|
+
submit: [
|
|
2369
|
+
"link",
|
|
2370
|
+
"menuitem",
|
|
2371
|
+
"menuitemcheckbox",
|
|
2372
|
+
"menuitemradio",
|
|
2373
|
+
"option",
|
|
2374
|
+
"radio",
|
|
2375
|
+
"switch",
|
|
2376
|
+
"tab"
|
|
2377
|
+
],
|
|
2378
|
+
reset: [
|
|
2379
|
+
"link",
|
|
2380
|
+
"menuitem",
|
|
2381
|
+
"menuitemcheckbox",
|
|
2382
|
+
"menuitemradio",
|
|
2383
|
+
"option",
|
|
2384
|
+
"radio",
|
|
2385
|
+
"switch",
|
|
2386
|
+
"tab"
|
|
2387
|
+
],
|
|
2388
|
+
image: [
|
|
2389
|
+
"link",
|
|
2390
|
+
"menuitem",
|
|
2391
|
+
"menuitemcheckbox",
|
|
2392
|
+
"menuitemradio",
|
|
2393
|
+
"option",
|
|
2394
|
+
"radio",
|
|
2395
|
+
"switch",
|
|
2396
|
+
"tab"
|
|
2397
|
+
],
|
|
2398
|
+
hidden: []
|
|
2399
|
+
};
|
|
2400
|
+
|
|
2401
|
+
// ../core/src/html/spec/elements/input.ts
|
|
2402
|
+
var inputElementSpec = {
|
|
2403
|
+
tag: "input",
|
|
2404
|
+
allowedRoles: definePropRolePolicy("type", ALLOWED_INPUT_ROLES, "text"),
|
|
2405
|
+
attributes: INPUT_ATTRIBUTE_TYPE_POLICIES,
|
|
2406
|
+
mutuallyExclusive: INPUT_MUTUALLY_EXCLUSIVE_POLICIES
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2409
|
+
// ../core/src/html/spec/roles/img.ts
|
|
2410
|
+
var IMG_NAMED_ROLES = [
|
|
2411
|
+
"button",
|
|
2412
|
+
"checkbox",
|
|
2413
|
+
"link",
|
|
2414
|
+
"menuitem",
|
|
2415
|
+
"menuitemcheckbox",
|
|
2416
|
+
"menuitemradio",
|
|
2417
|
+
"option",
|
|
2418
|
+
"progressbar",
|
|
2419
|
+
"scrollbar",
|
|
2420
|
+
"separator",
|
|
2421
|
+
"slider",
|
|
2422
|
+
"switch",
|
|
2423
|
+
"tab",
|
|
2424
|
+
"treeitem"
|
|
2425
|
+
];
|
|
2426
|
+
|
|
2427
|
+
// ../core/src/html/spec/elements/img.ts
|
|
2428
|
+
var imgElementSpec = {
|
|
2429
|
+
tag: "img",
|
|
2430
|
+
allowedRoles: {
|
|
2431
|
+
kind: "dynamic",
|
|
2432
|
+
resolve: ({ props }) => props.alt === "" ? [] : IMG_NAMED_ROLES
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2435
|
+
|
|
2436
|
+
// ../core/src/html/spec/roles/table.ts
|
|
2437
|
+
var ALLOWED_TABLE_ROLES = ["grid", "treegrid"];
|
|
2438
|
+
|
|
2439
|
+
// ../core/src/html/spec/elements/table.ts
|
|
2440
|
+
var tableElementSpec = {
|
|
2441
|
+
tag: "table",
|
|
2442
|
+
allowedRoles: { kind: "fixed", roles: ALLOWED_TABLE_ROLES }
|
|
2443
|
+
};
|
|
2444
|
+
|
|
2267
2445
|
// ../core/src/html/role-restrictions.ts
|
|
2268
2446
|
var ALLOWED_ROLES = {
|
|
2269
2447
|
article: ["application", "document", "feed", "main", "none", "presentation", "region"],
|
|
@@ -2336,86 +2514,17 @@ var ALLOWED_ROLES = {
|
|
|
2336
2514
|
"tab",
|
|
2337
2515
|
"treeitem"
|
|
2338
2516
|
],
|
|
2339
|
-
table: ["grid", "treegrid"],
|
|
2340
2517
|
dialog: ["alertdialog"],
|
|
2341
2518
|
fieldset: ["none", "presentation", "radiogroup"]
|
|
2342
2519
|
};
|
|
2343
|
-
var
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
"menuitem",
|
|
2348
|
-
"menuitemcheckbox",
|
|
2349
|
-
"menuitemradio",
|
|
2350
|
-
"option",
|
|
2351
|
-
"progressbar",
|
|
2352
|
-
"scrollbar",
|
|
2353
|
-
"separator",
|
|
2354
|
-
"slider",
|
|
2355
|
-
"switch",
|
|
2356
|
-
"tab",
|
|
2357
|
-
"treeitem"
|
|
2358
|
-
];
|
|
2359
|
-
var ALLOWED_INPUT_ROLES = {
|
|
2360
|
-
checkbox: ["menuitemcheckbox", "option", "switch", "button"],
|
|
2361
|
-
radio: ["menuitemradio"],
|
|
2362
|
-
range: [],
|
|
2363
|
-
number: [],
|
|
2364
|
-
search: ["combobox"],
|
|
2365
|
-
text: ["combobox", "searchbox", "spinbutton"],
|
|
2366
|
-
email: ["combobox"],
|
|
2367
|
-
tel: ["combobox"],
|
|
2368
|
-
url: ["combobox"],
|
|
2369
|
-
button: [
|
|
2370
|
-
"link",
|
|
2371
|
-
"menuitem",
|
|
2372
|
-
"menuitemcheckbox",
|
|
2373
|
-
"menuitemradio",
|
|
2374
|
-
"option",
|
|
2375
|
-
"radio",
|
|
2376
|
-
"switch",
|
|
2377
|
-
"tab"
|
|
2378
|
-
],
|
|
2379
|
-
submit: [
|
|
2380
|
-
"link",
|
|
2381
|
-
"menuitem",
|
|
2382
|
-
"menuitemcheckbox",
|
|
2383
|
-
"menuitemradio",
|
|
2384
|
-
"option",
|
|
2385
|
-
"radio",
|
|
2386
|
-
"switch",
|
|
2387
|
-
"tab"
|
|
2388
|
-
],
|
|
2389
|
-
reset: [
|
|
2390
|
-
"link",
|
|
2391
|
-
"menuitem",
|
|
2392
|
-
"menuitemcheckbox",
|
|
2393
|
-
"menuitemradio",
|
|
2394
|
-
"option",
|
|
2395
|
-
"radio",
|
|
2396
|
-
"switch",
|
|
2397
|
-
"tab"
|
|
2398
|
-
],
|
|
2399
|
-
image: [
|
|
2400
|
-
"link",
|
|
2401
|
-
"menuitem",
|
|
2402
|
-
"menuitemcheckbox",
|
|
2403
|
-
"menuitemradio",
|
|
2404
|
-
"option",
|
|
2405
|
-
"radio",
|
|
2406
|
-
"switch",
|
|
2407
|
-
"tab"
|
|
2408
|
-
],
|
|
2409
|
-
hidden: []
|
|
2520
|
+
var ELEMENT_SPECS = {
|
|
2521
|
+
input: inputElementSpec,
|
|
2522
|
+
img: imgElementSpec,
|
|
2523
|
+
table: tableElementSpec
|
|
2410
2524
|
};
|
|
2411
2525
|
function getAllowedRoles(tag, props) {
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
return ALLOWED_INPUT_ROLES[type];
|
|
2415
|
-
}
|
|
2416
|
-
if (tag === "img") {
|
|
2417
|
-
return props.alt === "" ? [] : IMG_NAMED_ROLES;
|
|
2418
|
-
}
|
|
2526
|
+
const spec = ELEMENT_SPECS[tag];
|
|
2527
|
+
if (spec) return resolveAllowedRoles(spec, props);
|
|
2419
2528
|
return ALLOWED_ROLES[tag];
|
|
2420
2529
|
}
|
|
2421
2530
|
var removeRoleFix = {
|
|
@@ -2456,21 +2565,24 @@ var removeLandmarkRoleOverride = {
|
|
|
2456
2565
|
return { applied: true, next: rest, previous: props };
|
|
2457
2566
|
}
|
|
2458
2567
|
};
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2568
|
+
var landmarkRoleRule = Object.assign(
|
|
2569
|
+
({ tag, props, implicitRole }) => {
|
|
2570
|
+
if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
|
|
2571
|
+
const role = props.role;
|
|
2572
|
+
if (!role || role === implicitRole) return [];
|
|
2573
|
+
const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
|
|
2574
|
+
return [
|
|
2575
|
+
{
|
|
2576
|
+
valid: false,
|
|
2577
|
+
fixable: true,
|
|
2578
|
+
severity: diagnostic.severity,
|
|
2579
|
+
fix: removeLandmarkRoleOverride,
|
|
2580
|
+
diagnostic
|
|
2581
|
+
}
|
|
2582
|
+
];
|
|
2583
|
+
},
|
|
2584
|
+
{ tags: [...LANDMARK_TAG_SET] }
|
|
2585
|
+
);
|
|
2474
2586
|
function requireAccessibleName({ tag, props }) {
|
|
2475
2587
|
if ("aria-label" in props || "aria-labelledby" in props) return [];
|
|
2476
2588
|
return [
|
|
@@ -2483,10 +2595,13 @@ function requireAccessibleName({ tag, props }) {
|
|
|
2483
2595
|
];
|
|
2484
2596
|
}
|
|
2485
2597
|
var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2598
|
+
var landmarkNameAdvisory = Object.assign(
|
|
2599
|
+
(ctx) => {
|
|
2600
|
+
if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
|
|
2601
|
+
return requireAccessibleName(ctx);
|
|
2602
|
+
},
|
|
2603
|
+
{ tags: [...NAMED_LANDMARK_TAGS] }
|
|
2604
|
+
);
|
|
2490
2605
|
var HTML_ARIA_RULES = [
|
|
2491
2606
|
landmarkRoleRule,
|
|
2492
2607
|
landmarkNameAdvisory,
|
|
@@ -2587,6 +2702,62 @@ var figureContract = contract([
|
|
|
2587
2702
|
]);
|
|
2588
2703
|
var detailsContract = firstChildContract("summary", "summary");
|
|
2589
2704
|
var fieldsetContract = firstChildContract("legend", "legend");
|
|
2705
|
+
var objectContract = contract([
|
|
2706
|
+
{ name: "param", match: isTag("param") },
|
|
2707
|
+
{ name: "content", match: isOpenContent("param") }
|
|
2708
|
+
]);
|
|
2709
|
+
var INTERACTIVE_CONTENT_TAGS = ["a", "button", "input", "select", "textarea", "label"];
|
|
2710
|
+
var buttonContract = closedContract([
|
|
2711
|
+
{ name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
|
|
2712
|
+
]);
|
|
2713
|
+
var anchorContract = closedContract([
|
|
2714
|
+
{ name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
|
|
2715
|
+
]);
|
|
2716
|
+
var LABELABLE_TAGS = [
|
|
2717
|
+
"button",
|
|
2718
|
+
"input",
|
|
2719
|
+
"meter",
|
|
2720
|
+
"output",
|
|
2721
|
+
"progress",
|
|
2722
|
+
"select",
|
|
2723
|
+
"textarea"
|
|
2724
|
+
];
|
|
2725
|
+
var labelContract = contract([
|
|
2726
|
+
{ name: "control", match: isTag(...LABELABLE_TAGS), cardinality: { max: 1 } }
|
|
2727
|
+
]);
|
|
2728
|
+
var P_BLOCKED_TAGS = [
|
|
2729
|
+
"address",
|
|
2730
|
+
"article",
|
|
2731
|
+
"aside",
|
|
2732
|
+
"blockquote",
|
|
2733
|
+
"details",
|
|
2734
|
+
"dialog",
|
|
2735
|
+
"div",
|
|
2736
|
+
"dl",
|
|
2737
|
+
"fieldset",
|
|
2738
|
+
"figure",
|
|
2739
|
+
"footer",
|
|
2740
|
+
"form",
|
|
2741
|
+
"h1",
|
|
2742
|
+
"h2",
|
|
2743
|
+
"h3",
|
|
2744
|
+
"h4",
|
|
2745
|
+
"h5",
|
|
2746
|
+
"h6",
|
|
2747
|
+
"header",
|
|
2748
|
+
"hr",
|
|
2749
|
+
"main",
|
|
2750
|
+
"nav",
|
|
2751
|
+
"ol",
|
|
2752
|
+
"p",
|
|
2753
|
+
"pre",
|
|
2754
|
+
"section",
|
|
2755
|
+
"table",
|
|
2756
|
+
"ul"
|
|
2757
|
+
];
|
|
2758
|
+
var pContract = closedContract([
|
|
2759
|
+
{ name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
|
|
2760
|
+
]);
|
|
2590
2761
|
var mediaContract = contract([
|
|
2591
2762
|
{ name: "source", match: isTag("source") },
|
|
2592
2763
|
{ name: "track", match: isTag("track") },
|
|
@@ -2641,6 +2812,11 @@ var htmlContracts = {
|
|
|
2641
2812
|
details: detailsContract,
|
|
2642
2813
|
fieldset: fieldsetContract,
|
|
2643
2814
|
dialog: dialogContract,
|
|
2815
|
+
object: objectContract,
|
|
2816
|
+
button: buttonContract,
|
|
2817
|
+
a: anchorContract,
|
|
2818
|
+
label: labelContract,
|
|
2819
|
+
p: pContract,
|
|
2644
2820
|
head: headContract,
|
|
2645
2821
|
html: htmlContract
|
|
2646
2822
|
};
|