mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-01 05:05:25 +08:00
chore: type src of addons/a11y
This commit is contained in:
parent
76029c9400
commit
d7ad26e90e
@ -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<ColorBlindnessProps, ColorBlindnessState> {
|
||||
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={<TooltipLinkList links={colorList} />}
|
||||
closeOnClick
|
||||
>
|
||||
|
@ -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<any, any> {
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
class A11YPanel extends Component<A11YPanelProps, A11YPanelState> {
|
||||
state: A11YPanelState = {
|
||||
status: 'ready',
|
||||
passes: [] as any[],
|
||||
violations: [] as any[],
|
||||
passes: [],
|
||||
violations: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@ -57,7 +63,7 @@ class A11YPanel extends Component<any, any> {
|
||||
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<any, any> {
|
||||
api.off(EVENTS.RESULT, this.onUpdate);
|
||||
}
|
||||
|
||||
onUpdate = ({ passes, violations }: any) => {
|
||||
onUpdate = ({ passes, violations }: AxeResults) => {
|
||||
this.setState(
|
||||
{
|
||||
status: 'ran',
|
||||
|
@ -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<ElementProps> = ({ element, passes }) => {
|
||||
const { any, all, none } = element;
|
||||
|
||||
const rules = [...any, ...all, ...none];
|
||||
@ -27,34 +32,19 @@ function Element({ element, passes }: any) {
|
||||
<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 }: any) => (
|
||||
interface ElementsProps {
|
||||
elements: NodeResult[];
|
||||
passes: boolean;
|
||||
}
|
||||
|
||||
const Elements: FunctionComponent<ElementsProps> = ({ elements, passes }) => (
|
||||
<ol>
|
||||
{elements.map((element: any, index: any) => (
|
||||
{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;
|
||||
|
@ -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<InfoProps> = ({ item }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Help>{item.help}</Help>
|
||||
@ -27,13 +31,6 @@ function Info({ item }: any) {
|
||||
</Link>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
Info.propTypes = {
|
||||
item: PropTypes.shape({
|
||||
help: PropTypes.node,
|
||||
helpUrl: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
export default Info;
|
||||
|
@ -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<any, any> {
|
||||
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<ItemProps, ItemState> {
|
||||
state = {
|
||||
open: false,
|
||||
};
|
||||
|
||||
onToggle = () =>
|
||||
this.setState((prevState: any) => ({
|
||||
this.setState(prevState => ({
|
||||
open: !prevState.open,
|
||||
}));
|
||||
|
||||
|
@ -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<RuleProps> = ({ rule, passes }) => (
|
||||
<Item>
|
||||
<Status passes={passes || undefined} impact={rule.impact}>
|
||||
{passes ? <Icons icon="check" /> : <Icons icon="cross" />}
|
||||
@ -51,30 +56,19 @@ const Rule = ({ rule, passes }: any) => (
|
||||
</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 }: any) {
|
||||
const Rules: FunctionComponent<RulesProps> = ({ rules, passes }) => {
|
||||
return (
|
||||
<List>
|
||||
{rules.map((rule: any, index: any) => (
|
||||
{rules.map((rule, index) => (
|
||||
<Rule passes={passes} rule={rule} key={index} />
|
||||
))}
|
||||
</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,17 +16,18 @@ const Item = styled.div(({ theme }) => ({
|
||||
borderRadius: theme.appBorderRadius,
|
||||
}));
|
||||
|
||||
function Tags({ tags }: any) {
|
||||
interface TagsProps {
|
||||
tags: TagValue[];
|
||||
}
|
||||
|
||||
const Tags: FunctionComponent<TagsProps> = ({ tags }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
{tags.map((tag: any) => (
|
||||
{tags.map(tag => (
|
||||
<Item key={tag}>{tag}</Item>
|
||||
))}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
Tags.propTypes = {
|
||||
tags: PropTypes.arrayOf(PropTypes.node).isRequired,
|
||||
};
|
||||
|
||||
export default Tags;
|
||||
|
@ -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<ReportProps> = ({ items, empty, passes }) => (
|
||||
<Fragment>
|
||||
{items.length ? (
|
||||
items.map((item: any) => <Item passes={passes} item={item} key={item.id} />)
|
||||
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;
|
||||
|
@ -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<any, any> {
|
||||
state = {
|
||||
interface TabsProps {
|
||||
tabs: Array<{
|
||||
label: JSX.Element;
|
||||
panel: JSX.Element;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface TabsState {
|
||||
active: number;
|
||||
}
|
||||
|
||||
class Tabs extends Component<TabsProps, TabsState> {
|
||||
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 (
|
||||
<Container>
|
||||
<List>
|
||||
{tabs.map((tab: any, index: any) => (
|
||||
{tabs.map((tab, index) => (
|
||||
<Item
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
@ -81,13 +91,4 @@ class Tabs extends Component<any, any> {
|
||||
}
|
||||
}
|
||||
|
||||
(Tabs as any).propTypes = {
|
||||
tabs: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.node,
|
||||
panel: PropTypes.node,
|
||||
})
|
||||
).isRequired,
|
||||
};
|
||||
|
||||
export default Tabs;
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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 => (
|
||||
<Fragment>
|
||||
{p.children}
|
||||
<Hidden>
|
||||
@ -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: () => <ColorBlindness />,
|
||||
} as any);
|
||||
});
|
||||
|
||||
addons.add(PANEL_ID, {
|
||||
type: types.PANEL,
|
||||
title: 'Accessibility',
|
||||
// eslint-disable-next-line react/prop-types
|
||||
type: types.PANEL,
|
||||
render: ({ active, key }) => <Panel key={key} api={api} active={active} />,
|
||||
});
|
||||
|
||||
addons.add(PANEL_ID, {
|
||||
title: '',
|
||||
type: types.PREVIEW,
|
||||
render: PreviewWrapper,
|
||||
} as any);
|
||||
render: PreviewWrapper as any,
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user