Skip to content

Commit

Permalink
Migrate @storybook/addon-events to Typescript (#7190)
Browse files Browse the repository at this point in the history
Migrate @storybook/addon-events to Typescript
  • Loading branch information
shilman committed Jul 4, 2019
2 parents 9062e93 + 4cadcc9 commit 4db4dc4
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 25 deletions.
3 changes: 2 additions & 1 deletion addons/events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/api": "5.2.0-alpha.35",
"@storybook/addons": "5.2.0-alpha.35",
"@storybook/core-events": "5.2.0-alpha.35",
"@storybook/theming": "5.2.0-alpha.35",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,19 @@ 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;
value?: string;
onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
}

const StyledTextarea = styled(Textarea)(
const StyledTextarea = styled(({ shown, failed, ...rest }: StyledTextareaProps) => (
<Textarea {...rest} />
))(
{
flex: '1 0 0',
boxSizing: 'border-box',
Expand Down Expand Up @@ -67,7 +76,7 @@ const Label = styled.label({
textAlign: 'right',
width: 100,
fontWeight: '600',
});
} as any);

const Wrapper = styled.div({
display: 'flex',
Expand All @@ -77,15 +86,29 @@ const Wrapper = styled.div({
width: '100%',
});

function getJSONFromString(str) {
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;
}

interface ItemState {
isTextAreaShowed: boolean;
failed: boolean;
payload: unknown;
payloadString: string;
prevPayload: unknown;
}

class Item extends Component {
class Item extends Component<ItemProps, ItemState> {
static propTypes = {
name: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
Expand All @@ -98,12 +121,16 @@ class Item extends Component {
payload: {},
};

state = {
state: ItemState = {
isTextAreaShowed: false,
failed: false,
payload: null,
payloadString: '',
prevPayload: null,
};

onChange = ({ target: { value } }) => {
const newState = {
onChange = ({ target: { value } }: React.ChangeEvent<HTMLTextAreaElement>) => {
const newState: Partial<ItemState> = {
payloadString: value,
};

Expand All @@ -114,7 +141,7 @@ class Item extends Component {
newState.failed = true;
}

this.setState(newState);
this.setState(state => ({ ...state, ...newState }));
};

onEmitClick = () => {
Expand All @@ -133,7 +160,7 @@ class Item extends Component {
}));
};

static getDerivedStateFromProps = ({ payload }, { prevPayload }) => {
static getDerivedStateFromProps = ({ payload }: ItemProps, { prevPayload }: ItemState) => {
if (!isEqual(payload, prevPayload)) {
const payloadString = json.plain(payload);
const refinedPayload = getJSONFromString(payloadString);
Expand All @@ -150,7 +177,6 @@ class Item extends Component {
render() {
const { title, name } = this.props;
const { failed, isTextAreaShowed, payloadString } = this.state;

return (
<Wrapper>
<Label htmlFor={`addon-event-${name}`}>{title}</Label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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%',
Expand All @@ -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<EventsPanelProps, EventsPanelState> {
static propTypes = {
active: PropTypes.bool.isRequired,
api: PropTypes.shape({
Expand All @@ -23,7 +33,7 @@ export default class EventsPanel extends Component {
}).isRequired,
};

state = {
state: EventsPanelState = {
events: [],
};

Expand All @@ -39,13 +49,12 @@ export default class EventsPanel extends Component {
api.off(EVENTS.ADD, this.onAdd);
}

onAdd = events => {
onAdd = (events: EventType[]) => {
this.setState({ events });
};

onEmit = event => {
onEmit = (event: OnEmitEvent) => {
const { api } = this.props;

api.emit(EVENTS.EMIT, event);
};

Expand Down
File renamed without changes.
33 changes: 26 additions & 7 deletions addons/events/src/index.js → addons/events/src/index.ts
Original file line number Diff line number Diff line change
@@ -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;
let currentEmit;
let prevEvents: Event[];
let currentEmit: (name: string, payload: unknown) => void;

export interface OnEmitEvent {
name: string;
payload: unknown;
}

const onEmit = event => {
const onEmit = (event: OnEmitEvent) => {
currentEmit(event.name, event.payload);
};

Expand All @@ -21,7 +28,7 @@ const subscription = () => {
};
};

const addEvents = ({ emit, events }) => {
const addEvents = ({ emit, events }: Options) => {
if (prevEvents !== events) {
addons.getChannel().emit(EVENTS.ADD, events);
prevEvents = events;
Expand All @@ -30,16 +37,28 @@ const addEvents = ({ emit, events }) => {
addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
};

const WithEvents = deprecate(({ children, ...options }) => {
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;
}, `<WithEvents> usage is deprecated, use .addDecorator(withEvents({emit, events})) instead`);

export default options => {
export default (options: Options) => {
if (options.children) {
return WithEvents(options);
}
return storyFn => {
return (storyFn: () => ReactNode) => {
addEvents(options);
return storyFn();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export function register() {
addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Events',
// eslint-disable-next-line react/prop-types
render: ({ active, key }) => <Panel key={key} api={api} active={active} />,
paramKey: PARAM_KEY,
});
Expand Down
2 changes: 2 additions & 0 deletions addons/events/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module 'react-lifecycles-compat';
declare module 'format-json';
13 changes: 13 additions & 0 deletions addons/events/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"types": ["webpack-env"]
},
"include": [
"src/**/*"
],
"exclude": [
"src/__tests__/**/*"
]
}

1 comment on commit 4db4dc4

@vercel
Copy link

@vercel vercel bot commented on 4db4dc4 Jul 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.