@accesslint/storybook-addon 0.6.5 → 0.6.8
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/manager.js +37 -41
- package/dist/preview.cjs +50 -48
- package/dist/preview.d.cts +8 -2
- package/dist/preview.d.ts +8 -2
- package/dist/preview.js +50 -48
- package/dist/vitest-plugin.cjs +24 -0
- package/dist/vitest-plugin.d.cts +19 -0
- package/dist/vitest-plugin.d.ts +19 -0
- package/dist/vitest-plugin.js +21 -0
- package/dist/vitest-setup.cjs +74 -0
- package/dist/vitest-setup.js +72 -0
- package/package.json +9 -2
package/dist/manager.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import React, { useMemo, useState, useRef,
|
|
2
|
-
import { addons, types,
|
|
1
|
+
import React, { useMemo, useState, useRef, useCallback } from 'react';
|
|
2
|
+
import { addons, types, useChannel } from 'storybook/internal/manager-api';
|
|
3
|
+
import { STORY_CHANGED, STORY_FINISHED } from 'storybook/internal/core-events';
|
|
3
4
|
import { useTheme } from 'storybook/internal/theming';
|
|
4
|
-
import { AddonPanel } from 'storybook/internal/components';
|
|
5
5
|
|
|
6
6
|
// src/manager.tsx
|
|
7
7
|
|
|
8
8
|
// src/constants.ts
|
|
9
9
|
var ADDON_ID = "accesslint/a11y";
|
|
10
|
-
var
|
|
10
|
+
var PARAM_KEY = "accesslint";
|
|
11
11
|
var IMPACT_COLOR = {
|
|
12
12
|
critical: "#d32f2f",
|
|
13
13
|
serious: "#d32f2f",
|
|
@@ -31,8 +31,7 @@ var LEVEL_COLOR = {
|
|
|
31
31
|
AA: "#1565c0",
|
|
32
32
|
AAA: "#6a1b9a"
|
|
33
33
|
};
|
|
34
|
-
var
|
|
35
|
-
var Panel = ({ active, ...rest }) => {
|
|
34
|
+
var Panel = ({ active }) => {
|
|
36
35
|
const theme = useTheme();
|
|
37
36
|
const isDark = theme.base === "dark";
|
|
38
37
|
const colors = useMemo(() => ({
|
|
@@ -48,41 +47,29 @@ var Panel = ({ active, ...rest }) => {
|
|
|
48
47
|
tagText: isDark ? "#ccc" : "#616161",
|
|
49
48
|
ruleId: isDark ? "#64b5f6" : "#1565c0"
|
|
50
49
|
}), [isDark, theme]);
|
|
51
|
-
const [violations, setViolations] =
|
|
52
|
-
|
|
53
|
-
[]
|
|
54
|
-
);
|
|
55
|
-
const [meta, setMeta] = useState(null);
|
|
50
|
+
const [violations, setViolations] = useState([]);
|
|
51
|
+
const [ruleCount, setRuleCount] = useState(0);
|
|
56
52
|
const [expandedIndex, setExpandedIndex] = useState(null);
|
|
57
53
|
const buttonRefs = useRef([]);
|
|
58
|
-
|
|
59
|
-
[
|
|
60
|
-
|
|
54
|
+
useChannel({
|
|
55
|
+
[STORY_FINISHED]: ({ reporters }) => {
|
|
56
|
+
const report = reporters.find((r) => r.type === "accesslint");
|
|
57
|
+
if (!report) return;
|
|
58
|
+
const result = report.result;
|
|
59
|
+
setViolations(result.violations ?? []);
|
|
60
|
+
setRuleCount(result.ruleCount ?? 0);
|
|
61
61
|
setExpandedIndex(null);
|
|
62
62
|
},
|
|
63
|
-
[
|
|
64
|
-
|
|
63
|
+
[STORY_CHANGED]: () => {
|
|
64
|
+
setViolations([]);
|
|
65
|
+
setRuleCount(0);
|
|
66
|
+
setExpandedIndex(null);
|
|
65
67
|
}
|
|
66
68
|
});
|
|
67
|
-
const sorted =
|
|
68
|
-
(a, b) => (IMPACT_ORDER[a.impact] ?? 4) - (IMPACT_ORDER[b.impact] ?? 4)
|
|
69
|
+
const sorted = useMemo(
|
|
70
|
+
() => [...violations].sort((a, b) => (IMPACT_ORDER[a.impact] ?? 4) - (IMPACT_ORDER[b.impact] ?? 4)),
|
|
71
|
+
[violations]
|
|
69
72
|
);
|
|
70
|
-
const expanded = expandedIndex !== null ? sorted[expandedIndex] : null;
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
if (expanded?.selector) {
|
|
73
|
-
const local = expanded.selector.replace(/^.*>>>\s*iframe>\s*/, "");
|
|
74
|
-
emit("storybook/highlight/add", {
|
|
75
|
-
id: HIGHLIGHT_ID,
|
|
76
|
-
selectors: [local],
|
|
77
|
-
styles: {
|
|
78
|
-
outline: `2px solid ${IMPACT_COLOR[expanded.impact] || "#1565c0"}`,
|
|
79
|
-
outlineOffset: "2px"
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
} else {
|
|
83
|
-
emit("storybook/highlight/remove", { id: HIGHLIGHT_ID });
|
|
84
|
-
}
|
|
85
|
-
}, [expandedIndex]);
|
|
86
73
|
const handleKeyDown = useCallback((e, index) => {
|
|
87
74
|
let next = null;
|
|
88
75
|
switch (e.key) {
|
|
@@ -105,7 +92,8 @@ var Panel = ({ active, ...rest }) => {
|
|
|
105
92
|
buttonRefs.current[next]?.focus();
|
|
106
93
|
}, [sorted.length]);
|
|
107
94
|
if (!active) return null;
|
|
108
|
-
|
|
95
|
+
const passed = ruleCount - new Set(violations.map((v) => v.ruleId)).size;
|
|
96
|
+
return /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", height: "100%", fontFamily: "system-ui, sans-serif" } }, ruleCount > 0 && /* @__PURE__ */ React.createElement("div", { style: {
|
|
109
97
|
display: "flex",
|
|
110
98
|
gap: "12px",
|
|
111
99
|
padding: "8px 12px",
|
|
@@ -113,7 +101,7 @@ var Panel = ({ active, ...rest }) => {
|
|
|
113
101
|
color: colors.textMuted,
|
|
114
102
|
borderBottom: `1px solid ${colors.border}`,
|
|
115
103
|
flexShrink: 0
|
|
116
|
-
} }, /* @__PURE__ */ React.createElement("span", null,
|
|
104
|
+
} }, /* @__PURE__ */ React.createElement("span", null, ruleCount, " rules"), /* @__PURE__ */ React.createElement("span", { style: { color: "#2e7d32" } }, passed, " passed"), /* @__PURE__ */ React.createElement("span", { style: { color: violations.length > 0 ? "#d32f2f" : colors.textMuted } }, new Set(violations.map((v) => v.ruleId)).size, " failed")), violations.length === 0 ? /* @__PURE__ */ React.createElement("p", { style: { padding: "12px", margin: 0, fontSize: "13px", color: colors.textMuted } }, "No accessibility violations found.") : /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", minHeight: 0 } }, /* @__PURE__ */ React.createElement(
|
|
117
105
|
"ul",
|
|
118
106
|
{
|
|
119
107
|
style: { listStyle: "none", padding: 0, margin: 0 },
|
|
@@ -200,13 +188,20 @@ var Panel = ({ active, ...rest }) => {
|
|
|
200
188
|
v.html
|
|
201
189
|
))));
|
|
202
190
|
})
|
|
203
|
-
)))
|
|
191
|
+
)));
|
|
204
192
|
};
|
|
205
193
|
|
|
206
194
|
// src/manager.tsx
|
|
195
|
+
var PANEL_ID = `${ADDON_ID}/panel`;
|
|
207
196
|
var Title = () => {
|
|
208
|
-
const [
|
|
209
|
-
|
|
197
|
+
const [count, setCount] = React.useState(0);
|
|
198
|
+
useChannel({
|
|
199
|
+
[STORY_FINISHED]: ({ reporters }) => {
|
|
200
|
+
const report = reporters.find((r) => r.type === "accesslint");
|
|
201
|
+
const violations = report?.result?.violations;
|
|
202
|
+
setCount(violations?.length ?? 0);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
210
205
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, "AccessLint", count > 0 && /* @__PURE__ */ React.createElement("span", { style: {
|
|
211
206
|
display: "inline-block",
|
|
212
207
|
marginLeft: "8px",
|
|
@@ -223,8 +218,9 @@ var Title = () => {
|
|
|
223
218
|
};
|
|
224
219
|
addons.register(ADDON_ID, () => {
|
|
225
220
|
addons.add(PANEL_ID, {
|
|
226
|
-
type: types.PANEL,
|
|
227
221
|
title: Title,
|
|
228
|
-
|
|
222
|
+
type: types.PANEL,
|
|
223
|
+
render: Panel,
|
|
224
|
+
paramKey: PARAM_KEY
|
|
229
225
|
});
|
|
230
226
|
});
|
package/dist/preview.cjs
CHANGED
|
@@ -1,58 +1,60 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var previewApi = require('storybook/internal/preview-api');
|
|
4
3
|
var core = require('@accesslint/core');
|
|
5
4
|
|
|
6
|
-
// src/preview.ts
|
|
7
|
-
|
|
8
|
-
// src/constants.ts
|
|
9
|
-
var ADDON_ID = "accesslint/a11y";
|
|
10
|
-
|
|
11
5
|
// src/preview.ts
|
|
12
6
|
core.configureRules({
|
|
13
7
|
disabledRules: ["accesslint-045"]
|
|
14
8
|
});
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
9
|
+
function scopeViolations(violations) {
|
|
10
|
+
const root = document.getElementById("storybook-root");
|
|
11
|
+
if (!root) return violations;
|
|
12
|
+
return violations.filter((v) => {
|
|
13
|
+
const local = v.selector.replace(/^.*>>>\s*iframe>\s*/, "");
|
|
14
|
+
try {
|
|
15
|
+
const el = document.querySelector(local);
|
|
16
|
+
return el && root.contains(el);
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function enrichViolations(violations) {
|
|
23
|
+
return violations.map((v) => {
|
|
24
|
+
const rule = core.getRuleById(v.ruleId);
|
|
25
|
+
return {
|
|
26
|
+
...v,
|
|
27
|
+
element: void 0,
|
|
28
|
+
// not serializable
|
|
29
|
+
description: rule?.description,
|
|
30
|
+
wcag: rule?.wcag,
|
|
31
|
+
level: rule?.level,
|
|
32
|
+
guidance: rule?.guidance
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
var afterEach = async ({
|
|
37
|
+
reporting,
|
|
38
|
+
parameters,
|
|
39
|
+
viewMode
|
|
40
|
+
}) => {
|
|
41
|
+
const accesslintParam = parameters?.accesslint;
|
|
42
|
+
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
43
|
+
if (viewMode !== "story") return;
|
|
44
|
+
const result = core.runAudit(document);
|
|
45
|
+
const scoped = scopeViolations(result.violations);
|
|
46
|
+
const enriched = enrichViolations(scoped);
|
|
47
|
+
const hasViolations = enriched.length > 0;
|
|
48
|
+
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
49
|
+
reporting.addReport({
|
|
50
|
+
type: "accesslint",
|
|
51
|
+
version: 1,
|
|
52
|
+
result: {
|
|
53
|
+
violations: enriched,
|
|
54
|
+
ruleCount: result.ruleCount
|
|
55
|
+
},
|
|
56
|
+
status: hasViolations ? mode : "passed"
|
|
57
|
+
});
|
|
55
58
|
};
|
|
56
|
-
var decorators = [decorator];
|
|
57
59
|
|
|
58
|
-
exports.
|
|
60
|
+
exports.afterEach = afterEach;
|
package/dist/preview.d.cts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
declare const
|
|
1
|
+
declare const afterEach: ({ reporting, parameters, viewMode, }: {
|
|
2
|
+
reporting: {
|
|
3
|
+
addReport: (report: Record<string, unknown>) => void;
|
|
4
|
+
};
|
|
5
|
+
parameters: Record<string, unknown>;
|
|
6
|
+
viewMode: string;
|
|
7
|
+
}) => Promise<void>;
|
|
2
8
|
|
|
3
|
-
export {
|
|
9
|
+
export { afterEach };
|
package/dist/preview.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
declare const
|
|
1
|
+
declare const afterEach: ({ reporting, parameters, viewMode, }: {
|
|
2
|
+
reporting: {
|
|
3
|
+
addReport: (report: Record<string, unknown>) => void;
|
|
4
|
+
};
|
|
5
|
+
parameters: Record<string, unknown>;
|
|
6
|
+
viewMode: string;
|
|
7
|
+
}) => Promise<void>;
|
|
2
8
|
|
|
3
|
-
export {
|
|
9
|
+
export { afterEach };
|
package/dist/preview.js
CHANGED
|
@@ -1,56 +1,58 @@
|
|
|
1
|
-
import { addons } from 'storybook/internal/preview-api';
|
|
2
1
|
import { configureRules, runAudit, getRuleById } from '@accesslint/core';
|
|
3
2
|
|
|
4
|
-
// src/preview.ts
|
|
5
|
-
|
|
6
|
-
// src/constants.ts
|
|
7
|
-
var ADDON_ID = "accesslint/a11y";
|
|
8
|
-
|
|
9
3
|
// src/preview.ts
|
|
10
4
|
configureRules({
|
|
11
5
|
disabledRules: ["accesslint-045"]
|
|
12
6
|
});
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
7
|
+
function scopeViolations(violations) {
|
|
8
|
+
const root = document.getElementById("storybook-root");
|
|
9
|
+
if (!root) return violations;
|
|
10
|
+
return violations.filter((v) => {
|
|
11
|
+
const local = v.selector.replace(/^.*>>>\s*iframe>\s*/, "");
|
|
12
|
+
try {
|
|
13
|
+
const el = document.querySelector(local);
|
|
14
|
+
return el && root.contains(el);
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function enrichViolations(violations) {
|
|
21
|
+
return violations.map((v) => {
|
|
22
|
+
const rule = getRuleById(v.ruleId);
|
|
23
|
+
return {
|
|
24
|
+
...v,
|
|
25
|
+
element: void 0,
|
|
26
|
+
// not serializable
|
|
27
|
+
description: rule?.description,
|
|
28
|
+
wcag: rule?.wcag,
|
|
29
|
+
level: rule?.level,
|
|
30
|
+
guidance: rule?.guidance
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
var afterEach = async ({
|
|
35
|
+
reporting,
|
|
36
|
+
parameters,
|
|
37
|
+
viewMode
|
|
38
|
+
}) => {
|
|
39
|
+
const accesslintParam = parameters?.accesslint;
|
|
40
|
+
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
41
|
+
if (viewMode !== "story") return;
|
|
42
|
+
const result = runAudit(document);
|
|
43
|
+
const scoped = scopeViolations(result.violations);
|
|
44
|
+
const enriched = enrichViolations(scoped);
|
|
45
|
+
const hasViolations = enriched.length > 0;
|
|
46
|
+
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
47
|
+
reporting.addReport({
|
|
48
|
+
type: "accesslint",
|
|
49
|
+
version: 1,
|
|
50
|
+
result: {
|
|
51
|
+
violations: enriched,
|
|
52
|
+
ruleCount: result.ruleCount
|
|
53
|
+
},
|
|
54
|
+
status: hasViolations ? mode : "passed"
|
|
55
|
+
});
|
|
53
56
|
};
|
|
54
|
-
var decorators = [decorator];
|
|
55
57
|
|
|
56
|
-
export {
|
|
58
|
+
export { afterEach };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
4
|
+
// src/vitest-plugin.ts
|
|
5
|
+
function accesslintTest() {
|
|
6
|
+
const distDir = new URL(".", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vitest-plugin.cjs', document.baseURI).href))).pathname;
|
|
7
|
+
return {
|
|
8
|
+
name: "@accesslint/storybook-addon",
|
|
9
|
+
config() {
|
|
10
|
+
return {
|
|
11
|
+
server: {
|
|
12
|
+
fs: {
|
|
13
|
+
allow: [distDir]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
test: {
|
|
17
|
+
setupFiles: ["@accesslint/storybook-addon/vitest-setup"]
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
exports.accesslintTest = accesslintTest;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest plugin that automatically registers AccessLint's afterEach annotation
|
|
3
|
+
* so that running component tests produces per-story accessibility badges.
|
|
4
|
+
*
|
|
5
|
+
* Usage in vitest.config.ts (or the storybook vitest workspace):
|
|
6
|
+
*
|
|
7
|
+
* import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
|
|
8
|
+
* import { accesslintTest } from "@accesslint/storybook-addon/vitest-plugin";
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({
|
|
11
|
+
* plugins: [storybookTest(), accesslintTest()],
|
|
12
|
+
* });
|
|
13
|
+
*/
|
|
14
|
+
declare function accesslintTest(): {
|
|
15
|
+
name: string;
|
|
16
|
+
config: () => Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { accesslintTest };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest plugin that automatically registers AccessLint's afterEach annotation
|
|
3
|
+
* so that running component tests produces per-story accessibility badges.
|
|
4
|
+
*
|
|
5
|
+
* Usage in vitest.config.ts (or the storybook vitest workspace):
|
|
6
|
+
*
|
|
7
|
+
* import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
|
|
8
|
+
* import { accesslintTest } from "@accesslint/storybook-addon/vitest-plugin";
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({
|
|
11
|
+
* plugins: [storybookTest(), accesslintTest()],
|
|
12
|
+
* });
|
|
13
|
+
*/
|
|
14
|
+
declare function accesslintTest(): {
|
|
15
|
+
name: string;
|
|
16
|
+
config: () => Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { accesslintTest };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/vitest-plugin.ts
|
|
2
|
+
function accesslintTest() {
|
|
3
|
+
const distDir = new URL(".", import.meta.url).pathname;
|
|
4
|
+
return {
|
|
5
|
+
name: "@accesslint/storybook-addon",
|
|
6
|
+
config() {
|
|
7
|
+
return {
|
|
8
|
+
server: {
|
|
9
|
+
fs: {
|
|
10
|
+
allow: [distDir]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
test: {
|
|
14
|
+
setupFiles: ["@accesslint/storybook-addon/vitest-setup"]
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { accesslintTest };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var previewApi = require('storybook/preview-api');
|
|
4
|
+
var core = require('@accesslint/core');
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/preview.ts
|
|
13
|
+
var preview_exports = {};
|
|
14
|
+
__export(preview_exports, {
|
|
15
|
+
afterEach: () => afterEach
|
|
16
|
+
});
|
|
17
|
+
core.configureRules({
|
|
18
|
+
disabledRules: ["accesslint-045"]
|
|
19
|
+
});
|
|
20
|
+
function scopeViolations(violations) {
|
|
21
|
+
const root = document.getElementById("storybook-root");
|
|
22
|
+
if (!root) return violations;
|
|
23
|
+
return violations.filter((v) => {
|
|
24
|
+
const local = v.selector.replace(/^.*>>>\s*iframe>\s*/, "");
|
|
25
|
+
try {
|
|
26
|
+
const el = document.querySelector(local);
|
|
27
|
+
return el && root.contains(el);
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function enrichViolations(violations) {
|
|
34
|
+
return violations.map((v) => {
|
|
35
|
+
const rule = core.getRuleById(v.ruleId);
|
|
36
|
+
return {
|
|
37
|
+
...v,
|
|
38
|
+
element: void 0,
|
|
39
|
+
// not serializable
|
|
40
|
+
description: rule?.description,
|
|
41
|
+
wcag: rule?.wcag,
|
|
42
|
+
level: rule?.level,
|
|
43
|
+
guidance: rule?.guidance
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
var afterEach = async ({
|
|
48
|
+
reporting,
|
|
49
|
+
parameters,
|
|
50
|
+
viewMode
|
|
51
|
+
}) => {
|
|
52
|
+
const accesslintParam = parameters?.accesslint;
|
|
53
|
+
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
54
|
+
if (viewMode !== "story") return;
|
|
55
|
+
const result = core.runAudit(document);
|
|
56
|
+
const scoped = scopeViolations(result.violations);
|
|
57
|
+
const enriched = enrichViolations(scoped);
|
|
58
|
+
const hasViolations = enriched.length > 0;
|
|
59
|
+
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
60
|
+
reporting.addReport({
|
|
61
|
+
type: "accesslint",
|
|
62
|
+
version: 1,
|
|
63
|
+
result: {
|
|
64
|
+
violations: enriched,
|
|
65
|
+
ruleCount: result.ruleCount
|
|
66
|
+
},
|
|
67
|
+
status: hasViolations ? mode : "passed"
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/vitest-setup.ts
|
|
72
|
+
var g = globalThis;
|
|
73
|
+
var existing = g.globalProjectAnnotations;
|
|
74
|
+
g.globalProjectAnnotations = existing ? previewApi.composeConfigs([existing, preview_exports]) : previewApi.composeConfigs([preview_exports]);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { composeConfigs } from 'storybook/preview-api';
|
|
2
|
+
import { configureRules, runAudit, getRuleById } from '@accesslint/core';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/preview.ts
|
|
11
|
+
var preview_exports = {};
|
|
12
|
+
__export(preview_exports, {
|
|
13
|
+
afterEach: () => afterEach
|
|
14
|
+
});
|
|
15
|
+
configureRules({
|
|
16
|
+
disabledRules: ["accesslint-045"]
|
|
17
|
+
});
|
|
18
|
+
function scopeViolations(violations) {
|
|
19
|
+
const root = document.getElementById("storybook-root");
|
|
20
|
+
if (!root) return violations;
|
|
21
|
+
return violations.filter((v) => {
|
|
22
|
+
const local = v.selector.replace(/^.*>>>\s*iframe>\s*/, "");
|
|
23
|
+
try {
|
|
24
|
+
const el = document.querySelector(local);
|
|
25
|
+
return el && root.contains(el);
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function enrichViolations(violations) {
|
|
32
|
+
return violations.map((v) => {
|
|
33
|
+
const rule = getRuleById(v.ruleId);
|
|
34
|
+
return {
|
|
35
|
+
...v,
|
|
36
|
+
element: void 0,
|
|
37
|
+
// not serializable
|
|
38
|
+
description: rule?.description,
|
|
39
|
+
wcag: rule?.wcag,
|
|
40
|
+
level: rule?.level,
|
|
41
|
+
guidance: rule?.guidance
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
var afterEach = async ({
|
|
46
|
+
reporting,
|
|
47
|
+
parameters,
|
|
48
|
+
viewMode
|
|
49
|
+
}) => {
|
|
50
|
+
const accesslintParam = parameters?.accesslint;
|
|
51
|
+
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
52
|
+
if (viewMode !== "story") return;
|
|
53
|
+
const result = runAudit(document);
|
|
54
|
+
const scoped = scopeViolations(result.violations);
|
|
55
|
+
const enriched = enrichViolations(scoped);
|
|
56
|
+
const hasViolations = enriched.length > 0;
|
|
57
|
+
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
58
|
+
reporting.addReport({
|
|
59
|
+
type: "accesslint",
|
|
60
|
+
version: 1,
|
|
61
|
+
result: {
|
|
62
|
+
violations: enriched,
|
|
63
|
+
ruleCount: result.ruleCount
|
|
64
|
+
},
|
|
65
|
+
status: hasViolations ? mode : "passed"
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// src/vitest-setup.ts
|
|
70
|
+
var g = globalThis;
|
|
71
|
+
var existing = g.globalProjectAnnotations;
|
|
72
|
+
g.globalProjectAnnotations = existing ? composeConfigs([existing, preview_exports]) : composeConfigs([preview_exports]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accesslint/storybook-addon",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"description": "Catch accessibility violations in your Storybook stories as you develop",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
"./preview": {
|
|
25
25
|
"import": "./dist/preview.js",
|
|
26
26
|
"require": "./dist/preview.cjs"
|
|
27
|
+
},
|
|
28
|
+
"./vitest-plugin": {
|
|
29
|
+
"import": "./dist/vitest-plugin.js",
|
|
30
|
+
"require": "./dist/vitest-plugin.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./vitest-setup": {
|
|
33
|
+
"import": "./dist/vitest-setup.js",
|
|
34
|
+
"require": "./dist/vitest-setup.cjs"
|
|
27
35
|
}
|
|
28
36
|
},
|
|
29
37
|
"main": "dist/index.cjs",
|
|
@@ -37,7 +45,6 @@
|
|
|
37
45
|
],
|
|
38
46
|
"scripts": {
|
|
39
47
|
"build": "tsup",
|
|
40
|
-
"prepublishOnly": "node -e \"const fs = require('fs'); const v = JSON.parse(fs.readFileSync('node_modules/@accesslint/core/package.json','utf8')).version; const pkg = JSON.parse(fs.readFileSync('package.json','utf8')); pkg.version = v; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');\"",
|
|
41
48
|
"build:watch": "tsup --watch",
|
|
42
49
|
"typecheck": "tsc --noEmit"
|
|
43
50
|
},
|