diff --git a/addons/cssresources/README.md b/addons/cssresources/README.md index 14bec5d98141..bdc7fe79efc9 100644 --- a/addons/cssresources/README.md +++ b/addons/cssresources/README.md @@ -35,7 +35,7 @@ import { withCssResources } from '@storybook/addon-cssresources'; addDecorator( withCssResources({ cssresources: [{ - name: `bluetheme`, + id: `bluetheme`, code: ``, picked: false, }, @@ -48,11 +48,11 @@ storiesOf('Addons|Cssresources', module) .addDecorator( withCssResources({ cssresources: [{ - name: `fontawesome`, + id: `fontawesome`, code: ``, picked: true, }, { - name: `whitetheme`, + id: `whitetheme`, code: ``, picked: true, }, diff --git a/addons/cssresources/package.json b/addons/cssresources/package.json index 7499c9f92965..cdd3afdbf687 100644 --- a/addons/cssresources/package.json +++ b/addons/cssresources/package.json @@ -19,13 +19,14 @@ "license": "MIT", "author": "nm123github", "main": "dist/index.js", - "jsnext:main": "src/index.js", + "types": "dist/index.d.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" }, "dependencies": { "@emotion/styled": "10.0.6", "@storybook/addons": "5.0.0-alpha.9", + "@storybook/channels": "5.0.0-alpha.9", "@storybook/components": "5.0.0-alpha.9", "@storybook/core-events": "5.0.0-alpha.9", "core-js": "^2.6.2", diff --git a/addons/cssresources/src/CssResource.ts b/addons/cssresources/src/CssResource.ts new file mode 100644 index 000000000000..0067ca677488 --- /dev/null +++ b/addons/cssresources/src/CssResource.ts @@ -0,0 +1,5 @@ +export interface CssResource { + id: string; + code: string; + picked: boolean; +} diff --git a/addons/cssresources/src/constants.js b/addons/cssresources/src/constants.ts similarity index 89% rename from addons/cssresources/src/constants.js rename to addons/cssresources/src/constants.ts index b8422207fb45..1a0f36540353 100644 --- a/addons/cssresources/src/constants.js +++ b/addons/cssresources/src/constants.ts @@ -2,7 +2,7 @@ export const ADDON_ID = 'storybook/cssresources'; export const PANEL_ID = `${ADDON_ID}/panel`; export const PARAM_KEY = 'cssresources'; -export default { +export const EVENTS = { SET: `${ADDON_ID}:set`, UNSET: `${ADDON_ID}:unset`, }; diff --git a/addons/cssresources/src/css-resource-panel.js b/addons/cssresources/src/css-resource-panel.tsx similarity index 52% rename from addons/cssresources/src/css-resource-panel.js rename to addons/cssresources/src/css-resource-panel.tsx index 38150a87a27e..628db155807f 100644 --- a/addons/cssresources/src/css-resource-panel.js +++ b/addons/cssresources/src/css-resource-panel.tsx @@ -1,12 +1,30 @@ import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; import { SyntaxHighlighter } from '@storybook/components'; +import events, { STORY_CHANGED } from '@storybook/core-events'; +import { EVENTS, PARAM_KEY } from './constants'; +import { Channel } from '@storybook/channels'; +import { CssResource } from './CssResource'; +import { bool, func, shape } from 'prop-types'; -import { STORY_CHANGED } from '@storybook/core-events'; -import EVENTS, { PARAM_KEY } from './constants'; +interface CssResourcePanelProps { + active: boolean; + channel: Channel; + api: { + emit: (event: any, data: any) => void; + on: (event: events, callback: (data: any) => void) => void; + off: (event: events, callback: (data: any) => void) => void; + getQueryParam: () => void; + getParameters: (id: string, paramKey: string) => any; + setQueryParams: () => void; + }; +} + +interface CssResourcePanelState { + list: CssResource[]; +} -export default class CssResourcePanel extends Component { - constructor(props) { +export class CssResourcePanel extends Component { + constructor(props: CssResourcePanelProps) { super(props); this.state = { @@ -24,9 +42,9 @@ export default class CssResourcePanel extends Component { api.off(STORY_CHANGED, this.onStoryChange); } - onStoryChange = id => { + onStoryChange = (id: string) => { const { api } = this.props; - const list = api.getParameters(id, PARAM_KEY); + const list = api.getParameters(id, PARAM_KEY) as CssResource[]; if (list) { const picked = list.filter(res => res.picked); @@ -34,16 +52,16 @@ export default class CssResourcePanel extends Component { } }; - onChange = event => { + onChange = (event: any) => { const { list: oldList } = this.state; const list = oldList.map(i => ({ ...i, picked: i.id === event.target.id ? event.target.checked : i.picked, })); - this.setState({ list }, () => this.emit(list.filter(res => res.picked))); + this.setState({ list }, () => this.emit(list.filter((res: any) => res.picked))); }; - emit(list) { + emit(list: CssResource[]) { const { api } = this.props; api.emit(EVENTS.SET, list); } @@ -73,16 +91,16 @@ export default class CssResourcePanel extends Component { } } -CssResourcePanel.propTypes = { - active: PropTypes.bool.isRequired, - channel: PropTypes.shape({ - on: PropTypes.func, - emit: PropTypes.func, - removeListener: PropTypes.func, +(CssResourcePanel as any).propTypes = { + active: bool.isRequired, + channel: shape({ + on: func, + emit: func, + removeListener: func, }).isRequired, - api: PropTypes.shape({ - on: PropTypes.func, - getQueryParam: PropTypes.func, - setQueryParams: PropTypes.func, + api: shape({ + on: func, + getQueryParam: func, + setQueryParams: func, }).isRequired, }; diff --git a/addons/cssresources/src/index.js b/addons/cssresources/src/index.ts similarity index 68% rename from addons/cssresources/src/index.js rename to addons/cssresources/src/index.ts index 17532d7df73e..436343c8f449 100644 --- a/addons/cssresources/src/index.js +++ b/addons/cssresources/src/index.ts @@ -1,8 +1,8 @@ import { document } from 'global'; -import addons, { makeDecorator } from '@storybook/addons'; -import EVENTS, { PARAM_KEY } from './constants'; +import { addons, makeDecorator } from '@storybook/addons'; +import { EVENTS, PARAM_KEY } from './constants'; -const changeMediaAttribute = (element, enabled) => { +const changeMediaAttribute = (element: HTMLElement, enabled: boolean) => { const current = element.getAttribute('media'); if ((enabled && !current) || (!enabled && current === 'max-width: 1px')) { // don't do anything @@ -19,29 +19,33 @@ const changeMediaAttribute = (element, enabled) => { element.setAttribute('media', value); } }; -const createElement = (id, code) => { - const element = document.createElement('div'); + +const createElement = (id: string, code: string): HTMLDivElement => { + const element: HTMLDivElement = document.createElement('div'); element.setAttribute('id', `storybook-addon-resource_${id}`); element.innerHTML = code; return element; }; -const getElement = (id, code) => { - const found = document.querySelector(`[id="storybook-addon-resource_${id}"]`); + +const getElement = (id: string, code: string) => { + const found: Element = document.querySelector(`[id="storybook-addon-resource_${id}"]`); return { element: found || createElement(id, code), created: !found }; }; -const updateElement = (id, code, value) => { + +const updateElement = (id: string, code: string, value: boolean) => { const { element, created } = getElement(id, code); - const tags = [...element.querySelectorAll('link'), ...element.querySelectorAll('style')]; - tags.forEach(child => changeMediaAttribute(child, value)); + element.querySelectorAll('link').forEach(child => changeMediaAttribute(child, value)); + element.querySelectorAll('style').forEach(child => changeMediaAttribute(child, value)); if (created) { document.body.appendChild(element); } }; -const list = []; -const setResources = resources => { +const list: any[] = []; + +const setResources = (resources: Array<{ code: string; id: string }>) => { const added = resources.filter(i => !list.find(r => r.code === i.code)); const removed = list.filter(i => !resources.find(r => r.code === i.code)); @@ -63,7 +67,7 @@ export const withCssResources = makeDecorator({ skipIfNoParametersOrOptions: true, allowDeprecatedUsage: false, - wrapper: (getStory, context, { options, parameters }) => { + wrapper: (getStory: any, context: any, { options, parameters }: any) => { const storyOptions = parameters || options; addons.getChannel().on(EVENTS.SET, setResources); diff --git a/addons/cssresources/src/register.js b/addons/cssresources/src/register.tsx similarity index 61% rename from addons/cssresources/src/register.js rename to addons/cssresources/src/register.tsx index 3effb0f6a733..7a8348cc2c0b 100644 --- a/addons/cssresources/src/register.js +++ b/addons/cssresources/src/register.tsx @@ -1,18 +1,18 @@ import React from 'react'; -import addons, { types } from '@storybook/addons'; +import { addons, types } from '@storybook/addons'; import { ADDON_ID, PANEL_ID } from './constants'; - -import CssResourcePanel from './css-resource-panel'; +import { CssResourcePanel } from './css-resource-panel'; addons.register(ADDON_ID, api => { const channel = addons.getChannel(); + // Need to cast as any as it's not matching Addon type, to investigate addons.add(PANEL_ID, { type: types.PANEL, title: 'CSS resources', // eslint-disable-next-line react/prop-types - render: ({ active, key }) => ( + render: ({ active, key }: any) => ( ), - }); + } as any); }); diff --git a/addons/cssresources/src/typings.d.ts b/addons/cssresources/src/typings.d.ts new file mode 100644 index 000000000000..1cebcd2c971a --- /dev/null +++ b/addons/cssresources/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'; diff --git a/addons/cssresources/tsconfig.json b/addons/cssresources/tsconfig.json new file mode 100644 index 000000000000..8876bb6737a1 --- /dev/null +++ b/addons/cssresources/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/__tests__/**/*" + ] +}