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

Use parameters for info addon #3697

Merged
merged 15 commits into from
Jun 9, 2018
Merged
Show file tree
Hide file tree
Changes from 11 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
191 changes: 113 additions & 78 deletions addons/info/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,102 +25,155 @@ npm i -D @storybook/addon-info
```

## Basic usage
Then, add `withInfo` as a decarator to your book of stories.
It is possible to add `info` by default to all or a subsection of stories by using a global or story decorator.

Then wrap your story with the `withInfo`, which is a function that takes either
documentation text or an options object:
It is important to declare this decorator as **the first decorator**, otherwise it won't work well.

```js
import { withInfo } from '@storybook/addon-info';

addDecorator(withInfo); // Globally in your .storybook/config.js.
```
or
```js
storiesOf('Component', module)
.add('simple info',
withInfo(`
description or documentation about my component, supports markdown

~~~js
<Button>Click Here</Button>
~~~

`)(() =>
<Component>Click the "?" mark at top-right to view the info.</Component>
)
)
.addDecorator(withInfo) // At your stories directly.
.add(...);
```

## Usage with options
Then, you can use the `info` parameter to either pass certain options or specific documentation text to your stories.
A complete list of possible configurations can be found at [in a later section](#setting-global-options).
This can be done per book of stories:

`withInfo` can also take an [options object](#global-options) in case you want to configure how
the info panel looks on a per-story basis:
```js
import { storiesOf } from '@storybook/react';

import Component from './Component';

storiesOf('Component', module)
.addParameters({
info: {
// Your settings
}
})
.add('with some emoji', () => <Component/>);
```

...or for each story individually:
```js
import { withInfo } from '@storybook/addon-info';
import { storiesOf } from '@storybook/react';

import Component from './Component';

storiesOf('Component', module)
.add('simple info',
withInfo({
styles: {
header: {
h1: {
color: 'red'
}
}
},
text: 'String or React Element with docs about my component', // Warning! This option's name will be likely renamed to "summary" in 3.3 release. Follow this PR #1501 for details
// other possible options see in Global options section below
})(() =>
<Component>Click the "?" mark at top-right to view the info.</Component>
)
)
.add(
'with some emoji',
() => <Component emoji/>,
{ info : { inline: false, header: false } } // Make your component render inline with the additional info
)
.add(
'with no emoji',
() => <Component/>,
{ info: '☹️ no emojis' } // Add additional info text directly
);
```

The `styles` prop can also accept a function. The default stylesheet is passed as argument:
...or even together:

```js
import { withInfo } from '@storybook/addon-info';
import { storiesOf } from '@storybook/react';

import Component from './Component';

storiesOf('Component', module)
.add('custom info styles using a function',
withInfo({
styles: stylesheet => ({
...stylesheet,
.addParameters({
info: { // Make a default for all stories in this book,
inline: true, // where the components are inlined
styles: {
header: {
...stylesheet.header,
h1: {
...stylesheet.header.h1,
color: 'red'
color: 'red' // and the headers of the sections are red.
}
}
})
})(() =>
<Component>Click the "?" mark at top-right to view the info.</Component>
)
)
},
}
})
.add(
'green version',
() => <Component green/>,
{
info: {
styles: stylesheet => ({ // Setting the style with a function
...stylesheet,
header: {
...stylesheet.header,
h1: {
...stylesheet.header.h1,
color: 'green' // Still inlined but with green headers!
}
}
})
}
})
.add(
'something else',
() => <Component different/>,
{
info: "This story has additional text added to the info!" // Still inlined and with red headers!
}
);
```

## Usage as decorator
It is also possible to disable the `info` addon entirely.
Depending on the scope at which you want to disable the addon, pass the following parameters object either to an individual story or to an `addParameters` call.

```
{
info: {
disable: true
}
}
```

It is possible to add infos by default to all components by using a global or story decorator. The drawback is you won't be able to display a distinct info message per story.
## Markdown
The `info` addon also supports markdown.
To use markdown as additional textual documentation for your stories, either pass it directly as a String to the `info` parameters, or use the `text` option.

It is important to declare this decorator as **the first decorator**, otherwise it won't work well.

```js
addDecorator((story, context) => withInfo('common info')(story)(context));
storiesOf('Button', module)
.add(
'Button Component',
() => <Button />,
{
info: {
text: `
description or documentation about my component, supports markdown

~~~js
<Button>Click Here</Button>
~~~
`
}
}
);
```

## Global options
## Setting Global Options

To configure default options for all usage of the info option, use `setDefaults` in `.storybook/config.js`:
To configure default options for all usage of the info addon, pass a option object along with the decorator in `.storybook/config.js`.

```js
// config.js
import { setDefaults } from '@storybook/addon-info';
import { withInfo } from '@storybook/addon-info';

