diff --git a/addons/docs/docs/recipes.md b/addons/docs/docs/recipes.md index aa0b9512be29..5ffd73b06bb2 100644 --- a/addons/docs/docs/recipes.md +++ b/addons/docs/docs/recipes.md @@ -30,7 +30,7 @@ The only limitation is that your exported titles (CSF: `default.title`, MDX `Met Perhaps you want to write your stories in CSF, but document them in MDX? Here's how to do that: -**Button.stories.mdx** +**Button.mdx** ```md import { Story } from '@storybook/addon-docs/blocks'; @@ -51,18 +51,24 @@ And of course I can also embed arbitrary markdown & JSX in this file. ```js import { Button } from './Button'; -import mdx from './Button.stories.mdx'; +import mdx from './Button.mdx'; export default { title: 'Demo/Button', parameters: { - docs: mdx.parameters.docs, + docs: mdx, }, }; export const basic = () => ; ``` +Note that in contrast to other examples, the MDX file suffix is `.mdx` rather than `.stories.mdx`. This key difference means that the file will be loaded with the default MDX loader rather than Storybook's CSF loader, which has several implications: + +1. You don't need to provide a `Meta` declaration. +2. You can refer to existing stories (i.e. ``) but cannot define new stories (i.e. ``). +3. The documentation gets exported as the default export (MDX default) rather than as a parameter hanging off the default export (CSF). + ## Migrating from notes/info addons If you're currently using the notes/info addons, you can upgrade to DocsPage [using slots](./docspage.md#docspage-slots). There are different ways to use each addon, so you can adapt this recipe according to your use case. diff --git a/addons/docs/src/blocks/DocsContainer.tsx b/addons/docs/src/blocks/DocsContainer.tsx index cca70a4886a6..f3a3c66ff6e0 100644 --- a/addons/docs/src/blocks/DocsContainer.tsx +++ b/addons/docs/src/blocks/DocsContainer.tsx @@ -9,7 +9,6 @@ import { DocsContextProps, DocsContext } from './DocsContext'; interface DocsContainerProps { context: DocsContextProps; - content: React.ElementType; } interface CodeOrSourceProps { @@ -43,7 +42,7 @@ const defaultComponents = { export const DocsContainer: React.FunctionComponent = ({ context, - content: MDXContent, + children, }) => { const parameters = (context && context.parameters) || {}; const options = parameters.options || {}; @@ -55,9 +54,7 @@ export const DocsContainer: React.FunctionComponent = ({ - - - + {children} diff --git a/addons/docs/src/blocks/DocsPage.tsx b/addons/docs/src/blocks/DocsPage.tsx index f9010b0265c4..ad111727114c 100644 --- a/addons/docs/src/blocks/DocsPage.tsx +++ b/addons/docs/src/blocks/DocsPage.tsx @@ -3,8 +3,7 @@ import React from 'react'; import { parseKind } from '@storybook/router'; import { DocsPage as PureDocsPage, PropsTable, PropsTableProps } from '@storybook/components'; import { H2, H3 } from '@storybook/components/html'; -import { DocsContext, DocsContextProps } from './DocsContext'; -import { DocsContainer } from './DocsContainer'; +import { DocsContext } from './DocsContext'; import { Description, getDocgen } from './Description'; import { Story } from './Story'; import { Preview } from './Preview'; @@ -95,13 +94,13 @@ const DocsStory: React.FunctionComponent = ({ ); -const DocsPage: React.FunctionComponent = ({ - titleSlot, - subtitleSlot, - descriptionSlot, - primarySlot, - propsSlot, - storiesSlot, +export const DocsPage: React.FunctionComponent = ({ + titleSlot = defaultTitleSlot, + subtitleSlot = defaultSubtitleSlot, + descriptionSlot = defaultDescriptionSlot, + primarySlot = defaultPrimarySlot, + propsSlot = defaultPropsSlot, + storiesSlot = defaultStoriesSlot, }) => ( {context => { @@ -130,35 +129,3 @@ const DocsPage: React.FunctionComponent = ({ }} ); - -interface DocsPageWrapperProps { - context: DocsContextProps; - titleSlot?: StringSlot; - subtitleSlot?: StringSlot; - descriptionSlot?: StringSlot; - primarySlot?: StorySlot; - propsSlot?: PropsSlot; - storiesSlot?: StoriesSlot; -} - -const DocsPageWrapper: React.FunctionComponent = ({ - context, - titleSlot = defaultTitleSlot, - subtitleSlot = defaultSubtitleSlot, - descriptionSlot = defaultDescriptionSlot, - primarySlot = defaultPrimarySlot, - propsSlot = defaultPropsSlot, - storiesSlot = defaultStoriesSlot, -}) => ( - /* eslint-disable react/destructuring-assignment */ - ( - - )} - /> -); - -export { DocsPageWrapper as DocsPage }; diff --git a/addons/docs/src/frameworks/angular/config.js b/addons/docs/src/frameworks/angular/config.js index 1c4f0ff0b166..2017a4bb6ad5 100644 --- a/addons/docs/src/frameworks/angular/config.js +++ b/addons/docs/src/frameworks/angular/config.js @@ -1,7 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ import { addParameters } from '@storybook/angular'; -import { DocsPage } from '@storybook/addon-docs/blocks'; +import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks'; addParameters({ + docsContainer: DocsContainer, docs: DocsPage, }); diff --git a/addons/docs/src/frameworks/html/config.js b/addons/docs/src/frameworks/html/config.js index e309c872803e..9b7b52320cdb 100644 --- a/addons/docs/src/frameworks/html/config.js +++ b/addons/docs/src/frameworks/html/config.js @@ -1,7 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ import { addParameters } from '@storybook/html'; -import { DocsPage } from '@storybook/addon-docs/blocks'; +import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks'; addParameters({ + docsContainer: DocsContainer, docs: DocsPage, }); diff --git a/addons/docs/src/frameworks/react/config.js b/addons/docs/src/frameworks/react/config.js index 0b0bcf5d69f4..69f35dc6db05 100644 --- a/addons/docs/src/frameworks/react/config.js +++ b/addons/docs/src/frameworks/react/config.js @@ -1,7 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ import { addParameters } from '@storybook/react'; -import { DocsPage } from '@storybook/addon-docs/blocks'; +import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks'; addParameters({ + docsContainer: DocsContainer, docs: DocsPage, }); diff --git a/addons/docs/src/frameworks/vue/config.js b/addons/docs/src/frameworks/vue/config.js index 94889f73bea7..17584c29c593 100644 --- a/addons/docs/src/frameworks/vue/config.js +++ b/addons/docs/src/frameworks/vue/config.js @@ -1,7 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ import { addParameters } from '@storybook/vue'; -import { DocsPage } from '@storybook/addon-docs/blocks'; +import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks'; addParameters({ + docsContainer: DocsContainer, docs: DocsPage, }); diff --git a/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap b/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap index f83d2bfa3515..fd74553dda9a 100644 --- a/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap +++ b/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap @@ -72,12 +72,12 @@ const componentMeta = { includeStories: ['one'], }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -125,12 +125,12 @@ storybookDocsOnly.story = { parameters: { docsOnly: true } }; const componentMeta = { title: 'docs-only', includeStories: ['storybookDocsOnly'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -186,12 +186,12 @@ helloStory.story.parameters = { mdxSource: '' }; const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -268,12 +268,12 @@ const componentMeta = { includeStories: ['componentNotes', 'storyNotes'], }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -344,12 +344,12 @@ const componentMeta = { includeStories: ['helloButton', 'two'], }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -386,12 +386,12 @@ MDXContent.isMDXComponent = true; const componentMeta = { includeStories: [] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -435,12 +435,12 @@ text.story.parameters = { mdxSource: \\"'Plain text'\\" }; const componentMeta = { title: 'Text', includeStories: ['text'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -501,12 +501,12 @@ wPunctuation.story.parameters = { mdxSource: '' const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory', 'wPunctuation'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -560,12 +560,12 @@ story0.story.parameters = { const componentMeta = { includeStories: ['story0'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -631,12 +631,12 @@ toStorybook.story.parameters = { const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -673,12 +673,12 @@ MDXContent.isMDXComponent = true; const componentMeta = { includeStories: [] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " @@ -716,12 +716,12 @@ MDXContent.isMDXComponent = true; const componentMeta = { includeStories: [] }; -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ( - -); +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => ( + {children} +); +componentMeta.parameters.docs = MDXContent; export default componentMeta; " diff --git a/addons/docs/src/mdx/mdx-compiler-plugin.js b/addons/docs/src/mdx/mdx-compiler-plugin.js index ce0eeb52e5e2..cacd34a1fd7c 100644 --- a/addons/docs/src/mdx/mdx-compiler-plugin.js +++ b/addons/docs/src/mdx/mdx-compiler-plugin.js @@ -163,10 +163,10 @@ function getExports(node, counter) { // insert `mdxKind` into the context so that we can know what "kind" we're rendering into // when we render ..., since this MDX can be attached to any `selectedKind`! const wrapperJs = ` -const mdxKind = componentMeta.title || componentMeta.displayName; -const WrappedMDXContent = ({ context }) => ; +const mdxKind = componentMeta.title; componentMeta.parameters = componentMeta.parameters || {}; -componentMeta.parameters.docs = WrappedMDXContent; +componentMeta.parameters.docsContainer = ({ context, children }) => {children}; +componentMeta.parameters.docs = MDXContent; `.trim(); function stringifyMeta(meta) { diff --git a/examples/official-storybook/stories/addon-docs/mdx.stories.js b/examples/official-storybook/stories/addon-docs/mdx.stories.js index caac0eb72601..48501bb9e820 100644 --- a/examples/official-storybook/stories/addon-docs/mdx.stories.js +++ b/examples/official-storybook/stories/addon-docs/mdx.stories.js @@ -1,8 +1,10 @@ import React from 'react'; +import { DocsContainer } from '@storybook/addon-docs/blocks'; import markdown from './markdown.stories.mdx'; export default { title: 'Addons|Docs/mdx-in-story', + decorators: [storyFn => {storyFn()}], }; // This renders the contents of the docs panel into story content diff --git a/examples/official-storybook/stories/notes/notes.mdx b/examples/official-storybook/stories/notes/notes.mdx index 48dc5de86eae..f030ec4a8932 100644 --- a/examples/official-storybook/stories/notes/notes.mdx +++ b/examples/official-storybook/stories/notes/notes.mdx @@ -1,3 +1,12 @@ +import { Props, Story } from '@storybook/addon-docs/blocks'; +import { Button } from '@storybook/react/demo'; + # Welcome! -Let's just write markdown without stories +Let's write markdown without stories + +But we can still use doc blocks in our stories + + + + diff --git a/lib/core/src/client/preview/start.js b/lib/core/src/client/preview/start.js index cf81ebf25004..5fa69e7df0f7 100644 --- a/lib/core/src/client/preview/start.js +++ b/lib/core/src/client/preview/start.js @@ -217,9 +217,14 @@ export default function start(render, { decorateStory } = {}) { // Given a cleaned up state, render the appropriate view mode switch (viewMode) { case 'docs': { - const StoryDocs = (parameters && parameters.docs) || NoDocs; + const DocsContainer = + // eslint-disable-next-line react/prop-types + (parameters && parameters.docsContainer) || (({ children }) => <>{children}); + const Docs = (parameters && parameters.docs) || NoDocs; ReactDOM.render( - , + + + , document.getElementById('docs-root') ); break;