diff --git a/addons/backgrounds/src/Tool.js b/addons/backgrounds/src/Tool.js index ca6268b34b70..dce93da22c6d 100644 --- a/addons/backgrounds/src/Tool.js +++ b/addons/backgrounds/src/Tool.js @@ -1,26 +1,25 @@ -import { document } from 'global'; import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import memoize from 'memoizerific'; -import { logger } from '@storybook/client-logger'; import { SET_STORIES } from '@storybook/core-events'; +import { Global } from '@storybook/theming'; import { Popout, Item, Icons, Icon, IconButton, Title, Detail, List } from '@storybook/components'; import * as S from './components'; import { PARAM_KEY } from './constants'; -const getIframe = () => document.getElementById('storybook-preview-background'); +const iframeId = 'storybook-preview-background'; -const getState = (props, state) => { +const getState = memoize(10)((props, state) => { const data = props.api.getCurrentStoryData(); const list = data && data.parameters && data.parameters[PARAM_KEY]; return list && list.length ? list.reduce( (acc, { name, value, default: isSelected }) => { - acc.backgrounds.push({ name, value }); + acc.items.push({ name, value }); if (isSelected && state.selected !== 'transparent') { if (!list.find(i => i.value === state.selected)) { @@ -30,23 +29,14 @@ const getState = (props, state) => { return acc; }, { - backgrounds: [], + items: [], selected: state.selected, } ) : { - backgrounds: [], + items: [], selected: 'transparent', }; -}; - -const apply = memoize(1)((value, iframe) => { - if (iframe) { - // eslint-disable-next-line no-param-reassign - iframe.style.background = value; - } else { - logger.error('Cannot find Storybook iframe'); - } }); export default class BackgroundTool extends Component { @@ -54,69 +44,81 @@ export default class BackgroundTool extends Component { super(props); this.state = { - backgrounds: [], + items: [], selected: 'transparent', }; + + this.listener = () => { + this.setState({ selected: null }); + }; } componentDidMount() { const { api } = this.props; + api.on(SET_STORIES, this.listener); + } - api.on(SET_STORIES, () => { - const { state, props } = this; - this.setState(getState(props, state)); - }); + componentWillUnmount() { + const { api } = this.props; + api.off(SET_STORIES, this.listener); } change = selected => { - this.setState({ selected }, this.apply); + this.setState({ selected }); }; render() { - const { backgrounds, selected } = getState(this.props, this.state); - const iframe = getIframe(); - - apply(selected, iframe); - - return backgrounds.length ? ( - - - - - {({ hide }) => ( - - {selected !== 'transparent' ? ( - + const { items, selected } = getState(this.props, this.state); + + return items.length ? ( + + + + + + + + {({ hide }) => ( + + {selected !== 'transparent' ? ( + + { + hide(); + this.change('transparent'); + }} + > + + Clear + transparent + + + ) : null} + + {items.map(({ name, value }) => ( { hide(); - this.change('transparent'); + this.change(value); }} > - - Clear - transparent + } /> + {name} + {value} - - ) : null} - - {backgrounds.map(({ name, value }) => ( - { - hide(); - this.change(value); - }} - > - } /> - {name} - {value} - - ))} - - )} - + ))} + + )} + + ) : null; } } diff --git a/addons/viewport/src/Tool.js b/addons/viewport/src/Tool.js index c82cb6ecc280..d714ba46f20b 100644 --- a/addons/viewport/src/Tool.js +++ b/addons/viewport/src/Tool.js @@ -1,121 +1,120 @@ -import { document } from 'global'; import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import memoize from 'memoizerific'; -import { Global, css } from '@storybook/theming'; +import { Global } from '@storybook/theming'; import { Popout, Item, Icons, Icon, IconButton, Title, List } from '@storybook/components'; -import { STORY_CHANGED } from '@storybook/core-events'; -import { logger } from '@storybook/client-logger'; +import { SET_STORIES } from '@storybook/core-events'; import { PARAM_KEY } from './constants'; -const toList = memoize(50)(viewports => Object.entries(viewports)); -const getIframe = memoize(1)(() => document.getElementById('storybook-preview-iframe')); -const iframeClass = 'storybook-preview-iframe-viewport'; +const toList = memoize(50)(items => + items ? Object.entries(items).map(([id, value]) => ({ ...value, id })) : [] +); +const iframeId = 'storybook-preview-background'; + +const getState = memoize(10)((props, state) => { + const data = props.api.getCurrentStoryData(); + const list = toList(data && data.parameters && data.parameters[PARAM_KEY]); + + return list && list.length + ? list.reduce( + (acc, { name, styles: value, id }) => { + acc.items.push({ name, value, id }); + + if (state.selected !== 'responsive') { + if (!list.find(i => i.id === state.selected)) { + acc.selected = id; + } + } + return acc; + }, + { + isRotated: state.isRotated, + items: [], + selected: state.selected, + } + ) + : { + isRotated: false, + items: [], + selected: 'responsive', + }; +}); + +const flip = ({ width, height }) => ({ height: width, widht: height }); export default class ViewportTool extends Component { constructor(props) { super(props); this.state = { - viewports: {}, - selected: undefined, isRotated: false, + items: [], + selected: 'responsive', + }; + + this.listener = () => { + this.setState({}); }; } componentDidMount() { const { api } = this.props; - api.on(STORY_CHANGED, this.onStoryChange); + api.on(SET_STORIES, this.listener); } componentWillUnmount() { const { api } = this.props; - api.off(STORY_CHANGED, this.onStoryChange); + api.off(SET_STORIES, this.listener); } - onStoryChange = id => { - const { api } = this.props; - const viewports = api.getParameters(id, PARAM_KEY); - - if (viewports) { - this.setState({ viewports }); - } - }; - - change = key => { - this.setState({ selected: key }, () => { - this.apply(); - }); + change = selected => { + this.setState({ selected }); }; rotate = () => { const { isRotated } = this.state; - this.setState({ isRotated: !isRotated }, () => { - this.apply(); - }); - }; - - apply = () => { - const iframe = getIframe(); - const { isRotated, selected, viewports } = this.state; - - if (iframe) { - if (selected) { - const { - styles: { width: a, height: b }, - } = viewports[selected]; - iframe.style.width = isRotated ? b : a; - iframe.style.height = isRotated ? a : b; - - if (!iframe.classList.item(iframeClass)) { - iframe.classList.add(iframeClass); - } - } else { - iframe.style.width = '100%'; - iframe.style.height = '100%'; - iframe.classList.remove(iframeClass); - } - } else { - logger.error('Cannot find Storybook iframe'); - } + this.setState({ isRotated: !isRotated }); }; render() { - const { viewports, selected } = this.state; - - const list = toList(viewports); + const { items, selected, isRotated } = getState(this.props, this.state); + const item = items.find(i => i.id === selected); - if (!list.length) { + if (!items.length) { return null; } return ( - + {item && item.value ? ( + + ) : null} {({ hide }) => ( - {selected !== undefined ? ( + {selected !== 'responsive' ? ( { hide(); - this.change(undefined); + this.change('responsive'); }} > @@ -134,12 +133,12 @@ export default class ViewportTool extends Component { ) : null} - {list.map(([key, { name, type }]) => ( + {items.map(({ id, name, type }) => ( { hide(); - this.change(key); + this.change(id); }} > @@ -155,14 +154,7 @@ export default class ViewportTool extends Component { } ViewportTool.propTypes = { - channel: PropTypes.shape({ - on: PropTypes.func, - emit: PropTypes.func, - removeListener: PropTypes.func, - }).isRequired, api: PropTypes.shape({ on: PropTypes.func, - getQueryParam: PropTypes.func, - setQueryParams: PropTypes.func, }).isRequired, }; diff --git a/addons/viewport/src/register.js b/addons/viewport/src/register.js index 522cbb55de76..deb8bf839d2a 100644 --- a/addons/viewport/src/register.js +++ b/addons/viewport/src/register.js @@ -6,11 +6,10 @@ import { ADDON_ID } from './constants'; import Tool from './Tool'; addons.register(ADDON_ID, api => { - const channel = addons.getChannel(); addons.add(ADDON_ID, { - type: types.TOOL, title: 'viewport / media-queries', + type: types.TOOL, match: ({ viewMode }) => viewMode === 'story', - render: () => , + render: () => , }); });