From e4cf45cce874ed05026e023411c794797888a0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 19 Feb 2019 20:53:38 +0100 Subject: [PATCH 1/7] chore: add tsconfig in addons/a11y --- addons/a11y/tsconfig.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 addons/a11y/tsconfig.json diff --git a/addons/a11y/tsconfig.json b/addons/a11y/tsconfig.json new file mode 100644 index 000000000000..8876bb6737a1 --- /dev/null +++ b/addons/a11y/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/__tests__/**/*" + ] +} From 76029c9400cba6c53da8bb1eb9d5249f731fb487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 19 Feb 2019 21:36:00 +0100 Subject: [PATCH 2/7] chore: migrate src of addons/a11y to Typescript --- addons/a11y/package.json | 5 +++- .../{ColorBlindness.js => ColorBlindness.tsx} | 8 +++--- .../src/components/{Panel.js => Panel.tsx} | 12 ++++---- .../Report/{Elements.js => Elements.tsx} | 6 ++-- .../components/Report/{Info.js => Info.tsx} | 2 +- .../components/Report/{Item.js => Item.tsx} | 6 ++-- .../components/Report/{Rules.js => Rules.tsx} | 12 ++++---- .../components/Report/{Tags.js => Tags.tsx} | 4 +-- .../components/Report/{index.js => index.tsx} | 4 +-- .../a11y/src/components/{Tabs.js => Tabs.tsx} | 12 ++++---- .../a11y/src/{constants.js => constants.ts} | 0 addons/a11y/src/{index.js => index.ts} | 28 +++++++++++-------- addons/a11y/src/{register.js => register.tsx} | 8 +++--- addons/a11y/src/typings.d.ts | 3 ++ 14 files changed, 60 insertions(+), 50 deletions(-) rename addons/a11y/src/components/{ColorBlindness.js => ColorBlindness.tsx} (93%) rename addons/a11y/src/components/{Panel.js => Panel.tsx} (94%) rename addons/a11y/src/components/Report/{Elements.js => Elements.tsx} (89%) rename addons/a11y/src/components/Report/{Info.js => Info.tsx} (95%) rename addons/a11y/src/components/Report/{Item.js => Item.tsx} (93%) rename addons/a11y/src/components/Report/{Rules.js => Rules.tsx} (84%) rename addons/a11y/src/components/Report/{Tags.js => Tags.tsx} (89%) rename addons/a11y/src/components/Report/{index.js => index.tsx} (81%) rename addons/a11y/src/components/{Tabs.js => Tabs.tsx} (89%) rename addons/a11y/src/{constants.js => constants.ts} (100%) rename addons/a11y/src/{index.js => index.ts} (72%) rename addons/a11y/src/{register.js => register.tsx} (96%) create mode 100644 addons/a11y/src/typings.d.ts diff --git a/addons/a11y/package.json b/addons/a11y/package.json index 281923dcf153..7743d15931d3 100644 --- a/addons/a11y/package.json +++ b/addons/a11y/package.json @@ -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" }, @@ -40,6 +40,9 @@ "react": "^16.8.3", "util-deprecate": "^1.0.2" }, + "devDependencies": { + "@types/common-tags": "^1.8.0" + }, "publishConfig": { "access": "public" } diff --git a/addons/a11y/src/components/ColorBlindness.js b/addons/a11y/src/components/ColorBlindness.tsx similarity index 93% rename from addons/a11y/src/components/ColorBlindness.js rename to addons/a11y/src/components/ColorBlindness.tsx index 375b9a723d45..63fafd1e383f 100644 --- a/addons/a11y/src/components/ColorBlindness.js +++ b/addons/a11y/src/components/ColorBlindness.tsx @@ -16,7 +16,7 @@ const ColorIcon = styled.span( height: '1rem', width: '1rem', }, - ({ filter }) => ({ + ({ filter }: any) => ({ filter: filter === 'mono' ? 'grayscale(100%)' : `url('#${filter}')`, }), ({ theme }) => ({ @@ -30,7 +30,7 @@ class ColorBlindness extends Component { filter: null, }; - setFilter = filter => { + setFilter = (filter: any) => { const iframe = getIframe(); if (iframe) { @@ -73,7 +73,7 @@ class ColorBlindness extends Component { onClick: () => { this.setFilter(null); }, - }, + } as any, ...colorList, ]; } @@ -83,7 +83,7 @@ class ColorBlindness extends Component { placement="top" trigger="click" tooltipShown={expanded} - onVisibilityChange={s => this.setState({ expanded: s })} + onVisibilityChange={(s: any) => this.setState({ expanded: s })} tooltip={} closeOnClick > diff --git a/addons/a11y/src/components/Panel.js b/addons/a11y/src/components/Panel.tsx similarity index 94% rename from addons/a11y/src/components/Panel.js rename to addons/a11y/src/components/Panel.tsx index 2898eb45def6..ba0eef9def2b 100644 --- a/addons/a11y/src/components/Panel.js +++ b/addons/a11y/src/components/Panel.tsx @@ -18,7 +18,7 @@ const Icon = styled(Icons)( width: '12px', marginRight: '4px', }, - ({ status, theme }) => + ({ status, theme }: any) => status === 'running' ? { animation: `${theme.animation.rotate360} 1s linear infinite;`, @@ -34,7 +34,7 @@ const Violations = styled.span(({ theme }) => ({ color: theme.color.negative, })); -class A11YPanel extends Component { +class A11YPanel extends Component { static propTypes = { active: PropTypes.bool.isRequired, api: PropTypes.shape({ @@ -46,8 +46,8 @@ class A11YPanel extends Component { state = { status: 'ready', - passes: [], - violations: [], + passes: [] as any[], + violations: [] as any[], }; componentDidMount() { @@ -57,7 +57,7 @@ class A11YPanel extends Component { api.on(EVENTS.RESULT, this.onUpdate); } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: any) { // TODO: might be able to remove this const { active } = this.props; @@ -73,7 +73,7 @@ class A11YPanel extends Component { api.off(EVENTS.RESULT, this.onUpdate); } - onUpdate = ({ passes, violations }) => { + onUpdate = ({ passes, violations }: any) => { this.setState( { status: 'ran', diff --git a/addons/a11y/src/components/Report/Elements.js b/addons/a11y/src/components/Report/Elements.tsx similarity index 89% rename from addons/a11y/src/components/Report/Elements.js rename to addons/a11y/src/components/Report/Elements.tsx index c8ba249e775a..850906bbc991 100644 --- a/addons/a11y/src/components/Report/Elements.js +++ b/addons/a11y/src/components/Report/Elements.tsx @@ -16,7 +16,7 @@ const ItemTitle = styled.span({ marginBottom: '4px', }); -function Element({ element, passes }) { +function Element({ element, passes }: any) { const { any, all, none } = element; const rules = [...any, ...all, ...none]; @@ -38,9 +38,9 @@ Element.propTypes = { }; /* eslint-disable react/no-array-index-key */ -const Elements = ({ elements, passes }) => ( +const Elements = ({ elements, passes }: any) => (
    - {elements.map((element, index) => ( + {elements.map((element: any, index: any) => ( ))}
diff --git a/addons/a11y/src/components/Report/Info.js b/addons/a11y/src/components/Report/Info.tsx similarity index 95% rename from addons/a11y/src/components/Report/Info.js rename to addons/a11y/src/components/Report/Info.tsx index 56054a38286b..e6a6d6c6b80c 100644 --- a/addons/a11y/src/components/Report/Info.js +++ b/addons/a11y/src/components/Report/Info.tsx @@ -18,7 +18,7 @@ const Link = styled.a({ display: 'block', }); -function Info({ item }) { +function Info({ item }: any) { return ( {item.help} diff --git a/addons/a11y/src/components/Report/Item.js b/addons/a11y/src/components/Report/Item.tsx similarity index 93% rename from addons/a11y/src/components/Report/Item.js rename to addons/a11y/src/components/Report/Item.tsx index 69dbddaea69e..a0e2efd606d7 100644 --- a/addons/a11y/src/components/Report/Item.js +++ b/addons/a11y/src/components/Report/Item.tsx @@ -10,7 +10,7 @@ import Elements from './Elements'; const Wrapper = styled.div(); -const Icon = styled(Icons)(({ theme }) => ({ +const Icon = styled(Icons)(({ theme }) => ({ height: 10, width: 10, color: theme.color.mediumdark, @@ -37,7 +37,7 @@ const HeaderBar = styled.button(({ theme }) => ({ }, })); -class Item extends Component { +class Item extends Component { static propTypes = { item: PropTypes.shape({ description: PropTypes.string, @@ -52,7 +52,7 @@ class Item extends Component { }; onToggle = () => - this.setState(prevState => ({ + this.setState((prevState: any) => ({ open: !prevState.open, })); diff --git a/addons/a11y/src/components/Report/Rules.js b/addons/a11y/src/components/Report/Rules.tsx similarity index 84% rename from addons/a11y/src/components/Report/Rules.js rename to addons/a11y/src/components/Report/Rules.tsx index 10989e555643..224cd1c44927 100644 --- a/addons/a11y/src/components/Report/Rules.js +++ b/addons/a11y/src/components/Report/Rules.tsx @@ -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 }: any) => ({ height: '16px', width: '16px', borderRadius: '8px', @@ -39,10 +39,10 @@ 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 }) => ( +const Rule = ({ rule, passes }: any) => ( {passes ? : } @@ -59,10 +59,10 @@ Rule.propTypes = { }; /* eslint-disable react/no-array-index-key */ -function Rules({ rules, passes }) { +function Rules({ rules, passes }: any) { return ( - {rules.map((rule, index) => ( + {rules.map((rule: any, index: any) => ( ))} diff --git a/addons/a11y/src/components/Report/Tags.js b/addons/a11y/src/components/Report/Tags.tsx similarity index 89% rename from addons/a11y/src/components/Report/Tags.js rename to addons/a11y/src/components/Report/Tags.tsx index 0ef1d2b2e32d..b910a644448f 100644 --- a/addons/a11y/src/components/Report/Tags.js +++ b/addons/a11y/src/components/Report/Tags.tsx @@ -16,10 +16,10 @@ const Item = styled.div(({ theme }) => ({ borderRadius: theme.appBorderRadius, })); -function Tags({ tags }) { +function Tags({ tags }: any) { return ( - {tags.map(tag => ( + {tags.map((tag: any) => ( {tag} ))} diff --git a/addons/a11y/src/components/Report/index.js b/addons/a11y/src/components/Report/index.tsx similarity index 81% rename from addons/a11y/src/components/Report/index.js rename to addons/a11y/src/components/Report/index.tsx index 3a9bdb9fbe2c..1eca0267e934 100644 --- a/addons/a11y/src/components/Report/index.js +++ b/addons/a11y/src/components/Report/index.tsx @@ -4,10 +4,10 @@ import { Placeholder } from '@storybook/components'; import Item from './Item'; -const Report = ({ items, empty, passes }) => ( +const Report = ({ items, empty, passes }: any) => ( {items.length ? ( - items.map(item => ) + items.map((item: any) => ) ) : ( {empty} )} diff --git a/addons/a11y/src/components/Tabs.js b/addons/a11y/src/components/Tabs.tsx similarity index 89% rename from addons/a11y/src/components/Tabs.js rename to addons/a11y/src/components/Tabs.tsx index 43568a96ce2e..49bf8c6549a4 100644 --- a/addons/a11y/src/components/Tabs.js +++ b/addons/a11y/src/components/Tabs.tsx @@ -37,7 +37,7 @@ const Item = styled.button( borderBottom: `3px solid ${theme.color.secondary}`, }, }), - ({ active, theme }) => + ({ active, theme }: any) => active ? { opacity: 1, @@ -46,25 +46,25 @@ const Item = styled.button( : {} ); -class Tabs extends Component { +class Tabs extends Component { state = { active: 0, }; - onToggle = index => { + onToggle = (index: any) => { this.setState({ active: index, }); }; render() { - const { tabs } = this.props; + const { tabs } = this.props as any; const { active } = this.state; return ( - {tabs.map((tab, index) => ( + {tabs.map((tab: any, index: any) => ( { const storyRoot = document.getElementById('story-root'); @@ -20,11 +20,11 @@ const getElement = () => { return document.getElementById('root'); }; -const report = input => { +const report = (input: any) => { 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` diff --git a/addons/a11y/src/register.js b/addons/a11y/src/register.tsx similarity index 96% rename from addons/a11y/src/register.js rename to addons/a11y/src/register.tsx index 5e48441705fa..64f0cd10f618 100644 --- a/addons/a11y/src/register.js +++ b/addons/a11y/src/register.tsx @@ -11,7 +11,7 @@ const Hidden = styled.div(() => ({ display: 'none', })); -const PreviewWrapper = p => ( +const PreviewWrapper = (p: any) => ( {p.children} @@ -82,9 +82,9 @@ const PreviewWrapper = p => ( addons.register(ADDON_ID, api => { addons.add(PANEL_ID, { type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode }: any) => viewMode === 'story', render: () => , - }); + } as any); addons.add(PANEL_ID, { type: types.PANEL, @@ -96,5 +96,5 @@ addons.register(ADDON_ID, api => { addons.add(PANEL_ID, { type: types.PREVIEW, render: PreviewWrapper, - }); + } as any); }); diff --git a/addons/a11y/src/typings.d.ts b/addons/a11y/src/typings.d.ts new file mode 100644 index 000000000000..1cebcd2c971a --- /dev/null +++ b/addons/a11y/src/typings.d.ts @@ -0,0 +1,3 @@ +// TODO: following packages need definition files or a TS migration +declare module '@storybook/components'; +declare module 'global'; From d7ad26e90e528d5a3d238d56eb3781292d6f7c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Sun, 24 Feb 2019 17:37:16 +0100 Subject: [PATCH 3/7] chore: type src of addons/a11y --- addons/a11y/src/components/ColorBlindness.tsx | 22 +++++++--- addons/a11y/src/components/Panel.tsx | 34 +++++++++------- .../a11y/src/components/Report/Elements.tsx | 40 +++++++------------ addons/a11y/src/components/Report/Info.tsx | 17 ++++---- addons/a11y/src/components/Report/Item.tsx | 22 +++++----- addons/a11y/src/components/Report/Rules.tsx | 36 +++++++---------- addons/a11y/src/components/Report/Tags.tsx | 15 +++---- addons/a11y/src/components/Report/index.tsx | 26 +++++------- addons/a11y/src/components/Tabs.tsx | 31 +++++++------- addons/a11y/src/index.ts | 8 ++-- addons/a11y/src/register.tsx | 17 ++++---- 11 files changed, 131 insertions(+), 137 deletions(-) diff --git a/addons/a11y/src/components/ColorBlindness.tsx b/addons/a11y/src/components/ColorBlindness.tsx index 63fafd1e383f..95d8859e4174 100644 --- a/addons/a11y/src/components/ColorBlindness.tsx +++ b/addons/a11y/src/components/ColorBlindness.tsx @@ -16,7 +16,7 @@ const ColorIcon = styled.span( height: '1rem', width: '1rem', }, - ({ filter }: any) => ({ + ({ 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; +} + +class ColorBlindness extends Component { + state: ColorBlindnessState = { expanded: false, filter: null, }; - setFilter = (filter: any) => { + setFilter = (filter: string | null) => { const iframe = getIframe(); if (iframe) { @@ -69,11 +77,13 @@ class ColorBlindness extends Component { if (filter !== null) { colorList = [ { + id: 'reset', title: 'Reset color filter', onClick: () => { this.setFilter(null); }, - } as any, + right: undefined, + }, ...colorList, ]; } @@ -83,7 +93,7 @@ class ColorBlindness extends Component { placement="top" trigger="click" tooltipShown={expanded} - onVisibilityChange={(s: any) => this.setState({ expanded: s })} + onVisibilityChange={(s: boolean) => this.setState({ expanded: s })} tooltip={} closeOnClick > diff --git a/addons/a11y/src/components/Panel.tsx b/addons/a11y/src/components/Panel.tsx index ba0eef9def2b..4f0c1fb0fd83 100644 --- a/addons/a11y/src/components/Panel.tsx +++ b/addons/a11y/src/components/Panel.tsx @@ -1,5 +1,4 @@ import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; import { styled } from '@storybook/theming'; @@ -11,6 +10,7 @@ import EVENTS from '../constants'; import Tabs from './Tabs'; import Report from './Report'; +import { AxeResults, Result } from 'axe-core'; const Icon = styled(Icons)( { @@ -34,20 +34,26 @@ 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[]; +} + +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; }; +} - state = { +class A11YPanel extends Component { + state: A11YPanelState = { status: 'ready', - passes: [] as any[], - violations: [] as any[], + passes: [], + violations: [], }; componentDidMount() { @@ -57,7 +63,7 @@ class A11YPanel extends Component { api.on(EVENTS.RESULT, this.onUpdate); } - componentDidUpdate(prevProps: any) { + componentDidUpdate(prevProps: A11YPanelProps) { // TODO: might be able to remove this const { active } = this.props; @@ -73,7 +79,7 @@ class A11YPanel extends Component { api.off(EVENTS.RESULT, this.onUpdate); } - onUpdate = ({ passes, violations }: any) => { + onUpdate = ({ passes, violations }: AxeResults) => { this.setState( { status: 'ran', diff --git a/addons/a11y/src/components/Report/Elements.tsx b/addons/a11y/src/components/Report/Elements.tsx index 850906bbc991..3e43739c1942 100644 --- a/addons/a11y/src/components/Report/Elements.tsx +++ b/addons/a11y/src/components/Report/Elements.tsx @@ -1,9 +1,9 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { FunctionComponent } from 'react'; import { styled } from '@storybook/theming'; import Rules from './Rules'; +import { NodeResult } from 'axe-core'; const Item = styled.li({ fontWeight: 600, @@ -16,7 +16,12 @@ const ItemTitle = styled.span({ marginBottom: '4px', }); -function Element({ element, passes }: any) { +interface ElementProps { + element: NodeResult; + passes: boolean; +} + +const Element: FunctionComponent = ({ element, passes }) => { const { any, all, none } = element; const rules = [...any, ...all, ...none]; @@ -27,34 +32,19 @@ function Element({ element, passes }: any) { ); -} -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 }: any) => ( +interface ElementsProps { + elements: NodeResult[]; + passes: boolean; +} + +const Elements: FunctionComponent = ({ elements, passes }) => (
    - {elements.map((element: any, index: any) => ( + {elements.map((element, index) => ( ))}
); -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; diff --git a/addons/a11y/src/components/Report/Info.tsx b/addons/a11y/src/components/Report/Info.tsx index e6a6d6c6b80c..26ba2b126e55 100644 --- a/addons/a11y/src/components/Report/Info.tsx +++ b/addons/a11y/src/components/Report/Info.tsx @@ -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 }: any) { +interface InfoProps { + item: Result; +} + +const Info: FunctionComponent = ({ item }) => { return ( {item.help} @@ -27,13 +31,6 @@ function Info({ item }: any) { ); -} - -Info.propTypes = { - item: PropTypes.shape({ - help: PropTypes.node, - helpUrl: PropTypes.string, - }).isRequired, }; export default Info; diff --git a/addons/a11y/src/components/Report/Item.tsx b/addons/a11y/src/components/Report/Item.tsx index a0e2efd606d7..d132a6cfd7b8 100644 --- a/addons/a11y/src/components/Report/Item.tsx +++ b/addons/a11y/src/components/Report/Item.tsx @@ -1,5 +1,4 @@ import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; import { styled } from '@storybook/theming'; import { Icons } from '@storybook/components'; @@ -7,6 +6,7 @@ import { Icons } from '@storybook/components'; import Info from './Info'; import Tags from './Tags'; import Elements from './Elements'; +import { Result } from 'axe-core'; const Wrapper = styled.div(); @@ -37,22 +37,22 @@ 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; +} +class Item extends Component { state = { open: false, }; onToggle = () => - this.setState((prevState: any) => ({ + this.setState(prevState => ({ open: !prevState.open, })); diff --git a/addons/a11y/src/components/Report/Rules.tsx b/addons/a11y/src/components/Report/Rules.tsx index 224cd1c44927..e443d52d6b8e 100644 --- a/addons/a11y/src/components/Report/Rules.tsx +++ b/addons/a11y/src/components/Report/Rules.tsx @@ -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', @@ -29,7 +29,7 @@ const Message = styled.div({ paddingLeft: '6px', }); -const Status = styled.div(({ passes, impact }: any) => ({ +const Status = styled.div(({ passes, impact }: { passes: boolean; impact: string }) => ({ height: '16px', width: '16px', borderRadius: '8px', @@ -42,7 +42,12 @@ const Status = styled.div(({ passes, impact }: any) => ({ color: passes ? impactColors.success : (impactColors as any)[impact], })); -const Rule = ({ rule, passes }: any) => ( +interface RuleProps { + rule: CheckResult; + passes: boolean; +} + +const Rule: FunctionComponent = ({ rule, passes }) => ( {passes ? : } @@ -51,30 +56,19 @@ const Rule = ({ rule, passes }: any) => ( ); -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 }: any) { +const Rules: FunctionComponent = ({ rules, passes }) => { return ( - {rules.map((rule: any, index: any) => ( + {rules.map((rule, index) => ( ))} ); -} -Rules.propTypes = { - rules: PropTypes.arrayOf( - PropTypes.shape({ - message: PropTypes.node, - }) - ).isRequired, - passes: PropTypes.bool.isRequired, }; export default Rules; diff --git a/addons/a11y/src/components/Report/Tags.tsx b/addons/a11y/src/components/Report/Tags.tsx index b910a644448f..26ea062d2eea 100644 --- a/addons/a11y/src/components/Report/Tags.tsx +++ b/addons/a11y/src/components/Report/Tags.tsx @@ -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,17 +16,18 @@ const Item = styled.div(({ theme }) => ({ borderRadius: theme.appBorderRadius, })); -function Tags({ tags }: any) { +interface TagsProps { + tags: TagValue[]; +} + +const Tags: FunctionComponent = ({ tags }) => { return ( - {tags.map((tag: any) => ( + {tags.map(tag => ( {tag} ))} ); -} -Tags.propTypes = { - tags: PropTypes.arrayOf(PropTypes.node).isRequired, }; export default Tags; diff --git a/addons/a11y/src/components/Report/index.tsx b/addons/a11y/src/components/Report/index.tsx index 1eca0267e934..c37b4a27cd32 100644 --- a/addons/a11y/src/components/Report/index.tsx +++ b/addons/a11y/src/components/Report/index.tsx @@ -1,29 +1,23 @@ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; +import React, { Fragment, FunctionComponent } from 'react'; import { Placeholder } from '@storybook/components'; import Item from './Item'; +import { Result } from 'axe-core'; -const Report = ({ items, empty, passes }: any) => ( +export interface ReportProps { + items: Result[]; + empty: string; + passes: boolean; +} + +const Report: FunctionComponent = ({ items, empty, passes }) => ( {items.length ? ( - items.map((item: any) => ) + items.map((item) => ) ) : ( {empty} )} ); -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; diff --git a/addons/a11y/src/components/Tabs.tsx b/addons/a11y/src/components/Tabs.tsx index 49bf8c6549a4..c442fe015925 100644 --- a/addons/a11y/src/components/Tabs.tsx +++ b/addons/a11y/src/components/Tabs.tsx @@ -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 @@ -46,25 +45,36 @@ const Item = styled.button( : {} ); -class Tabs extends Component { - state = { +interface TabsProps { + tabs: Array<{ + label: JSX.Element; + panel: JSX.Element; + }>; +} + +interface TabsState { + active: number; +} + +class Tabs extends Component { + state: TabsState = { active: 0, }; - onToggle = (index: any) => { + onToggle = (index: number) => { this.setState({ active: index, }); }; render() { - const { tabs } = this.props as any; + const { tabs } = this.props; const { active } = this.state; return ( - {tabs.map((tab: any, index: any) => ( + {tabs.map((tab, index) => ( { } } -(Tabs as any).propTypes = { - tabs: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.node, - panel: PropTypes.node, - }) - ).isRequired, -}; - export default Tabs; diff --git a/addons/a11y/src/index.ts b/addons/a11y/src/index.ts index 2e7161bdf206..43f4efcf1a67 100644 --- a/addons/a11y/src/index.ts +++ b/addons/a11y/src/index.ts @@ -1,15 +1,15 @@ import { document } from 'global'; -import axe, { RunOptions, Spec } from 'axe-core'; +import axe, { AxeResults, RunOptions, Spec } from 'axe-core'; import deprecate from 'util-deprecate'; import { stripIndents } from 'common-tags'; -import addons, { StoryGetter, StoryWrapper } from '@storybook/addons'; +import addons, { StoryWrapper } from '@storybook/addons'; import { STORY_RENDERED } from '@storybook/core-events'; import EVENTS, { PARAM_KEY } from './constants'; const channel = addons.getChannel(); let progress = Promise.resolve(); -let setup: any = {}; +let setup: { config: Spec; options: RunOptions } = { config: {}, options: {} }; const getElement = () => { const storyRoot = document.getElementById('story-root'); @@ -20,7 +20,7 @@ const getElement = () => { return document.getElementById('root'); }; -const report = (input: any) => { +const report = (input: AxeResults) => { channel.emit(EVENTS.RESULT, input); }; diff --git a/addons/a11y/src/register.tsx b/addons/a11y/src/register.tsx index 64f0cd10f618..40e361e97653 100644 --- a/addons/a11y/src/register.tsx +++ b/addons/a11y/src/register.tsx @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import React, { Fragment, FunctionComponent } from 'react'; import addons, { types } from '@storybook/addons'; import { styled } from '@storybook/theming'; @@ -11,7 +11,7 @@ const Hidden = styled.div(() => ({ display: 'none', })); -const PreviewWrapper = (p: any) => ( +const PreviewWrapper: FunctionComponent<{}> = p => ( {p.children} @@ -81,20 +81,21 @@ const PreviewWrapper = (p: any) => ( addons.register(ADDON_ID, api => { addons.add(PANEL_ID, { + title: '', type: types.TOOL, - match: ({ viewMode }: any) => viewMode === 'story', + match: ({ viewMode }) => viewMode === 'story', render: () => , - } as any); + }); addons.add(PANEL_ID, { - type: types.PANEL, title: 'Accessibility', - // eslint-disable-next-line react/prop-types + type: types.PANEL, render: ({ active, key }) => , }); addons.add(PANEL_ID, { + title: '', type: types.PREVIEW, - render: PreviewWrapper, - } as any); + render: PreviewWrapper as any, + }); }); From e913428796b88462fab3b2f737d1c14fe51e9269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Sun, 24 Feb 2019 19:01:09 +0100 Subject: [PATCH 4/7] chore: remove prop-types dependency from package.json of addons/a11y --- addons/a11y/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/a11y/package.json b/addons/a11y/package.json index 7743d15931d3..8762bc787e97 100644 --- a/addons/a11y/package.json +++ b/addons/a11y/package.json @@ -36,7 +36,6 @@ "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" }, From a22b88e0a239afbfb39094dfc33e612d65d1733f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Sun, 24 Feb 2019 19:19:02 +0100 Subject: [PATCH 5/7] chore: use named import/export instead of default ones in addons/a11y --- .../src/components/{Panel.tsx => A11YPanel.tsx} | 14 +++++--------- addons/a11y/src/components/ColorBlindness.tsx | 4 +--- addons/a11y/src/components/Report/Elements.tsx | 6 ++---- addons/a11y/src/components/Report/Info.tsx | 4 +--- addons/a11y/src/components/Report/Item.tsx | 10 ++++------ addons/a11y/src/components/Report/Rules.tsx | 4 +--- addons/a11y/src/components/Report/Tags.tsx | 4 +--- addons/a11y/src/components/Report/index.tsx | 8 +++----- addons/a11y/src/components/Tabs.tsx | 4 +--- addons/a11y/src/constants.ts | 2 +- addons/a11y/src/index.ts | 2 +- addons/a11y/src/register.tsx | 9 ++++----- 12 files changed, 25 insertions(+), 46 deletions(-) rename addons/a11y/src/components/{Panel.tsx => A11YPanel.tsx} (91%) diff --git a/addons/a11y/src/components/Panel.tsx b/addons/a11y/src/components/A11YPanel.tsx similarity index 91% rename from addons/a11y/src/components/Panel.tsx rename to addons/a11y/src/components/A11YPanel.tsx index 4f0c1fb0fd83..482cceda5915 100644 --- a/addons/a11y/src/components/Panel.tsx +++ b/addons/a11y/src/components/A11YPanel.tsx @@ -3,14 +3,12 @@ import React, { Component, Fragment } from 'react'; 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)( { @@ -49,7 +47,7 @@ interface A11YPanelProps { }; } -class A11YPanel extends Component { +export class A11YPanel extends Component { state: A11YPanelState = { status: 'ready', passes: [], @@ -159,5 +157,3 @@ class A11YPanel extends Component { ) : null; } } - -export default A11YPanel; diff --git a/addons/a11y/src/components/ColorBlindness.tsx b/addons/a11y/src/components/ColorBlindness.tsx index 95d8859e4174..83818eae20de 100644 --- a/addons/a11y/src/components/ColorBlindness.tsx +++ b/addons/a11y/src/components/ColorBlindness.tsx @@ -32,7 +32,7 @@ interface ColorBlindnessState { filter: string | null; } -class ColorBlindness extends Component { +export class ColorBlindness extends Component { state: ColorBlindnessState = { expanded: false, filter: null, @@ -104,5 +104,3 @@ class ColorBlindness extends Component ); } } - -export default ColorBlindness; diff --git a/addons/a11y/src/components/Report/Elements.tsx b/addons/a11y/src/components/Report/Elements.tsx index 3e43739c1942..cce537cba04c 100644 --- a/addons/a11y/src/components/Report/Elements.tsx +++ b/addons/a11y/src/components/Report/Elements.tsx @@ -2,8 +2,8 @@ import React, { FunctionComponent } from 'react'; import { styled } from '@storybook/theming'; -import Rules from './Rules'; import { NodeResult } from 'axe-core'; +import { Rules } from './Rules'; const Item = styled.li({ fontWeight: 600, @@ -39,12 +39,10 @@ interface ElementsProps { passes: boolean; } -const Elements: FunctionComponent = ({ elements, passes }) => ( +export const Elements: FunctionComponent = ({ elements, passes }) => (
    {elements.map((element, index) => ( ))}
); - -export default Elements; diff --git a/addons/a11y/src/components/Report/Info.tsx b/addons/a11y/src/components/Report/Info.tsx index 26ba2b126e55..678eb57d2628 100644 --- a/addons/a11y/src/components/Report/Info.tsx +++ b/addons/a11y/src/components/Report/Info.tsx @@ -22,7 +22,7 @@ interface InfoProps { item: Result; } -const Info: FunctionComponent = ({ item }) => { +export const Info: FunctionComponent = ({ item }) => { return ( {item.help} @@ -32,5 +32,3 @@ const Info: FunctionComponent = ({ item }) => { ); }; - -export default Info; diff --git a/addons/a11y/src/components/Report/Item.tsx b/addons/a11y/src/components/Report/Item.tsx index d132a6cfd7b8..6a493173a4d9 100644 --- a/addons/a11y/src/components/Report/Item.tsx +++ b/addons/a11y/src/components/Report/Item.tsx @@ -3,10 +3,10 @@ import React, { Component, Fragment } from 'react'; 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(); @@ -46,7 +46,7 @@ interface ItemState { open: boolean; } -class Item extends Component { +export class Item extends Component { state = { open: false, }; @@ -84,5 +84,3 @@ class Item extends Component { ); } } - -export default Item; diff --git a/addons/a11y/src/components/Report/Rules.tsx b/addons/a11y/src/components/Report/Rules.tsx index e443d52d6b8e..0a142eb98ee9 100644 --- a/addons/a11y/src/components/Report/Rules.tsx +++ b/addons/a11y/src/components/Report/Rules.tsx @@ -61,7 +61,7 @@ interface RulesProps { passes: boolean; } -const Rules: FunctionComponent = ({ rules, passes }) => { +export const Rules: FunctionComponent = ({ rules, passes }) => { return ( {rules.map((rule, index) => ( @@ -70,5 +70,3 @@ const Rules: FunctionComponent = ({ rules, passes }) => { ); }; - -export default Rules; diff --git a/addons/a11y/src/components/Report/Tags.tsx b/addons/a11y/src/components/Report/Tags.tsx index 26ea062d2eea..559a31ee79fa 100644 --- a/addons/a11y/src/components/Report/Tags.tsx +++ b/addons/a11y/src/components/Report/Tags.tsx @@ -20,7 +20,7 @@ interface TagsProps { tags: TagValue[]; } -const Tags: FunctionComponent = ({ tags }) => { +export const Tags: FunctionComponent = ({ tags }) => { return ( {tags.map(tag => ( @@ -29,5 +29,3 @@ const Tags: FunctionComponent = ({ tags }) => { ); }; - -export default Tags; diff --git a/addons/a11y/src/components/Report/index.tsx b/addons/a11y/src/components/Report/index.tsx index c37b4a27cd32..2498962ccfd9 100644 --- a/addons/a11y/src/components/Report/index.tsx +++ b/addons/a11y/src/components/Report/index.tsx @@ -1,8 +1,8 @@ import React, { Fragment, FunctionComponent } from 'react'; import { Placeholder } from '@storybook/components'; -import Item from './Item'; import { Result } from 'axe-core'; +import { Item } from './Item'; export interface ReportProps { items: Result[]; @@ -10,14 +10,12 @@ export interface ReportProps { passes: boolean; } -const Report: FunctionComponent = ({ items, empty, passes }) => ( +export const Report: FunctionComponent = ({ items, empty, passes }) => ( {items.length ? ( - items.map((item) => ) + items.map(item => ) ) : ( {empty} )} ); - -export default Report; diff --git a/addons/a11y/src/components/Tabs.tsx b/addons/a11y/src/components/Tabs.tsx index c442fe015925..ca1aae619006 100644 --- a/addons/a11y/src/components/Tabs.tsx +++ b/addons/a11y/src/components/Tabs.tsx @@ -56,7 +56,7 @@ interface TabsState { active: number; } -class Tabs extends Component { +export class Tabs extends Component { state: TabsState = { active: 0, }; @@ -90,5 +90,3 @@ class Tabs extends Component { ); } } - -export default Tabs; diff --git a/addons/a11y/src/constants.ts b/addons/a11y/src/constants.ts index 060abd6d2d32..a3563f5ed4bf 100755 --- a/addons/a11y/src/constants.ts +++ b/addons/a11y/src/constants.ts @@ -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 }; diff --git a/addons/a11y/src/index.ts b/addons/a11y/src/index.ts index 43f4efcf1a67..5c834cdc9007 100644 --- a/addons/a11y/src/index.ts +++ b/addons/a11y/src/index.ts @@ -5,7 +5,7 @@ import { stripIndents } from 'common-tags'; 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(); diff --git a/addons/a11y/src/register.tsx b/addons/a11y/src/register.tsx index 40e361e97653..4b9c9d22ffee 100644 --- a/addons/a11y/src/register.tsx +++ b/addons/a11y/src/register.tsx @@ -1,11 +1,10 @@ import React, { Fragment, FunctionComponent } from 'react'; -import addons, { types } from '@storybook/addons'; 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', @@ -90,7 +89,7 @@ addons.register(ADDON_ID, api => { addons.add(PANEL_ID, { title: 'Accessibility', type: types.PANEL, - render: ({ active, key }) => , + render: ({ active, key }) => , }); addons.add(PANEL_ID, { From f3a0ad6ff93d72081385a557c71673595668c49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Tue, 26 Feb 2019 21:20:28 +0100 Subject: [PATCH 6/7] refactor: use a class property to prevent performance issue See https://reactjs.org/docs/faq-functions.html#arrow-function-in-render And https://reactjs.org/docs/faq-functions.html#class-properties-stage-3-proposal --- addons/a11y/src/components/ColorBlindness.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/a11y/src/components/ColorBlindness.tsx b/addons/a11y/src/components/ColorBlindness.tsx index 83818eae20de..1e037ffe5912 100644 --- a/addons/a11y/src/components/ColorBlindness.tsx +++ b/addons/a11y/src/components/ColorBlindness.tsx @@ -52,6 +52,8 @@ export class ColorBlindness extends Component this.setState({ expanded: s }); + render() { const { filter, expanded } = this.state; @@ -93,7 +95,7 @@ export class ColorBlindness extends Component this.setState({ expanded: s })} + onVisibilityChange={this.onVisibilityChange} tooltip={} closeOnClick > From 1c013a36d741b53b86f57a8c9978385cd228a9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Maisse?= Date: Wed, 6 Mar 2019 17:40:33 +0100 Subject: [PATCH 7/7] fix: fix a11y option attribute in examples/official-storybook --- examples/official-storybook/config.js | 2 +- .../tests/__snapshots__/storyshots.test.js.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/official-storybook/config.js b/examples/official-storybook/config.js index a3e716b72f2e..cd15c87b136e 100644 --- a/examples/official-storybook/config.js +++ b/examples/official-storybook/config.js @@ -40,7 +40,7 @@ addDecorator(storyFn => ( addParameters({ a11y: { - configure: {}, + config: {}, options: { checks: { 'color-contrast': { options: { noScroll: true } } }, restoreScroll: true, diff --git a/examples/official-storybook/tests/__snapshots__/storyshots.test.js.snap b/examples/official-storybook/tests/__snapshots__/storyshots.test.js.snap index da4c2f46e456..86df522f604a 100644 --- a/examples/official-storybook/tests/__snapshots__/storyshots.test.js.snap +++ b/examples/official-storybook/tests/__snapshots__/storyshots.test.js.snap @@ -5196,7 +5196,7 @@ exports[`Storyshots Core|Parameters passed to story 1`] = `
   Parameters are {
   "a11y": {
-    "configure": {},
+    "config": {},
     "options": {
       "checks": {
         "color-contrast": {