Skip to content

Commit

Permalink
Merge pull request #3965 from storybooks/tmeasday/add-params-to-optio…
Browse files Browse the repository at this point in the history
…ns-addon

Add params-based API to options addon
  • Loading branch information
Hypnosphi authored Sep 8, 2018
2 parents b96f1d3 + d309b91 commit 1dc036e
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 220 deletions.
194 changes: 100 additions & 94 deletions addons/options/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,114 +20,120 @@ Add this line to your `addons.js` file (create this file inside your storybook c
import '@storybook/addon-options/register';
```

Import and use the `setOptions` function in your config.js file.
Import and use the `withOptions` decorator in your config.js file.

```js
import * as storybook from '@storybook/react';
import { setOptions } from '@storybook/addon-options';
import { addDecorator, configure } from '@storybook/react';
import { withOptions } from '@storybook/addon-options';

// Option defaults:
setOptions({
/**
* name to display in the top left corner
* @type {String}
*/
name: 'Storybook',
/**
* URL for name in top left corner to link to
* @type {String}
*/
url: '#',
/**
* show story component as full screen
* @type {Boolean}
*/
goFullScreen: false,
/**
* display panel that shows a list of stories
* @type {Boolean}
*/
showStoriesPanel: true,
/**
* display panel that shows addon configurations
* @type {Boolean}
*/
showAddonPanel: true,
/**
* display floating search box to search through stories
* @type {Boolean}
*/
showSearchBox: false,
/**
* show addon panel as a vertical panel on the right
* @type {Boolean}
*/
addonPanelInRight: false,
/**
* sorts stories
* @type {Boolean}
*/
sortStoriesByKind: false,
/**
* regex for finding the hierarchy separator
* @example:
* null - turn off hierarchy
* /\// - split by `/`
* /\./ - split by `.`
* /\/|\./ - split by `/` or `.`
* @type {Regex}
*/
hierarchySeparator: null,
/**
* regex for finding the hierarchy root separator
* @example:
* null - turn off multiple hierarchy roots
* /\|/ - split by `|`
* @type {Regex}
*/
hierarchyRootSeparator: null,
/**
* sidebar tree animations
* @type {Boolean}
*/
sidebarAnimations: true,
/**
* id to select an addon panel
* @type {String}
*/
selectedAddonPanel: undefined, // The order of addons in the "Addon panel" is the same as you import them in 'addons.js'. The first panel will be opened by default as you run Storybook
/**
* enable/disable shortcuts
* @type {Boolean}
*/
enableShortcuts: false, // true by default
});

storybook.configure(() => require('./stories'), module);
addDecorator(
withOptions({
/**
* name to display in the top left corner
* @type {String}
*/
name: 'Storybook',
/**
* URL for name in top left corner to link to
* @type {String}
*/
url: '#',
/**
* show story component as full screen
* @type {Boolean}
*/
goFullScreen: false,
/**
* display panel that shows a list of stories
* @type {Boolean}
*/
showStoriesPanel: true,
/**
* display panel that shows addon configurations
* @type {Boolean}
*/
showAddonPanel: true,
/**
* display floating search box to search through stories
* @type {Boolean}
*/
showSearchBox: false,
/**
* show addon panel as a vertical panel on the right
* @type {Boolean}
*/
addonPanelInRight: false,
/**
* sorts stories
* @type {Boolean}
*/
sortStoriesByKind: false,
/**
* regex for finding the hierarchy separator
* @example:
* null - turn off hierarchy
* /\// - split by `/`
* /\./ - split by `.`
* /\/|\./ - split by `/` or `.`
* @type {Regex}
*/
hierarchySeparator: null,
/**
* regex for finding the hierarchy root separator
* @example:
* null - turn off multiple hierarchy roots
* /\|/ - split by `|`
* @type {Regex}
*/
hierarchyRootSeparator: null,
/**
* sidebar tree animations
* @type {Boolean}
*/
sidebarAnimations: true,
/**
* id to select an addon panel
* @type {String}
*/
selectedAddonPanel: undefined, // The order of addons in the "Addon panel" is the same as you import them in 'addons.js'. The first panel will be opened by default as you run Storybook
/**
* enable/disable shortcuts
* @type {Boolean}
*/
enableShortcuts: false, // true by default
})
);

configure(() => require('./stories'), module);
```

### using withOptions options or parameters
### Using per-story options

The options-addon accepts story paramters to set options (as shown below).
The options-addon accepts story parameters on the `options` key:

```js
import { storiesOf } from '@storybook/marko';
import { withKnobs, text, number } from '@storybook/addon-knobs';
import { withOptions } from '@storybook/addon-options';
import Hello from '../components/hello/index.marko';

storiesOf('Addons|Knobs/Hello', module)
.addDecorator(withOptions)
.addDecorator(withKnobs)
// If you want to set the option for all stories in of this kind
.addParameters({ options: { addonPanelInRight: true } })
.add('Simple', () => {
const name = text('Name', 'John Doe');
const age = number('Age', 44);
return Hello.renderSync({
name,
age,
});
});
.addDecorator(withKnobs)
.add(
'Simple',
() => {
const name = text('Name', 'John Doe');
const age = number('Age', 44);
return Hello.renderSync({
name,
age,
});
},
// If you want to set the options for a specific story
{ options: { addonPanelInRight: false } }
);
```

It is also possible to call `setOptions()` inside individual stories. Note that this will bring impact story render performance significantly.
_NOTE_ that you must attach `withOptions` as a decorator (at the top-level) for this to work.
3 changes: 2 additions & 1 deletion addons/options/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.21"
"@storybook/addons": "4.0.0-alpha.21",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "*"
Expand Down
1 change: 0 additions & 1 deletion addons/options/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ const preview = require('./dist/preview');

exports.setOptions = preview.setOptions;
exports.withOptions = preview.withOptions;

preview.init();
53 changes: 23 additions & 30 deletions addons/options/src/preview/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import deprecate from 'util-deprecate';
import addons, { makeDecorator } from '@storybook/addons';
import { EVENT_ID } from '../shared';

Expand All @@ -21,9 +22,7 @@ function withRegexProp(object, propName) {
return hasOwnProp(object, propName) ? { [propName]: regExpStringify(object[propName]) } : {};
}

// setOptions function will send Storybook UI options when the channel is
// ready. If called before, options will be cached until it can be sent.
export function setOptions(newOptions) {
function emitOptions(options) {
const channel = addons.getChannel();
if (!channel) {
throw new Error(
Expand All @@ -33,39 +32,33 @@ export function setOptions(newOptions) {

// since 'undefined' and 'null' are the valid values we don't want to
// override the hierarchySeparator or hierarchyRootSeparator if the prop is missing
const options = {
...newOptions,
...withRegexProp(newOptions, 'hierarchySeparator'),
...withRegexProp(newOptions, 'hierarchyRootSeparator'),
};

channel.emit(EVENT_ID, { options });
channel.emit(EVENT_ID, {
options: {
...options,
...withRegexProp(options, 'hierarchySeparator'),
...withRegexProp(options, 'hierarchyRootSeparator'),
},
});
}

// setOptions function will send Storybook UI options when the channel is
// ready. If called before, options will be cached until it can be sent.
let globalOptions = {};
export const setOptions = deprecate(options => {
globalOptions = options;
emitOptions(options);
}, '`setOptions(options)` is deprecated. Please use the `withOptions(options)` decorator globally.');

export const withOptions = makeDecorator({
name: 'withOptions',
parameterName: 'options',
skipIfNoParametersOrOptions: false,
allowDeprecatedUsage: true,
wrapper: (getStory, context, { newOptions, parameters }) => {
const optionsIn = parameters || newOptions || {};

const channel = addons.getChannel();
if (!channel) {
throw new Error(
'Failed to find addon channel. This may be due to https://github.com/storybooks/storybook/issues/1192.'
);
}

// since 'undefined' and 'null' are the valid values we don't want to
// override the hierarchySeparator or hierarchyRootSeparator if the prop is missing
const options = {
...optionsIn,
...withRegexProp(optionsIn, 'hierarchySeparator'),
...withRegexProp(optionsIn, 'hierarchyRootSeparator'),
};

channel.emit(EVENT_ID, { options });
wrapper: (getStory, context, { options: inputOptions, parameters }) => {
emitOptions({
...globalOptions,
...inputOptions,
...parameters,
});

return getStory(context);
},
Expand Down
13 changes: 2 additions & 11 deletions examples/marko-cli/src/stories/index.stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { storiesOf } from '@storybook/marko';
import { withOptions } from '@storybook/addon-options';
import Hello from '../components/hello/index.marko';
import ClickCount from '../components/click-count/index.marko';
import StopWatch from '../components/stop-watch/index.marko';
Expand All @@ -8,17 +7,9 @@ import Welcome from '../components/welcome/index.marko';
storiesOf('Welcome', module).add('welcome', () => Welcome.renderSync({}));

storiesOf('Hello', module)
.addDecorator(withOptions)
.addParameters({ options: { addonPanelInRight: false } })
.add('Simple', () => Hello.renderSync({ name: 'abc', age: 20 }))
.add('with ERROR!', () => 'NOT A MARKO RENDER_RESULT');

storiesOf('ClickCount', module)
.addDecorator(withOptions)
.addParameters({ options: { addonPanelInRight: true } })
.add('Simple', () => ClickCount.renderSync({}), { hierarchyRootSeparator: /\|/ });
storiesOf('ClickCount', module).add('Simple', () => ClickCount.renderSync({}));

storiesOf('StopWatch', module)
.addDecorator(withOptions)
.addParameters({ options: { addonPanelInRight: false } })
.add('Simple', () => StopWatch.renderSync({}));
storiesOf('StopWatch', module).add('Simple', () => StopWatch.renderSync({}));
14 changes: 8 additions & 6 deletions examples/official-storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import ThemeProvider from '@emotion/provider';
import { configure, addDecorator } from '@storybook/react';
import { themes } from '@storybook/components';
import { setOptions } from '@storybook/addon-options';
import { withOptions } from '@storybook/addon-options';
import { configureViewport, INITIAL_VIEWPORTS } from '@storybook/addon-viewport';

import 'react-chromatic/storybook-addon';
Expand All @@ -12,11 +12,13 @@ import extraViewports from './extra-viewports.json';
addHeadWarning('Preview head not loaded', 'preview-head-not-loaded');
addHeadWarning('Dotenv file not loaded', 'dotenv-file-not-loaded');

setOptions({
hierarchySeparator: /\/|\./,
hierarchyRootSeparator: /\|/,
theme: themes.dark,
});
addDecorator(
withOptions({
hierarchySeparator: /\/|\./,
hierarchyRootSeparator: /\|/,
theme: themes.dark,
})
);

addDecorator(
(story, { kind }) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Storyshots Addons|Options withOptions hiding addon panel 1`] = `
<div>
This story should have changed hidden the addons panel
</div>
`;

exports[`Storyshots Addons|Options withOptions setting name 1`] = `
<div>
This story should have changed the name of the storybook
</div>
`;
22 changes: 22 additions & 0 deletions examples/official-storybook/stories/addon-options.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { storiesOf } from '@storybook/react';

storiesOf('Addons|Options', module)
.add(
'withOptions setting name',
() => <div>This story should have changed the name of the storybook</div>,
{
options: {
name: 'Custom Storybook',
},
}
)
.add(
'withOptions hiding addon panel',
() => <div>This story should have changed hidden the addons panel</div>,
{
options: {
showAddonPanel: false,
},
}
);
Loading

0 comments on commit 1dc036e

Please sign in to comment.