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

CSF: Promote args/argTypes to first-class metadata #10117

Merged
merged 2 commits into from
Mar 12, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/official-storybook/stories/core/args.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const PassedToStory = inputArgs => {
};

PassedToStory.story = {
parameters: { argTypes: { name: { defaultValue: 'initial' } } },
argTypes: { name: { defaultValue: 'initial' } },
};

PassedToStory.propTypes = {
Expand Down
4 changes: 2 additions & 2 deletions lib/client-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ For instance, for this story:

```js
export MyStory = ....
MyStory.story = { parameters: {
MyStory.story = {
argTypes: {
primary: { defaultValue: true, /* other things */ },
size: { /* other things */ },
Expand All @@ -80,7 +80,7 @@ MyStory.story = { parameters: {
size: 'large',
extra: 'prop',
}
}}
}
```

Then `context.args` will default to `{ primary: true, size: 'large', extra: 'prop' }`.
Expand Down
6 changes: 3 additions & 3 deletions lib/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ The `start` module initiaizes all the submodules:

- `StoryStore` (from `@storybook/client-api`) - stores the stories and their state as well as the current selection or error.
- `ClientApi` (from `@storybook/client-api`) - provides the entry point for `storiesOf()` API calls; re-exported by each framework.
- `ConfigApi` (from `@storybook/client-api`) - provides the configure API (wrapped by `makeConfigure` below).
- `ConfigApi` (from `@storybook/client-api`) - provides the configure API (wrapped by `loadCsf` below).
- `StoryRenderer` - controls the HTML that is rendered in the preview (calling the `render` function with the current story at appropriate times).
- `url.js` - controls the URL in the preview and sets the selection based on it.
- `makeConfigure` - loads CSF files from `require.context()` calls and uses `ClientApi` to load them into the store.
- `loadCsf` - loads CSF files from `require.context()` calls and uses `ClientApi` to load them into the store.

Each module uses the channel to communicate with each other and the manager. Each module also has direct access to the story store.

### Events on startup

The store can only be changed during "configuration". The `ConfigApi` will call `store.startConfiguration()`, then the user code (or `makeConfigure`'s loader) which will use client API to load up stories. At the end of the user's code the `ConfigApi` will call `store.finishConfiguration()`. At this point the `SET_STORIES` event is emitted and the stories are transmitted to the manager.
The store can only be changed during "configuration". The `ConfigApi` will call `store.startConfiguration()`, then the user code (or `loadCsf`'s loader) which will use client API to load up stories. At the end of the user's code the `ConfigApi` will call `store.finishConfiguration()`. At this point the `SET_STORIES` event is emitted and the stories are transmitted to the manager.

The `SET_CURRENT_STORY` "command" event can be used to set the selection on the store. However only once this has been recieved _and_ configuration is over will the store use the `RENDER_CURRENT_STORY` to tell the `StoryRenderer` to render it.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ConfigApi, ClientApi, StoryStore } from '@storybook/client-api';
import { RequireContext } from './types';

import { makeConfigure } from './makeConfigure';
import { loadCsf } from './loadCsf';

let cbs: ((data: any) => void)[];
let mod: NodeModule;
Expand Down Expand Up @@ -39,7 +39,7 @@ function makeMocks() {
} as unknown) as ClientApi;

const context = { configApi, storyStore, clientApi };
const configure = makeConfigure(context);
const configure = loadCsf(context);
return { ...context, configure };
}

Expand All @@ -52,7 +52,7 @@ function makeRequireContext(map: Record<string, any>): RequireContext {
});
}

