diff --git a/MIGRATION.md b/MIGRATION.md index 1e3ef9d02ce..1c8684f7ba2 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -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) @@ -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 diff --git a/addons/docs/src/DocsRenderer.tsx b/addons/docs/src/DocsRenderer.tsx new file mode 100644 index 00000000000..165412b53c8 --- /dev/null +++ b/addons/docs/src/DocsRenderer.tsx @@ -0,0 +1,33 @@ +import React, { ComponentType } from 'react'; +import ReactDOM from 'react-dom'; +import { AnyFramework, Parameters } from '@storybook/csf'; +import { DocsContextProps, DocsRenderFunction } from '@storybook/preview-web'; +import { Docs, DocsPage } from '@storybook/blocks'; + +export class DocsRenderer { + public render: DocsRenderFunction; + + public unmount: (element: HTMLElement) => void; + + constructor() { + this.render = ( + context: DocsContextProps, + parameters: 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( + , + element, + callback + ); + }; + + this.unmount = (element: HTMLElement) => { + ReactDOM.unmountComponentAtNode(element); + }; + } +} diff --git a/addons/docs/src/preview.ts b/addons/docs/src/preview.ts index c425f1f9d7f..0d1183bd0cf 100644 --- a/addons/docs/src/preview.ts +++ b/addons/docs/src/preview.ts @@ -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(); }, }, diff --git a/examples/external-docs/package.json b/examples/external-docs/package.json index abd87091222..5077210bdfd 100644 --- a/examples/external-docs/package.json +++ b/examples/external-docs/package.json @@ -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", diff --git a/examples/external-docs/pages/_app.js b/examples/external-docs/pages/_app.js index 091082b316e..adf9c62636e 100644 --- a/examples/external-docs/pages/_app.js +++ b/examples/external-docs/pages/_app.js @@ -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, ExternalDocsContainer } 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 ( - + - + ); } diff --git a/lib/blocks/package.json b/lib/blocks/package.json index 8a6b5af70c3..969d3579ffa 100644 --- a/lib/blocks/package.json +++ b/lib/blocks/package.json @@ -68,8 +68,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" diff --git a/lib/blocks/src/blocks/Docs.tsx b/lib/blocks/src/blocks/Docs.tsx new file mode 100644 index 00000000000..27dfefdc1fb --- /dev/null +++ b/lib/blocks/src/blocks/Docs.tsx @@ -0,0 +1,23 @@ +import React, { FunctionComponent, ComponentType } from 'react'; +import { AnyFramework, Parameters } from '@storybook/csf'; +import { DocsContextProps } from './DocsContext'; +import { DocsContainer } from './DocsContainer'; +import { DocsPage } from './DocsPage'; + +export type DocsProps = { + parameters: Parameters; + context: DocsContextProps; +}; + +export const Docs: FunctionComponent = ({ parameters, context }) => { + const Container: ComponentType<{ context: DocsContextProps }> = + parameters.container || DocsContainer; + + const Page = parameters.page || DocsPage; + + return ( + + + + ); +}; diff --git a/lib/blocks/src/blocks/DocsContainer.tsx b/lib/blocks/src/blocks/DocsContainer.tsx index 43738343116..a1761e3472b 100644 --- a/lib/blocks/src/blocks/DocsContainer.tsx +++ b/lib/blocks/src/blocks/DocsContainer.tsx @@ -3,7 +3,7 @@ import global from 'global'; import deprecate from 'util-deprecate'; import { dedent } from 'ts-dedent'; import { MDXProvider } from '@mdx-js/react'; -import { ThemeProvider, ensure as ensureTheme } from '@storybook/theming'; +import { ThemeProvider, ensure as ensureTheme, themes } from '@storybook/theming'; import { components as htmlComponents } from '@storybook/components'; import { AnyFramework } from '@storybook/csf'; import { DocsWrapper, DocsContent } from '../components'; @@ -37,21 +37,21 @@ const warnOptionsTheme = deprecate( export const DocsContainer: FunctionComponent = ({ 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 - } + const 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 + // } useEffect(() => { let url; diff --git a/lib/blocks/src/blocks/DocsRenderer.tsx b/lib/blocks/src/blocks/DocsRenderer.tsx deleted file mode 100644 index a7041a666c0..00000000000 --- a/lib/blocks/src/blocks/DocsRenderer.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { ComponentType } from 'react'; -import ReactDOM from 'react-dom'; -import { AnyFramework, Parameters } from '@storybook/csf'; -import { DocsRenderFunction } from '@storybook/preview-web'; - -import { DocsContainer } from './DocsContainer'; -import { DocsPage } from './DocsPage'; -import { DocsContextProps } from './DocsContext'; - -export class DocsRenderer { - public render: DocsRenderFunction; - - public unmount: (element: HTMLElement) => void; - - constructor() { - this.render = ( - docsContext: DocsContextProps, - docsParameters: Parameters, - element: HTMLElement, - callback: () => void - ): void => { - renderDocsAsync(docsContext, docsParameters, element).then(callback); - }; - - this.unmount = (element: HTMLElement) => { - ReactDOM.unmountComponentAtNode(element); - }; - } -} - -async function renderDocsAsync( - docsContext: DocsContextProps, - docsParameters: Parameters, - element: HTMLElement -) { - const Container: ComponentType<{ context: DocsContextProps }> = - docsParameters.container || (await docsParameters.getContainer?.()) || DocsContainer; - - const Page: ComponentType = docsParameters.page || (await docsParameters.getPage?.()) || DocsPage; - - // 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 - const docsElement = ( - - - - ); - - await new Promise((resolve) => { - ReactDOM.render(docsElement, element, resolve); - }); -} diff --git a/lib/blocks/src/blocks/external/ExternalDocs.tsx b/lib/blocks/src/blocks/external/ExternalDocs.tsx new file mode 100644 index 00000000000..d802fbaa278 --- /dev/null +++ b/lib/blocks/src/blocks/external/ExternalDocs.tsx @@ -0,0 +1,32 @@ +import React, { FunctionComponent, ComponentType, useRef } from 'react'; +import { AnyFramework, ProjectAnnotations } from '@storybook/csf'; +import { composeConfigs } from '@storybook/store'; + +import { Docs } from '../Docs'; +import { ExternalPreview } from './ExternalPreview'; + +export type ExternalDocsProps = { + projectAnnotationsList: ProjectAnnotations[]; +}; + +function usePreview( + projectAnnotations: ProjectAnnotations +) { + const previewRef = useRef(); + if (!previewRef.current) previewRef.current = new ExternalPreview(projectAnnotations); + return previewRef.current; +} + +export const ExternalDocs: FunctionComponent = ({ + projectAnnotationsList, + children, +}) => { + const projectAnnotations = composeConfigs(projectAnnotationsList); + const preview = usePreview(projectAnnotations); + const parameters = { + ...projectAnnotations.parameters?.docs, + page: () => children, + }; + + return ; +}; diff --git a/lib/blocks/src/blocks/external/ExternalPreview.ts b/lib/blocks/src/blocks/external/ExternalPreview.ts index a269791d57e..123bf9f2213 100644 --- a/lib/blocks/src/blocks/external/ExternalPreview.ts +++ b/lib/blocks/src/blocks/external/ExternalPreview.ts @@ -19,7 +19,9 @@ class ConstantMap { } } -export class ExternalPreview extends Preview { +export class ExternalPreview< + TFramework extends AnyFramework = AnyFramework +> extends Preview { private importPaths = new ConstantMap('./importPath/'); private titles = new ConstantMap('title-'); diff --git a/lib/blocks/src/blocks/index.ts b/lib/blocks/src/blocks/index.ts index 6f235adeac4..e407545418e 100644 --- a/lib/blocks/src/blocks/index.ts +++ b/lib/blocks/src/blocks/index.ts @@ -4,13 +4,13 @@ export * from './Anchor'; export * from './ArgsTable'; export * from './Canvas'; export * from './Description'; +export * from './Docs'; export * from './DocsContext'; -export * from './DocsRenderer'; export * from './DocsPage'; export * from './DocsContainer'; export * from './DocsStory'; +export * from './external/ExternalDocs'; export * from './external/ExternalDocsContainer'; -export * from './external/ExternalPreview'; export * from './Heading'; export * from './Meta'; export * from './Preview'; diff --git a/renderers/react/src/docs/jsxDecorator.tsx b/renderers/react/src/docs/jsxDecorator.tsx index daf30638cb8..f075b0feca0 100644 --- a/renderers/react/src/docs/jsxDecorator.tsx +++ b/renderers/react/src/docs/jsxDecorator.tsx @@ -122,7 +122,12 @@ export const renderJsx = (code: React.ReactElement, options: JSXOptions) => { const result = React.Children.map(code, (c) => { // @ts-ignore FIXME: workaround react-element-to-jsx-string const child = typeof c === 'number' ? c.toString() : c; - let string = applyBeforeRender(reactElementToJSXString(child, opts as Options), options); + const toJSXString = + typeof reactElementToJSXString === 'function' + ? reactElementToJSXString + : // @ts-ignore + reactElementToJSXString.default; + let string = applyBeforeRender(toJSXString(child, opts as Options), options); if (string.indexOf('"') > -1) { const matches = string.match(/\S+=\\"([^"]*)\\"/g); diff --git a/yarn.lock b/yarn.lock index c24d1c8b5c8..00842ad3fea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7839,7 +7839,6 @@ __metadata: util-deprecate: ^1.0.2 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 languageName: unknown linkType: soft @@ -8631,6 +8630,7 @@ __metadata: "@babel/preset-env": ^7.17.10 "@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