a11y-hud 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bookmarklet.html +133 -0
- package/dist/index.cjs +535 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -1
- package/dist/index.d.ts +69 -1
- package/dist/index.js +526 -23
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +536 -77
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,22 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
6
6
|
|
|
7
7
|
var axe__default = /*#__PURE__*/_interopDefault(axe);
|
|
8
8
|
|
|
9
|
+
// src/bookmarklet.ts
|
|
10
|
+
var CDN_BASE = "https://cdn.jsdelivr.net/npm/a11y-hud";
|
|
11
|
+
function generateBookmarklet(version = "latest") {
|
|
12
|
+
const src = `${CDN_BASE}@${version}/dist/index.umd.js`;
|
|
13
|
+
const js = [
|
|
14
|
+
"(function(){",
|
|
15
|
+
"if(window.A11yHud){window.A11yHud.mount();return;}",
|
|
16
|
+
"var s=document.createElement('script');",
|
|
17
|
+
`s.src='${src}';`,
|
|
18
|
+
"s.onload=function(){window.A11yHud.mount();};",
|
|
19
|
+
"document.head.appendChild(s);",
|
|
20
|
+
"})()"
|
|
21
|
+
].join("");
|
|
22
|
+
return `javascript:${js}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
// src/icons/alert-circle.svg
|
|
10
26
|
var alert_circle_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg>\n';
|
|
11
27
|
|
|
@@ -24,6 +40,9 @@ var chevron_up_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" hei
|
|
|
24
40
|
// src/icons/copy.svg
|
|
25
41
|
var copy_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>\n';
|
|
26
42
|
|
|
43
|
+
// src/icons/download.svg
|
|
44
|
+
var download_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>';
|
|
45
|
+
|
|
27
46
|
// src/icons/filter.svg
|
|
28
47
|
var filter_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>\n';
|
|
29
48
|
|
|
@@ -45,6 +64,12 @@ var refresh_cw_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" hei
|
|
|
45
64
|
// src/icons/sun.svg
|
|
46
65
|
var sun_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>\n';
|
|
47
66
|
|
|
67
|
+
// src/icons/trash-2.svg
|
|
68
|
+
var trash_2_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>';
|
|
69
|
+
|
|
70
|
+
// src/icons/upload.svg
|
|
71
|
+
var upload_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg>';
|
|
72
|
+
|
|
48
73
|
// src/icons/x.svg
|
|
49
74
|
var x_default = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>\n';
|
|
50
75
|
|
|
@@ -56,6 +81,7 @@ var registry = {
|
|
|
56
81
|
"chevron-down": chevron_down_default,
|
|
57
82
|
"chevron-up": chevron_up_default,
|
|
58
83
|
copy: copy_default,
|
|
84
|
+
download: download_default,
|
|
59
85
|
filter: filter_default,
|
|
60
86
|
info: info_default,
|
|
61
87
|
keyboard: keyboard_default,
|
|
@@ -63,12 +89,180 @@ var registry = {
|
|
|
63
89
|
moon: moon_default,
|
|
64
90
|
"refresh-cw": refresh_cw_default,
|
|
65
91
|
sun: sun_default,
|
|
92
|
+
"trash-2": trash_2_default,
|
|
93
|
+
upload: upload_default,
|
|
66
94
|
x: x_default
|
|
67
95
|
};
|
|
68
96
|
function icon(name) {
|
|
69
97
|
return registry[name] ?? "";
|
|
70
98
|
}
|
|
71
99
|
|
|
100
|
+
// src/ignores.ts
|
|
101
|
+
var STORAGE_KEY = "a11y-hud:ignores";
|
|
102
|
+
function load() {
|
|
103
|
+
try {
|
|
104
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
105
|
+
if (raw === null) return [];
|
|
106
|
+
return JSON.parse(raw);
|
|
107
|
+
} catch {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function save(entries) {
|
|
112
|
+
try {
|
|
113
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(entries));
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function matches(a, b) {
|
|
118
|
+
return a.ruleId === b.ruleId && a.selector === b.selector;
|
|
119
|
+
}
|
|
120
|
+
function addIgnore(ruleId, selector) {
|
|
121
|
+
const entries = load();
|
|
122
|
+
const entry = selector !== void 0 ? { ruleId, selector } : { ruleId };
|
|
123
|
+
if (entries.some((e) => matches(e, entry))) return;
|
|
124
|
+
entries.push(entry);
|
|
125
|
+
save(entries);
|
|
126
|
+
}
|
|
127
|
+
function removeIgnore(ruleId, selector) {
|
|
128
|
+
const entry = selector !== void 0 ? { ruleId, selector } : { ruleId };
|
|
129
|
+
save(load().filter((e) => !matches(e, entry)));
|
|
130
|
+
}
|
|
131
|
+
function clearIgnores() {
|
|
132
|
+
save([]);
|
|
133
|
+
}
|
|
134
|
+
function listIgnores() {
|
|
135
|
+
return load();
|
|
136
|
+
}
|
|
137
|
+
function exportIgnores() {
|
|
138
|
+
return JSON.stringify(listIgnores(), null, 2);
|
|
139
|
+
}
|
|
140
|
+
function importIgnores(json) {
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(json);
|
|
144
|
+
} catch {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (!Array.isArray(parsed)) return;
|
|
148
|
+
const entries = [];
|
|
149
|
+
for (const item of parsed) {
|
|
150
|
+
if (typeof item !== "object" || item === null) continue;
|
|
151
|
+
const { ruleId, selector } = item;
|
|
152
|
+
if (typeof ruleId !== "string") continue;
|
|
153
|
+
if (selector !== void 0 && typeof selector !== "string") continue;
|
|
154
|
+
entries.push(selector !== void 0 ? { ruleId, selector } : { ruleId });
|
|
155
|
+
}
|
|
156
|
+
save(entries);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/keyboard.ts
|
|
160
|
+
var FOCUSABLE_SELECTOR = [
|
|
161
|
+
"a[href]:not([tabindex='-1'])",
|
|
162
|
+
"button:not([disabled]):not([tabindex='-1'])",
|
|
163
|
+
"input:not([disabled]):not([tabindex='-1'])",
|
|
164
|
+
"select:not([disabled]):not([tabindex='-1'])",
|
|
165
|
+
"textarea:not([disabled]):not([tabindex='-1'])",
|
|
166
|
+
"[tabindex]:not([tabindex='-1'])",
|
|
167
|
+
"details > summary:not([tabindex='-1'])",
|
|
168
|
+
"area[href]:not([tabindex='-1'])"
|
|
169
|
+
].join(", ");
|
|
170
|
+
var INTERACTIVE_SELECTOR = "a[href], button, input, select, textarea, [role='button'], [role='link']";
|
|
171
|
+
function buildSelector(el) {
|
|
172
|
+
if (el.id) {
|
|
173
|
+
return `#${el.id}`;
|
|
174
|
+
}
|
|
175
|
+
let selector = el.tagName.toLowerCase();
|
|
176
|
+
if (el.className && typeof el.className === "string") {
|
|
177
|
+
const classes = el.className.trim().split(/\s+/).slice(0, 2);
|
|
178
|
+
if (classes.length > 0 && classes[0] !== "") {
|
|
179
|
+
selector += classes.map((c) => `.${c}`).join("");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return selector;
|
|
183
|
+
}
|
|
184
|
+
function getFocusableElements(scope) {
|
|
185
|
+
const all = Array.from(scope.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
186
|
+
const positive = [];
|
|
187
|
+
const zero = [];
|
|
188
|
+
for (const el of all) {
|
|
189
|
+
const ti = el.tabIndex;
|
|
190
|
+
if (ti > 0) {
|
|
191
|
+
positive.push(el);
|
|
192
|
+
} else {
|
|
193
|
+
zero.push(el);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
positive.sort((a, b) => a.tabIndex - b.tabIndex);
|
|
197
|
+
const ordered = [...positive, ...zero];
|
|
198
|
+
return ordered.map((element, i) => ({
|
|
199
|
+
element,
|
|
200
|
+
index: i + 1,
|
|
201
|
+
selector: buildSelector(element),
|
|
202
|
+
tabIndex: element.tabIndex
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
function injectFocusOrderOverlay(elements) {
|
|
206
|
+
if (!document.getElementById("a11y-hud-kbd-style")) {
|
|
207
|
+
const style = document.createElement("style");
|
|
208
|
+
style.id = "a11y-hud-kbd-style";
|
|
209
|
+
style.textContent = [
|
|
210
|
+
"#a11y-hud-kbd-overlay{position:absolute;top:0;left:0;width:0;height:0;pointer-events:none;z-index:2147483646}",
|
|
211
|
+
".a11y-hud-kbd-badge{position:absolute;min-width:20px;height:20px;padding:0 5px;border-radius:10px;background:#7c3aed;color:#fff;font:700 11px/20px system-ui,sans-serif;text-align:center;pointer-events:none}"
|
|
212
|
+
].join("");
|
|
213
|
+
document.head.appendChild(style);
|
|
214
|
+
}
|
|
215
|
+
const overlay = document.createElement("div");
|
|
216
|
+
overlay.id = "a11y-hud-kbd-overlay";
|
|
217
|
+
document.body.appendChild(overlay);
|
|
218
|
+
const scrollX = window.scrollX;
|
|
219
|
+
const scrollY = window.scrollY;
|
|
220
|
+
for (const info of elements) {
|
|
221
|
+
const rect = info.element.getBoundingClientRect();
|
|
222
|
+
const badge = document.createElement("span");
|
|
223
|
+
badge.className = "a11y-hud-kbd-badge";
|
|
224
|
+
badge.textContent = String(info.index);
|
|
225
|
+
badge.style.top = `${rect.top + scrollY}px`;
|
|
226
|
+
badge.style.left = `${rect.left + scrollX}px`;
|
|
227
|
+
overlay.appendChild(badge);
|
|
228
|
+
}
|
|
229
|
+
return () => {
|
|
230
|
+
document.getElementById("a11y-hud-kbd-overlay")?.remove();
|
|
231
|
+
document.getElementById("a11y-hud-kbd-style")?.remove();
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function detectKeyboardViolations(elements, scope = document.body) {
|
|
235
|
+
const violations = [];
|
|
236
|
+
if (elements.length === 0) {
|
|
237
|
+
violations.push({
|
|
238
|
+
type: "no-focusable-elements",
|
|
239
|
+
message: "No focusable elements found in scope. Users who rely on keyboard navigation cannot reach any interactive content."
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
for (const info of elements) {
|
|
243
|
+
if (info.tabIndex > 0) {
|
|
244
|
+
violations.push({
|
|
245
|
+
type: "positive-tabindex",
|
|
246
|
+
element: info.element,
|
|
247
|
+
selector: info.selector,
|
|
248
|
+
message: `tabindex="${info.tabIndex}" on <${info.element.tagName.toLowerCase()}> disrupts the natural tab order. Use tabindex="0" instead.`
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const excluded = Array.from(scope.querySelectorAll(INTERACTIVE_SELECTOR)).filter(
|
|
253
|
+
(el) => el.tabIndex === -1
|
|
254
|
+
);
|
|
255
|
+
for (const el of excluded) {
|
|
256
|
+
violations.push({
|
|
257
|
+
type: "interactive-excluded",
|
|
258
|
+
element: el,
|
|
259
|
+
selector: buildSelector(el),
|
|
260
|
+
message: `<${el.tagName.toLowerCase()}> with tabindex="-1" is removed from the tab order. Keyboard users cannot reach this element.`
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return violations;
|
|
264
|
+
}
|
|
265
|
+
|
|
72
266
|
// src/observer.ts
|
|
73
267
|
function debounce(fn, delay) {
|
|
74
268
|
let timer;
|
|
@@ -87,6 +281,7 @@ async function runScan(target = document.body, runOnly) {
|
|
|
87
281
|
}
|
|
88
282
|
const options = runOnly && runOnly.length > 0 ? { runOnly: { type: "tag", values: runOnly } } : {};
|
|
89
283
|
const run = axe__default.default.run(target, options).then((results) => {
|
|
284
|
+
const ignores = listIgnores();
|
|
90
285
|
results.violations = results.violations.map((v) => ({
|
|
91
286
|
...v,
|
|
92
287
|
nodes: v.nodes.filter((node) => {
|
|
@@ -94,7 +289,19 @@ async function runScan(target = document.body, runOnly) {
|
|
|
94
289
|
const selector = (Array.isArray(first) ? first[0] : first) ?? "";
|
|
95
290
|
return !String(selector).toLowerCase().startsWith("a11y-hud");
|
|
96
291
|
})
|
|
97
|
-
})).filter((v) => v.nodes.length > 0)
|
|
292
|
+
})).filter((v) => v.nodes.length > 0).map((v) => {
|
|
293
|
+
if (ignores.some((e) => e.ruleId === v.id && e.selector === void 0)) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
const hasNodeIgnores = ignores.some((e) => e.ruleId === v.id && e.selector !== void 0);
|
|
297
|
+
if (!hasNodeIgnores) return v;
|
|
298
|
+
const nodes = v.nodes.filter((node) => {
|
|
299
|
+
const last = node.target[node.target.length - 1];
|
|
300
|
+
const sel = (Array.isArray(last) ? last[last.length - 1] : last) ?? "";
|
|
301
|
+
return !ignores.some((e) => e.ruleId === v.id && e.selector === sel);
|
|
302
|
+
});
|
|
303
|
+
return nodes.length > 0 ? { ...v, nodes } : null;
|
|
304
|
+
}).filter((v) => v !== null);
|
|
98
305
|
return results;
|
|
99
306
|
}).finally(() => {
|
|
100
307
|
activeRun = null;
|
|
@@ -104,10 +311,10 @@ async function runScan(target = document.body, runOnly) {
|
|
|
104
311
|
}
|
|
105
312
|
|
|
106
313
|
// src/styles/base.css
|
|
107
|
-
var base_default = ':host {\n --a11y-hud-bg: #1e1e2e;\n --a11y-hud-bg-elevated: #313244;\n --a11y-hud-bg-hover: #45475a;\n --a11y-hud-border: #45475a;\n --a11y-hud-text: #cdd6f4;\n --a11y-hud-text-muted: #a6adc8;\n --a11y-hud-critical: #f38ba8;\n --a11y-hud-serious: #fab387;\n --a11y-hud-moderate: #f9e2af;\n --a11y-hud-minor: #89b4fa;\n --a11y-hud-highlight: #cba6f7;\n --a11y-hud-focus-ring: #89b4fa;\n --a11y-hud-radius: 8px;\n --a11y-hud-font: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;\n --a11y-hud-z-index: 999999;\n --a11y-hud-panel-width: 380px;\n\n all: initial;\n display: block;\n position: fixed;\n inset-block-end: 16px;\n inset-inline-end: 16px;\n z-index: var(--a11y-hud-z-index);\n font-family: var(--a11y-hud-font);\n font-size: 13px;\n line-height: 1.5;\n color: var(--a11y-hud-text);\n contain: layout style;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n.panel {\n width: var(--a11y-hud-panel-width);\n max-height: 70dvh;\n display: flex;\n flex-direction: column;\n background: var(--a11y-hud-bg);\n border: 1px solid var(--a11y-hud-border);\n border-radius: var(--a11y-hud-radius);\n overflow: hidden;\n box-shadow: 0 8px 32px rgb(0 0 0 / 40%);\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n background: var(--a11y-hud-bg-elevated);\n border-block-end: 1px solid var(--a11y-hud-border);\n flex-shrink: 0;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n.panel-title-icon {\n display: flex;\n align-items: center;\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n\n.panel-title-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.panel-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding-inline: 6px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 700;\n background: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.panel-count[data-count="0"] {\n background: var(--a11y-hud-minor);\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.btn-icon {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-icon svg {\n width: 14px;\n height: 14px;\n pointer-events: none;\n}\n\n.btn-icon:hover {\n background: var(--a11y-hud-bg-hover);\n color: var(--a11y-hud-text);\n}\n\n.btn-icon:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.btn-icon[data-scanning] {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.panel-filters {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 12px;\n border-block-end: 1px solid var(--a11y-hud-border);\n flex-shrink: 0;\n}\n\n.filter-group {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.filter-chip {\n all: unset;\n display: inline-flex;\n align-items: center;\n height: 22px;\n padding-inline: 8px;\n border-radius: 11px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n cursor: pointer;\n border: 1px solid var(--a11y-hud-border);\n color: var(--a11y-hud-text-muted);\n background: transparent;\n transition:\n background 120ms,\n color 120ms,\n border-color 120ms;\n}\n\n.filter-chip:hover {\n background: var(--a11y-hud-bg-hover);\n color: var(--a11y-hud-text);\n}\n\n.filter-chip:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.filter-chip[aria-pressed="true"][data-severity="critical"] {\n background: var(--a11y-hud-critical);\n border-color: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="serious"] {\n background: var(--a11y-hud-serious);\n border-color: var(--a11y-hud-serious);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="moderate"] {\n background: var(--a11y-hud-moderate);\n border-color: var(--a11y-hud-moderate);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="minor"] {\n background: var(--a11y-hud-minor);\n border-color: var(--a11y-hud-minor);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-level] {\n background: var(--a11y-hud-bg-elevated);\n border-color: var(--a11y-hud-text-muted);\n color: var(--a11y-hud-text);\n}\n\n.panel-body {\n flex: 1;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.panel-body:focus-visible {\n outline: none;\n}\n\n.violation-list {\n list-style: none;\n}\n\n.violation-item {\n border-block-end: 1px solid var(--a11y-hud-border);\n}\n\n.violation-item:last-child {\n border-block-end: none;\n}\n\n.violation-toggle {\n all: unset;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 8px 12px;\n cursor: pointer;\n text-align: start;\n transition: background 120ms;\n}\n\n.violation-toggle:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.violation-toggle:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: -2px;\n}\n\n.severity-icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n}\n\n.severity-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.severity-icon[data-severity="critical"] {\n color: var(--a11y-hud-critical);\n}\n\n.severity-icon[data-severity="serious"] {\n color: var(--a11y-hud-serious);\n}\n\n.severity-icon[data-severity="moderate"] {\n color: var(--a11y-hud-moderate);\n}\n\n.severity-icon[data-severity="minor"] {\n color: var(--a11y-hud-minor);\n}\n\n.violation-rule {\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n word-break: break-word;\n}\n\n.violation-node-count {\n font-size: 11px;\n color: var(--a11y-hud-text-muted);\n flex-shrink: 0;\n}\n\n.chevron-icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n color: var(--a11y-hud-text-muted);\n transition: transform 200ms;\n}\n\n.chevron-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.violation-toggle[aria-expanded="true"] .chevron-icon {\n transform: rotate(180deg);\n}\n\n.violation-detail {\n padding: 0 12px 10px 34px;\n display: none;\n flex-direction: column;\n gap: 8px;\n}\n\n.violation-detail[data-open] {\n display: flex;\n}\n\n.violation-description {\n font-size: 12px;\n color: var(--a11y-hud-text-muted);\n line-height: 1.6;\n}\n\n.violation-nodes-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.violation-node-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.btn-highlight {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-highlight);\n border: 1px solid var(--a11y-hud-border);\n cursor: pointer;\n word-break: break-all;\n transition: background 120ms;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.btn-highlight:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.btn-highlight:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.violation-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.violation-help-link {\n font-size: 11px;\n color: var(--a11y-hud-minor);\n text-decoration: none;\n}\n\n.violation-help-link:hover {\n text-decoration: underline;\n}\n\n.violation-help-link:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n border-radius: 2px;\n}\n\n.btn-copy-single {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-copy-single svg {\n width: 12px;\n height: 12px;\n pointer-events: none;\n}\n\n.btn-copy-single:hover {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-text);\n}\n\n.btn-copy-single:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--a11y-hud-text-muted);\n}\n\n.empty-state-icon {\n width: 32px;\n height: 32px;\n color: var(--a11y-hud-minor);\n}\n\n.empty-state-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.empty-state-title {\n font-weight: 600;\n color: var(--a11y-hud-text);\n}\n\n.empty-state-body {\n font-size: 12px;\n text-align: center;\n}\n\n.scanning-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 24px 16px;\n color: var(--a11y-hud-text-muted);\n font-size: 12px;\n}\n\n.scanning-spinner {\n width: 16px;\n height: 16px;\n color: var(--a11y-hud-minor);\n animation: spin 1s linear infinite;\n}\n\n.scanning-spinner svg {\n width: 100%;\n height: 100%;\n}\n\n/* \u2500\u2500 FAB (minimized state) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.fab {\n all: unset;\n display: none;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n background: var(--a11y-hud-bg);\n border: 1px solid var(--a11y-hud-border);\n border-radius: 24px;\n color: var(--a11y-hud-text);\n cursor: pointer;\n font-family: var(--a11y-hud-font);\n font-size: 13px;\n font-weight: 600;\n box-shadow: 0 4px 16px rgb(0 0 0 / 30%);\n transition: background 120ms;\n}\n\n:host([data-minimized]) .fab {\n display: flex;\n}\n\n:host([data-minimized]) .panel {\n display: none;\n}\n\n@keyframes panel-in {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.panel {\n animation: panel-in 120ms ease-out;\n}\n\n.fab:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.fab:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 2px;\n}\n\n.fab-icon {\n display: flex;\n align-items: center;\n width: 14px;\n height: 14px;\n}\n\n.fab-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.fab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding-inline: 5px;\n border-radius: 9px;\n font-size: 11px;\n font-weight: 700;\n background: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.fab-count[data-count="0"] {\n background: var(--a11y-hud-minor);\n}\n';
|
|
314
|
+
var base_default = ':host {\n --a11y-hud-bg: #1e1e2e;\n --a11y-hud-bg-elevated: #313244;\n --a11y-hud-bg-hover: #45475a;\n --a11y-hud-border: #45475a;\n --a11y-hud-text: #cdd6f4;\n --a11y-hud-text-muted: #a6adc8;\n --a11y-hud-critical: #f38ba8;\n --a11y-hud-serious: #fab387;\n --a11y-hud-moderate: #f9e2af;\n --a11y-hud-minor: #89b4fa;\n --a11y-hud-highlight: #cba6f7;\n --a11y-hud-tag: #94e2d5;\n --a11y-hud-focus-ring: #89b4fa;\n --a11y-hud-radius: 8px;\n --a11y-hud-font: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;\n --a11y-hud-z-index: 999999;\n --a11y-hud-panel-width: 380px;\n\n all: initial;\n display: block;\n position: fixed;\n inset-block-end: 16px;\n inset-inline-end: 16px;\n z-index: var(--a11y-hud-z-index);\n font-family: var(--a11y-hud-font);\n font-size: 13px;\n line-height: 1.5;\n color: var(--a11y-hud-text);\n contain: layout style;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n.panel {\n width: var(--a11y-hud-panel-width);\n max-height: 70dvh;\n display: flex;\n flex-direction: column;\n background: var(--a11y-hud-bg);\n border: 1px solid var(--a11y-hud-border);\n border-radius: var(--a11y-hud-radius);\n overflow: hidden;\n box-shadow: 0 8px 32px rgb(0 0 0 / 40%);\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n background: var(--a11y-hud-bg-elevated);\n border-block-end: 1px solid var(--a11y-hud-border);\n flex-shrink: 0;\n}\n\n.btn-panel-title {\n all: unset;\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n letter-spacing: 0.02em;\n cursor: pointer;\n border-radius: 4px;\n padding: 2px 4px;\n margin: -2px -4px;\n transition: color 120ms;\n}\n\n.btn-panel-title:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 2px;\n}\n\n.panel-title-icon {\n display: flex;\n align-items: center;\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n position: relative;\n transition: color 120ms;\n}\n\n.panel-title-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.btn-panel-title[data-active] .panel-title-icon {\n color: var(--a11y-hud-highlight);\n}\n\n.panel-title-chevron {\n display: flex;\n align-items: center;\n width: 12px;\n height: 12px;\n color: var(--a11y-hud-text-muted);\n transition: transform 200ms;\n}\n\n.panel-title-chevron svg {\n width: 100%;\n height: 100%;\n}\n\n.btn-panel-title[aria-expanded="true"] .panel-title-chevron {\n transform: rotate(180deg);\n}\n\n.panel-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding-inline: 6px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 700;\n background: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.panel-count[data-count="0"] {\n background: var(--a11y-hud-minor);\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.btn-icon {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-icon svg {\n width: 14px;\n height: 14px;\n pointer-events: none;\n}\n\n.btn-icon:hover {\n background: var(--a11y-hud-bg-hover);\n color: var(--a11y-hud-text);\n}\n\n.btn-icon:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.btn-icon[aria-pressed="true"] {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-highlight);\n outline: 1px solid var(--a11y-hud-highlight);\n outline-offset: -1px;\n}\n\n.btn-icon[data-scanning] {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.panel-filters {\n display: none;\n flex-direction: column;\n gap: 6px;\n padding: 8px 12px;\n border-block-end: 1px solid var(--a11y-hud-border);\n flex-shrink: 0;\n}\n\n.panel-filters[data-open] {\n display: flex;\n}\n\n.filter-group {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.filter-chip {\n all: unset;\n display: inline-flex;\n align-items: center;\n height: 22px;\n padding-inline: 8px;\n border-radius: 11px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n cursor: pointer;\n border: 1px solid var(--a11y-hud-border);\n color: var(--a11y-hud-text-muted);\n background: transparent;\n transition:\n background 120ms,\n color 120ms,\n border-color 120ms;\n}\n\n.filter-chip:hover {\n background: var(--a11y-hud-bg-hover);\n color: var(--a11y-hud-text);\n}\n\n.filter-chip:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.filter-chip[aria-pressed="true"][data-severity="critical"] {\n background: var(--a11y-hud-critical);\n border-color: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="serious"] {\n background: var(--a11y-hud-serious);\n border-color: var(--a11y-hud-serious);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="moderate"] {\n background: var(--a11y-hud-moderate);\n border-color: var(--a11y-hud-moderate);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-severity="minor"] {\n background: var(--a11y-hud-minor);\n border-color: var(--a11y-hud-minor);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-level] {\n background: var(--a11y-hud-highlight);\n border-color: var(--a11y-hud-highlight);\n color: var(--a11y-hud-bg);\n}\n\n.filter-chip[aria-pressed="true"][data-ruleset] {\n background: var(--a11y-hud-tag);\n border-color: var(--a11y-hud-tag);\n color: var(--a11y-hud-bg);\n}\n\n.panel-body {\n flex: 1;\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.panel-body:focus-visible {\n outline: none;\n}\n\n.violation-list {\n list-style: none;\n}\n\n.violation-item {\n border-block-end: 1px solid var(--a11y-hud-border);\n}\n\n.violation-item:last-child {\n border-block-end: none;\n}\n\n.violation-toggle {\n all: unset;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 8px 12px;\n cursor: pointer;\n text-align: start;\n transition: background 120ms;\n}\n\n.violation-toggle:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.violation-toggle:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: -2px;\n}\n\n.severity-icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n}\n\n.severity-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.severity-icon[data-severity="critical"] {\n color: var(--a11y-hud-critical);\n}\n\n.severity-icon[data-severity="serious"] {\n color: var(--a11y-hud-serious);\n}\n\n.severity-icon[data-severity="moderate"] {\n color: var(--a11y-hud-moderate);\n}\n\n.severity-icon[data-severity="minor"] {\n color: var(--a11y-hud-minor);\n}\n\n.violation-rule {\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n word-break: break-word;\n}\n\n.violation-node-count {\n font-size: 11px;\n color: var(--a11y-hud-text-muted);\n flex-shrink: 0;\n}\n\n.chevron-icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n color: var(--a11y-hud-text-muted);\n transition: transform 200ms;\n}\n\n.chevron-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.violation-toggle[aria-expanded="true"] .chevron-icon {\n transform: rotate(180deg);\n}\n\n.violation-detail {\n padding: 0 12px 10px 34px;\n display: none;\n flex-direction: column;\n gap: 8px;\n}\n\n.violation-detail[data-open] {\n display: flex;\n}\n\n.violation-description {\n font-size: 12px;\n color: var(--a11y-hud-text-muted);\n line-height: 1.6;\n}\n\n.violation-nodes-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.violation-node-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.btn-highlight {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-highlight);\n border: 1px solid var(--a11y-hud-border);\n cursor: pointer;\n word-break: break-all;\n transition: background 120ms;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.btn-highlight:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.btn-highlight:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.violation-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.violation-help-link {\n font-size: 11px;\n color: var(--a11y-hud-minor);\n text-decoration: none;\n}\n\n.violation-help-link:hover {\n text-decoration: underline;\n}\n\n.violation-help-link:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n border-radius: 2px;\n}\n\n.btn-copy-single {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-copy-single svg {\n width: 12px;\n height: 12px;\n pointer-events: none;\n}\n\n.btn-copy-single:hover {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-text);\n}\n\n.btn-copy-single:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.btn-ignore-rule {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-ignore-rule svg {\n width: 12px;\n height: 12px;\n pointer-events: none;\n}\n\n.btn-ignore-rule:hover {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-critical);\n}\n\n.btn-ignore-rule:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n/* \u2500\u2500 Ignored rules section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ignored-section {\n border-top: 1px solid var(--a11y-hud-border);\n margin-top: 8px;\n}\n\n.ignored-section-toggle {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 8px 12px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n font-weight: 600;\n color: var(--a11y-hud-text-muted);\n cursor: pointer;\n gap: 6px;\n box-sizing: border-box;\n}\n\n.ignored-section-toggle:hover {\n color: var(--a11y-hud-text);\n}\n\n.ignored-section-toggle:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.ignored-section-toggle .chevron-icon {\n width: 12px;\n height: 12px;\n transition: transform 120ms;\n flex-shrink: 0;\n}\n\n.ignored-section-toggle[aria-expanded="true"] .chevron-icon {\n transform: rotate(180deg);\n}\n\n.ignored-section-body {\n display: none;\n padding: 0 12px 10px;\n}\n\n.ignored-section-body[data-open] {\n display: block;\n}\n\n.ignored-empty {\n font-size: 11px;\n color: var(--a11y-hud-text-muted);\n margin: 0 0 8px;\n}\n\n.ignored-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0 0 8px;\n padding: 0;\n}\n\n.ignored-entry {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n}\n\n.ignored-rule-id {\n font-weight: 600;\n color: var(--a11y-hud-text);\n}\n\n.ignored-selector {\n font-size: 10px;\n font-family: ui-monospace, monospace;\n color: var(--a11y-hud-text-muted);\n background: var(--a11y-hud-bg-elevated);\n padding: 1px 4px;\n border-radius: 3px;\n}\n\n.btn-remove-ignore {\n all: unset;\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n color: var(--a11y-hud-text-muted);\n margin-left: auto;\n padding: 2px;\n border-radius: 3px;\n transition: color 120ms;\n}\n\n.btn-remove-ignore svg {\n width: 12px;\n height: 12px;\n pointer-events: none;\n}\n\n.btn-remove-ignore:hover {\n color: var(--a11y-hud-critical);\n}\n\n.btn-remove-ignore:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.ignored-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.btn-sm {\n all: unset;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 11px;\n font-family: var(--a11y-hud-font);\n color: var(--a11y-hud-text-muted);\n border: 1px solid var(--a11y-hud-border);\n cursor: pointer;\n transition:\n background 120ms,\n color 120ms;\n}\n\n.btn-sm svg {\n width: 11px;\n height: 11px;\n pointer-events: none;\n}\n\n.btn-sm:hover {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-text);\n}\n\n.btn-sm:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--a11y-hud-text-muted);\n}\n\n.empty-state-icon {\n width: 32px;\n height: 32px;\n color: var(--a11y-hud-minor);\n}\n\n.empty-state-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.empty-state-title {\n font-weight: 600;\n color: var(--a11y-hud-text);\n}\n\n.empty-state-body {\n font-size: 12px;\n text-align: center;\n}\n\n.scanning-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 24px 16px;\n color: var(--a11y-hud-text-muted);\n font-size: 12px;\n}\n\n.scanning-spinner {\n width: 16px;\n height: 16px;\n color: var(--a11y-hud-minor);\n animation: spin 1s linear infinite;\n}\n\n.scanning-spinner svg {\n width: 100%;\n height: 100%;\n}\n\n/* \u2500\u2500 Keyboard mode view \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel[data-kbd-mode] .panel-filters {\n display: none;\n}\n\n.kbd-mode-view {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 8px 0;\n}\n\n.kbd-mode-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0 12px 8px;\n border-bottom: 1px solid var(--a11y-hud-border);\n font-size: 12px;\n font-weight: 600;\n}\n\n.kbd-mode-stat {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--a11y-hud-text-muted);\n}\n\n.kbd-mode-stat svg {\n width: 13px;\n height: 13px;\n}\n\n.kbd-mode-stat--warn {\n color: var(--a11y-hud-serious);\n}\n\n.kbd-mode-stat--ok {\n color: var(--a11y-hud-minor);\n}\n\n.kbd-violation-list,\n.kbd-element-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n padding: 0 12px;\n}\n\n.kbd-violation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 11px;\n color: var(--a11y-hud-text);\n padding: 4px 0;\n border-bottom: 1px solid var(--a11y-hud-border);\n}\n\n.kbd-violation-item:last-child {\n border-bottom: none;\n}\n\n.kbd-violation-msg {\n flex: 1;\n line-height: 1.4;\n}\n\n.kbd-element-item {\n display: flex;\n align-items: center;\n}\n\n.btn-kbd-element {\n all: unset;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n font-size: 11px;\n color: var(--a11y-hud-text-muted);\n padding: 3px 6px;\n border-radius: 4px;\n cursor: pointer;\n transition: background 120ms;\n}\n\n.btn-kbd-element:hover {\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-text);\n}\n\n.btn-kbd-element:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 1px;\n}\n\n.kbd-element-index {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n border-radius: 10px;\n background: #7c3aed;\n color: #fff;\n font-size: 10px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.kbd-element-selector {\n font-family: ui-monospace, monospace;\n font-size: 10px;\n color: var(--a11y-hud-highlight);\n}\n\n.kbd-element-tag {\n color: var(--a11y-hud-text-muted);\n font-size: 10px;\n}\n\n.kbd-tabindex-badge {\n font-size: 10px;\n font-family: ui-monospace, monospace;\n background: var(--a11y-hud-bg-elevated);\n color: var(--a11y-hud-serious);\n padding: 1px 4px;\n border-radius: 3px;\n border: 1px solid var(--a11y-hud-border);\n}\n\n.kbd-empty {\n font-size: 12px;\n color: var(--a11y-hud-text-muted);\n padding: 0 12px;\n margin: 0;\n}\n\n/* \u2500\u2500 FAB (minimized state) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.fab {\n all: unset;\n display: none;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n background: var(--a11y-hud-bg);\n border: 1px solid var(--a11y-hud-border);\n border-radius: 24px;\n color: var(--a11y-hud-text);\n cursor: pointer;\n font-family: var(--a11y-hud-font);\n font-size: 13px;\n font-weight: 600;\n box-shadow: 0 4px 16px rgb(0 0 0 / 30%);\n transition: background 120ms;\n}\n\n:host([data-minimized]) .fab {\n display: flex;\n}\n\n:host([data-minimized]) .panel {\n display: none;\n}\n\n@keyframes panel-in {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.panel {\n animation: panel-in 120ms ease-out;\n}\n\n.fab:hover {\n background: var(--a11y-hud-bg-elevated);\n}\n\n.fab:focus-visible {\n outline: 2px solid var(--a11y-hud-focus-ring);\n outline-offset: 2px;\n}\n\n.fab-icon {\n display: flex;\n align-items: center;\n width: 14px;\n height: 14px;\n}\n\n.fab-icon svg {\n width: 100%;\n height: 100%;\n}\n\n.fab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding-inline: 5px;\n border-radius: 9px;\n font-size: 11px;\n font-weight: 700;\n background: var(--a11y-hud-critical);\n color: var(--a11y-hud-bg);\n}\n\n.fab-count[data-count="0"] {\n background: var(--a11y-hud-minor);\n}\n';
|
|
108
315
|
|
|
109
316
|
// src/styles/themes.css
|
|
110
|
-
var themes_default = ':host([data-theme="light"]) {\n --a11y-hud-bg: #eff1f5;\n --a11y-hud-bg-elevated: #e6e9ef;\n --a11y-hud-bg-hover: #dce0e8;\n --a11y-hud-border: #bcc0cc;\n --a11y-hud-text: #4c4f69;\n /* #5c5f77 gives 5.56:1 on #eff1f5 (was #6c6f85 at 4.36:1) */\n --a11y-hud-text-muted: #5c5f77;\n --a11y-hud-critical: #d20f39;\n --a11y-hud-serious: #fe640b;\n --a11y-hud-moderate: #df8e1d;\n /* #1452c7 gives 5.92:1 on #eff1f5 (was #1e66f5 at 4.34:1) */\n --a11y-hud-minor: #1452c7;\n --a11y-hud-highlight: #8839ef;\n --a11y-hud-focus-ring: #1452c7;\n}\n\n/* Chip text overrides \u2014 bright severity backgrounds need dark or white text\n to meet 4.5:1 at 11 px. The base CSS uses --a11y-hud-bg (light in this\n theme) which fails on orange and yellow. */\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="critical"] {\n color: #ffffff;\n}\n\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="serious"],\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="moderate"] {\n color: #1a1a2e;\n}\n\n:host([data-theme="github-dark"]) {\n --a11y-hud-bg: #0d1117;\n --a11y-hud-bg-elevated: #161b22;\n --a11y-hud-bg-hover: #21262d;\n --a11y-hud-border: #30363d;\n --a11y-hud-text: #e6edf3;\n --a11y-hud-text-muted: #8b949e;\n --a11y-hud-critical: #ff7b72;\n --a11y-hud-serious: #ffa657;\n --a11y-hud-moderate: #e3b341;\n --a11y-hud-minor: #79c0ff;\n --a11y-hud-highlight: #d2a8ff;\n --a11y-hud-focus-ring: #2f81f7;\n}\n\n:host([data-theme="github-light"]) {\n --a11y-hud-bg: #ffffff;\n --a11y-hud-bg-elevated: #f6f8fa;\n --a11y-hud-bg-hover: #eaeef2;\n --a11y-hud-border: #d0d7de;\n --a11y-hud-text: #1f2328;\n --a11y-hud-text-muted: #636c76;\n --a11y-hud-critical: #cf222e;\n --a11y-hud-serious: #bc4c00;\n /* #8a5e00 gives 5.33:1 white-on-chip (was #9a6700 at 4.37:1 \u2014 neither black nor white passed) */\n --a11y-hud-moderate: #8a5e00;\n --a11y-hud-minor: #0550ae;\n --a11y-hud-highlight: #8250df;\n --a11y-hud-focus-ring: #0550ae;\n}\n\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="critical"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="serious"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="moderate"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="minor"] {\n color: #ffffff;\n}\n\n:host([data-theme="tokyo-night"]) {\n --a11y-hud-bg: #1a1b26;\n --a11y-hud-bg-elevated: #24283b;\n --a11y-hud-bg-hover: #2f3549;\n --a11y-hud-border: #3b4261;\n --a11y-hud-text: #c0caf5;\n /* #9aa5ce gives 7.67:1 on #1a1b26 (was #737aa2 at ~4.1:1) */\n --a11y-hud-text-muted: #9aa5ce;\n --a11y-hud-critical: #f7768e;\n --a11y-hud-serious: #ff9e64;\n --a11y-hud-moderate: #e0af68;\n --a11y-hud-minor: #7aa2f7;\n --a11y-hud-highlight: #bb9af7;\n --a11y-hud-focus-ring: #7aa2f7;\n}\n\n:host([data-theme="solarized-dark"]) {\n --a11y-hud-bg: #002b36;\n --a11y-hud-bg-elevated: #073642;\n --a11y-hud-bg-hover: #0d4456;\n --a11y-hud-border: #586e75;\n --a11y-hud-text: #eee8d5;\n --a11y-hud-text-muted: #93a1a1;\n --a11y-hud-critical: #dc322f;\n --a11y-hud-serious: #cb4b16;\n --a11y-hud-moderate: #b58900;\n /* #5ba4cf gives 5.78:1 on #002b36 for text, 5.78:1 for chip (was #268bd2 at ~3.1:1 for both) */\n --a11y-hud-minor: #5ba4cf;\n /* #f06090 gives 4.88:1 on #002b36 (was #d33682 at ~3.3:1) */\n --a11y-hud-highlight: #f06090;\n --a11y-hud-focus-ring: #268bd2;\n}\n\n/* Solarized Dark chip text overrides \u2014 canonical solarized palette falls in the\n middle-luminance zone where neither the panel bg (#002b36) nor white passes\n 4.5:1 on yellow/blue chip backgrounds. Use white text on red/orange,\n dark panel bg text on yellow/blue. */\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="critical"],\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="serious"] {\n color: #ffffff;\n}\n\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="moderate"],\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="minor"] {\n color: #002b36;\n}\n\n:host([data-theme="high-contrast"]) {\n --a11y-hud-bg: #000000;\n --a11y-hud-bg-elevated: #111111;\n --a11y-hud-bg-hover: #222222;\n --a11y-hud-border: #ffffff;\n --a11y-hud-text: #ffffff;\n --a11y-hud-text-muted: #cccccc;\n --a11y-hud-critical: #ff4444;\n --a11y-hud-serious: #ff8800;\n --a11y-hud-moderate: #ffcc00;\n --a11y-hud-minor: #66aaff;\n --a11y-hud-highlight: #ff66ff;\n --a11y-hud-focus-ring: #ffffff;\n}\n';
|
|
317
|
+
var themes_default = ':host([data-theme="light"]) {\n --a11y-hud-bg: #eff1f5;\n --a11y-hud-bg-elevated: #e6e9ef;\n --a11y-hud-bg-hover: #dce0e8;\n --a11y-hud-border: #bcc0cc;\n --a11y-hud-text: #4c4f69;\n /* #5c5f77 gives 5.56:1 on #eff1f5 (was #6c6f85 at 4.36:1) */\n --a11y-hud-text-muted: #5c5f77;\n --a11y-hud-critical: #d20f39;\n --a11y-hud-serious: #fe640b;\n --a11y-hud-moderate: #df8e1d;\n /* #1452c7 gives 5.92:1 on #eff1f5 (was #1e66f5 at 4.34:1) */\n --a11y-hud-minor: #1452c7;\n --a11y-hud-highlight: #8839ef;\n --a11y-hud-tag: #0d7d80;\n --a11y-hud-focus-ring: #1452c7;\n}\n\n/* Chip text overrides \u2014 bright severity backgrounds need dark or white text\n to meet 4.5:1 at 11 px. The base CSS uses --a11y-hud-bg (light in this\n theme) which fails on orange and yellow. */\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="critical"] {\n color: #ffffff;\n}\n\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="serious"],\n:host([data-theme="light"]) .filter-chip[aria-pressed="true"][data-severity="moderate"] {\n color: #1a1a2e;\n}\n\n:host([data-theme="github-dark"]) {\n --a11y-hud-bg: #0d1117;\n --a11y-hud-bg-elevated: #161b22;\n --a11y-hud-bg-hover: #21262d;\n --a11y-hud-border: #30363d;\n --a11y-hud-text: #e6edf3;\n --a11y-hud-text-muted: #8b949e;\n --a11y-hud-critical: #ff7b72;\n --a11y-hud-serious: #ffa657;\n --a11y-hud-moderate: #e3b341;\n --a11y-hud-minor: #79c0ff;\n --a11y-hud-highlight: #d2a8ff;\n --a11y-hud-tag: #56d364;\n --a11y-hud-focus-ring: #2f81f7;\n}\n\n:host([data-theme="github-light"]) {\n --a11y-hud-bg: #ffffff;\n --a11y-hud-bg-elevated: #f6f8fa;\n --a11y-hud-bg-hover: #eaeef2;\n --a11y-hud-border: #d0d7de;\n --a11y-hud-text: #1f2328;\n --a11y-hud-text-muted: #636c76;\n --a11y-hud-critical: #cf222e;\n --a11y-hud-serious: #bc4c00;\n /* #8a5e00 gives 5.33:1 white-on-chip (was #9a6700 at 4.37:1 \u2014 neither black nor white passed) */\n --a11y-hud-moderate: #8a5e00;\n --a11y-hud-minor: #0550ae;\n --a11y-hud-highlight: #8250df;\n --a11y-hud-tag: #1a7f37;\n --a11y-hud-focus-ring: #0550ae;\n}\n\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="critical"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="serious"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="moderate"],\n:host([data-theme="github-light"]) .filter-chip[aria-pressed="true"][data-severity="minor"] {\n color: #ffffff;\n}\n\n:host([data-theme="tokyo-night"]) {\n --a11y-hud-bg: #1a1b26;\n --a11y-hud-bg-elevated: #24283b;\n --a11y-hud-bg-hover: #2f3549;\n --a11y-hud-border: #3b4261;\n --a11y-hud-text: #c0caf5;\n /* #9aa5ce gives 7.67:1 on #1a1b26 (was #737aa2 at ~4.1:1) */\n --a11y-hud-text-muted: #9aa5ce;\n --a11y-hud-critical: #f7768e;\n --a11y-hud-serious: #ff9e64;\n --a11y-hud-moderate: #e0af68;\n --a11y-hud-minor: #7aa2f7;\n --a11y-hud-highlight: #bb9af7;\n --a11y-hud-tag: #73daca;\n --a11y-hud-focus-ring: #7aa2f7;\n}\n\n:host([data-theme="solarized-dark"]) {\n --a11y-hud-bg: #002b36;\n --a11y-hud-bg-elevated: #073642;\n --a11y-hud-bg-hover: #0d4456;\n --a11y-hud-border: #586e75;\n --a11y-hud-text: #eee8d5;\n --a11y-hud-text-muted: #93a1a1;\n --a11y-hud-critical: #dc322f;\n --a11y-hud-serious: #cb4b16;\n --a11y-hud-moderate: #b58900;\n /* #5ba4cf gives 5.78:1 on #002b36 for text, 5.78:1 for chip (was #268bd2 at ~3.1:1 for both) */\n --a11y-hud-minor: #5ba4cf;\n /* #f06090 gives 4.88:1 on #002b36 (was #d33682 at ~3.3:1) */\n --a11y-hud-highlight: #f06090;\n --a11y-hud-tag: #5cccbc;\n --a11y-hud-focus-ring: #268bd2;\n}\n\n/* Solarized Dark chip text overrides \u2014 canonical solarized palette falls in the\n middle-luminance zone where neither the panel bg (#002b36) nor white passes\n 4.5:1 on yellow/blue chip backgrounds. Use white text on red/orange,\n dark panel bg text on yellow/blue. */\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="critical"],\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="serious"] {\n color: #ffffff;\n}\n\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="moderate"],\n:host([data-theme="solarized-dark"]) .filter-chip[aria-pressed="true"][data-severity="minor"] {\n color: #002b36;\n}\n\n:host([data-theme="high-contrast"]) {\n --a11y-hud-bg: #000000;\n --a11y-hud-bg-elevated: #111111;\n --a11y-hud-bg-hover: #222222;\n --a11y-hud-border: #ffffff;\n --a11y-hud-text: #ffffff;\n --a11y-hud-text-muted: #cccccc;\n --a11y-hud-critical: #ff4444;\n --a11y-hud-serious: #ff8800;\n --a11y-hud-moderate: #ffcc00;\n --a11y-hud-minor: #66aaff;\n --a11y-hud-highlight: #ff66ff;\n --a11y-hud-tag: #00e5d0;\n --a11y-hud-focus-ring: #ffffff;\n}\n';
|
|
111
318
|
|
|
112
319
|
// src/theme.ts
|
|
113
320
|
function resolveTheme(theme) {
|
|
@@ -168,6 +375,9 @@ function ensureHighlightStyle(doc) {
|
|
|
168
375
|
style.textContent = HIGHLIGHT_CSS;
|
|
169
376
|
doc.head.appendChild(style);
|
|
170
377
|
}
|
|
378
|
+
function escapeHtml(s) {
|
|
379
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
380
|
+
}
|
|
171
381
|
function buildStyleSheet(css) {
|
|
172
382
|
try {
|
|
173
383
|
const sheet = new CSSStyleSheet();
|
|
@@ -191,10 +401,15 @@ var A11yHudElement = class extends HTMLElement {
|
|
|
191
401
|
_observer;
|
|
192
402
|
_unwatchTheme;
|
|
193
403
|
_removeHighlight;
|
|
194
|
-
_activeSeverities = /* @__PURE__ */ new Set(
|
|
195
|
-
_activeLevels = /* @__PURE__ */ new Set(
|
|
404
|
+
_activeSeverities = /* @__PURE__ */ new Set();
|
|
405
|
+
_activeLevels = /* @__PURE__ */ new Set();
|
|
196
406
|
_runOnly = [];
|
|
197
407
|
_debouncedScan;
|
|
408
|
+
_keyboardMode = false;
|
|
409
|
+
_keyboardCleanup;
|
|
410
|
+
_kbElements = [];
|
|
411
|
+
_filtersOpen = false;
|
|
412
|
+
_ignoredSectionOpen = false;
|
|
198
413
|
constructor() {
|
|
199
414
|
super();
|
|
200
415
|
this._shadow = this.attachShadow({ mode: "open" });
|
|
@@ -232,6 +447,8 @@ ${themes_default}`;
|
|
|
232
447
|
this._unwatchTheme?.();
|
|
233
448
|
this._removeHighlight?.();
|
|
234
449
|
this._removeHighlight = void 0;
|
|
450
|
+
this._keyboardCleanup?.();
|
|
451
|
+
this._keyboardCleanup = void 0;
|
|
235
452
|
this._debouncedScan.cancel();
|
|
236
453
|
}
|
|
237
454
|
attributeChangedCallback(name, _old, value) {
|
|
@@ -354,9 +571,10 @@ ${themes_default}`;
|
|
|
354
571
|
const violations = this._results?.violations ?? [];
|
|
355
572
|
return violations.filter((v) => {
|
|
356
573
|
const impact = v.impact;
|
|
357
|
-
if (impact && !this._activeSeverities.has(impact))
|
|
574
|
+
if (this._activeSeverities.size > 0 && impact && !this._activeSeverities.has(impact))
|
|
575
|
+
return false;
|
|
358
576
|
const level = getViolationLevel(v.tags);
|
|
359
|
-
if (level && !this._activeLevels.has(level)) return false;
|
|
577
|
+
if (this._activeLevels.size > 0 && level && !this._activeLevels.has(level)) return false;
|
|
360
578
|
return true;
|
|
361
579
|
});
|
|
362
580
|
}
|
|
@@ -381,11 +599,14 @@ ${themes_default}`;
|
|
|
381
599
|
fabCountEl.textContent = String(total);
|
|
382
600
|
fabCountEl.setAttribute("data-count", String(total));
|
|
383
601
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
602
|
+
if (!this._keyboardMode) {
|
|
603
|
+
const body = panel.querySelector(".panel-body");
|
|
604
|
+
if (body) body.innerHTML = this._renderBody(filtered);
|
|
605
|
+
this._bindHighlightEvents();
|
|
606
|
+
}
|
|
387
607
|
}
|
|
388
608
|
_renderScanning() {
|
|
609
|
+
if (this._keyboardMode) return;
|
|
389
610
|
const body = this._shadow.querySelector(".panel-body");
|
|
390
611
|
if (body) {
|
|
391
612
|
body.innerHTML = `
|
|
@@ -393,6 +614,7 @@ ${themes_default}`;
|
|
|
393
614
|
<span class="scanning-spinner" aria-hidden="true">${icon("refresh-cw")}</span>
|
|
394
615
|
Scanning\u2026
|
|
395
616
|
</div>
|
|
617
|
+
${this._renderIgnoredSection()}
|
|
396
618
|
`;
|
|
397
619
|
}
|
|
398
620
|
}
|
|
@@ -400,18 +622,25 @@ ${themes_default}`;
|
|
|
400
622
|
return `
|
|
401
623
|
<div class="panel" role="complementary" aria-label="Accessibility panel">
|
|
402
624
|
<div class="panel-header">
|
|
403
|
-
<
|
|
625
|
+
<button class="btn-panel-title" aria-expanded="${this._filtersOpen}" aria-controls="panel-filters" aria-label="Toggle filters" title="Toggle filters">
|
|
404
626
|
<span class="panel-title-icon" aria-hidden="true">${icon("filter")}</span>
|
|
405
627
|
a11y
|
|
406
628
|
<span class="panel-count" data-count="${total}" aria-live="polite" aria-label="${total} violations">${total}</span>
|
|
407
|
-
|
|
629
|
+
<span class="panel-title-chevron" aria-hidden="true">${icon("chevron-down")}</span>
|
|
630
|
+
</button>
|
|
408
631
|
<div class="panel-actions" role="toolbar" aria-label="Panel actions">
|
|
409
632
|
<button class="btn-icon" id="btn-copy-all" aria-label="Copy all violations to clipboard" title="Copy all">
|
|
410
633
|
${icon("copy")}
|
|
411
634
|
</button>
|
|
635
|
+
<button class="btn-icon" id="btn-export" aria-label="Export results as JSON" title="Export JSON">
|
|
636
|
+
${icon("download")}
|
|
637
|
+
</button>
|
|
412
638
|
<button class="btn-icon" id="btn-rescan" aria-label="Re-scan page" title="Re-scan">
|
|
413
639
|
${icon("refresh-cw")}
|
|
414
640
|
</button>
|
|
641
|
+
<button class="btn-icon" id="btn-keyboard" aria-label="Toggle keyboard mode" title="Keyboard mode" aria-pressed="false">
|
|
642
|
+
${icon("keyboard")}
|
|
643
|
+
</button>
|
|
415
644
|
<button class="btn-icon" id="btn-minimize" aria-label="Minimize panel" title="Minimize">
|
|
416
645
|
${icon("minus")}
|
|
417
646
|
</button>
|
|
@@ -447,7 +676,7 @@ ${themes_default}`;
|
|
|
447
676
|
return `<button class="filter-chip" data-ruleset="${r}" aria-pressed="${active}">${r}</button>`;
|
|
448
677
|
}).join("");
|
|
449
678
|
return `
|
|
450
|
-
<div class="panel-filters" aria-label="Filters">
|
|
679
|
+
<div id="panel-filters" class="panel-filters" aria-label="Filters" ${this._filtersOpen ? "data-open" : ""}>
|
|
451
680
|
<div class="filter-group" role="group" aria-label="Filter by severity">${severityChips}</div>
|
|
452
681
|
<div class="filter-group" role="group" aria-label="Filter by WCAG level">${levelChips}</div>
|
|
453
682
|
<div class="filter-group" role="group" aria-label="Run only rule sets">${ruleSetChips}</div>
|
|
@@ -461,6 +690,7 @@ ${themes_default}`;
|
|
|
461
690
|
<span class="scanning-spinner" aria-hidden="true">${icon("refresh-cw")}</span>
|
|
462
691
|
<span class="empty-state-body">Running first scan\u2026</span>
|
|
463
692
|
</div>
|
|
693
|
+
${this._renderIgnoredSection()}
|
|
464
694
|
`;
|
|
465
695
|
}
|
|
466
696
|
if (violations.length === 0) {
|
|
@@ -472,10 +702,44 @@ ${themes_default}`;
|
|
|
472
702
|
${this._results.violations.length > 0 ? "All violations filtered out." : "Great job! The scanned area has no axe-core violations."}
|
|
473
703
|
</span>
|
|
474
704
|
</div>
|
|
705
|
+
${this._renderIgnoredSection()}
|
|
475
706
|
`;
|
|
476
707
|
}
|
|
477
708
|
const items = violations.map((v, i) => this._renderViolationItem(v, i)).join("");
|
|
478
|
-
return `<ul class="violation-list" role="list" aria-label="${violations.length} violation${violations.length !== 1 ? "s" : ""}">${items}</ul
|
|
709
|
+
return `<ul class="violation-list" role="list" aria-label="${violations.length} violation${violations.length !== 1 ? "s" : ""}">${items}</ul>${this._renderIgnoredSection()}`;
|
|
710
|
+
}
|
|
711
|
+
_renderIgnoredSection() {
|
|
712
|
+
const entries = listIgnores();
|
|
713
|
+
const removeAttrs = (e) => e.selector !== void 0 ? `data-remove-rule="${e.ruleId}" data-remove-selector="${e.selector}"` : `data-remove-rule="${e.ruleId}"`;
|
|
714
|
+
const listHtml = entries.length === 0 ? `<p class="ignored-empty">No rules ignored yet.</p>` : `<ul class="ignored-list" aria-label="Ignored rules">${entries.map(
|
|
715
|
+
(e) => `
|
|
716
|
+
<li class="ignored-entry">
|
|
717
|
+
<span class="ignored-rule-id">${e.ruleId}</span>
|
|
718
|
+
${e.selector !== void 0 ? `<code class="ignored-selector">${e.selector}</code>` : ""}
|
|
719
|
+
<button class="btn-remove-ignore" ${removeAttrs(e)} aria-label="Remove ignore for ${e.ruleId}">
|
|
720
|
+
${icon("trash-2")}
|
|
721
|
+
</button>
|
|
722
|
+
</li>`
|
|
723
|
+
).join("")}</ul>`;
|
|
724
|
+
return `
|
|
725
|
+
<div class="ignored-section">
|
|
726
|
+
<button class="ignored-section-toggle" aria-expanded="${this._ignoredSectionOpen}" aria-controls="ignored-section-body">
|
|
727
|
+
<span>Ignored rules (${entries.length})</span>
|
|
728
|
+
<span class="chevron-icon" aria-hidden="true">${icon("chevron-down")}</span>
|
|
729
|
+
</button>
|
|
730
|
+
<div id="ignored-section-body" class="ignored-section-body" ${this._ignoredSectionOpen ? "data-open" : ""}>
|
|
731
|
+
${listHtml}
|
|
732
|
+
<div class="ignored-actions">
|
|
733
|
+
<button class="btn-export-ignores btn-sm" aria-label="Export ignored rules as JSON" title="Export ignores">
|
|
734
|
+
${icon("download")} Export
|
|
735
|
+
</button>
|
|
736
|
+
<button class="btn-import-ignores btn-sm" aria-label="Import ignored rules from JSON" title="Import ignores">
|
|
737
|
+
${icon("upload")} Import
|
|
738
|
+
</button>
|
|
739
|
+
${entries.length > 0 ? `<button class="btn-clear-ignores btn-sm" aria-label="Clear all ignored rules" title="Clear all">${icon("trash-2")} Clear all</button>` : ""}
|
|
740
|
+
</div>
|
|
741
|
+
</div>
|
|
742
|
+
</div>`;
|
|
479
743
|
}
|
|
480
744
|
_renderViolationItem(violation, index) {
|
|
481
745
|
const impact = violation.impact ?? "minor";
|
|
@@ -510,6 +774,9 @@ ${themes_default}`;
|
|
|
510
774
|
<button class="btn-copy-single" data-copy-violation="${index}" aria-label="Copy ${violation.id} to clipboard" title="Copy violation">
|
|
511
775
|
${icon("copy")} Copy
|
|
512
776
|
</button>
|
|
777
|
+
<button class="btn-ignore-rule" data-ignore-rule="${violation.id}" aria-label="Ignore rule ${violation.id}" title="Ignore this rule">
|
|
778
|
+
${icon("trash-2")} Ignore
|
|
779
|
+
</button>
|
|
513
780
|
</div>
|
|
514
781
|
</div>
|
|
515
782
|
</li>
|
|
@@ -522,11 +789,14 @@ ${themes_default}`;
|
|
|
522
789
|
_bindEvents() {
|
|
523
790
|
const panel = this._shadow.querySelector(".panel");
|
|
524
791
|
if (!panel) return;
|
|
792
|
+
panel.querySelector(".btn-panel-title")?.addEventListener("click", () => this._toggleFilters());
|
|
525
793
|
panel.querySelector("#btn-rescan")?.addEventListener("click", () => void this._runScan());
|
|
526
794
|
panel.querySelector("#btn-minimize")?.addEventListener("click", () => {
|
|
527
795
|
this.setAttribute("data-minimized", "");
|
|
528
796
|
});
|
|
529
797
|
panel.querySelector("#btn-copy-all")?.addEventListener("click", () => void this._copyAll());
|
|
798
|
+
panel.querySelector("#btn-export")?.addEventListener("click", () => this._exportJson());
|
|
799
|
+
panel.querySelector("#btn-keyboard")?.addEventListener("click", () => this._toggleKeyboardMode());
|
|
530
800
|
panel.addEventListener("click", (e) => this._handlePanelClick(e));
|
|
531
801
|
panel.addEventListener("keydown", (e) => this._handlePanelKeydown(e));
|
|
532
802
|
this._shadow.querySelector(".fab")?.addEventListener("click", () => {
|
|
@@ -567,29 +837,84 @@ ${themes_default}`;
|
|
|
567
837
|
void this._copySingle(vIdx);
|
|
568
838
|
return;
|
|
569
839
|
}
|
|
840
|
+
const kbdElementBtn = target.closest(".btn-kbd-element");
|
|
841
|
+
if (kbdElementBtn) {
|
|
842
|
+
const idx = Number.parseInt(kbdElementBtn.dataset.kbdElement ?? "", 10);
|
|
843
|
+
const info = this._kbElements.find((e2) => e2.index === idx);
|
|
844
|
+
if (info) {
|
|
845
|
+
this._removeHighlight?.();
|
|
846
|
+
ensureHighlightStyle(document);
|
|
847
|
+
const el = info.element;
|
|
848
|
+
el.setAttribute(HIGHLIGHT_ATTR, "");
|
|
849
|
+
el.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
850
|
+
this._removeHighlight = () => el.removeAttribute(HIGHLIGHT_ATTR);
|
|
851
|
+
}
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
const ignoreBtn = target.closest(".btn-ignore-rule");
|
|
855
|
+
if (ignoreBtn) {
|
|
856
|
+
const ruleId = ignoreBtn.dataset.ignoreRule;
|
|
857
|
+
if (ruleId) {
|
|
858
|
+
addIgnore(ruleId);
|
|
859
|
+
void this._runScan();
|
|
860
|
+
}
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const removeIgnoreBtn = target.closest(".btn-remove-ignore");
|
|
864
|
+
if (removeIgnoreBtn) {
|
|
865
|
+
const ruleId = removeIgnoreBtn.dataset.removeRule;
|
|
866
|
+
const selector = removeIgnoreBtn.dataset.removeSelector || void 0;
|
|
867
|
+
if (ruleId) {
|
|
868
|
+
removeIgnore(ruleId, selector);
|
|
869
|
+
void this._runScan();
|
|
870
|
+
}
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (target.closest(".btn-export-ignores")) {
|
|
874
|
+
this._exportIgnoresJson();
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (target.closest(".btn-import-ignores")) {
|
|
878
|
+
this._importIgnoresJson();
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (target.closest(".btn-clear-ignores")) {
|
|
882
|
+
clearIgnores();
|
|
883
|
+
void this._runScan();
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
const ignoredToggle = target.closest(".ignored-section-toggle");
|
|
887
|
+
if (ignoredToggle) {
|
|
888
|
+
this._ignoredSectionOpen = !this._ignoredSectionOpen;
|
|
889
|
+
ignoredToggle.setAttribute("aria-expanded", String(this._ignoredSectionOpen));
|
|
890
|
+
const bodyId = ignoredToggle.getAttribute("aria-controls");
|
|
891
|
+
const sectionBody = bodyId ? this._shadow.getElementById(bodyId) : null;
|
|
892
|
+
if (sectionBody) {
|
|
893
|
+
sectionBody.toggleAttribute("data-open", this._ignoredSectionOpen);
|
|
894
|
+
}
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
570
897
|
const chip = target.closest(".filter-chip");
|
|
571
898
|
if (chip) {
|
|
572
899
|
const severity = chip.dataset.severity;
|
|
573
900
|
const level = chip.dataset.level;
|
|
574
901
|
if (severity && isSeverity(severity)) {
|
|
575
902
|
const active = this._activeSeverities.has(severity);
|
|
576
|
-
if (active
|
|
903
|
+
if (active) {
|
|
577
904
|
this._activeSeverities.delete(severity);
|
|
578
|
-
|
|
579
|
-
} else if (!active) {
|
|
905
|
+
} else {
|
|
580
906
|
this._activeSeverities.add(severity);
|
|
581
|
-
chip.setAttribute("aria-pressed", "true");
|
|
582
907
|
}
|
|
908
|
+
chip.setAttribute("aria-pressed", String(!active));
|
|
583
909
|
this._refreshBody();
|
|
584
910
|
} else if (level) {
|
|
585
911
|
const active = this._activeLevels.has(level);
|
|
586
|
-
if (active
|
|
912
|
+
if (active) {
|
|
587
913
|
this._activeLevels.delete(level);
|
|
588
|
-
|
|
589
|
-
} else if (!active) {
|
|
914
|
+
} else {
|
|
590
915
|
this._activeLevels.add(level);
|
|
591
|
-
chip.setAttribute("aria-pressed", "true");
|
|
592
916
|
}
|
|
917
|
+
chip.setAttribute("aria-pressed", String(!active));
|
|
593
918
|
this._refreshBody();
|
|
594
919
|
} else if (chip.dataset.ruleset) {
|
|
595
920
|
const ruleset = chip.dataset.ruleset;
|
|
@@ -601,6 +926,7 @@ ${themes_default}`;
|
|
|
601
926
|
this._runOnly = [...this._runOnly, ruleset];
|
|
602
927
|
chip.setAttribute("aria-pressed", "true");
|
|
603
928
|
}
|
|
929
|
+
this._updateFilterToggle();
|
|
604
930
|
void this._runScan();
|
|
605
931
|
}
|
|
606
932
|
}
|
|
@@ -646,6 +972,7 @@ ${themes_default}`;
|
|
|
646
972
|
fabCountEl.textContent = String(total);
|
|
647
973
|
fabCountEl.setAttribute("data-count", String(total));
|
|
648
974
|
}
|
|
975
|
+
this._updateFilterToggle();
|
|
649
976
|
}
|
|
650
977
|
_formatViolationsAsMarkdown(violations) {
|
|
651
978
|
const header = `# a11y-hud scan results
|
|
@@ -694,6 +1021,155 @@ ${themes_default}`;
|
|
|
694
1021
|
if (!violation) return;
|
|
695
1022
|
await this._copyToClipboard(this._formatViolationsAsMarkdown([violation]));
|
|
696
1023
|
}
|
|
1024
|
+
_hasActiveFilters() {
|
|
1025
|
+
return this._activeSeverities.size > 0 || this._activeLevels.size > 0 || this._runOnly.length > 0;
|
|
1026
|
+
}
|
|
1027
|
+
_updateFilterToggle() {
|
|
1028
|
+
const btn = this._shadow.querySelector(".btn-panel-title");
|
|
1029
|
+
if (!btn) return;
|
|
1030
|
+
btn.setAttribute("aria-expanded", String(this._filtersOpen));
|
|
1031
|
+
if (this._hasActiveFilters()) {
|
|
1032
|
+
btn.setAttribute("data-active", "");
|
|
1033
|
+
} else {
|
|
1034
|
+
btn.removeAttribute("data-active");
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
_toggleFilters() {
|
|
1038
|
+
this._filtersOpen = !this._filtersOpen;
|
|
1039
|
+
const filters = this._shadow.getElementById("panel-filters");
|
|
1040
|
+
filters?.toggleAttribute("data-open", this._filtersOpen);
|
|
1041
|
+
this._updateFilterToggle();
|
|
1042
|
+
}
|
|
1043
|
+
_toggleKeyboardMode() {
|
|
1044
|
+
this._keyboardMode = !this._keyboardMode;
|
|
1045
|
+
const btn = this._shadow.querySelector("#btn-keyboard");
|
|
1046
|
+
if (btn) btn.setAttribute("aria-pressed", String(this._keyboardMode));
|
|
1047
|
+
this._shadow.querySelector(".panel")?.toggleAttribute("data-kbd-mode", this._keyboardMode);
|
|
1048
|
+
if (this._keyboardMode) {
|
|
1049
|
+
this._activateKeyboardMode();
|
|
1050
|
+
} else {
|
|
1051
|
+
this._deactivateKeyboardMode();
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
_activateKeyboardMode() {
|
|
1055
|
+
const scope = this._getScopeTarget();
|
|
1056
|
+
this._kbElements = getFocusableElements(scope);
|
|
1057
|
+
const violations = detectKeyboardViolations(this._kbElements, scope);
|
|
1058
|
+
this._keyboardCleanup = injectFocusOrderOverlay(this._kbElements);
|
|
1059
|
+
const body = this._shadow.querySelector(".panel-body");
|
|
1060
|
+
if (body) body.innerHTML = this._renderKeyboardView(this._kbElements, violations);
|
|
1061
|
+
}
|
|
1062
|
+
_deactivateKeyboardMode() {
|
|
1063
|
+
this._keyboardCleanup?.();
|
|
1064
|
+
this._keyboardCleanup = void 0;
|
|
1065
|
+
this._kbElements = [];
|
|
1066
|
+
this._removeHighlight?.();
|
|
1067
|
+
this._removeHighlight = void 0;
|
|
1068
|
+
const body = this._shadow.querySelector(".panel-body");
|
|
1069
|
+
if (body) {
|
|
1070
|
+
body.innerHTML = this._renderBody(this._getFilteredViolations());
|
|
1071
|
+
this._bindHighlightEvents();
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
_renderKeyboardView(elements, violations) {
|
|
1075
|
+
const elementItems = elements.map(
|
|
1076
|
+
(info) => `
|
|
1077
|
+
<li class="kbd-element-item">
|
|
1078
|
+
<button class="btn-kbd-element" data-kbd-element="${info.index}" aria-label="Highlight element ${info.index}: ${escapeHtml(info.selector)}">
|
|
1079
|
+
<span class="kbd-element-index" aria-hidden="true">${info.index}</span>
|
|
1080
|
+
<code class="kbd-element-selector">${escapeHtml(info.selector)}</code>
|
|
1081
|
+
<span class="kbd-element-tag"><${info.element.tagName.toLowerCase()}></span>
|
|
1082
|
+
${info.tabIndex > 0 ? `<span class="kbd-tabindex-badge">tabindex=${info.tabIndex}</span>` : ""}
|
|
1083
|
+
</button>
|
|
1084
|
+
</li>`
|
|
1085
|
+
).join("");
|
|
1086
|
+
const violationItems = violations.map(
|
|
1087
|
+
(v) => `
|
|
1088
|
+
<li class="kbd-violation-item">
|
|
1089
|
+
<span class="severity-icon" data-severity="serious" aria-hidden="true">${icon("alert-circle")}</span>
|
|
1090
|
+
<span class="kbd-violation-msg">${escapeHtml(v.message)}</span>
|
|
1091
|
+
</li>`
|
|
1092
|
+
).join("");
|
|
1093
|
+
return `
|
|
1094
|
+
<div class="kbd-mode-view">
|
|
1095
|
+
<div class="kbd-mode-header">
|
|
1096
|
+
<span class="kbd-mode-stat">
|
|
1097
|
+
<span aria-hidden="true">${icon("keyboard")}</span>
|
|
1098
|
+
${elements.length} focusable element${elements.length !== 1 ? "s" : ""}
|
|
1099
|
+
</span>
|
|
1100
|
+
${violations.length > 0 ? `<span class="kbd-mode-stat kbd-mode-stat--warn">
|
|
1101
|
+
<span aria-hidden="true">${icon("alert-circle")}</span>
|
|
1102
|
+
${violations.length} issue${violations.length !== 1 ? "s" : ""}
|
|
1103
|
+
</span>` : `<span class="kbd-mode-stat kbd-mode-stat--ok">
|
|
1104
|
+
<span aria-hidden="true">${icon("check-circle")}</span>
|
|
1105
|
+
No issues
|
|
1106
|
+
</span>`}
|
|
1107
|
+
</div>
|
|
1108
|
+
${violations.length > 0 ? `<ul class="kbd-violation-list" aria-label="Keyboard issues">${violationItems}</ul>` : ""}
|
|
1109
|
+
${elements.length > 0 ? `<ul class="kbd-element-list" aria-label="Focusable elements in tab order">${elementItems}</ul>` : `<p class="kbd-empty">No focusable elements found in the scoped area.</p>`}
|
|
1110
|
+
</div>`;
|
|
1111
|
+
}
|
|
1112
|
+
_exportIgnoresJson() {
|
|
1113
|
+
const json = exportIgnores();
|
|
1114
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
1115
|
+
const url = URL.createObjectURL(blob);
|
|
1116
|
+
const a = document.createElement("a");
|
|
1117
|
+
a.href = url;
|
|
1118
|
+
a.download = "a11y-hud-ignores.json";
|
|
1119
|
+
a.click();
|
|
1120
|
+
URL.revokeObjectURL(url);
|
|
1121
|
+
}
|
|
1122
|
+
_importIgnoresJson() {
|
|
1123
|
+
const input = document.createElement("input");
|
|
1124
|
+
input.type = "file";
|
|
1125
|
+
input.accept = ".json,application/json";
|
|
1126
|
+
input.onchange = () => {
|
|
1127
|
+
const file = input.files?.[0];
|
|
1128
|
+
if (!file) return;
|
|
1129
|
+
const reader = new FileReader();
|
|
1130
|
+
reader.onload = (evt) => {
|
|
1131
|
+
importIgnores(evt.target?.result ?? "");
|
|
1132
|
+
void this._runScan();
|
|
1133
|
+
};
|
|
1134
|
+
reader.readAsText(file);
|
|
1135
|
+
};
|
|
1136
|
+
input.click();
|
|
1137
|
+
}
|
|
1138
|
+
_getScopeString() {
|
|
1139
|
+
if (this._scopeSelector) return this._scopeSelector;
|
|
1140
|
+
if (this._scopeElement) {
|
|
1141
|
+
const el = this._scopeElement;
|
|
1142
|
+
if (el.id) return `#${el.id}`;
|
|
1143
|
+
return el.tagName.toLowerCase();
|
|
1144
|
+
}
|
|
1145
|
+
return "document.body";
|
|
1146
|
+
}
|
|
1147
|
+
_buildExport() {
|
|
1148
|
+
if (!this._results) return null;
|
|
1149
|
+
return {
|
|
1150
|
+
version: "1",
|
|
1151
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1152
|
+
url: location.href,
|
|
1153
|
+
scope: this._getScopeString(),
|
|
1154
|
+
results: this._results
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
_exportJson() {
|
|
1158
|
+
const data = this._buildExport();
|
|
1159
|
+
if (!data) return;
|
|
1160
|
+
const json = JSON.stringify(data, null, 2);
|
|
1161
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
1162
|
+
const url = URL.createObjectURL(blob);
|
|
1163
|
+
const a = document.createElement("a");
|
|
1164
|
+
a.href = url;
|
|
1165
|
+
a.download = "a11y-hud-results.json";
|
|
1166
|
+
a.click();
|
|
1167
|
+
URL.revokeObjectURL(url);
|
|
1168
|
+
}
|
|
1169
|
+
exportResults() {
|
|
1170
|
+
const data = this._buildExport();
|
|
1171
|
+
return data ? JSON.stringify(data, null, 2) : null;
|
|
1172
|
+
}
|
|
697
1173
|
_highlightNode(violationIndex, nodeIndex) {
|
|
698
1174
|
this._removeHighlight?.();
|
|
699
1175
|
this._removeHighlight = void 0;
|
|
@@ -749,12 +1225,49 @@ function mount(options = {}) {
|
|
|
749
1225
|
},
|
|
750
1226
|
async runScan() {
|
|
751
1227
|
return el.runScan();
|
|
1228
|
+
},
|
|
1229
|
+
exportResults() {
|
|
1230
|
+
return el.exportResults();
|
|
1231
|
+
},
|
|
1232
|
+
ignores: {
|
|
1233
|
+
add(ruleId, selector) {
|
|
1234
|
+
addIgnore(ruleId, selector);
|
|
1235
|
+
void el.runScan();
|
|
1236
|
+
},
|
|
1237
|
+
remove(ruleId, selector) {
|
|
1238
|
+
removeIgnore(ruleId, selector);
|
|
1239
|
+
void el.runScan();
|
|
1240
|
+
},
|
|
1241
|
+
clear() {
|
|
1242
|
+
clearIgnores();
|
|
1243
|
+
void el.runScan();
|
|
1244
|
+
},
|
|
1245
|
+
list() {
|
|
1246
|
+
return listIgnores();
|
|
1247
|
+
},
|
|
1248
|
+
exportJson() {
|
|
1249
|
+
return exportIgnores();
|
|
1250
|
+
},
|
|
1251
|
+
importJson(json) {
|
|
1252
|
+
importIgnores(json);
|
|
1253
|
+
void el.runScan();
|
|
1254
|
+
}
|
|
752
1255
|
}
|
|
753
1256
|
};
|
|
754
1257
|
}
|
|
755
1258
|
|
|
756
1259
|
exports.A11yHudElement = A11yHudElement;
|
|
1260
|
+
exports.addIgnore = addIgnore;
|
|
1261
|
+
exports.clearIgnores = clearIgnores;
|
|
1262
|
+
exports.detectKeyboardViolations = detectKeyboardViolations;
|
|
1263
|
+
exports.exportIgnores = exportIgnores;
|
|
1264
|
+
exports.generateBookmarklet = generateBookmarklet;
|
|
1265
|
+
exports.getFocusableElements = getFocusableElements;
|
|
1266
|
+
exports.importIgnores = importIgnores;
|
|
1267
|
+
exports.injectFocusOrderOverlay = injectFocusOrderOverlay;
|
|
1268
|
+
exports.listIgnores = listIgnores;
|
|
757
1269
|
exports.mount = mount;
|
|
1270
|
+
exports.removeIgnore = removeIgnore;
|
|
758
1271
|
exports.runScan = runScan;
|
|
759
1272
|
//# sourceMappingURL=index.cjs.map
|
|
760
1273
|
//# sourceMappingURL=index.cjs.map
|