describe('core.preview.makeConfigure', () => {
describe('core.preview.loadCsf', () => {
it('calls storiesOf and add correctly from CSF exports', () => {
const { configure, clientApi } = makeMocks();

Expand Down Expand Up @@ -197,7 +197,7 @@ describe('core.preview.makeConfigure', () => {
});
});

it('allows setting component parameters and decorators', () => {
it('allows setting component parameters, decorators, and args/argTypes', () => {
const { configure, clientApi } = makeMocks();

const decorator = jest.fn();
Expand All @@ -207,6 +207,8 @@ describe('core.preview.makeConfigure', () => {
title: 'a',
parameters: { x: 'y' },
decorators: [decorator],
args: { b: 1 },
argTypes: { b: 'string' },
},
x: () => 0,
},
Expand All @@ -215,11 +217,13 @@ describe('core.preview.makeConfigure', () => {

const mockedStoriesOf = clientApi.storiesOf as jest.Mock;
const aApi = mockedStoriesOf.mock.results[0].value;
expect(aApi.addParameters).toHaveBeenCalledWith(expect.objectContaining({ x: 'y' }));
expect(aApi.addParameters).toHaveBeenCalledWith(
expect.objectContaining({ x: 'y', args: { b: 1 }, argTypes: { b: 'string' } })
);
expect(aApi.addDecorator).toHaveBeenCalledWith(decorator);
});

it('allows setting story parameters and decorators', () => {
it('allows setting story parameters and decorators, and args/argTypes', () => {
const { configure, clientApi } = makeMocks();

const decorator = jest.fn();
Expand All @@ -232,6 +236,8 @@ describe('core.preview.makeConfigure', () => {
story: {
parameters: { x: 'y' },
decorators: [decorator],
args: { b: 1 },
argTypes: { b: 'string' },
},
}),
},
Expand All @@ -244,6 +250,8 @@ describe('core.preview.makeConfigure', () => {
x: 'y',
decorators: [decorator],
__id: 'a--x',
args: { b: 1 },
argTypes: { b: 'string' },
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ const loadStories = (
const {
title: kindName,
id: componentId,
parameters: params,
decorators: decos,
parameters: kindParameters,
decorators: kindDecorators,
component,
subcomponents,
args: kindArgs,
argTypes: kindArgTypes,
} = meta;
// We pass true here to avoid the warning about HMR. It's cool clientApi, we got this
// todo discuss: TS now wants a NodeModule; should we fix this differently?
Expand All @@ -103,38 +105,44 @@ const loadStories = (
component,
subcomponents,
fileName: currentExports.get(fileExports),
...params,
...kindParameters,
args: kindArgs,
argTypes: kindArgTypes,
});

// todo add type
(decos || []).forEach((decorator: any) => {
(kindDecorators || []).forEach((decorator: any) => {
kind.addDecorator(decorator);
});

Object.keys(exports).forEach(key => {
if (isExportStory(key, meta)) {
const storyFn = exports[key];
const { name, parameters, decorators } = storyFn.story || {};
const { name, parameters, decorators, args, argTypes } = storyFn.story || {};
if (parameters && parameters.decorators) {
deprecate(() => {},
`${kindName} => ${name || key}: story.parameters.decorators is deprecated; use story.decorators instead.`)();
}
const decoratorParams = decorators ? { decorators } : null;
const exportName = storyNameFromExport(key);
const idParams = { __id: toId(componentId || kindName, exportName) };
kind.add(name || exportName, storyFn, {

const storyParams = {
...parameters,
...decoratorParams,
...idParams,
});
args,
argTypes,
};
kind.add(name || exportName, storyFn, storyParams);
}
});
});
previousExports = currentExports;
};

let loaded = false;
export const makeConfigure = ({
export const loadCsf = ({
clientApi,
storyStore,
configApi,
Expand Down
4 changes: 2 additions & 2 deletions lib/core/src/client/preview/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Events from '@storybook/core-events';

import { initializePath, setPath } from './url';
import { RenderStoryFunction } from './types';
import { makeConfigure } from './makeConfigure';
import { loadCsf } from './loadCsf';
import { StoryRenderer } from './StoryRenderer';

const isBrowser =
Expand Down Expand Up @@ -93,6 +93,6 @@ export default function start(
window.__STORYBOOK_ADDONS_CHANNEL__ = channel; // may not be defined
}

const configure = makeConfigure({ clientApi, storyStore, configApi });
const configure = loadCsf({ clientApi, storyStore, configApi });
return { configure, clientApi, configApi, forceReRender: () => storyRenderer.forceReRender() };
}