Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ There are many things you can do with React Storybook. You can explore them with
* [Writing Stories](docs/writing_stories.md)
* [Setting up for CSS](docs/setting_up_for_css.md)
* [Configuration APIs](docs/configure_storybook.md)
* [Extensions](docs/extensions.md)
* [Power Tools](https://voice.kadira.io/power-tools-for-react-storybook-d404d7b29b82#.4yodlbqi8)
* [How Storybook Works](docs/how_storybook_works.md)
* [Known Issues](docs/known_issues.md)
Expand Down
4 changes: 3 additions & 1 deletion dist/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.configure = exports.linkTo = exports.action = exports.storiesOf = undefined;
exports.configure = exports.addDecorator = exports.setAddon = exports.linkTo = exports.action = exports.storiesOf = undefined;

var _preview = require('./preview');

Expand All @@ -14,4 +14,6 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
var storiesOf = exports.storiesOf = previewApi.storiesOf;
var action = exports.action = previewApi.action;
var linkTo = exports.linkTo = previewApi.linkTo;
var setAddon = exports.setAddon = previewApi.setAddon;
var addDecorator = exports.addDecorator = previewApi.addDecorator;
var configure = exports.configure = previewApi.configure;
57 changes: 50 additions & 7 deletions dist/client/preview/client_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ var _from = require('babel-runtime/core-js/array/from');

var _from2 = _interopRequireDefault(_from);

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');

var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
Expand All @@ -30,9 +38,21 @@ var ClientApi = function () {

this._pageBus = pageBus;
this._storyStore = storyStore;
this._addons = {};
this._globalDecorators = [];
}

(0, _createClass3.default)(ClientApi, [{
key: 'setAddon',
value: function setAddon(addon) {
this._addons = (0, _extends3.default)({}, this._addons, addon);
}
}, {
key: 'addDecorator',
value: function addDecorator(decorator) {
this._globalDecorators.push(decorator);
}
}, {
key: 'storiesOf',
value: function storiesOf(kind, m) {
var _this = this;
Expand All @@ -43,16 +63,39 @@ var ClientApi = function () {
});
}

var decorators = [];
var api = {};
var localDecorators = [];
var api = {
kind: kind
};

// apply addons
for (var name in this._addons) {
if (this._addons.hasOwnProperty(name)) {
(function () {
var addon = _this._addons[name];
api[name] = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}

addon.apply(api, args);
return api;
};
})();
}
}

api.add = function (storyName, getStory) {
// Wrap the getStory function with each decorator. The first
// decorator will wrap the story function. The second will
// wrap the first decorator and so on.
var decorators = [].concat(localDecorators, (0, _toConsumableArray3.default)(_this._globalDecorators));

var fn = decorators.reduce(function (decorated, decorator) {
return function () {
return decorator(decorated);
return function (context) {
return decorator(function () {
return decorated(context);
}, context);
};
}, getStory);

Expand All @@ -62,7 +105,7 @@ var ClientApi = function () {
};

api.addDecorator = function (decorator) {
decorators.push(decorator);
localDecorators.push(decorator);
return api;
};

Expand All @@ -74,8 +117,8 @@ var ClientApi = function () {
var pageBus = this._pageBus;

return function () {
for (var _len = arguments.length, _args = Array(_len), _key = 0; _key < _len; _key++) {
_args[_key] = arguments[_key];
for (var _len2 = arguments.length, _args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
_args[_key2] = arguments[_key2];
}

var args = (0, _from2.default)(_args);
Expand Down
4 changes: 3 additions & 1 deletion dist/client/preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.configure = exports.linkTo = exports.action = exports.storiesOf = undefined;
exports.configure = exports.addDecorator = exports.setAddon = exports.linkTo = exports.action = exports.storiesOf = undefined;

require('es6-shim');

Expand Down Expand Up @@ -60,6 +60,8 @@ var configApi = new _config_api2.default(context);
var storiesOf = exports.storiesOf = clientApi.storiesOf.bind(clientApi);
var action = exports.action = clientApi.action.bind(clientApi);
var linkTo = exports.linkTo = clientApi.linkTo.bind(clientApi);
var setAddon = exports.setAddon = clientApi.setAddon.bind(clientApi);
var addDecorator = exports.addDecorator = clientApi.addDecorator.bind(clientApi);
var configure = exports.configure = configApi.configure.bind(configApi);

// initialize the UI
Expand Down
24 changes: 12 additions & 12 deletions dist/manager.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/manager.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 95 additions & 0 deletions docs/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# React Storybook Extensions

React Storybook comes with an extensions API to customize the storybook experience. Let's have a look at them.

## TOC

* [API](#api)
* [Decorators](#decorators)
* [Addons](#addons)
* [Available Extensions](#available-extensions)

## API

### Decorators

A decorator is a way to wrap an story with a common set of component(s). Let's say you want to center all your stories. Then this is how we can do it with a decorator:

```js
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import MyComponent from '../my_component';

storiesOf('MyComponent', module)
.addDecorator((story) => (
<div style={{textAlign: 'center'}}>
{story()}
</div>
));
.add('without props', () => (<MyComponent />))
.add('with some props', () => (<MyComponent text="The Comp"/>));
```

Here we only add the decorator for the current set of stories for a given story kind.

But, you can add a decorator **globally** and it'll be applied to all the stories you create. This is how to add a decorator like that.

```js
import { configure, addDecorator } from '@kadira/storybook';

addDecorator((story) => (
<div style={{textAlign: 'center'}}>
{story()}
</div>
));

configure(function () {
...
}, module);
```

### Addons

With an addon, you can introduce new methods to the story creation API. For an example, you can achieve the above centered component functionality with an addon like this:

```js
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import MyComponent from '../my_component';

storiesOf('MyComponent', module)
.addWithCentered('without props', () => (<MyComponent />))
.addWithCentered('with some props', () => (<MyComponent text="The Comp"/>));
```
Here we are using a new API called `addWithCentered`. That's introduce by an addon.

This is how we set that addon.

```js
import { configure, setAddon } from '@kadira/storybook';

setAddon({
addWithCentered(storyName, storyFn) {
// You can access the .add and other API added by addons in here.
this.add(storyName, (context) => (
<div style={{textAlign: "center"}}>
{storyFn(context)}
</div>
));
}
});

configure(function () {
...
}, module);
```

## Available Extensions

Rather than creating extensions yourself, you can use extensions available below:

* [Centered Decorator](https://github.com/kadirahq/react-storybook-decorator-centered)
* [Info addon for displaying propTypes, source and more info](https://github.com/kadirahq/react-storybook-addon-info)

> Feel free to include your extension to the above list and share it with other. <br/>
> Just make it available on NPM (and GitHub) and send a PR to this page.
53 changes: 7 additions & 46 deletions docs/writing_stories.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

* [Basic API](#basic-api)
* [Creating Actions](#creating-actions)
* [Using Decorators](#using-decorators)
* [Linking Stories](#linking-stories)
* [Use Extensions](#use-extensions)

You need to write stories to show your components inside React Storybook. We've a set of APIs allows you to write stories and do more with them:

Expand Down Expand Up @@ -76,51 +76,6 @@ Here we can see the name we've mentioned when creating the action. After that, w

> For simplicity, React Storybook does not show the actual object. Instead it will show `[SyntheticEvent]`.

## Using Decorators

In some apps, we need to wrap our components with a given context. Most of the time, you have to do this when you are using Material UI or Radium.

So, you need to write your stories like this:

```js
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import Theme from '../theme';
import MyComponent from '../my_component';

storiesOf('MyComponent', modules)
.add('without props', () => (
<Theme>
<MyComponent />
</Theme>
))
.add('with some props', () => (
<Theme>
<MyComponent name="Arunoda"/>
</Theme>
));
```

As you can see, you always need to wrap your components with the `Theme` component. But, there's a much better way. See following example with a decorator:

```js
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import Theme from '../theme';
import MyComponent from '../my_component';

storiesOf('MyComponent', modules)
.addDecorator((story) => (
<Theme>
{story()}
</Theme>
))
.add('without props', () => (<MyComponent />))
.add('with some props', () => (<MyComponent name="Arunoda"/>));
```

You can add as many as decorators you want, but make sure to call `.addDecorator()` before you call `.add()`.

## Linking Stories

Sometimes, we may need to link stories. With that, we could use Storybook as a prototype builder. (like [InVision](https://www.invisionapp.com/), [Framer.js](http://framerjs.com/)). Here's how to do that.
Expand Down Expand Up @@ -153,3 +108,9 @@ With that, you can link an event prop to any story in the Storybook.
> You can also pass a function instead for any of above parameter. That function accepts arguments emitted by the event and it should return a string.

Have a look at [PR86](https://github.com/kadirahq/react-storybook/pull/86) for more information.

## Use Extensions

You can use [React Storybook Extensions](extensions.md) to group common functionalities and reduce the amount of code you need to write. You can also [re-use extensions](extensions.md#available-extensions) created by others.

Have a look at [React Storybook Extensions](extensions.md) for more information.
2 changes: 2 additions & 0 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ import * as previewApi from './preview';
export const storiesOf = previewApi.storiesOf;
export const action = previewApi.action;
export const linkTo = previewApi.linkTo;
export const setAddon = previewApi.setAddon;
export const addDecorator = previewApi.addDecorator;
export const configure = previewApi.configure;
Loading