mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-01 05:05:25 +08:00
Merge pull request #5738 from gaetanmaisse/ts-migration/addon-a11y
Migrate addon a11y to TS
This commit is contained in:
commit
77ad48e74a
@ -21,7 +21,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"jsnext:main": "src/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
@ -36,10 +36,12 @@
|
||||
"core-js": "^2.6.5",
|
||||
"global": "^4.3.2",
|
||||
"memoizerific": "^1.11.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.3",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/common-tags": "^1.8.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import { STORY_RENDERED } from '@storybook/core-events';
|
||||
import { ActionBar, Icons } from '@storybook/components';
|
||||
import { ActionBar, Icons, ScrollArea } from '@storybook/components';
|
||||
|
||||
import { ScrollArea } from '@storybook/components/dist/ScrollArea/ScrollArea';
|
||||
import EVENTS from '../constants';
|
||||
|
||||
import Tabs from './Tabs';
|
||||
import Report from './Report';
|
||||
import { AxeResults, Result } from 'axe-core';
|
||||
import { Report } from './Report';
|
||||
import { Tabs } from './Tabs';
|
||||
import { EVENTS } from '../constants';
|
||||
|
||||
const Icon = styled(Icons)(
|
||||
{
|
||||
@ -18,7 +16,7 @@ const Icon = styled(Icons)(
|
||||
width: '12px',
|
||||
marginRight: '4px',
|
||||
},
|
||||
({ status, theme }) =>
|
||||
({ status, theme }: any) =>
|
||||
status === 'running'
|
||||
? {
|
||||
animation: `${theme.animation.rotate360} 1s linear infinite;`,
|
||||
@ -34,17 +32,23 @@ const Violations = styled.span(({ theme }) => ({
|
||||
color: theme.color.negative,
|
||||
}));
|
||||
|
||||
class A11YPanel extends Component {
|
||||
static propTypes = {
|
||||
active: PropTypes.bool.isRequired,
|
||||
api: PropTypes.shape({
|
||||
on: PropTypes.func,
|
||||
emit: PropTypes.func,
|
||||
off: PropTypes.func,
|
||||
}).isRequired,
|
||||
};
|
||||
interface A11YPanelState {
|
||||
status: string;
|
||||
passes: Result[];
|
||||
violations: Result[];
|
||||
}
|
||||
|
||||
state = {
|
||||
interface A11YPanelProps {
|
||||
active: boolean;
|
||||
api: {
|
||||
on(event: string, callback: (data: any) => void): void;
|
||||
off(event: string, callback: (data: any) => void): void;
|
||||
emit(event: string): void;
|
||||
};
|
||||
}
|
||||
|
||||
export class A11YPanel extends Component<A11YPanelProps, A11YPanelState> {
|
||||
state: A11YPanelState = {
|
||||
status: 'ready',
|
||||
passes: [],
|
||||
violations: [],
|
||||
@ -57,7 +61,7 @@ class A11YPanel extends Component {
|
||||
api.on(EVENTS.RESULT, this.onUpdate);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: A11YPanelProps) {
|
||||
// TODO: might be able to remove this
|
||||
const { active } = this.props;
|
||||
|
||||
@ -73,7 +77,7 @@ class A11YPanel extends Component {
|
||||
api.off(EVENTS.RESULT, this.onUpdate);
|
||||
}
|
||||
|
||||
onUpdate = ({ passes, violations }) => {
|
||||
onUpdate = ({ passes, violations }: AxeResults) => {
|
||||
this.setState(
|
||||
{
|
||||
status: 'ran',
|
||||
@ -153,5 +157,3 @@ class A11YPanel extends Component {
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
|
||||
export default A11YPanel;
|
@ -16,7 +16,7 @@ const ColorIcon = styled.span(
|
||||
height: '1rem',
|
||||
width: '1rem',
|
||||
},
|
||||
({ filter }) => ({
|
||||
({ filter }: { filter: string | null }) => ({
|
||||
filter: filter === 'mono' ? 'grayscale(100%)' : `url('#${filter}')`,
|
||||
}),
|
||||
({ theme }) => ({
|
||||
@ -24,13 +24,21 @@ const ColorIcon = styled.span(
|
||||
})
|
||||
);
|
||||
|
||||
class ColorBlindness extends Component {
|
||||
state = {
|
||||
// tslint:disable-next-line:no-empty-interface
|
||||
interface ColorBlindnessProps {}
|
||||
|
||||
interface ColorBlindnessState {
|
||||
expanded: boolean;
|
||||
filter: string | null;
|
||||
}
|
||||
|
||||
export class ColorBlindness extends Component<ColorBlindnessProps, ColorBlindnessState> {
|
||||
state: ColorBlindnessState = {
|
||||
expanded: false,
|
||||
filter: null,
|
||||
};
|
||||
|
||||
setFilter = filter => {
|
||||
setFilter = (filter: string | null) => {
|
||||
const iframe = getIframe();
|
||||
|
||||
if (iframe) {
|
||||
@ -44,6 +52,8 @@ class ColorBlindness extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
onVisibilityChange = (s: boolean) => this.setState({ expanded: s });
|
||||
|
||||
render() {
|
||||
const { filter, expanded } = this.state;
|
||||
|
||||
@ -69,10 +79,12 @@ class ColorBlindness extends Component {
|
||||
if (filter !== null) {
|
||||
colorList = [
|
||||
{
|
||||
id: 'reset',
|
||||
title: 'Reset color filter',
|
||||
onClick: () => {
|
||||
this.setFilter(null);
|
||||
},
|
||||
right: undefined,
|
||||
},
|
||||
...colorList,
|
||||
];
|
||||
@ -83,7 +95,7 @@ class ColorBlindness extends Component {
|
||||
placement="top"
|
||||
trigger="click"
|
||||
tooltipShown={expanded}
|
||||
onVisibilityChange={s => this.setState({ expanded: s })}
|
||||
onVisibilityChange={this.onVisibilityChange}
|
||||
tooltip={<TooltipLinkList links={colorList} />}
|
||||
closeOnClick
|
||||
>
|
||||
@ -94,5 +106,3 @@ class ColorBlindness extends Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ColorBlindness;
|
@ -1,60 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import Rules from './Rules';
|
||||
|
||||
const Item = styled.li({
|
||||
fontWeight: 600,
|
||||
});
|
||||
const ItemTitle = styled.span({
|
||||
borderBottom: '1px solid rgb(130, 130, 130)',
|
||||
width: '100%',
|
||||
display: 'inline-block',
|
||||
paddingBottom: '4px',
|
||||
marginBottom: '4px',
|
||||
});
|
||||
|
||||
function Element({ element, passes }) {
|
||||
const { any, all, none } = element;
|
||||
|
||||
const rules = [...any, ...all, ...none];
|
||||
|
||||
return (
|
||||
<Item>
|
||||
<ItemTitle>{element.target[0]}</ItemTitle>
|
||||
<Rules rules={rules} passes={passes} />
|
||||
</Item>
|
||||
);
|
||||
}
|
||||
Element.propTypes = {
|
||||
element: PropTypes.shape({
|
||||
any: PropTypes.array.isRequired,
|
||||
all: PropTypes.array.isRequired,
|
||||
none: PropTypes.array.isRequired,
|
||||
}).isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
const Elements = ({ elements, passes }) => (
|
||||
<ol>
|
||||
{elements.map((element, index) => (
|
||||
<Element passes={passes} element={element} key={index} />
|
||||
))}
|
||||
</ol>
|
||||
);
|
||||
|
||||
Elements.propTypes = {
|
||||
elements: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
any: PropTypes.array.isRequired,
|
||||
all: PropTypes.array.isRequired,
|
||||
none: PropTypes.array.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default Elements;
|
48
addons/a11y/src/components/Report/Elements.tsx
Normal file
48
addons/a11y/src/components/Report/Elements.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import { NodeResult } from 'axe-core';
|
||||
import { Rules } from './Rules';
|
||||
|
||||
const Item = styled.li({
|
||||
fontWeight: 600,
|
||||
});
|
||||
const ItemTitle = styled.span({
|
||||
borderBottom: '1px solid rgb(130, 130, 130)',
|
||||
width: '100%',
|
||||
display: 'inline-block',
|
||||
paddingBottom: '4px',
|
||||
marginBottom: '4px',
|
||||
});
|
||||
|
||||
interface ElementProps {
|
||||
element: NodeResult;
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
const Element: FunctionComponent<ElementProps> = ({ element, passes }) => {
|
||||
const { any, all, none } = element;
|
||||
|
||||
const rules = [...any, ...all, ...none];
|
||||
|
||||
return (
|
||||
<Item>
|
||||
<ItemTitle>{element.target[0]}</ItemTitle>
|
||||
<Rules rules={rules} passes={passes} />
|
||||
</Item>
|
||||
);
|
||||
};
|
||||
|
||||
interface ElementsProps {
|
||||
elements: NodeResult[];
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
export const Elements: FunctionComponent<ElementsProps> = ({ elements, passes }) => (
|
||||
<ol>
|
||||
{elements.map((element, index) => (
|
||||
<Element passes={passes} element={element} key={index} />
|
||||
))}
|
||||
</ol>
|
||||
);
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
import { Result } from 'axe-core';
|
||||
|
||||
const Wrapper = styled.div(({ theme }) => ({
|
||||
backgroundColor: theme.background.bar,
|
||||
@ -18,7 +18,11 @@ const Link = styled.a({
|
||||
display: 'block',
|
||||
});
|
||||
|
||||
function Info({ item }) {
|
||||
interface InfoProps {
|
||||
item: Result;
|
||||
}
|
||||
|
||||
export const Info: FunctionComponent<InfoProps> = ({ item }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Help>{item.help}</Help>
|
||||
@ -27,13 +31,4 @@ function Info({ item }) {
|
||||
</Link>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
Info.propTypes = {
|
||||
item: PropTypes.shape({
|
||||
help: PropTypes.node,
|
||||
helpUrl: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
export default Info;
|
@ -1,16 +1,16 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
import { Icons } from '@storybook/components';
|
||||
|
||||
import Info from './Info';
|
||||
import Tags from './Tags';
|
||||
import Elements from './Elements';
|
||||
import { Result } from 'axe-core';
|
||||
import { Info } from './Info';
|
||||
import { Elements } from './Elements';
|
||||
import { Tags } from './Tags';
|
||||
|
||||
const Wrapper = styled.div();
|
||||
|
||||
const Icon = styled(Icons)(({ theme }) => ({
|
||||
const Icon = styled<any, any>(Icons)(({ theme }) => ({
|
||||
height: 10,
|
||||
width: 10,
|
||||
color: theme.color.mediumdark,
|
||||
@ -37,16 +37,16 @@ const HeaderBar = styled.button(({ theme }) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
class Item extends Component {
|
||||
static propTypes = {
|
||||
item: PropTypes.shape({
|
||||
description: PropTypes.string,
|
||||
nodes: PropTypes.array,
|
||||
tags: PropTypes.array,
|
||||
}).isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
interface ItemProps {
|
||||
item: Result;
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
interface ItemState {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
export class Item extends Component<ItemProps, ItemState> {
|
||||
state = {
|
||||
open: false,
|
||||
};
|
||||
@ -84,5 +84,3 @@ class Item extends Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Item;
|
@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import { Icons } from '@storybook/components';
|
||||
import { CheckResult } from 'axe-core';
|
||||
|
||||
const impactColors = {
|
||||
minor: '#f1c40f',
|
||||
@ -17,7 +17,7 @@ const List = styled.div({
|
||||
flexDirection: 'column',
|
||||
padding: '4px',
|
||||
fontWeight: '400',
|
||||
});
|
||||
} as any);
|
||||
|
||||
const Item = styled.div({
|
||||
display: 'flex',
|
||||
@ -29,7 +29,7 @@ const Message = styled.div({
|
||||
paddingLeft: '6px',
|
||||
});
|
||||
|
||||
const Status = styled.div(({ passes, impact }) => ({
|
||||
const Status = styled.div(({ passes, impact }: { passes: boolean; impact: string }) => ({
|
||||
height: '16px',
|
||||
width: '16px',
|
||||
borderRadius: '8px',
|
||||
@ -39,10 +39,15 @@ const Status = styled.div(({ passes, impact }) => ({
|
||||
alignItems: 'center',
|
||||
textAlign: 'center',
|
||||
flex: '0 0 16px',
|
||||
color: passes ? impactColors.success : impactColors[impact],
|
||||
color: passes ? impactColors.success : (impactColors as any)[impact],
|
||||
}));
|
||||
|
||||
const Rule = ({ rule, passes }) => (
|
||||
interface RuleProps {
|
||||
rule: CheckResult;
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
const Rule: FunctionComponent<RuleProps> = ({ rule, passes }) => (
|
||||
<Item>
|
||||
<Status passes={passes || undefined} impact={rule.impact}>
|
||||
{passes ? <Icons icon="check" /> : <Icons icon="cross" />}
|
||||
@ -51,15 +56,12 @@ const Rule = ({ rule, passes }) => (
|
||||
</Item>
|
||||
);
|
||||
|
||||
Rule.propTypes = {
|
||||
rule: PropTypes.shape({
|
||||
message: PropTypes.node,
|
||||
}).isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
interface RulesProps {
|
||||
rules: CheckResult[];
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
function Rules({ rules, passes }) {
|
||||
export const Rules: FunctionComponent<RulesProps> = ({ rules, passes }) => {
|
||||
return (
|
||||
<List>
|
||||
{rules.map((rule, index) => (
|
||||
@ -67,14 +69,4 @@ function Rules({ rules, passes }) {
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
Rules.propTypes = {
|
||||
rules: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
message: PropTypes.node,
|
||||
})
|
||||
).isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default Rules;
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
import { TagValue } from 'axe-core';
|
||||
|
||||
const Wrapper = styled.div({
|
||||
display: 'flex',
|
||||
@ -16,7 +16,11 @@ const Item = styled.div(({ theme }) => ({
|
||||
borderRadius: theme.appBorderRadius,
|
||||
}));
|
||||
|
||||
function Tags({ tags }) {
|
||||
interface TagsProps {
|
||||
tags: TagValue[];
|
||||
}
|
||||
|
||||
export const Tags: FunctionComponent<TagsProps> = ({ tags }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
{tags.map(tag => (
|
||||
@ -24,9 +28,4 @@ function Tags({ tags }) {
|
||||
))}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
Tags.propTypes = {
|
||||
tags: PropTypes.arrayOf(PropTypes.node).isRequired,
|
||||
};
|
||||
|
||||
export default Tags;
|
@ -1,29 +0,0 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Placeholder } from '@storybook/components';
|
||||
|
||||
import Item from './Item';
|
||||
|
||||
const Report = ({ items, empty, passes }) => (
|
||||
<Fragment>
|
||||
{items.length ? (
|
||||
items.map(item => <Item passes={passes} item={item} key={item.id} />)
|
||||
) : (
|
||||
<Placeholder key="placeholder">{empty}</Placeholder>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
Report.propTypes = {
|
||||
items: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
description: PropTypes.string,
|
||||
nodes: PropTypes.array,
|
||||
tags: PropTypes.array,
|
||||
})
|
||||
).isRequired,
|
||||
empty: PropTypes.string.isRequired,
|
||||
passes: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default Report;
|
21
addons/a11y/src/components/Report/index.tsx
Normal file
21
addons/a11y/src/components/Report/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { Fragment, FunctionComponent } from 'react';
|
||||
import { Placeholder } from '@storybook/components';
|
||||
|
||||
import { Result } from 'axe-core';
|
||||
import { Item } from './Item';
|
||||
|
||||
export interface ReportProps {
|
||||
items: Result[];
|
||||
empty: string;
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
export const Report: FunctionComponent<ReportProps> = ({ items, empty, passes }) => (
|
||||
<Fragment>
|
||||
{items.length ? (
|
||||
items.map(item => <Item passes={passes} item={item} key={item.id} />)
|
||||
) : (
|
||||
<Placeholder key="placeholder">{empty}</Placeholder>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
@ -1,5 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
// TODO: reuse the Tabs component from @storybook/theming instead
|
||||
@ -37,7 +36,7 @@ const Item = styled.button(
|
||||
borderBottom: `3px solid ${theme.color.secondary}`,
|
||||
},
|
||||
}),
|
||||
({ active, theme }) =>
|
||||
({ active, theme }: any) =>
|
||||
active
|
||||
? {
|
||||
opacity: 1,
|
||||
@ -46,12 +45,23 @@ const Item = styled.button(
|
||||
: {}
|
||||
);
|
||||
|
||||
class Tabs extends Component {
|
||||
state = {
|
||||
interface TabsProps {
|
||||
tabs: Array<{
|
||||
label: JSX.Element;
|
||||
panel: JSX.Element;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface TabsState {
|
||||
active: number;
|
||||
}
|
||||
|
||||
export class Tabs extends Component<TabsProps, TabsState> {
|
||||
state: TabsState = {
|
||||
active: 0,
|
||||
};
|
||||
|
||||
onToggle = index => {
|
||||
onToggle = (index: number) => {
|
||||
this.setState({
|
||||
active: index,
|
||||
});
|
||||
@ -80,14 +90,3 @@ class Tabs extends Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Tabs.propTypes = {
|
||||
tabs: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.node,
|
||||
panel: PropTypes.node,
|
||||
})
|
||||
).isRequired,
|
||||
};
|
||||
|
||||
export default Tabs;
|
@ -5,4 +5,4 @@ export const PARAM_KEY = `a11y`;
|
||||
const RESULT = `${ADDON_ID}/result`;
|
||||
const REQUEST = `${ADDON_ID}/request`;
|
||||
|
||||
export default { RESULT, REQUEST };
|
||||
export const EVENTS = { RESULT, REQUEST };
|
@ -1,15 +1,15 @@
|
||||
import { document } from 'global';
|
||||
import axe from 'axe-core';
|
||||
import axe, { AxeResults, RunOptions, Spec } from 'axe-core';
|
||||
import deprecate from 'util-deprecate';
|
||||
import { stripIndents } from 'common-tags';
|
||||
|
||||
import addons from '@storybook/addons';
|
||||
import addons, { StoryWrapper } from '@storybook/addons';
|
||||
import { STORY_RENDERED } from '@storybook/core-events';
|
||||
import EVENTS, { PARAM_KEY } from './constants';
|
||||
import { EVENTS, PARAM_KEY } from './constants';
|
||||
|
||||
const channel = addons.getChannel();
|
||||
let progress = Promise.resolve();
|
||||
let setup = {};
|
||||
let setup: { config: Spec; options: RunOptions } = { config: {}, options: {} };
|
||||
|
||||
const getElement = () => {
|
||||
const storyRoot = document.getElementById('story-root');
|
||||
@ -20,11 +20,11 @@ const getElement = () => {
|
||||
return document.getElementById('root');
|
||||
};
|
||||
|
||||
const report = input => {
|
||||
const report = (input: AxeResults) => {
|
||||
channel.emit(EVENTS.RESULT, input);
|
||||
};
|
||||
|
||||
const run = (config, options) => {
|
||||
const run = (config: Spec, options: RunOptions) => {
|
||||
progress = progress.then(() => {
|
||||
axe.reset();
|
||||
if (config) {
|
||||
@ -33,16 +33,18 @@ const run = (config, options) => {
|
||||
return axe
|
||||
.run(
|
||||
getElement(),
|
||||
options || {
|
||||
restoreScroll: true,
|
||||
}
|
||||
options ||
|
||||
// tslint:disable-next-line:no-object-literal-type-assertion
|
||||
({
|
||||
restoreScroll: true,
|
||||
} as RunOptions) // cast to RunOptions is necessary because axe types are not up to date
|
||||
)
|
||||
.then(report);
|
||||
});
|
||||
};
|
||||
|
||||
// NOTE: we should add paramaters to the STORY_RENDERED event and deprecate this
|
||||
export const withA11y = (getStory, context) => {
|
||||
export const withA11y: StoryWrapper = (getStory, context) => {
|
||||
const params = context.parameters[PARAM_KEY];
|
||||
if (params) {
|
||||
setup = params;
|
||||
@ -59,19 +61,21 @@ if (module && module.hot && module.hot.decline) {
|
||||
|
||||
// TODO: REMOVE at v6.0.0
|
||||
export const withA11Y = deprecate(
|
||||
(...args) => withA11y(...args),
|
||||
// @ts-ignore
|
||||
(...args: any[]) => withA11y(...args),
|
||||
'withA11Y has been renamed withA11y'
|
||||
);
|
||||
|
||||
// TODO: REMOVE at v6.0.0
|
||||
export const checkA11y = deprecate(
|
||||
(...args) => withA11y(...args),
|
||||
// @ts-ignore
|
||||
(...args: any[]) => withA11y(...args),
|
||||
'checkA11y has been renamed withA11y'
|
||||
);
|
||||
|
||||
// TODO: REMOVE at v6.0.0
|
||||
export const configureA11y = deprecate(
|
||||
config => {
|
||||
(config: any) => {
|
||||
setup = config;
|
||||
},
|
||||
stripIndents`
|
@ -1,17 +1,16 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import addons, { types } from '@storybook/addons';
|
||||
import React, { Fragment, FunctionComponent } from 'react';
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import Panel from './components/Panel';
|
||||
import ColorBlindness from './components/ColorBlindness';
|
||||
|
||||
import { ADDON_ID, PANEL_ID } from './constants';
|
||||
import { ColorBlindness } from './components/ColorBlindness';
|
||||
import { A11YPanel } from './components/A11YPanel';
|
||||
import { addons, types } from '@storybook/addons';
|
||||
|
||||
const Hidden = styled.div(() => ({
|
||||
display: 'none',
|
||||
}));
|
||||
|
||||
const PreviewWrapper = p => (
|
||||
const PreviewWrapper: FunctionComponent<{}> = p => (
|
||||
<Fragment>
|
||||
{p.children}
|
||||
<Hidden>
|
||||
@ -81,20 +80,21 @@ const PreviewWrapper = p => (
|
||||
|
||||
addons.register(ADDON_ID, api => {
|
||||
addons.add(PANEL_ID, {
|
||||
title: '',
|
||||
type: types.TOOL,
|
||||
match: ({ viewMode }) => viewMode === 'story',
|
||||
render: () => <ColorBlindness />,
|
||||
});
|
||||
|
||||
addons.add(PANEL_ID, {
|
||||
type: types.PANEL,
|
||||
title: 'Accessibility',
|
||||
// eslint-disable-next-line react/prop-types
|
||||
render: ({ active, key }) => <Panel key={key} api={api} active={active} />,
|
||||
type: types.PANEL,
|
||||
render: ({ active, key }) => <A11YPanel key={key} api={api} active={active} />,
|
||||
});
|
||||
|
||||
addons.add(PANEL_ID, {
|
||||
title: '',
|
||||
type: types.PREVIEW,
|
||||
render: PreviewWrapper,
|
||||
render: PreviewWrapper as any,
|
||||
});
|
||||
});
|
3
addons/a11y/src/typings.d.ts
vendored
Normal file
3
addons/a11y/src/typings.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: following packages need definition files or a TS migration
|
||||
declare module '@storybook/components';
|
||||
declare module 'global';
|
13
addons/a11y/tsconfig.json
Normal file
13
addons/a11y/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"types": ["webpack-env"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"src/__tests__/**/*"
|
||||
]
|
||||
}
|
@ -40,7 +40,7 @@ addDecorator(storyFn => (
|
||||
|
||||
addParameters({
|
||||
a11y: {
|
||||
configure: {},
|
||||
config: {},
|
||||
options: {
|
||||
checks: { 'color-contrast': { options: { noScroll: true } } },
|
||||
restoreScroll: true,
|
||||
|
@ -5196,7 +5196,7 @@ exports[`Storyshots Core|Parameters passed to story 1`] = `
|
||||
<pre>
|
||||
Parameters are {
|
||||
"a11y": {
|
||||
"configure": {},
|
||||
"config": {},
|
||||
"options": {
|
||||
"checks": {
|
||||
"color-contrast": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user