@tanstack/devtools-a11y 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/dist/esm/core/components/IssueCard.d.ts +10 -0
  3. package/dist/esm/core/components/IssueCard.js +83 -0
  4. package/dist/esm/core/components/IssueCard.js.map +1 -0
  5. package/dist/esm/core/components/IssueList.d.ts +6 -0
  6. package/dist/esm/core/components/IssueList.js +134 -0
  7. package/dist/esm/core/components/IssueList.js.map +1 -0
  8. package/dist/esm/core/components/Settings.d.ts +6 -0
  9. package/dist/esm/core/components/Settings.js +251 -0
  10. package/dist/esm/core/components/Settings.js.map +1 -0
  11. package/dist/esm/core/components/Shell.d.ts +2 -0
  12. package/dist/esm/core/components/Shell.js +214 -0
  13. package/dist/esm/core/components/Shell.js.map +1 -0
  14. package/dist/esm/core/components/index.d.ts +2 -0
  15. package/dist/esm/core/components/index.js +14 -0
  16. package/dist/esm/core/components/index.js.map +1 -0
  17. package/dist/esm/core/contexts/allyContext.d.ts +17 -0
  18. package/dist/esm/core/contexts/allyContext.js +66 -0
  19. package/dist/esm/core/contexts/allyContext.js.map +1 -0
  20. package/dist/esm/core/core.d.ts +19 -0
  21. package/dist/esm/core/core.js +8 -0
  22. package/dist/esm/core/core.js.map +1 -0
  23. package/dist/esm/core/index.d.ts +9 -0
  24. package/dist/esm/core/index.js +9 -0
  25. package/dist/esm/core/index.js.map +1 -0
  26. package/dist/esm/core/production.d.ts +2 -0
  27. package/dist/esm/core/production.js +4 -0
  28. package/dist/esm/core/styles/styles.d.ts +85 -0
  29. package/dist/esm/core/styles/styles.js +547 -0
  30. package/dist/esm/core/styles/styles.js.map +1 -0
  31. package/dist/esm/core/types/types.d.ts +141 -0
  32. package/dist/esm/core/utils/ally-audit.utils.d.ts +19 -0
  33. package/dist/esm/core/utils/ally-audit.utils.js +226 -0
  34. package/dist/esm/core/utils/ally-audit.utils.js.map +1 -0
  35. package/dist/esm/core/utils/config.utils.d.ts +17 -0
  36. package/dist/esm/core/utils/config.utils.js +63 -0
  37. package/dist/esm/core/utils/config.utils.js.map +1 -0
  38. package/dist/esm/core/utils/custom-audit.utils.d.ts +13 -0
  39. package/dist/esm/core/utils/custom-audit.utils.js +426 -0
  40. package/dist/esm/core/utils/custom-audit.utils.js.map +1 -0
  41. package/dist/esm/core/utils/export-audit.uitls.d.ts +17 -0
  42. package/dist/esm/core/utils/export-audit.uitls.js +83 -0
  43. package/dist/esm/core/utils/export-audit.uitls.js.map +1 -0
  44. package/dist/esm/core/utils/ui.utils.d.ts +24 -0
  45. package/dist/esm/core/utils/ui.utils.js +330 -0
  46. package/dist/esm/core/utils/ui.utils.js.map +1 -0
  47. package/dist/esm/react/A11yDevtools.d.ts +5 -0
  48. package/dist/esm/react/A11yDevtools.js +8 -0
  49. package/dist/esm/react/A11yDevtools.js.map +1 -0
  50. package/dist/esm/react/index.d.ts +8 -0
  51. package/dist/esm/react/index.js +11 -0
  52. package/dist/esm/react/index.js.map +1 -0
  53. package/dist/esm/react/plugin.d.ts +12 -0
  54. package/dist/esm/react/plugin.js +11 -0
  55. package/dist/esm/react/plugin.js.map +1 -0
  56. package/dist/esm/react/production/A11yDevtools.d.ts +5 -0
  57. package/dist/esm/react/production/A11yDevtools.js +8 -0
  58. package/dist/esm/react/production/A11yDevtools.js.map +1 -0
  59. package/dist/esm/react/production/plugin.d.ts +7 -0
  60. package/dist/esm/react/production/plugin.js +11 -0
  61. package/dist/esm/react/production/plugin.js.map +1 -0
  62. package/dist/esm/react/production.d.ts +3 -0
  63. package/dist/esm/react/production.js +5 -0
  64. package/dist/esm/solid/A11yDevtools.d.ts +5 -0
  65. package/dist/esm/solid/A11yDevtools.js +8 -0
  66. package/dist/esm/solid/A11yDevtools.js.map +1 -0
  67. package/dist/esm/solid/index.d.ts +8 -0
  68. package/dist/esm/solid/index.js +9 -0
  69. package/dist/esm/solid/index.js.map +1 -0
  70. package/dist/esm/solid/plugin.d.ts +12 -0
  71. package/dist/esm/solid/plugin.js +11 -0
  72. package/dist/esm/solid/plugin.js.map +1 -0
  73. package/dist/esm/solid/production/A11yDevtools.d.ts +5 -0
  74. package/dist/esm/solid/production/A11yDevtools.js +8 -0
  75. package/dist/esm/solid/production/A11yDevtools.js.map +1 -0
  76. package/dist/esm/solid/production/plugin.d.ts +7 -0
  77. package/dist/esm/solid/production/plugin.js +11 -0
  78. package/dist/esm/solid/production/plugin.js.map +1 -0
  79. package/dist/esm/solid/production.d.ts +3 -0
  80. package/dist/esm/solid/production.js +3 -0
  81. package/package.json +110 -7
  82. package/src/core/components/IssueCard.tsx +75 -0
  83. package/src/core/components/IssueList.tsx +155 -0
  84. package/src/core/components/Settings.tsx +221 -0
  85. package/src/core/components/Shell.tsx +154 -0
  86. package/src/core/components/index.tsx +12 -0
  87. package/src/core/contexts/allyContext.tsx +118 -0
  88. package/src/core/core.tsx +11 -0
  89. package/src/core/index.ts +10 -0
  90. package/src/core/production.ts +5 -0
  91. package/src/core/styles/styles.ts +556 -0
  92. package/src/core/types/types.ts +177 -0
  93. package/src/core/utils/ally-audit.utils.ts +345 -0
  94. package/src/core/utils/config.utils.ts +68 -0
  95. package/src/core/utils/custom-audit.utils.ts +643 -0
  96. package/src/core/utils/export-audit.uitls.ts +180 -0
  97. package/src/core/utils/ui.utils.ts +483 -0
  98. package/src/react/A11yDevtools.ts +12 -0
  99. package/src/react/index.ts +16 -0
  100. package/src/react/plugin.ts +9 -0
  101. package/src/react/production/A11yDevtools.ts +11 -0
  102. package/src/react/production/plugin.ts +9 -0
  103. package/src/react/production.ts +7 -0
  104. package/src/solid/A11yDevtools.ts +11 -0
  105. package/src/solid/index.ts +14 -0
  106. package/src/solid/plugin.ts +9 -0
  107. package/src/solid/production/A11yDevtools.ts +10 -0
  108. package/src/solid/production/plugin.ts +9 -0
  109. package/src/solid/production.ts +5 -0
  110. package/README.md +0 -45
