praxis-kit 3.1.1 → 4.0.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/README.md +141 -126
- package/dist/chunk-TJRHF6MS.js +2777 -0
- package/dist/codemod/index.js +20 -20
- package/dist/contract/index.d.ts +2 -258
- package/dist/contract/index.js +158 -1190
- package/dist/eslint/index.js +403 -178
- package/dist/lit/index.d.ts +5 -235
- package/dist/lit/index.js +1384 -747
- package/dist/merge-refs-DUuHyTRO.d.ts +144 -0
- package/dist/preact/index.d.ts +9 -254
- package/dist/preact/index.js +1686 -1025
- package/dist/react/index.d.ts +23 -11
- package/dist/react/index.js +115 -116
- package/dist/react/legacy.d.ts +7 -11
- package/dist/react/legacy.js +116 -136
- package/dist/solid/index.d.ts +5 -250
- package/dist/solid/index.js +1476 -706
- package/dist/svelte/index.d.ts +5 -325
- package/dist/svelte/index.js +1407 -725
- package/dist/tailwind/index.d.ts +5 -4
- package/dist/tailwind/index.js +366 -90
- package/dist/ts-plugin/index.cjs +5 -5
- package/dist/vite-plugin/index.d.ts +91 -120
- package/dist/vite-plugin/index.js +568 -347
- package/dist/vue/index.d.ts +12 -257
- package/dist/vue/index.js +1701 -926
- package/dist/web/index.d.ts +9 -238
- package/dist/web/index.js +1369 -732
- package/package.json +4 -3
- package/dist/chunk-6RJN5B6L.js +0 -2221
- package/dist/merge-refs-BKyE8h8M.d.ts +0 -381
package/dist/svelte/index.js
CHANGED
|
@@ -1,44 +1,14 @@
|
|
|
1
|
-
// ../../lib/
|
|
2
|
-
function defineContractComponent(options) {
|
|
3
|
-
return (factory) => factory(options);
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
// ../core/dist/chunk-KKSHJDE7.js
|
|
1
|
+
// ../../lib/primitive/src/tag/resolve-tag.ts
|
|
7
2
|
function makeResolveTag(defaultTag) {
|
|
8
3
|
return function tag(as) {
|
|
9
4
|
return as ?? defaultTag;
|
|
10
5
|
};
|
|
11
6
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if ("string" == typeof e || "number" == typeof e) n += e;
|
|
18
|
-
else if ("object" == typeof e) if (Array.isArray(e)) {
|
|
19
|
-
var o = e.length;
|
|
20
|
-
for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
|
|
21
|
-
} else for (f in e) e[f] && (n && (n += " "), n += f);
|
|
22
|
-
return n;
|
|
23
|
-
}
|
|
24
|
-
function clsx() {
|
|
25
|
-
for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
|
|
26
|
-
return n;
|
|
27
|
-
}
|
|
28
|
-
function cn(...inputs) {
|
|
29
|
-
return clsx(...inputs);
|
|
30
|
-
}
|
|
31
|
-
function mergeProps(defaultProps, props) {
|
|
32
|
-
return {
|
|
33
|
-
...defaultProps ?? {},
|
|
34
|
-
...props
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function isNull(value) {
|
|
38
|
-
return value === null;
|
|
39
|
-
}
|
|
40
|
-
function isObject(value) {
|
|
41
|
-
return !isNull(value) && typeof value === "object";
|
|
7
|
+
|
|
8
|
+
// ../../lib/primitive/src/utils/is-object.ts
|
|
9
|
+
function isObject(value, excludeArrays = false) {
|
|
10
|
+
if (value === null || typeof value !== "object") return false;
|
|
11
|
+
return excludeArrays ? !Array.isArray(value) : true;
|
|
42
12
|
}
|
|
43
13
|
function isString(value) {
|
|
44
14
|
return typeof value === "string";
|
|
@@ -46,308 +16,197 @@ function isString(value) {
|
|
|
46
16
|
function isNumber(value) {
|
|
47
17
|
return typeof value === "number";
|
|
48
18
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const patched = normalizers.reduce(
|
|
54
|
-
(acc, normalizer) => ({ ...acc, ...normalizer(acc) }),
|
|
55
|
-
props
|
|
56
|
-
);
|
|
57
|
-
return fn ? fn(patched) : patched;
|
|
58
|
-
});
|
|
19
|
+
|
|
20
|
+
// ../../lib/primitive/src/utils/assert-never.ts
|
|
21
|
+
function assertNever(value) {
|
|
22
|
+
throw new Error(`Unexpected value: ${String(value)}`);
|
|
59
23
|
}
|
|
60
|
-
|
|
61
|
-
|
|
24
|
+
|
|
25
|
+
// ../../lib/primitive/src/utils/cn.ts
|
|
26
|
+
import { clsx } from "clsx";
|
|
27
|
+
function cn(...inputs) {
|
|
28
|
+
return clsx(...inputs);
|
|
62
29
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
...whenDefined("baseClassName", styling?.base),
|
|
74
|
-
...whenDefined("tagMap", styling?.tags),
|
|
75
|
-
...whenDefined("recipeMap", styling?.presets),
|
|
76
|
-
...whenDefined("variants", styling?.variants),
|
|
77
|
-
...whenDefined("defaultVariants", styling?.defaults),
|
|
78
|
-
...whenDefined("compoundVariants", styling?.compounds),
|
|
79
|
-
...whenDefined("normalizeFn", composedNormalizeFn),
|
|
80
|
-
...whenDefined("ariaRules", enforcement?.aria),
|
|
81
|
-
...whenDefined("childRules", enforcement?.children),
|
|
82
|
-
...whenDefined("allowedAs", enforcement?.allowedAs),
|
|
83
|
-
...whenDefined("precomputedClasses", styling?.precomputedClasses)
|
|
84
|
-
});
|
|
30
|
+
|
|
31
|
+
// ../../lib/primitive/src/utils/iterate.ts
|
|
32
|
+
function find(iterable, callback) {
|
|
33
|
+
for (const value of iterable) {
|
|
34
|
+
const result = callback(value);
|
|
35
|
+
if (result != null) {
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
85
40
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
41
|
+
function some(iterable, predicate) {
|
|
42
|
+
for (const value of iterable) {
|
|
43
|
+
if (predicate(value)) return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
91
46
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const checkSelection = (label2, selection) => {
|
|
98
|
-
const record = selection;
|
|
99
|
-
for (const dim in record) {
|
|
100
|
-
const value = record[dim];
|
|
101
|
-
if (value === void 0 || value === null) continue;
|
|
102
|
-
if (!variants || !Object.hasOwn(variants, dim)) {
|
|
103
|
-
report(strict, `${name}: ${label2} references unknown variant "${dim}".`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const states = variants[dim];
|
|
107
|
-
const stateKey = String(value);
|
|
108
|
-
if (!Object.hasOwn(states, stateKey)) {
|
|
109
|
-
report(
|
|
110
|
-
strict,
|
|
111
|
-
`${name}: ${label2} sets "${dim}" to unknown value "${stateKey}" (valid: ${Object.keys(states).join(", ")}).`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
47
|
+
function every(iterable, predicate) {
|
|
48
|
+
let index = 0;
|
|
49
|
+
for (const value of iterable) {
|
|
50
|
+
if (!predicate(value, index++)) {
|
|
51
|
+
return false;
|
|
114
52
|
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
function* filter(iterable, predicate) {
|
|
57
|
+
let index = 0;
|
|
58
|
+
for (const value of iterable) {
|
|
59
|
+
if (predicate(value, index++)) {
|
|
60
|
+
yield value;
|
|
120
61
|
}
|
|
121
62
|
}
|
|
122
|
-
if (resolved.defaultVariants) checkSelection("defaults", resolved.defaultVariants);
|
|
123
63
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
64
|
+
function* map(iterable, callback) {
|
|
65
|
+
let index = 0;
|
|
66
|
+
for (const value of iterable) {
|
|
67
|
+
yield callback(value, index++);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function forEach(iterable, callback) {
|
|
71
|
+
let index = 0;
|
|
72
|
+
for (const value of iterable) {
|
|
73
|
+
callback(value, index++);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function reduce(iterable, initial, callback) {
|
|
77
|
+
let accumulator = initial;
|
|
78
|
+
let index = 0;
|
|
79
|
+
for (const value of iterable) {
|
|
80
|
+
accumulator = callback(accumulator, value, index++);
|
|
81
|
+
}
|
|
82
|
+
return accumulator;
|
|
83
|
+
}
|
|
84
|
+
function collect(iterable, callback) {
|
|
85
|
+
const result = {};
|
|
86
|
+
let index = 0;
|
|
87
|
+
for (const value of iterable) {
|
|
88
|
+
const entry = callback(value, index++);
|
|
89
|
+
if (entry === null) {
|
|
90
|
+
return null;
|
|
145
91
|
}
|
|
146
|
-
|
|
92
|
+
result[entry[0]] = entry[1];
|
|
147
93
|
}
|
|
148
|
-
|
|
149
|
-
warned.add(message);
|
|
150
|
-
console.warn(message);
|
|
94
|
+
return result;
|
|
151
95
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
96
|
+
function findLast(value, callback) {
|
|
97
|
+
for (let index = value.length - 1; index >= 0; index--) {
|
|
98
|
+
const result = callback(value[index], index);
|
|
99
|
+
if (result != null) {
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
154
104
|
}
|
|
155
|
-
function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
105
|
+
function* items(collection) {
|
|
106
|
+
for (let i = 0; i < collection.length; i++) {
|
|
107
|
+
const item = collection.item(i);
|
|
108
|
+
if (item !== null) {
|
|
109
|
+
yield item;
|
|
110
|
+
}
|
|
161
111
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`${tag} Variant "${key}=${String(value)}" is not a defined value for the "${key}" dimension.`
|
|
172
|
-
);
|
|
112
|
+
}
|
|
113
|
+
function nodeList(list) {
|
|
114
|
+
return {
|
|
115
|
+
*[Symbol.iterator]() {
|
|
116
|
+
for (let i = 0; i < list.length; i++) {
|
|
117
|
+
const node = list.item(i);
|
|
118
|
+
if (node !== null) {
|
|
119
|
+
yield node;
|
|
120
|
+
}
|
|
173
121
|
}
|
|
174
122
|
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function mapEntries(m) {
|
|
126
|
+
return m.entries();
|
|
127
|
+
}
|
|
128
|
+
function set(s) {
|
|
129
|
+
return s.values();
|
|
130
|
+
}
|
|
131
|
+
function hasOwn(object, key) {
|
|
132
|
+
return Object.hasOwn(object, key);
|
|
133
|
+
}
|
|
134
|
+
function* entries(object) {
|
|
135
|
+
for (const key in object) {
|
|
136
|
+
if (!hasOwn(object, key)) continue;
|
|
137
|
+
yield [key, object[key]];
|
|
175
138
|
}
|
|
176
139
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
140
|
+
function* keys(object) {
|
|
141
|
+
for (const [key] of entries(object)) {
|
|
142
|
+
yield key;
|
|
143
|
+
}
|
|
179
144
|
}
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
145
|
+
function* values(object) {
|
|
146
|
+
for (const [, value] of entries(object)) {
|
|
147
|
+
yield value;
|
|
148
|
+
}
|
|
184
149
|
}
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (typeof plugin.pipeline !== "function")
|
|
192
|
-
panic(
|
|
193
|
-
`[praxis-kit] Plugin factory return value is missing a 'pipeline' function. Got pipeline: ${typeof plugin.pipeline}.`
|
|
194
|
-
);
|
|
150
|
+
function mapValues(object, callback) {
|
|
151
|
+
const result = {};
|
|
152
|
+
for (const [key, value] of entries(object)) {
|
|
153
|
+
result[key] = callback(value, key);
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
195
156
|
}
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (typeof result !== "string")
|
|
201
|
-
panic(`[praxis-kit] Plugin pipeline must return a string. Got: ${describe(result)}.`);
|
|
202
|
-
return result;
|
|
203
|
-
};
|
|
157
|
+
function forEachEntry(object, callback) {
|
|
158
|
+
for (const [key, value] of entries(object)) {
|
|
159
|
+
callback(key, value);
|
|
160
|
+
}
|
|
204
161
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (!factory) {
|
|
209
|
-
const createClassPipeline2 = capabilities?.createClassPipeline;
|
|
210
|
-
const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
|
|
211
|
-
return { pluginResult: void 0, classPipeline: classPipeline2 };
|
|
162
|
+
function forEachKey(object, callback) {
|
|
163
|
+
for (const key of keys(object)) {
|
|
164
|
+
callback(key);
|
|
212
165
|
}
|
|
213
|
-
const pluginResult = factory(resolved, strict);
|
|
214
|
-
assertPluginShape(pluginResult);
|
|
215
|
-
const classPipeline = guardPipeline(pluginResult.pipeline);
|
|
216
|
-
return { pluginResult, classPipeline };
|
|
217
166
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return mergeProps(resolved.defaultProps, props);
|
|
223
|
-
},
|
|
224
|
-
resolveClasses(tag, props, className, recipe) {
|
|
225
|
-
if (process.env.NODE_ENV !== "production") {
|
|
226
|
-
validateRenderProps(resolved, props, recipe);
|
|
227
|
-
}
|
|
228
|
-
return classPipeline(tag, props, className, recipe);
|
|
229
|
-
},
|
|
230
|
-
resolveAria(tag, props) {
|
|
231
|
-
if (!engine) return { props };
|
|
232
|
-
const result = engine.validate(tag, props);
|
|
233
|
-
return { props: result.props };
|
|
234
|
-
}
|
|
235
|
-
};
|
|
167
|
+
function forEachValue(object, callback) {
|
|
168
|
+
for (const value of values(object)) {
|
|
169
|
+
callback(value);
|
|
170
|
+
}
|
|
236
171
|
}
|
|
237
|
-
function
|
|
238
|
-
|
|
172
|
+
function forEachSet(s, callback) {
|
|
173
|
+
for (const value of s) {
|
|
174
|
+
callback(value);
|
|
175
|
+
}
|
|
239
176
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
177
|
+
var iterate = Object.freeze({
|
|
178
|
+
entries,
|
|
179
|
+
filter,
|
|
180
|
+
find,
|
|
181
|
+
findLast,
|
|
182
|
+
forEach,
|
|
183
|
+
forEachEntry,
|
|
184
|
+
forEachKey,
|
|
185
|
+
forEachSet,
|
|
186
|
+
forEachValue,
|
|
187
|
+
items,
|
|
188
|
+
keys,
|
|
189
|
+
map,
|
|
190
|
+
mapEntries,
|
|
191
|
+
mapValues,
|
|
192
|
+
nodeList,
|
|
193
|
+
reduce,
|
|
194
|
+
collect,
|
|
195
|
+
set,
|
|
196
|
+
some,
|
|
197
|
+
every,
|
|
198
|
+
values
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// ../../lib/primitive/src/utils/merge-props.ts
|
|
202
|
+
function mergeProps(defaultProps, props) {
|
|
203
|
+
return {
|
|
204
|
+
...defaultProps ?? {},
|
|
205
|
+
...props
|
|
206
|
+
};
|
|
266
207
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
"alertdialog",
|
|
270
|
-
"application",
|
|
271
|
-
"article",
|
|
272
|
-
"banner",
|
|
273
|
-
"blockquote",
|
|
274
|
-
"button",
|
|
275
|
-
"caption",
|
|
276
|
-
"cell",
|
|
277
|
-
"checkbox",
|
|
278
|
-
"code",
|
|
279
|
-
"columnheader",
|
|
280
|
-
"combobox",
|
|
281
|
-
"complementary",
|
|
282
|
-
"contentinfo",
|
|
283
|
-
"definition",
|
|
284
|
-
"deletion",
|
|
285
|
-
"dialog",
|
|
286
|
-
"document",
|
|
287
|
-
"emphasis",
|
|
288
|
-
"feed",
|
|
289
|
-
"figure",
|
|
290
|
-
"form",
|
|
291
|
-
"generic",
|
|
292
|
-
"grid",
|
|
293
|
-
"gridcell",
|
|
294
|
-
"group",
|
|
295
|
-
"heading",
|
|
296
|
-
"img",
|
|
297
|
-
"insertion",
|
|
298
|
-
"link",
|
|
299
|
-
"list",
|
|
300
|
-
"listbox",
|
|
301
|
-
"listitem",
|
|
302
|
-
"log",
|
|
303
|
-
"main",
|
|
304
|
-
"marquee",
|
|
305
|
-
"math",
|
|
306
|
-
"menu",
|
|
307
|
-
"menubar",
|
|
308
|
-
"menuitem",
|
|
309
|
-
"menuitemcheckbox",
|
|
310
|
-
"menuitemradio",
|
|
311
|
-
"meter",
|
|
312
|
-
"navigation",
|
|
313
|
-
"none",
|
|
314
|
-
"note",
|
|
315
|
-
"option",
|
|
316
|
-
"paragraph",
|
|
317
|
-
"presentation",
|
|
318
|
-
"progressbar",
|
|
319
|
-
"radio",
|
|
320
|
-
"radiogroup",
|
|
321
|
-
"region",
|
|
322
|
-
"row",
|
|
323
|
-
"rowgroup",
|
|
324
|
-
"rowheader",
|
|
325
|
-
"scrollbar",
|
|
326
|
-
"search",
|
|
327
|
-
"searchbox",
|
|
328
|
-
"separator",
|
|
329
|
-
"slider",
|
|
330
|
-
"spinbutton",
|
|
331
|
-
"status",
|
|
332
|
-
"strong",
|
|
333
|
-
"subscript",
|
|
334
|
-
"superscript",
|
|
335
|
-
"switch",
|
|
336
|
-
"tab",
|
|
337
|
-
"table",
|
|
338
|
-
"tablist",
|
|
339
|
-
"tabpanel",
|
|
340
|
-
"term",
|
|
341
|
-
"textbox",
|
|
342
|
-
"time",
|
|
343
|
-
"timer",
|
|
344
|
-
"toolbar",
|
|
345
|
-
"tooltip",
|
|
346
|
-
"tree",
|
|
347
|
-
"treegrid",
|
|
348
|
-
"treeitem"
|
|
349
|
-
];
|
|
350
|
-
var KNOWN_ARIA_ROLES_SET = new Set(KNOWN_ARIA_ROLES);
|
|
208
|
+
|
|
209
|
+
// ../../lib/primitive/src/constants/aria/global-aria-attributes.ts
|
|
351
210
|
var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
352
211
|
"aria-atomic",
|
|
353
212
|
"aria-busy",
|
|
@@ -367,29 +226,59 @@ var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
|
367
226
|
"aria-relevant",
|
|
368
227
|
"aria-roledescription"
|
|
369
228
|
]);
|
|
229
|
+
|
|
230
|
+
// ../../lib/primitive/src/constants/aria/implicit-role-record.ts
|
|
370
231
|
var IMPLICIT_ROLE_RECORD = {
|
|
232
|
+
// Landmarks
|
|
371
233
|
article: "article",
|
|
372
234
|
aside: "complementary",
|
|
373
235
|
footer: "contentinfo",
|
|
374
236
|
header: "banner",
|
|
375
237
|
main: "main",
|
|
376
238
|
nav: "navigation",
|
|
377
|
-
|
|
239
|
+
// Interactive
|
|
378
240
|
a: "link",
|
|
241
|
+
button: "button",
|
|
379
242
|
select: "listbox",
|
|
243
|
+
textarea: "textbox",
|
|
244
|
+
// Headings
|
|
380
245
|
h1: "heading",
|
|
381
246
|
h2: "heading",
|
|
382
247
|
h3: "heading",
|
|
383
248
|
h4: "heading",
|
|
384
249
|
h5: "heading",
|
|
385
250
|
h6: "heading",
|
|
251
|
+
// Lists
|
|
386
252
|
ul: "list",
|
|
387
253
|
ol: "list",
|
|
388
254
|
li: "listitem",
|
|
255
|
+
// Tables
|
|
389
256
|
table: "table",
|
|
390
257
|
tr: "row",
|
|
391
258
|
td: "cell",
|
|
392
|
-
th: "columnheader"
|
|
259
|
+
th: "columnheader",
|
|
260
|
+
// Structural / semantic
|
|
261
|
+
dialog: "dialog",
|
|
262
|
+
fieldset: "group",
|
|
263
|
+
figure: "figure",
|
|
264
|
+
meter: "meter",
|
|
265
|
+
output: "status",
|
|
266
|
+
progress: "progressbar"
|
|
267
|
+
};
|
|
268
|
+
var INPUT_TYPE_ROLE_MAP = {
|
|
269
|
+
checkbox: "checkbox",
|
|
270
|
+
radio: "radio",
|
|
271
|
+
range: "slider",
|
|
272
|
+
number: "spinbutton",
|
|
273
|
+
search: "searchbox",
|
|
274
|
+
text: "textbox",
|
|
275
|
+
email: "textbox",
|
|
276
|
+
tel: "textbox",
|
|
277
|
+
url: "textbox",
|
|
278
|
+
button: "button",
|
|
279
|
+
submit: "button",
|
|
280
|
+
reset: "button",
|
|
281
|
+
image: "button"
|
|
393
282
|
};
|
|
394
283
|
var STRONG_ROLES = [
|
|
395
284
|
"main",
|
|
@@ -401,6 +290,8 @@ var STRONG_ROLES = [
|
|
|
401
290
|
var STANDALONE_ROLES = ["article"];
|
|
402
291
|
var STRONG_ROLES_SET = new Set(STRONG_ROLES);
|
|
403
292
|
var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
|
|
293
|
+
|
|
294
|
+
// ../../lib/primitive/src/constants/aria/role-restricted-attributes.ts
|
|
404
295
|
var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
|
|
405
296
|
[
|
|
406
297
|
"aria-activedescendant",
|
|
@@ -550,9 +441,18 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
|
|
|
550
441
|
/* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
|
|
551
442
|
]
|
|
552
443
|
]);
|
|
444
|
+
|
|
445
|
+
// ../../lib/primitive/src/guards/foundational/is-defined.ts
|
|
553
446
|
function isUndefined(value) {
|
|
554
447
|
return value === void 0;
|
|
555
448
|
}
|
|
449
|
+
|
|
450
|
+
// ../../lib/primitive/src/guards/foundational/is-null.ts
|
|
451
|
+
function isNull(value) {
|
|
452
|
+
return value === null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
|
|
556
456
|
function isGlobalAriaAttribute(attr) {
|
|
557
457
|
return GLOBAL_ARIA_ATTRIBUTES.has(attr);
|
|
558
458
|
}
|
|
@@ -562,6 +462,8 @@ function isAriaAttributeValidForRole(attr, role) {
|
|
|
562
462
|
if (isUndefined(role)) return false;
|
|
563
463
|
return allowedRoles.has(role);
|
|
564
464
|
}
|
|
465
|
+
|
|
466
|
+
// ../../lib/primitive/src/guards/aria/is-aria-role.ts
|
|
565
467
|
function isStrongImplicitRole(tag) {
|
|
566
468
|
if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
|
|
567
469
|
return STRONG_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
|
|
@@ -570,116 +472,543 @@ function isStandaloneTag(tag) {
|
|
|
570
472
|
if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
|
|
571
473
|
return STANDALONE_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
|
|
572
474
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
article: "article",
|
|
577
|
-
aside: "complementary",
|
|
578
|
-
footer: "contentinfo",
|
|
579
|
-
header: "banner",
|
|
580
|
-
main: "main",
|
|
581
|
-
nav: "navigation",
|
|
582
|
-
button: "button",
|
|
583
|
-
a: "link",
|
|
584
|
-
select: "listbox",
|
|
585
|
-
h1: "heading",
|
|
586
|
-
h2: "heading",
|
|
587
|
-
h3: "heading",
|
|
588
|
-
h4: "heading",
|
|
589
|
-
h5: "heading",
|
|
590
|
-
h6: "heading",
|
|
591
|
-
ul: "list",
|
|
592
|
-
ol: "list",
|
|
593
|
-
li: "listitem",
|
|
594
|
-
table: "table",
|
|
595
|
-
tr: "row",
|
|
596
|
-
td: "cell",
|
|
597
|
-
th: "columnheader"
|
|
598
|
-
};
|
|
599
|
-
function getImplicitRole(tag) {
|
|
600
|
-
if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
|
|
601
|
-
return void 0;
|
|
475
|
+
function getInputImplicitRole(type) {
|
|
476
|
+
if (type == null || !(type in INPUT_TYPE_ROLE_MAP)) return void 0;
|
|
477
|
+
return INPUT_TYPE_ROLE_MAP[type];
|
|
602
478
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
if (!
|
|
606
|
-
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
return isString(as) && as !== "" ? as : void 0;
|
|
479
|
+
function getConditionalImplicitRole(tag, ariaLabel, ariaLabelledBy) {
|
|
480
|
+
const isNamed = typeof ariaLabel === "string" || typeof ariaLabelledBy === "string";
|
|
481
|
+
if (!isNamed) return void 0;
|
|
482
|
+
if (tag === "section") return "region";
|
|
483
|
+
if (tag === "form") return "form";
|
|
484
|
+
return void 0;
|
|
610
485
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
if (
|
|
615
|
-
if (
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
return
|
|
486
|
+
|
|
487
|
+
// ../../lib/contract/src/aria/aria-role-policy.ts
|
|
488
|
+
function getImplicitRole(tag, props) {
|
|
489
|
+
if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
|
|
490
|
+
if (tag === "input") return getInputImplicitRole(props?.type);
|
|
491
|
+
if (tag === "img") return props?.alt === "" ? "none" : "img";
|
|
492
|
+
if (tag === "section" || tag === "form") {
|
|
493
|
+
return getConditionalImplicitRole(tag, props?.["aria-label"], props?.["aria-labelledby"]);
|
|
619
494
|
}
|
|
620
495
|
return void 0;
|
|
621
496
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
};
|
|
497
|
+
|
|
498
|
+
// ../../lib/contract/src/strict/invariant-base.ts
|
|
499
|
+
var InvariantBase = class {
|
|
500
|
+
diagnostics;
|
|
501
|
+
constructor(diagnostics) {
|
|
502
|
+
this.diagnostics = diagnostics;
|
|
629
503
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
var pendingAsyncWarns2 = /* @__PURE__ */ new Set();
|
|
636
|
-
var asyncWarnScheduled2 = false;
|
|
637
|
-
function flushAsyncWarns2() {
|
|
638
|
-
asyncWarnScheduled2 = false;
|
|
639
|
-
const messages = [...pendingAsyncWarns2];
|
|
640
|
-
pendingAsyncWarns2.clear();
|
|
641
|
-
for (const msg of messages) {
|
|
642
|
-
console.warn(msg);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
function scheduleAsyncWarn(message) {
|
|
646
|
-
if (pendingAsyncWarns2.has(message)) return;
|
|
647
|
-
pendingAsyncWarns2.add(message);
|
|
648
|
-
if (!asyncWarnScheduled2) {
|
|
649
|
-
asyncWarnScheduled2 = true;
|
|
650
|
-
queueMicrotask(flushAsyncWarns2);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
var StrictBase = class {
|
|
654
|
-
strict;
|
|
655
|
-
constructor(strict) {
|
|
656
|
-
this.strict = strict;
|
|
657
|
-
}
|
|
658
|
-
violate(message) {
|
|
659
|
-
if (this.strict === true || this.strict === "throw") {
|
|
660
|
-
throw new Error(message);
|
|
661
|
-
}
|
|
662
|
-
this.warn(message);
|
|
504
|
+
get active() {
|
|
505
|
+
return this.diagnostics.active;
|
|
506
|
+
}
|
|
507
|
+
violate(input) {
|
|
508
|
+
this.diagnostics.error(input);
|
|
663
509
|
}
|
|
664
|
-
// Always caps at
|
|
510
|
+
// Always caps at warn — never throws. ARIA 'warning' violations route here
|
|
665
511
|
// so they surface even in strict='throw' mode without aborting a render.
|
|
666
|
-
warn(
|
|
667
|
-
|
|
668
|
-
if (this.strict === "async-warn") {
|
|
669
|
-
scheduleAsyncWarn(message);
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
console.warn(message);
|
|
512
|
+
warn(input) {
|
|
513
|
+
this.diagnostics.warn(input);
|
|
673
514
|
}
|
|
674
|
-
invariant(condition,
|
|
675
|
-
if (!condition)
|
|
676
|
-
this.violate(message);
|
|
677
|
-
}
|
|
515
|
+
invariant(condition, input) {
|
|
516
|
+
if (!condition) this.violate(input);
|
|
678
517
|
}
|
|
679
518
|
};
|
|
680
|
-
|
|
681
|
-
|
|
519
|
+
|
|
520
|
+
// ../../lib/diagnostics/src/category.ts
|
|
521
|
+
var DiagnosticCategory = /* @__PURE__ */ ((DiagnosticCategory2) => {
|
|
522
|
+
DiagnosticCategory2[DiagnosticCategory2["Contract"] = 0] = "Contract";
|
|
523
|
+
DiagnosticCategory2[DiagnosticCategory2["HTML"] = 1] = "HTML";
|
|
524
|
+
DiagnosticCategory2[DiagnosticCategory2["ARIA"] = 2] = "ARIA";
|
|
525
|
+
DiagnosticCategory2[DiagnosticCategory2["Composition"] = 3] = "Composition";
|
|
526
|
+
DiagnosticCategory2[DiagnosticCategory2["Rendering"] = 4] = "Rendering";
|
|
527
|
+
DiagnosticCategory2[DiagnosticCategory2["Accessibility"] = 5] = "Accessibility";
|
|
528
|
+
DiagnosticCategory2[DiagnosticCategory2["Performance"] = 6] = "Performance";
|
|
529
|
+
DiagnosticCategory2[DiagnosticCategory2["Internal"] = 7] = "Internal";
|
|
530
|
+
DiagnosticCategory2[DiagnosticCategory2["Deprecation"] = 8] = "Deprecation";
|
|
531
|
+
DiagnosticCategory2[DiagnosticCategory2["Lint"] = 9] = "Lint";
|
|
532
|
+
return DiagnosticCategory2;
|
|
533
|
+
})(DiagnosticCategory || {});
|
|
534
|
+
|
|
535
|
+
// ../../lib/diagnostics/src/error.ts
|
|
536
|
+
var PraxisError = class extends Error {
|
|
537
|
+
diagnostic;
|
|
538
|
+
constructor(diagnostic) {
|
|
539
|
+
super(diagnostic.message);
|
|
540
|
+
this.name = "PraxisError";
|
|
541
|
+
this.diagnostic = diagnostic;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// ../../lib/diagnostics/src/severity.ts
|
|
546
|
+
var Severity = /* @__PURE__ */ ((Severity2) => {
|
|
547
|
+
Severity2[Severity2["Debug"] = 0] = "Debug";
|
|
548
|
+
Severity2[Severity2["Info"] = 1] = "Info";
|
|
549
|
+
Severity2[Severity2["Warning"] = 2] = "Warning";
|
|
550
|
+
Severity2[Severity2["Error"] = 3] = "Error";
|
|
551
|
+
Severity2[Severity2["Fatal"] = 4] = "Fatal";
|
|
552
|
+
return Severity2;
|
|
553
|
+
})(Severity || {});
|
|
554
|
+
|
|
555
|
+
// ../../lib/diagnostics/src/policy.ts
|
|
556
|
+
var DefaultPolicy = class {
|
|
557
|
+
reportThreshold;
|
|
558
|
+
throwThreshold;
|
|
559
|
+
constructor({
|
|
560
|
+
reportThreshold = 1 /* Info */,
|
|
561
|
+
throwThreshold = 4 /* Fatal */
|
|
562
|
+
} = {}) {
|
|
563
|
+
this.reportThreshold = reportThreshold;
|
|
564
|
+
this.throwThreshold = throwThreshold;
|
|
565
|
+
}
|
|
566
|
+
resolve(diagnostic) {
|
|
567
|
+
if (diagnostic.severity >= this.throwThreshold) return 2 /* Throw */;
|
|
568
|
+
if (diagnostic.severity >= this.reportThreshold) return 1 /* Report */;
|
|
569
|
+
return 0 /* Ignore */;
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
// ../../lib/diagnostics/src/diagnostics.ts
|
|
574
|
+
var Diagnostics = class {
|
|
575
|
+
reporter;
|
|
576
|
+
policy;
|
|
577
|
+
// Pre-computed at construction time: true if Warning-level diagnostics are not ignored.
|
|
578
|
+
active;
|
|
579
|
+
constructor(reporter, policy = new DefaultPolicy()) {
|
|
580
|
+
this.reporter = reporter;
|
|
581
|
+
this.policy = policy;
|
|
582
|
+
this.active = policy.resolve({ severity: 2 /* Warning */ }) !== 0 /* Ignore */;
|
|
583
|
+
}
|
|
584
|
+
report(diagnostic) {
|
|
585
|
+
const enforcement = this.policy.resolve(diagnostic);
|
|
586
|
+
if (enforcement === 0 /* Ignore */) return diagnostic;
|
|
587
|
+
if (enforcement === 2 /* Throw */) throw new PraxisError(diagnostic);
|
|
588
|
+
this.reporter.report(diagnostic);
|
|
589
|
+
return diagnostic;
|
|
590
|
+
}
|
|
591
|
+
warn(input) {
|
|
592
|
+
return this.report({ ...input, severity: 2 /* Warning */ });
|
|
593
|
+
}
|
|
594
|
+
error(input) {
|
|
595
|
+
return this.report({ ...input, severity: 3 /* Error */ });
|
|
596
|
+
}
|
|
597
|
+
info(input) {
|
|
598
|
+
return this.report({ ...input, severity: 1 /* Info */ });
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// ../../lib/diagnostics/src/formatter.ts
|
|
603
|
+
function formatDiagnostic(diagnostic) {
|
|
604
|
+
const level = Severity[diagnostic.severity];
|
|
605
|
+
const category = DiagnosticCategory[diagnostic.category];
|
|
606
|
+
const prefix = category !== void 0 ? `[${category}] ` : "";
|
|
607
|
+
return `${level} ${diagnostic.code}: ${prefix}${diagnostic.message}`;
|
|
682
608
|
}
|
|
609
|
+
|
|
610
|
+
// ../../lib/diagnostics/src/console-reporter.ts
|
|
611
|
+
var ConsoleReporter = class {
|
|
612
|
+
report(diagnostic) {
|
|
613
|
+
const message = formatDiagnostic(diagnostic);
|
|
614
|
+
switch (diagnostic.severity) {
|
|
615
|
+
case 0 /* Debug */:
|
|
616
|
+
console.debug(message);
|
|
617
|
+
break;
|
|
618
|
+
case 1 /* Info */:
|
|
619
|
+
console.info(message);
|
|
620
|
+
break;
|
|
621
|
+
case 2 /* Warning */:
|
|
622
|
+
console.warn(message);
|
|
623
|
+
break;
|
|
624
|
+
case 3 /* Error */:
|
|
625
|
+
case 4 /* Fatal */:
|
|
626
|
+
console.error(message);
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
// ../../lib/diagnostics/src/null-reporter.ts
|
|
633
|
+
var nullReporter = {
|
|
634
|
+
report() {
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
// ../../lib/diagnostics/src/presets.ts
|
|
639
|
+
var ignoreAllPolicy = {
|
|
640
|
+
resolve(_) {
|
|
641
|
+
return 0 /* Ignore */;
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
var warnOnlyReporter = {
|
|
645
|
+
report(diagnostic) {
|
|
646
|
+
console.warn(formatDiagnostic(diagnostic));
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
var silentDiagnostics = new Diagnostics(nullReporter, ignoreAllPolicy);
|
|
650
|
+
var warnDiagnostics = new Diagnostics(
|
|
651
|
+
warnOnlyReporter,
|
|
652
|
+
new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 4 /* Fatal */ })
|
|
653
|
+
);
|
|
654
|
+
var throwDiagnostics = new Diagnostics(
|
|
655
|
+
new ConsoleReporter(),
|
|
656
|
+
new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 3 /* Error */ })
|
|
657
|
+
);
|
|
658
|
+
|
|
659
|
+
// ../../lib/contract/src/diagnostics/aria.ts
|
|
660
|
+
var AriaDiagnostics = {
|
|
661
|
+
/** Generic bridge for violations produced by external AriaRule functions. */
|
|
662
|
+
fromViolation(v) {
|
|
663
|
+
return {
|
|
664
|
+
code: "ARIA2002" /* AriaViolation */,
|
|
665
|
+
category: 2 /* ARIA */,
|
|
666
|
+
message: v.message
|
|
667
|
+
};
|
|
668
|
+
},
|
|
669
|
+
attributeInvalid(key, role) {
|
|
670
|
+
return {
|
|
671
|
+
code: "ARIA2003" /* AriaAttributeInvalid */,
|
|
672
|
+
category: 2 /* ARIA */,
|
|
673
|
+
message: `"${key}" is not valid on role="${role}". It will be removed.`,
|
|
674
|
+
rationale: "Invalid ARIA attributes are ignored by assistive technology and may trigger accessibility-tree warnings in browser devtools.",
|
|
675
|
+
suggestions: [
|
|
676
|
+
{
|
|
677
|
+
title: "Remove the attribute",
|
|
678
|
+
description: `"${key}" is not in the allowed attribute set for role="${role}".`
|
|
679
|
+
}
|
|
680
|
+
]
|
|
681
|
+
};
|
|
682
|
+
},
|
|
683
|
+
missingLiveRegion(role, impliedLive) {
|
|
684
|
+
return {
|
|
685
|
+
code: "ARIA2004" /* AriaMissingLiveRegion */,
|
|
686
|
+
category: 2 /* ARIA */,
|
|
687
|
+
message: `role="${role}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`,
|
|
688
|
+
rationale: "Live-region roles announce dynamic content changes to screen readers. Without aria-live the politeness level is unspecified and announcements may be silent.",
|
|
689
|
+
suggestions: [
|
|
690
|
+
{
|
|
691
|
+
title: `Add aria-live="${impliedLive}"`,
|
|
692
|
+
description: `role="${role}" conventionally implies aria-live="${impliedLive}".`,
|
|
693
|
+
fix: `aria-live="${impliedLive}"`
|
|
694
|
+
}
|
|
695
|
+
]
|
|
696
|
+
};
|
|
697
|
+
},
|
|
698
|
+
missingAtomic(role) {
|
|
699
|
+
return {
|
|
700
|
+
code: "ARIA2005" /* AriaMissingAtomic */,
|
|
701
|
+
category: 2 /* ARIA */,
|
|
702
|
+
message: `role="${role}" is a live region. Consider setting aria-atomic="true" if the full region should be announced as a unit, or aria-atomic="false" if only changed nodes should be read.`,
|
|
703
|
+
rationale: "aria-atomic controls whether assistive technology announces the entire live region or only the changed nodes. Omitting it leaves the behaviour browser-defined."
|
|
704
|
+
};
|
|
705
|
+
},
|
|
706
|
+
relevantInvalidTokens(invalid) {
|
|
707
|
+
const quoted = invalid.map((t) => `"${t}"`).join(", ");
|
|
708
|
+
return {
|
|
709
|
+
code: "ARIA2006" /* AriaRelevantInvalidToken */,
|
|
710
|
+
category: 2 /* ARIA */,
|
|
711
|
+
message: `aria-relevant contains invalid token(s): ${quoted}. Valid tokens are: additions, removals, text, all.`,
|
|
712
|
+
rationale: "aria-relevant accepts a space-separated list of change types. Unrecognised tokens are silently ignored by assistive technology, making the attribute ineffective.",
|
|
713
|
+
suggestions: [
|
|
714
|
+
{
|
|
715
|
+
title: "Use only valid tokens",
|
|
716
|
+
description: "Valid values are: additions, removals, text, all (or a space-separated combination)."
|
|
717
|
+
}
|
|
718
|
+
]
|
|
719
|
+
};
|
|
720
|
+
},
|
|
721
|
+
relevantSuperseded() {
|
|
722
|
+
return {
|
|
723
|
+
code: "ARIA2007" /* AriaRelevantSuperseded */,
|
|
724
|
+
category: 2 /* ARIA */,
|
|
725
|
+
message: 'aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.',
|
|
726
|
+
rationale: '"all" is equivalent to "additions removals text". Combining it with other tokens is redundant and may confuse readers of the markup.',
|
|
727
|
+
suggestions: [
|
|
728
|
+
{
|
|
729
|
+
title: 'Use aria-relevant="all"',
|
|
730
|
+
fix: 'aria-relevant="all"'
|
|
731
|
+
}
|
|
732
|
+
]
|
|
733
|
+
};
|
|
734
|
+
},
|
|
735
|
+
missingAccessibleName(tag) {
|
|
736
|
+
return {
|
|
737
|
+
code: "ARIA2009" /* AriaMissingAccessibleName */,
|
|
738
|
+
category: 2 /* ARIA */,
|
|
739
|
+
message: `<${tag}> has no accessible name. Add aria-label or aria-labelledby.`,
|
|
740
|
+
rationale: "Elements with a landmark or interactive role must have an accessible name so that assistive technology can identify them when presenting the page outline.",
|
|
741
|
+
suggestions: [
|
|
742
|
+
{
|
|
743
|
+
title: "Add aria-label",
|
|
744
|
+
description: `Add aria-label="\u2026" directly to the <${tag}> element.`
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
title: "Add aria-labelledby",
|
|
748
|
+
description: "Point aria-labelledby at the id of an existing heading or label element."
|
|
749
|
+
}
|
|
750
|
+
]
|
|
751
|
+
};
|
|
752
|
+
},
|
|
753
|
+
attributeOnPresentational(attr, tag) {
|
|
754
|
+
return {
|
|
755
|
+
code: "ARIA2010" /* AriaAttributeOnPresentational */,
|
|
756
|
+
category: 2 /* ARIA */,
|
|
757
|
+
message: `"${attr}" is not allowed on a presentational <${tag}>. Presentational elements are invisible to assistive technology.`,
|
|
758
|
+
rationale: 'role="none" and role="presentation" (including <img alt="">) remove an element from the accessibility tree. ARIA attributes on such elements are ignored by assistive technology.',
|
|
759
|
+
suggestions: [
|
|
760
|
+
{
|
|
761
|
+
title: "Remove the attribute",
|
|
762
|
+
description: `"${attr}" has no effect when the element has role="none" or role="presentation".`
|
|
763
|
+
}
|
|
764
|
+
]
|
|
765
|
+
};
|
|
766
|
+
},
|
|
767
|
+
ariaHiddenOnFocusable(tag) {
|
|
768
|
+
return {
|
|
769
|
+
code: "ARIA2011" /* AriaHiddenOnFocusable */,
|
|
770
|
+
category: 2 /* ARIA */,
|
|
771
|
+
message: `aria-hidden="true" must not be used on focusable <${tag}> elements. Screen reader users who navigate by keyboard will encounter the element but receive no information about it.`,
|
|
772
|
+
rationale: 'aria-hidden removes an element from the accessibility tree while leaving it keyboard-reachable. This creates a "ghost" \u2014 a focusable element assistive technology cannot describe.',
|
|
773
|
+
suggestions: [
|
|
774
|
+
{
|
|
775
|
+
title: "Remove aria-hidden",
|
|
776
|
+
description: "If the element should be hidden from all users, use the HTML hidden attribute or CSS display:none instead."
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
title: "Make the element non-focusable",
|
|
780
|
+
description: 'If the element is intentionally decorative, add tabindex="-1" and disable it so it is not reachable by keyboard.'
|
|
781
|
+
}
|
|
782
|
+
]
|
|
783
|
+
};
|
|
784
|
+
},
|
|
785
|
+
invalidAttributeValue(attr, value, expected) {
|
|
786
|
+
const got = value === null ? "null" : value === void 0 ? "undefined" : typeof value === "string" ? `"${value}"` : String(value);
|
|
787
|
+
return {
|
|
788
|
+
code: "ARIA2013" /* AriaInvalidAttributeValue */,
|
|
789
|
+
category: 2 /* ARIA */,
|
|
790
|
+
message: `"${attr}" has an invalid value (${got}). Expected: ${expected}.`,
|
|
791
|
+
rationale: "ARIA attributes with invalid values are silently ignored by assistive technology, making the markup semantically inert.",
|
|
792
|
+
suggestions: [
|
|
793
|
+
{
|
|
794
|
+
title: `Use a valid value for ${attr}`,
|
|
795
|
+
description: `Valid values are: ${expected}.`
|
|
796
|
+
}
|
|
797
|
+
]
|
|
798
|
+
};
|
|
799
|
+
},
|
|
800
|
+
redundantAriaLevel(tag, level) {
|
|
801
|
+
return {
|
|
802
|
+
code: "ARIA2014" /* AriaRedundantLevelAttribute */,
|
|
803
|
+
category: 2 /* ARIA */,
|
|
804
|
+
message: `aria-level="${level}" is redundant on <${tag}>: the element already has an implicit heading level of ${level}. Remove the attribute.`,
|
|
805
|
+
rationale: 'Restating the implicit aria-level adds noise without semantic value. Use aria-level only to override the native heading level (e.g. aria-level="3" on <h2>).',
|
|
806
|
+
suggestions: [
|
|
807
|
+
{
|
|
808
|
+
title: "Remove aria-level",
|
|
809
|
+
description: `<${tag}> already implies aria-level="${level}".`
|
|
810
|
+
}
|
|
811
|
+
]
|
|
812
|
+
};
|
|
813
|
+
},
|
|
814
|
+
requiredProperty(attr, role) {
|
|
815
|
+
return {
|
|
816
|
+
code: "ARIA2012" /* AriaRequiredProperty */,
|
|
817
|
+
category: 2 /* ARIA */,
|
|
818
|
+
message: `"${attr}" is required for role="${role}" but is missing.`,
|
|
819
|
+
rationale: `WAI-ARIA 1.2 specifies required states and properties for certain roles. Without "${attr}", assistive technology cannot correctly communicate the element's state to users.`,
|
|
820
|
+
suggestions: [
|
|
821
|
+
{
|
|
822
|
+
title: `Add ${attr}`,
|
|
823
|
+
description: `role="${role}" requires "${attr}" to be present.`
|
|
824
|
+
}
|
|
825
|
+
]
|
|
826
|
+
};
|
|
827
|
+
},
|
|
828
|
+
invalidRole(role, tag) {
|
|
829
|
+
return {
|
|
830
|
+
code: "ARIA2008" /* AriaInvalidRole */,
|
|
831
|
+
category: 2 /* ARIA */,
|
|
832
|
+
message: `Invalid role "${role ?? ""}" on <${tag}>.`,
|
|
833
|
+
rationale: "An unrecognised or misapplied ARIA role is ignored by assistive technology and may degrade the accessibility of the element."
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// ../../lib/contract/src/diagnostics/contract.ts
|
|
839
|
+
var ContractDiagnostics = {
|
|
840
|
+
unexpectedChild(typeName, index, context) {
|
|
841
|
+
return {
|
|
842
|
+
code: "COMP1004" /* UnexpectedChild */,
|
|
843
|
+
category: 0 /* Contract */,
|
|
844
|
+
component: context,
|
|
845
|
+
message: `${context}: unexpected child "${typeName}" at index ${index}.`
|
|
846
|
+
};
|
|
847
|
+
},
|
|
848
|
+
ambiguousChild(typeName, index, ruleNames, context) {
|
|
849
|
+
const quoted = ruleNames.map((n) => `"${n}"`).join(" and ");
|
|
850
|
+
return {
|
|
851
|
+
code: "COMP1005" /* AmbiguousChild */,
|
|
852
|
+
category: 0 /* Contract */,
|
|
853
|
+
component: context,
|
|
854
|
+
message: `${context}: child "${typeName}" at index ${index} matches multiple child rules: ${quoted}.`
|
|
855
|
+
};
|
|
856
|
+
},
|
|
857
|
+
cardinalityMin(ruleName, min, context) {
|
|
858
|
+
return {
|
|
859
|
+
code: "COMP1006" /* CardinalityMin */,
|
|
860
|
+
category: 0 /* Contract */,
|
|
861
|
+
component: context,
|
|
862
|
+
message: `${context}: "${ruleName}" requires at least ${min}.`
|
|
863
|
+
};
|
|
864
|
+
},
|
|
865
|
+
cardinalityMax(ruleName, max, context) {
|
|
866
|
+
return {
|
|
867
|
+
code: "COMP1007" /* CardinalityMax */,
|
|
868
|
+
category: 0 /* Contract */,
|
|
869
|
+
component: context,
|
|
870
|
+
message: `${context}: "${ruleName}" allows at most ${max}.`
|
|
871
|
+
};
|
|
872
|
+
},
|
|
873
|
+
positionViolation(ruleName, position, index, context) {
|
|
874
|
+
return {
|
|
875
|
+
code: "COMP1008" /* PositionViolation */,
|
|
876
|
+
category: 0 /* Contract */,
|
|
877
|
+
component: context,
|
|
878
|
+
message: `${context}: "${ruleName}" must be ${position}, got index ${index}`
|
|
879
|
+
};
|
|
880
|
+
},
|
|
881
|
+
unknownVariantDim(component, label2, dim) {
|
|
882
|
+
return {
|
|
883
|
+
code: "COMP1010" /* ContractUnknownVariantDim */,
|
|
884
|
+
category: 0 /* Contract */,
|
|
885
|
+
message: `${component}: ${label2} references unknown variant "${dim}".`
|
|
886
|
+
};
|
|
887
|
+
},
|
|
888
|
+
unknownVariantValue(component, label2, dim, value, valid) {
|
|
889
|
+
return {
|
|
890
|
+
code: "COMP1011" /* ContractUnknownVariantValue */,
|
|
891
|
+
category: 0 /* Contract */,
|
|
892
|
+
message: `${component}: ${label2} sets "${dim}" to unknown value "${value}" (valid: ${valid.join(", ")}).`
|
|
893
|
+
};
|
|
894
|
+
},
|
|
895
|
+
unknownRecipeKey(component, key) {
|
|
896
|
+
return {
|
|
897
|
+
code: "COMP1012" /* ContractUnknownRecipeKey */,
|
|
898
|
+
category: 0 /* Contract */,
|
|
899
|
+
message: `${component} Unknown recipeKey "${key}" \u2014 no preset with that name exists.`
|
|
900
|
+
};
|
|
901
|
+
},
|
|
902
|
+
invalidVariantValue(component, key, value) {
|
|
903
|
+
return {
|
|
904
|
+
code: "COMP1013" /* ContractInvalidVariantValue */,
|
|
905
|
+
category: 0 /* Contract */,
|
|
906
|
+
message: `${component} Variant "${key}=${value}" is not a defined value for the "${key}" dimension.`
|
|
907
|
+
};
|
|
908
|
+
},
|
|
909
|
+
allowedAsViolation(tag, allowedAs, component) {
|
|
910
|
+
const allowed = allowedAs.map((t) => `"${String(t)}"`).join(", ");
|
|
911
|
+
return {
|
|
912
|
+
code: "COMP1009" /* AllowedAsViolation */,
|
|
913
|
+
category: 0 /* Contract */,
|
|
914
|
+
component,
|
|
915
|
+
message: `<${component}>: "as" prop received "${tag}" but only [${allowed}] are allowed.`
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
// ../../lib/contract/src/diagnostics/html.ts
|
|
921
|
+
var HtmlDiagnostics = {
|
|
922
|
+
emptyRole(tag) {
|
|
923
|
+
return {
|
|
924
|
+
code: "HTML3002" /* HtmlEmptyRole */,
|
|
925
|
+
category: 1 /* HTML */,
|
|
926
|
+
message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`
|
|
927
|
+
};
|
|
928
|
+
},
|
|
929
|
+
implicitRoleRedundant(tag, implicitRole) {
|
|
930
|
+
return {
|
|
931
|
+
code: "HTML3003" /* HtmlImplicitRoleRedundant */,
|
|
932
|
+
category: 1 /* HTML */,
|
|
933
|
+
message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
|
|
934
|
+
};
|
|
935
|
+
},
|
|
936
|
+
implicitRoleOverride(tag, implicitRole, role) {
|
|
937
|
+
return {
|
|
938
|
+
code: "HTML3004" /* HtmlImplicitRoleOverride */,
|
|
939
|
+
category: 1 /* HTML */,
|
|
940
|
+
message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
|
|
941
|
+
};
|
|
942
|
+
},
|
|
943
|
+
standaloneRegionOverride(tag, implicitRole) {
|
|
944
|
+
return {
|
|
945
|
+
code: "HTML3005" /* HtmlStandaloneRegionOverride */,
|
|
946
|
+
category: 1 /* HTML */,
|
|
947
|
+
message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
|
|
948
|
+
};
|
|
949
|
+
},
|
|
950
|
+
landmarkRoleOverride(tag, implicitRole, role) {
|
|
951
|
+
return {
|
|
952
|
+
code: "HTML3006" /* HtmlLandmarkRoleOverride */,
|
|
953
|
+
category: 1 /* HTML */,
|
|
954
|
+
message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
|
|
955
|
+
};
|
|
956
|
+
},
|
|
957
|
+
invalidChild(child, parent, allowed) {
|
|
958
|
+
return {
|
|
959
|
+
code: "HTML3007" /* HtmlInvalidChild */,
|
|
960
|
+
category: 1 /* HTML */,
|
|
961
|
+
message: `<${child}> is not a valid direct child of <${parent}>. Allowed: ${allowed}.`
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
// ../../lib/contract/src/diagnostics/slot.ts
|
|
967
|
+
var SlotDiagnostics = {
|
|
968
|
+
exclusive(name) {
|
|
969
|
+
return {
|
|
970
|
+
code: "SLOT1001" /* SlotExclusive */,
|
|
971
|
+
category: 0 /* Contract */,
|
|
972
|
+
component: name,
|
|
973
|
+
message: `${name}: "as" and "asChild" are mutually exclusive`
|
|
974
|
+
};
|
|
975
|
+
},
|
|
976
|
+
singleChildRequired(name, elementTerm) {
|
|
977
|
+
return {
|
|
978
|
+
code: "SLOT1002" /* SlotSingleChild */,
|
|
979
|
+
category: 0 /* Contract */,
|
|
980
|
+
component: name,
|
|
981
|
+
message: `${name}: asChild requires a ${elementTerm} child`
|
|
982
|
+
};
|
|
983
|
+
},
|
|
984
|
+
singleChildExceeded(name, elementTerm, count) {
|
|
985
|
+
return {
|
|
986
|
+
code: "SLOT1002" /* SlotSingleChild */,
|
|
987
|
+
category: 0 /* Contract */,
|
|
988
|
+
component: name,
|
|
989
|
+
message: `${name}: asChild requires exactly one ${elementTerm} child, got ${count}`
|
|
990
|
+
};
|
|
991
|
+
},
|
|
992
|
+
discardedChildren(name, elementTerm, count) {
|
|
993
|
+
const suffix = count === 1 ? "" : "ren";
|
|
994
|
+
return {
|
|
995
|
+
code: "SLOT1003" /* SlotDiscardedChildren */,
|
|
996
|
+
category: 0 /* Contract */,
|
|
997
|
+
component: name,
|
|
998
|
+
message: `${name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${elementTerm}s are valid asChild children.`
|
|
999
|
+
};
|
|
1000
|
+
},
|
|
1001
|
+
renderFnRequired(name, received) {
|
|
1002
|
+
return {
|
|
1003
|
+
code: "SLOT1004" /* SlotRenderFn */,
|
|
1004
|
+
category: 0 /* Contract */,
|
|
1005
|
+
component: name,
|
|
1006
|
+
message: `${name}: asChild requires a render function as children, got ${received}`
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
// ../../lib/contract/src/aria/polymorphic-validator.ts
|
|
683
1012
|
var VALID = [{ valid: true }];
|
|
684
1013
|
function isIntrinsicTag(tag) {
|
|
685
1014
|
return isString(tag);
|
|
@@ -688,26 +1017,28 @@ function omitProp(obj, key) {
|
|
|
688
1017
|
const { [key]: _, ...rest } = obj;
|
|
689
1018
|
return rest;
|
|
690
1019
|
}
|
|
691
|
-
var AriaPolicyEngine = class _AriaPolicyEngine extends
|
|
1020
|
+
var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
|
|
692
1021
|
#extraRules;
|
|
693
1022
|
#planCache = /* @__PURE__ */ new Map();
|
|
694
1023
|
static #MAX_CACHE = 100;
|
|
695
1024
|
// Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
|
|
696
1025
|
// finite so this Map is bounded and avoids recreating closures on every cache miss.
|
|
697
1026
|
static #removeAttributeFixCache = /* @__PURE__ */ new Map();
|
|
698
|
-
constructor(
|
|
699
|
-
super(
|
|
1027
|
+
constructor(diagnostics, options) {
|
|
1028
|
+
super(diagnostics);
|
|
700
1029
|
this.#extraRules = options?.rules ?? [];
|
|
701
1030
|
}
|
|
702
1031
|
static #normalizeEmptyRole(tag, props) {
|
|
703
1032
|
if (props.role !== "") return { normalized: false };
|
|
1033
|
+
const d = HtmlDiagnostics.emptyRole(tag);
|
|
704
1034
|
return {
|
|
705
1035
|
normalized: true,
|
|
706
1036
|
result: {
|
|
707
1037
|
props: omitProp(props, "role"),
|
|
708
1038
|
violations: [
|
|
709
1039
|
{
|
|
710
|
-
message:
|
|
1040
|
+
message: d.message,
|
|
1041
|
+
diagnostic: d,
|
|
711
1042
|
tag,
|
|
712
1043
|
role: "",
|
|
713
1044
|
attribute: void 0,
|
|
@@ -720,10 +1051,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
720
1051
|
}
|
|
721
1052
|
static #deriveContext(tag, props) {
|
|
722
1053
|
if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
|
|
723
|
-
const implicitRole = getImplicitRole(tag);
|
|
724
|
-
const
|
|
725
|
-
if (!
|
|
726
|
-
return { proceed: false, result: { props, violations: [] } };
|
|
1054
|
+
const implicitRole = getImplicitRole(tag, props);
|
|
1055
|
+
const hasRole = implicitRole != null || isString(props.role) && props.role.length > 0;
|
|
1056
|
+
if (!hasRole) return { proceed: false, result: { props, violations: [] } };
|
|
727
1057
|
const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
|
|
728
1058
|
if (normalized.normalized) return { proceed: false, result: normalized.result };
|
|
729
1059
|
const effectiveRole = props.role ?? implicitRole;
|
|
@@ -738,25 +1068,36 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
738
1068
|
static #runRules(rules, context) {
|
|
739
1069
|
const violations = [];
|
|
740
1070
|
const fixes = [];
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
if (
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1071
|
+
iterate.forEach(rules, (rule) => {
|
|
1072
|
+
iterate.forEach(rule(context), (result) => {
|
|
1073
|
+
if (result.valid) return;
|
|
1074
|
+
const {
|
|
1075
|
+
tag,
|
|
1076
|
+
props: { role }
|
|
1077
|
+
} = context;
|
|
1078
|
+
const { message, attribute, severity } = result;
|
|
1079
|
+
const resolvedMessage = message ?? result.diagnostic?.message;
|
|
1080
|
+
const fallbackDiag = resolvedMessage == null ? AriaDiagnostics.invalidRole(role, tag) : void 0;
|
|
1081
|
+
violations.push({
|
|
1082
|
+
message: resolvedMessage ?? fallbackDiag.message,
|
|
1083
|
+
tag,
|
|
1084
|
+
role,
|
|
1085
|
+
attribute,
|
|
1086
|
+
severity,
|
|
1087
|
+
phase: "evaluate",
|
|
1088
|
+
...result.diagnostic != null && { diagnostic: result.diagnostic },
|
|
1089
|
+
...fallbackDiag != null && { diagnostic: fallbackDiag }
|
|
1090
|
+
});
|
|
1091
|
+
if (result.fixable) fixes.push(result.fix);
|
|
1092
|
+
});
|
|
1093
|
+
});
|
|
756
1094
|
return { violations, fixes };
|
|
757
1095
|
}
|
|
758
1096
|
static #getRules(context) {
|
|
759
|
-
|
|
1097
|
+
if (_AriaPolicyEngine.#hasRole(context.props) || context.effectiveRole != null && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
|
|
1098
|
+
return _AriaPolicyEngine.#pipeline;
|
|
1099
|
+
}
|
|
1100
|
+
return _AriaPolicyEngine.#implicitOnlyRules;
|
|
760
1101
|
}
|
|
761
1102
|
static evaluate(tag, props) {
|
|
762
1103
|
const derived = _AriaPolicyEngine.#deriveContext(tag, props);
|
|
@@ -781,10 +1122,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
781
1122
|
return { props: next, violations };
|
|
782
1123
|
}
|
|
783
1124
|
report(violations) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1125
|
+
iterate.forEach(violations, (v) => {
|
|
1126
|
+
const d = v.diagnostic ?? AriaDiagnostics.fromViolation(v);
|
|
1127
|
+
if (v.severity === "error") this.violate(d);
|
|
1128
|
+
else this.warn(d);
|
|
1129
|
+
});
|
|
788
1130
|
}
|
|
789
1131
|
// Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
|
|
790
1132
|
// Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
|
|
@@ -796,27 +1138,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
796
1138
|
if (!isIntrinsicTag(tag)) return null;
|
|
797
1139
|
const parts = [tag];
|
|
798
1140
|
if (typeof props.role === "string") parts.push(`role:${props.role}`);
|
|
1141
|
+
if (tag === "input" && typeof props.type === "string") parts.push(`type:${props.type}`);
|
|
1142
|
+
if (tag === "img") parts.push(`alt:${props.alt === "" ? "empty" : "present"}`);
|
|
799
1143
|
const ariaEntries = [];
|
|
800
|
-
|
|
801
|
-
if (!
|
|
802
|
-
|
|
803
|
-
if (!isString(v) && !isNumber(v) && typeof v !== "boolean") continue;
|
|
1144
|
+
iterate.forEachEntry(props, (k, v) => {
|
|
1145
|
+
if (!k.startsWith("aria-")) return;
|
|
1146
|
+
if (!isString(v) && !isNumber(v) && typeof v !== "boolean") return;
|
|
804
1147
|
ariaEntries.push(`${k}:${String(v)}`);
|
|
805
|
-
}
|
|
1148
|
+
});
|
|
806
1149
|
if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
|
|
807
1150
|
return parts.join("|");
|
|
808
1151
|
}
|
|
809
1152
|
static #computePlan(inputProps, resultProps) {
|
|
810
1153
|
const removals = /* @__PURE__ */ new Set();
|
|
811
1154
|
const updates = {};
|
|
812
|
-
|
|
813
|
-
if (
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
if (!Object.hasOwn(resultProps, key)) continue;
|
|
817
|
-
const resultVal = resultProps[key];
|
|
1155
|
+
iterate.forEachKey(inputProps, (key) => {
|
|
1156
|
+
if (!(key in resultProps)) removals.add(key);
|
|
1157
|
+
});
|
|
1158
|
+
iterate.forEachEntry(resultProps, (key, resultVal) => {
|
|
818
1159
|
if (inputProps[key] !== resultVal) updates[key] = resultVal;
|
|
819
|
-
}
|
|
1160
|
+
});
|
|
820
1161
|
return { removals, updates };
|
|
821
1162
|
}
|
|
822
1163
|
static #applyPlan(props, removals, updates) {
|
|
@@ -824,15 +1165,15 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
824
1165
|
const hasUpdates = Object.keys(updates).length > 0;
|
|
825
1166
|
if (!hasRemovals && !hasUpdates) return props;
|
|
826
1167
|
const next = {};
|
|
827
|
-
|
|
828
|
-
if (
|
|
829
|
-
}
|
|
1168
|
+
iterate.forEachEntry(props, (k, v) => {
|
|
1169
|
+
if (!removals.has(k)) next[k] = v;
|
|
1170
|
+
});
|
|
830
1171
|
Object.assign(next, updates);
|
|
831
1172
|
return next;
|
|
832
1173
|
}
|
|
833
1174
|
validate(tag, props) {
|
|
834
1175
|
const key = _AriaPolicyEngine.#createPlanKey(tag, props);
|
|
835
|
-
if (!
|
|
1176
|
+
if (!isNull(key)) {
|
|
836
1177
|
const cached = this.#planCache.get(key);
|
|
837
1178
|
if (cached !== void 0) {
|
|
838
1179
|
this.#planCache.delete(key);
|
|
@@ -846,7 +1187,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
846
1187
|
}
|
|
847
1188
|
const result = this.#extraRules.length ? _AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules) : _AriaPolicyEngine.evaluate(tag, props);
|
|
848
1189
|
if (result.violations.length > 0) this.report(result.violations);
|
|
849
|
-
if (!
|
|
1190
|
+
if (!isNull(key)) {
|
|
850
1191
|
const { removals, updates } = _AriaPolicyEngine.#computePlan(
|
|
851
1192
|
props,
|
|
852
1193
|
result.props
|
|
@@ -867,12 +1208,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
867
1208
|
if (fixes.length === 0) return props;
|
|
868
1209
|
const sorted = [...fixes].sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
|
|
869
1210
|
let next = props;
|
|
870
|
-
|
|
1211
|
+
iterate.forEach(sorted, ({ apply }) => {
|
|
871
1212
|
const effectiveRole = next.role ?? implicitRole;
|
|
872
1213
|
const fixContext = { tag, implicitRole, effectiveRole, props: next };
|
|
873
1214
|
const fixResult = apply(fixContext);
|
|
874
1215
|
if (fixResult.applied) next = fixResult.next;
|
|
875
|
-
}
|
|
1216
|
+
});
|
|
876
1217
|
return next;
|
|
877
1218
|
}
|
|
878
1219
|
static #removeRole = {
|
|
@@ -900,10 +1241,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
900
1241
|
_AriaPolicyEngine.#checkInvalidRoleOverride,
|
|
901
1242
|
_AriaPolicyEngine.#checkRedundantRole,
|
|
902
1243
|
_AriaPolicyEngine.#checkStandaloneRegion,
|
|
1244
|
+
_AriaPolicyEngine.#checkAriaAttributeValues,
|
|
903
1245
|
_AriaPolicyEngine.#checkInvalidAriaAttributes,
|
|
1246
|
+
_AriaPolicyEngine.#checkRequiredAriaProperties,
|
|
1247
|
+
_AriaPolicyEngine.#checkNameRequiredRoles,
|
|
1248
|
+
_AriaPolicyEngine.#checkRedundantAriaLevel,
|
|
904
1249
|
_AriaPolicyEngine.#checkMissingLiveRegion,
|
|
905
1250
|
_AriaPolicyEngine.#checkMissingAtomic,
|
|
906
|
-
_AriaPolicyEngine.#checkInvalidAriaRelevant
|
|
1251
|
+
_AriaPolicyEngine.#checkInvalidAriaRelevant,
|
|
1252
|
+
_AriaPolicyEngine.#checkAriaHiddenOnFocusable,
|
|
1253
|
+
_AriaPolicyEngine.#checkPresentationalAriaAttributes
|
|
1254
|
+
];
|
|
1255
|
+
// Rules for elements with an implicit role but no explicit role (not a live region).
|
|
1256
|
+
static #implicitOnlyRules = [
|
|
1257
|
+
_AriaPolicyEngine.#checkAriaAttributeValues,
|
|
1258
|
+
_AriaPolicyEngine.#checkInvalidAriaAttributes,
|
|
1259
|
+
_AriaPolicyEngine.#checkRequiredAriaProperties,
|
|
1260
|
+
_AriaPolicyEngine.#checkNameRequiredRoles,
|
|
1261
|
+
_AriaPolicyEngine.#checkRedundantAriaLevel,
|
|
1262
|
+
_AriaPolicyEngine.#checkAriaHiddenOnFocusable,
|
|
1263
|
+
_AriaPolicyEngine.#checkPresentationalAriaAttributes
|
|
907
1264
|
];
|
|
908
1265
|
static #checkInvalidRoleOverride({
|
|
909
1266
|
tag,
|
|
@@ -919,7 +1276,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
919
1276
|
fixable: true,
|
|
920
1277
|
severity: "error",
|
|
921
1278
|
fix: _AriaPolicyEngine.#removeRole,
|
|
922
|
-
|
|
1279
|
+
diagnostic: HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role)
|
|
923
1280
|
}
|
|
924
1281
|
];
|
|
925
1282
|
}
|
|
@@ -933,45 +1290,302 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
933
1290
|
valid: false,
|
|
934
1291
|
fixable: true,
|
|
935
1292
|
severity: "warning",
|
|
936
|
-
fix: _AriaPolicyEngine.#removeRole,
|
|
937
|
-
|
|
1293
|
+
fix: _AriaPolicyEngine.#removeRole,
|
|
1294
|
+
diagnostic: HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole)
|
|
1295
|
+
}
|
|
1296
|
+
];
|
|
1297
|
+
}
|
|
1298
|
+
static #checkStandaloneRegion({ tag, props, implicitRole }) {
|
|
1299
|
+
const role = props.role;
|
|
1300
|
+
if (role !== "region") return VALID;
|
|
1301
|
+
if (!isStandaloneTag(tag)) return VALID;
|
|
1302
|
+
return [
|
|
1303
|
+
{
|
|
1304
|
+
valid: false,
|
|
1305
|
+
fixable: true,
|
|
1306
|
+
severity: "error",
|
|
1307
|
+
fix: _AriaPolicyEngine.#removeRole,
|
|
1308
|
+
diagnostic: HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag)
|
|
1309
|
+
}
|
|
1310
|
+
];
|
|
1311
|
+
}
|
|
1312
|
+
static #checkInvalidAriaAttributes({
|
|
1313
|
+
tag,
|
|
1314
|
+
props,
|
|
1315
|
+
effectiveRole
|
|
1316
|
+
}) {
|
|
1317
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
|
|
1318
|
+
const results = [];
|
|
1319
|
+
iterate.forEachEntry(props, (key) => {
|
|
1320
|
+
if (!key.startsWith("aria-")) return;
|
|
1321
|
+
if (isGlobalAriaAttribute(key)) return;
|
|
1322
|
+
if (isAriaAttributeValidForRole(key, effectiveRole)) return;
|
|
1323
|
+
results.push({
|
|
1324
|
+
valid: false,
|
|
1325
|
+
severity: "warning",
|
|
1326
|
+
fixable: true,
|
|
1327
|
+
attribute: key,
|
|
1328
|
+
diagnostic: AriaDiagnostics.attributeInvalid(key, effectiveRole ?? tag),
|
|
1329
|
+
fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
|
|
1330
|
+
});
|
|
1331
|
+
});
|
|
1332
|
+
return results;
|
|
1333
|
+
}
|
|
1334
|
+
// ─── ARIA attribute value validation ──────────────────────────────────────
|
|
1335
|
+
// Accepted value shapes for typed ARIA attributes.
|
|
1336
|
+
// Attributes not in this map are unconstrained (arbitrary string values permitted).
|
|
1337
|
+
static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
1338
|
+
// Boolean (true | false)
|
|
1339
|
+
["aria-atomic", { kind: "boolean" }],
|
|
1340
|
+
["aria-busy", { kind: "boolean" }],
|
|
1341
|
+
["aria-disabled", { kind: "boolean" }],
|
|
1342
|
+
["aria-expanded", { kind: "boolean" }],
|
|
1343
|
+
["aria-hidden", { kind: "boolean" }],
|
|
1344
|
+
["aria-modal", { kind: "boolean" }],
|
|
1345
|
+
["aria-multiline", { kind: "boolean" }],
|
|
1346
|
+
["aria-multiselectable", { kind: "boolean" }],
|
|
1347
|
+
["aria-readonly", { kind: "boolean" }],
|
|
1348
|
+
["aria-required", { kind: "boolean" }],
|
|
1349
|
+
["aria-selected", { kind: "boolean" }],
|
|
1350
|
+
// Tristate (true | false | mixed)
|
|
1351
|
+
["aria-checked", { kind: "tristate" }],
|
|
1352
|
+
["aria-pressed", { kind: "tristate" }],
|
|
1353
|
+
// Numeric (any finite number)
|
|
1354
|
+
["aria-valuenow", { kind: "number" }],
|
|
1355
|
+
["aria-valuemin", { kind: "number" }],
|
|
1356
|
+
["aria-valuemax", { kind: "number" }],
|
|
1357
|
+
// Integer with optional range
|
|
1358
|
+
["aria-level", { kind: "integer", min: 1, max: 6 }],
|
|
1359
|
+
["aria-posinset", { kind: "integer", min: 1 }],
|
|
1360
|
+
["aria-setsize", { kind: "integer", min: -1 }],
|
|
1361
|
+
["aria-rowcount", { kind: "integer", min: -1 }],
|
|
1362
|
+
["aria-colcount", { kind: "integer", min: -1 }],
|
|
1363
|
+
["aria-rowindex", { kind: "integer", min: 1 }],
|
|
1364
|
+
["aria-colindex", { kind: "integer", min: 1 }],
|
|
1365
|
+
["aria-rowspan", { kind: "integer", min: 0 }],
|
|
1366
|
+
["aria-colspan", { kind: "integer", min: 0 }],
|
|
1367
|
+
// Enum (specific allowed tokens)
|
|
1368
|
+
["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
|
|
1369
|
+
[
|
|
1370
|
+
"aria-current",
|
|
1371
|
+
{
|
|
1372
|
+
kind: "enum",
|
|
1373
|
+
values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
|
|
1374
|
+
}
|
|
1375
|
+
],
|
|
1376
|
+
[
|
|
1377
|
+
"aria-haspopup",
|
|
1378
|
+
{
|
|
1379
|
+
kind: "enum",
|
|
1380
|
+
values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
|
|
1381
|
+
}
|
|
1382
|
+
],
|
|
1383
|
+
["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
|
|
1384
|
+
["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
|
|
1385
|
+
[
|
|
1386
|
+
"aria-orientation",
|
|
1387
|
+
{ kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
|
|
1388
|
+
],
|
|
1389
|
+
["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
|
|
1390
|
+
]);
|
|
1391
|
+
static #isValidAriaValue(value, type) {
|
|
1392
|
+
switch (type.kind) {
|
|
1393
|
+
case "boolean":
|
|
1394
|
+
return value === "true" || value === "false" || value === true || value === false;
|
|
1395
|
+
case "tristate":
|
|
1396
|
+
return value === "true" || value === "false" || value === "mixed" || value === true || value === false;
|
|
1397
|
+
case "number": {
|
|
1398
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
1399
|
+
if (typeof value !== "string") return false;
|
|
1400
|
+
const n = parseFloat(value);
|
|
1401
|
+
return Number.isFinite(n);
|
|
1402
|
+
}
|
|
1403
|
+
case "integer": {
|
|
1404
|
+
const n = typeof value === "number" ? value : typeof value === "string" ? parseInt(value, 10) : NaN;
|
|
1405
|
+
if (!Number.isFinite(n) || !Number.isInteger(n)) return false;
|
|
1406
|
+
if (type.min !== void 0 && n < type.min) return false;
|
|
1407
|
+
if (type.max !== void 0 && n > type.max) return false;
|
|
1408
|
+
return true;
|
|
1409
|
+
}
|
|
1410
|
+
case "enum":
|
|
1411
|
+
return typeof value === "string" && type.values.has(value);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
static #describeExpected(type) {
|
|
1415
|
+
switch (type.kind) {
|
|
1416
|
+
case "boolean":
|
|
1417
|
+
return '"true" or "false"';
|
|
1418
|
+
case "tristate":
|
|
1419
|
+
return '"true", "false", or "mixed"';
|
|
1420
|
+
case "number":
|
|
1421
|
+
return "a finite number";
|
|
1422
|
+
case "integer": {
|
|
1423
|
+
const parts = ["an integer"];
|
|
1424
|
+
if (type.min !== void 0 && type.max !== void 0)
|
|
1425
|
+
parts.push(`between ${type.min} and ${type.max}`);
|
|
1426
|
+
else if (type.min !== void 0) parts.push(`\u2265 ${type.min}`);
|
|
1427
|
+
else if (type.max !== void 0) parts.push(`\u2264 ${type.max}`);
|
|
1428
|
+
return parts.join(" ");
|
|
1429
|
+
}
|
|
1430
|
+
case "enum":
|
|
1431
|
+
return [...type.values].map((v) => `"${v}"`).join(", ");
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
static #checkAriaAttributeValues({ props, effectiveRole }) {
|
|
1435
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
|
|
1436
|
+
const results = [];
|
|
1437
|
+
iterate.forEachEntry(props, (key, value) => {
|
|
1438
|
+
if (!key.startsWith("aria-")) return;
|
|
1439
|
+
const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
|
|
1440
|
+
if (type == null) return;
|
|
1441
|
+
if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
|
|
1442
|
+
results.push({
|
|
1443
|
+
valid: false,
|
|
1444
|
+
fixable: true,
|
|
1445
|
+
severity: "warning",
|
|
1446
|
+
attribute: key,
|
|
1447
|
+
diagnostic: AriaDiagnostics.invalidAttributeValue(
|
|
1448
|
+
key,
|
|
1449
|
+
value,
|
|
1450
|
+
_AriaPolicyEngine.#describeExpected(type)
|
|
1451
|
+
),
|
|
1452
|
+
fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
|
|
1453
|
+
});
|
|
1454
|
+
});
|
|
1455
|
+
return results;
|
|
1456
|
+
}
|
|
1457
|
+
// ─── Heading implicit level ────────────────────────────────────────────────
|
|
1458
|
+
static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1459
|
+
["h1", 1],
|
|
1460
|
+
["h2", 2],
|
|
1461
|
+
["h3", 3],
|
|
1462
|
+
["h4", 4],
|
|
1463
|
+
["h5", 5],
|
|
1464
|
+
["h6", 6]
|
|
1465
|
+
]);
|
|
1466
|
+
static #checkRedundantAriaLevel({
|
|
1467
|
+
tag,
|
|
1468
|
+
props,
|
|
1469
|
+
effectiveRole
|
|
1470
|
+
}) {
|
|
1471
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
|
|
1472
|
+
const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
|
|
1473
|
+
if (implicitLevel == null) return VALID;
|
|
1474
|
+
const raw = props["aria-level"];
|
|
1475
|
+
if (raw == null) return VALID;
|
|
1476
|
+
const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
|
|
1477
|
+
if (!Number.isFinite(n) || n !== implicitLevel) return VALID;
|
|
1478
|
+
return [
|
|
1479
|
+
{
|
|
1480
|
+
valid: false,
|
|
1481
|
+
fixable: true,
|
|
1482
|
+
severity: "warning",
|
|
1483
|
+
attribute: "aria-level",
|
|
1484
|
+
diagnostic: AriaDiagnostics.redundantAriaLevel(tag, implicitLevel),
|
|
1485
|
+
fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-level")
|
|
938
1486
|
}
|
|
939
1487
|
];
|
|
940
1488
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1489
|
+
// ─── Name-required roles ───────────────────────────────────────────────────
|
|
1490
|
+
// Roles that always require an accessible name per WAI-ARIA APG.
|
|
1491
|
+
// Dialog and landmark names are enforced via contracts (ariaContract) rather than
|
|
1492
|
+
// the built-in pipeline so consumers can opt in; img is built in because role=img
|
|
1493
|
+
// on any element (including bare <img>) is definitionally useless without a name.
|
|
1494
|
+
static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1495
|
+
static #checkNameRequiredRoles({
|
|
1496
|
+
tag,
|
|
1497
|
+
props,
|
|
1498
|
+
effectiveRole
|
|
1499
|
+
}) {
|
|
1500
|
+
if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID;
|
|
1501
|
+
if ("aria-label" in props || "aria-labelledby" in props) return VALID;
|
|
1502
|
+
if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return VALID;
|
|
945
1503
|
return [
|
|
946
1504
|
{
|
|
947
1505
|
valid: false,
|
|
948
|
-
fixable:
|
|
1506
|
+
fixable: false,
|
|
1507
|
+
severity: "warning",
|
|
1508
|
+
diagnostic: AriaDiagnostics.missingAccessibleName(tag)
|
|
1509
|
+
}
|
|
1510
|
+
];
|
|
1511
|
+
}
|
|
1512
|
+
// WAI-ARIA 1.2 required states and properties, keyed by role.
|
|
1513
|
+
// Source: https://www.w3.org/TR/wai-aria-1.2/#requiredState
|
|
1514
|
+
static #REQUIRED_PROPERTIES = /* @__PURE__ */ new Map([
|
|
1515
|
+
["combobox", ["aria-expanded"]],
|
|
1516
|
+
["option", ["aria-selected"]],
|
|
1517
|
+
["slider", ["aria-valuenow"]],
|
|
1518
|
+
["scrollbar", ["aria-controls", "aria-valuenow"]],
|
|
1519
|
+
["spinbutton", ["aria-valuenow"]]
|
|
1520
|
+
]);
|
|
1521
|
+
static #checkRequiredAriaProperties({
|
|
1522
|
+
props,
|
|
1523
|
+
effectiveRole
|
|
1524
|
+
}) {
|
|
1525
|
+
if (!effectiveRole) return VALID;
|
|
1526
|
+
const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
|
|
1527
|
+
if (required == null) return VALID;
|
|
1528
|
+
const results = [];
|
|
1529
|
+
iterate.forEach(required, (attr) => {
|
|
1530
|
+
if (attr in props) return;
|
|
1531
|
+
results.push({
|
|
1532
|
+
valid: false,
|
|
1533
|
+
fixable: false,
|
|
1534
|
+
severity: "warning",
|
|
1535
|
+
attribute: attr,
|
|
1536
|
+
diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
|
|
1537
|
+
});
|
|
1538
|
+
});
|
|
1539
|
+
return results;
|
|
1540
|
+
}
|
|
1541
|
+
// Natively interactive HTML elements — always keyboard-reachable unless explicitly disabled.
|
|
1542
|
+
static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
1543
|
+
"a",
|
|
1544
|
+
"button",
|
|
1545
|
+
"input",
|
|
1546
|
+
"select",
|
|
1547
|
+
"textarea"
|
|
1548
|
+
]);
|
|
1549
|
+
// WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
|
|
1550
|
+
static #checkAriaHiddenOnFocusable({ tag, props }) {
|
|
1551
|
+
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID;
|
|
1552
|
+
const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
|
|
1553
|
+
if (!isInteractive) {
|
|
1554
|
+
const tabindex = props.tabindex;
|
|
1555
|
+
const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
|
|
1556
|
+
if (!Number.isFinite(n) || n < 0) return VALID;
|
|
1557
|
+
}
|
|
1558
|
+
return [
|
|
1559
|
+
{
|
|
1560
|
+
valid: false,
|
|
1561
|
+
fixable: false,
|
|
949
1562
|
severity: "error",
|
|
950
|
-
|
|
951
|
-
|
|
1563
|
+
attribute: "aria-hidden",
|
|
1564
|
+
diagnostic: AriaDiagnostics.ariaHiddenOnFocusable(tag)
|
|
952
1565
|
}
|
|
953
1566
|
];
|
|
954
1567
|
}
|
|
955
|
-
|
|
1568
|
+
// Presentational elements (role=none/presentation, including <img alt="">) are removed
|
|
1569
|
+
// from the accessibility tree — ARIA attributes on them are meaningless and misleading.
|
|
1570
|
+
static #checkPresentationalAriaAttributes({
|
|
956
1571
|
tag,
|
|
957
1572
|
props,
|
|
958
1573
|
effectiveRole
|
|
959
1574
|
}) {
|
|
1575
|
+
if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID;
|
|
960
1576
|
const results = [];
|
|
961
|
-
|
|
962
|
-
if (!
|
|
963
|
-
if (
|
|
964
|
-
if (isGlobalAriaAttribute(key)) continue;
|
|
965
|
-
if (isAriaAttributeValidForRole(key, effectiveRole)) continue;
|
|
1577
|
+
iterate.forEachEntry(props, (key) => {
|
|
1578
|
+
if (!key.startsWith("aria-")) return;
|
|
1579
|
+
if (key === "aria-hidden") return;
|
|
966
1580
|
results.push({
|
|
967
1581
|
valid: false,
|
|
968
|
-
severity: "warning",
|
|
969
1582
|
fixable: true,
|
|
1583
|
+
severity: "warning",
|
|
970
1584
|
attribute: key,
|
|
971
|
-
|
|
1585
|
+
diagnostic: AriaDiagnostics.attributeOnPresentational(key, tag),
|
|
972
1586
|
fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
|
|
973
1587
|
});
|
|
974
|
-
}
|
|
1588
|
+
});
|
|
975
1589
|
return results;
|
|
976
1590
|
}
|
|
977
1591
|
// WAI-ARIA live region roles and their implied aria-live politeness values.
|
|
@@ -1000,7 +1614,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
1000
1614
|
fixable: true,
|
|
1001
1615
|
severity: "warning",
|
|
1002
1616
|
fix: injectLive,
|
|
1003
|
-
|
|
1617
|
+
diagnostic: AriaDiagnostics.missingLiveRegion(effectiveRole, impliedLive)
|
|
1004
1618
|
}
|
|
1005
1619
|
];
|
|
1006
1620
|
}
|
|
@@ -1012,7 +1626,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
1012
1626
|
valid: false,
|
|
1013
1627
|
fixable: false,
|
|
1014
1628
|
severity: "warning",
|
|
1015
|
-
|
|
1629
|
+
diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
|
|
1016
1630
|
}
|
|
1017
1631
|
];
|
|
1018
1632
|
}
|
|
@@ -1041,7 +1655,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
1041
1655
|
fixable: true,
|
|
1042
1656
|
severity: "warning",
|
|
1043
1657
|
attribute: "aria-relevant",
|
|
1044
|
-
|
|
1658
|
+
diagnostic: AriaDiagnostics.relevantInvalidTokens(invalid),
|
|
1045
1659
|
fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-relevant")
|
|
1046
1660
|
}
|
|
1047
1661
|
];
|
|
@@ -1053,7 +1667,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
1053
1667
|
fixable: true,
|
|
1054
1668
|
severity: "warning",
|
|
1055
1669
|
attribute: "aria-relevant",
|
|
1056
|
-
|
|
1670
|
+
diagnostic: AriaDiagnostics.relevantSuperseded(),
|
|
1057
1671
|
fix: _AriaPolicyEngine.#normalizeRelevantAllFix
|
|
1058
1672
|
}
|
|
1059
1673
|
];
|
|
@@ -1061,6 +1675,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
|
|
|
1061
1675
|
return VALID;
|
|
1062
1676
|
}
|
|
1063
1677
|
};
|
|
1678
|
+
|
|
1679
|
+
// ../../lib/contract/src/children/get-type-name.ts
|
|
1064
1680
|
function getTypeName(value) {
|
|
1065
1681
|
if (value === null) return "null";
|
|
1066
1682
|
if (value === void 0) return "undefined";
|
|
@@ -1071,39 +1687,8 @@ function getTypeName(value) {
|
|
|
1071
1687
|
const name = value.constructor?.name;
|
|
1072
1688
|
return typeof name === "string" && name !== "Object" ? name : "object";
|
|
1073
1689
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
constructor(ctx = "") {
|
|
1077
|
-
this.#prefix = ctx ? `${ctx}:
|
|
1078
|
-
` : "";
|
|
1079
|
-
}
|
|
1080
|
-
#template(typeName, index, prefix = "", suffix = "") {
|
|
1081
|
-
const leadingStr = prefix ? `${prefix} ` : "";
|
|
1082
|
-
const followingStr = suffix ? ` ${suffix}` : "";
|
|
1083
|
-
return `${leadingStr}child "${typeName}" at index ${index}${followingStr}.`;
|
|
1084
|
-
}
|
|
1085
|
-
unexpectedChild(typeName, index) {
|
|
1086
|
-
return this.#template(typeName, index, "unexpected");
|
|
1087
|
-
}
|
|
1088
|
-
multipleMatches(typeName, index, ruleNames) {
|
|
1089
|
-
const quoted = ruleNames.map((n) => `"${n}"`);
|
|
1090
|
-
return this.#template(
|
|
1091
|
-
typeName,
|
|
1092
|
-
index,
|
|
1093
|
-
"",
|
|
1094
|
-
`matches multiple child rules: ${quoted.join(" and ")}`
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
#format(errors) {
|
|
1098
|
-
return this.#prefix + errors.join("\n");
|
|
1099
|
-
}
|
|
1100
|
-
toError(errors) {
|
|
1101
|
-
if (errors.length === 0) {
|
|
1102
|
-
return new Error(this.#prefix + "Unknown validation error.");
|
|
1103
|
-
}
|
|
1104
|
-
return new Error(this.#format(errors));
|
|
1105
|
-
}
|
|
1106
|
-
};
|
|
1690
|
+
|
|
1691
|
+
// ../../lib/contract/src/children/normalize-child-rule.ts
|
|
1107
1692
|
function normalizeCardinality(input, impliesSingleton) {
|
|
1108
1693
|
const min = input?.min ?? 0;
|
|
1109
1694
|
const max = input?.max ?? (impliesSingleton ? 1 : Infinity);
|
|
@@ -1128,6 +1713,8 @@ function normalizeChildRule(rule) {
|
|
|
1128
1713
|
cardinality: normalizeCardinality(rule.cardinality, impliesSingleton)
|
|
1129
1714
|
};
|
|
1130
1715
|
}
|
|
1716
|
+
|
|
1717
|
+
// ../../lib/contract/src/children/rules-matcher.ts
|
|
1131
1718
|
function getChildType(child) {
|
|
1132
1719
|
if (!isObject(child) || !("type" in child)) return void 0;
|
|
1133
1720
|
return child.type;
|
|
@@ -1136,8 +1723,8 @@ function buildPartialIndex(rules) {
|
|
|
1136
1723
|
const typeIndex = /* @__PURE__ */ new Map();
|
|
1137
1724
|
const duplicateTypes = /* @__PURE__ */ new Set();
|
|
1138
1725
|
const untypedIndices = [];
|
|
1139
|
-
|
|
1140
|
-
const t =
|
|
1726
|
+
iterate.forEach(rules, (rule, ri) => {
|
|
1727
|
+
const t = rule.type;
|
|
1141
1728
|
if (t === void 0) {
|
|
1142
1729
|
untypedIndices.push(ri);
|
|
1143
1730
|
} else if (typeIndex.has(t)) {
|
|
@@ -1145,12 +1732,14 @@ function buildPartialIndex(rules) {
|
|
|
1145
1732
|
} else {
|
|
1146
1733
|
typeIndex.set(t, ri);
|
|
1147
1734
|
}
|
|
1148
|
-
}
|
|
1735
|
+
});
|
|
1149
1736
|
if (duplicateTypes.size > 0) {
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1737
|
+
iterate.forEachSet(duplicateTypes, (t) => {
|
|
1738
|
+
typeIndex.delete(t);
|
|
1739
|
+
});
|
|
1740
|
+
iterate.forEach(rules, (rule, ri) => {
|
|
1741
|
+
if (duplicateTypes.has(rule.type)) untypedIndices.push(ri);
|
|
1742
|
+
});
|
|
1154
1743
|
}
|
|
1155
1744
|
return { typeIndex, untypedIndices };
|
|
1156
1745
|
}
|
|
@@ -1169,10 +1758,10 @@ var RuleMatcher = class {
|
|
|
1169
1758
|
const reverse = /* @__PURE__ */ new Map();
|
|
1170
1759
|
const unexpectedIndices = /* @__PURE__ */ new Set();
|
|
1171
1760
|
const ambiguousIndices = /* @__PURE__ */ new Set();
|
|
1172
|
-
|
|
1761
|
+
iterate.forEach(this.#rules, (_, ri) => {
|
|
1173
1762
|
reverse.set(ri, /* @__PURE__ */ new Set());
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1763
|
+
});
|
|
1764
|
+
iterate.forEach(children, (child, ci) => {
|
|
1176
1765
|
const t = getChildType(child);
|
|
1177
1766
|
if (t !== void 0) {
|
|
1178
1767
|
const ri = this.#typeIndex.get(t);
|
|
@@ -1186,8 +1775,8 @@ var RuleMatcher = class {
|
|
|
1186
1775
|
reverse.get(ri).add(ci);
|
|
1187
1776
|
}
|
|
1188
1777
|
}
|
|
1189
|
-
|
|
1190
|
-
if (!this.#rules[ri].match(child))
|
|
1778
|
+
iterate.forEach(this.#untypedIndices, (ri) => {
|
|
1779
|
+
if (!this.#rules[ri].match(child)) return;
|
|
1191
1780
|
let childEntry = forward.get(ci);
|
|
1192
1781
|
if (!childEntry) {
|
|
1193
1782
|
childEntry = /* @__PURE__ */ new Set();
|
|
@@ -1195,33 +1784,35 @@ var RuleMatcher = class {
|
|
|
1195
1784
|
}
|
|
1196
1785
|
childEntry.add(ri);
|
|
1197
1786
|
reverse.get(ri).add(ci);
|
|
1198
|
-
}
|
|
1787
|
+
});
|
|
1199
1788
|
const entry = forward.get(ci);
|
|
1200
1789
|
if (!entry) {
|
|
1201
1790
|
unexpectedIndices.add(ci);
|
|
1202
1791
|
} else if (entry.size > 1) {
|
|
1203
1792
|
ambiguousIndices.add(ci);
|
|
1204
1793
|
}
|
|
1205
|
-
}
|
|
1794
|
+
});
|
|
1206
1795
|
return { matrix: { childToRules: { forward, reverse } }, unexpectedIndices, ambiguousIndices };
|
|
1207
1796
|
}
|
|
1208
1797
|
};
|
|
1209
|
-
|
|
1798
|
+
|
|
1799
|
+
// ../../lib/contract/src/children/rule-validator.ts
|
|
1800
|
+
var RuleValidator = class _RuleValidator extends InvariantBase {
|
|
1210
1801
|
#context;
|
|
1211
|
-
constructor(context,
|
|
1212
|
-
super(
|
|
1802
|
+
constructor(context, diagnostics) {
|
|
1803
|
+
super(diagnostics);
|
|
1213
1804
|
this.#context = context;
|
|
1214
1805
|
}
|
|
1215
1806
|
validate(rules, matrix, childCount) {
|
|
1216
1807
|
const firstIndex = 0;
|
|
1217
1808
|
const lastIndex = childCount - 1;
|
|
1218
|
-
|
|
1809
|
+
iterate.forEach(rules, (rule, ri) => {
|
|
1219
1810
|
const matches = matrix.childToRules.reverse.get(ri);
|
|
1220
1811
|
const matchCount = matches.size;
|
|
1221
1812
|
this.#validateCardinality(rule, matchCount);
|
|
1222
|
-
if (matchCount === 0)
|
|
1813
|
+
if (matchCount === 0) return;
|
|
1223
1814
|
this.#validatePositions(rule, matches, firstIndex, lastIndex);
|
|
1224
|
-
}
|
|
1815
|
+
});
|
|
1225
1816
|
}
|
|
1226
1817
|
#validateCardinality(rule, matchCount) {
|
|
1227
1818
|
const { cardinality, name } = rule;
|
|
@@ -1230,21 +1821,21 @@ var RuleValidator = class _RuleValidator extends StrictBase {
|
|
|
1230
1821
|
}
|
|
1231
1822
|
const { min, max } = cardinality;
|
|
1232
1823
|
if (matchCount < min) {
|
|
1233
|
-
this.violate(
|
|
1824
|
+
this.violate(ContractDiagnostics.cardinalityMin(name, min, this.#context));
|
|
1234
1825
|
return;
|
|
1235
1826
|
}
|
|
1236
1827
|
if (matchCount > max) {
|
|
1237
|
-
this.violate(
|
|
1828
|
+
this.violate(ContractDiagnostics.cardinalityMax(name, max, this.#context));
|
|
1238
1829
|
}
|
|
1239
1830
|
}
|
|
1240
1831
|
#validatePositions(rule, matches, firstIndex, lastIndex) {
|
|
1241
1832
|
const { name, position } = rule;
|
|
1242
|
-
|
|
1833
|
+
iterate.forEachSet(matches, (index) => {
|
|
1243
1834
|
if (_RuleValidator.#isValidPosition(index, position, firstIndex, lastIndex)) {
|
|
1244
|
-
|
|
1835
|
+
return;
|
|
1245
1836
|
}
|
|
1246
|
-
this.violate(
|
|
1247
|
-
}
|
|
1837
|
+
this.violate(ContractDiagnostics.positionViolation(name, position, index, this.#context));
|
|
1838
|
+
});
|
|
1248
1839
|
}
|
|
1249
1840
|
static #isValidPosition(matchIndex, position, firstIndex, lastIndex) {
|
|
1250
1841
|
switch (position) {
|
|
@@ -1259,48 +1850,50 @@ var RuleValidator = class _RuleValidator extends StrictBase {
|
|
|
1259
1850
|
}
|
|
1260
1851
|
}
|
|
1261
1852
|
};
|
|
1262
|
-
|
|
1853
|
+
|
|
1854
|
+
// ../../lib/contract/src/children/children-evaluator.ts
|
|
1855
|
+
var ChildrenEvaluator = class extends InvariantBase {
|
|
1856
|
+
#context;
|
|
1263
1857
|
#rules;
|
|
1264
1858
|
#ruleNames;
|
|
1265
1859
|
#matcher;
|
|
1266
1860
|
#ruleValidator;
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
this.#rules = rules.map((
|
|
1271
|
-
this.#ruleNames = this.#rules.map((
|
|
1272
|
-
|
|
1861
|
+
constructor(rules, diagnostics, context = "Component") {
|
|
1862
|
+
super(diagnostics);
|
|
1863
|
+
this.#context = context;
|
|
1864
|
+
this.#rules = rules.map((r) => normalizeChildRule(r));
|
|
1865
|
+
this.#ruleNames = this.#rules.map((r) => r.name);
|
|
1866
|
+
iterate.forEach(this.#rules, (rule) => {
|
|
1273
1867
|
const { name, position, cardinality } = rule;
|
|
1274
1868
|
if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
|
|
1275
1869
|
throw new RangeError(
|
|
1276
1870
|
`ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
|
|
1277
1871
|
);
|
|
1278
1872
|
}
|
|
1279
|
-
}
|
|
1873
|
+
});
|
|
1280
1874
|
this.#matcher = new RuleMatcher(this.#rules);
|
|
1281
|
-
this.#ruleValidator = new RuleValidator(context,
|
|
1282
|
-
this.#matchBuilder = new MatchValidationErrorBuilder(context);
|
|
1875
|
+
this.#ruleValidator = new RuleValidator(context, diagnostics);
|
|
1283
1876
|
}
|
|
1284
1877
|
evaluate(children) {
|
|
1285
|
-
if (!this.
|
|
1878
|
+
if (!this.active) return;
|
|
1286
1879
|
const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
|
|
1287
1880
|
this.#ruleValidator.validate(this.#rules, matrix, children.length);
|
|
1288
1881
|
if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
|
|
1289
|
-
const errors = [];
|
|
1290
1882
|
const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
|
|
1291
|
-
|
|
1883
|
+
iterate.forEach(violating, (ci) => {
|
|
1292
1884
|
const typeName = getTypeName(children[ci]);
|
|
1293
1885
|
if (unexpectedIndices.has(ci)) {
|
|
1294
|
-
|
|
1886
|
+
this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
|
|
1295
1887
|
} else {
|
|
1296
1888
|
const matches = matrix.childToRules.forward.get(ci);
|
|
1297
1889
|
const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
|
|
1298
|
-
|
|
1890
|
+
this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
|
|
1299
1891
|
}
|
|
1300
|
-
}
|
|
1301
|
-
this.invariant(errors.length === 0, this.#matchBuilder.toError(errors).message);
|
|
1892
|
+
});
|
|
1302
1893
|
}
|
|
1303
1894
|
};
|
|
1895
|
+
|
|
1896
|
+
// ../../lib/contract/src/props/get-disabled-props.ts
|
|
1304
1897
|
var disabledProps = ({
|
|
1305
1898
|
disabled,
|
|
1306
1899
|
"aria-disabled": ariaDisabled,
|
|
@@ -1312,6 +1905,8 @@ var disabledProps = ({
|
|
|
1312
1905
|
...dataDisabled === void 0 && { "data-disabled": "" }
|
|
1313
1906
|
};
|
|
1314
1907
|
};
|
|
1908
|
+
|
|
1909
|
+
// ../../lib/contract/src/props/get-invalid-props.ts
|
|
1315
1910
|
var invalidProps = ({
|
|
1316
1911
|
invalid,
|
|
1317
1912
|
"aria-invalid": ariaInvalid,
|
|
@@ -1323,6 +1918,8 @@ var invalidProps = ({
|
|
|
1323
1918
|
...dataInvalid === void 0 && { "data-invalid": "" }
|
|
1324
1919
|
};
|
|
1325
1920
|
};
|
|
1921
|
+
|
|
1922
|
+
// ../../lib/contract/src/props/get-readonly-props.ts
|
|
1326
1923
|
var readonlyProps = ({
|
|
1327
1924
|
readOnly,
|
|
1328
1925
|
"aria-readonly": ariaReadonly,
|
|
@@ -1338,6 +1935,8 @@ var readonlyProps = ({
|
|
|
1338
1935
|
}
|
|
1339
1936
|
};
|
|
1340
1937
|
};
|
|
1938
|
+
|
|
1939
|
+
// ../core/src/html/aria-rules.ts
|
|
1341
1940
|
var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
|
|
1342
1941
|
var removeLandmarkRoleOverride = {
|
|
1343
1942
|
kind: "removeRole",
|
|
@@ -1357,154 +1956,29 @@ function landmarkRoleRule({ tag, props, implicitRole }) {
|
|
|
1357
1956
|
fixable: true,
|
|
1358
1957
|
severity: "error",
|
|
1359
1958
|
fix: removeLandmarkRoleOverride,
|
|
1360
|
-
|
|
1959
|
+
diagnostic: HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role)
|
|
1361
1960
|
}
|
|
1362
1961
|
];
|
|
1363
1962
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
return { name, match: metadataMatch };
|
|
1373
|
-
}
|
|
1374
|
-
function firstOptional(name, tag) {
|
|
1375
|
-
return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
|
|
1376
|
-
}
|
|
1377
|
-
function contract(children) {
|
|
1378
|
-
return { strict: "warn", children };
|
|
1379
|
-
}
|
|
1380
|
-
function ariaContract(aria) {
|
|
1381
|
-
return { strict: "warn", aria };
|
|
1382
|
-
}
|
|
1383
|
-
function firstChildContract(name, tag) {
|
|
1384
|
-
return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
|
|
1385
|
-
}
|
|
1386
|
-
var VOID_TAGS = [
|
|
1387
|
-
"area",
|
|
1388
|
-
"base",
|
|
1389
|
-
"br",
|
|
1390
|
-
"col",
|
|
1391
|
-
"embed",
|
|
1392
|
-
"hr",
|
|
1393
|
-
"img",
|
|
1394
|
-
"input",
|
|
1395
|
-
"link",
|
|
1396
|
-
"meta",
|
|
1397
|
-
"param",
|
|
1398
|
-
"source",
|
|
1399
|
-
"track",
|
|
1400
|
-
"wbr"
|
|
1401
|
-
];
|
|
1402
|
-
var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
|
|
1403
|
-
var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
|
|
1404
|
-
var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
|
|
1405
|
-
var tableContract = contract([
|
|
1406
|
-
firstOptional("caption", "caption"),
|
|
1407
|
-
{ name: "colgroup", match: isTag("colgroup") },
|
|
1408
|
-
{ name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
|
|
1409
|
-
{ name: "tbody", match: isTag("tbody") },
|
|
1410
|
-
{ name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
|
|
1411
|
-
{ name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
|
|
1412
|
-
]);
|
|
1413
|
-
var tableBodyContract = contract([
|
|
1414
|
-
{ name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
|
|
1415
|
-
]);
|
|
1416
|
-
var tableRowContract = contract([
|
|
1417
|
-
{ name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
|
|
1418
|
-
]);
|
|
1419
|
-
var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
|
|
1420
|
-
var dlContract = contract([
|
|
1421
|
-
{ name: "term", match: isTag("dt") },
|
|
1422
|
-
{ name: "description", match: isTag("dd") },
|
|
1423
|
-
{ name: "group", match: isTag("div") },
|
|
1424
|
-
metadata()
|
|
1425
|
-
]);
|
|
1426
|
-
var selectContract = contract([
|
|
1427
|
-
{ name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
|
|
1428
|
-
]);
|
|
1429
|
-
var optgroupContract = contract([
|
|
1430
|
-
{ name: "option", match: isTag("option", ...METADATA_TAGS) }
|
|
1431
|
-
]);
|
|
1432
|
-
var datalistContract = contract([
|
|
1433
|
-
{ name: "option", match: isTag("option", ...METADATA_TAGS) }
|
|
1434
|
-
]);
|
|
1435
|
-
var pictureContract = contract([
|
|
1436
|
-
{ name: "source", match: isTag("source", ...METADATA_TAGS) },
|
|
1437
|
-
{ name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
|
|
1438
|
-
]);
|
|
1439
|
-
var figureContract = contract([
|
|
1440
|
-
{ name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
|
|
1441
|
-
{ name: "content", match: isOpenContent("figcaption") }
|
|
1442
|
-
]);
|
|
1443
|
-
var detailsContract = firstChildContract("summary", "summary");
|
|
1444
|
-
var fieldsetContract = firstChildContract("legend", "legend");
|
|
1445
|
-
var mediaContract = contract([
|
|
1446
|
-
{ name: "source", match: isTag("source") },
|
|
1447
|
-
{ name: "track", match: isTag("track") },
|
|
1448
|
-
metadata(),
|
|
1449
|
-
{ name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
|
|
1450
|
-
]);
|
|
1451
|
-
var headContract = contract([
|
|
1452
|
-
{
|
|
1453
|
-
name: "metadata",
|
|
1454
|
-
match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
|
|
1455
|
-
}
|
|
1456
|
-
]);
|
|
1457
|
-
var htmlContract = contract([
|
|
1458
|
-
{ name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
|
|
1459
|
-
{ name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
|
|
1460
|
-
]);
|
|
1461
|
-
var voidContract = contract([]);
|
|
1462
|
-
var textOnlyContract = contract([
|
|
1463
|
-
{
|
|
1464
|
-
name: "text",
|
|
1465
|
-
match: (child) => isString(child) || isNumber(child)
|
|
1466
|
-
}
|
|
1467
|
-
]);
|
|
1468
|
-
var landmarkContract = ariaContract([landmarkRoleRule]);
|
|
1469
|
-
var CONTRACT_GROUPS = [
|
|
1470
|
-
[VOID_TAGS, voidContract],
|
|
1471
|
-
[TEXT_ONLY_TAGS, textOnlyContract],
|
|
1472
|
-
[LANDMARK_TAGS, landmarkContract],
|
|
1473
|
-
[["ul", "ol", "menu"], listContract],
|
|
1474
|
-
[["audio", "video"], mediaContract],
|
|
1475
|
-
[["thead", "tbody", "tfoot"], tableBodyContract]
|
|
1476
|
-
];
|
|
1477
|
-
function contractMap(groups) {
|
|
1478
|
-
return Object.fromEntries(
|
|
1479
|
-
groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
|
|
1480
|
-
);
|
|
1481
|
-
}
|
|
1482
|
-
var htmlContracts = {
|
|
1483
|
-
...contractMap(CONTRACT_GROUPS),
|
|
1484
|
-
table: tableContract,
|
|
1485
|
-
tr: tableRowContract,
|
|
1486
|
-
colgroup: colgroupContract,
|
|
1487
|
-
dl: dlContract,
|
|
1488
|
-
select: selectContract,
|
|
1489
|
-
optgroup: optgroupContract,
|
|
1490
|
-
datalist: datalistContract,
|
|
1491
|
-
picture: pictureContract,
|
|
1492
|
-
figure: figureContract,
|
|
1493
|
-
details: detailsContract,
|
|
1494
|
-
fieldset: fieldsetContract,
|
|
1495
|
-
head: headContract,
|
|
1496
|
-
html: htmlContract
|
|
1497
|
-
};
|
|
1498
|
-
function buildEvaluatorMap() {
|
|
1499
|
-
const map = /* @__PURE__ */ new Map();
|
|
1500
|
-
for (const [tag, { children }] of Object.entries(htmlContracts)) {
|
|
1501
|
-
if (children?.length) {
|
|
1502
|
-
map.set(tag, new ChildrenEvaluator(children, "warn", `<${tag}>`));
|
|
1963
|
+
function requireAccessibleName({ tag, props }) {
|
|
1964
|
+
if ("aria-label" in props || "aria-labelledby" in props) return [];
|
|
1965
|
+
return [
|
|
1966
|
+
{
|
|
1967
|
+
valid: false,
|
|
1968
|
+
fixable: false,
|
|
1969
|
+
severity: "warning",
|
|
1970
|
+
diagnostic: AriaDiagnostics.missingAccessibleName(tag)
|
|
1503
1971
|
}
|
|
1504
|
-
|
|
1505
|
-
return map;
|
|
1972
|
+
];
|
|
1506
1973
|
}
|
|
1507
|
-
var
|
|
1974
|
+
var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
|
|
1975
|
+
function landmarkNameAdvisory(ctx) {
|
|
1976
|
+
if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
|
|
1977
|
+
return requireAccessibleName(ctx);
|
|
1978
|
+
}
|
|
1979
|
+
var HTML_ARIA_RULES = [landmarkRoleRule, landmarkNameAdvisory];
|
|
1980
|
+
|
|
1981
|
+
// ../core/src/html/prop-normalizers.ts
|
|
1508
1982
|
var HTML_FORM_NORMALIZERS = /* @__PURE__ */ new Map([
|
|
1509
1983
|
["button", [disabledProps]],
|
|
1510
1984
|
["input", [disabledProps, readonlyProps, invalidProps]],
|
|
@@ -1517,9 +1991,10 @@ function getHtmlPropNormalizers(tag) {
|
|
|
1517
1991
|
return typeof tag === "string" ? HTML_FORM_NORMALIZERS.get(tag) : void 0;
|
|
1518
1992
|
}
|
|
1519
1993
|
|
|
1520
|
-
//
|
|
1994
|
+
// ../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.mjs
|
|
1995
|
+
import { clsx as clsx2 } from "clsx";
|
|
1521
1996
|
var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
|
|
1522
|
-
var cx =
|
|
1997
|
+
var cx = clsx2;
|
|
1523
1998
|
var cva = (base, config) => (props) => {
|
|
1524
1999
|
var _config_compoundVariants;
|
|
1525
2000
|
if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
|
|
@@ -1558,10 +2033,14 @@ var cva = (base, config) => (props) => {
|
|
|
1558
2033
|
}, []);
|
|
1559
2034
|
return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
|
|
1560
2035
|
};
|
|
2036
|
+
|
|
2037
|
+
// ../../lib/styling/src/cva.ts
|
|
1561
2038
|
function cva2(base, config) {
|
|
1562
2039
|
const fn = cva(base, config);
|
|
1563
2040
|
return (props) => cn(fn(props));
|
|
1564
2041
|
}
|
|
2042
|
+
|
|
2043
|
+
// ../../lib/styling/src/static-class-resolver.ts
|
|
1565
2044
|
var StaticClassResolver = class {
|
|
1566
2045
|
#baseClass;
|
|
1567
2046
|
#cache = /* @__PURE__ */ new Map();
|
|
@@ -1592,6 +2071,8 @@ var StaticClassResolver = class {
|
|
|
1592
2071
|
return result;
|
|
1593
2072
|
}
|
|
1594
2073
|
};
|
|
2074
|
+
|
|
2075
|
+
// ../../lib/styling/src/variant-class-resolver.ts
|
|
1595
2076
|
var VariantClassResolver = class _VariantClassResolver {
|
|
1596
2077
|
#cvaFn;
|
|
1597
2078
|
#recipeMap;
|
|
@@ -1639,15 +2120,15 @@ var VariantClassResolver = class _VariantClassResolver {
|
|
|
1639
2120
|
#createCacheKey(props, recipe) {
|
|
1640
2121
|
if (this.#variantKeys !== null) {
|
|
1641
2122
|
let key2 = recipe;
|
|
1642
|
-
|
|
2123
|
+
iterate.forEachSet(this.#variantKeys, (k) => {
|
|
1643
2124
|
if (k in props) key2 += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
|
|
1644
|
-
}
|
|
2125
|
+
});
|
|
1645
2126
|
return key2;
|
|
1646
2127
|
}
|
|
1647
2128
|
let key = recipe;
|
|
1648
|
-
|
|
2129
|
+
iterate.forEach(Object.keys(props).sort(), (k) => {
|
|
1649
2130
|
key += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
|
|
1650
|
-
}
|
|
2131
|
+
});
|
|
1651
2132
|
return key;
|
|
1652
2133
|
}
|
|
1653
2134
|
static #serializeValue(value) {
|
|
@@ -1658,6 +2139,8 @@ var VariantClassResolver = class _VariantClassResolver {
|
|
|
1658
2139
|
return `x:${String(value)}`;
|
|
1659
2140
|
}
|
|
1660
2141
|
};
|
|
2142
|
+
|
|
2143
|
+
// ../../lib/styling/src/create-class-pipeline.ts
|
|
1661
2144
|
function createClassPipeline(resolved) {
|
|
1662
2145
|
const baseClass = resolved.baseClassName ?? "";
|
|
1663
2146
|
const cvaFn = resolved.variants ? cva2("", {
|
|
@@ -1682,7 +2165,203 @@ function createClassPipeline(resolved) {
|
|
|
1682
2165
|
};
|
|
1683
2166
|
}
|
|
1684
2167
|
|
|
1685
|
-
// ../core/
|
|
2168
|
+
// ../core/src/options/resolve-factory-options.ts
|
|
2169
|
+
var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
|
|
2170
|
+
function composeNormalizers(normalizers, fn) {
|
|
2171
|
+
if (!normalizers?.length) return fn;
|
|
2172
|
+
return ((props) => {
|
|
2173
|
+
const patched = normalizers.reduce(
|
|
2174
|
+
(acc, normalizer) => ({ ...acc, ...normalizer(acc) }),
|
|
2175
|
+
props
|
|
2176
|
+
);
|
|
2177
|
+
return fn ? fn(patched) : patched;
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
function whenDefined(key, value) {
|
|
2181
|
+
return value === void 0 ? {} : { [key]: value };
|
|
2182
|
+
}
|
|
2183
|
+
function resolveFactoryOptions(options = {}) {
|
|
2184
|
+
const { styling, enforcement } = options;
|
|
2185
|
+
const composedNormalizeFn = composeNormalizers(enforcement?.props, options.normalize);
|
|
2186
|
+
const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
|
|
2187
|
+
return Object.freeze({
|
|
2188
|
+
defaultTag: options.tag ?? "div",
|
|
2189
|
+
diagnostics: enforcement?.diagnostics ?? silentDiagnostics,
|
|
2190
|
+
variantKeys,
|
|
2191
|
+
...whenDefined("displayName", options.name),
|
|
2192
|
+
...whenDefined("defaultProps", options.defaults),
|
|
2193
|
+
...whenDefined("baseClassName", styling?.base),
|
|
2194
|
+
...whenDefined("tagMap", styling?.tags),
|
|
2195
|
+
...whenDefined("recipeMap", styling?.presets),
|
|
2196
|
+
...whenDefined("variants", styling?.variants),
|
|
2197
|
+
...whenDefined("defaultVariants", styling?.defaults),
|
|
2198
|
+
...whenDefined("compoundVariants", styling?.compounds),
|
|
2199
|
+
...whenDefined("normalizeFn", composedNormalizeFn),
|
|
2200
|
+
...whenDefined("ariaRules", enforcement?.aria),
|
|
2201
|
+
...whenDefined("childRules", enforcement?.children),
|
|
2202
|
+
...whenDefined("allowedAs", enforcement?.allowedAs),
|
|
2203
|
+
...whenDefined("precomputedClasses", styling?.precomputedClasses)
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// ../core/src/options/validate-factory-options.ts
|
|
2208
|
+
function validateFactoryOptions(resolved, diagnostics) {
|
|
2209
|
+
if (!diagnostics.active) return;
|
|
2210
|
+
const name = resolved.displayName ?? "Component";
|
|
2211
|
+
const { variants } = resolved;
|
|
2212
|
+
const checkSelection = (label2, selection) => {
|
|
2213
|
+
iterate.forEachEntry(selection, (dim, value) => {
|
|
2214
|
+
if (value === void 0 || value === null) return;
|
|
2215
|
+
if (!variants || !Object.hasOwn(variants, dim)) {
|
|
2216
|
+
diagnostics.error(ContractDiagnostics.unknownVariantDim(name, label2, dim));
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
const states = variants[dim];
|
|
2220
|
+
const stateKey = String(value);
|
|
2221
|
+
if (!Object.hasOwn(states, stateKey)) {
|
|
2222
|
+
diagnostics.error(
|
|
2223
|
+
ContractDiagnostics.unknownVariantValue(name, label2, dim, stateKey, Object.keys(states))
|
|
2224
|
+
);
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
};
|
|
2228
|
+
const { recipeMap } = resolved;
|
|
2229
|
+
if (recipeMap) {
|
|
2230
|
+
iterate.forEachEntry(recipeMap, (recipeKey, selection) => {
|
|
2231
|
+
checkSelection(`preset "${recipeKey}"`, selection);
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
if (resolved.defaultVariants) checkSelection("defaults", resolved.defaultVariants);
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
// ../core/src/options/validate-render-props.ts
|
|
2238
|
+
function label(name) {
|
|
2239
|
+
return name ? `[${name}]` : "[createContractComponent]";
|
|
2240
|
+
}
|
|
2241
|
+
function validateRenderProps(diagnostics, options, props, recipeKey) {
|
|
2242
|
+
const { recipeMap, variants, displayName } = options;
|
|
2243
|
+
const tag = label(displayName);
|
|
2244
|
+
if (recipeKey !== void 0 && (!recipeMap || !Object.hasOwn(recipeMap, recipeKey))) {
|
|
2245
|
+
diagnostics.error(ContractDiagnostics.unknownRecipeKey(tag, recipeKey));
|
|
2246
|
+
}
|
|
2247
|
+
if (variants) {
|
|
2248
|
+
iterate.forEachKey(variants, (key) => {
|
|
2249
|
+
if (!Object.hasOwn(props, key)) return;
|
|
2250
|
+
const value = props[key];
|
|
2251
|
+
if (value === void 0 || value === null) return;
|
|
2252
|
+
const dim = variants[key];
|
|
2253
|
+
if (dim && !Object.hasOwn(dim, String(value))) {
|
|
2254
|
+
diagnostics.error(ContractDiagnostics.invalidVariantValue(tag, key, String(value)));
|
|
2255
|
+
}
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
// ../core/src/factory/plugin-diagnostics.ts
|
|
2261
|
+
var PluginDiagnostics = {
|
|
2262
|
+
invalidShape(received) {
|
|
2263
|
+
const got = received === null ? "null" : typeof received;
|
|
2264
|
+
return {
|
|
2265
|
+
code: "PLUGIN7001" /* PluginInvalidShape */,
|
|
2266
|
+
category: 7 /* Internal */,
|
|
2267
|
+
message: `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${got}.`
|
|
2268
|
+
};
|
|
2269
|
+
},
|
|
2270
|
+
pipelineReturnType(received) {
|
|
2271
|
+
const got = received === null ? "null" : Array.isArray(received) ? "array" : typeof received;
|
|
2272
|
+
return {
|
|
2273
|
+
code: "PLUGIN7002" /* PluginPipelineReturnType */,
|
|
2274
|
+
category: 7 /* Internal */,
|
|
2275
|
+
message: `[praxis-kit] Plugin pipeline must return a string. Got: ${got}.`
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
|
|
2280
|
+
// ../core/src/factory/plugin-invariants.ts
|
|
2281
|
+
function assertPluginShape(result) {
|
|
2282
|
+
if (result === null || typeof result !== "object")
|
|
2283
|
+
throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
|
|
2284
|
+
const plugin = result;
|
|
2285
|
+
if (typeof plugin.pipeline !== "function")
|
|
2286
|
+
throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
|
|
2287
|
+
}
|
|
2288
|
+
function guardPipeline(pipeline) {
|
|
2289
|
+
if (process.env.NODE_ENV === "production") return pipeline;
|
|
2290
|
+
return function guardedPipeline(tag, props, className, recipe) {
|
|
2291
|
+
const result = pipeline(tag, props, className, recipe);
|
|
2292
|
+
if (typeof result !== "string")
|
|
2293
|
+
throwDiagnostics.error(PluginDiagnostics.pipelineReturnType(result));
|
|
2294
|
+
return result;
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
// ../core/src/factory/create-polymorphic.ts
|
|
2299
|
+
var NOOP_CLASS_PIPELINE = (_tag, _props, className) => Array.isArray(className) ? className.join(" ") : className ?? "";
|
|
2300
|
+
function resolveClassPipeline(options, resolved, diagnostics, capabilities) {
|
|
2301
|
+
const factory = options.styling?.plugin;
|
|
2302
|
+
if (!factory) {
|
|
2303
|
+
const createClassPipeline2 = capabilities?.createClassPipeline;
|
|
2304
|
+
const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
|
|
2305
|
+
return { pluginResult: void 0, classPipeline: classPipeline2 };
|
|
2306
|
+
}
|
|
2307
|
+
const pluginResult = factory(resolved, diagnostics);
|
|
2308
|
+
assertPluginShape(pluginResult);
|
|
2309
|
+
const classPipeline = guardPipeline(pluginResult.pipeline);
|
|
2310
|
+
return { pluginResult, classPipeline };
|
|
2311
|
+
}
|
|
2312
|
+
function createRuntimeMethods(resolved, classPipeline, engine, renderDiagnostics) {
|
|
2313
|
+
return {
|
|
2314
|
+
resolveTag: makeResolveTag(resolved.defaultTag),
|
|
2315
|
+
resolveProps(props) {
|
|
2316
|
+
return mergeProps(resolved.defaultProps, props);
|
|
2317
|
+
},
|
|
2318
|
+
resolveClasses(tag, props, className, recipe) {
|
|
2319
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2320
|
+
validateRenderProps(renderDiagnostics, resolved, props, recipe);
|
|
2321
|
+
}
|
|
2322
|
+
return classPipeline(tag, props, className, recipe);
|
|
2323
|
+
},
|
|
2324
|
+
resolveAria(tag, props) {
|
|
2325
|
+
if (!engine) return { props };
|
|
2326
|
+
const result = engine.validate(tag, props);
|
|
2327
|
+
return { props: result.props };
|
|
2328
|
+
}
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
function createRuntimeObject(methods, resolved, pluginResult) {
|
|
2332
|
+
return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
|
|
2333
|
+
}
|
|
2334
|
+
function createPolymorphic(options = {}, capabilities) {
|
|
2335
|
+
const baseResolved = resolveFactoryOptions(options);
|
|
2336
|
+
const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
|
|
2337
|
+
...baseResolved,
|
|
2338
|
+
htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
|
|
2339
|
+
}) : baseResolved;
|
|
2340
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2341
|
+
validateFactoryOptions(resolved, resolved.diagnostics);
|
|
2342
|
+
}
|
|
2343
|
+
const { pluginResult, classPipeline } = resolveClassPipeline(
|
|
2344
|
+
options,
|
|
2345
|
+
resolved,
|
|
2346
|
+
resolved.diagnostics,
|
|
2347
|
+
capabilities
|
|
2348
|
+
);
|
|
2349
|
+
const allAriaRules = [
|
|
2350
|
+
.../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
|
|
2351
|
+
];
|
|
2352
|
+
const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
|
|
2353
|
+
resolved.diagnostics,
|
|
2354
|
+
allAriaRules.length ? { rules: allAriaRules } : void 0
|
|
2355
|
+
) : null;
|
|
2356
|
+
const methods = createRuntimeMethods(resolved, classPipeline, engine, resolved.diagnostics);
|
|
2357
|
+
return createRuntimeObject(
|
|
2358
|
+
methods,
|
|
2359
|
+
resolved,
|
|
2360
|
+
pluginResult
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
// ../core/src/factory/create-polymorphic-full.ts
|
|
1686
2365
|
var FULL_CAPABILITIES = {
|
|
1687
2366
|
createClassPipeline,
|
|
1688
2367
|
AriaEngine: AriaPolicyEngine,
|
|
@@ -1693,6 +2372,11 @@ function createPolymorphic2(options = {}) {
|
|
|
1693
2372
|
return createPolymorphic(options, FULL_CAPABILITIES);
|
|
1694
2373
|
}
|
|
1695
2374
|
|
|
2375
|
+
// ../../lib/adapter-utils/src/define-component.ts
|
|
2376
|
+
function defineContractComponent(options) {
|
|
2377
|
+
return (factory) => factory(options);
|
|
2378
|
+
}
|
|
2379
|
+
|
|
1696
2380
|
// ../../lib/adapter-utils/src/build-core-runtime.ts
|
|
1697
2381
|
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
1698
2382
|
function buildCoreRuntime(normalized) {
|
|
@@ -1702,8 +2386,8 @@ function buildCoreRuntime(normalized) {
|
|
|
1702
2386
|
}
|
|
1703
2387
|
|
|
1704
2388
|
// ../../lib/adapter-utils/src/build-engines.ts
|
|
1705
|
-
function buildEngines(
|
|
1706
|
-
return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules,
|
|
2389
|
+
function buildEngines(diagnostics, childRules, context) {
|
|
2390
|
+
return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
|
|
1707
2391
|
}
|
|
1708
2392
|
|
|
1709
2393
|
// ../../lib/adapter-utils/src/compose-filter.ts
|
|
@@ -1716,34 +2400,32 @@ function composeFilter(ownedKeys, filterProps) {
|
|
|
1716
2400
|
}
|
|
1717
2401
|
|
|
1718
2402
|
// ../../lib/adapter-utils/src/resolve-adapter-common-options.ts
|
|
1719
|
-
function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent",
|
|
2403
|
+
function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics) {
|
|
1720
2404
|
return {
|
|
1721
2405
|
name: options.name ?? defaultName,
|
|
1722
|
-
|
|
2406
|
+
diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
|
|
1723
2407
|
};
|
|
1724
2408
|
}
|
|
1725
2409
|
|
|
1726
2410
|
// ../../lib/adapter-utils/src/slot-validator.ts
|
|
1727
|
-
var SlotValidator = class extends
|
|
2411
|
+
var SlotValidator = class extends InvariantBase {
|
|
1728
2412
|
#name;
|
|
1729
2413
|
#elementTerm;
|
|
1730
|
-
constructor(name,
|
|
1731
|
-
super(
|
|
2414
|
+
constructor(name, diagnostics, elementTerm) {
|
|
2415
|
+
super(diagnostics);
|
|
1732
2416
|
this.#name = name;
|
|
1733
2417
|
this.#elementTerm = elementTerm;
|
|
1734
2418
|
}
|
|
1735
2419
|
assertExclusive() {
|
|
1736
|
-
this.violate(
|
|
2420
|
+
this.violate(SlotDiagnostics.exclusive(this.#name));
|
|
1737
2421
|
}
|
|
1738
2422
|
warnDiscardedChildren(count) {
|
|
1739
|
-
|
|
1740
|
-
this.warn(
|
|
1741
|
-
`${this.#name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${this.#elementTerm}s are valid asChild children.`
|
|
1742
|
-
);
|
|
2423
|
+
this.warn(SlotDiagnostics.discardedChildren(this.#name, this.#elementTerm, count));
|
|
1743
2424
|
}
|
|
1744
2425
|
assertSingleChild(count) {
|
|
1745
|
-
|
|
1746
|
-
|
|
2426
|
+
this.violate(
|
|
2427
|
+
count === 0 ? SlotDiagnostics.singleChildRequired(this.#name, this.#elementTerm) : SlotDiagnostics.singleChildExceeded(this.#name, this.#elementTerm, count)
|
|
2428
|
+
);
|
|
1747
2429
|
}
|
|
1748
2430
|
};
|
|
1749
2431
|
|
|
@@ -1755,12 +2437,12 @@ function buildRuntime(options) {
|
|
|
1755
2437
|
const normalized = normalizeOptions(options);
|
|
1756
2438
|
const { runtime, ownedKeys } = buildCoreRuntime(normalized);
|
|
1757
2439
|
const { childrenEvaluator } = buildEngines(
|
|
1758
|
-
normalized.
|
|
2440
|
+
normalized.diagnostics,
|
|
1759
2441
|
normalized.enforcement?.children,
|
|
1760
2442
|
normalized.name
|
|
1761
2443
|
);
|
|
1762
2444
|
const filterProps = composeFilter(ownedKeys, normalized.filterProps);
|
|
1763
|
-
const slotValidator = new SlotValidator(normalized.name, normalized.
|
|
2445
|
+
const slotValidator = new SlotValidator(normalized.name, normalized.diagnostics, "Snippet");
|
|
1764
2446
|
return {
|
|
1765
2447
|
runtime,
|
|
1766
2448
|
filterProps,
|