@markuplint/ml-spec 2.0.1 → 3.0.0-alpha.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.
Files changed (129) hide show
  1. package/lib/dom-traverse/accname-computation.d.ts +1 -0
  2. package/lib/dom-traverse/accname-computation.js +8 -0
  3. package/lib/dom-traverse/focusability-computation.d.ts +1 -0
  4. package/lib/dom-traverse/focusability-computation.js +8 -0
  5. package/lib/dom-traverse/get-aria.d.ts +9 -0
  6. package/lib/dom-traverse/get-aria.js +54 -0
  7. package/lib/dom-traverse/get-attr-specs.d.ts +2 -0
  8. package/lib/dom-traverse/get-attr-specs.js +8 -0
  9. package/lib/dom-traverse/get-computed-role.d.ts +2 -0
  10. package/lib/dom-traverse/get-computed-role.js +170 -0
  11. package/lib/dom-traverse/get-explicit-role.d.ts +2 -0
  12. package/lib/dom-traverse/get-explicit-role.js +102 -0
  13. package/lib/dom-traverse/get-implicit-role.d.ts +3 -0
  14. package/lib/dom-traverse/get-implicit-role.js +37 -0
  15. package/lib/dom-traverse/get-non-presentational-ancestor.d.ts +5 -0
  16. package/lib/dom-traverse/get-non-presentational-ancestor.js +21 -0
  17. package/lib/dom-traverse/get-permitted-roles.d.ts +5 -0
  18. package/lib/dom-traverse/get-permitted-roles.js +8 -0
  19. package/lib/dom-traverse/get-spec.d.ts +2 -0
  20. package/lib/dom-traverse/get-spec.js +8 -0
  21. package/lib/dom-traverse/has-required-owned-elements.d.ts +3 -0
  22. package/lib/dom-traverse/has-required-owned-elements.js +81 -0
  23. package/lib/dom-traverse/may-be-focusable.d.ts +2 -0
  24. package/lib/dom-traverse/may-be-focusable.js +22 -0
  25. package/lib/index.d.ts +17 -6
  26. package/lib/index.js +18 -7
  27. package/lib/specs/aria-spec.d.ts +5 -0
  28. package/lib/specs/aria-spec.js +12 -0
  29. package/lib/specs/aria-specs.d.ts +6 -0
  30. package/lib/specs/aria-specs.js +8 -0
  31. package/lib/specs/content-model-category-to-tag-names.d.ts +3 -0
  32. package/lib/specs/content-model-category-to-tag-names.js +15 -0
  33. package/lib/specs/get-aria.d.ts +3 -0
  34. package/lib/specs/get-aria.js +71 -0
  35. package/lib/specs/get-attr-specs.d.ts +8 -0
  36. package/lib/{get-attr-specs.js → specs/get-attr-specs.js} +8 -6
  37. package/lib/specs/get-implicit-role.d.ts +2 -0
  38. package/lib/specs/get-implicit-role.js +12 -0
  39. package/lib/specs/get-permitted-roles.d.ts +12 -0
  40. package/lib/specs/get-permitted-roles.js +61 -0
  41. package/lib/specs/get-role-spec.d.ts +5 -0
  42. package/lib/specs/get-role-spec.js +52 -0
  43. package/lib/specs/get-selectors-by-content-model-category.d.ts +3 -0
  44. package/lib/specs/get-selectors-by-content-model-category.js +8 -0
  45. package/lib/specs/get-spec-by-tag-name.d.ts +2 -0
  46. package/lib/specs/get-spec-by-tag-name.js +16 -0
  47. package/lib/{get-spec.d.ts → specs/get-spec.d.ts} +4 -4
  48. package/lib/{get-spec.js → specs/get-spec.js} +1 -1
  49. package/lib/specs/html-spec.d.ts +6 -0
  50. package/lib/specs/html-spec.js +16 -0
  51. package/lib/specs/is-presentational.d.ts +1 -0
  52. package/lib/specs/is-presentational.js +10 -0
  53. package/lib/specs/resolve-namespace.d.ts +9 -0
  54. package/lib/specs/resolve-namespace.js +26 -0
  55. package/lib/specs/resolve-version.d.ts +3 -0
  56. package/lib/specs/resolve-version.js +21 -0
  57. package/lib/specs/schema-to-spec.d.ts +13 -0
  58. package/lib/specs/schema-to-spec.js +93 -0
  59. package/lib/types/aria.d.ts +130 -0
  60. package/lib/{attributes.js → types/aria.js} +0 -0
  61. package/lib/{attributes.d.ts → types/attributes.d.ts} +5 -12
  62. package/lib/{permitted-structres.js → types/attributes.js} +0 -0
  63. package/lib/{types.d.ts → types/index.d.ts} +50 -65
  64. package/lib/{types.js → types/index.js} +0 -0
  65. package/lib/{permitted-structres.d.ts → types/permitted-structres.d.ts} +14 -23
  66. package/lib/types/permitted-structres.js +8 -0
  67. package/lib/utils/cache.d.ts +10 -0
  68. package/lib/utils/cache.js +42 -0
  69. package/lib/utils/get-ns.d.ts +2 -0
  70. package/lib/{get-ns.js → utils/get-ns.js} +3 -0
  71. package/lib/utils/merge-array.d.ts +5 -0
  72. package/lib/utils/merge-array.js +36 -0
  73. package/lib/utils/resolve-namespace.d.ts +9 -0
  74. package/lib/utils/resolve-namespace.js +31 -0
  75. package/lib/utils.d.ts +6 -3
  76. package/lib/utils.js +15 -1
  77. package/package.json +10 -6
  78. package/schemas/aria.schema.json +258 -0
  79. package/schemas/attributes.schema.json +5 -23
  80. package/schemas/{permitted-structures.schema.json → content-models.schema.json} +52 -81
  81. package/schemas/element.schema.json +11 -0
  82. package/schemas/global-attributes.schema.json +6 -2
  83. package/src/dom-traverse/accname-computation.spec.ts +69 -0
  84. package/src/dom-traverse/accname-computation.ts +5 -0
  85. package/src/dom-traverse/get-attr-specs.ts +8 -0
  86. package/src/dom-traverse/get-computed-role.spec.ts +134 -0
  87. package/src/dom-traverse/get-computed-role.ts +181 -0
  88. package/src/dom-traverse/get-explicit-role.ts +112 -0
  89. package/src/dom-traverse/get-implicit-role.ts +36 -0
  90. package/src/dom-traverse/get-non-presentational-ancestor.ts +20 -0
  91. package/src/dom-traverse/get-permitted-roles.ts +7 -0
  92. package/src/dom-traverse/get-spec.ts +7 -0
  93. package/src/dom-traverse/has-required-owned-elements.spec.ts +36 -0
  94. package/src/dom-traverse/has-required-owned-elements.ts +85 -0
  95. package/src/dom-traverse/may-be-focusable.ts +21 -0
  96. package/src/index.ts +17 -6
  97. package/src/specs/aria-specs.ts +6 -0
  98. package/src/specs/content-model-category-to-tag-names.ts +15 -0
  99. package/src/specs/get-aria.ts +85 -0
  100. package/src/{get-attr-specs.spec.ts → specs/get-attr-specs.spec.ts} +9 -6
  101. package/src/{get-attr-specs.ts → specs/get-attr-specs.ts} +12 -7
  102. package/src/specs/get-implicit-role.spec.ts +81 -0
  103. package/src/specs/get-implicit-role.ts +17 -0
  104. package/src/specs/get-permitted-roles.spec.ts +420 -0
  105. package/src/specs/get-permitted-roles.ts +87 -0
  106. package/src/specs/get-role-spec.spec.ts +67 -0
  107. package/src/specs/get-role-spec.ts +72 -0
  108. package/src/specs/get-selectors-by-content-model-category.ts +10 -0
  109. package/src/specs/get-spec-by-tag-name.spec.ts +68 -0
  110. package/src/specs/get-spec-by-tag-name.ts +16 -0
  111. package/src/specs/is-presentational.ts +6 -0
  112. package/src/specs/resolve-version.ts +20 -0
  113. package/src/{get-spec.spec.ts → specs/schema-to-spec.spec.ts} +2 -2
  114. package/src/{get-spec.ts → specs/schema-to-spec.ts} +22 -8
  115. package/src/types/aria.ts +147 -0
  116. package/src/{attributes.ts → types/attributes.ts} +5 -12
  117. package/src/{types.ts → types/index.ts} +70 -69
  118. package/src/{permitted-structres.ts → types/permitted-structres.ts} +15 -25
  119. package/src/{get-ns.ts → utils/get-ns.ts} +6 -1
  120. package/src/{utils.ts → utils/merge-array.ts} +0 -0
  121. package/src/utils/resolve-namespace.spec.ts +37 -0
  122. package/src/utils/resolve-namespace.ts +40 -0
  123. package/tsconfig.tsbuildinfo +1 -1
  124. package/lib/get-attr-specs.d.ts +0 -7
  125. package/lib/get-ns.d.ts +0 -1
  126. package/lib/get-spec-by-tag-name.d.ts +0 -2
  127. package/lib/get-spec-by-tag-name.js +0 -31
  128. package/schemas/wai-aria.schema.json +0 -87
  129. package/src/get-spec-by-tag-name.ts +0 -32