@@ -0,0 +1,556 @@
1
+ import * as goober from 'goober'
2
+ import { useTheme } from '@tanstack/devtools-ui'
3
+ import { createMemo } from 'solid-js'
4
+
5
+ import type { TanStackDevtoolsTheme } from '@tanstack/devtools-ui'
6
+ import type { RuleCategory, SeverityThreshold } from '../types/types'
7
+
8
+ const SEVERITY_COLORS: Record<SeverityThreshold, string> = {
9
+ critical: '#dc2626',
10
+ serious: '#ea580c',
11
+ moderate: '#ca8a04',
12
+ minor: '#2563eb',
13
+ }
14
+
15
+ export const CATEGORY_LABELS: Record<RuleCategory, string> = {
16
+ all: 'All Categories',
17
+ 'cat.aria': 'ARIA',
18
+ 'cat.color': 'Color & Contrast',
19
+ 'cat.forms': 'Forms',
20
+ 'cat.keyboard': 'Keyboard',
21
+ 'cat.language': 'Language',
22
+ 'cat.name-role-value': 'Names & Roles',
23
+ 'cat.parsing': 'Parsing',
24
+ 'cat.semantics': 'Semantics',
25
+ 'cat.sensory-and-visual-cues': 'Sensory Cues',
26
+ 'cat.structure': 'Structure',
27
+ 'cat.tables': 'Tables',
28
+ 'cat.text-alternatives': 'Text Alternatives',
29
+ 'cat.time-and-media': 'Time & Media',
30
+ }
31
+
32
+ export const CATEGORIES: Array<RuleCategory> = [
33
+ 'all',
34
+ 'cat.aria',
35
+ 'cat.color',
36
+ 'cat.forms',
37
+ 'cat.keyboard',
38
+ 'cat.language',
39
+ 'cat.name-role-value',
40
+ 'cat.parsing',
41
+ 'cat.semantics',
42
+ 'cat.sensory-and-visual-cues',
43
+ 'cat.structure',
44
+ 'cat.tables',
45
+ 'cat.text-alternatives',
46
+ 'cat.time-and-media',
47
+ ]
48
+
49
+ const css = goober.css
50
+ const FONT_SCALE = 1.1
51
+ const fontPx = (size: number) => `calc(${size}px * ${FONT_SCALE})`
52
+
53
+ function createA11yPanelStyles(theme: TanStackDevtoolsTheme) {
54
+ const t = (light: string, dark: string) => (theme === 'light' ? light : dark)
55
+
56
+ const bg = t('#f9fafb;', '#191c24')
57
+ const fg = t('#1e293b', '#e2e8f0')
58
+ const border = t('#e2e8f0', '#292e3d')
59
+ const muted = t('#64748b', '#94a3b8')
60
+ const muted2 = t('#727c8b', '#818386')
61
+
62
+ return {
63
+ colors: { bg, fg, border, muted, muted2, theme },
64
+
65
+ root: css`
66
+ height: 100%;
67
+ display: flex;
68
+ flex-direction: column;
69
+ overflow: hidden;
70
+ position: relative;
71
+ `,
72
+
73
+ header: css`
74
+ padding: 16px;
75
+ border-bottom: 1px solid ${border};
76
+ display: flex;
77
+ justify-content: space-between;
78
+ align-items: center;
79
+ flex-shrink: 0;
80
+ anchor-name: --a11y-toast-anchor;
81
+ `,
82
+ headerTitleRow: css`
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 12px;
86
+ min-width: 0;
87
+ `,
88
+ headerTitle: css`
89
+ margin: 0;
90
+ font-size: ${fontPx(16)};
91
+ font-weight: 600;
92
+ `,
93
+ headerSub: css`
94
+ font-size: ${fontPx(12)};
95
+ color: ${muted};
96
+ white-space: nowrap;
97
+ `,
98
+ headerActions: css`
99
+ display: flex;
100
+ gap: 8px;
101
+ align-items: center;
102
+ flex-wrap: wrap;
103
+ justify-content: flex-end;
104
+ `,
105
+ primaryButton: css`
106
+ padding: 8px 16px;
107
+ color: #fff;
108
+ border-radius: 6px;
109
+ cursor: pointer;
110
+ font-weight: 500;
111
+ font-size: ${fontPx(13)};
112
+ opacity: 1;
113
+ `,
114
+ primaryButtonDisabled: css`
115
+ cursor: not-allowed;
116
+ opacity: 0.7;
117
+ `,
118
+ button: css`
119
+ padding: 8px 12px;
120
+ color: ${fg};
121
+ border: 1px solid ${border};
122
+ border-radius: 6px;
123
+ cursor: pointer;
124
+ font-size: ${fontPx(11)};
125
+ `,
126
+ buttonRow: css`
127
+ display: flex;
128
+ gap: 6px;
129
+ align-items: center;
130
+ `,
131
+ toggleOverlay: css`
132
+ padding: 8px 12px;
133
+ color: ${fg};
134
+ border: 1px solid ${border};
135
+ border-radius: 6px;
136
+ cursor: pointer;
137
+ font-size: ${fontPx(13)};
138
+ `,
139
+ toggleOverlayOn: css`
140
+ background: #10b981;
141
+ color: #fff;
142
+ border-color: #10b981;
143
+ `,
144
+
145
+ statusBar: css`
146
+ padding: 8px 16px;
147
+ border-bottom: 1px solid ${border};
148
+ display: flex;
149
+ gap: 12px;
150
+ align-items: center;
151
+ flex-shrink: 0;
152
+ font-size: ${fontPx(11)};
153
+ color: ${muted};
154
+ `,
155
+ statusSpacer: css`
156
+ flex: 1;
157
+ `,
158
+ smallLinkButton: css`
159
+ padding: 4px 10px;
160
+ background: transparent;
161
+ color: #0ea5e9;
162
+ border: 1px solid ${border};
163
+ border-radius: 4px;
164
+ cursor: pointer;
165
+ font-size: ${fontPx(11)};
166
+ font-weight: 500;
167
+ `,
168
+
169
+ content: css`
170
+ flex: 1;
171
+ overflow-y: auto;
172
+ padding: 16px;
173
+ `,
174
+ emptyState: css`
175
+ display: flex;
176
+ flex-direction: column;
177
+ align-items: center;
178
+ justify-content: center;
179
+ height: 100%;
180
+ text-align: center;
181
+ color: ${muted};
182
+ `,
183
+ emptyPrimary: css`
184
+ font-size: ${fontPx(14)};
185
+ margin: 0 0 8px 0;
186
+ `,
187
+ emptySecondary: css`
188
+ font-size: ${fontPx(12)};
189
+ margin: 0;
190
+ `,
191
+ successState: css`
192
+ display: flex;
193
+ flex-direction: column;
194
+ align-items: center;
195
+ justify-content: center;
196
+ height: 100%;
197
+ text-align: center;
198
+ `,
199
+ successTitle: css`
200
+ font-size: ${fontPx(16)};
201
+ color: #10b981;
202
+ font-weight: 600;
203
+ margin: 0;
204
+ `,
205
+ successSub: css`
206
+ font-size: ${fontPx(12)};
207
+ color: ${muted};
208
+ margin-top: 8px;
209
+ margin-bottom: 0;
210
+ `,
211
+
212
+ summaryGrid: css`
213
+ display: grid;
214
+ grid-template-columns: repeat(4, 1fr);
215
+ gap: 12px;
216
+ margin-bottom: 20px;
217
+
218
+ @media (max-width: 520px) {
219
+ grid-template-columns: repeat(2, 1fr);
220
+ }
221
+ `,
222
+ summaryButton: css`
223
+ padding: 12px;
224
+ color: ${fg};
225
+ background: ${bg};
226
+ border-radius: 8px;
227
+ border: 1px solid ${border};
228
+ text-align: left;
229
+ cursor: pointer;
230
+ box-shadow: none;
231
+
232
+ &:hover {
233
+ background: ${t('#f0f2f5', '#111318')};
234
+ }
235
+ `,
236
+ summaryButtonActive: (impact: SeverityThreshold) => css`
237
+ box-shadow: 0 0 0 2px ${SEVERITY_COLORS[impact]};
238
+ `,
239
+ summaryCount: (impact: SeverityThreshold) => css`
240
+ font-size: ${fontPx(24)};
241
+ font-weight: 700;
242
+ color: ${SEVERITY_COLORS[impact]};
243
+ `,
244
+ summaryLabel: css`
245
+ font-size: ${fontPx(11)};
246
+ color: ${muted};
247
+ text-transform: uppercase;
248
+ `,
249
+
250
+ section: css`
251
+ margin-bottom: 16px;
252
+ `,
253
+ sectionTitle: (impact: SeverityThreshold) => css`
254
+ color: ${SEVERITY_COLORS[impact]};
255
+ font-size: ${fontPx(13)};
256
+ font-weight: 600;
257
+ margin: 0 0 8px 0;
258
+ text-transform: uppercase;
259
+ letter-spacing: 0.5px;
260
+ `,
261
+
262
+ issueCard: css`
263
+ padding: 12px;
264
+ margin-bottom: 8px;
265
+ border: 1px solid ${border};
266
+ border-radius: 6px;
267
+ cursor: pointer;
268
+ `,
269
+ issueCardSelected: css`
270
+ background: ${t('#e0f2fe', '#1e3a5f')};
271
+ border-color: #0ea5e9;
272
+ `,
273
+ issueRow: css`
274
+ display: flex;
275
+ justify-content: space-between;
276
+ align-items: flex-start;
277
+ gap: 12px;
278
+ `,
279
+ issueMain: css`
280
+ flex: 1;
281
+ min-width: 0;
282
+ `,
283
+ issueTitleRow: css`
284
+ font-weight: 600;
285
+ font-size: ${fontPx(13)};
286
+ margin-bottom: 4px;
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 8px;
290
+ `,
291
+ dot: (impact: SeverityThreshold) => css`
292
+ width: 8px;
293
+ height: 8px;
294
+ border-radius: 50%;
295
+ background: ${SEVERITY_COLORS[impact]};
296
+ flex-shrink: 0;
297
+ `,
298
+ issueMessage: css`
299
+ font-size: ${fontPx(12)};
300
+ color: ${t('#475569', '#cbd5e1')};
301
+ margin: 0 0 8px 0;
302
+ line-height: 1.4;
303
+ `,
304
+ selector: css`
305
+ font-size: ${fontPx(10)};
306
+ color: ${muted2};
307
+ font-family:
308
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
309
+ 'Liberation Mono', 'Courier New', monospace;
310
+ overflow: hidden;
311
+ text-overflow: ellipsis;
312
+ white-space: nowrap;
313
+ `,
314
+ issueAside: css`
315
+ display: flex;
316
+ flex-direction: column;
317
+ align-items: flex-end;
318
+ gap: 4px;
319
+ flex-shrink: 0;
320
+ `,
321
+ helpLink: css`
322
+ font-size: ${fontPx(12)};
323
+ color: #0ea5e9;
324
+ padding: 0 12px;
325
+ font-weight: 600;
326
+ text-decoration: underline;
327
+ text-underline-offset: 2px;
328
+
329
+ &:hover {
330
+ color: #0284c7;
331
+ }
332
+
333
+ &:focus-visible {
334
+ outline: 2px solid #0ea5e9;
335
+ outline-offset: 2px;
336
+ border-radius: 4px;
337
+ }
338
+ `,
339
+ disableRule: css`
340
+ font-size: ${fontPx(10)};
341
+ color: ${muted};
342
+ background: none;
343
+ border: none;
344
+ cursor: pointer;
345
+ padding: 0;
346
+ font-weight: 600;
347
+
348
+ &:hover {
349
+ color: #000000;
350
+ }
351
+
352
+ &:focus-visible {
353
+ outline: 2px solid #0ea5e9;
354
+ outline-offset: 2px;
355
+ border-radius: 4px;
356
+ }
357
+ `,
358
+ tags: css`
359
+ display: flex;
360
+ gap: 4px;
361
+ margin-top: 8px;
362
+ flex-wrap: wrap;
363
+ `,
364
+ tag: css`
365
+ font-size: ${fontPx(10)};
366
+ padding: 2px 6px;
367
+ border: 1px solid ${border};
368
+ border-radius: 4px;
369
+ color: ${muted};
370
+ `,
371
+
372
+ settingsOverlay: css`
373
+ position: absolute;
374
+ inset: 0;
375
+ background: ${bg};
376
+ display: flex;
377
+ flex-direction: column;
378
+ z-index: 10;
379
+ `,
380
+ settingsHeader: css`
381
+ padding: 12px 16px;
382
+ border-bottom: 1px solid ${border};
383
+ display: flex;
384
+ justify-content: space-between;
385
+ align-items: center;
386
+ flex-shrink: 0;
387
+ `,
388
+ settingsTitle: css`
389
+ margin: 0;
390
+ font-size: ${fontPx(14)};
391
+ font-weight: 600;
392
+ `,
393
+ doneButton: css`
394
+ padding: 6px 12px;
395
+ background: ${bg};
396
+ color: ${bg};
397
+ border: none;
398
+ border-radius: 4px;
399
+ cursor: pointer;
400
+ font-size: ${fontPx(12)};
401
+ font-weight: 500;
402
+ `,
403
+ settingsContent: css`
404
+ flex: 1;
405
+ overflow-y: auto;
406
+ padding: 16px;
407
+ `,
408
+ settingsSection: css`
409
+ margin-bottom: 24px;
410
+ `,
411
+ settingsRowStack: css`
412
+ display: grid;
413
+ gap: 12px;
414
+ `,
415
+ settingsSectionLabel: css`
416
+ margin: 0 0 12px 0;
417
+ font-size: ${fontPx(12)};
418
+ font-weight: 600;
419
+ text-transform: uppercase;
420
+ letter-spacing: 0.5px;
421
+ color: ${muted};
422
+ `,
423
+ settingsRow: css`
424
+ display: flex;
425
+ align-items: center;
426
+ justify-content: space-between;
427
+ padding: 10px 0;
428
+ border-bottom: 1px solid ${border};
429
+ gap: 12px;
430
+ `,
431
+ settingsRowTitle: css`
432
+ font-size: ${fontPx(13)};
433
+ font-weight: 500;
434
+ `,
435
+ settingsRowDesc: css`
436
+ font-size: ${fontPx(11)};
437
+ color: ${muted};
438
+ margin-top: 2px;
439
+ `,
440
+ select: css`
441
+ padding: 6px 10px;
442
+ border: 1px solid ${border};
443
+ border-radius: 4px;
444
+ background: ${bg};
445
+ color: ${fg};
446
+ font-size: ${fontPx(12)};
447
+ `,
448
+ rulesHeaderRow: css`
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: space-between;
452
+ margin-bottom: 12px;
453
+ gap: 12px;
454
+ flex-wrap: wrap;
455
+ `,
456
+ rulesHeaderActions: css`
457
+ display: flex;
458
+ gap: 6px;
459
+ `,
460
+ filtersRow: css`
461
+ display: flex;
462
+ gap: 8px;
463
+ margin-bottom: 12px;
464
+ flex-wrap: wrap;
465
+ `,
466
+ search: css`
467
+ flex: 1;
468
+ min-width: 180px;
469
+ padding: 8px 10px;
470
+ border: 1px solid ${border};
471
+ border-radius: 4px;
472
+ background: ${bg};
473
+ color: ${fg};
474
+ font-size: ${fontPx(12)};
475
+ box-sizing: border-box;
476
+ `,
477
+ rulesList: css`
478
+ border: 1px solid ${border};
479
+ border-radius: 6px;
480
+ overflow-y: auto;
481
+ `,
482
+ ruleRow: css`
483
+ display: flex;
484
+ align-items: flex-start;
485
+ gap: 8px;
486
+ padding: 8px 10px;
487
+ cursor: pointer;
488
+ opacity: 1;
489
+ background: transparent;
490
+
491
+ &:hover {
492
+ background: ${t('#f0f2f5', '#111318')};
493
+ }
494
+ `,
495
+ ruleRowDisabled: css`
496
+ opacity: 0.6;
497
+ `,
498
+ ruleRowBorder: css`
499
+ border-bottom: 1px solid ${border};
500
+ `,
501
+ ruleCheckbox: css`
502
+ margin-top: 2px;
503
+ flex-shrink: 0;
504
+ `,
505
+ ruleInfo: css`
506
+ flex: 1;
507
+ min-width: 0;
508
+ `,
509
+ ruleTop: css`
510
+ display: flex;
511
+ align-items: center;
512
+ gap: 6px;
513
+ margin-bottom: 2px;
514
+ `,
515
+ ruleId: css`
516
+ font-weight: 500;
517
+ font-size: ${fontPx(12)};
518
+ text-decoration: none;
519
+ `,
520
+ ruleIdDisabled: css`
521
+ text-decoration: line-through;
522
+ `,
523
+ bpBadge: css`
524
+ font-size: ${fontPx(9)};
525
+ padding: 1px 4px;
526
+ background: #f59e0b;
527
+ color: #fff;
528
+ border-radius: 3px;
529
+ font-weight: 500;
530
+ `,
531
+ ruleDesc: css`
532
+ font-size: ${fontPx(11)};
533
+ color: ${muted};
534
+ line-height: 2;
535
+ `,
536
+ catTagRow: css`
537
+ display: flex;
538
+ gap: 4px;
539
+ margin-top: 4px;
540
+ `,
541
+ catTag: css`
542
+ font-size: ${fontPx(9)};
543
+ padding: 1px 4px;
544
+ border: 1px solid ${muted};
545
+ border-radius: 3px;
546
+ color: ${muted};
547
+ `,
548
+ }
549
+ }
550
+
551
+ export function useStyles() {
552
+ const { theme } = useTheme()
553
+ const styles = createMemo(() => createA11yPanelStyles(theme()))
554
+
555
+ return styles
556
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Severity threshold for filtering issues
3
+ */
4
+ export type SeverityThreshold = 'critical' | 'serious' | 'moderate' | 'minor'
5
+
6
+ /**
7
+ * Rule set presets
8
+ */
9
+ export type RuleSetPreset =
10
+ | 'wcag2a'
11
+ | 'wcag2aa'
12
+ | 'wcag21aa'
13
+ | 'wcag22aa'
14
+ | 'section508'
15
+ | 'best-practice'
16
+ | 'all'
17
+
18
+ /**
19
+ * Rule categories (axe-core tags)
20
+ */
21
+ export type RuleCategory =
22
+ | 'all'
23
+ | 'cat.aria'
24
+ | 'cat.color'
25
+ | 'cat.forms'
26
+ | 'cat.keyboard'
27
+ | 'cat.language'
28
+ | 'cat.name-role-value'
29
+ | 'cat.parsing'
30
+ | 'cat.semantics'
31
+ | 'cat.sensory-and-visual-cues'
32
+ | 'cat.structure'
33
+ | 'cat.tables'
34
+ | 'cat.text-alternatives'
35
+ | 'cat.time-and-media'
36
+
37
+ /**
38
+ * Represents a single node affected by an accessibility issue
39
+ */
40
+ export interface A11yNode {
41
+ /** CSS selector for the element */
42
+ selector: string
43
+ /** HTML snippet of the element */
44
+ html: string
45
+ /** XPath to the element (optional) */
46
+ xpath?: string
47
+ /** Failure summary for this specific node */
48
+ failureSummary?: string
49
+ }
50
+
51
+ /**
52
+ * Represents a single accessibility issue
53
+ */
54
+ export interface A11yIssue {
55
+ /** Unique identifier for this issue instance */
56
+ id: string
57
+ /** The axe-core rule ID */
58
+ ruleId: string
59
+ /** Impact severity level */
60
+ impact: SeverityThreshold
61
+ /** Human-readable description of the issue */
62
+ message: string
63
+ /** Detailed help text */
64
+ help: string
65
+ /** URL to learn more about this issue */
66
+ helpUrl: string
67
+ /** WCAG tags associated with this rule */
68
+ wcagTags: Array<string>
69
+ /** DOM nodes affected by this issue */
70
+ nodes: Array<A11yNode>
71
+ /** Whether this issue meets the current severity threshold */
72
+ meetsThreshold: boolean
73
+ /** Timestamp when this issue was detected */
74
+ timestamp: number
75
+ }
76
+
77
+ /**
78
+ * Summary statistics for an audit
79
+ */
80
+ export interface A11ySummary {
81
+ total: number
82
+ critical: number
83
+ serious: number
84
+ moderate: number
85
+ minor: number
86
+ passes: number
87
+ incomplete: number
88
+ }
89
+
90
+ /**
91
+ * Result of an accessibility audit
92
+ */
93
+ export interface A11yAuditResult {
94
+ /** All issues found */
95
+ issues: Array<A11yIssue>
96
+ /** Summary statistics */
97
+ summary: A11ySummary
98
+ /** Timestamp when the audit was run */
99
+ timestamp: number
100
+ /** URL of the page audited */
101
+ url: string
102
+ /** Description of the context (document, selector, or element) */
103
+ context: string
104
+ /** Time taken to run the audit in ms */
105
+ duration: number
106
+ }
107
+
108
+ /**
109
+ * Configuration for custom rules
110
+ */
111
+ export interface CustomRulesConfig {
112
+ /** Enable click-handler-on-non-interactive rule (default: true) */
113
+ clickHandlerOnNonInteractive?: boolean
114
+ /** Enable mouse-only-event-handlers rule (default: true) */
115
+ mouseOnlyEventHandlers?: boolean
116
+ /** Enable static-element-interaction rule (default: true) */
117
+ staticElementInteraction?: boolean
118
+ }
119
+
120
+ /**
121
+ * Options for running an audit
122
+ */
123
+ export interface A11yAuditOptions {
124
+ /** Minimum severity to report (default: 'serious') */
125
+ threshold?: SeverityThreshold
126
+ /** DOM context to audit (default: document) */
127
+ context?: Document | Element | string
128
+ /** Rule set preset to use (default: 'wcag21aa') */
129
+ ruleSet?: RuleSetPreset
130
+ /** Specific rules to enable (overrides ruleSet) */
131
+ enabledRules?: Array<string>
132
+ /** Specific rules to disable */
133
+ disabledRules?: Array<string>
134
+ /** Selectors to exclude from auditing */
135
+ exclude?: Array<string>
136
+ /** Configuration for custom rules (default: all enabled) */
137
+ customRules?: CustomRulesConfig
138
+ }
139
+
140
+ /**
141
+ * Options for the A11y plugin
142
+ */
143
+ export interface A11yPluginOptions {
144
+ /** Minimum severity threshold (default: 'serious') */
145
+ threshold?: SeverityThreshold
146
+
147
+ /** Rule set preset (default: 'wcag21aa') */
148
+ ruleSet?: RuleSetPreset
149
+
150
+ /** Show visual overlays on page (default: true) */
151
+ showOverlays?: boolean
152
+
153
+ /** Persist settings to localStorage (default: true) */
154
+ persistSettings?: boolean
155
+
156
+ /** Rules to disable (by rule ID) */
157
+ disabledRules?: Array<string>
158
+ }
159
+
160
+ /**
161
+ * Export format options
162
+ */
163
+ export type ExportFormat = 'json' | 'csv'
164
+
165
+ /**
166
+ * Export options
167
+ */
168
+ export interface ExportOptions {
169
+ /** Export format */
170
+ format: ExportFormat
171
+ /** Include passing rules in export */
172
+ includePasses?: boolean
173
+ /** Include incomplete rules in export */
174
+ includeIncomplete?: boolean
175
+ /** Custom filename (without extension) */
176
+ filename?: string
177
+ }