Addon-docs: Fix MDX story rendering with dynamic component titl… (#9248)

Addon-docs: Fix MDX story rendering with dynamic component titles
This commit is contained in:
Michael Shilman 2019-12-28 08:56:25 +08:00 committed by GitHub
commit ddaa466869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 68 additions and 63 deletions

View File

@ -6,11 +6,12 @@ export interface DocsContextProps {
selectedStory?: string;
/**
* mdxStoryNameToId is an MDX-compiler-generated mapping of an MDX story's
* display name to its storyId. It's used internally by the `<Story>`
* doc block.
* mdxStoryNameToKey is an MDX-compiler-generated mapping of an MDX story's
* display name to its story key for ID generation. It's used internally by the `<Story>`
* and `Preview` doc blocks.
*/
mdxStoryNameToId?: Record<string, string>;
mdxStoryNameToKey?: Record<string, string>;
mdxComponentMeta?: any;
parameters?: any;
storyStore?: any;
forceRender?: () => void;

View File

@ -1,4 +1,5 @@
import React, { FunctionComponent, ReactElement, ReactNode, ReactNodeArray } from 'react';
import { toId, storyNameFromExport } from '@storybook/csf';
import { Preview as PurePreview, PreviewProps as PurePreviewProps } from '@storybook/components';
import { getSourceProps } from './Source';
import { DocsContext, DocsContextProps } from './DocsContext';
@ -21,7 +22,7 @@ const getPreviewProps = (
children,
...props
}: PreviewProps & { children?: ReactNode },
{ mdxStoryNameToId, storyStore }: DocsContextProps
{ mdxStoryNameToKey, mdxComponentMeta, storyStore }: DocsContextProps
): PurePreviewProps => {
if (withSource === SourceState.NONE) {
return props;
@ -36,7 +37,14 @@ const getPreviewProps = (
const stories = childArray.filter(
(c: ReactElement) => c.props && (c.props.id || c.props.name)
) as ReactElement[];
const targetIds = stories.map(s => s.props.id || mdxStoryNameToId[s.props.name]);
const targetIds = stories.map(
s =>
s.props.id ||
toId(
mdxComponentMeta.id || mdxComponentMeta.title,
storyNameFromExport(mdxStoryNameToKey[s.props.name])
)
);
const sourceProps = getSourceProps({ ids: targetIds }, { storyStore });
return {
...props, // pass through columns etc.

View File

@ -2,6 +2,7 @@ import React, { createElement, ElementType, FunctionComponent, ReactNode } from
import { MDXProvider } from '@mdx-js/react';
import { components as docsComponents } from '@storybook/components/html';
import { Story, StoryProps as PureStoryProps } from '@storybook/components';
import { toId, storyNameFromExport } from '@storybook/csf';
import { CURRENT_SELECTION } from './shared';
import { DocsContext, DocsContextProps } from './DocsContext';
@ -40,12 +41,17 @@ const inferInlineStories = (framework: string): boolean => {
export const getStoryProps = (
props: StoryProps,
{ id: currentId, storyStore, parameters, mdxStoryNameToId }: DocsContextProps | null
{ id: currentId, storyStore, mdxStoryNameToKey, mdxComponentMeta }: DocsContextProps | null
): PureStoryProps => {
const { id } = props as StoryRefProps;
const { name } = props as StoryDefProps;
const inputId = id === CURRENT_SELECTION ? currentId : id;
const previewId = inputId || mdxStoryNameToId[name];
const previewId =
inputId ||
toId(
mdxComponentMeta.id || mdxComponentMeta.title,
storyNameFromExport(mdxStoryNameToKey[name])
);
const { height, inline } = props;
const data = storyStore.fromId(previewId);

View File

@ -39,13 +39,13 @@ componentNotes.story.parameters = { mdxSource: '<Button>Component notes</Button>
const componentMeta = { title: 'Button', id: 'button-id', includeStories: ['componentNotes'] };
const mdxStoryNameToId = { 'component notes': 'button-id--component-notes' };
const mdxStoryNameToKey = { 'component notes': 'componentNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -73,13 +73,13 @@ const componentMeta = {
includeStories: ['one'],
};
const mdxStoryNameToId = { one: 'button--one' };
const mdxStoryNameToKey = { one: 'one' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -42,13 +42,13 @@ __page.story = { parameters: { docsOnly: true } };
const componentMeta = { title: 'docs-only', includeStories: ['__page'] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -36,13 +36,13 @@ __page.story = { parameters: { docsOnly: true } };
const componentMeta = { title: \\"Addons/Docs/what's in a title?\\", includeStories: ['__page'] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -51,13 +51,13 @@ helloStory.story.parameters = { mdxSource: '<Button>Hello button</Button>' };
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };
const mdxStoryNameToId = { one: 'button--one', 'hello story': 'button--hello-story' };
const mdxStoryNameToKey = { one: 'one', 'hello story': 'helloStory' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -71,16 +71,13 @@ const componentMeta = {
includeStories: ['componentNotes', 'storyNotes'],
};
const mdxStoryNameToId = {
'component notes': 'button--component-notes',
'story notes': 'button--story-notes',
};
const mdxStoryNameToKey = { 'component notes': 'componentNotes', 'story notes': 'storyNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -70,13 +70,13 @@ const componentMeta = {
includeStories: ['helloButton', 'two'],
};
const mdxStoryNameToId = { 'hello button': 'button--hello-button', two: 'button--two' };
const mdxStoryNameToKey = { 'hello button': 'helloButton', two: 'two' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -31,13 +31,13 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -39,13 +39,13 @@ text.story.parameters = { mdxSource: \\"'Plain text'\\" };
const componentMeta = { title: 'Text', includeStories: ['text'] };
const mdxStoryNameToId = { text: 'text--text' };
const mdxStoryNameToKey = { text: 'text' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -67,18 +67,18 @@ const componentMeta = {
includeStories: ['one', 'helloStory', 'wPunctuation', '_1FineDay'],
};
const mdxStoryNameToId = {
one: 'button--one',
'hello story': 'button--hello-story',
'w/punctuation': 'button--w-punctuation',
'1 fine day': 'button--1-fine-day',
const mdxStoryNameToKey = {
one: 'one',
'hello story': 'helloStory',
'w/punctuation': 'wPunctuation',
'1 fine day': '_1FineDay',
};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -43,13 +43,13 @@ basic.story.parameters = { mdxSource: 'basicFn' };
const componentMeta = { title: 'story-function-var', includeStories: ['basic'] };
const mdxStoryNameToId = { basic: 'story-function-var--basic' };
const mdxStoryNameToKey = { basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -48,13 +48,13 @@ functionStory.story.parameters = {
const componentMeta = { includeStories: ['functionStory'] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = { function: 'functionStory' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -60,13 +60,13 @@ toStorybook.story.parameters = {
const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] };
const mdxStoryNameToId = { 'to storybook': 'mdx-welcome--to-storybook' };
const mdxStoryNameToKey = { 'to storybook': 'toStorybook' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -31,13 +31,13 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -37,13 +37,13 @@ __page.story = { parameters: { docsOnly: true } };
const componentMeta = { title: \`\${titleFunction('template')}\`, includeStories: ['__page'] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -32,13 +32,13 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToId = {};
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToId={mdxStoryNameToId}>
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}>
<MDXContent />
</AddContext>
),

View File

@ -3,7 +3,6 @@ const parser = require('@babel/parser');
const generate = require('@babel/generator').default;
const camelCase = require('lodash/camelCase');
const jsStringEscape = require('js-string-escape');
const { toId, storyNameFromExport } = require('@storybook/csf');
// Generate the MDX as is, but append named exports for every
// story in the contents
@ -198,13 +197,13 @@ function getExports(node, counter, options) {
return null;
}
// insert `mdxKind` into the context so that we can know what "kind" we're rendering into
// when we render <Story name="xxx">...</Story>, since this MDX can be attached to any `selectedKind`!
// insert `mdxStoryNameToKey` and `mdxComponentMeta` into the context so that we
// can reconstruct the Story ID dynamically from the `name` at render time
const wrapperJs = `
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => <AddContext mdxStoryNameToId={mdxStoryNameToId}><MDXContent /></AddContext>,
page: () => <AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentMeta={componentMeta}><MDXContent /></AddContext>,
};
`.trim();
@ -322,23 +321,12 @@ function extractExports(node, options) {
}
metaExport.includeStories = JSON.stringify(includeStories);
const { title, id: componentId } = metaExport;
const mdxStoryNameToId = Object.entries(context.storyNameToKey).reduce(
(acc, [storyName, storyKey]) => {
if (title) {
acc[storyName] = toId(componentId || title, storyNameFromExport(storyKey));
}
return acc;
},
{}
);
const fullJsx = [
'import { assertIsFn, AddContext } from "@storybook/addon-docs/blocks";',
defaultJsx,
...storyExports,
`const componentMeta = ${stringifyMeta(metaExport)};`,
`const mdxStoryNameToId = ${JSON.stringify(mdxStoryNameToId)};`,
`const mdxStoryNameToKey = ${JSON.stringify(context.storyNameToKey)};`,
wrapperJs,
'export default componentMeta;',
].join('\n\n');

View File

@ -5,3 +5,8 @@ import { titleFunction } from '@storybook/addon-docs/dist/mdx/title-generators';
# Meta title from a string template
## Stories
<Story name="testing">
<>hello</>
</Story>