Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate addon viewport to TS #7177

Merged
merged 3 commits into from
Jun 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions addons/viewport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
Expand All @@ -37,5 +38,8 @@
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/util-deprecate": "^1.0.0"
}
}
178 changes: 107 additions & 71 deletions addons/viewport/src/Tool.js → addons/viewport/src/Tool.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import memoize from 'memoizerific';
import deprecate from 'util-deprecate';

Expand All @@ -10,23 +9,37 @@ import { SET_STORIES } from '@storybook/core-events';

import { PARAM_KEY } from './constants';
import { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from './defaults';
import { ViewportAddonParameter, ViewportMap, ViewportStyles } from './models';

const toList = memoize(50)(items =>
const toList = memoize(50)((items: ViewportMap) =>
items ? Object.entries(items).map(([id, value]) => ({ ...value, id })) : []
);
const iframeId = 'storybook-preview-iframe';

const createItem = memoize(1000)((id, name, value, change) => ({
id: id || name,
title: name,
onClick: () => {
change({ selected: id, expanded: false });
},
right: `${value.width.replace('px', '')}x${value.height.replace('px', '')}`,
value,
}));
interface ViewportVM {
id: string;
title: string;
onClick: () => void;
right: string;
value: ViewportStyles;
}

const flip = ({ width, height }) => ({ height: width, width: height });
const createItem = memoize(1000)(
(id: string, name: string, value: ViewportStyles, change: (...args: unknown[]) => void) => {
const result: ViewportVM = {
id: id || name,
title: name,
onClick: () => {
change({ selected: id, expanded: false });
},
right: `${value.width.replace('px', '')}x${value.height.replace('px', '')}`,
value,
};
return result;
}
);

const flip = ({ width, height }: ViewportStyles) => ({ height: width, width: height });

const deprecatedViewportString = deprecate(
() => 0,
Expand All @@ -37,56 +50,69 @@ const deprecateOnViewportChange = deprecate(
'The viewport parameter `onViewportChange` is no longer supported'
);

const getState = memoize(10)((props, state, change) => {
const data = props.api.getCurrentStoryData();
const parameters = data && data.parameters && data.parameters[PARAM_KEY];

if (parameters && typeof parameters !== 'object') {
deprecatedViewportString();
}
const getState = memoize(10)(
(
props: ViewportToolProps,
state: ViewportToolState,
change: (statePatch: Partial<ViewportToolState>) => void
) => {
const data = props.api.getCurrentStoryData();
const parameters: ViewportAddonParameter =
data && (data as any).parameters && (data as any).parameters[PARAM_KEY];

if (parameters && typeof parameters !== 'object') {
deprecatedViewportString();
}

const { disable, viewports, defaultViewport, onViewportChange } = parameters || {};
const { disable, viewports, defaultViewport, onViewportChange } = parameters || ({} as any);

if (onViewportChange) {
deprecateOnViewportChange();
}
if (onViewportChange) {
deprecateOnViewportChange();
}

const list = disable ? [] : toList(viewports || INITIAL_VIEWPORTS);

const selected =
state.selected === 'responsive' || list.find(i => i.id === state.selected)
? state.selected
: list.find(i => i.default) || defaultViewport || DEFAULT_VIEWPORT;

const resets =
selected !== 'responsive'
? [
{
id: 'reset',
title: 'Reset viewport',
onClick: () => {
change({ selected: undefined, expanded: false });
const list = disable ? [] : toList(viewports || INITIAL_VIEWPORTS);
const viewportVMList = list.map(({ id, name, styles: value }) =>
createItem(id, name, value, change)
);

const selected =
state.selected === 'responsive' || list.find(i => i.id === state.selected)
? state.selected
: list.find(i => i.default) || defaultViewport || DEFAULT_VIEWPORT;

const resets: ViewportVM[] =
selected !== 'responsive'
? [
{
id: 'reset',
title: 'Reset viewport',
onClick: () => {
change({ selected: undefined, expanded: false });
},
right: undefined,
value: undefined,
},
},
{
id: 'rotate',
title: 'Rotate viewport',
onClick: () => {
change({ isRotated: !state.isRotated, expanded: false });
{
id: 'rotate',
title: 'Rotate viewport',
onClick: () => {
change({ isRotated: !state.isRotated, expanded: false });
},
right: undefined,
value: undefined,
},
},
]
: [];
const items = list.length
? resets.concat(list.map(({ id, name, styles: value }) => createItem(id, name, value, change)))
: list;

return {
isRotated: state.isRotated,
items,
selected,
};
});
]
: [];

const items = viewportVMList.length !== 0 ? resets.concat(viewportVMList) : [];

return {
isRotated: state.isRotated,
items,
selected,
};
}
);

const ActiveViewportSize = styled.div(() => ({
display: 'inline-flex',
Expand Down Expand Up @@ -116,8 +142,20 @@ const IconButtonLabel = styled.div(({ theme }) => ({
marginLeft: '10px',
}));

export default class ViewportTool extends Component {
constructor(props) {
interface ViewportToolState {
isRotated: boolean;
items: any[];
selected: string;
expanded: boolean;
}
interface ViewportToolProps {
api: any;
}

export class ViewportTool extends Component<ViewportToolProps, ViewportToolState> {
listener: () => void;

constructor(props: ViewportToolProps) {
super(props);

this.state = {
Expand All @@ -144,12 +182,16 @@ export default class ViewportTool extends Component {
api.off(SET_STORIES, this.listener);
}

change = (...args) => this.setState(...args);
// @ts-ignore
change = (...args: any[]) => this.setState(...args);

flipViewport = () =>
this.setState(({ isRotated }) => ({ isRotated: !isRotated, expanded: false }));
this.setState(({ isRotated }: { isRotated: boolean }) => ({
isRotated: !isRotated,
expanded: false,
}));

resetViewport = e => {
resetViewport = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();

Expand All @@ -161,8 +203,8 @@ export default class ViewportTool extends Component {
const { items, selected, isRotated } = getState(this.props, this.state, this.change);
const item = items.find(i => i.id === selected);

let viewportX = 0;
let viewportY = 0;
let viewportX = '0';
let viewportY = '0';
let viewportTitle = '';
if (item) {
const height = item.value.height.replace('px', '');
Expand All @@ -188,7 +230,7 @@ export default class ViewportTool extends Component {
boxShadow: '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08);',
boxSizing: 'content-box',

...(isRotated ? flip(item.value || {}) : item.value || {}),
...(isRotated ? flip(item.value) : item.value),
},
}}
/>
Expand Down Expand Up @@ -224,9 +266,3 @@ export default class ViewportTool extends Component {
) : null;
}
}

ViewportTool.propTypes = {
api: PropTypes.shape({
on: PropTypes.func,
}).isRequired,
};
9 changes: 0 additions & 9 deletions addons/viewport/src/constants.js

This file was deleted.

7 changes: 7 additions & 0 deletions addons/viewport/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const ADDON_ID = 'storybook/viewport';
export const PARAM_KEY = 'viewport';

export const UPDATE = `${ADDON_ID}/update`;
export const CONFIGURE = `${ADDON_ID}/configure`;
export const SET = `${ADDON_ID}/setStoryDefaultViewport`;
export const CHANGED = `${ADDON_ID}/viewportChanged`;
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const INITIAL_VIEWPORTS = {
import { ViewportMap } from './models';

export const INITIAL_VIEWPORTS: ViewportMap = {
iphone5: {
name: 'iPhone 5',
styles: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import deprecate from 'util-deprecate';

export { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from '../defaults';
export { default as withViewport } from './withViewport';

export const configureViewport = deprecate(() => {},
'configureViewport is no longer supported, use .addParameters({ viewport }) instead');
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { makeDecorator } from '@storybook/addons';
import { makeDecorator, StoryGetter, StoryContext } from '@storybook/addons';
import deprecate from 'util-deprecate';

const withViewport = makeDecorator({
name: 'withViewport',
parameterName: 'viewport',
wrapper: deprecate(
(getStory, context) => getStory(context),
(getStory: StoryGetter, context: StoryContext) => getStory(context),
'withViewport is no longer supported, use .addParameters({ viewport }) instead'
),
});
Expand Down
19 changes: 19 additions & 0 deletions addons/viewport/src/models/Viewport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface Viewport {
name: string;
styles: ViewportStyles;
type: 'desktop' | 'mobile' | 'tablet';
/*
* @deprecated
* Deprecated option?
*/
default?: boolean;
}

export interface ViewportStyles {
height: string;
width: string;
}

export interface ViewportMap {
[key: string]: Viewport;
}
12 changes: 12 additions & 0 deletions addons/viewport/src/models/ViewportAddonParameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ViewportMap } from './Viewport';

export interface ViewportAddonParameter {
disable: boolean;
defaultViewport: string;
viewports: ViewportMap;
/*
* @deprecated
* The viewport parameter `onViewportChange` is no longer supported
*/
onViewportChange?: never;
}
2 changes: 2 additions & 0 deletions addons/viewport/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Viewport';
export * from './ViewportAddonParameter';
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import addons, { types } from '@storybook/addons';

import { ADDON_ID } from './constants';

import Tool from './Tool';
import { ViewportTool } from './Tool';

addons.register(ADDON_ID, api => {
addons.add(ADDON_ID, {
title: 'viewport / media-queries',
type: types.TOOL,
match: ({ viewMode }) => viewMode === 'story',
render: () => <Tool api={api} />,
render: () => <ViewportTool api={api} />,
});
});
13 changes: 13 additions & 0 deletions addons/viewport/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__/**/*"
]
}