@techsio/storybook-better-a11y 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/AccessibilityRuleMaps.js +532 -0
  2. package/dist/a11yRunner.js +105 -0
  3. package/dist/a11yRunner.test.js +21 -0
  4. package/dist/a11yRunnerUtils.js +30 -0
  5. package/dist/a11yRunnerUtils.test.js +61 -0
  6. package/dist/{699.js → apcaChecker.js} +1 -255
  7. package/dist/apcaChecker.test.js +124 -0
  8. package/dist/axeRuleMappingHelper.js +4 -0
  9. package/dist/components/A11YPanel.js +140 -0
  10. package/dist/components/A11YPanel.stories.js +198 -0
  11. package/dist/components/A11YPanel.test.js +110 -0
  12. package/dist/components/A11yContext.js +438 -0
  13. package/dist/components/A11yContext.test.js +277 -0
  14. package/dist/components/Report/Details.js +169 -0
  15. package/dist/components/Report/Report.js +106 -0
  16. package/dist/components/Report/Report.stories.js +86 -0
  17. package/dist/components/Tabs.js +54 -0
  18. package/dist/components/TestDiscrepancyMessage.js +55 -0
  19. package/dist/components/TestDiscrepancyMessage.stories.js +40 -0
  20. package/dist/components/VisionSimulator.js +83 -0
  21. package/dist/components/VisionSimulator.stories.js +56 -0
  22. package/dist/constants.js +25 -0
  23. package/dist/index.js +5 -6
  24. package/dist/manager.js +11 -1540
  25. package/dist/manager.test.js +86 -0
  26. package/dist/params.js +0 -0
  27. package/dist/postinstall.js +1 -1
  28. package/dist/preview.js +68 -1
  29. package/dist/preview.test.js +215 -0
  30. package/dist/results.mock.js +874 -0
  31. package/dist/types.js +6 -0
  32. package/dist/utils.js +21 -0
  33. package/dist/{100.js → visionSimulatorFilters.js} +1 -23
  34. package/dist/withVisionSimulator.js +41 -0
  35. package/package.json +1 -1
  36. package/dist/212.js +0 -1965
  37. package/dist/212.js.LICENSE.txt +0 -19
  38. package/dist/rslib-runtime.js +0 -37
