mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-08 11:11:53 +08:00
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:
commit
ddaa466869
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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');
|
||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user