@@ -0,0 +1 @@
1
+ export declare function getAccname(el: Element): string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAccname = void 0;
4
+ const dom_accessibility_api_1 = require("dom-accessibility-api");
5
+ function getAccname(el) {
6
+ return (0, dom_accessibility_api_1.computeAccessibleName)(el);
7
+ }
8
+ exports.getAccname = getAccname;
@@ -0,0 +1 @@
1
+ export declare function isFocusable(el: Element): boolean;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isFocusable = void 0;
4
+ const tabbable_1 = require("tabbable");
5
+ function isFocusable(el) {
6
+ return (0, tabbable_1.isFocusable)(el, { displayCheck: 'none' });
7
+ }
8
+ exports.isFocusable = isFocusable;
@@ -0,0 +1,9 @@
1
+ import type { ARIAVersion, Matches, MLMLSpec } from '../types';
2
+ import type { ARIA } from '../types/aria';
3
+ export declare function getARIA(
4
+ specs: Readonly<MLMLSpec>,
5
+ localName: string,
6
+ namespace: string | null,
7
+ version: ARIAVersion,
8
+ matches: Matches,
9
+ ): Omit<ARIA, ARIAVersion | 'conditions'> | null;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getARIA = void 0;
4
+ const html_spec_1 = require("../specs/html-spec");
5
+ const resolve_version_1 = require("../specs/resolve-version");
6
+ const cache = new Map();
7
+ function getARIA(specs, localName, namespace, version, matches) {
8
+ var _a, _b, _c, _d, _e;
9
+ const aria = getVersionResolvedARIA(specs, localName, namespace, version);
10
+ if (!aria) {
11
+ return null;
12
+ }
13
+ const conditions = aria.conditions;
14
+ if (!conditions) {
15
+ return aria;
16
+ }
17
+ const conds = Object.keys(conditions);
18
+ let { implicitRole, permittedRoles, implicitProperties, properties, namingProhibited } = aria;
19
+ for (const cond of conds) {
20
+ if (!matches(cond)) {
21
+ continue;
22
+ }
23
+ const condARIA = conditions[cond];
24
+ implicitRole = (_a = condARIA.implicitRole) !== null && _a !== void 0 ? _a : implicitRole;
25
+ permittedRoles = (_b = condARIA.permittedRoles) !== null && _b !== void 0 ? _b : permittedRoles;
26
+ implicitProperties = (_c = condARIA.implicitProperties) !== null && _c !== void 0 ? _c : implicitProperties;
27
+ properties = (_d = condARIA.properties) !== null && _d !== void 0 ? _d : properties;
28
+ namingProhibited = (_e = condARIA.namingProhibited) !== null && _e !== void 0 ? _e : namingProhibited;
29
+ }
30
+ return {
31
+ implicitRole,
32
+ permittedRoles,
33
+ implicitProperties,
34
+ properties,
35
+ namingProhibited,
36
+ };
37
+ }
38
+ exports.getARIA = getARIA;
39
+ function getVersionResolvedARIA(specs, localName, namespace, version) {
40
+ var _a;
41
+ const key = localName + namespace + version;
42
+ let aria = cache.get(key);
43
+ if (aria !== undefined) {
44
+ return aria;
45
+ }
46
+ const spec = (_a = (0, html_spec_1.htmlSpec)(specs, localName, namespace)) === null || _a === void 0 ? void 0 : _a.aria;
47
+ if (!spec) {
48
+ cache.set(key, null);
49
+ return null;
50
+ }
51
+ aria = (0, resolve_version_1.resolveVersion)(spec, version);
52
+ cache.set(key, aria);
53
+ return aria;
54
+ }
@@ -0,0 +1,2 @@
1
+ import type { MLMLSpec } from '../types';
2
+ export declare function getAttrSpecs(el: Element, schema: MLMLSpec): import("../types").Attribute[] | null;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAttrSpecs = void 0;
4
+ const get_attr_specs_1 = require("../specs/get-attr-specs");
5
+ function getAttrSpecs(el, schema) {
6
+ return (0, get_attr_specs_1.getAttrSpecs)(el.localName, el.namespaceURI, schema);
7
+ }
8
+ exports.getAttrSpecs = getAttrSpecs;
@@ -0,0 +1,2 @@
1
+ import type { ARIAVersion, ComputedRole, MLMLSpec } from '../types';
2
+ export declare function getComputedRole(specs: Readonly<MLMLSpec>, el: Element, version: ARIAVersion): ComputedRole;
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getComputedRole = void 0;
4
+ const aria_specs_1 = require("../specs/aria-specs");
5
+ const is_presentational_1 = require("../specs/is-presentational");
6
+ const get_attr_specs_1 = require("./get-attr-specs");
7
+ const get_explicit_role_1 = require("./get-explicit-role");
8
+ const get_implicit_role_1 = require("./get-implicit-role");
9
+ const get_non_presentational_ancestor_1 = require("./get-non-presentational-ancestor");
10
+ const has_required_owned_elements_1 = require("./has-required-owned-elements");
11
+ const may_be_focusable_1 = require("./may-be-focusable");
12
+ function getComputedRole(specs, el, version) {
13
+ var _a, _b, _c, _d;
14
+ const implicitRole = (0, get_implicit_role_1.getImplicitRole)(specs, el, version);
15
+ const explicitRole = (0, get_explicit_role_1.getExplicitRole)(specs, el, version);
16
+ const computedRole = explicitRole.role ? explicitRole : implicitRole;
17
+ /**
18
+ * Presentational Roles Conflict Resolution
19
+ *
20
+ * @see https://www.w3.org/TR/wai-aria/#conflict_resolution_presentation_none
21
+ * @see https://w3c.github.io/aria/#conflict_resolution_presentation_none
22
+ */
23
+ /**
24
+ * > If the action of exposing the explicit role
25
+ * > causes the accessibility tree to be malformed,
26
+ * > the expected results are undefined.
27
+ *
28
+ * Determines whether the context is valid.
29
+ * ⚠ THE SPECIFICATION HAS AN ISSUE
30
+ * that has not decided whether the context is a parent or an ancestor.
31
+ *
32
+ * @see https://github.com/w3c/aria/issues/1033
33
+ * @see https://github.com/w3c/aria/issues/748
34
+ * @see https://github.com/w3c/aria/pull/1162
35
+ * @see https://github.com/w3c/aria/pull/1213
36
+ *
37
+ * Currently, this process interprets that as A PARENT
38
+ * because it wants to be near to HTML semantics.
39
+ * However, the presentational role behaves transparently
40
+ * according to the sample code in WAI-ARIA specification.
41
+ */
42
+ if ((_a = computedRole.role) === null || _a === void 0 ? void 0 : _a.requiredContextRole.length) {
43
+ const nonPresentationalAncestor = (0, get_non_presentational_ancestor_1.getNonPresentationalAncestor)(el, specs, version);
44
+ if (!nonPresentationalAncestor.role) {
45
+ return {
46
+ el,
47
+ role: null,
48
+ errorType: 'NO_OWNER',
49
+ };
50
+ }
51
+ if (!((_b = computedRole.role) === null || _b === void 0 ? void 0 : _b.requiredContextRole.includes(nonPresentationalAncestor.role.name))) {
52
+ return {
53
+ el,
54
+ role: null,
55
+ errorType: 'INVALID_REQUIRED_CONTEXT_ROLE',
56
+ };
57
+ }
58
+ }
59
+ if (computedRole.role && !(0, is_presentational_1.isPresentational)(computedRole.role.name)) {
60
+ return computedRole;
61
+ }
62
+ /**
63
+ * > If an element is focusable,
64
+ * > user agents MUST ignore the presentation/none role
65
+ * > and expose the element with its implicit role,
66
+ * > in order to ensure that the element is operable.
67
+ *
68
+ * With the issue: What does focusable or otherwise interactive mean](https://github.com/w3c/aria/issues/1192)
69
+ *
70
+ * - Focus: https://html.spec.whatwg.org/multipage/interaction.html#focus
71
+ * - Interactive content: https://html.spec.whatwg.org/multipage/dom.html#interactive-content
72
+ */
73
+ if (
74
+ /**
75
+ * If interactive element
76
+ *
77
+ * 1. It may be focusable
78
+ *
79
+ * THIS CONDITION IS ALMOST MEANINGLESS.
80
+ * Because it has already been determined that
81
+ * the interactive elements can not specify the presentational role
82
+ * in the previous processing that computes the permitted role (`getExplicitRole`).
83
+ */
84
+ (0, may_be_focusable_1.mayBeFocusable)(el, specs) &&
85
+ /**
86
+ * 2. No disabled
87
+ */
88
+ !someAncestors(el, p => isEnabledAttr(p, specs, 'disabled')) &&
89
+ /**
90
+ * 3. No inert
91
+ */
92
+ !someAncestors(el, p => isEnabledAttr(p, specs, 'inert')) &&
93
+ /**
94
+ * 4. No hidden
95
+ */
96
+ !someAncestors(el, p => isEnabledAttr(p, specs, 'hidden'))) {
97
+ return {
98
+ ...implicitRole,
99
+ errorType: 'INTERACTIVE_ELEMENT_MUST_NOT_BE_PRESENTATIONAL',
100
+ };
101
+ }
102
+ /**
103
+ * > If a required owned element has an explicit non-presentational role,
104
+ * > user agents MUST ignore an inherited presentational role
105
+ * > and expose the element with its explicit role.
106
+ *
107
+ * In other words,
108
+ * if the element has `role=presentation` and
109
+ * the role of the parent element has a required owned element,
110
+ * `role=presentation` is to be ignored absolutely.
111
+ */
112
+ if (explicitRole.role) {
113
+ const nonPresentationalAncestor = (0, get_non_presentational_ancestor_1.getNonPresentationalAncestor)(el, specs, version);
114
+ if ((_c = nonPresentationalAncestor.role) === null || _c === void 0 ? void 0 : _c.requiredOwnedElements.length) {
115
+ if (nonPresentationalAncestor.role.requiredOwnedElements.some(expected => {
116
+ // const ancestor = nonPresentationalAncestor.el;
117
+ // const ancestorImplicitRole = getImplicitRole(specs, ancestor, version);
118
+ // console.log({ nonPresentationalAncestor, ancestorImplicitRole });
119
+ return (0, has_required_owned_elements_1.isRequiredOwnedElement)(implicitRole, expected, specs, version);
120
+ })) {
121
+ return {
122
+ ...implicitRole,
123
+ errorType: 'REQUIRED_OWNED_ELEMENT_MUST_NOT_BE_PRESENTATIONAL',
124
+ };
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * > If an element has global WAI-ARIA states or properties,
130
+ * > user agents MUST ignore the presentation role
131
+ * > and instead expose the element's implicit role.
132
+ * > However, if an element has only non-global,
133
+ * > role-specific WAI-ARIA states or properties,
134
+ * > the element MUST NOT be exposed
135
+ * > unless the presentational role is inherited
136
+ * > and an explicit non-presentational role is applied.
137
+ */
138
+ const { props } = (0, aria_specs_1.ariaSpecs)(specs, version);
139
+ for (const attr of Array.from(el.attributes)) {
140
+ if ((_d = props.find(p => p.name === attr.name)) === null || _d === void 0 ? void 0 : _d.isGlobal) {
141
+ return {
142
+ ...implicitRole,
143
+ errorType: 'GLOBAL_PROP_MUST_NOT_BE_PRESENTATIONAL',
144
+ };
145
+ }
146
+ }
147
+ return computedRole;
148
+ }
149
+ exports.getComputedRole = getComputedRole;
150
+ /**
151
+ * The attribute is available in its owner element,
152
+ * it has the attribute.
153
+ */
154
+ function isEnabledAttr(el, specs, attrName) {
155
+ const attrs = (0, get_attr_specs_1.getAttrSpecs)(el, specs);
156
+ const attr = attrs === null || attrs === void 0 ? void 0 : attrs.find(attr => attr.name === attrName);
157
+ return !!attr && el.hasAttribute(attrName);
158
+ }
159
+ /**
160
+ * Determines whether some ancestors match the condition that the specified callback function.
161
+ */
162
+ function someAncestors(el, predicate) {
163
+ const list = [];
164
+ let current = el;
165
+ while (current) {
166
+ list.push(current);
167
+ current = current.parentElement;
168
+ }
169
+ return list.some(predicate);
170
+ }
@@ -0,0 +1,2 @@
1
+ import type { ARIAVersion, ComputedRole, MLMLSpec } from '../types';
2
+ export declare function getExplicitRole(specs: MLMLSpec, el: Element, version: ARIAVersion): ComputedRole;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getExplicitRole = void 0;
4
+ const get_role_spec_1 = require("../specs/get-role-spec");
5
+ const resolve_namespace_1 = require("../utils/resolve-namespace");
6
+ const get_permitted_roles_1 = require("./get-permitted-roles");
7
+ function getExplicitRole(specs, el, version) {
8
+ const roleValue = el.getAttribute('role');
9
+ const roleNames = (roleValue === null || roleValue === void 0 ? void 0 : roleValue.toLowerCase().trim().split(/\s+/g)) || [];
10
+ const permittedRoles = (0, get_permitted_roles_1.getPermittedRoles)(el, version, specs);
11
+ const { namespaceURI } = (0, resolve_namespace_1.resolveNamespace)(el.localName, el.namespaceURI);
12
+ let error = 'NO_EXPLICIT';
13
+ /**
14
+ * Resolve from values and **Handling Author Errors**
15
+ *
16
+ * @see https://w3c.github.io/aria/#document-handling_author-errors_roles
17
+ */
18
+ for (const roleName of roleNames) {
19
+ const spec = (0, get_role_spec_1.getRoleSpec)(specs, roleName, namespaceURI, version);
20
+ /**
21
+ * If `spec` is null, the role DOES NOT EXIST.
22
+ *
23
+ * > If the role attribute contains no tokens matching the name
24
+ * > of a non-abstract WAI-ARIA role,
25
+ * > the user agent MUST treat the element as
26
+ * > if no role had been provided. For example,
27
+ * > <table role="foo"> should be exposed
28
+ * > in the same way as <table> and <input type="text" role="structure">
29
+ * > in the same way as <input type="text">.
30
+ */
31
+ if (!spec) {
32
+ error = 'ROLE_NO_EXISTS';
33
+ continue;
34
+ }
35
+ /**
36
+ * > As stated in the Definition of Roles section,
37
+ * > it is considered an authoring error to use abstract roles in content.
38
+ * > User agents MUST NOT map abstract roles
39
+ * > via the standard role mechanism of the accessibility API.
40
+ */
41
+ if (spec.isAbstract) {
42
+ error = 'ABSTRACT';
43
+ continue;
44
+ }
45
+ /**
46
+ * Whether the role is the permitted role according to ARIA in HTML.
47
+ */
48
+ if (!permittedRoles.some(r => r.name === roleName)) {
49
+ error = 'NO_PERMITTED';
50
+ continue;
51
+ }
52
+ /**
53
+ * > Certain landmark roles require names from authors.
54
+ * > In situations where an author has not specified names for these landmarks,
55
+ * > it is considered an authoring error.
56
+ * > The user agent MUST treat such elements as if no role had been provided.
57
+ * > If a valid fallback role had been specified,
58
+ * > or if the element had an implicit ARIA role,
59
+ * > then user agents would continue to expose that role, instead.
60
+ */
61
+ if (isLandmarkRole(spec) && !isValidLandmarkRole(el, spec)) {
62
+ error = 'INVALID_LANDMARK';
63
+ continue;
64
+ }
65
+ /**
66
+ * Otherwise
67
+ */
68
+ return {
69
+ el,
70
+ role: {
71
+ ...spec,
72
+ isImplicit: false,
73
+ },
74
+ };
75
+ }
76
+ return {
77
+ el,
78
+ role: null,
79
+ errorType: error,
80
+ };
81
+ }
82
+ exports.getExplicitRole = getExplicitRole;
83
+ function isLandmarkRole(role) {
84
+ return role === null || role === void 0 ? void 0 : role.superClassRoles.some(su => su.name === 'landmark');
85
+ }
86
+ function isValidLandmarkRole(el, role) {
87
+ if (!role.accessibleNameRequired) {
88
+ return true;
89
+ }
90
+ if (role.accessibleNameFromAuthor) {
91
+ if (el.getAttribute('aria-label')) {
92
+ return true;
93
+ }
94
+ const id = el.getAttribute('aria-labelledby');
95
+ if (id && el.ownerDocument.getElementById(id)) {
96
+ return true;
97
+ }
98
+ }
99
+ // The landmark role does not require names from the content
100
+ // if (role.accessibleNameFromContent) {}
101
+ return false;
102
+ }
@@ -0,0 +1,3 @@
1
+ import type { ARIAVersion, ComputedRole, MLMLSpec } from '../types';
2
+ export declare function getImplicitRole(specs: Readonly<MLMLSpec>, el: Element, version: ARIAVersion): ComputedRole;
3
+ export declare function getImplicitRoleName(el: Element, version: ARIAVersion, specs: Readonly<MLMLSpec>): import("..").ImplicitRole;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getImplicitRoleName = exports.getImplicitRole = void 0;
4
+ const get_implicit_role_1 = require("../specs/get-implicit-role");
5
+ const get_role_spec_1 = require("../specs/get-role-spec");
6
+ const resolve_namespace_1 = require("../utils/resolve-namespace");
7
+ function getImplicitRole(specs, el, version) {
8
+ const implicitRole = getImplicitRoleName(el, version, specs);
9
+ if (implicitRole === false) {
10
+ // No Corresponding Role
11
+ return {
12
+ el,
13
+ role: null,
14
+ };
15
+ }
16
+ const { namespaceURI } = (0, resolve_namespace_1.resolveNamespace)(el.localName, el.namespaceURI);
17
+ const spec = (0, get_role_spec_1.getRoleSpec)(specs, implicitRole, namespaceURI, version);
18
+ if (!spec) {
19
+ return {
20
+ el,
21
+ role: null,
22
+ errorType: 'IMPLICIT_ROLE_NAMESPACE_ERROR',
23
+ };
24
+ }
25
+ return {
26
+ el,
27
+ role: {
28
+ ...spec,
29
+ isImplicit: true,
30
+ },
31
+ };
32
+ }
33
+ exports.getImplicitRole = getImplicitRole;
34
+ function getImplicitRoleName(el, version, specs) {
35
+ return (0, get_implicit_role_1.getImplicitRole)(specs, el.localName, el.namespaceURI, version, el.matches.bind(el));
36
+ }
37
+ exports.getImplicitRoleName = getImplicitRoleName;
@@ -0,0 +1,5 @@
1
+ import type { ARIAVersion, MLMLSpec } from '../types';
2
+ export declare function getNonPresentationalAncestor(el: Element, specs: MLMLSpec, version: ARIAVersion): import("../types").ComputedRole | {
3
+ el: null;
4
+ role: null;
5
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNonPresentationalAncestor = void 0;
4
+ const is_presentational_1 = require("../specs/is-presentational");
5
+ const get_computed_role_1 = require("./get-computed-role");
6
+ function getNonPresentationalAncestor(el, specs, version) {
7
+ var _a;
8
+ let ancestor = el.parentElement;
9
+ while (ancestor) {
10
+ const ancestorRole = (0, get_computed_role_1.getComputedRole)(specs, ancestor, version);
11
+ if (!(0, is_presentational_1.isPresentational)((_a = ancestorRole.role) === null || _a === void 0 ? void 0 : _a.name)) {
12
+ return ancestorRole;
13
+ }
14
+ ancestor = ancestor.parentElement;
15
+ }
16
+ return {
17
+ el: ancestor,
18
+ role: null,
19
+ };
20
+ }
21
+ exports.getNonPresentationalAncestor = getNonPresentationalAncestor;
@@ -0,0 +1,5 @@
1
+ import type { ARIAVersion, MLMLSpec } from '../types';
2
+ export declare function getPermittedRoles(el: Element, version: ARIAVersion, specs: Readonly<MLMLSpec>): {
3
+ name: string;
4
+ deprecated?: boolean | undefined;
5
+ }[];
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPermittedRoles = void 0;
4
+ const get_permitted_roles_1 = require("../specs/get-permitted-roles");
5
+ function getPermittedRoles(el, version, specs) {
6
+ return (0, get_permitted_roles_1.getPermittedRoles)(specs, el.localName, el.namespaceURI, version, el.matches.bind(el));
7
+ }
8
+ exports.getPermittedRoles = getPermittedRoles;
@@ -0,0 +1,2 @@
1
+ import type { MLMLSpec } from '../types';
2
+ export declare function getSpec(el: Element, schema: MLMLSpec): import("../types").ElementSpec | null;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSpec = void 0;
4
+ const get_spec_by_tag_name_1 = require("../specs/get-spec-by-tag-name");
5
+ function getSpec(el, schema) {
6
+ return (0, get_spec_by_tag_name_1.getSpecByTagName)(schema, el.localName, el.namespaceURI);
7
+ }
8
+ exports.getSpec = getSpec;
@@ -0,0 +1,3 @@
1
+ import type { ARIAVersion, ComputedRole, MLMLSpec } from '../types';
2
+ export declare function hasRequiredOwnedElement(el: Element, specs: Readonly<MLMLSpec>, version: ARIAVersion): boolean;
3
+ export declare function isRequiredOwnedElement(owned: ComputedRole, query: string, specs: MLMLSpec, version: ARIAVersion): boolean;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRequiredOwnedElement = exports.hasRequiredOwnedElement = void 0;
4
+ const is_presentational_1 = require("../specs/is-presentational");
5
+ const get_computed_role_1 = require("./get-computed-role");
6
+ const get_explicit_role_1 = require("./get-explicit-role");
7
+ const get_implicit_role_1 = require("./get-implicit-role");
8
+ function hasRequiredOwnedElement(el, specs, version) {
9
+ /**
10
+ * The element has aria-owns which means it may have owned elements.
11
+ *
12
+ * THIS CONDITION IS PARTIAL SUPPORT.
13
+ */
14
+ if (el.hasAttribute('aria-owns')) {
15
+ // FIXME
16
+ return true;
17
+ }
18
+ /**
19
+ * Otherwise, traverses descendants to find owned elements.
20
+ */
21
+ const computed = (0, get_computed_role_1.getComputedRole)(specs, el, version);
22
+ if (!computed.role || computed.role.requiredOwnedElements.length === 0) {
23
+ return true;
24
+ }
25
+ for (const expectRole of computed.role.requiredOwnedElements) {
26
+ for (const owned of getClosestNonPresentationalDescendants(el, specs, version)) {
27
+ if (isRequiredOwnedElement(owned, expectRole, specs, version)) {
28
+ return true;
29
+ }
30
+ }
31
+ }
32
+ return false;
33
+ }
34
+ exports.hasRequiredOwnedElement = hasRequiredOwnedElement;
35
+ function isRequiredOwnedElement(owned, query, specs, version) {
36
+ var _a, _b;
37
+ const [baseRole, owningRole] = query.split(' > ');
38
+ if (((_a = owned.role) === null || _a === void 0 ? void 0 : _a.name) !== baseRole) {
39
+ return false;
40
+ }
41
+ if (!owningRole) {
42
+ return true;
43
+ }
44
+ for (const owning of getClosestNonPresentationalDescendants(owned.el, specs, version)) {
45
+ if (((_b = owning.role) === null || _b === void 0 ? void 0 : _b.name) === owningRole) {
46
+ return true;
47
+ }
48
+ }
49
+ return false;
50
+ }
51
+ exports.isRequiredOwnedElement = isRequiredOwnedElement;
52
+ /**
53
+ * Gets the list of closest non-presentational descendants.
54
+ * ⚠ THE SPECIFICATION HAS AN ISSUE
55
+ * that has not decided whether the owned element is a child or a descendant.
56
+ *
57
+ * @see https://github.com/w3c/aria/issues/1033
58
+ * @see https://github.com/w3c/aria/issues/748
59
+ * @see https://github.com/w3c/aria/pull/1162
60
+ * @see https://github.com/w3c/aria/pull/1213
61
+ *
62
+ * Currently, this process interprets that as A CHILD
63
+ * because it wants to be near to HTML semantics.
64
+ * However, the presentational role behaves transparently
65
+ * according to the sample code in WAI-ARIA specification.
66
+ */
67
+ function getClosestNonPresentationalDescendants(el, specs, version) {
68
+ var _a;
69
+ const owned = [];
70
+ for (const child of Array.from(el.children)) {
71
+ const implicitRole = (0, get_implicit_role_1.getImplicitRole)(specs, child, version);
72
+ const explicitRole = (0, get_explicit_role_1.getExplicitRole)(specs, child, version);
73
+ const computed = explicitRole.role ? explicitRole : implicitRole;
74
+ if ((0, is_presentational_1.isPresentational)((_a = computed.role) === null || _a === void 0 ? void 0 : _a.name)) {
75
+ owned.push(...getClosestNonPresentationalDescendants(child, specs, version));
76
+ continue;
77
+ }
78
+ owned.push({ ...computed, el: child });
79
+ }
80
+ return owned;
81
+ }
@@ -0,0 +1,2 @@
1
+ import type { MLMLSpec } from '../types';
2
+ export declare function mayBeFocusable(el: Element, specs: Readonly<MLMLSpec>): boolean;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mayBeFocusable = void 0;
4
+ const get_selectors_by_content_model_category_1 = require("../specs/get-selectors-by-content-model-category");
5
+ function mayBeFocusable(el, specs) {
6
+ return [
7
+ /**
8
+ * Interactive content
9
+ *
10
+ * @see https://html.spec.whatwg.org/multipage/dom.html#interactive-content
11
+ */
12
+ ...(0, get_selectors_by_content_model_category_1.getSelectorsByContentModelCategory)(specs, '#interactive'),
13
+ /**
14
+ * Interaction
15
+ *
16
+ * @see https://html.spec.whatwg.org/multipage/interaction.html
17
+ */
18
+ '[tabindex]',
19
+ '[contenteditable]:not([contenteditable="false" i])',
20
+ ].some(selector => el.matches(selector));
21
+ }
22
+ exports.mayBeFocusable = mayBeFocusable;
package/lib/index.d.ts CHANGED
@@ -1,7 +1,18 @@
1
- export * from './permitted-structres';
2
- export * from './attributes';
3
- export * from './get-attr-specs';
4
- export * from './get-spec-by-tag-name';
5
- export * from './get-spec';
6
- export * from './get-ns';
1
+ export * from './dom-traverse/accname-computation';
2
+ export * from './dom-traverse/get-attr-specs';
3
+ export * from './dom-traverse/get-computed-role';
4
+ export * from './dom-traverse/get-implicit-role';
5
+ export * from './dom-traverse/get-permitted-roles';
6
+ export * from './dom-traverse/get-spec';
7
+ export * from './dom-traverse/has-required-owned-elements';
8
+ export * from './dom-traverse/may-be-focusable';
9
+ export * from './specs/aria-specs';
10
+ export * from './specs/content-model-category-to-tag-names';
11
+ export * from './specs/get-role-spec';
12
+ export * from './specs/get-spec-by-tag-name';
13
+ export * from './specs/schema-to-spec';
7
14
  export * from './types';
15
+ export * from './types/aria';
16
+ export * from './types/attributes';
17
+ export * from './types/permitted-structres';
18
+ export * from './utils/resolve-namespace';
package/lib/index.js CHANGED
@@ -1,10 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- (0, tslib_1.__exportStar)(require("./permitted-structres"), exports);
5
- (0, tslib_1.__exportStar)(require("./attributes"), exports);
6
- (0, tslib_1.__exportStar)(require("./get-attr-specs"), exports);
7
- (0, tslib_1.__exportStar)(require("./get-spec-by-tag-name"), exports);
8
- (0, tslib_1.__exportStar)(require("./get-spec"), exports);
9
- (0, tslib_1.__exportStar)(require("./get-ns"), exports);
10
- (0, tslib_1.__exportStar)(require("./types"), exports);
4
+ tslib_1.__exportStar(require("./dom-traverse/accname-computation"), exports);
5
+ tslib_1.__exportStar(require("./dom-traverse/get-attr-specs"), exports);
6
+ tslib_1.__exportStar(require("./dom-traverse/get-computed-role"), exports);
7
+ tslib_1.__exportStar(require("./dom-traverse/get-implicit-role"), exports);
8
+ tslib_1.__exportStar(require("./dom-traverse/get-permitted-roles"), exports);
9
+ tslib_1.__exportStar(require("./dom-traverse/get-spec"), exports);
10
+ tslib_1.__exportStar(require("./dom-traverse/has-required-owned-elements"), exports);
11
+ tslib_1.__exportStar(require("./dom-traverse/may-be-focusable"), exports);
12
+ tslib_1.__exportStar(require("./specs/aria-specs"), exports);
13
+ tslib_1.__exportStar(require("./specs/content-model-category-to-tag-names"), exports);
14
+ tslib_1.__exportStar(require("./specs/get-role-spec"), exports);
15
+ tslib_1.__exportStar(require("./specs/get-spec-by-tag-name"), exports);
16
+ tslib_1.__exportStar(require("./specs/schema-to-spec"), exports);
17
+ tslib_1.__exportStar(require("./types"), exports);
18
+ tslib_1.__exportStar(require("./types/aria"), exports);
19
+ tslib_1.__exportStar(require("./types/attributes"), exports);
20
+ tslib_1.__exportStar(require("./types/permitted-structres"), exports);
21
+ tslib_1.__exportStar(require("./utils/resolve-namespace"), exports);