Skip to content

Commit

Permalink
Merge pull request #5829 from storybooks/5757-restore-viewport
Browse files Browse the repository at this point in the history
Restore viewport behaviour
  • Loading branch information
shilman authored Mar 4, 2019
2 parents 9e7952e + a0ade4a commit 112b9f4
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 331 deletions.
22 changes: 22 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,28 @@ storiesOf('Stories', module)
.add('centered', () => 'Hello', { decorators: [centered] });
```

## Addon viewport uses parameters

Similarly, `@storybook/addon-viewport` uses parameters to pass viewport options. If you previously had:

```js
import { configureViewport } from `@storybook/addon-viewport`;

configureViewport(options);
```

You can replace it with:

```js
import { addParameters } from '@storybook/react'; // or others

addParameters({ viewport: options });
```

The `withViewport` decorator is also no longer supported and should be replaced with a parameter based API as above. Also the `onViewportChange` callback is no longer supported.

See the [README](https://github.com/storybooks/storybook/blob/master/addons/viewport/README.md) for the viewport addon for more information.

## From version 4.0.x to 4.1.x

There are are a few migrations you should be aware of in 4.1, including one unintentionally breaking change for advanced addon usage.
Expand Down
152 changes: 44 additions & 108 deletions addons/viewport/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Storybook Viewport Addon

Storybook Viewport Addon allows your stories to be displayed in different sizes and layouts in [Storybook](https://storybook.js.org). This helps build responsive components inside of Storybook.
Storybook Viewport Addon allows your stories to be displayed in different sizes and layouts in [Storybook](https://storybook.js.org). This helps build responsive components inside of Storybook.

[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

Expand Down Expand Up @@ -28,21 +28,30 @@ import '@storybook/addon-viewport/register';

## Configuration

Import and use the `configureViewport` function in your `config.js` file.
The viewport addon is configured by story parameters with the `viewport` key. To configure globally, import `addParameters` from your app layer in your `config.js` file.

```js
import { configureViewport } from '@storybook/addon-viewport';
import { addParameters } from '@storybook/react';

