Skip to content

Commit

Permalink
Migrate addon viewport to TS (#7177)
Browse files Browse the repository at this point in the history
Migrate addon viewport to TS
  • Loading branch information
ndelangen authored Jun 25, 2019
2 parents ba5ef30 + 2c5b08f commit c61dfb7
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 86 deletions.
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__/**/*"
]
}

0 comments on commit c61dfb7

Please sign in to comment.