// addon-info
setDefaults({
header: false, // Toggles display of header with component name and description
});
addDecorator(withInfo({
header: false, // Global configuration for the info addon across all of your stories.
}));
```

Configuration parameters can be set at 3 different locations: passed as default options along the `addDecorator` call, passed as an object of parameters to a book of stories to the `addParameters` call, and passed as direct parameters to each individual story.
In order, all of them will be combined together, with a later call overriding the previous set configurations on a per-key basis.

## Options and Defaults

```js
Expand All @@ -141,24 +194,6 @@ setDefaults({
}
```

## Customizing defaults

To customize your defaults:

```js
// config.js
import { setDefaults } from '@storybook/addon-info';

// addon-info
setDefaults({
inline: true,
maxPropsIntoLine: 1,
maxPropObjectKeys: 10,
maxPropArrayLength: 10,
maxPropStringLength: 100,
});
```

### Rendering a Custom Table

The `TableComponent` option allows you to define how the prop table should be rendered. Your component will be rendered with the following props.
Expand Down
4 changes: 3 additions & 1 deletion addons/info/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.8",
"@storybook/client-logger": "4.0.0-alpha.8",
"@storybook/components": "4.0.0-alpha.8",
"babel-runtime": "^6.26.0",
Expand All @@ -24,7 +25,8 @@
"prop-types": "^15.6.1",
"react-addons-create-fragment": "^15.5.3",
"react-emotion": "^9.1.3",
"react-lifecycles-compat": "^3.0.4"
"react-lifecycles-compat": "^3.0.4",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"react-test-renderer": "^16.4.0"
Expand Down
22 changes: 17 additions & 5 deletions addons/info/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import nestedObjectAssign from 'nested-object-assign';
import deprecate from 'util-deprecate';
import { makeDecorator } from '@storybook/addons';
import { logger } from '@storybook/client-logger';
import Story from './components/Story';
import PropTable from './components/PropTable';
Expand Down Expand Up @@ -82,13 +84,23 @@ function addInfo(storyFn, context, infoOptions) {
return <Story {...props}>{storyFn(context)}</Story>;
}

export const withInfo = textOrOptions => {
const options = typeof textOrOptions === 'string' ? { text: textOrOptions } : textOrOptions;
return storyFn => context => addInfo(storyFn, context, options);
};
export const withInfo = makeDecorator({
name: 'withInfo',
parameterName: 'info',
wrapper: (getStory, context, { options, parameters }) => {
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to skip the addon if they don't set options or parameters? Either by passing skipIfNoOptionsOrParameters: true or manually doing it here..

Copy link
Member

Choose a reason for hiding this comment

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

Otherwise (or maybe anyway) we should document setting { info: { disable: true } }

Copy link
Contributor Author

@Keraito Keraito Jun 2, 2018

Choose a reason for hiding this comment

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

Def agree with the disable: true part, will do. I'm not so sure about the skipIfNoOptionsOrParameters part though. I assume the both of them do the same thing, namely disable the addon entirely. But info is slightly different from the others addons imo that it does something even without configuration: display Proptypes, the component, etc.

Example: https://github.com/storybooks/storybook/pull/3697/files#diff-c915ecbefba3a2734ebd93eb258431dbR353 This is basically an parameters- and options-less story, besides some minor options (header styling) and parameters (inline and manual text). The configuration don't add a lot, but the addon itself adds a lot of information stand-alone already.

So I would say just only documenting the disable flag should be the only way

Copy link
Member

Choose a reason for hiding this comment

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

Ok, makes sense. Thanks for thinking about that.

const storyOptions = parameters || options;
const infoOptions = typeof storyOptions === 'string' ? { text: storyOptions } : storyOptions;
const mergedOptions =
typeof infoOptions === 'string' ? infoOptions : { ...options, ...infoOptions };
return addInfo(getStory, context, mergedOptions);
},
});

export { Story };

export function setDefaults(newDefaults) {
return Object.assign(defaultOptions, newDefaults);
return deprecate(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't feel like this is how I should've implemented the depreciation, but only this worked for me for some reason.

Copy link
Member

Choose a reason for hiding this comment

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

@Keraito you tried export const setDefaults = deprecate(newDefaults => Object.assign(...), 'setDefaults is ...')

I mean what you have is fine anyway ;)

() => Object.assign(defaultOptions, newDefaults),
'setDefaults is deprecated. Instead, you can pass options into withInfo(options) directly, or use the info parameter.'
)();
}
Loading