@accesslint/storybook-addon 0.7.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -152
- package/dist/manager.js +73 -40
- package/dist/matchers.cjs +9 -52
- package/dist/matchers.d.cts +1 -11
- package/dist/matchers.d.ts +1 -11
- package/dist/matchers.js +1 -55
- package/dist/portable.cjs +13 -3
- package/dist/portable.d.cts +1 -1
- package/dist/portable.d.ts +1 -1
- package/dist/portable.js +14 -4
- package/dist/preview.cjs +13 -3
- package/dist/preview.d.cts +1 -1
- package/dist/preview.d.ts +1 -1
- package/dist/preview.js +14 -4
- package/dist/vitest-setup.cjs +18 -5
- package/dist/vitest-setup.d.cts +2 -0
- package/dist/vitest-setup.d.ts +2 -0
- package/dist/vitest-setup.js +19 -6
- package/matchers.d.ts +1 -1
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -17,153 +17,111 @@ Add the addon to your `.storybook/main.ts` (or `.storybook/main.js`):
|
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
19
|
const config = {
|
|
20
|
-
addons: ["@
|
|
20
|
+
addons: ["@accesslint/storybook-addon"],
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export default config;
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Restart Storybook and an **AccessLint** panel will appear in the addon bar. Every story is audited automatically after it renders.
|
|
27
|
+
|
|
28
|
+
## Vitest integration
|
|
29
|
+
|
|
30
|
+
If you use [`@storybook/addon-vitest`](https://storybook.js.org/docs/writing-tests/vitest-plugin), add the AccessLint plugin next to `storybookTest()` in your Vite config:
|
|
27
31
|
|
|
28
32
|
```ts
|
|
29
|
-
import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
|
|
30
33
|
import { accesslintTest } from "@accesslint/storybook-addon/vitest-plugin";
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
storybookTest({ configDir: ".storybook" }),
|
|
38
|
-
accesslintTest(),
|
|
39
|
-
],
|
|
40
|
-
test: {
|
|
41
|
-
name: "storybook",
|
|
42
|
-
browser: {
|
|
43
|
-
enabled: true,
|
|
44
|
-
headless: true,
|
|
45
|
-
provider: playwright({}),
|
|
46
|
-
instances: [{ browser: "chromium" }],
|
|
47
|
-
},
|
|
48
|
-
setupFiles: [".storybook/vitest.setup.ts"],
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
|
-
});
|
|
35
|
+
// Inside your Storybook test project:
|
|
36
|
+
plugins: [
|
|
37
|
+
storybookTest({ configDir: ".storybook" }),
|
|
38
|
+
accesslintTest(),
|
|
39
|
+
],
|
|
54
40
|
```
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## Usage
|
|
42
|
+
This gives you:
|
|
59
43
|
|
|
60
|
-
|
|
44
|
+
- Per-story status dots in the sidebar (green/yellow/red)
|
|
45
|
+
- A test widget in the sidebar's testing module
|
|
46
|
+
- The `toBeAccessible()` matcher registered automatically
|
|
47
|
+
- Accessibility results in CI alongside your component tests
|
|
61
48
|
|
|
62
|
-
|
|
63
|
-
- **WCAG criteria** and conformance level (A, AA, AAA)
|
|
64
|
-
- **How to fix** guidance for each rule
|
|
65
|
-
- **Element HTML** snippet of the failing element
|
|
49
|
+
## Accessibility assertions
|
|
66
50
|
|
|
67
|
-
|
|
51
|
+
Use `toBeAccessible()` to make accessibility a first-class assertion in your tests and play functions.
|
|
68
52
|
|
|
69
|
-
|
|
53
|
+
### With the Vitest plugin
|
|
70
54
|
|
|
71
|
-
|
|
72
|
-
- Yellow — violations present, but running in `"todo"` mode (warnings)
|
|
73
|
-
- Red — violations present in `"error"` mode (failures)
|
|
74
|
-
|
|
75
|
-
Click a status dot to jump to the AccessLint panel for that story. Right-click any story in the sidebar to access "View AccessLint results".
|
|
76
|
-
|
|
77
|
-
### Test widget
|
|
78
|
-
|
|
79
|
-
The AccessLint test provider widget appears in the sidebar's testing module alongside Storybook's built-in component tests. It shows the current story's violation count and responds to the global "Run all" and "Clear all" buttons.
|
|
80
|
-
|
|
81
|
-
## Configuration
|
|
82
|
-
|
|
83
|
-
### Parameters
|
|
84
|
-
|
|
85
|
-
Control AccessLint behavior per-story or globally via `parameters.accesslint`:
|
|
55
|
+
If you added `accesslintTest()` above, the matcher is already registered. Use it directly in play functions:
|
|
86
56
|
|
|
87
57
|
```ts
|
|
88
|
-
|
|
89
|
-
const preview = {
|
|
90
|
-
parameters: {
|
|
91
|
-
accesslint: {
|
|
92
|
-
// 'todo' - show violations as warnings in the test UI (non-blocking)
|
|
93
|
-
// 'error' - fail CI on violations
|
|
94
|
-
// 'off' - skip checks entirely
|
|
95
|
-
test: "todo",
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export default preview;
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Override per-story:
|
|
58
|
+
import { expect } from "storybook/test";
|
|
104
59
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
accesslint: { test: "off" },
|
|
60
|
+
export const Default = {
|
|
61
|
+
play: async ({ canvasElement }) => {
|
|
62
|
+
await expect(canvasElement).toBeAccessible();
|
|
109
63
|
},
|
|
110
64
|
};
|
|
111
65
|
```
|
|
112
66
|
|
|
113
|
-
###
|
|
67
|
+
### Without the Vitest plugin
|
|
114
68
|
|
|
115
|
-
|
|
69
|
+
For play functions or standalone tests without the plugin, import the matchers entry point to register `toBeAccessible()`:
|
|
116
70
|
|
|
117
71
|
```ts
|
|
118
|
-
|
|
119
|
-
import { configureRules } from "@accesslint/core";
|
|
120
|
-
|
|
121
|
-
configureRules({
|
|
122
|
-
disabledRules: ["accesslint-045"], // e.g. disable landmark region rule
|
|
123
|
-
});
|
|
72
|
+
import "@accesslint/storybook-addon/matchers";
|
|
124
73
|
```
|
|
125
74
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Tag stories with `"no-a11y"` to skip AccessLint auditing:
|
|
75
|
+
Then use it in a play function:
|
|
129
76
|
|
|
130
77
|
```ts
|
|
131
|
-
|
|
132
|
-
|
|
78
|
+
import { expect } from "storybook/test";
|
|
79
|
+
import "@accesslint/storybook-addon/matchers";
|
|
80
|
+
|
|
81
|
+
export const Default = {
|
|
82
|
+
play: async ({ canvasElement }) => {
|
|
83
|
+
await expect(canvasElement).toBeAccessible();
|
|
84
|
+
},
|
|
133
85
|
};
|
|
134
86
|
```
|
|
135
87
|
|
|
136
|
-
|
|
88
|
+
Or in a standalone Vitest/Jest test:
|
|
137
89
|
|
|
138
90
|
```ts
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
91
|
+
import "@accesslint/storybook-addon/matchers";
|
|
92
|
+
import { render } from "@testing-library/react";
|
|
93
|
+
|
|
94
|
+
test("LoginForm is accessible", () => {
|
|
95
|
+
const { container } = render(<LoginForm />);
|
|
96
|
+
expect(container).toBeAccessible();
|
|
97
|
+
});
|
|
144
98
|
```
|
|
145
99
|
|
|
146
|
-
|
|
100
|
+
### Disabling rules per assertion
|
|
147
101
|
|
|
148
102
|
```ts
|
|
149
|
-
|
|
150
|
-
|
|
103
|
+
await expect(canvasElement).toBeAccessible({
|
|
104
|
+
disabledRules: ["accesslint-045"],
|
|
151
105
|
});
|
|
152
106
|
```
|
|
153
107
|
|
|
154
|
-
|
|
108
|
+
### Failure output
|
|
155
109
|
|
|
156
|
-
|
|
110
|
+
When the assertion fails, the error message lists each violation with its rule ID, WCAG criteria, conformance level, message, and the CSS selector of the failing element:
|
|
157
111
|
|
|
158
|
-
|
|
112
|
+
```
|
|
113
|
+
Expected element to have no accessibility violations, but found 2:
|
|
159
114
|
|
|
160
|
-
|
|
115
|
+
accesslint-001 [A] (1.1.1): Image is missing alt text
|
|
116
|
+
img[src="hero.png"]
|
|
161
117
|
|
|
162
|
-
|
|
163
|
-
|
|
118
|
+
accesslint-012 [A] (1.3.1): Form input is missing a label
|
|
119
|
+
input[type="email"]
|
|
164
120
|
```
|
|
165
121
|
|
|
166
|
-
|
|
122
|
+
### TypeScript support
|
|
123
|
+
|
|
124
|
+
Add the type reference to your `tsconfig.json`:
|
|
167
125
|
|
|
168
126
|
```json
|
|
169
127
|
{
|
|
@@ -179,60 +137,82 @@ Or add a triple-slash reference in a `.d.ts` file:
|
|
|
179
137
|
/// <reference types="@accesslint/storybook-addon/matchers" />
|
|
180
138
|
```
|
|
181
139
|
|
|
182
|
-
|
|
140
|
+
## Configuration
|
|
183
141
|
|
|
184
|
-
|
|
185
|
-
import { expect } from "storybook/test";
|
|
186
|
-
import "@accesslint/storybook-addon/matchers";
|
|
142
|
+
### Test mode
|
|
187
143
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
144
|
+
Control how violations are reported via `parameters.accesslint`:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// .storybook/preview.ts — applies to all stories
|
|
148
|
+
const preview = {
|
|
149
|
+
parameters: {
|
|
150
|
+
accesslint: {
|
|
151
|
+
test: "todo", // "error" (default) | "todo" | "off"
|
|
152
|
+
},
|
|
191
153
|
},
|
|
192
154
|
};
|
|
155
|
+
|
|
156
|
+
export default preview;
|
|
193
157
|
```
|
|
194
158
|
|
|
195
|
-
|
|
159
|
+
| Mode | Behavior |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| `"error"` | Violations fail the test (default) |
|
|
162
|
+
| `"todo"` | Violations show as warnings — yellow sidebar dots, non-blocking in CI |
|
|
163
|
+
| `"off"` | Skip auditing entirely |
|
|
196
164
|
|
|
197
|
-
|
|
198
|
-
import "@accesslint/storybook-addon/matchers";
|
|
199
|
-
import { render } from "@testing-library/react";
|
|
165
|
+
Override per-story:
|
|
200
166
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
167
|
+
```ts
|
|
168
|
+
export const Experimental = {
|
|
169
|
+
parameters: {
|
|
170
|
+
accesslint: { test: "off" },
|
|
171
|
+
},
|
|
172
|
+
};
|
|
205
173
|
```
|
|
206
174
|
|
|
207
|
-
###
|
|
175
|
+
### Disabling rules
|
|
208
176
|
|
|
209
|
-
|
|
177
|
+
Disable specific rules globally in your preview file:
|
|
210
178
|
|
|
211
179
|
```ts
|
|
212
|
-
|
|
213
|
-
|
|
180
|
+
// .storybook/preview.ts
|
|
181
|
+
import { configureRules } from "@accesslint/core";
|
|
182
|
+
|
|
183
|
+
configureRules({
|
|
184
|
+
disabledRules: ["accesslint-045"], // e.g. disable landmark region rule
|
|
214
185
|
});
|
|
215
186
|
```
|
|
216
187
|
|
|
217
|
-
###
|
|
188
|
+
### Skipping stories with tags
|
|
218
189
|
|
|
219
|
-
|
|
190
|
+
Tag individual stories or entire components with `"no-a11y"` to skip auditing:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
// Skip a single story
|
|
194
|
+
export const Prototype = {
|
|
195
|
+
tags: ["no-a11y"],
|
|
196
|
+
};
|
|
220
197
|
|
|
198
|
+
// Skip all stories for a component
|
|
199
|
+
export default {
|
|
200
|
+
component: ExperimentalWidget,
|
|
201
|
+
tags: ["no-a11y"],
|
|
202
|
+
};
|
|
221
203
|
```
|
|
222
|
-
Expected element to have no accessibility violations, but found 2:
|
|
223
204
|
|
|
224
|
-
|
|
225
|
-
img[src="hero.png"]
|
|
205
|
+
With the Vitest plugin, you can also define custom skip tags:
|
|
226
206
|
|
|
227
|
-
|
|
228
|
-
|
|
207
|
+
```ts
|
|
208
|
+
accesslintTest({
|
|
209
|
+
tags: { skip: ["no-a11y", "wip"] },
|
|
210
|
+
});
|
|
229
211
|
```
|
|
230
212
|
|
|
231
213
|
## Portable stories
|
|
232
214
|
|
|
233
|
-
Use AccessLint with `composeStories` outside of Storybook (plain Vitest, Jest, or Playwright CT).
|
|
234
|
-
|
|
235
|
-
### Setup
|
|
215
|
+
Use AccessLint with [`composeStories`](https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest) outside of Storybook (plain Vitest, Jest, or Playwright CT).
|
|
236
216
|
|
|
237
217
|
In your test setup file, pass the AccessLint annotations to `setProjectAnnotations`:
|
|
238
218
|
|
|
@@ -250,7 +230,7 @@ const project = setProjectAnnotations([
|
|
|
250
230
|
beforeAll(project.beforeAll);
|
|
251
231
|
```
|
|
252
232
|
|
|
253
|
-
|
|
233
|
+
Then in your tests:
|
|
254
234
|
|
|
255
235
|
```ts
|
|
256
236
|
import { composeStories } from "@storybook/react";
|
|
@@ -273,22 +253,13 @@ test("Primary button is accessible", async () => {
|
|
|
273
253
|
| `@accesslint/storybook-addon` | Main addon registration (manager + preview) |
|
|
274
254
|
| `@accesslint/storybook-addon/vitest-plugin` | `accesslintTest()` Vite plugin for Vitest integration |
|
|
275
255
|
| `@accesslint/storybook-addon/vitest-setup` | Setup file registered by the Vite plugin |
|
|
276
|
-
| `@accesslint/storybook-addon/matchers` | `toBeAccessible()` custom
|
|
256
|
+
| `@accesslint/storybook-addon/matchers` | `toBeAccessible()` custom matcher |
|
|
277
257
|
| `@accesslint/storybook-addon/portable` | `enableAccessLint()` for portable stories |
|
|
278
258
|
| `@accesslint/storybook-addon/preview` | Preview annotations (afterEach hook) |
|
|
279
259
|
|
|
280
260
|
### `accesslintTest(options?)`
|
|
281
261
|
|
|
282
|
-
Vite plugin that registers AccessLint's `afterEach` annotation for Vitest story tests.
|
|
283
|
-
|
|
284
|
-
```ts
|
|
285
|
-
import { accesslintTest } from "@accesslint/storybook-addon/vitest-plugin";
|
|
286
|
-
|
|
287
|
-
accesslintTest();
|
|
288
|
-
accesslintTest({ tags: { skip: ["no-a11y"] } });
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
**Options:**
|
|
262
|
+
Vite plugin that registers AccessLint's `afterEach` annotation and the `toBeAccessible()` matcher for Vitest story tests.
|
|
292
263
|
|
|
293
264
|
| Option | Type | Description |
|
|
294
265
|
| --- | --- | --- |
|
|
@@ -298,20 +269,13 @@ accesslintTest({ tags: { skip: ["no-a11y"] } });
|
|
|
298
269
|
|
|
299
270
|
| Parameter | Type | Default | Description |
|
|
300
271
|
| --- | --- | --- | --- |
|
|
301
|
-
| `test` | `"todo" \| "error" \| "off"` | `"error"` |
|
|
272
|
+
| `test` | `"todo" \| "error" \| "off"` | `"error"` | Controls how violations are reported |
|
|
302
273
|
| `disable` | `boolean` | `false` | Set to `true` to skip auditing (same as `test: "off"`) |
|
|
303
274
|
|
|
304
275
|
### `toBeAccessible(options?)`
|
|
305
276
|
|
|
306
277
|
Custom matcher for asserting an element has no accessibility violations.
|
|
307
278
|
|
|
308
|
-
```ts
|
|
309
|
-
expect(element).toBeAccessible();
|
|
310
|
-
expect(element).toBeAccessible({ disabledRules: ["accesslint-045"] });
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
**Options:**
|
|
314
|
-
|
|
315
279
|
| Option | Type | Description |
|
|
316
280
|
| --- | --- | --- |
|
|
317
281
|
| `disabledRules` | `string[]` | Rule IDs to skip for this assertion |
|
|
@@ -320,14 +284,11 @@ expect(element).toBeAccessible({ disabledRules: ["accesslint-045"] });
|
|
|
320
284
|
|
|
321
285
|
Returns AccessLint's preview annotations for use with `setProjectAnnotations` in portable stories setups.
|
|
322
286
|
|
|
323
|
-
```ts
|
|
324
|
-
import { enableAccessLint } from "@accesslint/storybook-addon/portable";
|
|
325
|
-
```
|
|
326
|
-
|
|
327
287
|
## Compatibility
|
|
328
288
|
|
|
329
289
|
| Addon version | Storybook version |
|
|
330
290
|
| ------------- | ----------------- |
|
|
291
|
+
| 0.7.x | 10.x |
|
|
331
292
|
| 0.6.x | 10.x |
|
|
332
293
|
|
|
333
294
|
## Issues
|
package/dist/manager.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import React, { useMemo, useState, useRef, useCallback } from 'react';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import * as managerApi from 'storybook/internal/manager-api';
|
|
3
|
+
import { useChannel } from 'storybook/internal/manager-api';
|
|
4
4
|
import { styled, useTheme } from 'storybook/internal/theming';
|
|
5
5
|
import { STORY_CHANGED, STORY_FINISHED } from 'storybook/internal/core-events';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
8
13
|
|
|
9
14
|
// src/constants.ts
|
|
10
15
|
var ADDON_ID = "accesslint/a11y";
|
|
@@ -194,16 +199,31 @@ var Panel = ({ active }) => {
|
|
|
194
199
|
};
|
|
195
200
|
|
|
196
201
|
// src/manager.tsx
|
|
202
|
+
var { addons, types, useChannel: useChannel2, useStorybookApi } = managerApi;
|
|
197
203
|
var PANEL_ID = `${ADDON_ID}/panel`;
|
|
198
204
|
var TEST_PROVIDER_ID = `${ADDON_ID}/test-provider`;
|
|
199
|
-
var
|
|
200
|
-
var
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
205
|
+
var _getStatusStore = managerApi.experimental_getStatusStore;
|
|
206
|
+
var _getTestProviderStore = managerApi.experimental_getTestProviderStore;
|
|
207
|
+
var _useTestProviderStore = managerApi.experimental_useTestProviderStore ?? null;
|
|
208
|
+
var hasTestProvider = !!(_getStatusStore && _getTestProviderStore);
|
|
209
|
+
var statusStore = hasTestProvider ? _getStatusStore(STATUS_TYPE_ID) : null;
|
|
210
|
+
var testProviderStore = hasTestProvider ? _getTestProviderStore(TEST_PROVIDER_ID) : null;
|
|
211
|
+
if (testProviderStore && statusStore) {
|
|
212
|
+
testProviderStore.onClearAll(() => {
|
|
213
|
+
statusStore.unset();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
var ActionList = null;
|
|
217
|
+
var Form = null;
|
|
218
|
+
try {
|
|
219
|
+
const components = __require("storybook/internal/components");
|
|
220
|
+
ActionList = components.ActionList ?? null;
|
|
221
|
+
Form = components.Form ?? null;
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
204
224
|
var Title = () => {
|
|
205
225
|
const [count, setCount] = React.useState(0);
|
|
206
|
-
|
|
226
|
+
useChannel2({
|
|
207
227
|
[STORY_FINISHED]: ({ reporters }) => {
|
|
208
228
|
const report = reporters.find((r) => r.type === "accesslint");
|
|
209
229
|
const violations = report?.result?.violations;
|
|
@@ -224,9 +244,7 @@ var Title = () => {
|
|
|
224
244
|
color: "inherit"
|
|
225
245
|
} }, /* @__PURE__ */ React.createElement("span", { style: { color: "#fff" } }, count)));
|
|
226
246
|
};
|
|
227
|
-
var StyledActionList = styled(ActionList)({
|
|
228
|
-
padding: 0
|
|
229
|
-
});
|
|
247
|
+
var StyledActionList = ActionList ? styled(ActionList)({ padding: 0 }) : styled.div({ padding: 0 });
|
|
230
248
|
var StatusDot = styled.div(
|
|
231
249
|
{
|
|
232
250
|
width: 6,
|
|
@@ -248,33 +266,34 @@ var StatusDot = styled.div(
|
|
|
248
266
|
var TestProviderWidget = () => {
|
|
249
267
|
const [violationCount, setViolationCount] = React.useState(null);
|
|
250
268
|
const api = useStorybookApi();
|
|
251
|
-
const providerState =
|
|
252
|
-
(state) => state[TEST_PROVIDER_ID]
|
|
253
|
-
);
|
|
269
|
+
const providerState = _useTestProviderStore ? _useTestProviderStore((state) => state[TEST_PROVIDER_ID]) : null;
|
|
254
270
|
React.useEffect(() => {
|
|
271
|
+
if (!statusStore) return;
|
|
255
272
|
const unsub = statusStore.onSelect(() => {
|
|
256
273
|
api.setSelectedPanel(PANEL_ID);
|
|
257
274
|
api.togglePanel(true);
|
|
258
275
|
});
|
|
259
276
|
return unsub;
|
|
260
277
|
}, [api]);
|
|
261
|
-
|
|
278
|
+
useChannel2({
|
|
262
279
|
[STORY_FINISHED]: ({ storyId, reporters }) => {
|
|
263
280
|
const report = reporters.find((r) => r.type === "accesslint");
|
|
264
281
|
if (!report) return;
|
|
265
282
|
const violations = report.result?.violations ?? [];
|
|
266
283
|
setViolationCount(violations.length);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
if (statusStore) {
|
|
285
|
+
const hasViolations2 = violations.length > 0;
|
|
286
|
+
const isWarning = report.status === "warning";
|
|
287
|
+
statusStore.set([{
|
|
288
|
+
value: hasViolations2 ? isWarning ? "status-value:warning" : "status-value:error" : "status-value:success",
|
|
289
|
+
typeId: STATUS_TYPE_ID,
|
|
290
|
+
storyId,
|
|
291
|
+
title: "AccessLint",
|
|
292
|
+
description: hasViolations2 ? `${violations.length} violation${violations.length === 1 ? "" : "s"}` : "No violations",
|
|
293
|
+
sidebarContextMenu: true
|
|
294
|
+
}]);
|
|
295
|
+
}
|
|
296
|
+
if (testProviderStore && providerState === "test-provider-state:running") {
|
|
278
297
|
testProviderStore.setState("test-provider-state:succeeded");
|
|
279
298
|
}
|
|
280
299
|
}
|
|
@@ -285,20 +304,32 @@ var TestProviderWidget = () => {
|
|
|
285
304
|
api.setSelectedPanel(PANEL_ID);
|
|
286
305
|
api.togglePanel(true);
|
|
287
306
|
};
|
|
288
|
-
|
|
289
|
-
ActionList.
|
|
307
|
+
if (ActionList && Form) {
|
|
308
|
+
return /* @__PURE__ */ React.createElement(StyledActionList, null, /* @__PURE__ */ React.createElement(ActionList.Item, null, /* @__PURE__ */ React.createElement(ActionList.Action, { as: "label", readOnly: true }, /* @__PURE__ */ React.createElement(ActionList.Icon, null, /* @__PURE__ */ React.createElement(Form.Checkbox, { name: "AccessLint", checked: true, disabled: true })), /* @__PURE__ */ React.createElement(ActionList.Text, null, "AccessLint")), /* @__PURE__ */ React.createElement(
|
|
309
|
+
ActionList.Button,
|
|
310
|
+
{
|
|
311
|
+
ariaLabel: violationCount === null ? "AccessLint: not run yet" : hasViolations ? `AccessLint: ${violationCount} violation${violationCount === 1 ? "" : "s"}` : "AccessLint: no violations",
|
|
312
|
+
disabled: violationCount === null,
|
|
313
|
+
onClick: openPanel
|
|
314
|
+
},
|
|
315
|
+
hasViolations ? violationCount : null,
|
|
316
|
+
/* @__PURE__ */ React.createElement(StatusDot, { status })
|
|
317
|
+
)));
|
|
318
|
+
}
|
|
319
|
+
return /* @__PURE__ */ React.createElement(
|
|
320
|
+
StyledActionList,
|
|
290
321
|
{
|
|
291
|
-
|
|
292
|
-
disabled: violationCount === null,
|
|
322
|
+
style: { display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", cursor: "pointer" },
|
|
293
323
|
onClick: openPanel
|
|
294
324
|
},
|
|
295
|
-
|
|
296
|
-
/* @__PURE__ */ React.createElement(
|
|
297
|
-
|
|
325
|
+
/* @__PURE__ */ React.createElement(StatusDot, { status }),
|
|
326
|
+
/* @__PURE__ */ React.createElement("span", { style: { fontSize: 12 } }, "AccessLint"),
|
|
327
|
+
hasViolations && /* @__PURE__ */ React.createElement("span", { style: { fontSize: 11, fontWeight: "bold" } }, violationCount)
|
|
328
|
+
);
|
|
298
329
|
};
|
|
299
330
|
var SidebarContextMenu = ({ context }) => {
|
|
300
331
|
const api = useStorybookApi();
|
|
301
|
-
if (context.type !== "story") return null;
|
|
332
|
+
if (context.type !== "story" || !ActionList) return null;
|
|
302
333
|
return /* @__PURE__ */ React.createElement(
|
|
303
334
|
ActionList.Item,
|
|
304
335
|
{
|
|
@@ -318,9 +349,11 @@ addons.register(ADDON_ID, () => {
|
|
|
318
349
|
render: Panel,
|
|
319
350
|
paramKey: PARAM_KEY
|
|
320
351
|
});
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
352
|
+
if (hasTestProvider && types.experimental_TEST_PROVIDER) {
|
|
353
|
+
addons.add(TEST_PROVIDER_ID, {
|
|
354
|
+
type: types.experimental_TEST_PROVIDER,
|
|
355
|
+
render: () => /* @__PURE__ */ React.createElement(TestProviderWidget, null),
|
|
356
|
+
sidebarContextMenu: ({ context }) => /* @__PURE__ */ React.createElement(SidebarContextMenu, { context })
|
|
357
|
+
});
|
|
358
|
+
}
|
|
326
359
|
});
|
package/dist/matchers.cjs
CHANGED
|
@@ -1,57 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var matchers = require('@accesslint/vitest/matchers');
|
|
4
4
|
|
|
5
|
-
// src/matchers.ts
|
|
6
|
-
function scopeViolationsToElement(violations, root) {
|
|
7
|
-
return violations.filter((v) => {
|
|
8
|
-
try {
|
|
9
|
-
const el = root.ownerDocument.querySelector(v.selector);
|
|
10
|
-
return el && root.contains(el);
|
|
11
|
-
} catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
function formatViolation(v) {
|
|
17
|
-
const rule = core.getRuleById(v.ruleId);
|
|
18
|
-
const wcag = rule?.wcag?.length ? ` (${rule.wcag.join(", ")})` : "";
|
|
19
|
-
const level = rule?.level ? ` [${rule.level}]` : "";
|
|
20
|
-
return ` ${v.ruleId}${level}${wcag}: ${v.message}
|
|
21
|
-
${v.selector}`;
|
|
22
|
-
}
|
|
23
|
-
var toBeAccessible = function(received, options) {
|
|
24
|
-
if (!(received instanceof Element)) {
|
|
25
|
-
return {
|
|
26
|
-
pass: false,
|
|
27
|
-
message: () => `toBeAccessible() expects an Element (e.g. canvasElement), but received ${typeof received}`
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
if (options?.disabledRules) {
|
|
31
|
-
core.configureRules({ disabledRules: options.disabledRules });
|
|
32
|
-
}
|
|
33
|
-
const result = core.runAudit(received.ownerDocument);
|
|
34
|
-
const scoped = scopeViolationsToElement(result.violations, received);
|
|
35
|
-
const pass = scoped.length === 0;
|
|
36
|
-
return {
|
|
37
|
-
pass,
|
|
38
|
-
message: () => {
|
|
39
|
-
if (pass) {
|
|
40
|
-
return "Expected element to have accessibility violations, but none were found";
|
|
41
|
-
}
|
|
42
|
-
const summary = scoped.map(formatViolation).join("\n\n");
|
|
43
|
-
return `Expected element to have no accessibility violations, but found ${scoped.length}:
|
|
44
5
|
|
|
45
|
-
${summary}`;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
if (typeof globalThis !== "undefined") {
|
|
50
|
-
const g = globalThis;
|
|
51
|
-
const expectFn = g.expect;
|
|
52
|
-
if (expectFn?.extend) {
|
|
53
|
-
expectFn.extend({ toBeAccessible });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
6
|
|
|
57
|
-
exports
|
|
7
|
+
Object.defineProperty(exports, "accesslintMatchers", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return matchers.accesslintMatchers; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "toBeAccessible", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return matchers.toBeAccessible; }
|
|
14
|
+
});
|
package/dist/matchers.d.cts
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
disabledRules?: string[];
|
|
3
|
-
}
|
|
4
|
-
declare const toBeAccessible: (this: {
|
|
5
|
-
isNot: boolean;
|
|
6
|
-
}, received: Element, options?: AccessibleMatcherOptions) => {
|
|
7
|
-
pass: boolean;
|
|
8
|
-
message: () => string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export { type AccessibleMatcherOptions, toBeAccessible };
|
|
1
|
+
export { AccessibleMatcherOptions, accesslintMatchers, toBeAccessible } from '@accesslint/vitest/matchers';
|
package/dist/matchers.d.ts
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
disabledRules?: string[];
|
|
3
|
-
}
|
|
4
|
-
declare const toBeAccessible: (this: {
|
|
5
|
-
isNot: boolean;
|
|
6
|
-
}, received: Element, options?: AccessibleMatcherOptions) => {
|
|
7
|
-
pass: boolean;
|
|
8
|
-
message: () => string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export { type AccessibleMatcherOptions, toBeAccessible };
|
|
1
|
+
export { AccessibleMatcherOptions, accesslintMatchers, toBeAccessible } from '@accesslint/vitest/matchers';
|
package/dist/matchers.js
CHANGED
|
@@ -1,55 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// src/matchers.ts
|
|
4
|
-
function scopeViolationsToElement(violations, root) {
|
|
5
|
-
return violations.filter((v) => {
|
|
6
|
-
try {
|
|
7
|
-
const el = root.ownerDocument.querySelector(v.selector);
|
|
8
|
-
return el && root.contains(el);
|
|
9
|
-
} catch {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
function formatViolation(v) {
|
|
15
|
-
const rule = getRuleById(v.ruleId);
|
|
16
|
-
const wcag = rule?.wcag?.length ? ` (${rule.wcag.join(", ")})` : "";
|
|
17
|
-
const level = rule?.level ? ` [${rule.level}]` : "";
|
|
18
|
-
return ` ${v.ruleId}${level}${wcag}: ${v.message}
|
|
19
|
-
${v.selector}`;
|
|
20
|
-
}
|
|
21
|
-
var toBeAccessible = function(received, options) {
|
|
22
|
-
if (!(received instanceof Element)) {
|
|
23
|
-
return {
|
|
24
|
-
pass: false,
|
|
25
|
-
message: () => `toBeAccessible() expects an Element (e.g. canvasElement), but received ${typeof received}`
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
if (options?.disabledRules) {
|
|
29
|
-
configureRules({ disabledRules: options.disabledRules });
|
|
30
|
-
}
|
|
31
|
-
const result = runAudit(received.ownerDocument);
|
|
32
|
-
const scoped = scopeViolationsToElement(result.violations, received);
|
|
33
|
-
const pass = scoped.length === 0;
|
|
34
|
-
return {
|
|
35
|
-
pass,
|
|
36
|
-
message: () => {
|
|
37
|
-
if (pass) {
|
|
38
|
-
return "Expected element to have accessibility violations, but none were found";
|
|
39
|
-
}
|
|
40
|
-
const summary = scoped.map(formatViolation).join("\n\n");
|
|
41
|
-
return `Expected element to have no accessibility violations, but found ${scoped.length}:
|
|
42
|
-
|
|
43
|
-
${summary}`;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
if (typeof globalThis !== "undefined") {
|
|
48
|
-
const g = globalThis;
|
|
49
|
-
const expectFn = g.expect;
|
|
50
|
-
if (expectFn?.extend) {
|
|
51
|
-
expectFn.extend({ toBeAccessible });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export { toBeAccessible };
|
|
1
|
+
export { accesslintMatchers, toBeAccessible } from '@accesslint/vitest/matchers';
|
package/dist/portable.cjs
CHANGED
|
@@ -16,6 +16,10 @@ __export(preview_exports, {
|
|
|
16
16
|
core.configureRules({
|
|
17
17
|
disabledRules: ["accesslint-045"]
|
|
18
18
|
});
|
|
19
|
+
var BUDGET_MS = 12;
|
|
20
|
+
function yieldToMain() {
|
|
21
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
22
|
+
}
|
|
19
23
|
function scopeViolations(violations) {
|
|
20
24
|
const root = document.getElementById("storybook-root");
|
|
21
25
|
if (!root) return violations;
|
|
@@ -53,8 +57,14 @@ var afterEach = async ({
|
|
|
53
57
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
54
58
|
if (viewMode !== "story") return;
|
|
55
59
|
if (tags?.includes("no-a11y")) return;
|
|
56
|
-
const
|
|
57
|
-
|
|
60
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
61
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
62
|
+
const audit = core.createChunkedAudit(document);
|
|
63
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
64
|
+
await yieldToMain();
|
|
65
|
+
}
|
|
66
|
+
const violations = audit.getViolations();
|
|
67
|
+
const scoped = scopeViolations(violations);
|
|
58
68
|
const enriched = enrichViolations(scoped);
|
|
59
69
|
const hasViolations = enriched.length > 0;
|
|
60
70
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -63,7 +73,7 @@ var afterEach = async ({
|
|
|
63
73
|
version: 1,
|
|
64
74
|
result: {
|
|
65
75
|
violations: enriched,
|
|
66
|
-
ruleCount:
|
|
76
|
+
ruleCount: core.getActiveRules().length
|
|
67
77
|
},
|
|
68
78
|
status: hasViolations ? mode : "passed"
|
|
69
79
|
});
|
package/dist/portable.d.cts
CHANGED
package/dist/portable.d.ts
CHANGED
package/dist/portable.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { configureRules,
|
|
1
|
+
import { configureRules, createChunkedAudit, getActiveRules, getRuleById } from '@accesslint/core';
|
|
2
2
|
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __export = (target, all) => {
|
|
@@ -14,6 +14,10 @@ __export(preview_exports, {
|
|
|
14
14
|
configureRules({
|
|
15
15
|
disabledRules: ["accesslint-045"]
|
|
16
16
|
});
|
|
17
|
+
var BUDGET_MS = 12;
|
|
18
|
+
function yieldToMain() {
|
|
19
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
20
|
+
}
|
|
17
21
|
function scopeViolations(violations) {
|
|
18
22
|
const root = document.getElementById("storybook-root");
|
|
19
23
|
if (!root) return violations;
|
|
@@ -51,8 +55,14 @@ var afterEach = async ({
|
|
|
51
55
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
52
56
|
if (viewMode !== "story") return;
|
|
53
57
|
if (tags?.includes("no-a11y")) return;
|
|
54
|
-
const
|
|
55
|
-
|
|
58
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
59
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
60
|
+
const audit = createChunkedAudit(document);
|
|
61
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
62
|
+
await yieldToMain();
|
|
63
|
+
}
|
|
64
|
+
const violations = audit.getViolations();
|
|
65
|
+
const scoped = scopeViolations(violations);
|
|
56
66
|
const enriched = enrichViolations(scoped);
|
|
57
67
|
const hasViolations = enriched.length > 0;
|
|
58
68
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -61,7 +71,7 @@ var afterEach = async ({
|
|
|
61
71
|
version: 1,
|
|
62
72
|
result: {
|
|
63
73
|
violations: enriched,
|
|
64
|
-
ruleCount:
|
|
74
|
+
ruleCount: getActiveRules().length
|
|
65
75
|
},
|
|
66
76
|
status: hasViolations ? mode : "passed"
|
|
67
77
|
});
|
package/dist/preview.cjs
CHANGED
|
@@ -6,6 +6,10 @@ var core = require('@accesslint/core');
|
|
|
6
6
|
core.configureRules({
|
|
7
7
|
disabledRules: ["accesslint-045"]
|
|
8
8
|
});
|
|
9
|
+
var BUDGET_MS = 12;
|
|
10
|
+
function yieldToMain() {
|
|
11
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
12
|
+
}
|
|
9
13
|
function scopeViolations(violations) {
|
|
10
14
|
const root = document.getElementById("storybook-root");
|
|
11
15
|
if (!root) return violations;
|
|
@@ -43,8 +47,14 @@ var afterEach = async ({
|
|
|
43
47
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
44
48
|
if (viewMode !== "story") return;
|
|
45
49
|
if (tags?.includes("no-a11y")) return;
|
|
46
|
-
const
|
|
47
|
-
|
|
50
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
51
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
52
|
+
const audit = core.createChunkedAudit(document);
|
|
53
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
54
|
+
await yieldToMain();
|
|
55
|
+
}
|
|
56
|
+
const violations = audit.getViolations();
|
|
57
|
+
const scoped = scopeViolations(violations);
|
|
48
58
|
const enriched = enrichViolations(scoped);
|
|
49
59
|
const hasViolations = enriched.length > 0;
|
|
50
60
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -53,7 +63,7 @@ var afterEach = async ({
|
|
|
53
63
|
version: 1,
|
|
54
64
|
result: {
|
|
55
65
|
violations: enriched,
|
|
56
|
-
ruleCount:
|
|
66
|
+
ruleCount: core.getActiveRules().length
|
|
57
67
|
},
|
|
58
68
|
status: hasViolations ? mode : "passed"
|
|
59
69
|
});
|
package/dist/preview.d.cts
CHANGED
package/dist/preview.d.ts
CHANGED
package/dist/preview.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { configureRules,
|
|
1
|
+
import { configureRules, createChunkedAudit, getActiveRules, getRuleById } from '@accesslint/core';
|
|
2
2
|
|
|
3
3
|
// src/preview.ts
|
|
4
4
|
configureRules({
|
|
5
5
|
disabledRules: ["accesslint-045"]
|
|
6
6
|
});
|
|
7
|
+
var BUDGET_MS = 12;
|
|
8
|
+
function yieldToMain() {
|
|
9
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
10
|
+
}
|
|
7
11
|
function scopeViolations(violations) {
|
|
8
12
|
const root = document.getElementById("storybook-root");
|
|
9
13
|
if (!root) return violations;
|
|
@@ -41,8 +45,14 @@ var afterEach = async ({
|
|
|
41
45
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
42
46
|
if (viewMode !== "story") return;
|
|
43
47
|
if (tags?.includes("no-a11y")) return;
|
|
44
|
-
const
|
|
45
|
-
|
|
48
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
49
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
50
|
+
const audit = createChunkedAudit(document);
|
|
51
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
52
|
+
await yieldToMain();
|
|
53
|
+
}
|
|
54
|
+
const violations = audit.getViolations();
|
|
55
|
+
const scoped = scopeViolations(violations);
|
|
46
56
|
const enriched = enrichViolations(scoped);
|
|
47
57
|
const hasViolations = enriched.length > 0;
|
|
48
58
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -51,7 +61,7 @@ var afterEach = async ({
|
|
|
51
61
|
version: 1,
|
|
52
62
|
result: {
|
|
53
63
|
violations: enriched,
|
|
54
|
-
ruleCount:
|
|
64
|
+
ruleCount: getActiveRules().length
|
|
55
65
|
},
|
|
56
66
|
status: hasViolations ? mode : "passed"
|
|
57
67
|
});
|
package/dist/vitest-setup.cjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var test = require('storybook/test');
|
|
4
|
+
var vitest = require('vitest');
|
|
3
5
|
var previewApi = require('storybook/preview-api');
|
|
4
6
|
var core = require('@accesslint/core');
|
|
7
|
+
var matchers = require('@accesslint/vitest/matchers');
|
|
5
8
|
|
|
6
9
|
var __defProp = Object.defineProperty;
|
|
7
10
|
var __export = (target, all) => {
|
|
@@ -17,6 +20,10 @@ __export(preview_exports, {
|
|
|
17
20
|
core.configureRules({
|
|
18
21
|
disabledRules: ["accesslint-045"]
|
|
19
22
|
});
|
|
23
|
+
var BUDGET_MS = 12;
|
|
24
|
+
function yieldToMain() {
|
|
25
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
26
|
+
}
|
|
20
27
|
function scopeViolations(violations) {
|
|
21
28
|
const root = document.getElementById("storybook-root");
|
|
22
29
|
if (!root) return violations;
|
|
@@ -54,8 +61,14 @@ var afterEach = async ({
|
|
|
54
61
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
55
62
|
if (viewMode !== "story") return;
|
|
56
63
|
if (tags?.includes("no-a11y")) return;
|
|
57
|
-
const
|
|
58
|
-
|
|
64
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
65
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
66
|
+
const audit = core.createChunkedAudit(document);
|
|
67
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
68
|
+
await yieldToMain();
|
|
69
|
+
}
|
|
70
|
+
const violations = audit.getViolations();
|
|
71
|
+
const scoped = scopeViolations(violations);
|
|
59
72
|
const enriched = enrichViolations(scoped);
|
|
60
73
|
const hasViolations = enriched.length > 0;
|
|
61
74
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -64,13 +77,13 @@ var afterEach = async ({
|
|
|
64
77
|
version: 1,
|
|
65
78
|
result: {
|
|
66
79
|
violations: enriched,
|
|
67
|
-
ruleCount:
|
|
80
|
+
ruleCount: core.getActiveRules().length
|
|
68
81
|
},
|
|
69
82
|
status: hasViolations ? mode : "passed"
|
|
70
83
|
});
|
|
71
84
|
};
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
test.expect.extend(matchers.accesslintMatchers);
|
|
86
|
+
vitest.expect.extend(matchers.accesslintMatchers);
|
|
74
87
|
var g = globalThis;
|
|
75
88
|
var existing = g.globalProjectAnnotations;
|
|
76
89
|
g.globalProjectAnnotations = existing ? previewApi.composeConfigs([existing, preview_exports]) : previewApi.composeConfigs([preview_exports]);
|
package/dist/vitest-setup.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { expect } from 'storybook/test';
|
|
2
|
+
import { expect as expect$1 } from 'vitest';
|
|
1
3
|
import { composeConfigs } from 'storybook/preview-api';
|
|
2
|
-
import { configureRules,
|
|
4
|
+
import { configureRules, createChunkedAudit, getActiveRules, getRuleById } from '@accesslint/core';
|
|
5
|
+
import { accesslintMatchers } from '@accesslint/vitest/matchers';
|
|
3
6
|
|
|
4
7
|
var __defProp = Object.defineProperty;
|
|
5
8
|
var __export = (target, all) => {
|
|
@@ -15,6 +18,10 @@ __export(preview_exports, {
|
|
|
15
18
|
configureRules({
|
|
16
19
|
disabledRules: ["accesslint-045"]
|
|
17
20
|
});
|
|
21
|
+
var BUDGET_MS = 12;
|
|
22
|
+
function yieldToMain() {
|
|
23
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
24
|
+
}
|
|
18
25
|
function scopeViolations(violations) {
|
|
19
26
|
const root = document.getElementById("storybook-root");
|
|
20
27
|
if (!root) return violations;
|
|
@@ -52,8 +59,14 @@ var afterEach = async ({
|
|
|
52
59
|
if (accesslintParam?.disable === true || accesslintParam?.test === "off") return;
|
|
53
60
|
if (viewMode !== "story") return;
|
|
54
61
|
if (tags?.includes("no-a11y")) return;
|
|
55
|
-
const
|
|
56
|
-
|
|
62
|
+
const skipTags = typeof __ACCESSLINT_SKIP_TAGS__ !== "undefined" ? __ACCESSLINT_SKIP_TAGS__ : [];
|
|
63
|
+
if (skipTags.length > 0 && tags?.some((t) => skipTags.includes(t))) return;
|
|
64
|
+
const audit = createChunkedAudit(document);
|
|
65
|
+
while (audit.processChunk(BUDGET_MS)) {
|
|
66
|
+
await yieldToMain();
|
|
67
|
+
}
|
|
68
|
+
const violations = audit.getViolations();
|
|
69
|
+
const scoped = scopeViolations(violations);
|
|
57
70
|
const enriched = enrichViolations(scoped);
|
|
58
71
|
const hasViolations = enriched.length > 0;
|
|
59
72
|
const mode = accesslintParam?.test === "todo" ? "warning" : "failed";
|
|
@@ -62,13 +75,13 @@ var afterEach = async ({
|
|
|
62
75
|
version: 1,
|
|
63
76
|
result: {
|
|
64
77
|
violations: enriched,
|
|
65
|
-
ruleCount:
|
|
78
|
+
ruleCount: getActiveRules().length
|
|
66
79
|
},
|
|
67
80
|
status: hasViolations ? mode : "passed"
|
|
68
81
|
});
|
|
69
82
|
};
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
expect.extend(accesslintMatchers);
|
|
84
|
+
expect$1.extend(accesslintMatchers);
|
|
72
85
|
var g = globalThis;
|
|
73
86
|
var existing = g.globalProjectAnnotations;
|
|
74
87
|
g.globalProjectAnnotations = existing ? composeConfigs([existing, preview_exports]) : composeConfigs([preview_exports]);
|
package/matchers.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accesslint/storybook-addon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Catch accessibility violations in your Storybook stories as you develop",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"require": "./dist/vitest-plugin.cjs"
|
|
31
31
|
},
|
|
32
32
|
"./vitest-setup": {
|
|
33
|
+
"types": "./dist/vitest-setup.d.ts",
|
|
33
34
|
"import": "./dist/vitest-setup.js",
|
|
34
35
|
"require": "./dist/vitest-setup.cjs"
|
|
35
36
|
},
|
|
@@ -57,17 +58,20 @@
|
|
|
57
58
|
"typecheck": "tsc --noEmit"
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
60
|
-
"@accesslint/core": "^0.6.5"
|
|
61
|
+
"@accesslint/core": "^0.6.5",
|
|
62
|
+
"@accesslint/vitest": "^0.1.3"
|
|
61
63
|
},
|
|
62
64
|
"devDependencies": {
|
|
63
65
|
"react": "^18.2.0",
|
|
64
66
|
"react-dom": "^18.2.0",
|
|
65
67
|
"storybook": "^10.2.0",
|
|
66
68
|
"tsup": "^8.4.0",
|
|
67
|
-
"typescript": "^5.7.0"
|
|
69
|
+
"typescript": "^5.7.0",
|
|
70
|
+
"vitest": "^4.0.18"
|
|
68
71
|
},
|
|
69
72
|
"peerDependencies": {
|
|
70
|
-
"storybook": "^10.0.0"
|
|
73
|
+
"storybook": "^9.0.0 || ^10.0.0",
|
|
74
|
+
"vitest": ">=3.0.0"
|
|
71
75
|
},
|
|
72
76
|
"keywords": [
|
|
73
77
|
"storybook-addon",
|