mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-17 05:02:23 +08:00
Merge pull request #10117 from storybookjs/promote-args-argtypes-in-csf
CSF: Promote args/argTypes to first-class metadata
This commit is contained in:
commit
a9fc57fe49
@ -54,7 +54,7 @@ export const PassedToStory = inputArgs => {
|
||||
};
|
||||
|
||||
PassedToStory.story = {
|
||||
parameters: { argTypes: { name: { defaultValue: 'initial' } } },
|
||||
argTypes: { name: { defaultValue: 'initial' } },
|
||||
};
|
||||
|
||||
PassedToStory.propTypes = {
|
||||
|
@ -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 */ },
|
||||
@ -80,7 +80,7 @@ MyStory.story = { parameters: {
|
||||
size: 'large',
|
||||
extra: 'prop',
|
||||
}
|
||||
}}
|
||||
}
|
||||
```
|
||||
|
||||
Then `context.args` will default to `{ primary: true, size: 'large', extra: 'prop' }`.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
@ -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 };
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
@ -207,6 +207,8 @@ describe('core.preview.makeConfigure', () => {
|
||||
title: 'a',
|
||||
parameters: { x: 'y' },
|
||||
decorators: [decorator],
|
||||
args: { b: 1 },
|
||||
argTypes: { b: 'string' },
|
||||
},
|
||||
x: () => 0,
|
||||
},
|
||||
@ -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();
|
||||
@ -232,6 +236,8 @@ describe('core.preview.makeConfigure', () => {
|
||||
story: {
|
||||
parameters: { x: 'y' },
|
||||
decorators: [decorator],
|
||||
args: { b: 1 },
|
||||
argTypes: { b: 'string' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
@ -244,6 +250,8 @@ describe('core.preview.makeConfigure', () => {
|
||||
x: 'y',
|
||||
decorators: [decorator],
|
||||
__id: 'a--x',
|
||||
args: { b: 1 },
|
||||
argTypes: { b: 'string' },
|
||||
});
|
||||
});
|
||||
|
@ -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?
|
||||
@ -103,18 +105,20 @@ 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.`)();
|
||||
@ -122,11 +126,15 @@ const loadStories = (
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -134,7 +142,7 @@ const loadStories = (
|
||||
};
|
||||
|
||||
let loaded = false;
|
||||
export const makeConfigure = ({
|
||||
export const loadCsf = ({
|
||||
clientApi,
|
||||
storyStore,
|
||||
configApi,
|
@ -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 =
|
||||
@ -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() };
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user