Skip to content

Commit

Permalink
Merge pull request #18708 from storybookjs/tom/sb-453-dependencies-en…
Browse files Browse the repository at this point in the history
…sure-react-dom-mdx

Addon-docs: Move DocsRenderer back to addon-docs
  • Loading branch information
tmeasday authored Jul 19, 2022
2 parents 2a77787 + 3ff9b31 commit e925226
Show file tree
Hide file tree
Showing 18 changed files with 175 additions and 162 deletions.
5 changes: 5 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [Docs modern inline rendering by default](#docs-modern-inline-rendering-by-default)
- [Babel mode v7 by default](#babel-mode-v7-by-default)
- [7.0 feature flags removed](#70-feature-flags-removed)
- [Removed docs.getContainer and getPage parameters](#removed-docs-getcontainer-and-getpage-parameters)
- [From version 6.4.x to 6.5.0](#from-version-64x-to-650)
- [Vue 3 upgrade](#vue-3-upgrade)
- [React18 new root API](#react18-new-root-api)
Expand Down Expand Up @@ -393,6 +394,10 @@ In 7.0 we've removed the following feature flags:
| `emotionAlias` | This flag is no longer needed and should be deleted. |
| `breakingChangesV7` | This flag is no longer needed and should be deleted. |

#### Removed docs.getContainer and getPage parameters

It is no longer possible to set `parameters.docs.getContainer()` and `getPage()`. Instead use `parameters.docs.container` or `parameters.docs.page` directly.

## From version 6.4.x to 6.5.0

### Vue 3 upgrade
Expand Down
45 changes: 45 additions & 0 deletions addons/docs/src/DocsRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { AnyFramework, Parameters } from '@storybook/csf';
import { DocsContextProps, DocsRenderFunction } from '@storybook/preview-web';
import { components as htmlComponents } from '@storybook/components';
import { Docs, CodeOrSourceMdx, AnchorMdx, HeadersMdx } from '@storybook/blocks';
import { MDXProvider } from '@mdx-js/react';

// TS doesn't like that we export a component with types that it doesn't know about (TS4203)
export const defaultComponents: Record<string, any> = {
...htmlComponents,
code: CodeOrSourceMdx,
a: AnchorMdx,
...HeadersMdx,
};

export class DocsRenderer<TFramework extends AnyFramework> {
public render: DocsRenderFunction<TFramework>;

public unmount: (element: HTMLElement) => void;

constructor() {
this.render = (
context: DocsContextProps<TFramework>,
docsParameter: Parameters,
element: HTMLElement,
callback: () => void
): void => {
// Use a random key to force the container to re-render each time we call `renderDocs`
// TODO: do we still need this? It was needed for angular (legacy) inline rendering:
// https://github.com/storybookjs/storybook/pull/16149
ReactDOM.render(
<MDXProvider components={defaultComponents}>
<Docs key={Math.random()} context={context} docsParameter={docsParameter} />
</MDXProvider>,
element,
callback
);
};

this.unmount = (element: HTMLElement) => {
ReactDOM.unmountComponentAtNode(element);
};
}
}
1 change: 1 addition & 0 deletions addons/docs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './blocks';
export { DocsRenderer } from './DocsRenderer';
2 changes: 1 addition & 1 deletion addons/docs/src/preview.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const parameters: any = {
docs: {
renderer: async () => {
const { DocsRenderer } = (await import('./blocks')) as any;
const { DocsRenderer } = (await import('./DocsRenderer')) as any;
return new DocsRenderer();
},
},
Expand Down
1 change: 1 addition & 0 deletions examples/external-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@storybook/addon-docs": "7.0.0-alpha.13",
"@storybook/addon-essentials": "7.0.0-alpha.13",
"@storybook/blocks": "7.0.0-alpha.13",
"@storybook/components": "7.0.0-alpha.13",
"@storybook/csf": "0.0.2--canary.4566f4d.1",
"@storybook/preview-web": "7.0.0-alpha.13",
Expand Down
12 changes: 4 additions & 8 deletions examples/external-docs/pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
/* eslint-disable react/prop-types */
import React from 'react';
import 'nextra-theme-docs/style.css';
import { ExternalDocsContainer } from '@storybook/addon-docs';
import { ExternalDocs } from '@storybook/addon-docs';

import * as reactAnnotations from '@storybook/react/preview';
import * as previewAnnotations from '../.storybook/preview';

const projectAnnotations = {
...reactAnnotations,
...previewAnnotations,
};

export default function Nextra({ Component, pageProps }) {
return (
<ExternalDocsContainer projectAnnotations={projectAnnotations}>
<ExternalDocs projectAnnotationsList={[reactAnnotations, previewAnnotations]}>
<Component {...pageProps} />
</ExternalDocsContainer>
</ExternalDocs>
);
}
47 changes: 25 additions & 22 deletions examples/official-storybook/stories/addon-docs/mdx.stories.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,48 @@
import React from 'react';
import { DocsContainer } from '@storybook/addon-docs';
import { themes } from '@storybook/theming';
import { MDXProvider } from '@mdx-js/react';

import markdown from './markdown.stories.mdx';
import { defaultComponents } from '../../../../addons/docs/src/DocsRenderer';

export default {
title: 'Addons/Docs/mdx-in-story',
decorators: [
(storyFn) => (
<DocsContainer
context={{ componentStories: () => [], storyById: () => ({ parameters: {} }) }}
>
{storyFn()}
</DocsContainer>
),
],
parameters: {
layout: 'fullscreen',
},
parameters: { layout: 'fullscreen' },
};

// This renders the contents of the docs panel into story content
// The purpose of these stories are to document that MDX renders properly in docs itself
// As tools like Chromatic cannot capture docs entries, we need to create a story that
// actually renders it's own docs, much like the DocsRenderer might.
export const Typography = () => {
const Docs = markdown.parameters.docs.page;
return <Docs />;
};

Typography.decorators = [
(storyFn) => (
<MDXProvider components={defaultComponents}>
<DocsContainer context={{ componentStories: () => [], storyById: () => ({}) }}>
{storyFn()}
</DocsContainer>
</MDXProvider>
),
];

export const DarkModeDocs = () => {
const Docs = markdown.parameters.docs.page;
return <Docs />;
};

DarkModeDocs.decorators = [
(storyFn) => (
<DocsContainer
context={{
type: 'legacy',
componentStories: () => [],
storyById: () => ({ parameters: { docs: { theme: themes.dark } } }),
}}
>
{storyFn()}
</DocsContainer>
<MDXProvider components={defaultComponents}>
<DocsContainer
context={{ componentStories: () => [], storyById: () => ({}) }}
theme={themes.dark}
>
{storyFn()}
</DocsContainer>
</MDXProvider>
),
];
4 changes: 1 addition & 3 deletions lib/blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"prepare": "esrun ../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@mdx-js/react": "^1.6.22",
"@storybook/addons": "7.0.0-alpha.13",
"@storybook/api": "7.0.0-alpha.13",
"@storybook/client-logger": "7.0.0-alpha.13",
Expand All @@ -68,8 +67,7 @@
"@digitak/esrun": "^3.2.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"publishConfig": {
"access": "public"
Expand Down
8 changes: 1 addition & 7 deletions lib/blocks/src/blocks/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React, { FC, ReactElement, ReactNode, ReactNodeArray, useContext } from 'react';
import { MDXProvider } from '@mdx-js/react';
import { AnyFramework } from '@storybook/csf';
import { resetComponents } from '@storybook/components';
import {
Preview as PurePreview,
PreviewProps as PurePreviewProps,
Expand Down Expand Up @@ -77,9 +75,5 @@ export const Canvas: FC<CanvasProps> = (props) => {

if (isLoading) return <PreviewSkeleton />;

return (
<MDXProvider components={resetComponents}>
<PurePreview {...previewProps}>{children}</PurePreview>
</MDXProvider>
);
return <PurePreview {...previewProps}>{children}</PurePreview>;
};
26 changes: 26 additions & 0 deletions lib/blocks/src/blocks/Docs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import type { FunctionComponent, ComponentType } from 'react';
import type { AnyFramework, Parameters } from '@storybook/csf';
import type { Theme } from '@storybook/theming';

import type { DocsContextProps } from './DocsContext';
import { DocsContainer } from './DocsContainer';
import { DocsPage } from './DocsPage';

export type DocsProps<TFramework extends AnyFramework = AnyFramework> = {
docsParameter: Parameters;
context: DocsContextProps<TFramework>;
};

export const Docs: FunctionComponent<DocsProps> = ({ docsParameter, context }) => {
const Container: ComponentType<{ context: DocsContextProps; theme: Theme }> =
docsParameter.container || DocsContainer;

const Page = docsParameter.page || DocsPage;

return (
<Container context={context} theme={docsParameter.theme}>
<Page />
</Container>
);
};
57 changes: 11 additions & 46 deletions lib/blocks/src/blocks/DocsContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,25 @@
import React, { FunctionComponent, useEffect } from 'react';
import global from 'global';
import deprecate from 'util-deprecate';
import { dedent } from 'ts-dedent';
import { MDXProvider } from '@mdx-js/react';
import type { ThemeVars } from '@storybook/theming';
import { ThemeProvider, ensure as ensureTheme } from '@storybook/theming';
import { components as htmlComponents } from '@storybook/components';
import { AnyFramework } from '@storybook/csf';
import { DocsWrapper, DocsContent } from '../components';
import { DocsContextProps, DocsContext } from './DocsContext';
import { SourceContainer } from './SourceContainer';
import { CodeOrSourceMdx, AnchorMdx, HeadersMdx } from './mdx';
import { scrollToElement } from './utils';

const { document, window: globalWindow } = global;

export interface DocsContainerProps<TFramework extends AnyFramework = AnyFramework> {
context: DocsContextProps<TFramework>;
theme?: ThemeVars;
}

const defaultComponents = {
...htmlComponents,
code: CodeOrSourceMdx,
a: AnchorMdx,
...HeadersMdx,
};

const warnOptionsTheme = deprecate(
() => {},
dedent`
Deprecated parameter: options.theme => docs.theme
https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/theming.md#storybook-theming
`
);

export const DocsContainer: FunctionComponent<DocsContainerProps> = ({ context, children }) => {
const { storyById } = context;
const allComponents = { ...defaultComponents };
let theme = ensureTheme(null);
try {
const {
parameters: { options = {}, docs = {} },
} = storyById();
let themeVars = docs.theme;
if (!themeVars && options.theme) {
warnOptionsTheme();
themeVars = options.theme;
}
theme = ensureTheme(themeVars);
Object.assign(allComponents, docs.components);
} catch (err) {
// No primary story, ie. standalone docs
}

export const DocsContainer: FunctionComponent<DocsContainerProps> = ({
context,
theme,
children,
}) => {
useEffect(() => {
let url;
try {
Expand All @@ -74,12 +41,10 @@ export const DocsContainer: FunctionComponent<DocsContainerProps> = ({ context,
return (
<DocsContext.Provider value={context}>
<SourceContainer>
<ThemeProvider theme={theme}>
<MDXProvider components={allComponents}>
<DocsWrapper className="sbdocs sbdocs-wrapper">
<DocsContent className="sbdocs sbdocs-content">{children}</DocsContent>
</DocsWrapper>
</MDXProvider>
<ThemeProvider theme={ensureTheme(theme)}>
<DocsWrapper className="sbdocs sbdocs-wrapper">
<DocsContent className="sbdocs sbdocs-content">{children}</DocsContent>
</DocsWrapper>
</ThemeProvider>
</SourceContainer>
</DocsContext.Provider>
Expand Down
53 changes: 0 additions & 53 deletions lib/blocks/src/blocks/DocsRenderer.tsx

This file was deleted.

Loading

0 comments on commit e925226

Please sign in to comment.