Here's a rough plan of where I am interested in taking Storybook's Story API.
The basic idea is to transition towards a new API that is:
- More powerful
- More flexible and interoperable with other tools
- More familiar+idomatic.
The ground work of @storybook/core
has been done, now we can do the fun stuff!
Ideas of what I'd like to add:
The PR for this is ready and will go into 3.5. The next part of this is using it in all the addons. So:
storiesOf('Component', module)
// Instead of this slightly weird API
.add('with some emoji', withNotes('A very simple component')(() => </Component>));
// A more familiar:
.add('with some emoji', () => </Component>, { notes: 'A very simple component' });
It'll make it easy to add per-story parameters to things like storyshots also:
storiesOf('Component', module)
.add('with some emoji', () => </Component>, { storyshots: { skip: true } });
Allow you to do the following in decorators/addons:
addDecorator(story => {
return story({
storyRef: ref => {
// ref is a React ref to the story element, so you can inspect it directly.
}
})
});
I'm not sure what the equivalent concept is in the other view layers, I need to do more research.
Here, by "example" I really just mean the "story component": ie the () => <Component with={props} />
part
(this is just a stateless functional component after all).
In order to allow many many other things, for instance reusing story examples in tests, we should move towards an API where the component examples are defined separately from the storybook parts, which after all are just a mechanism to describe in-storybook-UI behaviour (see below).
So, at first:
import { storiesOf } from '@storybook/react';
import Component from './Component';
export basic = () => <Component with="basic-props" />;
export complex = () => <Component with="complex-props" />;
storiesOf('Component', module)
.add('basic', basic, { params }); //etc
Moving perhaps towards a world where you don't need to worry about the boilerplate storiesOf
etc.
(Not sure where the params / other decorators are best defined).
A second step could be defining the examples in Component.examples.js
so that the stories file becomes:
import { storiesOf } from '@storybook/react';
import Component from './Component';
import { basic, complex } from './Component.examples';
storiesOf('Component', module)
.add('basic', basic, { params }); //etc
Note that this doesn't necessarily require a change to anything bar documentation.
As an example of what the above gives you, here is a test that reuses an example:
import React from 'react';
import { shallow } from 'enzyme';
import { basic } from './Component.examples';
describe('Component', () => {
it('the basic example renders three Foos', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find(Foo)).to.have.length(3);
});
});
Ultimately we may want to make storybook autodetect *.example.js
and do something smart with them.
Apologies that this section is not tightly specced at all
Make it easy to define Component.README.md
or the like that can use the component's examples.
We would add a new "context" to the build (in addition to manager and preview) that would render markdown files into a documentation style UI. Each markdown file can contain one or more preview iframe rendered based on some syntax (probably borrowed from styleguidist or equivalent):
## My component
Here is the basic description, let's see it:
<Story name="basic" />
Here's the source:
<StorySource name="basic" />
This would lead toward a migration of documentation style addons away from the current manager UI (so strip down the current UI to be more focused on development). But that would be a few more steps away.
We would want a way to customize addons per-components, have a documentation template, and more.