@@ -0,0 +1,54 @@
1
+ import { createElement } from "react";
2
+ import { Button, Tabs } from "storybook/internal/components";
3
+ import { CollapseIcon, ExpandAltIcon, EyeCloseIcon, EyeIcon, SyncIcon } from "@storybook/icons";
4
+ import { styled, useTheme } from "storybook/theming";
5
+ import { useA11yContext } from "./A11yContext.js";
6
+ const Container = styled.div({
7
+ width: '100%',
8
+ position: 'relative',
9
+ height: '100%',
10
+ overflow: 'hidden',
11
+ display: 'flex',
12
+ flexDirection: 'column'
13
+ });
14
+ const ActionsWrapper = styled.div({
15
+ display: 'flex',
16
+ justifyContent: 'flex-end',
17
+ gap: 6
18
+ });
19
+ const TabPanel = ({ id, children })=>/*#__PURE__*/ createElement("div", {
20
+ id: id
21
+ }, children);
22
+ const Tabs_Tabs = ({ tabs })=>{
23
+ const { tab, setTab, toggleHighlight, highlighted, handleManual, allExpanded, handleCollapseAll, handleExpandAll } = useA11yContext();
24
+ const theme = useTheme();
25
+ return /*#__PURE__*/ createElement(Container, null, /*#__PURE__*/ createElement(Tabs, {
26
+ backgroundColor: theme.background.app,
27
+ selected: tab,
28
+ actions: {
29
+ onSelect: (id)=>setTab(id)
30
+ },
31
+ tools: /*#__PURE__*/ createElement(ActionsWrapper, null, /*#__PURE__*/ createElement(Button, {
32
+ variant: "ghost",
33
+ padding: "small",
34
+ onClick: toggleHighlight,
35
+ ariaLabel: highlighted ? 'Hide accessibility test result highlights' : 'Highlight elements with accessibility test results'
36
+ }, highlighted ? /*#__PURE__*/ createElement(EyeCloseIcon, null) : /*#__PURE__*/ createElement(EyeIcon, null)), /*#__PURE__*/ createElement(Button, {
37
+ variant: "ghost",
38
+ padding: "small",
39
+ onClick: allExpanded ? handleCollapseAll : handleExpandAll,
40
+ ariaLabel: allExpanded ? 'Collapse all results' : 'Expand all results',
41
+ "aria-expanded": allExpanded
42
+ }, allExpanded ? /*#__PURE__*/ createElement(CollapseIcon, null) : /*#__PURE__*/ createElement(ExpandAltIcon, null)), /*#__PURE__*/ createElement(Button, {
43
+ variant: "ghost",
44
+ padding: "small",
45
+ onClick: handleManual,
46
+ ariaLabel: "Rerun accessibility scan"
47
+ }, /*#__PURE__*/ createElement(SyncIcon, null)))
48
+ }, tabs.map((tabItem)=>/*#__PURE__*/ createElement(TabPanel, {
49
+ key: tabItem.type,
50
+ id: tabItem.type,
51
+ title: tabItem.label
52
+ }, tabItem.panel))));
53
+ };
54
+ export { Tabs_Tabs as Tabs };
@@ -0,0 +1,55 @@
1
+ import react, { useMemo } from "react";
2
+ import { Link } from "storybook/internal/components";
3
+ import { useStorybookApi } from "storybook/manager-api";
4
+ import { styled } from "storybook/theming";
5
+ import { DOCUMENTATION_DISCREPANCY_LINK } from "../constants.js";
6
+ const Wrapper = styled.div(({ theme: { color, typography, background } })=>({
7
+ textAlign: 'start',
8
+ padding: '11px 15px',
9
+ fontSize: `${typography.size.s2}px`,
10
+ fontWeight: typography.weight.regular,
11
+ lineHeight: '1rem',
12
+ background: background.app,
13
+ borderBottom: `1px solid ${color.border}`,
14
+ color: color.defaultText,
15
+ backgroundClip: 'padding-box',
16
+ position: 'relative',
17
+ code: {
18
+ fontSize: `${typography.size.s1 - 1}px`,
19
+ color: 'inherit',
20
+ margin: '0 0.2em',
21
+ padding: '0 0.2em',
22
+ background: 'rgba(255, 255, 255, 0.8)',
23
+ borderRadius: '2px',
24
+ boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)'
25
+ }
26
+ }));
27
+ const TestDiscrepancyMessage = ({ discrepancy })=>{
28
+ const api = useStorybookApi();
29
+ const docsUrl = api.getDocsUrl({
30
+ subpath: DOCUMENTATION_DISCREPANCY_LINK,
31
+ versioned: true,
32
+ renderer: true
33
+ });
34
+ const message = useMemo(()=>{
35
+ switch(discrepancy){
36
+ case 'browserPassedCliFailed':
37
+ return 'Accessibility checks passed in this browser but failed in the CLI.';
38
+ case 'cliPassedBrowserFailed':
39
+ return 'Accessibility checks passed in the CLI but failed in this browser.';
40
+ case 'cliFailedButModeManual':
41
+ return 'Accessibility checks failed in the CLI. Run the tests manually to see the results.';
42
+ default:
43
+ return null;
44
+ }
45
+ }, [
46
+ discrepancy
47
+ ]);
48
+ if (!message) return null;
49
+ return /*#__PURE__*/ react.createElement(Wrapper, null, message, ' ', /*#__PURE__*/ react.createElement(Link, {
50
+ href: docsUrl,
51
+ target: "_blank",
52
+ withArrow: true
53
+ }, "Learn what could cause this"));
54
+ };
55
+ export { TestDiscrepancyMessage };
@@ -0,0 +1,40 @@
1
+ import react from "react";
2
+ import { ManagerContext } from "storybook/manager-api";
3
+ import { fn } from "storybook/test";
4
+ import preview from "../../../../.storybook/preview";
5
+ import { TestDiscrepancyMessage } from "./TestDiscrepancyMessage.js";
6
+ const managerContext = {
7
+ state: {},
8
+ api: {
9
+ getDocsUrl: fn().mockName('api::getDocsUrl'),
10
+ getCurrentParameter: fn().mockName('api::getCurrentParameter')
11
+ }
12
+ };
13
+ const meta = preview.meta({
14
+ title: 'TestDiscrepancyMessage',
15
+ component: TestDiscrepancyMessage,
16
+ parameters: {
17
+ layout: 'fullscreen'
18
+ },
19
+ decorators: [
20
+ (storyFn)=>/*#__PURE__*/ react.createElement(ManagerContext.Provider, {
21
+ value: managerContext
22
+ }, storyFn())
23
+ ]
24
+ });
25
+ const BrowserPassedCliFailed = meta.story({
26
+ args: {
27
+ discrepancy: 'browserPassedCliFailed'
28
+ }
29
+ });
30
+ const CliPassedBrowserFailed = meta.story({
31
+ args: {
32
+ discrepancy: 'cliPassedBrowserFailed'
33
+ }
34
+ });
35
+ const CliFailedButModeManual = meta.story({
36
+ args: {
37
+ discrepancy: 'cliFailedButModeManual'
38
+ }
39
+ });
40
+ export { BrowserPassedCliFailed, CliFailedButModeManual, CliPassedBrowserFailed };
@@ -0,0 +1,83 @@
1
+ import react from "react";
2
+ import { Button } from "storybook/internal/components";
3
+ import { AccessibilityIcon } from "@storybook/icons";
4
+ import { useGlobals } from "storybook/manager-api";
5
+ import { styled } from "storybook/theming";
6
+ import { VISION_GLOBAL_KEY } from "../constants.js";
7
+ import { filterDefs, filters } from "../visionSimulatorFilters.js";
8
+ const Hidden = styled.div({
9
+ '&, & svg': {
10
+ position: 'absolute',
11
+ width: 0,
12
+ height: 0
13
+ }
14
+ });
15
+ const ColorIcon = styled.span({
16
+ background: 'linear-gradient(to right, #F44336, #FF9800, #FFEB3B, #8BC34A, #2196F3, #9C27B0)',
17
+ borderRadius: 14,
18
+ display: 'block',
19
+ flexShrink: 0,
20
+ height: 14,
21
+ width: 14
22
+ }, ({ $filter })=>({
23
+ filter: filters[$filter]?.filter || 'none'
24
+ }), ({ theme })=>({
25
+ boxShadow: `${theme.appBorderColor} 0 0 0 1px inset`
26
+ }));
27
+ const SelectRow = styled.div(({ theme })=>({
28
+ display: 'flex',
29
+ alignItems: 'center',
30
+ gap: 8,
31
+ padding: '6px 10px',
32
+ border: `1px solid ${theme.appBorderColor}`,
33
+ borderRadius: theme.appBorderRadius,
34
+ background: theme.background.content
35
+ }));
36
+ const SelectInput = styled.select(({ theme })=>({
37
+ flex: 1,
38
+ minWidth: 0,
39
+ padding: '4px 6px',
40
+ border: `1px solid ${theme.appBorderColor}`,
41
+ borderRadius: theme.appBorderRadius,
42
+ background: theme.background.app,
43
+ color: theme.color.defaultText,
44
+ fontSize: theme.typography.size.s2
45
+ }));
46
+ const ResetButton = styled(Button)({
47
+ whiteSpace: 'nowrap'
48
+ });
49
+ const VisionSimulator = ()=>{
50
+ const [globals, updateGlobals] = useGlobals();
51
+ const value = globals[VISION_GLOBAL_KEY];
52
+ const options = Object.entries(filters).map(([key, { label, percentage }])=>({
53
+ label: percentage ? `${label} (${percentage}% of users)` : label,
54
+ value: key
55
+ }));
56
+ return /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(SelectRow, {
57
+ "aria-label": "Vision simulator"
58
+ }, /*#__PURE__*/ react.createElement(AccessibilityIcon, null), /*#__PURE__*/ react.createElement(ColorIcon, {
59
+ $filter: String(value || 'none')
60
+ }), /*#__PURE__*/ react.createElement(SelectInput, {
61
+ value: value ?? '',
62
+ onChange: (event)=>updateGlobals({
63
+ [VISION_GLOBAL_KEY]: event.target.value || void 0
64
+ })
65
+ }, /*#__PURE__*/ react.createElement("option", {
66
+ value: ""
67
+ }, "No filter"), options.map((option)=>/*#__PURE__*/ react.createElement("option", {
68
+ key: option.value,
69
+ value: option.value
70
+ }, option.label))), /*#__PURE__*/ react.createElement(ResetButton, {
71
+ variant: "ghost",
72
+ padding: "small",
73
+ onClick: ()=>updateGlobals({
74
+ [VISION_GLOBAL_KEY]: void 0
75
+ }),
76
+ ariaLabel: "Reset color filter"
77
+ }, "Reset")), /*#__PURE__*/ react.createElement(Hidden, {
78
+ dangerouslySetInnerHTML: {
79
+ __html: filterDefs
80
+ }
81
+ }));
82
+ };
83
+ export { VisionSimulator };
@@ -0,0 +1,56 @@
1
+ import { ManagerContext } from "storybook/manager-api";
2
+ import { expect, fn, screen } from "storybook/test";
3
+ import preview from "../../../../.storybook/preview";
4
+ import { VisionSimulator } from "./VisionSimulator.js";
5
+ const managerContext = {
6
+ state: {},
7
+ api: {
8
+ getGlobals: fn(()=>({
9
+ vision: void 0
10
+ })),
11
+ updateGlobals: fn(),
12
+ getStoryGlobals: fn(()=>({
13
+ vision: void 0
14
+ })),
15
+ getUserGlobals: fn(()=>({
16
+ vision: void 0
17
+ }))
18
+ }
19
+ };
20
+ const meta = preview.meta({
21
+ title: 'Vision Simulator',
22
+ component: VisionSimulator,
23
+ decorators: [
24
+ (Story)=>/*#__PURE__*/ React.createElement(ManagerContext.Provider, {
25
+ value: managerContext
26
+ }, /*#__PURE__*/ React.createElement(Story, null))
27
+ ]
28
+ });
29
+ const VisionSimulator_stories = meta;
30
+ const openMenu = async ({ canvas, userEvent })=>{
31
+ await userEvent.click(canvas.getByRole('button', {
32
+ name: 'Vision simulator'
33
+ }));
34
+ };
35
+ const Default = meta.story({
36
+ play: openMenu
37
+ });
38
+ const WithFilter = meta.story({
39
+ play: openMenu,
40
+ globals: {
41
+ vision: 'achromatopsia'
42
+ }
43
+ });
44
+ const Selection = meta.story({
45
+ play: async (context)=>{
46
+ await openMenu(context);
47
+ await context.userEvent.click(await screen.findByText('Blurred vision'));
48
+ await expect(managerContext.api.updateGlobals).toHaveBeenCalledWith({
49
+ vision: 'blurred'
50
+ });
51
+ await expect(context.canvas.getByRole('button', {
52
+ name: 'Vision simulator Blurred vision'
53
+ })).toBeVisible();
54
+ }
55
+ });
56
+ export { Default, Selection, WithFilter, VisionSimulator_stories as default };
@@ -0,0 +1,25 @@
1
+ const ADDON_ID = 'storybook/a11y';
2
+ const PANEL_ID = `${ADDON_ID}/panel`;
3
+ const PARAM_KEY = "a11y";
4
+ const VISION_GLOBAL_KEY = "vision";
5
+ const UI_STATE_ID = `${ADDON_ID}/ui`;
6
+ const RESULT = `${ADDON_ID}/result`;
7
+ const REQUEST = `${ADDON_ID}/request`;
8
+ const RUNNING = `${ADDON_ID}/running`;
9
+ const ERROR = `${ADDON_ID}/error`;
10
+ const MANUAL = `${ADDON_ID}/manual`;
11
+ const SELECT = `${ADDON_ID}/select`;
12
+ const DOCUMENTATION_LINK = 'writing-tests/accessibility-testing';
13
+ const DOCUMENTATION_DISCREPANCY_LINK = `${DOCUMENTATION_LINK}#why-are-my-tests-failing-in-different-environments`;
14
+ const TEST_PROVIDER_ID = 'storybook/addon-a11y/test-provider';
15
+ const EVENTS = {
16
+ RESULT,
17
+ REQUEST,
18
+ RUNNING,
19
+ ERROR,
20
+ MANUAL,
21
+ SELECT
22
+ };
23
+ const STATUS_TYPE_ID_COMPONENT_TEST = 'storybook/component-test';
24
+ const STATUS_TYPE_ID_A11Y = 'storybook/a11y';
25
+ export { ADDON_ID, DOCUMENTATION_DISCREPANCY_LINK, DOCUMENTATION_LINK, EVENTS, PANEL_ID, PARAM_KEY, STATUS_TYPE_ID_A11Y, STATUS_TYPE_ID_COMPONENT_TEST, TEST_PROVIDER_ID, UI_STATE_ID, VISION_GLOBAL_KEY };
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { definePreviewAddon } from "storybook/internal/csf";
2
- import { preview_namespaceObject } from "./699.js";
3
- import "./100.js";
4
- const src = ()=>definePreviewAddon(preview_namespaceObject);
5
- var src_PARAM_KEY = "a11y";
6
- export default src;
7
- export { src_PARAM_KEY as PARAM_KEY };
2
+ import { PARAM_KEY } from "./constants.js";
3
+ export * from "./params.js";
4
+ import * as __rspack_external__preview_js_3b21eac2 from "./preview.js";
5
+ const src = ()=>definePreviewAddon(__rspack_external__preview_js_3b21eac2);
6
+ export { PARAM_KEY, src as default };