From 063792bfcf0aac9504eeaa6dcf55ddf74bfd0428 Mon Sep 17 00:00:00 2001 From: lonyele Date: Fri, 21 Jun 2019 11:32:28 +0900 Subject: [PATCH 01/14] chore: add tsconfig to addon-events --- addons/events/tsconfig.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 addons/events/tsconfig.json diff --git a/addons/events/tsconfig.json b/addons/events/tsconfig.json new file mode 100644 index 000000000000..8876bb6737a1 --- /dev/null +++ b/addons/events/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/__tests__/**/*" + ] +} From 1d0821f4c14cb276ea81769cb0b81b8c1929b4b7 Mon Sep 17 00:00:00 2001 From: lonyele Date: Fri, 21 Jun 2019 12:01:50 +0900 Subject: [PATCH 02/14] chore: migrate src of addon-events to Typescript --- addons/events/package.json | 2 +- .../src/components/{Event.js => Event.tsx} | 18 +++++++++--------- .../src/components/{Panel.js => Panel.tsx} | 10 +++++----- .../events/src/{constants.js => constants.ts} | 0 addons/events/src/{index.js => index.ts} | 14 +++++++------- addons/events/src/{manager.js => manager.tsx} | 3 +-- addons/events/src/typings.d.ts | 2 ++ 7 files changed, 25 insertions(+), 24 deletions(-) rename addons/events/src/components/{Event.js => Event.tsx} (92%) rename addons/events/src/components/{Panel.js => Panel.tsx} (85%) rename addons/events/src/{constants.js => constants.ts} (100%) rename addons/events/src/{index.js => index.ts} (79%) rename addons/events/src/{manager.js => manager.tsx} (68%) create mode 100644 addons/events/src/typings.d.ts diff --git a/addons/events/package.json b/addons/events/package.json index 146314582b96..ebe6edc27aaa 100644 --- a/addons/events/package.json +++ b/addons/events/package.json @@ -19,7 +19,7 @@ }, "license": "MIT", "main": "dist/index.js", - "jsnext:main": "src/index.js", + "types": "dist/index.d.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" }, diff --git a/addons/events/src/components/Event.js b/addons/events/src/components/Event.tsx similarity index 92% rename from addons/events/src/components/Event.js rename to addons/events/src/components/Event.tsx index 7e3634959479..4ac0732b88e3 100644 --- a/addons/events/src/components/Event.js +++ b/addons/events/src/components/Event.tsx @@ -24,7 +24,7 @@ const StyledTextarea = styled(Textarea)( minHeight: '32px', resize: 'vertical', }, - ({ shown }) => + ({ shown }: any) => shown ? {} : { @@ -67,7 +67,7 @@ const Label = styled.label({ textAlign: 'right', width: 100, fontWeight: '600', -}); +} as any); const Wrapper = styled.div({ display: 'flex', @@ -77,7 +77,7 @@ const Wrapper = styled.div({ width: '100%', }); -function getJSONFromString(str) { +function getJSONFromString(str: any) { try { return JSON.parse(str); } catch (e) { @@ -85,7 +85,7 @@ function getJSONFromString(str) { } } -class Item extends Component { +class Item extends Component { static propTypes = { name: PropTypes.string.isRequired, title: PropTypes.string.isRequired, @@ -98,12 +98,12 @@ class Item extends Component { payload: {}, }; - state = { + state: any = { isTextAreaShowed: false, }; - onChange = ({ target: { value } }) => { - const newState = { + onChange = ({ target: { value } }: any) => { + const newState: any = { payloadString: value, }; @@ -128,12 +128,12 @@ class Item extends Component { }; onToggleEditClick = () => { - this.setState(({ isTextAreaShowed }) => ({ + this.setState(({ isTextAreaShowed }: any) => ({ isTextAreaShowed: !isTextAreaShowed, })); }; - static getDerivedStateFromProps = ({ payload }, { prevPayload }) => { + static getDerivedStateFromProps = ({ payload }: any, { prevPayload }: any) => { if (!isEqual(payload, prevPayload)) { const payloadString = json.plain(payload); const refinedPayload = getJSONFromString(payloadString); diff --git a/addons/events/src/components/Panel.js b/addons/events/src/components/Panel.tsx similarity index 85% rename from addons/events/src/components/Panel.js rename to addons/events/src/components/Panel.tsx index 4c37e0727a50..38b391c0098d 100644 --- a/addons/events/src/components/Panel.js +++ b/addons/events/src/components/Panel.tsx @@ -13,7 +13,7 @@ const Wrapper = styled.div({ minHeight: '100%', }); -export default class EventsPanel extends Component { +export default class EventsPanel extends Component { static propTypes = { active: PropTypes.bool.isRequired, api: PropTypes.shape({ @@ -23,7 +23,7 @@ export default class EventsPanel extends Component { }).isRequired, }; - state = { + state: any = { events: [], }; @@ -39,11 +39,11 @@ export default class EventsPanel extends Component { api.off(EVENTS.ADD, this.onAdd); } - onAdd = events => { + onAdd = (events: any) => { this.setState({ events }); }; - onEmit = event => { + onEmit = (event: any) => { const { api } = this.props; api.emit(EVENTS.EMIT, event); @@ -54,7 +54,7 @@ export default class EventsPanel extends Component { const { active } = this.props; return active ? ( - {events.map(event => ( + {events.map((event: any) => ( ))} diff --git a/addons/events/src/constants.js b/addons/events/src/constants.ts similarity index 100% rename from addons/events/src/constants.js rename to addons/events/src/constants.ts diff --git a/addons/events/src/index.js b/addons/events/src/index.ts similarity index 79% rename from addons/events/src/index.js rename to addons/events/src/index.ts index 31eb1960e36f..4c77147d4cda 100644 --- a/addons/events/src/index.js +++ b/addons/events/src/index.ts @@ -4,10 +4,10 @@ import deprecate from 'util-deprecate'; import { EVENTS } from './constants'; -let prevEvents; -let currentEmit; +let prevEvents: any; +let currentEmit: any; -const onEmit = event => { +const onEmit = (event: any) => { currentEmit(event.name, event.payload); }; @@ -21,7 +21,7 @@ const subscription = () => { }; }; -const addEvents = ({ emit, events }) => { +const addEvents = ({ emit, events }: any) => { if (prevEvents !== events) { addons.getChannel().emit(EVENTS.ADD, events); prevEvents = events; @@ -30,16 +30,16 @@ const addEvents = ({ emit, events }) => { addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription); }; -const WithEvents = deprecate(({ children, ...options }) => { +const WithEvents = deprecate(({ children, ...options }: any) => { addEvents(options); return children; }, ` usage is deprecated, use .addDecorator(withEvents({emit, events})) instead`); -export default options => { +export default (options: any) => { if (options.children) { return WithEvents(options); } - return storyFn => { + return (storyFn: any) => { addEvents(options); return storyFn(); }; diff --git a/addons/events/src/manager.js b/addons/events/src/manager.tsx similarity index 68% rename from addons/events/src/manager.js rename to addons/events/src/manager.tsx index 6d8bea634686..f6ebba0f92bb 100644 --- a/addons/events/src/manager.js +++ b/addons/events/src/manager.tsx @@ -8,8 +8,7 @@ export function register() { addons.register(ADDON_ID, api => { addons.addPanel(PANEL_ID, { title: 'Events', - // eslint-disable-next-line react/prop-types - render: ({ active, key }) => , + render: ({ active, key }: any) => , }); }); } diff --git a/addons/events/src/typings.d.ts b/addons/events/src/typings.d.ts new file mode 100644 index 000000000000..d6932d989ba0 --- /dev/null +++ b/addons/events/src/typings.d.ts @@ -0,0 +1,2 @@ +declare module 'react-lifecycles-compat'; +declare module 'format-json'; From 33f1960b64662740bf986c51f6c5a886cd9a84e9 Mon Sep 17 00:00:00 2001 From: lonyele Date: Tue, 25 Jun 2019 14:08:33 +0900 Subject: [PATCH 03/14] refactor: improve types of index.ts, manager.tsx --- addons/events/src/index.ts | 33 ++++++++++++++++++++++++++------- addons/events/src/manager.tsx | 2 +- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/addons/events/src/index.ts b/addons/events/src/index.ts index 4c77147d4cda..db09b493cad1 100644 --- a/addons/events/src/index.ts +++ b/addons/events/src/index.ts @@ -1,13 +1,20 @@ +import { ReactNode } from 'react'; + import addons from '@storybook/addons'; import CoreEvents from '@storybook/core-events'; import deprecate from 'util-deprecate'; import { EVENTS } from './constants'; -let prevEvents: any; -let currentEmit: any; +let prevEvents: Event[]; +let currentEmit: (name: string, payload: unknown) => void; + +export interface OnEmitEvent { + name: string; + payload: unknown; +} -const onEmit = (event: any) => { +const onEmit = (event: OnEmitEvent) => { currentEmit(event.name, event.payload); }; @@ -21,7 +28,7 @@ const subscription = () => { }; }; -const addEvents = ({ emit, events }: any) => { +const addEvents = ({ emit, events }: Options) => { if (prevEvents !== events) { addons.getChannel().emit(EVENTS.ADD, events); prevEvents = events; @@ -30,16 +37,28 @@ const addEvents = ({ emit, events }: any) => { addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription); }; -const WithEvents = deprecate(({ children, ...options }: any) => { +export interface Event { + name: string; + title: string; + payload: unknown; +} + +interface Options { + children?: ReactNode; + emit: (eventName: string, ...args: any) => void; + events: Event[]; +} + +const WithEvents = deprecate(({ children, ...options }: Options) => { addEvents(options); return children; }, ` usage is deprecated, use .addDecorator(withEvents({emit, events})) instead`); -export default (options: any) => { +export default (options: Options) => { if (options.children) { return WithEvents(options); } - return (storyFn: any) => { + return (storyFn: () => ReactNode) => { addEvents(options); return storyFn(); }; diff --git a/addons/events/src/manager.tsx b/addons/events/src/manager.tsx index f6ebba0f92bb..d5c818fe3bca 100644 --- a/addons/events/src/manager.tsx +++ b/addons/events/src/manager.tsx @@ -8,7 +8,7 @@ export function register() { addons.register(ADDON_ID, api => { addons.addPanel(PANEL_ID, { title: 'Events', - render: ({ active, key }: any) => , + render: ({ active, key }) => , }); }); } From fa27db5a6d15c8c786de0a67b07d3bc1c8f5b507 Mon Sep 17 00:00:00 2001 From: lonyele Date: Tue, 25 Jun 2019 14:38:14 +0900 Subject: [PATCH 04/14] refactor: improve types of Event component --- addons/events/src/components/Event.tsx | 47 +++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/addons/events/src/components/Event.tsx b/addons/events/src/components/Event.tsx index 4ac0732b88e3..427ba7b37fa3 100644 --- a/addons/events/src/components/Event.tsx +++ b/addons/events/src/components/Event.tsx @@ -5,10 +5,15 @@ import isEqual from 'lodash/isEqual'; import { styled } from '@storybook/theming'; import json from 'format-json'; - import Textarea from 'react-textarea-autosize'; +import { OnEmitEvent } from '../index'; + +interface StyledTextareaProps { + shown: boolean; + failed: boolean; +} -const StyledTextarea = styled(Textarea)( +const StyledTextarea = styled(Textarea)( { flex: '1 0 0', boxSizing: 'border-box', @@ -24,7 +29,7 @@ const StyledTextarea = styled(Textarea)( minHeight: '32px', resize: 'vertical', }, - ({ shown }: any) => + ({ shown }) => shown ? {} : { @@ -77,15 +82,29 @@ const Wrapper = styled.div({ width: '100%', }); -function getJSONFromString(str: any) { +function getJSONFromString(str: string) { try { return JSON.parse(str); } catch (e) { return str; } } +interface ItemProps { + name: string; + title: string; + onEmit: (event: OnEmitEvent) => void; + payload: unknown; +} -class Item extends Component { +interface ItemState { + isTextAreaShowed: boolean; + failed: boolean; + payload: unknown; + payloadString: string; + prevPayload: unknown; +} + +class Item extends Component { static propTypes = { name: PropTypes.string.isRequired, title: PropTypes.string.isRequired, @@ -98,12 +117,17 @@ class Item extends Component { payload: {}, }; - state: any = { + state: ItemState = { isTextAreaShowed: false, + failed: false, + payload: null, + payloadString: '', + // eslint-disable-next-line react/no-unused-state, + prevPayload: null, }; - onChange = ({ target: { value } }: any) => { - const newState: any = { + onChange = ({ target: { value } }: React.ChangeEvent) => { + const newState: Partial = { payloadString: value, }; @@ -114,7 +138,7 @@ class Item extends Component { newState.failed = true; } - this.setState(newState); + this.setState(newState as ItemState); }; onEmitClick = () => { @@ -128,12 +152,12 @@ class Item extends Component { }; onToggleEditClick = () => { - this.setState(({ isTextAreaShowed }: any) => ({ + this.setState(({ isTextAreaShowed }) => ({ isTextAreaShowed: !isTextAreaShowed, })); }; - static getDerivedStateFromProps = ({ payload }: any, { prevPayload }: any) => { + static getDerivedStateFromProps = ({ payload }: ItemProps, { prevPayload }: ItemState) => { if (!isEqual(payload, prevPayload)) { const payloadString = json.plain(payload); const refinedPayload = getJSONFromString(payloadString); @@ -150,7 +174,6 @@ class Item extends Component { render() { const { title, name } = this.props; const { failed, isTextAreaShowed, payloadString } = this.state; - return ( From f420cbbaaa009173b3f2526aa327394243eefd35 Mon Sep 17 00:00:00 2001 From: lonyele Date: Tue, 25 Jun 2019 14:41:17 +0900 Subject: [PATCH 05/14] refactor: improve types of Panel component --- addons/events/package.json | 1 + addons/events/src/components/Panel.tsx | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/addons/events/package.json b/addons/events/package.json index ebe6edc27aaa..3b0d640dbfb6 100644 --- a/addons/events/package.json +++ b/addons/events/package.json @@ -25,6 +25,7 @@ }, "dependencies": { "@storybook/addons": "5.2.0-alpha.23", + "@storybook/api": "^5.1.9", "@storybook/core-events": "5.2.0-alpha.23", "@storybook/theming": "5.2.0-alpha.23", "core-js": "^3.0.1", diff --git a/addons/events/src/components/Panel.tsx b/addons/events/src/components/Panel.tsx index 38b391c0098d..6c79a5ff2e5d 100644 --- a/addons/events/src/components/Panel.tsx +++ b/addons/events/src/components/Panel.tsx @@ -2,9 +2,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { styled } from '@storybook/theming'; +import { API } from '@storybook/api'; import { EVENTS } from '../constants'; import Event from './Event'; +import { Event as EventType, OnEmitEvent } from '../index'; const Wrapper = styled.div({ width: '100%', @@ -13,7 +15,15 @@ const Wrapper = styled.div({ minHeight: '100%', }); -export default class EventsPanel extends Component { +interface EventsPanelProps { + active: boolean; + api: API; +} +interface EventsPanelState { + events: EventType[]; +} + +export default class EventsPanel extends Component { static propTypes = { active: PropTypes.bool.isRequired, api: PropTypes.shape({ @@ -23,7 +33,7 @@ export default class EventsPanel extends Component { }).isRequired, }; - state: any = { + state: EventsPanelState = { events: [], }; @@ -39,13 +49,12 @@ export default class EventsPanel extends Component { api.off(EVENTS.ADD, this.onAdd); } - onAdd = (events: any) => { + onAdd = (events: EventType[]) => { this.setState({ events }); }; - onEmit = (event: any) => { + onEmit = (event: OnEmitEvent) => { const { api } = this.props; - api.emit(EVENTS.EMIT, event); }; @@ -54,7 +63,7 @@ export default class EventsPanel extends Component { const { active } = this.props; return active ? ( - {events.map((event: any) => ( + {events.map(event => ( ))} From 220b17e8aaacbd266ce8418a4b57a8737b1c59b4 Mon Sep 17 00:00:00 2001 From: lonyele Date: Tue, 25 Jun 2019 15:41:27 +0900 Subject: [PATCH 06/14] fix: remove receiving non-boolean attribute console warning --- addons/events/src/components/Event.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/events/src/components/Event.tsx b/addons/events/src/components/Event.tsx index 427ba7b37fa3..1cc500725b73 100644 --- a/addons/events/src/components/Event.tsx +++ b/addons/events/src/components/Event.tsx @@ -11,9 +11,13 @@ import { OnEmitEvent } from '../index'; interface StyledTextareaProps { shown: boolean; failed: boolean; + value?: string; + onChange?: (event: React.ChangeEvent) => void; } -const StyledTextarea = styled(Textarea)( +const StyledTextarea = styled(({ shown, failed, ...rest }: StyledTextareaProps) => ( +