@a13y/devtools 0.1.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/LICENSE +21 -0
- package/README.md +278 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1620 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +1510 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/invariants/index.d.ts +30 -0
- package/dist/runtime/invariants/index.js +452 -0
- package/dist/runtime/invariants/index.js.map +1 -0
- package/dist/runtime/validators/index.d.ts +140 -0
- package/dist/runtime/validators/index.js +1201 -0
- package/dist/runtime/validators/index.js.map +1 -0
- package/dist/runtime/warnings/index.d.ts +206 -0
- package/dist/runtime/warnings/index.js +194 -0
- package/dist/runtime/warnings/index.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { isDevelopment } from '@a13y/core/runtime/env';
|
|
2
|
+
|
|
3
|
+
// @a13y/devtools - Development-time validators (tree-shakeable in production)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
// src/runtime/warnings/warning-system.ts
|
|
7
|
+
var Styles = {
|
|
8
|
+
reset: "\x1B[0m",
|
|
9
|
+
bold: "\x1B[1m",
|
|
10
|
+
dim: "\x1B[2m",
|
|
11
|
+
blue: "\x1B[34m",
|
|
12
|
+
cyan: "\x1B[36m",
|
|
13
|
+
gray: "\x1B[90m",
|
|
14
|
+
// Backgrounds
|
|
15
|
+
bgRed: "\x1B[41m",
|
|
16
|
+
bgYellow: "\x1B[43m",
|
|
17
|
+
bgBlue: "\x1B[44m"
|
|
18
|
+
};
|
|
19
|
+
var style = (text, ...styles) => {
|
|
20
|
+
return `${styles.join("")}${text}${Styles.reset}`;
|
|
21
|
+
};
|
|
22
|
+
var WarningSystemClass = class {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.config = {
|
|
25
|
+
enabled: true,
|
|
26
|
+
minSeverity: "warn",
|
|
27
|
+
showElement: true,
|
|
28
|
+
showStackTrace: true,
|
|
29
|
+
deduplicate: true,
|
|
30
|
+
onWarning: () => {
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
this.warningCache = /* @__PURE__ */ new Set();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Configure the warning system
|
|
37
|
+
*/
|
|
38
|
+
configure(config) {
|
|
39
|
+
this.config = { ...this.config, ...config };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Emit a warning
|
|
43
|
+
*/
|
|
44
|
+
warn(warning) {
|
|
45
|
+
if (!this.config.enabled) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const severityLevel = { info: 0, warn: 1, error: 2 };
|
|
49
|
+
if (severityLevel[warning.severity] < severityLevel[this.config.minSeverity]) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (this.config.deduplicate) {
|
|
53
|
+
const key = this.getWarningKey(warning);
|
|
54
|
+
if (this.warningCache.has(key)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.warningCache.add(key);
|
|
58
|
+
}
|
|
59
|
+
if (this.config.onWarning) {
|
|
60
|
+
this.config.onWarning(warning);
|
|
61
|
+
}
|
|
62
|
+
this.printWarning(warning);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear warning cache
|
|
66
|
+
*/
|
|
67
|
+
clearCache() {
|
|
68
|
+
this.warningCache.clear();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generate a unique key for a warning
|
|
72
|
+
*/
|
|
73
|
+
getWarningKey(warning) {
|
|
74
|
+
const parts = [warning.code, warning.message];
|
|
75
|
+
if (warning.element) {
|
|
76
|
+
const tag = warning.element.tagName.toLowerCase();
|
|
77
|
+
const id = warning.element.id;
|
|
78
|
+
const classes = Array.from(warning.element.classList).join(".");
|
|
79
|
+
parts.push(`${tag}#${id}.${classes}`);
|
|
80
|
+
}
|
|
81
|
+
return parts.join("|");
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Print warning to console
|
|
85
|
+
*/
|
|
86
|
+
printWarning(warning) {
|
|
87
|
+
const { severity, code, category, message, element, wcag, fixes } = warning;
|
|
88
|
+
const badge = this.getSeverityBadge(severity);
|
|
89
|
+
console.group(
|
|
90
|
+
`${badge} ${style(code, Styles.bold, Styles.cyan)} ${style(category, Styles.dim)}`
|
|
91
|
+
);
|
|
92
|
+
console.log(style(message, Styles.bold));
|
|
93
|
+
if (element && this.config.showElement) {
|
|
94
|
+
console.log(style("\nElement:", Styles.bold));
|
|
95
|
+
console.log(element);
|
|
96
|
+
}
|
|
97
|
+
if (wcag) {
|
|
98
|
+
console.log(style("\nWCAG:", Styles.bold), `${wcag.criterion} (Level ${wcag.level})`);
|
|
99
|
+
console.log(style("Learn more:", Styles.blue), wcag.url);
|
|
100
|
+
}
|
|
101
|
+
if (fixes.length > 0) {
|
|
102
|
+
console.log(style("\nHow to fix:", Styles.bold, Styles.cyan));
|
|
103
|
+
fixes.forEach((fix, index) => {
|
|
104
|
+
console.log(`${index + 1}. ${fix.description}`);
|
|
105
|
+
if (fix.example) {
|
|
106
|
+
console.log(style("\n Example:", Styles.dim));
|
|
107
|
+
console.log(style(` ${fix.example}`, Styles.dim, Styles.gray));
|
|
108
|
+
}
|
|
109
|
+
if (fix.learnMoreUrl) {
|
|
110
|
+
console.log(style(" Learn more:", Styles.blue), fix.learnMoreUrl);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (severity === "error" && this.config.showStackTrace) {
|
|
115
|
+
console.log(style("\nStack trace:", Styles.dim));
|
|
116
|
+
console.trace();
|
|
117
|
+
}
|
|
118
|
+
console.groupEnd();
|
|
119
|
+
console.log("");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get severity badge for console
|
|
123
|
+
*/
|
|
124
|
+
getSeverityBadge(severity) {
|
|
125
|
+
switch (severity) {
|
|
126
|
+
case "error":
|
|
127
|
+
return style(" ERROR ", Styles.bold, Styles.bgRed);
|
|
128
|
+
case "warn":
|
|
129
|
+
return style(" WARN ", Styles.bold, Styles.bgYellow);
|
|
130
|
+
case "info":
|
|
131
|
+
return style(" INFO ", Styles.bold, Styles.bgBlue);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
var WarningSystem = new WarningSystemClass();
|
|
136
|
+
var createWarning = (partial) => {
|
|
137
|
+
return {
|
|
138
|
+
fixes: [],
|
|
139
|
+
...partial
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/runtime/warnings/warning-types.ts
|
|
144
|
+
var WarningCodes = {
|
|
145
|
+
// Focus Management (001-099)
|
|
146
|
+
FOCUS_LOST: "A13Y001",
|
|
147
|
+
// Keyboard Navigation (100-199)
|
|
148
|
+
NOT_KEYBOARD_ACCESSIBLE: "A13Y100",
|
|
149
|
+
MISSING_KEYBOARD_HANDLER: "A13Y101",
|
|
150
|
+
INVALID_TABINDEX: "A13Y102",
|
|
151
|
+
// Accessible Name (200-299)
|
|
152
|
+
MISSING_ACCESSIBLE_NAME: "A13Y200",
|
|
153
|
+
REDUNDANT_ARIA: "A13Y303",
|
|
154
|
+
MISSING_REQUIRED_ARIA: "A13Y304"};
|
|
155
|
+
var WCAGUrls = {
|
|
156
|
+
"2.1.1": "https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html",
|
|
157
|
+
"2.4.3": "https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html",
|
|
158
|
+
"4.1.2": "https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html"};
|
|
159
|
+
|
|
160
|
+
// src/runtime/invariants/invariants.ts
|
|
161
|
+
var invariant = (condition, message) => {
|
|
162
|
+
if (!isDevelopment()) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!condition) {
|
|
166
|
+
throw new Error(`[@a13y/devtools] Invariant violation: ${message}`);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var assertHasAccessibleName = (element, context) => {
|
|
170
|
+
if (!isDevelopment()) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
import('@a13y/core/runtime/aria').then(({ getAccessibleName }) => {
|
|
174
|
+
const name = getAccessibleName(element);
|
|
175
|
+
if (!name || name.trim().length === 0) {
|
|
176
|
+
WarningSystem.warn(
|
|
177
|
+
createWarning({
|
|
178
|
+
code: WarningCodes.MISSING_ACCESSIBLE_NAME,
|
|
179
|
+
severity: "error",
|
|
180
|
+
category: "accessible-name",
|
|
181
|
+
message: `Element is missing an accessible name${context ? ` in ${context}` : ""}`,
|
|
182
|
+
element,
|
|
183
|
+
wcag: {
|
|
184
|
+
criterion: "4.1.2",
|
|
185
|
+
level: "A",
|
|
186
|
+
url: WCAGUrls["4.1.2"]
|
|
187
|
+
},
|
|
188
|
+
fixes: [
|
|
189
|
+
{
|
|
190
|
+
description: "Add an aria-label attribute",
|
|
191
|
+
example: `<${element.tagName.toLowerCase()} aria-label="Descriptive name">`
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
description: "Add text content",
|
|
195
|
+
example: `<${element.tagName.toLowerCase()}>Click me</${element.tagName.toLowerCase()}>`
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
description: "Use aria-labelledby to reference another element",
|
|
199
|
+
example: `<${element.tagName.toLowerCase()} aria-labelledby="label-id">`
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}).catch(() => {
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
var assertKeyboardAccessible = (element, context) => {
|
|
209
|
+
if (!isDevelopment()) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const isButton = element instanceof HTMLButtonElement;
|
|
213
|
+
const isLink = element instanceof HTMLAnchorElement && element.hasAttribute("href");
|
|
214
|
+
const isInput = element instanceof HTMLInputElement;
|
|
215
|
+
const hasTabindex = element.hasAttribute("tabindex");
|
|
216
|
+
const tabindex = hasTabindex ? parseInt(element.getAttribute("tabindex") || "0", 10) : -1;
|
|
217
|
+
const isAccessible = isButton || isLink || isInput || hasTabindex && tabindex >= 0;
|
|
218
|
+
if (!isAccessible) {
|
|
219
|
+
WarningSystem.warn(
|
|
220
|
+
createWarning({
|
|
221
|
+
code: WarningCodes.NOT_KEYBOARD_ACCESSIBLE,
|
|
222
|
+
severity: "error",
|
|
223
|
+
category: "keyboard-navigation",
|
|
224
|
+
message: `Element is not keyboard accessible${context ? ` in ${context}` : ""}`,
|
|
225
|
+
element,
|
|
226
|
+
wcag: {
|
|
227
|
+
criterion: "2.1.1",
|
|
228
|
+
level: "A",
|
|
229
|
+
url: WCAGUrls["2.1.1"]
|
|
230
|
+
},
|
|
231
|
+
fixes: [
|
|
232
|
+
{
|
|
233
|
+
description: "Use a semantic HTML element (button, a, input)",
|
|
234
|
+
example: `<button type="button">Click me</button>`
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
description: 'Add tabindex="0" to make it focusable',
|
|
238
|
+
example: `<${element.tagName.toLowerCase()} tabindex="0">`
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
description: "Add keyboard event handlers (Enter, Space)",
|
|
242
|
+
example: `element.addEventListener('keydown', (e) => {
|
|
243
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
// Handle activation
|
|
246
|
+
}
|
|
247
|
+
});`
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
})
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
const hasClickHandler = element.getAttribute("onclick") !== null;
|
|
254
|
+
if (hasClickHandler && !isButton && !isLink) {
|
|
255
|
+
WarningSystem.warn(
|
|
256
|
+
createWarning({
|
|
257
|
+
code: WarningCodes.MISSING_KEYBOARD_HANDLER,
|
|
258
|
+
severity: "warn",
|
|
259
|
+
category: "keyboard-navigation",
|
|
260
|
+
message: `Element has click handler but no keyboard handlers${context ? ` in ${context}` : ""}`,
|
|
261
|
+
element,
|
|
262
|
+
wcag: {
|
|
263
|
+
criterion: "2.1.1",
|
|
264
|
+
level: "A",
|
|
265
|
+
url: WCAGUrls["2.1.1"]
|
|
266
|
+
},
|
|
267
|
+
fixes: [
|
|
268
|
+
{
|
|
269
|
+
description: "Add onKeyDown handler for Enter and Space keys",
|
|
270
|
+
example: `const handleKeyDown = (e: KeyboardEvent) => {
|
|
271
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
272
|
+
e.preventDefault();
|
|
273
|
+
onClick(e);
|
|
274
|
+
}
|
|
275
|
+
};`
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
})
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var assertValidTabindex = (element) => {
|
|
283
|
+
if (!isDevelopment()) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const tabindex = element.getAttribute("tabindex");
|
|
287
|
+
if (tabindex === null) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const value = parseInt(tabindex, 10);
|
|
291
|
+
if (value > 0) {
|
|
292
|
+
WarningSystem.warn(
|
|
293
|
+
createWarning({
|
|
294
|
+
code: WarningCodes.INVALID_TABINDEX,
|
|
295
|
+
severity: "warn",
|
|
296
|
+
category: "keyboard-navigation",
|
|
297
|
+
message: `Positive tabindex (${value}) creates confusing tab order`,
|
|
298
|
+
element,
|
|
299
|
+
wcag: {
|
|
300
|
+
criterion: "2.4.3",
|
|
301
|
+
level: "A",
|
|
302
|
+
url: WCAGUrls["2.4.3"]
|
|
303
|
+
},
|
|
304
|
+
fixes: [
|
|
305
|
+
{
|
|
306
|
+
description: 'Use tabindex="0" to add element to natural tab order',
|
|
307
|
+
example: `<div tabindex="0">Focusable in natural order</div>`
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
description: 'Use tabindex="-1" to remove from tab order (programmatic focus only)',
|
|
311
|
+
example: `<div tabindex="-1">Not in tab order</div>`
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
description: "Restructure DOM to achieve desired focus order",
|
|
315
|
+
learnMoreUrl: "https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html"
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
})
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
var assertValidAriaAttributes = (element) => {
|
|
323
|
+
if (!isDevelopment()) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const role = element.getAttribute("role");
|
|
327
|
+
const ariaAttributes = Array.from(element.attributes).filter(
|
|
328
|
+
(attr) => attr.name.startsWith("aria-")
|
|
329
|
+
);
|
|
330
|
+
if (!role && ariaAttributes.length > 0 && !isSemanticElement(element)) {
|
|
331
|
+
WarningSystem.warn(
|
|
332
|
+
createWarning({
|
|
333
|
+
code: WarningCodes.MISSING_REQUIRED_ARIA,
|
|
334
|
+
severity: "warn",
|
|
335
|
+
category: "aria-usage",
|
|
336
|
+
message: "Element has ARIA attributes but no explicit role",
|
|
337
|
+
element,
|
|
338
|
+
wcag: {
|
|
339
|
+
criterion: "4.1.2",
|
|
340
|
+
level: "A",
|
|
341
|
+
url: WCAGUrls["4.1.2"]
|
|
342
|
+
},
|
|
343
|
+
fixes: [
|
|
344
|
+
{
|
|
345
|
+
description: "Add an appropriate role attribute",
|
|
346
|
+
example: `<div role="button" aria-pressed="false">Toggle</div>`
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
description: "Use a semantic HTML element instead",
|
|
350
|
+
example: `<button aria-pressed="false">Toggle</button>`
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
})
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
if (role && isSemanticElement(element)) {
|
|
357
|
+
const semanticRole = getImplicitRole(element);
|
|
358
|
+
if (role === semanticRole) {
|
|
359
|
+
WarningSystem.warn(
|
|
360
|
+
createWarning({
|
|
361
|
+
code: WarningCodes.REDUNDANT_ARIA,
|
|
362
|
+
severity: "info",
|
|
363
|
+
category: "aria-usage",
|
|
364
|
+
message: `Role "${role}" is redundant on <${element.tagName.toLowerCase()}>`,
|
|
365
|
+
element,
|
|
366
|
+
fixes: [
|
|
367
|
+
{
|
|
368
|
+
description: "Remove the redundant role attribute",
|
|
369
|
+
example: `<${element.tagName.toLowerCase()}> (role="${role}" is implicit)`
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
})
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
var assertFocusVisible = (context) => {
|
|
378
|
+
if (!isDevelopment()) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
setTimeout(() => {
|
|
382
|
+
const activeElement = document.activeElement;
|
|
383
|
+
if (!activeElement || activeElement === document.body) {
|
|
384
|
+
WarningSystem.warn(
|
|
385
|
+
createWarning({
|
|
386
|
+
code: WarningCodes.FOCUS_LOST,
|
|
387
|
+
severity: "warn",
|
|
388
|
+
category: "focus-management",
|
|
389
|
+
message: `Focus was lost${context ? ` after ${context}` : ""}`,
|
|
390
|
+
wcag: {
|
|
391
|
+
criterion: "2.4.3",
|
|
392
|
+
level: "A",
|
|
393
|
+
url: WCAGUrls["2.4.3"]
|
|
394
|
+
},
|
|
395
|
+
fixes: [
|
|
396
|
+
{
|
|
397
|
+
description: "Ensure focus is moved to an appropriate element",
|
|
398
|
+
example: `// After closing dialog
|
|
399
|
+
const returnElement = document.getElementById('trigger-button');
|
|
400
|
+
returnElement?.focus();`
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
description: "Use FocusManager to save and restore focus",
|
|
404
|
+
example: `import { FocusManager } from '@a13y/core/runtime/focus';
|
|
405
|
+
|
|
406
|
+
const restore = FocusManager.saveFocus();
|
|
407
|
+
// ... perform action ...
|
|
408
|
+
restore();`
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
})
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}, 100);
|
|
415
|
+
};
|
|
416
|
+
var isSemanticElement = (element) => {
|
|
417
|
+
const tag = element.tagName.toLowerCase();
|
|
418
|
+
const semanticTags = [
|
|
419
|
+
"button",
|
|
420
|
+
"a",
|
|
421
|
+
"input",
|
|
422
|
+
"select",
|
|
423
|
+
"textarea",
|
|
424
|
+
"nav",
|
|
425
|
+
"main",
|
|
426
|
+
"article",
|
|
427
|
+
"section",
|
|
428
|
+
"header",
|
|
429
|
+
"footer",
|
|
430
|
+
"aside"
|
|
431
|
+
];
|
|
432
|
+
return semanticTags.includes(tag);
|
|
433
|
+
};
|
|
434
|
+
var getImplicitRole = (element) => {
|
|
435
|
+
const tag = element.tagName.toLowerCase();
|
|
436
|
+
const roleMap = {
|
|
437
|
+
button: "button",
|
|
438
|
+
a: "link",
|
|
439
|
+
nav: "navigation",
|
|
440
|
+
main: "main",
|
|
441
|
+
article: "article",
|
|
442
|
+
section: "region",
|
|
443
|
+
header: "banner",
|
|
444
|
+
footer: "contentinfo",
|
|
445
|
+
aside: "complementary"
|
|
446
|
+
};
|
|
447
|
+
return roleMap[tag] || null;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
export { assertFocusVisible, assertHasAccessibleName, assertKeyboardAccessible, assertValidAriaAttributes, assertValidTabindex, invariant };
|
|
451
|
+
//# sourceMappingURL=index.js.map
|
|
452
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/warnings/warning-system.ts","../../../src/runtime/warnings/warning-types.ts","../../../src/runtime/invariants/invariants.ts"],"names":[],"mappings":";;;;;;AAUA,IAAM,MAAA,GAAS;AAAA,EACb,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,GAAA,EAAK,SAAA;AAAA,EAKL,IAAA,EAAM,UAAA;AAAA,EACN,IAAA,EAAM,UAAA;AAAA,EACN,IAAA,EAAM,UAAA;AAAA;AAAA,EAGN,KAAA,EAAO,UAAA;AAAA,EACP,QAAA,EAAU,UAAA;AAAA,EACV,MAAA,EAAQ;AACV,CAAA;AAKA,IAAM,KAAA,GAAQ,CAAC,IAAA,EAAA,GAAiB,MAAA,KAA6B;AAC3D,EAAA,OAAO,CAAA,EAAG,OAAO,IAAA,CAAK,EAAE,CAAC,CAAA,EAAG,IAAI,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA,CAAA;AACjD,CAAA;AA6CA,IAAM,qBAAN,MAAyB;AAAA,EAAzB,WAAA,GAAA;AACE,IAAA,IAAA,CAAQ,MAAA,GAAwC;AAAA,MAC9C,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,WAAA,EAAa,IAAA;AAAA,MACb,cAAA,EAAgB,IAAA;AAAA,MAChB,WAAA,EAAa,IAAA;AAAA,MACb,WAAW,MAAM;AAAA,MAAC;AAAA,KACpB;AAEA,IAAA,IAAA,CAAQ,YAAA,uBAAmB,GAAA,EAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKvC,UAAU,MAAA,EAAmC;AAC3C,IAAA,IAAA,CAAK,SAAS,EAAE,GAAG,IAAA,CAAK,MAAA,EAAQ,GAAG,MAAA,EAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAAA,EAAqC;AACxC,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,OAAA,EAAS;AACxB,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,gBAAgB,EAAE,IAAA,EAAM,GAAG,IAAA,EAAM,CAAA,EAAG,OAAO,CAAA,EAAE;AACnD,IAAA,IAAI,aAAA,CAAc,QAAQ,QAAQ,CAAA,GAAI,cAAc,IAAA,CAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AAC5E,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,CAAK,OAAO,WAAA,EAAa;AAC3B,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,CAAc,OAAO,CAAA;AACtC,MAAA,IAAI,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA,EAAG;AAC9B,QAAA;AAAA,MACF;AACA,MAAA,IAAA,CAAK,YAAA,CAAa,IAAI,GAAG,CAAA;AAAA,IAC3B;AAGA,IAAA,IAAI,IAAA,CAAK,OAAO,SAAA,EAAW;AACzB,MAAA,IAAA,CAAK,MAAA,CAAO,UAAU,OAAO,CAAA;AAAA,IAC/B;AAGA,IAAA,IAAA,CAAK,aAAa,OAAO,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAAA,EAAuC;AAC3D,IAAA,MAAM,KAAA,GAAQ,CAAC,OAAA,CAAQ,IAAA,EAAM,QAAQ,OAAO,CAAA;AAE5C,IAAA,IAAI,QAAQ,OAAA,EAAS;AAEnB,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAY;AAChD,MAAA,MAAM,EAAA,GAAK,QAAQ,OAAA,CAAQ,EAAA;AAC3B,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,OAAA,CAAQ,QAAQ,SAAS,CAAA,CAAE,KAAK,GAAG,CAAA;AAC9D,MAAA,KAAA,CAAM,KAAK,CAAA,EAAG,GAAG,IAAI,EAAE,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AAAA,IACtC;AAEA,IAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAA,EAAqC;AACxD,IAAA,MAAM,EAAE,UAAU,IAAA,EAAM,QAAA,EAAU,SAAS,OAAA,EAAS,IAAA,EAAM,OAAM,GAAI,OAAA;AAGpE,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAG5C,IAAA,OAAA,CAAQ,KAAA;AAAA,MACN,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,KAAA,CAAM,MAAM,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,QAAA,EAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,KAClF;AAGA,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,OAAA,EAAS,MAAA,CAAO,IAAI,CAAC,CAAA;AAGvC,IAAA,IAAI,OAAA,IAAW,IAAA,CAAK,MAAA,CAAO,WAAA,EAAa;AACtC,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,YAAA,EAAc,MAAA,CAAO,IAAI,CAAC,CAAA;AAC5C,MAAA,OAAA,CAAQ,IAAI,OAAO,CAAA;AAAA,IACrB;AAGA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,SAAA,EAAW,MAAA,CAAO,IAAI,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA,QAAA,EAAW,IAAA,CAAK,KAAK,CAAA,CAAA,CAAG,CAAA;AACpF,MAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,aAAA,EAAe,OAAO,IAAI,CAAA,EAAG,KAAK,GAAG,CAAA;AAAA,IACzD;AAGA,IAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,MAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,eAAA,EAAiB,OAAO,IAAA,EAAM,MAAA,CAAO,IAAI,CAAC,CAAA;AAC5D,MAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,GAAA,EAAK,KAAA,KAAU;AAC5B,QAAA,OAAA,CAAQ,IAAI,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAA,EAAA,EAAK,GAAA,CAAI,WAAW,CAAA,CAAE,CAAA;AAE9C,QAAA,IAAI,IAAI,OAAA,EAAS;AACf,UAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,eAAA,EAAiB,MAAA,CAAO,GAAG,CAAC,CAAA;AAC9C,UAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,CAAA,GAAA,EAAM,GAAA,CAAI,OAAO,IAAI,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,QACjE;AAEA,QAAA,IAAI,IAAI,YAAA,EAAc;AACpB,UAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,gBAAA,EAAkB,OAAO,IAAI,CAAA,EAAG,IAAI,YAAY,CAAA;AAAA,QACpE;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAGA,IAAA,IAAI,QAAA,KAAa,OAAA,IAAW,IAAA,CAAK,MAAA,CAAO,cAAA,EAAgB;AACtD,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,gBAAA,EAAkB,MAAA,CAAO,GAAG,CAAC,CAAA;AAC/C,MAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,IAChB;AAEA,IAAA,OAAA,CAAQ,QAAA,EAAS;AACjB,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,QAAA,EAAmC;AAC1D,IAAA,QAAQ,QAAA;AAAU,MAChB,KAAK,OAAA;AACH,QAAA,OAAO,KAAA,CAAM,SAAA,EAAW,MAAA,CAAO,IAAA,EAAM,OAAO,KAAK,CAAA;AAAA,MACnD,KAAK,MAAA;AACH,QAAA,OAAO,KAAA,CAAM,QAAA,EAAU,MAAA,CAAO,IAAA,EAAM,OAAO,QAAQ,CAAA;AAAA,MACrD,KAAK,MAAA;AACH,QAAA,OAAO,KAAA,CAAM,QAAA,EAAU,MAAA,CAAO,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA;AACrD,EACF;AACF,CAAA;AAKO,IAAM,aAAA,GAAgB,IAAI,kBAAA,EAAmB;AAK7C,IAAM,aAAA,GAAgB,CAC3B,OAAA,KAGyB;AACzB,EAAA,OAAO;AAAA,IACL,OAAO,EAAC;AAAA,IACR,GAAG;AAAA,GACL;AACF,CAAA;;;AC9IO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,UAAA,EAAY,SAAA;AAAA,EAIQ;AAAA,EAGpB,uBAAA,EAAyB,SAAA;AAAA,EACzB,wBAAA,EAA0B,SAAA;AAAA,EAC1B,gBAAA,EAAkB,SAAA;AAAA,EAEG;AAAA,EAGrB,uBAAA,EAAyB,SAAA;AAAA,EAUzB,cAAA,EAAgB,SAAA;AAAA,EAChB,qBAAA,EAAuB,SAiBzB,CAAA;AAKO,IAAM,QAAA,GAAW;AAAA,EAGtB,OAAA,EAAS,2DAAA;AAAA,EAET,OAAA,EAAS,8DAAA;AAAA,EAGT,OAAA,EAAS,kEAEX,CAAA;;;AClJO,IAAM,SAAA,GAAY,CAAC,SAAA,EAAoB,OAAA,KAA0B;AACtE,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,OAAO,CAAA,CAAE,CAAA;AAAA,EACpE;AACF;AAKO,IAAM,uBAAA,GAA0B,CAAC,OAAA,EAAkB,OAAA,KAA2B;AACnF,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAGA,EAAA,OAAO,yBAAyB,CAAA,CAC7B,IAAA,CAAK,CAAC,EAAE,mBAAkB,KAAM;AAC/B,IAAA,MAAM,IAAA,GAAO,kBAAkB,OAAO,CAAA;AAEtC,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AACrC,MAAA,aAAA,CAAc,IAAA;AAAA,QACZ,aAAA,CAAc;AAAA,UACZ,MAAM,YAAA,CAAa,uBAAA;AAAA,UACnB,QAAA,EAAU,OAAA;AAAA,UACV,QAAA,EAAU,iBAAA;AAAA,UACV,SAAS,CAAA,qCAAA,EAAwC,OAAA,GAAU,CAAA,IAAA,EAAO,OAAO,KAAK,EAAE,CAAA,CAAA;AAAA,UAChF,OAAA;AAAA,UACA,IAAA,EAAM;AAAA,YACJ,SAAA,EAAW,OAAA;AAAA,YACX,KAAA,EAAO,GAAA;AAAA,YACP,GAAA,EAAK,SAAS,OAAO;AAAA,WACvB;AAAA,UACA,KAAA,EAAO;AAAA,YACL;AAAA,cACE,WAAA,EAAa,6BAAA;AAAA,cACb,OAAA,EAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAA,+BAAA;AAAA,aAC5C;AAAA,YACA;AAAA,cACE,WAAA,EAAa,kBAAA;AAAA,cACb,OAAA,EAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAa,CAAA,WAAA,EAAc,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAa,CAAA,CAAA;AAAA,aACvF;AAAA,YACA;AAAA,cACE,WAAA,EAAa,kDAAA;AAAA,cACb,OAAA,EAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAA,4BAAA;AAAA;AAC5C;AACF,SACD;AAAA,OACH;AAAA,IACF;AAAA,EACF,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AAAA,EAEb,CAAC,CAAA;AACL;AAKO,IAAM,wBAAA,GAA2B,CAAC,OAAA,EAAkB,OAAA,KAA2B;AACpF,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,OAAA,YAAmB,iBAAA;AACpC,EAAA,MAAM,MAAA,GAAS,OAAA,YAAmB,iBAAA,IAAqB,OAAA,CAAQ,aAAa,MAAM,CAAA;AAClF,EAAA,MAAM,UAAU,OAAA,YAAmB,gBAAA;AACnC,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,YAAA,CAAa,UAAU,CAAA;AACnD,EAAA,MAAM,QAAA,GAAW,cAAc,QAAA,CAAS,OAAA,CAAQ,aAAa,UAAU,CAAA,IAAK,GAAA,EAAK,EAAE,CAAA,GAAI,EAAA;AAGvF,EAAA,MAAM,YAAA,GAAe,QAAA,IAAY,MAAA,IAAU,OAAA,IAAY,eAAe,QAAA,IAAY,CAAA;AAElF,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,aAAA,CAAc,IAAA;AAAA,MACZ,aAAA,CAAc;AAAA,QACZ,MAAM,YAAA,CAAa,uBAAA;AAAA,QACnB,QAAA,EAAU,OAAA;AAAA,QACV,QAAA,EAAU,qBAAA;AAAA,QACV,SAAS,CAAA,kCAAA,EAAqC,OAAA,GAAU,CAAA,IAAA,EAAO,OAAO,KAAK,EAAE,CAAA,CAAA;AAAA,QAC7E,OAAA;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,SAAA,EAAW,OAAA;AAAA,UACX,KAAA,EAAO,GAAA;AAAA,UACP,GAAA,EAAK,SAAS,OAAO;AAAA,SACvB;AAAA,QACA,KAAA,EAAO;AAAA,UACL;AAAA,YACE,WAAA,EAAa,gDAAA;AAAA,YACb,OAAA,EAAS,CAAA,uCAAA;AAAA,WACX;AAAA,UACA;AAAA,YACE,WAAA,EAAa,uCAAA;AAAA,YACb,OAAA,EAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAA,cAAA;AAAA,WAC5C;AAAA,UACA;AAAA,YACE,WAAA,EAAa,4CAAA;AAAA,YACb,OAAA,EAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAAA;AAAA;AAMX;AACF,OACD;AAAA,KACH;AAAA,EACF;AAGA,EAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,YAAA,CAAa,SAAS,CAAA,KAAM,IAAA;AAC5D,EAAA,IAAI,eAAA,IAAmB,CAAC,QAAA,IAAY,CAAC,MAAA,EAAQ;AAC3C,IAAA,aAAA,CAAc,IAAA;AAAA,MACZ,aAAA,CAAc;AAAA,QACZ,MAAM,YAAA,CAAa,wBAAA;AAAA,QACnB,QAAA,EAAU,MAAA;AAAA,QACV,QAAA,EAAU,qBAAA;AAAA,QACV,SAAS,CAAA,kDAAA,EAAqD,OAAA,GAAU,CAAA,IAAA,EAAO,OAAO,KAAK,EAAE,CAAA,CAAA;AAAA,QAC7F,OAAA;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,SAAA,EAAW,OAAA;AAAA,UACX,KAAA,EAAO,GAAA;AAAA,UACP,GAAA,EAAK,SAAS,OAAO;AAAA,SACvB;AAAA,QACA,KAAA,EAAO;AAAA,UACL;AAAA,YACE,WAAA,EAAa,gDAAA;AAAA,YACb,OAAA,EAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAAA;AAMX;AACF,OACD;AAAA,KACH;AAAA,EACF;AACF;AAKO,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAA2B;AAC7D,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,YAAA,CAAa,UAAU,CAAA;AAChD,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,QAAA,EAAU,EAAE,CAAA;AAGnC,EAAA,IAAI,QAAQ,CAAA,EAAG;AACb,IAAA,aAAA,CAAc,IAAA;AAAA,MACZ,aAAA,CAAc;AAAA,QACZ,MAAM,YAAA,CAAa,gBAAA;AAAA,QACnB,QAAA,EAAU,MAAA;AAAA,QACV,QAAA,EAAU,qBAAA;AAAA,QACV,OAAA,EAAS,sBAAsB,KAAK,CAAA,6BAAA,CAAA;AAAA,QACpC,OAAA;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,SAAA,EAAW,OAAA;AAAA,UACX,KAAA,EAAO,GAAA;AAAA,UACP,GAAA,EAAK,SAAS,OAAO;AAAA,SACvB;AAAA,QACA,KAAA,EAAO;AAAA,UACL;AAAA,YACE,WAAA,EAAa,sDAAA;AAAA,YACb,OAAA,EAAS,CAAA,kDAAA;AAAA,WACX;AAAA,UACA;AAAA,YACE,WAAA,EAAa,sEAAA;AAAA,YACb,OAAA,EAAS,CAAA,yCAAA;AAAA,WACX;AAAA,UACA;AAAA,YACE,WAAA,EAAa,gDAAA;AAAA,YACb,YAAA,EAAc;AAAA;AAChB;AACF,OACD;AAAA,KACH;AAAA,EACF;AACF;AAKO,IAAM,yBAAA,GAA4B,CAAC,OAAA,KAA2B;AACnE,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,YAAA,CAAa,MAAM,CAAA;AACxC,EAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,UAAU,CAAA,CAAE,MAAA;AAAA,IAAO,CAAC,IAAA,KAC5D,IAAA,CAAK,IAAA,CAAK,WAAW,OAAO;AAAA,GAC9B;AAGA,EAAA,IAAI,CAAC,QAAQ,cAAA,CAAe,MAAA,GAAS,KAAK,CAAC,iBAAA,CAAkB,OAAO,CAAA,EAAG;AACrE,IAAA,aAAA,CAAc,IAAA;AAAA,MACZ,aAAA,CAAc;AAAA,QACZ,MAAM,YAAA,CAAa,qBAAA;AAAA,QACnB,QAAA,EAAU,MAAA;AAAA,QACV,QAAA,EAAU,YAAA;AAAA,QACV,OAAA,EAAS,kDAAA;AAAA,QACT,OAAA;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,SAAA,EAAW,OAAA;AAAA,UACX,KAAA,EAAO,GAAA;AAAA,UACP,GAAA,EAAK,SAAS,OAAO;AAAA,SACvB;AAAA,QACA,KAAA,EAAO;AAAA,UACL;AAAA,YACE,WAAA,EAAa,mCAAA;AAAA,YACb,OAAA,EAAS,CAAA,oDAAA;AAAA,WACX;AAAA,UACA;AAAA,YACE,WAAA,EAAa,qCAAA;AAAA,YACb,OAAA,EAAS,CAAA,4CAAA;AAAA;AACX;AACF,OACD;AAAA,KACH;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,IAAQ,iBAAA,CAAkB,OAAO,CAAA,EAAG;AACtC,IAAA,MAAM,YAAA,GAAe,gBAAgB,OAAO,CAAA;AAC5C,IAAA,IAAI,SAAS,YAAA,EAAc;AACzB,MAAA,aAAA,CAAc,IAAA;AAAA,QACZ,aAAA,CAAc;AAAA,UACZ,MAAM,YAAA,CAAa,cAAA;AAAA,UACnB,QAAA,EAAU,MAAA;AAAA,UACV,QAAA,EAAU,YAAA;AAAA,UACV,SAAS,CAAA,MAAA,EAAS,IAAI,sBAAsB,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAA,CAAA,CAAA;AAAA,UACzE,OAAA;AAAA,UACA,KAAA,EAAO;AAAA,YACL;AAAA,cACE,WAAA,EAAa,qCAAA;AAAA,cACb,SAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,QAAQ,WAAA,EAAa,YAAY,IAAI,CAAA,cAAA;AAAA;AAC5D;AACF,SACD;AAAA,OACH;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,kBAAA,GAAqB,CAAC,OAAA,KAA2B;AAC5D,EAAA,IAAI,CAAC,eAAc,EAAG;AACpB,IAAA;AAAA,EACF;AAGA,EAAA,UAAA,CAAW,MAAM;AACf,IAAA,MAAM,gBAAgB,QAAA,CAAS,aAAA;AAE/B,IAAA,IAAI,CAAC,aAAA,IAAiB,aAAA,KAAkB,QAAA,CAAS,IAAA,EAAM;AACrD,MAAA,aAAA,CAAc,IAAA;AAAA,QACZ,aAAA,CAAc;AAAA,UACZ,MAAM,YAAA,CAAa,UAAA;AAAA,UACnB,QAAA,EAAU,MAAA;AAAA,UACV,QAAA,EAAU,kBAAA;AAAA,UACV,SAAS,CAAA,cAAA,EAAiB,OAAA,GAAU,CAAA,OAAA,EAAU,OAAO,KAAK,EAAE,CAAA,CAAA;AAAA,UAC5D,IAAA,EAAM;AAAA,YACJ,SAAA,EAAW,OAAA;AAAA,YACX,KAAA,EAAO,GAAA;AAAA,YACP,GAAA,EAAK,SAAS,OAAO;AAAA,WACvB;AAAA,UACA,KAAA,EAAO;AAAA,YACL;AAAA,cACE,WAAA,EAAa,iDAAA;AAAA,cACb,OAAA,EAAS,CAAA;AAAA;AAAA,uBAAA;AAAA,aAGX;AAAA,YACA;AAAA,cACE,WAAA,EAAa,4CAAA;AAAA,cACb,OAAA,EAAS,CAAA;;AAAA;AAAA;AAAA,UAAA;AAAA;AAKX;AACF,SACD;AAAA,OACH;AAAA,IACF;AAAA,EACF,GAAG,GAAG,CAAA;AACR;AAKA,IAAM,iBAAA,GAAoB,CAAC,OAAA,KAA8B;AACvD,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAY;AACxC,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,QAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,OAAO,YAAA,CAAa,SAAS,GAAG,CAAA;AAClC,CAAA;AAKA,IAAM,eAAA,GAAkB,CAAC,OAAA,KAAoC;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAY;AAExC,EAAA,MAAM,OAAA,GAAkC;AAAA,IACtC,MAAA,EAAQ,QAAA;AAAA,IACR,CAAA,EAAG,MAAA;AAAA,IACH,GAAA,EAAK,YAAA;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,OAAA,EAAS,SAAA;AAAA,IACT,OAAA,EAAS,QAAA;AAAA,IACT,MAAA,EAAQ,QAAA;AAAA,IACR,MAAA,EAAQ,aAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAEA,EAAA,OAAO,OAAA,CAAQ,GAAG,CAAA,IAAK,IAAA;AACzB,CAAA","file":"index.js","sourcesContent":["/**\n * @a13y/devtools - Warning System\n * Structured warning system with styled console output\n */\n\nimport type { AccessibilityWarning, WarningSeverity } from './warning-types';\n\n/**\n * Console styling for warnings\n */\nconst Styles = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n\n // Colors\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n\n // Backgrounds\n bgRed: '\\x1b[41m',\n bgYellow: '\\x1b[43m',\n bgBlue: '\\x1b[44m',\n} as const;\n\n/**\n * Format a message with console styling\n */\nconst style = (text: string, ...styles: string[]): string => {\n return `${styles.join('')}${text}${Styles.reset}`;\n};\n\n/**\n * Configuration for warning system\n */\nexport interface WarningSystemConfig {\n /**\n * Enable/disable warnings\n * @default true in development\n */\n enabled?: boolean;\n\n /**\n * Minimum severity to show\n * @default 'warn'\n */\n minSeverity?: WarningSeverity;\n\n /**\n * Show element in console\n * @default true\n */\n showElement?: boolean;\n\n /**\n * Show stack traces for errors\n * @default true\n */\n showStackTrace?: boolean;\n\n /**\n * Deduplicate warnings\n * @default true\n */\n deduplicate?: boolean;\n\n /**\n * Custom warning handler\n */\n onWarning?: (warning: AccessibilityWarning) => void;\n}\n\n/**\n * Warning system class\n */\nclass WarningSystemClass {\n private config: Required<WarningSystemConfig> = {\n enabled: true,\n minSeverity: 'warn',\n showElement: true,\n showStackTrace: true,\n deduplicate: true,\n onWarning: () => {},\n };\n\n private warningCache = new Set<string>();\n\n /**\n * Configure the warning system\n */\n configure(config: WarningSystemConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Emit a warning\n */\n warn(warning: AccessibilityWarning): void {\n if (!this.config.enabled) {\n return;\n }\n\n // Check severity threshold\n const severityLevel = { info: 0, warn: 1, error: 2 };\n if (severityLevel[warning.severity] < severityLevel[this.config.minSeverity]) {\n return;\n }\n\n // Deduplicate\n if (this.config.deduplicate) {\n const key = this.getWarningKey(warning);\n if (this.warningCache.has(key)) {\n return;\n }\n this.warningCache.add(key);\n }\n\n // Custom handler\n if (this.config.onWarning) {\n this.config.onWarning(warning);\n }\n\n // Console output\n this.printWarning(warning);\n }\n\n /**\n * Clear warning cache\n */\n clearCache(): void {\n this.warningCache.clear();\n }\n\n /**\n * Generate a unique key for a warning\n */\n private getWarningKey(warning: AccessibilityWarning): string {\n const parts = [warning.code, warning.message];\n\n if (warning.element) {\n // Use element's tag, id, and classes for uniqueness\n const tag = warning.element.tagName.toLowerCase();\n const id = warning.element.id;\n const classes = Array.from(warning.element.classList).join('.');\n parts.push(`${tag}#${id}.${classes}`);\n }\n\n return parts.join('|');\n }\n\n /**\n * Print warning to console\n */\n private printWarning(warning: AccessibilityWarning): void {\n const { severity, code, category, message, element, wcag, fixes } = warning;\n\n // Severity badge\n const badge = this.getSeverityBadge(severity);\n\n // Header\n console.group(\n `${badge} ${style(code, Styles.bold, Styles.cyan)} ${style(category, Styles.dim)}`\n );\n\n // Message\n console.log(style(message, Styles.bold));\n\n // Element\n if (element && this.config.showElement) {\n console.log(style('\\nElement:', Styles.bold));\n console.log(element);\n }\n\n // WCAG info\n if (wcag) {\n console.log(style('\\nWCAG:', Styles.bold), `${wcag.criterion} (Level ${wcag.level})`);\n console.log(style('Learn more:', Styles.blue), wcag.url);\n }\n\n // Fix suggestions\n if (fixes.length > 0) {\n console.log(style('\\nHow to fix:', Styles.bold, Styles.cyan));\n fixes.forEach((fix, index) => {\n console.log(`${index + 1}. ${fix.description}`);\n\n if (fix.example) {\n console.log(style('\\n Example:', Styles.dim));\n console.log(style(` ${fix.example}`, Styles.dim, Styles.gray));\n }\n\n if (fix.learnMoreUrl) {\n console.log(style(' Learn more:', Styles.blue), fix.learnMoreUrl);\n }\n });\n }\n\n // Stack trace for errors\n if (severity === 'error' && this.config.showStackTrace) {\n console.log(style('\\nStack trace:', Styles.dim));\n console.trace();\n }\n\n console.groupEnd();\n console.log(''); // Empty line for spacing\n }\n\n /**\n * Get severity badge for console\n */\n private getSeverityBadge(severity: WarningSeverity): string {\n switch (severity) {\n case 'error':\n return style(' ERROR ', Styles.bold, Styles.bgRed);\n case 'warn':\n return style(' WARN ', Styles.bold, Styles.bgYellow);\n case 'info':\n return style(' INFO ', Styles.bold, Styles.bgBlue);\n }\n }\n}\n\n/**\n * Singleton warning system\n */\nexport const WarningSystem = new WarningSystemClass();\n\n/**\n * Helper to create a warning\n */\nexport const createWarning = (\n partial: Omit<AccessibilityWarning, 'fixes'> & {\n fixes?: AccessibilityWarning['fixes'];\n }\n): AccessibilityWarning => {\n return {\n fixes: [],\n ...partial,\n };\n};\n","/**\n * @a13y/devtools - Warning Types\n * Type definitions for accessibility warnings\n */\n\n/**\n * Warning severity level\n */\nexport type WarningSeverity = 'error' | 'warn' | 'info';\n\n/**\n * WCAG level for the violation\n */\nexport type WCAGLevel = 'A' | 'AA' | 'AAA';\n\n/**\n * Category of accessibility issue\n */\nexport type WarningCategory =\n | 'focus-management'\n | 'keyboard-navigation'\n | 'aria-usage'\n | 'accessible-name'\n | 'semantic-html'\n | 'wcag-compliance'\n | 'performance';\n\n/**\n * Fix suggestion for a warning\n */\nexport interface FixSuggestion {\n /**\n * Description of how to fix the issue\n */\n description: string;\n\n /**\n * Code example showing the fix\n */\n example?: string;\n\n /**\n * Link to documentation\n */\n learnMoreUrl?: string;\n}\n\n/**\n * Accessibility warning\n */\nexport interface AccessibilityWarning {\n /**\n * Unique warning code (e.g., \"A13Y001\")\n */\n code: string;\n\n /**\n * Severity level\n */\n severity: WarningSeverity;\n\n /**\n * Category of the issue\n */\n category: WarningCategory;\n\n /**\n * Human-readable message\n */\n message: string;\n\n /**\n * Element that caused the warning\n */\n element?: Element;\n\n /**\n * WCAG criterion violated\n */\n wcag?: {\n criterion: string;\n level: WCAGLevel;\n url: string;\n };\n\n /**\n * Suggestions for fixing the issue\n */\n fixes: FixSuggestion[];\n\n /**\n * Additional context\n */\n context?: Record<string, unknown>;\n}\n\n/**\n * Warning code definitions\n */\nexport const WarningCodes = {\n // Focus Management (001-099)\n FOCUS_LOST: 'A13Y001',\n FOCUS_NOT_VISIBLE: 'A13Y002',\n FOCUS_TRAP_BROKEN: 'A13Y003',\n FOCUS_ORDER_INVALID: 'A13Y004',\n FOCUS_NOT_RESTORED: 'A13Y005',\n\n // Keyboard Navigation (100-199)\n NOT_KEYBOARD_ACCESSIBLE: 'A13Y100',\n MISSING_KEYBOARD_HANDLER: 'A13Y101',\n INVALID_TABINDEX: 'A13Y102',\n ROVING_TABINDEX_BROKEN: 'A13Y103',\n MISSING_ESC_HANDLER: 'A13Y104',\n\n // Accessible Name (200-299)\n MISSING_ACCESSIBLE_NAME: 'A13Y200',\n EMPTY_ACCESSIBLE_NAME: 'A13Y201',\n DUPLICATE_ID: 'A13Y202',\n INVALID_LABELLEDBY: 'A13Y203',\n PLACEHOLDER_AS_LABEL: 'A13Y204',\n\n // ARIA Usage (300-399)\n INVALID_ARIA_ROLE: 'A13Y300',\n INVALID_ARIA_ATTRIBUTE: 'A13Y301',\n CONFLICTING_ARIA: 'A13Y302',\n REDUNDANT_ARIA: 'A13Y303',\n MISSING_REQUIRED_ARIA: 'A13Y304',\n INVALID_ARIA_VALUE: 'A13Y305',\n\n // Semantic HTML (400-499)\n DIV_BUTTON: 'A13Y400',\n DIV_LINK: 'A13Y401',\n MISSING_LANDMARK: 'A13Y402',\n INVALID_NESTING: 'A13Y403',\n\n // WCAG Compliance (500-599)\n CONTRAST_INSUFFICIENT: 'A13Y500',\n TARGET_SIZE_TOO_SMALL: 'A13Y501',\n ANIMATION_NO_REDUCE_MOTION: 'A13Y502',\n\n // Performance (600-699)\n TOO_MANY_LIVE_REGIONS: 'A13Y600',\n EXCESSIVE_ANNOUNCEMENTS: 'A13Y601',\n} as const;\n\n/**\n * WCAG criterion URLs\n */\nexport const WCAGUrls = {\n '1.3.1': 'https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html',\n '1.4.3': 'https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html',\n '2.1.1': 'https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html',\n '2.1.2': 'https://www.w3.org/WAI/WCAG22/Understanding/no-keyboard-trap.html',\n '2.4.3': 'https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html',\n '2.4.7': 'https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html',\n '2.5.5': 'https://www.w3.org/WAI/WCAG22/Understanding/target-size.html',\n '4.1.2': 'https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html',\n '4.1.3': 'https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html',\n} as const;\n","/**\n * @a13y/devtools - Invariants\n * Development-only assertions for accessibility constraints\n */\n\nimport { isDevelopment } from '@a13y/core/runtime/env';\nimport { createWarning, WarningSystem } from '../warnings/warning-system';\nimport { WarningCodes, WCAGUrls } from '../warnings/warning-types';\n\n/**\n * Assert that a condition is true, throw error if false (development only)\n */\nexport const invariant = (condition: boolean, message: string): void => {\n if (!isDevelopment()) {\n return;\n }\n\n if (!condition) {\n throw new Error(`[@a13y/devtools] Invariant violation: ${message}`);\n }\n};\n\n/**\n * Assert that an element has an accessible name\n */\nexport const assertHasAccessibleName = (element: Element, context?: string): void => {\n if (!isDevelopment()) {\n return;\n }\n\n // Import getAccessibleName at runtime to avoid circular deps\n import('@a13y/core/runtime/aria')\n .then(({ getAccessibleName }) => {\n const name = getAccessibleName(element);\n\n if (!name || name.trim().length === 0) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.MISSING_ACCESSIBLE_NAME,\n severity: 'error',\n category: 'accessible-name',\n message: `Element is missing an accessible name${context ? ` in ${context}` : ''}`,\n element,\n wcag: {\n criterion: '4.1.2',\n level: 'A',\n url: WCAGUrls['4.1.2'],\n },\n fixes: [\n {\n description: 'Add an aria-label attribute',\n example: `<${element.tagName.toLowerCase()} aria-label=\"Descriptive name\">`,\n },\n {\n description: 'Add text content',\n example: `<${element.tagName.toLowerCase()}>Click me</${element.tagName.toLowerCase()}>`,\n },\n {\n description: 'Use aria-labelledby to reference another element',\n example: `<${element.tagName.toLowerCase()} aria-labelledby=\"label-id\">`,\n },\n ],\n })\n );\n }\n })\n .catch(() => {\n // Silently fail if @a13y/core is not available\n });\n};\n\n/**\n * Assert that an element is keyboard accessible\n */\nexport const assertKeyboardAccessible = (element: Element, context?: string): void => {\n if (!isDevelopment()) {\n return;\n }\n\n const isButton = element instanceof HTMLButtonElement;\n const isLink = element instanceof HTMLAnchorElement && element.hasAttribute('href');\n const isInput = element instanceof HTMLInputElement;\n const hasTabindex = element.hasAttribute('tabindex');\n const tabindex = hasTabindex ? parseInt(element.getAttribute('tabindex') || '0', 10) : -1;\n\n // Check if element is naturally keyboard accessible or has tabindex >= 0\n const isAccessible = isButton || isLink || isInput || (hasTabindex && tabindex >= 0);\n\n if (!isAccessible) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.NOT_KEYBOARD_ACCESSIBLE,\n severity: 'error',\n category: 'keyboard-navigation',\n message: `Element is not keyboard accessible${context ? ` in ${context}` : ''}`,\n element,\n wcag: {\n criterion: '2.1.1',\n level: 'A',\n url: WCAGUrls['2.1.1'],\n },\n fixes: [\n {\n description: 'Use a semantic HTML element (button, a, input)',\n example: `<button type=\"button\">Click me</button>`,\n },\n {\n description: 'Add tabindex=\"0\" to make it focusable',\n example: `<${element.tagName.toLowerCase()} tabindex=\"0\">`,\n },\n {\n description: 'Add keyboard event handlers (Enter, Space)',\n example: `element.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n // Handle activation\n }\n});`,\n },\n ],\n })\n );\n }\n\n // Check for click handler without keyboard handler\n const hasClickHandler = element.getAttribute('onclick') !== null;\n if (hasClickHandler && !isButton && !isLink) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.MISSING_KEYBOARD_HANDLER,\n severity: 'warn',\n category: 'keyboard-navigation',\n message: `Element has click handler but no keyboard handlers${context ? ` in ${context}` : ''}`,\n element,\n wcag: {\n criterion: '2.1.1',\n level: 'A',\n url: WCAGUrls['2.1.1'],\n },\n fixes: [\n {\n description: 'Add onKeyDown handler for Enter and Space keys',\n example: `const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick(e);\n }\n};`,\n },\n ],\n })\n );\n }\n};\n\n/**\n * Assert that tabindex value is valid\n */\nexport const assertValidTabindex = (element: Element): void => {\n if (!isDevelopment()) {\n return;\n }\n\n const tabindex = element.getAttribute('tabindex');\n if (tabindex === null) {\n return;\n }\n\n const value = parseInt(tabindex, 10);\n\n // Warn about positive tabindex (antipattern)\n if (value > 0) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.INVALID_TABINDEX,\n severity: 'warn',\n category: 'keyboard-navigation',\n message: `Positive tabindex (${value}) creates confusing tab order`,\n element,\n wcag: {\n criterion: '2.4.3',\n level: 'A',\n url: WCAGUrls['2.4.3'],\n },\n fixes: [\n {\n description: 'Use tabindex=\"0\" to add element to natural tab order',\n example: `<div tabindex=\"0\">Focusable in natural order</div>`,\n },\n {\n description: 'Use tabindex=\"-1\" to remove from tab order (programmatic focus only)',\n example: `<div tabindex=\"-1\">Not in tab order</div>`,\n },\n {\n description: 'Restructure DOM to achieve desired focus order',\n learnMoreUrl: 'https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html',\n },\n ],\n })\n );\n }\n};\n\n/**\n * Assert that ARIA attributes are valid for the element's role\n */\nexport const assertValidAriaAttributes = (element: Element): void => {\n if (!isDevelopment()) {\n return;\n }\n\n const role = element.getAttribute('role');\n const ariaAttributes = Array.from(element.attributes).filter((attr) =>\n attr.name.startsWith('aria-')\n );\n\n // Check for ARIA attributes without role\n if (!role && ariaAttributes.length > 0 && !isSemanticElement(element)) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.MISSING_REQUIRED_ARIA,\n severity: 'warn',\n category: 'aria-usage',\n message: 'Element has ARIA attributes but no explicit role',\n element,\n wcag: {\n criterion: '4.1.2',\n level: 'A',\n url: WCAGUrls['4.1.2'],\n },\n fixes: [\n {\n description: 'Add an appropriate role attribute',\n example: `<div role=\"button\" aria-pressed=\"false\">Toggle</div>`,\n },\n {\n description: 'Use a semantic HTML element instead',\n example: `<button aria-pressed=\"false\">Toggle</button>`,\n },\n ],\n })\n );\n }\n\n // Check for redundant ARIA on semantic elements\n if (role && isSemanticElement(element)) {\n const semanticRole = getImplicitRole(element);\n if (role === semanticRole) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.REDUNDANT_ARIA,\n severity: 'info',\n category: 'aria-usage',\n message: `Role \"${role}\" is redundant on <${element.tagName.toLowerCase()}>`,\n element,\n fixes: [\n {\n description: 'Remove the redundant role attribute',\n example: `<${element.tagName.toLowerCase()}> (role=\"${role}\" is implicit)`,\n },\n ],\n })\n );\n }\n }\n};\n\n/**\n * Assert that focus is visible after an action\n */\nexport const assertFocusVisible = (context?: string): void => {\n if (!isDevelopment()) {\n return;\n }\n\n // Delay check to allow focus to settle\n setTimeout(() => {\n const activeElement = document.activeElement;\n\n if (!activeElement || activeElement === document.body) {\n WarningSystem.warn(\n createWarning({\n code: WarningCodes.FOCUS_LOST,\n severity: 'warn',\n category: 'focus-management',\n message: `Focus was lost${context ? ` after ${context}` : ''}`,\n wcag: {\n criterion: '2.4.3',\n level: 'A',\n url: WCAGUrls['2.4.3'],\n },\n fixes: [\n {\n description: 'Ensure focus is moved to an appropriate element',\n example: `// After closing dialog\nconst returnElement = document.getElementById('trigger-button');\nreturnElement?.focus();`,\n },\n {\n description: 'Use FocusManager to save and restore focus',\n example: `import { FocusManager } from '@a13y/core/runtime/focus';\n\nconst restore = FocusManager.saveFocus();\n// ... perform action ...\nrestore();`,\n },\n ],\n })\n );\n }\n }, 100);\n};\n\n/**\n * Check if element is a semantic HTML element\n */\nconst isSemanticElement = (element: Element): boolean => {\n const tag = element.tagName.toLowerCase();\n const semanticTags = [\n 'button',\n 'a',\n 'input',\n 'select',\n 'textarea',\n 'nav',\n 'main',\n 'article',\n 'section',\n 'header',\n 'footer',\n 'aside',\n ];\n return semanticTags.includes(tag);\n};\n\n/**\n * Get implicit ARIA role of an element\n */\nconst getImplicitRole = (element: Element): string | null => {\n const tag = element.tagName.toLowerCase();\n\n const roleMap: Record<string, string> = {\n button: 'button',\n a: 'link',\n nav: 'navigation',\n main: 'main',\n article: 'article',\n section: 'region',\n header: 'banner',\n footer: 'contentinfo',\n aside: 'complementary',\n };\n\n return roleMap[tag] || null;\n};\n"]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @a13y/devtools - ARIA Validator
|
|
3
|
+
* Validates ARIA attributes and usage
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* ARIA validator class
|
|
7
|
+
*/
|
|
8
|
+
declare class AriaValidator {
|
|
9
|
+
/**
|
|
10
|
+
* Validate ARIA attributes on an element
|
|
11
|
+
*/
|
|
12
|
+
validateElement(element: Element): void;
|
|
13
|
+
/**
|
|
14
|
+
* Validate accessible name
|
|
15
|
+
*/
|
|
16
|
+
validateAccessibleName(element: Element, context?: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Validate role attribute
|
|
19
|
+
*/
|
|
20
|
+
private validateRole;
|
|
21
|
+
/**
|
|
22
|
+
* Validate ARIA attribute
|
|
23
|
+
*/
|
|
24
|
+
private validateAriaAttribute;
|
|
25
|
+
/**
|
|
26
|
+
* Validate ID references in ARIA attributes
|
|
27
|
+
*/
|
|
28
|
+
private validateIdReferences;
|
|
29
|
+
/**
|
|
30
|
+
* Validate required ARIA props for a role
|
|
31
|
+
*/
|
|
32
|
+
private validateRequiredProps;
|
|
33
|
+
/**
|
|
34
|
+
* Check for redundant ARIA
|
|
35
|
+
*/
|
|
36
|
+
private checkRedundantAria;
|
|
37
|
+
/**
|
|
38
|
+
* Check for conflicting ARIA attributes
|
|
39
|
+
*/
|
|
40
|
+
private checkConflictingAria;
|
|
41
|
+
/**
|
|
42
|
+
* Get all ARIA attributes from an element
|
|
43
|
+
*/
|
|
44
|
+
private getAriaAttributes;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Singleton ARIA validator
|
|
48
|
+
*/
|
|
49
|
+
declare const ariaValidator: AriaValidator;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @a13y/devtools - Focus Validator
|
|
53
|
+
* Validates focus management and visual focus indicators
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Focus validator class
|
|
57
|
+
*/
|
|
58
|
+
declare class FocusValidator {
|
|
59
|
+
private focusHistory;
|
|
60
|
+
private isActive;
|
|
61
|
+
/**
|
|
62
|
+
* Start monitoring focus changes
|
|
63
|
+
*/
|
|
64
|
+
start(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Stop monitoring focus changes
|
|
67
|
+
*/
|
|
68
|
+
stop(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Validate that focus is visible
|
|
71
|
+
*/
|
|
72
|
+
validateFocusVisible(element: Element): void;
|
|
73
|
+
/**
|
|
74
|
+
* Validate focus trap
|
|
75
|
+
*/
|
|
76
|
+
validateFocusTrap(container: Element, expectedTrapped: boolean): void;
|
|
77
|
+
/**
|
|
78
|
+
* Validate focus order
|
|
79
|
+
*/
|
|
80
|
+
validateFocusOrder(container: Element): void;
|
|
81
|
+
/**
|
|
82
|
+
* Track focus restoration after actions
|
|
83
|
+
*/
|
|
84
|
+
expectFocusRestoration(expectedElement: Element, action: string): void;
|
|
85
|
+
private handleFocusIn;
|
|
86
|
+
private handleFocusOut;
|
|
87
|
+
private getFocusableElements;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Singleton focus validator
|
|
91
|
+
*/
|
|
92
|
+
declare const focusValidator: FocusValidator;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @a13y/devtools - Keyboard Validator
|
|
96
|
+
* Validates keyboard accessibility
|
|
97
|
+
*/
|
|
98
|
+
/**
|
|
99
|
+
* Keyboard validator class
|
|
100
|
+
*/
|
|
101
|
+
declare class KeyboardValidator {
|
|
102
|
+
/**
|
|
103
|
+
* Validate that interactive elements are keyboard accessible
|
|
104
|
+
*/
|
|
105
|
+
validateInteractiveElement(element: Element): void;
|
|
106
|
+
/**
|
|
107
|
+
* Validate that a container's children are reachable via keyboard
|
|
108
|
+
*/
|
|
109
|
+
validateContainer(container: Element): void;
|
|
110
|
+
/**
|
|
111
|
+
* Validate roving tabindex implementation
|
|
112
|
+
*/
|
|
113
|
+
validateRovingTabindex(container: Element): void;
|
|
114
|
+
/**
|
|
115
|
+
* Check for escape key handler in dialogs/modals
|
|
116
|
+
*/
|
|
117
|
+
validateEscapeHandler(container: Element, shouldHaveEscape: boolean): void;
|
|
118
|
+
/**
|
|
119
|
+
* Analyze an element for keyboard accessibility
|
|
120
|
+
*/
|
|
121
|
+
private analyzeElement;
|
|
122
|
+
/**
|
|
123
|
+
* Check if element is focusable
|
|
124
|
+
*/
|
|
125
|
+
private isFocusable;
|
|
126
|
+
/**
|
|
127
|
+
* Find all interactive elements in a container
|
|
128
|
+
*/
|
|
129
|
+
private findInteractiveElements;
|
|
130
|
+
/**
|
|
131
|
+
* Check for div/span styled as button (antipattern)
|
|
132
|
+
*/
|
|
133
|
+
private checkForDivButton;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Singleton keyboard validator
|
|
137
|
+
*/
|
|
138
|
+
declare const keyboardValidator: KeyboardValidator;
|
|
139
|
+
|
|
140
|
+
export { AriaValidator, FocusValidator, KeyboardValidator, ariaValidator, focusValidator, keyboardValidator };
|