addParameters({ viewport: options });
```

Options can take a object with the following keys:

### defaultViewport : String
----

---

Setting this property to, let say `iphone6`, will make `iPhone 6` the default device/viewport for all stories. Default is `'responsive'` which fills 100% of the preview area.

### viewports : Object
----

---

A key-value pair of viewport's key and properties (see `Viewport` definition below) for all viewports to be displayed. Default is [`INITIAL_VIEWPORTS`](src/shared/index.js)

#### Viewport Model

```js
{
/**
Expand Down Expand Up @@ -70,154 +79,81 @@ A key-value pair of viewport's key and properties (see `Viewport` definition bel
}
```

## Decorators
## Configuring per component or story

Sometimes you want to show collection of mobile stories, and you know those stories look horible on desktop (`responsive`), so you think you need to change the default viewport only for those?
Parameters can be configured for a whole set of stories or a single story via the standard parameter API:

Here is the answer, with `withViewport` decorator, you can change the default viewport of single, multiple, or all stories.

`withViewport` accepts either
* A `String`, which represents the default viewport, or
* An `Object`, which looks like
```js
{
name: 'iphone6', // default viewport
onViewportChange({ viewport }) { // called whenever different viewport is selected from the dropdown
import addStories from '@storybook/react';

}
}
addStories('Stories', module)
// To set a default viewport for all the stories for this component
.addParameters({ viewport: { defaultViewport: 'iphone6' }})
.add('story', () => </>, { viewport: 'iphonex' });
```

## Examples

### Basic Usage

Simply import the Storybook Viewport Addon in the `addons.js` file in your `.storybook` directory.

```js
import '@storybook/addon-viewport/register'
```

This will register the Viewport Addon to Storybook and will show up in the action area.


### Use Custom Set of Devices

This will replace all previous devices with `Kindle Fire 2` and `Kindle Fire HD` by simply calling `configureViewport` with the two devices as `viewports` in `config.js` file in your `.storybook` directory.
This will replace all previous devices with `Kindle Fire 2` and `Kindle Fire HD` by simply calling `addParameters` with the two devices as `viewports` in `config.js` file in your `.storybook` directory.

```js
import { configureViewport } from '@storybook/addon-viewport';
import { addParameters } from '@storybook/react';

const newViewports = {
kindleFire2: {
name: 'Kindle Fire 2',
styles: {
width: '600px',
height: '963px'
}
height: '963px',
},
},
kindleFireHD: {
name: 'Kindle Fire HD',
styles: {
width: '533px',
height: '801px'
}
}
height: '801px',
},
},
};

configureViewport({
viewports: newViewports
addParameters({
viewport: { viewports: newViewports },
});
```


### Add New Device

This will add both `Kindle Fire 2` and `Kindle Fire HD` to the list of devices. This is acheived by making use of the exported [`INITIAL_VIEWPORTS`](src/shared/index.js) property, by merging it with the new viewports and pass the result as `viewports` to `configureViewport` function

```js
import { configureViewport, INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { addParameters } from '@storybook/react';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';

const newViewports = {
kindleFire2: {
name: 'Kindle Fire 2',
styles: {
width: '600px',
height: '963px'
}
height: '963px',
},
},
kindleFireHD: {
name: 'Kindle Fire HD',
styles: {
width: '533px',
height: '801px'
}
}
height: '801px',
},
},
};

configureViewport({
viewports: {
...INITIAL_VIEWPORTS,
...newViewports
}
});
```


### Change The Default Viewport

This will make `iPhone 6` the default viewport for all stories.

```js
import { configureViewport } from '@storybook/addon-viewport';

configureViewport({
defaultViewport: 'iphone6'
addParameters({
viewport: {
viewports: {
...INITIAL_VIEWPORTS,
...newViewports,
},
},
});
```

## withViewport Decorator

Change the default viewport for single/multiple/global stories, or listen to viewport selection changes

```js
import React from 'react';
import { storiesOf, addDecorator } from '@storybook/react';
import { withViewport } from '@storybook/addon-viewport';

// Globablly
addDecorator(withViewport('iphone5'));

// Collection
storiesOf('Decorator with string', module)
.addDecorator(withViewport('iphone6'))
.add('iPhone 6', () => (
<h1>
Do I look good on <b>iPhone 6</b>?
</h1>
));

// Single
storiesOf('Parameterized story', module)
.addDecorator(withViewport())
.add(
'iPad',
() => (
<h1>
Do I look good on <b>iPad</b>?
</h1>
),
{ viewport: 'ipad' }
);

storiesOf('Decorator with object', module)
.addDecorator(
withViewport({
onViewportChange({ viewport }) {
console.log(`Viewport changed: ${viewport.name} (${viewport.type})`); // e.g. Viewport changed: iphone6 (mobile)
},
})
)
.add('onViewportChange', () => <MobileFirstComponent />);

```
1 change: 0 additions & 1 deletion addons/viewport/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ exports.configureViewport = preview.configureViewport;
exports.DEFAULT_VIEWPORT = preview.DEFAULT_VIEWPORT;
exports.INITIAL_VIEWPORTS = preview.INITIAL_VIEWPORTS;
exports.withViewport = preview.withViewport;
exports.Viewport = preview.Viewport;
27 changes: 25 additions & 2 deletions addons/viewport/src/Tool.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import memoize from 'memoizerific';
import deprecate from 'util-deprecate';

import { Global } from '@storybook/theming';

import { Icons, IconButton, WithTooltip, TooltipLinkList } from '@storybook/components';
import { SET_STORIES } from '@storybook/core-events';

import { PARAM_KEY } from './constants';
import { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from './defaults';

const toList = memoize(50)(items =>
items ? Object.entries(items).map(([id, value]) => ({ ...value, id })) : []
Expand All @@ -26,14 +28,35 @@ const createItem = memoize(1000)((id, name, value, change) => ({

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

const deprecatedViewportString = deprecate(
() => 0,
'The viewport parameter must be an object with keys `viewports` and `defaultViewport`'
);
const deprecateOnViewportChange = deprecate(
() => 0,
'The viewport parameter `onViewportChange` is no longer supported'
);

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

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

const { disable, viewports, defaultViewport, onViewportChange } = parameters || {};

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) || 'responsive';
: list.find(i => i.default) || defaultViewport || DEFAULT_VIEWPORT;

const resets =
selected !== 'responsive'
Expand Down
2 changes: 1 addition & 1 deletion addons/viewport/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const ADDON_ID = 'storybook/viewport';
export const PARAM_KEY = 'viewports';
export const PARAM_KEY = 'viewport';

export default {
UPDATE: `${ADDON_ID}/update`,
Expand Down
4 changes: 2 additions & 2 deletions addons/viewport/src/legacy_preview/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import deprecate from 'util-deprecate';

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

export const configureViewport = deprecate(() => {},
'usage is deprecated, use .addParameters({ viewport }) instead');
'configureViewport is no longer supported, use .addParameters({ viewport }) instead');
10 changes: 2 additions & 8 deletions addons/viewport/src/legacy_preview/withViewport.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,11 @@ import deprecate from 'util-deprecate';

const withViewport = makeDecorator({
name: 'withViewport',
parameterName: 'viewports',
allowDeprecatedUsage: true,
parameterName: 'viewport',
wrapper: deprecate(
(getStory, context) => getStory(context),
'usage is deprecated, use .addParameters({ viewport }) instead'
'withViewport is no longer supported, use .addParameters({ viewport }) instead'
),
});

export default withViewport;

export const Viewport = deprecate(
({ children }) => children,
`<Viewport> usage is deprecated, use .addParameters({ viewport }) instead`
);
6 changes: 0 additions & 6 deletions examples/official-storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import React from 'react';
import { storiesOf, configure, addDecorator, addParameters } from '@storybook/react';
import { Global, ThemeProvider, themes, createReset } from '@storybook/theming';

import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { withCssResources } from '@storybook/addon-cssresources';
import { withA11Y } from '@storybook/addon-a11y';
import { withNotes } from '@storybook/addon-notes';

import 'storybook-chromatic';

import addHeadWarning from './head-warning';
import extraViewports from './extra-viewports.json';

if (process.env.NODE_ENV === 'development') {
if (!process.env.DOTENV_DEVELOPMENT_DISPLAY_WARNING) {
Expand Down Expand Up @@ -52,10 +50,6 @@ addParameters({
hierarchySeparator: /\/|\./,
hierarchyRootSeparator: '|',
},
viewports: {
...INITIAL_VIEWPORTS,
...extraViewports,
},
backgrounds: [
{ name: 'storybook app', value: themes.normal.background.app, default: true },
{ name: 'light', value: '#eeeeee' },
Expand Down
18 changes: 0 additions & 18 deletions examples/official-storybook/extra-viewports.json

This file was deleted.

Loading

1 comment on commit 112b9f4

@vercel
Copy link

@vercel vercel bot commented on 112b9f4 Mar 4, 2019

Choose a reason for hiding this comment

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

Deployment failed with the following error:

Builds rate limit exceeded (0 of 32 remaining). Try again in 38m

Please sign in to comment.