diff --git a/addons/interactions/package.json b/addons/interactions/package.json index d86a5ae3e0f2..a9cdfc2204d0 100644 --- a/addons/interactions/package.json +++ b/addons/interactions/package.json @@ -59,7 +59,7 @@ }, "devDependencies": { "@storybook/jest": "^0.0.5", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "formik": "^2.2.9" }, "peerDependencies": { diff --git a/addons/interactions/src/Panel.tsx b/addons/interactions/src/Panel.tsx index fcd6918cfcf5..0b8325166ace 100644 --- a/addons/interactions/src/Panel.tsx +++ b/addons/interactions/src/Panel.tsx @@ -134,32 +134,12 @@ export const Panel: React.FC = (props) => { const [isRerunAnimating, setIsRerunAnimating] = React.useState(false); const [scrollTarget, setScrollTarget] = React.useState(); const [collapsed, setCollapsed] = React.useState>(new Set()); + const [log, setLog] = React.useState([]); // Calls are tracked in a ref so we don't needlessly rerender. const calls = React.useRef>>(new Map()); const setCall = ({ status, ...call }: Call) => calls.current.set(call.id, call); - const [log, setLog] = React.useState([]); - const childCallMap = new Map(); - const interactions = log - .filter((call) => { - if (!call.parentId) return true; - childCallMap.set(call.parentId, (childCallMap.get(call.parentId) || []).concat(call.callId)); - return !collapsed.has(call.parentId); - }) - .map(({ callId, status }) => ({ - ...calls.current.get(callId), - status, - childCallIds: childCallMap.get(callId), - isCollapsed: collapsed.has(callId), - toggleCollapsed: () => - setCollapsed((ids) => { - if (ids.has(callId)) ids.delete(callId); - else ids.add(callId); - return new Set(ids); - }), - })); - const endRef = React.useRef(); React.useEffect(() => { let observer: IntersectionObserver; @@ -212,6 +192,38 @@ export const Panel: React.FC = (props) => { const showStatus = log.length > 0 && !isPlaying; const hasException = log.some((item) => item.status === CallStates.ERROR); + const interactions = React.useMemo(() => { + const callsById = new Map(); + const childCallMap = new Map(); + return log + .filter(({ callId, parentId }) => { + if (!parentId) return true; + childCallMap.set(parentId, (childCallMap.get(parentId) || []).concat(callId)); + return !collapsed.has(parentId); + }) + .map(({ callId, status }) => ({ ...calls.current.get(callId), status } as Call)) + .map((call) => { + const status = + call.status === CallStates.ERROR && + callsById.get(call.parentId)?.status === CallStates.ACTIVE + ? CallStates.ACTIVE + : call.status; + callsById.set(call.id, { ...call, status }); + return { + ...call, + status, + childCallIds: childCallMap.get(call.id), + isCollapsed: collapsed.has(call.id), + toggleCollapsed: () => + setCollapsed((ids) => { + if (ids.has(call.id)) ids.delete(call.id); + else ids.add(call.id); + return new Set(ids); + }), + }; + }); + }, [log, collapsed]); + return ( diff --git a/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx b/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx index d3df3f635f2f..f1d8aace3951 100644 --- a/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx +++ b/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx @@ -35,6 +35,12 @@ export const Demo: CSF2Story = (args) => ( Demo.play = async ({ args, canvasElement }) => { await userEvent.click(within(canvasElement).getByRole('button')); await expect(args.onSubmit).toHaveBeenCalledWith(expect.stringMatching(/([A-Z])\w+/gi)); + await expect([{ name: 'John', age: 42 }]).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: 'John' }), + expect.objectContaining({ age: 42 }), + ]) + ); }; export const FindBy: CSF2Story = (args) => { diff --git a/addons/interactions/src/components/MethodCall.tsx b/addons/interactions/src/components/MethodCall.tsx index fa792dce56aa..871068cea0ef 100644 --- a/addons/interactions/src/components/MethodCall.tsx +++ b/addons/interactions/src/components/MethodCall.tsx @@ -112,7 +112,7 @@ export const Node = ({ case value === undefined: return ; case Array.isArray(value): - return ; + return ; case typeof value === 'string': return ; case typeof value === 'number': @@ -191,12 +191,22 @@ export const BooleanNode = ({ value, ...props }: { value: boolean }) => { ); }; -export const ArrayNode = ({ value, nested = false }: { value: any[]; nested?: boolean }) => { +export const ArrayNode = ({ + value, + nested = false, + callsById, +}: { + value: any[]; + nested?: boolean; + callsById?: Map; +}) => { const colors = useThemeColors(); if (nested) { return […]; } - const nodes = value.slice(0, 3).map((v) => ); + const nodes = value + .slice(0, 3) + .map((v) => ); const nodelist = interleave(nodes, , ); if (value.length <= 3) { return [{nodelist}]; diff --git a/app/react/src/client/preview/render.tsx b/app/react/src/client/preview/render.tsx index 94db184a3b6b..e2f305158a58 100644 --- a/app/react/src/client/preview/render.tsx +++ b/app/react/src/client/preview/render.tsx @@ -147,4 +147,6 @@ export async function renderToDOM( } await renderElement(element, domElement); + + return () => unmountElement(domElement); } diff --git a/docs/configure/overview.md b/docs/configure/overview.md index c2a7fa44c02c..5cc0081afff2 100644 --- a/docs/configure/overview.md +++ b/docs/configure/overview.md @@ -28,7 +28,7 @@ The `main.js` configuration file is a [preset](../addons/addon-types.md) and, as - `stories` - an array of globs that indicates the [location of your story files](#configure-story-loading), relative to `main.js`. - `addons` - a list of the [addons](https://storybook.js.org/addons/) you are using. -- `webpackFinal` - custom [webpack configuration](./webpack.md#extending-storybooks-webpack-config). +- `webpackFinal` - custom [webpack configuration](../builders/webpack.md#extending-storybooks-webpack-config). - `babel` - custom [babel configuration](./babel.md). - `framework` - framework specific configurations to help the loading and building process. @@ -185,7 +185,7 @@ You can also use Storybook's API to configure your project with TypeScript. Unde | `features` | Enables Storybook's additional features.
See table below for a list of available features `features: { storyStoreV7: true }` | | `refs` | Configures [Storybook composition](../sharing/storybook-composition.md)
`refs:{ example: { title: 'ExampleStorybook', url:'https://your-url.com' } }` | | `logLevel` | Configures Storybook's logs in the browser terminal. Useful for debugging
`logLevel: 'debug'` | -| `webpackFinal` | Customize Storybook's [Webpack](./webpack.md) setup
`webpackFinal: async (config:any) => { return config; }` | +| `webpackFinal` | Customize Storybook's [Webpack](../builders/webpack.md) setup
`webpackFinal: async (config:any) => { return config; }` | | `env` | Defines custom Storybook [environment variables](./environment-variables.md#using-storybook-configuration).
`env: (config) => ({...config, EXAMPLE_VAR: 'Example var' }),` | ## Configure story rendering diff --git a/docs/configure/story-rendering.md b/docs/configure/story-rendering.md index 360dde244f14..f930fe1e3765 100644 --- a/docs/configure/story-rendering.md +++ b/docs/configure/story-rendering.md @@ -2,7 +2,7 @@ title: 'Story rendering' --- -In Storybook, your stories render in a particular “preview” iframe (Canvas tab) inside the larger Storybook web application. The JavaScript build configuration of the preview is controlled by a [webpack](./webpack.md) config, but you also may want to directly control the rendered HTML to help your stories render correctly. +In Storybook, your stories render in a particular “preview” iframe (Canvas tab) inside the larger Storybook web application. The JavaScript build configuration of the preview is controlled by a [webpack](../builders/webpack.md) config, but you also may want to directly control the rendered HTML to help your stories render correctly. ## Adding to <head> diff --git a/docs/configure/styling-and-css.md b/docs/configure/styling-and-css.md index 2253874499fb..a6c01a6589bf 100644 --- a/docs/configure/styling-and-css.md +++ b/docs/configure/styling-and-css.md @@ -10,7 +10,7 @@ CSS-in-JS libraries are designed to use basic JavaScript, and they often work in ### Importing CSS files -If your component files import their CSS, Storybook's webpack configuration will work out of the box. The noticeable exception to this is if you're using a CSS precompiler. In this case, you can either install and configure a Storybook preset (e.g., [SCSS preset](https://github.com/storybookjs/presets/tree/master/packages/preset-scss)), or customize [Storybook's webpack configuration](./webpack.md#extending-storybooks-webpack-config) and include the appropriate loader. +If your component files import their CSS, Storybook's webpack configuration will work out of the box. The noticeable exception to this is if you're using a CSS precompiler. In this case, you can either install and configure a Storybook preset (e.g., [SCSS preset](https://github.com/storybookjs/presets/tree/master/packages/preset-scss)), or customize [Storybook's webpack configuration](../builders/webpack.md#extending-storybooks-webpack-config) and include the appropriate loader. @@ -18,4 +18,4 @@ To use your CSS in all stories, you import it in [`.storybook/preview.js`](./ove ### Adding webfonts -If you need webfonts to be available, you may need to add some code to the [`.storybook/preview-head.html`](./story-rendering.md#adding-to-head) file. We recommend including any assets with your Storybook if possible, in which case you likely want to configure the [static file location](./images-and-assets.md#serving-static-files-via-storybook-configuration). \ No newline at end of file +If you need webfonts to be available, you may need to add some code to the [`.storybook/preview-head.html`](./story-rendering.md#adding-to-head) file. We recommend including any assets with your Storybook if possible, in which case you likely want to configure the [static file location](./images-and-assets.md#serving-static-files-via-storybook-configuration). diff --git a/docs/faq.md b/docs/faq.md index f05062edf05e..cc1dec1ca45a 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -145,72 +145,70 @@ With the release of version 6.0, we updated our documentation as well. That does We're only covering versions 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo. - -| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | -|------------------|-------------------------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| -| Get started | Install | [See current documentation](./get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | -| | What's a story | [See current documentation](./get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | -| | Browse Stories | [See current documentation](./get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | -| | Setup | [See current documentation](./get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | -| Write stories | Introduction | [See current documentation](./writing-stories/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Parameters | [See current documentation](./writing-stories/parameters.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters) | Non existing feature or undocumented | -| | Decorators | [See current documentation](./writing-stories/decorators.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) | -| | Naming components and hierarchy | [See current documentation](./writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Build pages and screens | [See current documentation](./writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Stories for multiple components | [See current documentation](./writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Write docs | DocsPage | [See current documentation](./writing-docs/docs-page.md) | See versioned addon documentation | Non existing feature or undocumented | -| | MDX | [See current documentation](./writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | -| | Doc Blocks/Argstable | [See current documentation](./writing-docs/doc-block-argstable.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Canvas | [See current documentation](./writing-docs/doc-block-canvas.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Color Palette | [See current documentation](./writing-docs/doc-block-colorpalette.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Description | [See current documentation](./writing-docs/doc-block-description.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Icon Gallery | [See current documentation](./writing-docs/doc-block-icongallery.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Source | [See current documentation](./writing-docs/doc-block-source.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Story | [See current documentation](./writing-docs/doc-block-story.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Typeset | [See current documentation](./writing-docs/doc-block-typeset.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Preview and build docs | [See current documentation](./writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Testing | Visual tests | [See current documentation](./writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | -| | Accessibility tests | [See current documentation](./writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Interaction tests | [See current documentation](./writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | -| | Snapshot tests | [See current documentation](./writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | -| | Import stories in tests | [See current documentation](./writing-tests/importing-stories-in-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | -| Sharing | Publish Storybook | [See current documentation](./sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | -| | Embed | [See current documentation](./sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Composition | [See current documentation](./sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Package Composition | [See current documentation](./sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Essential addons | Controls | [See current documentation](./essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | -| | Actions | [See current documentation](./essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | -| | Viewport | [See current documentation](./essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | -| | Backgrounds | [See current documentation](./essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | -| | Toolbars and globals | [See current documentation](./essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | -| Configure | Overview | [See current documentation](./configure/overview.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Integration/Babel | [See current documentation](./configure/babel.md) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | -| | Integration/Typescript | [See current documentation](./configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | -| | Integration/Styling and CSS | [See current documentation](./configure/styling-and-css.md) | See versioned documentation | See versioned documentation | -| | Integration/Images and assets | [See current documentation](./configure/images-and-assets.md) | See versioned documentation | See versioned documentation | -| | Story rendering | [See current documentation](./configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | -| | Story Layout | [See current documentation](./configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | User Interface/Features and behavior | [See current documentation](./configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | User Interface/Theming | [See current documentation](./configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | -| | User Interface/Sidebar & URLS | [See current documentation](./configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | Environment variables | [See current documentation](./configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | -| Builders | Introduction | [See current documentation](./builders/overview.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Vite | [See current documentation](./builders/vite.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Webpack | [See current documentation](./builders/webpack.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md) | -| | Builder API | [See current documentation](./builders/builder-api.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Addons | Introduction | [See current documentation](./addons/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Install addons | [See current documentation](./addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/) | -| | Writing Addons | [See current documentation](./addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Writing Presets | [See current documentation](./addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | -| | Addons Knowledge Base | [See current documentation](./addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Types of addons | [See current documentation](./addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Addons API | [See current documentation](./addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | -| API | Stories/Component Story Format | [See current documentation](./api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | -| | Stories/MDX syntax | [See current documentation](./api/mdx.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/mdx-syntax) | Non existing feature or undocumented | -| | Stories/StoriesOF format (see note below) | [See current documentation](../lib/core/docs/storiesOf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/storiesof-api) | Non existing feature or undocumented | -| | Frameworks | [See current documentation](./api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | CLI options | [See current documentation](./api/cli-options.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options) | - +| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | +| ---------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Get started | Install | [See current documentation](./get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | +| | What's a story | [See current documentation](./get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| | Browse Stories | [See current documentation](./get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | +| | Setup | [See current documentation](./get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| Write stories | Introduction | [See current documentation](./writing-stories/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Parameters | [See current documentation](./writing-stories/parameters.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters) | Non existing feature or undocumented | +| | Decorators | [See current documentation](./writing-stories/decorators.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) | +| | Naming components and hierarchy | [See current documentation](./writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Build pages and screens | [See current documentation](./writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Stories for multiple components | [See current documentation](./writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Write docs | DocsPage | [See current documentation](./writing-docs/docs-page.md) | See versioned addon documentation | Non existing feature or undocumented | +| | MDX | [See current documentation](./writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | +| | Doc Blocks/Argstable | [See current documentation](./writing-docs/doc-block-argstable.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Canvas | [See current documentation](./writing-docs/doc-block-canvas.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Color Palette | [See current documentation](./writing-docs/doc-block-colorpalette.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Description | [See current documentation](./writing-docs/doc-block-description.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Icon Gallery | [See current documentation](./writing-docs/doc-block-icongallery.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Source | [See current documentation](./writing-docs/doc-block-source.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Story | [See current documentation](./writing-docs/doc-block-story.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Typeset | [See current documentation](./writing-docs/doc-block-typeset.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Preview and build docs | [See current documentation](./writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Testing | Visual tests | [See current documentation](./writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | +| | Accessibility tests | [See current documentation](./writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Interaction tests | [See current documentation](./writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | +| | Snapshot tests | [See current documentation](./writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | +| | Import stories in tests | [See current documentation](./writing-tests/importing-stories-in-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | +| Sharing | Publish Storybook | [See current documentation](./sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | +| | Embed | [See current documentation](./sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Composition | [See current documentation](./sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Package Composition | [See current documentation](./sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Essential addons | Controls | [See current documentation](./essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | +| | Actions | [See current documentation](./essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | +| | Viewport | [See current documentation](./essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | +| | Backgrounds | [See current documentation](./essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | +| | Toolbars and globals | [See current documentation](./essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | +| Configure | Overview | [See current documentation](./configure/overview.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Integration/Babel | [See current documentation](./configure/babel.md) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | +| | Integration/Typescript | [See current documentation](./configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | +| | Integration/Styling and CSS | [See current documentation](./configure/styling-and-css.md) | See versioned documentation | See versioned documentation | +| | Integration/Images and assets | [See current documentation](./configure/images-and-assets.md) | See versioned documentation | See versioned documentation | +| | Story rendering | [See current documentation](./configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | +| | Story Layout | [See current documentation](./configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | User Interface/Features and behavior | [See current documentation](./configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | User Interface/Theming | [See current documentation](./configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | +| | User Interface/Sidebar & URLS | [See current documentation](./configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | Environment variables | [See current documentation](./configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | +| Builders | Introduction | [See current documentation](./builders/overview.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Vite | [See current documentation](./builders/vite.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Webpack | [See current documentation](./builders/webpack.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md) | +| | Builder API | [See current documentation](./builders/builder-api.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Addons | Introduction | [See current documentation](./addons/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Install addons | [See current documentation](./addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/) | +| | Writing Addons | [See current documentation](./addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Writing Presets | [See current documentation](./addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | +| | Addons Knowledge Base | [See current documentation](./addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Types of addons | [See current documentation](./addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Addons API | [See current documentation](./addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | +| API | Stories/Component Story Format | [See current documentation](./api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | +| | Stories/MDX syntax | [See current documentation](./api/mdx.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/mdx-syntax) | Non existing feature or undocumented | +| | Stories/StoriesOF format (see note below) | [See current documentation](https://github.com/storybookjs/storybook/blob/next/lib/core/docs/storiesOf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/storiesof-api) | Non existing feature or undocumented | +| | Frameworks | [See current documentation](./api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | CLI options | [See current documentation](./api/cli-options.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options) |
With the release of version 5.3, we've updated how you can write your stories more compactly and easily. It doesn't mean that the storiesOf format has been removed. For the time being, we're still supporting it, and we have documentation for it. But be advised that this is bound to change in the future. @@ -285,7 +283,6 @@ See our documentation on how to customize the [Storyshots configuration](./writi Currently there's an issue when using MDX stories with IE11. This issue does not apply to [DocsPage](./writing-docs/docs-page.md). If you're interested in helping us fix this issue, read our Contribution guidelines and submit a pull request. - ### Why aren't my code blocks highlighted with Storybook MDX Out of the box, Storybook provides syntax highlighting for a set of languages (e.g., Javascript, Markdown, CSS, HTML, Typescript, GraphQL) that you can use with your code blocks. If you're writing your custom code blocks with MDX, you'll need to import the syntax highlighter manually. For example, if you're adding a code block for SCSS, adjust your story to the following: @@ -341,7 +338,6 @@ You'll need to update it to make it compatible with MDX 2. See the following [issue](https://github.com/mdx-js/mdx/issues/1945) for more information. - ### Why can't I import my own stories into MDX 2? This is a known issue with MDX 2. We're working to fix it. For now you can apply the following workaround: @@ -356,7 +352,6 @@ import * as stories from './Button.stories.jsx'; ``` - ### Why are my mocked GraphQL queries failing with Storybook's MSW addon? If you're working with Vue 3, you'll need to install [`@vue/apollo-composable`](https://www.npmjs.com/package/@vue/apollo-composable). With Svelte, you'll need to install [`@rollup/plugin-replace`](https://www.npmjs.com/package/@rollup/plugin-replace) and update your `rollup.config` file to the following: @@ -399,8 +394,6 @@ Yes, check the [addon's examples](https://github.com/mswjs/msw-storybook-addon/t No, currently, the MSW addon only has support for GraphQL queries. If you're interested in including this feature, open an issue in the [MSW addon repository](https://github.com/mswjs/msw-storybook-addon) and follow up with the maintainer. - - ### How can my code detect if it is running in Storybook? You can do this by checking for the `IS_STORYBOOK` global variable, which will equal `true` when running in Storybook. The environment variable `process.env.STORYBOOK` is also set to `true`. @@ -477,11 +470,10 @@ export default { There's an issue with Storybook's test runner and the latest version of Jest (i.e., version 28), which prevents it from running effectively. As a workaround, you can downgrade Jest to the previous stable version (i.e., version 27), and you'll be able to run it. See the following [issue](https://github.com/storybookjs/test-runner/issues/99) for more information. - ### How does Storybook handles enviroment variables? Storybook has built-in support for [environment variables](./configure/environment-variables.md). By default, environment variables are only available in Node.js code and are not available in the browser as some variables should be kept secret (e.g., API keys) and **not** exposed to anyone visiting the published Storybook. To expose a variable, you must preface its name with `STORYBOOK_`. So `STORYBOOK_API_URL` will be available in browser code but `API_KEY` will not. Additionally you can also customize which variables are exposed by setting the [`env`](./configure/environment-variables.md#using-storybook-configuration) field in the `.storybook/main.js` file. -Variables are set when JavaScript is compiled so when the development server is started or you build your Storybook. Environment variable files should not be committed to Git as they often contain secrets which are not safe to add to Git. Instead, add `.env.*` to your `.gitignore` file and set up the environment variables manually on your hosting provider (e.g., [GitHub](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository)). \ No newline at end of file +Variables are set when JavaScript is compiled so when the development server is started or you build your Storybook. Environment variable files should not be committed to Git as they often contain secrets which are not safe to add to Git. Instead, add `.env.*` to your `.gitignore` file and set up the environment variables manually on your hosting provider (e.g., [GitHub](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository)). diff --git a/docs/frameworks.js b/docs/frameworks.js index e634b6612c45..8d2e1156f7b8 100644 --- a/docs/frameworks.js +++ b/docs/frameworks.js @@ -117,27 +117,27 @@ module.exports = { { name: 'Source', unsupported: [], - path: 'writing-docs/doc-blocks#source', + path: 'writing-docs/doc-block-source', }, { name: 'Dynamic source', supported: ['react', 'vue', 'angular', 'svelte', 'web-components', 'html'], - path: 'writing-docs/doc-blocks#source', + path: 'writing-docs/doc-block-source', }, { name: 'Args Table', supported: ['react', 'vue', 'angular', 'html', 'ember', 'web-components', 'svelte'], - path: 'writing-docs/doc-blocks#argstable', + path: 'writing-docs/doc-block-argstable', }, { name: 'Description', supported: ['react', 'vue', 'angular', 'ember', 'web-components'], - path: 'writing-docs/doc-blocks#description', + path: 'writing-docs/doc-block-description', }, { name: 'Inline stories', supported: ['react', 'vue', 'web-components', 'html', 'svelte', 'angular'], - path: 'writing-docs/doc-blocks#inline-rendering', + path: 'writing-docs/docs-page#inline-stories-vs-iframe-stories', }, ], }, diff --git a/docs/get-started/installation-problems/angular.mdx b/docs/get-started/installation-problems/angular.mdx index 773e23f801ac..c0c463e548bf 100644 --- a/docs/get-started/installation-problems/angular.mdx +++ b/docs/get-started/installation-problems/angular.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type angular` flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/installation-problems/ember.mdx b/docs/get-started/installation-problems/ember.mdx index 23856fe3d542..7a7698e3d84b 100644 --- a/docs/get-started/installation-problems/ember.mdx +++ b/docs/get-started/installation-problems/ember.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type ember` flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/installation-problems/preact.mdx b/docs/get-started/installation-problems/preact.mdx index 3b1a2b94a1bd..593f0c13ef33 100644 --- a/docs/get-started/installation-problems/preact.mdx +++ b/docs/get-started/installation-problems/preact.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type preact` flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/installation-problems/react.mdx b/docs/get-started/installation-problems/react.mdx index 36f517bcdaff..0acc6ef29f97 100644 --- a/docs/get-started/installation-problems/react.mdx +++ b/docs/get-started/installation-problems/react.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type react` flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/installation-problems/svelte.mdx b/docs/get-started/installation-problems/svelte.mdx index 2b53693d98c8..68f248b11ec8 100644 --- a/docs/get-started/installation-problems/svelte.mdx +++ b/docs/get-started/installation-problems/svelte.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type svelte` flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/installation-problems/vue.mdx b/docs/get-started/installation-problems/vue.mdx index 61ab98ead519..d0c276ff4970 100644 --- a/docs/get-started/installation-problems/vue.mdx +++ b/docs/get-started/installation-problems/vue.mdx @@ -1,3 +1,10 @@ +- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. + If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + + ```shell + npx storybook init --use-npm + ``` + - Add the `--type vue` (for Vue 2), or `--type vue3` (for Vue 3) flag to the installation command to set up Storybook manually: ```shell diff --git a/docs/get-started/whats-a-story.md b/docs/get-started/whats-a-story.md index 8425cc063cfc..c349c1768787 100644 --- a/docs/get-started/whats-a-story.md +++ b/docs/get-started/whats-a-story.md @@ -93,6 +93,6 @@ Stories are also helpful for checking that UI continues to look correct as you m /> -Checking component’s stories as you develop helps prevent accidental regressions. Tools that integrate with Storybook can also [automate](../writing-tests/introduction.md) this for you. +Checking component’s stories as you develop helps prevent accidental regressions. [Tools that integrate with Storybook can automate this](../writing-tests/introduction.md) for you. Now that we’ve seen the basic anatomy of a story let’s see how we use Storybook’s UI to develop stories. diff --git a/docs/snippets/html/button-story-component-decorator.js.mdx b/docs/snippets/html/button-story-component-decorator.js.mdx new file mode 100644 index 000000000000..c87cb62adbb8 --- /dev/null +++ b/docs/snippets/html/button-story-component-decorator.js.mdx @@ -0,0 +1,21 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + decorators: [(story) => { + const decorator = document.createElement('div'); + decorator.style.margin = '3em'; + decorator.appendChild(story()); + return decorator; + }], +}; + +export const Primary = (args) => createButton(args); +``` diff --git a/docs/snippets/html/button-story-component-decorator.ts.mdx b/docs/snippets/html/button-story-component-decorator.ts.mdx new file mode 100644 index 000000000000..d1a4efaa4258 --- /dev/null +++ b/docs/snippets/html/button-story-component-decorator.ts.mdx @@ -0,0 +1,23 @@ +```ts +// Button.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + decorators: [(story) => { + const decorator = document.createElement('div'); + decorator.style.margin = '3em'; + decorator.appendChild(story()); + return decorator; + }], +} as Meta; + +export const Primary: StoryFn = (args) => createButton(args); +``` diff --git a/docs/snippets/html/button-story-default-exports.js.mdx b/docs/snippets/html/button-story-default-exports.js.mdx new file mode 100644 index 000000000000..c6bbe5bf64f1 --- /dev/null +++ b/docs/snippets/html/button-story-default-exports.js.mdx @@ -0,0 +1,13 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +}; +``` diff --git a/docs/snippets/html/button-story-default-exports.ts.mdx b/docs/snippets/html/button-story-default-exports.ts.mdx new file mode 100644 index 000000000000..e294d98b1b40 --- /dev/null +++ b/docs/snippets/html/button-story-default-exports.ts.mdx @@ -0,0 +1,15 @@ +```ts +// Button.stories.ts + +import { Meta } from '@storybook/html'; + +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +} as Meta; +``` diff --git a/docs/snippets/html/button-story-rename-story.js.mdx b/docs/snippets/html/button-story-rename-story.js.mdx new file mode 100644 index 000000000000..3f13f148ce43 --- /dev/null +++ b/docs/snippets/html/button-story-rename-story.js.mdx @@ -0,0 +1,16 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +}; + +export const Primary = (args) => createButton(args); +Primary.storyName = 'I am the primary'; +``` diff --git a/docs/snippets/html/button-story-rename-story.ts.mdx b/docs/snippets/html/button-story-rename-story.ts.mdx new file mode 100644 index 000000000000..0b37196b9a41 --- /dev/null +++ b/docs/snippets/html/button-story-rename-story.ts.mdx @@ -0,0 +1,18 @@ +```ts +// Button.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +} as Meta; + +export const Primary: StoryFn = (args) => createButton(args); +Primary.storyName = 'I am the primary'; +``` diff --git a/docs/snippets/html/button-story-using-args.js.mdx b/docs/snippets/html/button-story-using-args.js.mdx new file mode 100644 index 000000000000..9df04fd6e394 --- /dev/null +++ b/docs/snippets/html/button-story-using-args.js.mdx @@ -0,0 +1,26 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +}; + +//👇 We create a “template” of how args map to rendering +const Template = (args) => createButton(args); + +//👇 Each story then reuses that template +export const Primary = Template.bind({}); +Primary.args = { primary: true, label: 'Button' }; + +export const Secondary = Template.bind({}); +Secondary.args = { ...Primary.args, label: '😄👍😍💯' }; + +export const Tertiary = Template.bind({}); +Tertiary.args = { ...Primary.args, label: '📚📕📈🤓' }; +``` diff --git a/docs/snippets/html/button-story-using-args.ts.mdx b/docs/snippets/html/button-story-using-args.ts.mdx new file mode 100644 index 000000000000..759858bf1da4 --- /dev/null +++ b/docs/snippets/html/button-story-using-args.ts.mdx @@ -0,0 +1,27 @@ +```ts +// Button.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +} as Meta; + +//👇 We create a “template” of how args map to rendering +const Template: StoryFn = (args): HTMLButtonElement => createButton(args); + +//👇 Each story then reuses that template +export const Primary = Template.bind({}); +Primary.args = { primary: true, label: 'Button' }; + +export const Secondary = Template.bind({}); +Secondary.args = { ...Primary.args, label: '😄👍😍💯' }; + +export const Tertiary = Template.bind({}); +Tertiary.args = { ...Primary.args, label: '📚📕📈🤓' }; +``` diff --git a/docs/snippets/html/button-story-with-args.js.mdx b/docs/snippets/html/button-story-with-args.js.mdx index 60feb2014547..8d71b288cef9 100644 --- a/docs/snippets/html/button-story-with-args.js.mdx +++ b/docs/snippets/html/button-story-with-args.js.mdx @@ -1,4 +1,6 @@ ```js +// Button.stories.js + export default { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading diff --git a/docs/snippets/html/button-story-with-args.ts.mdx b/docs/snippets/html/button-story-with-args.ts.mdx index 3130fc260de7..9b75446177ee 100644 --- a/docs/snippets/html/button-story-with-args.ts.mdx +++ b/docs/snippets/html/button-story-with-args.ts.mdx @@ -1,16 +1,23 @@ ```ts +// Button.stories.ts + import { Meta, StoryFn } from '@storybook/html'; +type ButtonArgs = { + primary: boolean; + label: string; +} + export default { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading * to learn how to generate automatic titles */ title: 'Button', -} as Meta; +} as Meta; //👇 We create a “template” of how args map to rendering -const Template: StoryFn = (args): HTMLButtonElement => { +const Template: StoryFn = (args): HTMLButtonElement => { const btn = document.createElement('button'); btn.innerText = args.label; diff --git a/docs/snippets/html/button-story-with-blue-args.js.mdx b/docs/snippets/html/button-story-with-blue-args.js.mdx new file mode 100644 index 000000000000..5cb8981ad168 --- /dev/null +++ b/docs/snippets/html/button-story-with-blue-args.js.mdx @@ -0,0 +1,25 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + //👇 Creates specific parameters for the story + parameters: { + backgrounds: { + values: [ + { name: 'red', value: '#f00' }, + { name: 'green', value: '#0f0' }, + { name: 'blue', value: '#00f' }, + ], + }, + }, +}; + +export const Primary = (args) => createButton(args); +``` diff --git a/docs/snippets/html/button-story-with-blue-args.ts.mdx b/docs/snippets/html/button-story-with-blue-args.ts.mdx new file mode 100644 index 000000000000..906845b4f472 --- /dev/null +++ b/docs/snippets/html/button-story-with-blue-args.ts.mdx @@ -0,0 +1,27 @@ +```ts +// Button.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + //👇 Creates specific parameters for the story + parameters: { + backgrounds: { + values: [ + { name: 'red', value: '#f00' }, + { name: 'green', value: '#0f0' }, + { name: 'blue', value: '#00f' }, + ], + }, + }, +} as Meta; + +export const Primary: StoryFn = (args) => createButton(args); +``` diff --git a/docs/snippets/html/button-story-with-emojis.js.mdx b/docs/snippets/html/button-story-with-emojis.js.mdx new file mode 100644 index 000000000000..b6b9b43ec295 --- /dev/null +++ b/docs/snippets/html/button-story-with-emojis.js.mdx @@ -0,0 +1,16 @@ +```js +// Button.stories.js + +import { createButton } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +}; +export const Primary = () => createButton({ backgroundColor: "#ff0", label: "Button"}); +export const Secondary = () => createButton({ backgroundColor: "#ff0", label: "😄👍😍💯"}); +export const Tertiary = () => createButton({ backgroundColor: "#ff0", label: "📚📕📈🤓"}); +``` diff --git a/docs/snippets/html/button-story-with-emojis.ts.mdx b/docs/snippets/html/button-story-with-emojis.ts.mdx new file mode 100644 index 000000000000..47a1f99f8ee1 --- /dev/null +++ b/docs/snippets/html/button-story-with-emojis.ts.mdx @@ -0,0 +1,17 @@ +```ts +// Button.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; +import { createButton, ButtonArgs } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', +} as Meta; +export const Primary: StoryFn = () => createButton({ backgroundColor: "#ff0", label: "Button"}); +export const Secondary: StoryFn = () => createButton({ backgroundColor: "#ff0", label: "😄👍😍💯"}); +export const Tertiary: StoryFn = () => createButton({ backgroundColor: "#ff0", label: "📚📕📈🤓"}); +``` diff --git a/docs/snippets/html/button-story.js.mdx b/docs/snippets/html/button-story.js.mdx index 743c489eff80..6268687c428b 100644 --- a/docs/snippets/html/button-story.js.mdx +++ b/docs/snippets/html/button-story.js.mdx @@ -1,4 +1,6 @@ ```js +// Button.stories.js + export default { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading diff --git a/docs/snippets/html/button-story.ts.mdx b/docs/snippets/html/button-story.ts.mdx index 104aa6ccbd19..62e72638171e 100644 --- a/docs/snippets/html/button-story.ts.mdx +++ b/docs/snippets/html/button-story.ts.mdx @@ -1,4 +1,6 @@ ```ts +// Button.stories.ts + import { Meta, StoryFn } from '@storybook/html'; export default { diff --git a/docs/snippets/html/list-story-expanded.js.mdx b/docs/snippets/html/list-story-expanded.js.mdx new file mode 100644 index 000000000000..b9cbe7d627f1 --- /dev/null +++ b/docs/snippets/html/list-story-expanded.js.mdx @@ -0,0 +1,27 @@ + +```js +// List.stories.js + +import { createList } from './List'; +import { createListItem } from './ListItem'; + +export default { + title: 'List', +}; + +export const Empty = (args) => createList(args); + +export const OneItem = (args) => { + const list = createList(args); + list.appendChild(createListItem()); + return list; +}; + +export const ManyItems = (args) => { + const list = createList(args); + list.appendChild(createListItem()); + list.appendChild(createListItem()); + list.appendChild(createListItem()); + return list; +}; +``` diff --git a/docs/snippets/html/list-story-expanded.ts.mdx b/docs/snippets/html/list-story-expanded.ts.mdx new file mode 100644 index 000000000000..81e14d1162a4 --- /dev/null +++ b/docs/snippets/html/list-story-expanded.ts.mdx @@ -0,0 +1,29 @@ + +```ts +// List.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createList, ListArgs } from './List'; +import { createListItem } from './ListItem'; + +export default { + title: 'List', +} as Meta; + +export const Empty: StoryFn = (args) => createList(args); + +export const OneItem: StoryFn = (args) => { + const list = createList(args); + list.appendChild(createListItem()); + return list; +}; + +export const ManyItems: StoryFn = (args) => { + const list = createList(args); + list.appendChild(createListItem()); + list.appendChild(createListItem()); + list.appendChild(createListItem()); + return list; +}; +``` diff --git a/docs/snippets/html/list-story-reuse-data.js.mdx b/docs/snippets/html/list-story-reuse-data.js.mdx new file mode 100644 index 000000000000..a58833617912 --- /dev/null +++ b/docs/snippets/html/list-story-reuse-data.js.mdx @@ -0,0 +1,22 @@ + +```js +// List.stories.js + +import { createList } from './List'; +import { createListItem } from './ListItem'; + +// 👇 We're importing the necessary stories from ListItem +import { Selected, Unselected } from './ListItem.stories'; + +export default { + title: 'List', +}; + +export const ManyItems = (args) => { + const list = createList(args); + list.appendChild(createListItem(Selected.args)); + list.appendChild(createListItem(Unselected.args)); + list.appendChild(createListItem(Unselected.args)); + return list; +}; +``` diff --git a/docs/snippets/html/list-story-reuse-data.ts.mdx b/docs/snippets/html/list-story-reuse-data.ts.mdx new file mode 100644 index 000000000000..434bec00d690 --- /dev/null +++ b/docs/snippets/html/list-story-reuse-data.ts.mdx @@ -0,0 +1,32 @@ + +```ts +// List.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createList, ListArgs } from './List'; +import { createListItem } from './ListItem'; + +// 👇 We're importing the necessary stories from ListItem +import { Selected, Unselected } from './ListItem.stories'; + +export default { + title: 'List', +} as Meta; + +export const Empty: StoryFn = (args) => createList(args); + +export const OneItem: StoryFn = (args) => { + const list = createList(args); + list.appendChild(createListItem()); + return list; +}; + +export const ManyItems: StoryFn = (args) => { + const list = createList(args); + list.appendChild(createListItem(Selected.args)); + list.appendChild(createListItem(Unselected.args)); + list.appendChild(createListItem(Unselected.args)); + return list; +}; +``` diff --git a/docs/snippets/html/list-story-starter.js.mdx b/docs/snippets/html/list-story-starter.js.mdx new file mode 100644 index 000000000000..8e4959b468d3 --- /dev/null +++ b/docs/snippets/html/list-story-starter.js.mdx @@ -0,0 +1,12 @@ +```js +// List.stories.js + +import { createList } from './List'; + +export default { + title: 'List', +}; + +// Always an empty list, not super interesting +const Template = (args) => createList(args); +``` diff --git a/docs/snippets/html/list-story-starter.ts.mdx b/docs/snippets/html/list-story-starter.ts.mdx new file mode 100644 index 000000000000..e0706e6c0827 --- /dev/null +++ b/docs/snippets/html/list-story-starter.ts.mdx @@ -0,0 +1,14 @@ +```ts +// List.stories.ts + +import { Meta, StoryFn } from '@storybook/html'; + +import { createList, ListArgs } from './List'; + +export default { + title: 'List', +} as Meta; + +// Always an empty list, not super interesting +const Template: StoryFn = (args) => createList(args); +``` diff --git a/docs/writing-stories/args.md b/docs/writing-stories/args.md index b7b5ac95c273..6d10a8faab72 100644 --- a/docs/writing-stories/args.md +++ b/docs/writing-stories/args.md @@ -33,6 +33,8 @@ To define the args of a single story, use the `args` CSF story key: 'svelte/button-story-with-args.native-format.mdx', 'svelte/button-story-with-args.mdx.mdx', 'web-components/button-story-with-args.js.mdx', + 'html/button-story-with-args.ts.mdx', + 'html/button-story-with-args.js.mdx', ]} /> diff --git a/docs/writing-stories/introduction.md b/docs/writing-stories/introduction.md index 96ca9925fffa..15e4c456516b 100644 --- a/docs/writing-stories/introduction.md +++ b/docs/writing-stories/introduction.md @@ -37,6 +37,8 @@ The _default_ export metadata controls how Storybook lists your stories and prov 'angular/button-story-default-export-with-component.ts.mdx', 'svelte/button-story-default-export-with-component.js.mdx', 'web-components/button-story-default-export-with-component.js.mdx', + 'html/button-story-default-export.js.mdx', + 'html/button-story-default-export.ts.mdx', ]} /> @@ -59,6 +61,8 @@ Use the _named_ exports of a CSF file to define your component’s stories. We r 'svelte/button-story.js.mdx', 'svelte/button-story.native-format.mdx', 'web-components/button-story.js.mdx', + 'html/button-story.js.mdx', + 'html/button-story.ts.mdx', ]} /> @@ -99,6 +103,8 @@ You can rename any particular story you need. For instance, to give it a more ac 'angular/button-story-rename-story.ts.mdx', 'svelte/button-story-rename-story.js.mdx', 'web-components/button-story-rename-story.js.mdx', + 'html/button-story-rename-story.js.mdx', + 'html/button-story-rename-story.ts.mdx', ]} /> @@ -127,6 +133,8 @@ A story is a function that describes how to render a component. You can have mul 'svelte/button-story-with-emojis.native-format.mdx', 'svelte/button-story-with-emojis.mdx.mdx', 'web-components/button-story-with-emojis.js.mdx', + 'html/button-story-with-emojis.js.mdx', + 'html/button-story-with-emojis.ts.mdx', ]} /> @@ -152,6 +160,8 @@ Refine this pattern by introducing `args` for your component's stories. It reduc 'svelte/button-story-using-args.js.mdx', 'svelte/button-story-using-args.native-format.mdx', 'web-components/button-story-using-args.js.mdx', + 'html/button-story-using-args.js.mdx', + 'html/button-story-using-args.ts.mdx', ]} /> @@ -254,6 +264,8 @@ For instance, suppose you wanted to test your Button component against a differe 'svelte/button-story-with-blue-args.native-format.mdx', 'svelte/button-story-with-blue-args.mdx.mdx', 'web-components/button-story-with-blue-args.js.mdx', + 'html/button-story-with-blue-args.js.mdx', + 'html/button-story-with-blue-args.ts.mdx', ]} /> @@ -286,6 +298,8 @@ A simple example is adding padding to a component’s stories. Accomplish this u 'svelte/button-story-component-decorator.native-format.mdx', 'svelte/button-story-component-decorator.mdx.mdx', 'web-components/button-story-component-decorator.js.mdx', + 'html/button-story-component-decorator.js.mdx', + 'html/button-story-component-decorator.ts.mdx', ]} /> @@ -310,6 +324,8 @@ When building design systems or component libraries, you may have two or more co 'vue/list-story-starter.ts-3.ts.mdx', 'svelte/list-story-starter.native-format.mdx', 'web-components/list-story-starter.js.mdx', + 'html/list-story-starter.js.mdx', + 'html/list-story-starter.ts.mdx', ]} /> @@ -330,6 +346,8 @@ In such cases, it makes sense to render a different function for each story: 'vue/list-story-expanded.ts-3.ts.mdx', 'svelte/list-story-expanded.native-format.mdx', 'web-components/list-story-expanded.js.mdx', + 'html/list-story-expanded.js.mdx', + 'html/list-story-expanded.ts.mdx', ]} /> @@ -349,6 +367,8 @@ You can also reuse stories from the child `ListItem` in your `List` component. T 'vue/list-story-reuse-data.3.js.mdx', 'vue/list-story-reuse-data.ts-3.ts.mdx', 'web-components/list-story-reuse-data.js.mdx', + 'html/list-story-reuse-data.js.mdx', + 'html/list-story-reuse-data.ts.mdx', ]} /> diff --git a/docs/writing-tests/interaction-testing.md b/docs/writing-tests/interaction-testing.md index 1b86c56dfc01..d4d74ea0ca48 100644 --- a/docs/writing-tests/interaction-testing.md +++ b/docs/writing-tests/interaction-testing.md @@ -157,7 +157,7 @@ Interaction tests can be expensive to maintain when applied wholesale to every c - [Test runner](./test-runner.md) to automate test execution - [Visual tests](./visual-testing.md) for appearance -- [Accessibility tests](accessibility-testing.md) for accessibility +- [Accessibility tests](./accessibility-testing.md) for accessibility - Interaction tests for user behavior simulation - [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings -- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools diff --git a/docs/writing-tests/test-runner.md b/docs/writing-tests/test-runner.md index 1940f87630c0..e72bd8205454 100644 --- a/docs/writing-tests/test-runner.md +++ b/docs/writing-tests/test-runner.md @@ -45,7 +45,6 @@ Start your Storybook with: 'angular/storybook-run-dev.with-builder.js.mdx', 'common/storybook-run-dev.yarn.js.mdx', 'common/storybook-run-dev.npm.js.mdx', - ]} /> diff --git a/examples/angular-cli/package.json b/examples/angular-cli/package.json index cf04964c67aa..a4144d29e1bb 100644 --- a/examples/angular-cli/package.json +++ b/examples/angular-cli/package.json @@ -54,7 +54,7 @@ "@storybook/babel-plugin-require-context-hook": "1.0.1", "@storybook/jest": "^0.0.5", "@storybook/source-loader": "6.5.0-rc.1", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@types/core-js": "^2.5.4", "@types/jest": "^26.0.16", "@types/node": "^14.14.20 || ^16.0.0", diff --git a/examples/official-storybook/package.json b/examples/official-storybook/package.json index 1bd706b5591d..35f2cb44eb4d 100644 --- a/examples/official-storybook/package.json +++ b/examples/official-storybook/package.json @@ -36,7 +36,7 @@ "@storybook/react": "6.5.0-rc.1", "@storybook/router": "6.5.0-rc.1", "@storybook/source-loader": "6.5.0-rc.1", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@storybook/theming": "6.5.0-rc.1", "@testing-library/dom": "^7.31.2", "@testing-library/user-event": "^13.1.9", diff --git a/examples/react-ts/.storybook/main.ts b/examples/react-ts/.storybook/main.ts index 752f85c6ac60..33fb89ce230f 100644 --- a/examples/react-ts/.storybook/main.ts +++ b/examples/react-ts/.storybook/main.ts @@ -37,7 +37,7 @@ const config: StorybookConfig = { }, features: { postcss: false, - // modernInlineRender: true, + modernInlineRender: true, storyStoreV7: !global.navigator?.userAgent?.match?.('jsdom'), buildStoriesJson: true, babelModeV7: true, diff --git a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap index 409f2a8ab57e..a3430706744a 100644 --- a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap +++ b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap @@ -4041,6 +4041,51 @@ exports[`Storyshots Demo/Examples / Emoji Button With Args 1`] = ` `; +exports[`Storyshots Demo/button2 One 1`] = ` + +`; + +exports[`Storyshots Demo/button2 Three 1`] = ` + +`; + +exports[`Storyshots Demo/button2 Two 1`] = ` + +`; + +exports[`Storyshots Demo/button3 Five 1`] = ` + +`; + +exports[`Storyshots Demo/button3 Four 1`] = ` + +`; + exports[`Storyshots Docs/ButtonMdx Basic 1`] = ` -); +export const Button = ({ label = 'Hello', icon: Icon, ...props }: ButtonProps) => { + useEffect(() => { + const fn = () => console.log(`click ${label}`); + global.window.document.querySelector('body')?.addEventListener('click', fn); + return () => global.window.document.querySelector('body')?.removeEventListener('click', fn); + }); + return ( + + ); +}; diff --git a/examples/react-ts/src/button2.stories.tsx b/examples/react-ts/src/button2.stories.tsx new file mode 100644 index 000000000000..cfaa6df924d4 --- /dev/null +++ b/examples/react-ts/src/button2.stories.tsx @@ -0,0 +1,10 @@ +import { Button } from './button'; + +export default { + component: Button, + title: 'button2', +}; + +export const one = { args: { label: 'one' } }; +export const two = { args: { label: 'two' } }; +export const three = { args: { label: 'three' } }; diff --git a/examples/react-ts/src/button3.stories.tsx b/examples/react-ts/src/button3.stories.tsx new file mode 100644 index 000000000000..941d8f436f3b --- /dev/null +++ b/examples/react-ts/src/button3.stories.tsx @@ -0,0 +1,9 @@ +import { Button } from './button'; + +export default { + component: Button, + title: 'button3', +}; + +export const four = { args: { label: 'four' } }; +export const five = { args: { label: 'five' } }; diff --git a/examples/svelte-kitchen-sink/package.json b/examples/svelte-kitchen-sink/package.json index 881a8306072f..9d6edc94512f 100644 --- a/examples/svelte-kitchen-sink/package.json +++ b/examples/svelte-kitchen-sink/package.json @@ -24,7 +24,7 @@ "@storybook/jest": "^0.0.5", "@storybook/source-loader": "6.5.0-rc.1", "@storybook/svelte": "6.5.0-rc.1", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "svelte-jester": "1.3.0", "svelte-preprocess": "4.6.8" }, diff --git a/examples/vue-3-cli/package.json b/examples/vue-3-cli/package.json index f2f4f3481380..f87414b6d097 100644 --- a/examples/vue-3-cli/package.json +++ b/examples/vue-3-cli/package.json @@ -20,7 +20,7 @@ "@storybook/addon-links": "6.5.0-rc.1", "@storybook/addon-storyshots": "6.5.0-rc.1", "@storybook/jest": "^0.0.5", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@storybook/vue3": "6.5.0-rc.1", "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-typescript": "~4.5.0", diff --git a/examples/vue-kitchen-sink/package.json b/examples/vue-kitchen-sink/package.json index 29d40181469a..042c6c94925d 100644 --- a/examples/vue-kitchen-sink/package.json +++ b/examples/vue-kitchen-sink/package.json @@ -27,7 +27,7 @@ "@storybook/addons": "6.5.0-rc.1", "@storybook/jest": "^0.0.5", "@storybook/source-loader": "6.5.0-rc.1", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@storybook/vue": "6.5.0-rc.1", "@vue/babel-preset-jsx": "^1.2.4", "babel-loader": "^8.0.0", diff --git a/examples/web-components-kitchen-sink/package.json b/examples/web-components-kitchen-sink/package.json index 9fc08ebcee34..f13f2d0481ab 100644 --- a/examples/web-components-kitchen-sink/package.json +++ b/examples/web-components-kitchen-sink/package.json @@ -51,7 +51,7 @@ "@storybook/source-loader": "portal:../../lib/source-loader", "@storybook/store": "portal:../../lib/store", "@storybook/telemetry": "portal:../../lib/telemetry", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@storybook/theming": "portal:../../lib/theming", "@storybook/ui": "portal:../../lib/ui", "@storybook/web-components": "portal:../../app/web-components", diff --git a/lib/cli/src/automigrate/fixes/index.ts b/lib/cli/src/automigrate/fixes/index.ts index 566162243ed3..7cc92a1bba40 100644 --- a/lib/cli/src/automigrate/fixes/index.ts +++ b/lib/cli/src/automigrate/fixes/index.ts @@ -5,6 +5,7 @@ import { vue3 } from './vue3'; import { mainjsFramework } from './mainjsFramework'; import { eslintPlugin } from './eslint-plugin'; import { builderVite } from './builder-vite'; +import { npm7 } from './npm7'; import { Fix } from '../types'; export * from '../types'; @@ -16,4 +17,5 @@ export const fixes: Fix[] = [ mainjsFramework, eslintPlugin, builderVite, + npm7, ]; diff --git a/lib/cli/src/automigrate/fixes/npm7.test.ts b/lib/cli/src/automigrate/fixes/npm7.test.ts new file mode 100644 index 000000000000..83346ccdfaf1 --- /dev/null +++ b/lib/cli/src/automigrate/fixes/npm7.test.ts @@ -0,0 +1,47 @@ +import { NPMProxy } from '../../js-package-manager/NPMProxy'; +import { npm7 } from './npm7'; + +const mockExecuteCommand = jest.fn(); +class MockedNPMProxy extends NPMProxy { + executeCommand(...args) { + return mockExecuteCommand(...args); + } +} + +function mockExecuteResults(map: Record) { + mockExecuteCommand.mockImplementation((command, args) => { + const commandString = `${command} ${args.join(' ')}`; + if (map[commandString]) return map[commandString]; + + throw new Error(`Unexpected execution of '${commandString}'`); + }); +} + +describe('npm7 fix', () => { + describe('npm < 7', () => { + it('does not match', async () => { + mockExecuteResults({ 'npm --version': '6.0.0' }); + expect(await npm7.check({ packageManager: new MockedNPMProxy() })).toEqual(null); + }); + }); + + describe('npm 7+', () => { + it('matches if config is not installed', async () => { + mockExecuteResults({ + 'npm --version': '7.0.0', + 'npm config get legacy-peer-deps --location=project': 'false', + }); + expect(await npm7.check({ packageManager: new MockedNPMProxy() })).toEqual({ + npmVersion: '7.0.0', + }); + }); + + it('does not match if config is installed', async () => { + mockExecuteResults({ + 'npm --version': '7.0.0', + 'npm config get legacy-peer-deps --location=project': 'true', + }); + expect(await npm7.check({ packageManager: new MockedNPMProxy() })).toEqual(null); + }); + }); +}); diff --git a/lib/cli/src/automigrate/fixes/npm7.ts b/lib/cli/src/automigrate/fixes/npm7.ts new file mode 100644 index 000000000000..74f40e6723d8 --- /dev/null +++ b/lib/cli/src/automigrate/fixes/npm7.ts @@ -0,0 +1,41 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; +import { Fix } from '../types'; +import { NPMProxy } from '../../js-package-manager/NPMProxy'; + +interface Npm7RunOptions { + npmVersion: string; +} + +/** + * Is the user using npm7+? If so create a .npmrc with legacy-peer-deps=true + */ +export const npm7: Fix = { + id: 'npm7', + + async check({ packageManager }) { + if (packageManager.type !== 'npm') return null; + + const npmVersion = (packageManager as NPMProxy).getNpmVersion(); + if ((packageManager as NPMProxy).needsLegacyPeerDeps(npmVersion)) { + return { npmVersion }; + } + return null; + }, + + prompt({ npmVersion }) { + const npmFormatted = chalk.cyan(`npm ${npmVersion}`); + return dedent` + We've detected you are running ${npmFormatted} which has peer dependency semantics which Storybook is incompatible with. + + In order to work with Storybook's package structure, you'll need to run \`npm\` with the + \`--legacy-peer-deps=true\` flag. We can generate an \`.npmrc\` which will do that automatically. + + More info: ${chalk.yellow('https://github.com/storybookjs/storybook/issues/18298')} + `; + }, + + async run({ packageManager }) { + (packageManager as NPMProxy).setLegacyPeerDeps(); + }, +}; diff --git a/lib/cli/src/js-package-manager/NPMProxy.ts b/lib/cli/src/js-package-manager/NPMProxy.ts index 052bb6fcd255..8f74cf57e446 100644 --- a/lib/cli/src/js-package-manager/NPMProxy.ts +++ b/lib/cli/src/js-package-manager/NPMProxy.ts @@ -18,10 +18,31 @@ export class NPMProxy extends JsPackageManager { return `npm run ${command}`; } + getNpmVersion(): string { + return this.executeCommand('npm', ['--version']); + } + + hasLegacyPeerDeps() { + const result = this.executeCommand('npm', [ + 'config', + 'get', + 'legacy-peer-deps', + '--location=project', + ]); + return result.trim() === 'true'; + } + + setLegacyPeerDeps() { + this.executeCommand('npm', ['config', 'set', 'legacy-peer-deps=true', '--location=project']); + } + + needsLegacyPeerDeps(version: string) { + return semver.gte(version, '7.0.0') && !this.hasLegacyPeerDeps(); + } + getInstallArgs(): string[] { if (!this.installArgs) { - const version = this.executeCommand('npm', ['--version']); - this.installArgs = semver.gte(version, '7.0.0') + this.installArgs = this.needsLegacyPeerDeps(this.getNpmVersion()) ? ['install', '--legacy-peer-deps'] : ['install']; } diff --git a/lib/instrumenter/src/instrumenter.ts b/lib/instrumenter/src/instrumenter.ts index 4b8253cd3548..86b5f64cc4b1 100644 --- a/lib/instrumenter/src/instrumenter.ts +++ b/lib/instrumenter/src/instrumenter.ts @@ -133,6 +133,9 @@ export class Instrumenter { this.channel.on(STORY_RENDER_PHASE_CHANGED, ({ storyId, newPhase }) => { const { isDebugging } = this.getState(storyId); this.setState(storyId, { renderPhase: newPhase }); + if (newPhase === 'preparing' && isDebugging) { + resetState({ storyId }); + } if (newPhase === 'playing') { resetState({ storyId, isDebugging }); } diff --git a/lib/preview-web/src/Preview.tsx b/lib/preview-web/src/Preview.tsx index 2eae90f861bf..a206506774f8 100644 --- a/lib/preview-web/src/Preview.tsx +++ b/lib/preview-web/src/Preview.tsx @@ -23,6 +23,7 @@ import { StoryIndex, PromiseLike, WebProjectAnnotations, + RenderToDOM, } from '@storybook/store'; import { StoryRender } from './StoryRender'; @@ -45,7 +46,7 @@ export class Preview { importFn?: ModuleImportFn; - renderToDOM: WebProjectAnnotations['renderToDOM']; + renderToDOM: RenderToDOM; storyRenders: StoryRender[] = []; diff --git a/lib/preview-web/src/PreviewWeb.mockdata.ts b/lib/preview-web/src/PreviewWeb.mockdata.ts index ae2eadf8c707..2bca04fe2ac2 100644 --- a/lib/preview-web/src/PreviewWeb.mockdata.ts +++ b/lib/preview-web/src/PreviewWeb.mockdata.ts @@ -7,7 +7,7 @@ import { STORY_RENDER_PHASE_CHANGED, STORY_THREW_EXCEPTION, } from '@storybook/core-events'; -import { StoryIndex } from '@storybook/store'; +import { StoryIndex, TeardownRenderToDOM } from '@storybook/store'; import { RenderPhase } from './PreviewWeb'; export const componentOneExports = { @@ -32,12 +32,13 @@ export const importFn = jest.fn(async (path) => { return path === './src/ComponentOne.stories.js' ? componentOneExports : componentTwoExports; }); +export const teardownRenderToDOM: jest.Mock = jest.fn(); export const projectAnnotations = { globals: { a: 'b' }, globalTypes: {}, decorators: [jest.fn((s) => s())], render: jest.fn(), - renderToDOM: jest.fn(), + renderToDOM: jest.fn().mockReturnValue(teardownRenderToDOM), }; export const getProjectAnnotations = () => projectAnnotations; diff --git a/lib/preview-web/src/PreviewWeb.test.ts b/lib/preview-web/src/PreviewWeb.test.ts index 8d58970be041..4620b661ebe5 100644 --- a/lib/preview-web/src/PreviewWeb.test.ts +++ b/lib/preview-web/src/PreviewWeb.test.ts @@ -44,6 +44,7 @@ import { waitForRender, waitForQuiescence, waitForRenderPhase, + teardownRenderToDOM, } from './PreviewWeb.mockdata'; jest.mock('./WebView'); @@ -120,7 +121,8 @@ beforeEach(() => { componentOneExports.default.loaders[0].mockReset().mockImplementation(async () => ({ l: 7 })); componentOneExports.default.parameters.docs.container.mockClear(); componentOneExports.a.play.mockReset(); - projectAnnotations.renderToDOM.mockReset(); + teardownRenderToDOM.mockReset(); + projectAnnotations.renderToDOM.mockReset().mockReturnValue(teardownRenderToDOM); projectAnnotations.render.mockClear(); projectAnnotations.decorators[0].mockClear(); (ReactDOM.render as any as jest.Mock) @@ -470,7 +472,7 @@ describe('PreviewWeb', () => { it('renders exception if renderToDOM throws', async () => { const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { throw error; }); @@ -519,9 +521,7 @@ describe('PreviewWeb', () => { it('renders error if the story calls showError', async () => { const error = { title: 'title', description: 'description' }; - projectAnnotations.renderToDOM.mockImplementationOnce((context) => - context.showError(error) - ); + projectAnnotations.renderToDOM.mockImplementation((context) => context.showError(error)); document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); @@ -535,7 +535,7 @@ describe('PreviewWeb', () => { it('renders exception if the story calls showException', async () => { const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce((context) => + projectAnnotations.renderToDOM.mockImplementation((context) => context.showException(error) ); @@ -562,7 +562,7 @@ describe('PreviewWeb', () => { it('does not show error display if the render function throws IGNORED_EXCEPTION', async () => { document.location.search = '?id=component-one--a'; - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { throw IGNORED_EXCEPTION; }); @@ -837,7 +837,7 @@ describe('PreviewWeb', () => { const [gate, openGate] = createGate(); document.location.search = '?id=component-one--a'; - projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate); + projectAnnotations.renderToDOM.mockImplementation(async () => gate); await new PreviewWeb().initialize({ importFn, getProjectAnnotations }); await waitForRenderPhase('rendering'); @@ -876,7 +876,7 @@ describe('PreviewWeb', () => { it('works if it is called directly from inside non async renderToDOM', async () => { document.location.search = '?id=component-one--a'; - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, @@ -912,7 +912,7 @@ describe('PreviewWeb', () => { componentOneExports.a.play.mockImplementationOnce(async () => gate); const renderToDOMCalled = new Promise((resolve) => { - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { resolve(null); }); }); @@ -1296,7 +1296,7 @@ describe('PreviewWeb', () => { const [gate, openGate] = createGate(); document.location.search = '?id=component-one--a'; - projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate); + projectAnnotations.renderToDOM.mockImplementation(async () => gate); await new PreviewWeb().initialize({ importFn, getProjectAnnotations }); await waitForRenderPhase('rendering'); @@ -1463,6 +1463,20 @@ describe('PreviewWeb', () => { expect(projectAnnotations.renderToDOM).not.toHaveBeenCalled(); }); + it('does NOT call renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + await createAndRenderPreview(); + + projectAnnotations.renderToDOM.mockClear(); + emitter.emit(SET_CURRENT_STORY, { + storyId: 'component-one--a', + viewMode: 'story', + }); + await waitForSetCurrentStory(); + + expect(teardownRenderToDOM).not.toHaveBeenCalled(); + }); + // For https://github.com/storybookjs/storybook/issues/17214 it('does NOT render a second time if preparing', async () => { document.location.search = '?id=component-one--a'; @@ -1510,6 +1524,20 @@ describe('PreviewWeb', () => { }); describe('when changing story in story viewMode', () => { + it('calls renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + await createAndRenderPreview(); + + projectAnnotations.renderToDOM.mockClear(); + emitter.emit(SET_CURRENT_STORY, { + storyId: 'component-one--b', + viewMode: 'story', + }); + await waitForSetCurrentStory(); + + expect(teardownRenderToDOM).toHaveBeenCalled(); + }); + it('updates URL', async () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); @@ -1645,7 +1673,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { throw error; }); @@ -1666,9 +1694,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = { title: 'title', description: 'description' }; - projectAnnotations.renderToDOM.mockImplementationOnce((context) => - context.showError(error) - ); + projectAnnotations.renderToDOM.mockImplementation((context) => context.showError(error)); mockChannel.emit.mockClear(); emitter.emit(SET_CURRENT_STORY, { @@ -1690,7 +1716,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce((context) => + projectAnnotations.renderToDOM.mockImplementation((context) => context.showException(error) ); @@ -1811,7 +1837,7 @@ describe('PreviewWeb', () => { const [gate, openGate] = createGate(); document.location.search = '?id=component-one--a'; - projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate); + projectAnnotations.renderToDOM.mockImplementation(async () => gate); await new PreviewWeb().initialize({ importFn, getProjectAnnotations }); await waitForRenderPhase('rendering'); @@ -1937,6 +1963,19 @@ describe('PreviewWeb', () => { }); describe('when changing from story viewMode to docs', () => { + it('calls renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + await createAndRenderPreview(); + + emitter.emit(SET_CURRENT_STORY, { + storyId: 'component-one--a', + viewMode: 'docs', + }); + await waitForSetCurrentStory(); + + expect(teardownRenderToDOM).toHaveBeenCalled(); + }); + it('updates URL', async () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); @@ -2199,7 +2238,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { throw error; }); @@ -2217,9 +2256,7 @@ describe('PreviewWeb', () => { it('renders error if the story calls showError', async () => { const error = { title: 'title', description: 'description' }; - projectAnnotations.renderToDOM.mockImplementationOnce((context) => - context.showError(error) - ); + projectAnnotations.renderToDOM.mockImplementation((context) => context.showError(error)); document.location.search = '?id=component-one--a&viewMode=docs'; const preview = await createAndRenderPreview(); @@ -2241,7 +2278,7 @@ describe('PreviewWeb', () => { it('renders exception if the story calls showException', async () => { const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce((context) => + projectAnnotations.renderToDOM.mockImplementation((context) => context.showException(error) ); @@ -2347,6 +2384,17 @@ describe('PreviewWeb', () => { : componentTwoExports; }); + it('calls renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + const preview = await createAndRenderPreview(); + mockChannel.emit.mockClear(); + + preview.onStoriesChanged({ importFn: newImportFn }); + await waitForRender(); + + expect(teardownRenderToDOM).toHaveBeenCalled(); + }); + it('does not emit STORY_UNCHANGED', async () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); @@ -2491,7 +2539,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce(() => { + projectAnnotations.renderToDOM.mockImplementation(() => { throw error; }); @@ -2508,9 +2556,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = { title: 'title', description: 'description' }; - projectAnnotations.renderToDOM.mockImplementationOnce((context) => - context.showError(error) - ); + projectAnnotations.renderToDOM.mockImplementation((context) => context.showError(error)); mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn: newImportFn }); @@ -2528,7 +2574,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const error = new Error('error'); - projectAnnotations.renderToDOM.mockImplementationOnce((context) => + projectAnnotations.renderToDOM.mockImplementation((context) => context.showException(error) ); @@ -2629,6 +2675,17 @@ describe('PreviewWeb', () => { : newComponentTwoExports; }); + it('does NOT call renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + const preview = await createAndRenderPreview(); + + mockChannel.emit.mockClear(); + preview.onStoriesChanged({ importFn: newImportFn }); + await waitForEvents([STORY_UNCHANGED]); + + expect(teardownRenderToDOM).not.toHaveBeenCalled(); + }); + it('emits STORY_UNCHANGED', async () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); @@ -2754,6 +2811,17 @@ describe('PreviewWeb', () => { }, }; + it('calls renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + const preview = await createAndRenderPreview(); + + mockChannel.emit.mockClear(); + preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex }); + await waitForEvents([STORY_MISSING]); + + expect(teardownRenderToDOM).toHaveBeenCalled(); + }); + it('renders loading error', async () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); @@ -2920,6 +2988,18 @@ describe('PreviewWeb', () => { }); }); + it('calls renderToDOMs teardown', async () => { + document.location.search = '?id=component-one--a'; + const preview = await createAndRenderPreview(); + + projectAnnotations.renderToDOM.mockClear(); + mockChannel.emit.mockClear(); + preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations }); + await waitForRender(); + + expect(teardownRenderToDOM).toHaveBeenCalled(); + }); + it('rerenders the current story with new global meta-generated context', async () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); diff --git a/lib/preview-web/src/StoryRender.ts b/lib/preview-web/src/StoryRender.ts index d0ede7cc1223..7bbb7f31f400 100644 --- a/lib/preview-web/src/StoryRender.ts +++ b/lib/preview-web/src/StoryRender.ts @@ -6,7 +6,13 @@ import { StoryContextForLoaders, StoryContext, } from '@storybook/csf'; -import { Story, RenderContext, StoryStore } from '@storybook/store'; +import { + Story, + RenderContext, + StoryStore, + RenderToDOM, + TeardownRenderToDOM, +} from '@storybook/store'; import { Channel } from '@storybook/addons'; import { STORY_RENDER_PHASE_CHANGED, STORY_RENDERED } from '@storybook/core-events'; @@ -62,13 +68,12 @@ export class StoryRender implements Render {}; + constructor( public channel: Channel, public store: StoryStore, - private renderToScreen: ( - renderContext: RenderContext, - canvasElement: HTMLElement - ) => void | Promise, + private renderToScreen: RenderToDOM, private callbacks: RenderContextCallbacks, public id: StoryId, public viewMode: ViewMode, @@ -190,9 +195,10 @@ export class StoryRender implements Render - this.renderToScreen(renderContext, this.canvasElement) - ); + await this.runPhase(abortSignal, 'rendering', async () => { + this.teardownRender = + (await this.renderToScreen(renderContext, this.canvasElement)) || (() => {}); + }); this.notYetRendered = false; if (abortSignal.aborted) return; @@ -241,7 +247,11 @@ export class StoryRender implements Render setTimeout(resolve, 0)); } diff --git a/lib/store/src/storySort.test.ts b/lib/store/src/storySort.test.ts index 50976f126bd5..8ffe07a3e2b9 100644 --- a/lib/store/src/storySort.test.ts +++ b/lib/store/src/storySort.test.ts @@ -124,4 +124,19 @@ describe('preview.storySort', () => { expect(sortFn(fixture.a_c, fixture.a_b)).toBeLessThan(0); expect(sortFn(fixture.a_b, fixture.a_c)).toBeGreaterThan(0); }); + + it('sorts according to the nested order array with parent wildcard', () => { + const sortFn = storySort({ + order: ['*', ['*', 'b', 'a']], + includeNames: true, + }); + + expect(sortFn(fixture.a_a, fixture.a_b)).toBeGreaterThan(0); + expect(sortFn(fixture.a_b, fixture.a_a)).toBeLessThan(0); + expect(sortFn(fixture.a_c, fixture.a_a)).toBeLessThan(0); + expect(sortFn(fixture.a_c, fixture.a_b)).toBeLessThan(0); + expect(sortFn(fixture.a_a, fixture.a_c)).toBeGreaterThan(0); + expect(sortFn(fixture.a_b, fixture.a_c)).toBeGreaterThan(0); + expect(sortFn(fixture.a_a, fixture.a_a)).toBe(0); + }); }); diff --git a/lib/store/src/storySort.ts b/lib/store/src/storySort.ts index ec3d01e3040a..b1d49bfb2865 100644 --- a/lib/store/src/storySort.ts +++ b/lib/store/src/storySort.ts @@ -79,7 +79,8 @@ export const storySort = } // If a nested array is provided for a name, use it for ordering. - const index = order.indexOf(nameA); + let index = order.indexOf(nameA); + if (index === -1) index = order.indexOf('*'); order = index !== -1 && Array.isArray(order[index + 1]) ? order[index + 1] : []; // We'll need to look at the next part of the name. diff --git a/lib/store/src/types.ts b/lib/store/src/types.ts index d52a0f2588e6..6271fab4cb5c 100644 --- a/lib/store/src/types.ts +++ b/lib/store/src/types.ts @@ -29,9 +29,17 @@ export type ModuleExports = Record; export type PromiseLike = Promise | SynchronousPromise; export type ModuleImportFn = (path: Path) => PromiseLike; +type MaybePromise = Promise | T; + +export type TeardownRenderToDOM = () => MaybePromise; +export type RenderToDOM = ( + context: RenderContext, + element: Element +) => MaybePromise; + export type WebProjectAnnotations = ProjectAnnotations & { - renderToDOM?: (context: RenderContext, element: Element) => Promise | void; + renderToDOM?: RenderToDOM; }; export type NormalizedProjectAnnotations = diff --git a/lib/ui/src/components/sidebar/Tree.tsx b/lib/ui/src/components/sidebar/Tree.tsx index 222df3e2bcf3..20887cae22f2 100644 --- a/lib/ui/src/components/sidebar/Tree.tsx +++ b/lib/ui/src/components/sidebar/Tree.tsx @@ -190,7 +190,6 @@ const Node = React.memo( data-ref-id={refId} data-item-id={item.id} data-nodetype="root" - aria-expanded={isExpanded} > ( event.preventDefault(); setExpanded({ ids: [item.id], value: !isExpanded }); }} + aria-expanded={isExpanded} > {item.renderLabel?.(item) || item.name} diff --git a/netlify.toml b/netlify.toml index b390f857e386..8dc12b5ad1e3 100644 --- a/netlify.toml +++ b/netlify.toml @@ -2,7 +2,7 @@ publish = "built-storybooks" command = "yarn bootstrap --core && yarn build-storybooks --all" [build.environment] - NODE_VERSION = "12" + NODE_VERSION = "14" YARN_VERSION = "1.22.10" DOTENV_DISPLAY_WARNING = "none" STORYBOOK_EXAMPLE_APP ="true" diff --git a/package.json b/package.json index 0713dc02c531..8695fe63253f 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,7 @@ "@storybook/store": "workspace:*", "@storybook/svelte": "workspace:*", "@storybook/telemetry": "workspace:*", - "@storybook/testing-library": "^0.0.7", + "@storybook/testing-library": "0.0.14-next.0", "@storybook/theming": "workspace:*", "@storybook/ui": "workspace:*", "@storybook/vue": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 342557e467ed..be9ddfd72d27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6681,7 +6681,7 @@ __metadata: "@storybook/csf": 0.0.2--canary.4566f4d.1 "@storybook/instrumenter": 6.5.0-rc.1 "@storybook/jest": ^0.0.5 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@storybook/theming": 6.5.0-rc.1 core-js: ^3.8.2 formik: ^2.2.9 @@ -7051,6 +7051,28 @@ __metadata: languageName: node linkType: hard +"@storybook/addons@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/addons@npm:6.5.9" + dependencies: + "@storybook/api": 6.5.9 + "@storybook/channels": 6.5.9 + "@storybook/client-logger": 6.5.9 + "@storybook/core-events": 6.5.9 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/router": 6.5.9 + "@storybook/theming": 6.5.9 + "@types/webpack-env": ^1.16.0 + core-js: ^3.8.2 + global: ^4.4.0 + regenerator-runtime: ^0.13.7 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 3ee3e61abc7bff6b481374597cc6717936685222b187d173462483d77d9b284fe5650e9764f7232ae80678e4718440d712f182c01c16887d53c77a1abe262616 + languageName: node + linkType: hard + "@storybook/angular@6.5.0-rc.1, @storybook/angular@workspace:*, @storybook/angular@workspace:app/angular": version: 0.0.0-use.local resolution: "@storybook/angular@workspace:app/angular" @@ -7200,6 +7222,34 @@ __metadata: languageName: node linkType: hard +"@storybook/api@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/api@npm:6.5.9" + dependencies: + "@storybook/channels": 6.5.9 + "@storybook/client-logger": 6.5.9 + "@storybook/core-events": 6.5.9 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/router": 6.5.9 + "@storybook/semver": ^7.3.2 + "@storybook/theming": 6.5.9 + core-js: ^3.8.2 + fast-deep-equal: ^3.1.3 + global: ^4.4.0 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + regenerator-runtime: ^0.13.7 + store2: ^2.12.0 + telejson: ^6.0.8 + ts-dedent: ^2.0.0 + 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 + checksum: 6f3aaed66c27715740397ff80a01fda1e363e75165c90cb5f50e4effc00e91b2d1f58b506d2279e83a905f794988e9aaaa75d5b7380c192c954f8c6520368d67 + languageName: node + linkType: hard + "@storybook/babel-plugin-require-context-hook@npm:1.0.1": version: 1.0.1 resolution: "@storybook/babel-plugin-require-context-hook@npm:1.0.1" @@ -7375,6 +7425,17 @@ __metadata: languageName: node linkType: hard +"@storybook/channels@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/channels@npm:6.5.9" + dependencies: + core-js: ^3.8.2 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + checksum: 3011663b754fe9028076b2a27573c6ca2040eb227918c315b9e6ea4d23298b1ac305e26aa4e89c02c9120ddd475d0f49d42bcb287b84cb37953c5f99606c3ed1 + languageName: node + linkType: hard + "@storybook/cli@6.5.0-rc.1, @storybook/cli@workspace:*, @storybook/cli@workspace:lib/cli": version: 0.0.0-use.local resolution: "@storybook/cli@workspace:lib/cli" @@ -7470,6 +7531,16 @@ __metadata: languageName: node linkType: hard +"@storybook/client-logger@npm:6.5.9, @storybook/client-logger@npm:^6.4.0": + version: 6.5.9 + resolution: "@storybook/client-logger@npm:6.5.9" + dependencies: + core-js: ^3.8.2 + global: ^4.4.0 + checksum: 764aacff6859c2cfe93f90498504e6628d8c7606490f1eec835639e21f177b10f0e93cad605dadf0ca6e08f6d5e62153597de6c80570ae65d76b4c71b6884e09 + languageName: node + linkType: hard + "@storybook/codemod@6.5.0-rc.1, @storybook/codemod@workspace:*, @storybook/codemod@workspace:lib/codemod": version: 0.0.0-use.local resolution: "@storybook/codemod@workspace:lib/codemod" @@ -7651,6 +7722,15 @@ __metadata: languageName: node linkType: hard +"@storybook/core-events@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/core-events@npm:6.5.9" + dependencies: + core-js: ^3.8.2 + checksum: 5d9eb651ef528330bebe9048eec61d4e3af29fabcf3cc8d7572a94f199e2220dfa738c19d65a761de5ec377d7933316af5eb2bfd0dc8c4027cd7dd57951552bd + languageName: node + linkType: hard + "@storybook/core-server@6.5.0-rc.1, @storybook/core-server@workspace:lib/core-server": version: 0.0.0-use.local resolution: "@storybook/core-server@workspace:lib/core-server" @@ -8026,6 +8106,19 @@ __metadata: languageName: node linkType: hard +"@storybook/instrumenter@npm:^6.4.0": + version: 6.5.9 + resolution: "@storybook/instrumenter@npm:6.5.9" + dependencies: + "@storybook/addons": 6.5.9 + "@storybook/client-logger": 6.5.9 + "@storybook/core-events": 6.5.9 + core-js: ^3.8.2 + global: ^4.4.0 + checksum: df6e535759540c09cb0addd65250121a10767ea7f43d6452417208eb09f565250f52c4417c707c964b61da063ee06d15c7aa3baaa86a0a585768fc94cdb8f31d + languageName: node + linkType: hard + "@storybook/jest@npm:^0.0.5": version: 0.0.5 resolution: "@storybook/jest@npm:0.0.5" @@ -8497,7 +8590,7 @@ __metadata: "@storybook/store": "workspace:*" "@storybook/svelte": "workspace:*" "@storybook/telemetry": "workspace:*" - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@storybook/theming": "workspace:*" "@storybook/ui": "workspace:*" "@storybook/vue": "workspace:*" @@ -8705,6 +8798,22 @@ __metadata: languageName: node linkType: hard +"@storybook/router@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/router@npm:6.5.9" + dependencies: + "@storybook/client-logger": 6.5.9 + core-js: ^3.8.2 + memoizerific: ^1.11.3 + qs: ^6.10.0 + regenerator-runtime: ^0.13.7 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 765977adbcaa1d06958489bd1316056c35f712f04c603a3848ed04dea3155f65369a085759913ccf19ffda3de41d429f455fbc330c3bcf7b3fdc65e9a3ddd320 + languageName: node + linkType: hard + "@storybook/semver@npm:^7.3.2": version: 7.3.2 resolution: "@storybook/semver@npm:7.3.2" @@ -8851,16 +8960,16 @@ __metadata: languageName: unknown linkType: soft -"@storybook/testing-library@npm:^0.0.7": - version: 0.0.7 - resolution: "@storybook/testing-library@npm:0.0.7" +"@storybook/testing-library@npm:0.0.14-next.0": + version: 0.0.14-next.0 + resolution: "@storybook/testing-library@npm:0.0.14-next.0" dependencies: - "@storybook/client-logger": 6.4.0-rc.5 - "@storybook/instrumenter": 6.4.0-rc.5 + "@storybook/client-logger": ^6.4.0 + "@storybook/instrumenter": ^6.4.0 "@testing-library/dom": ^8.3.0 "@testing-library/user-event": ^13.2.1 ts-dedent: ^2.2.0 - checksum: 6be4b2d418195417cd0a04e5a4f2b71a93364cb88780084714a0553c39e6b38943458511b25b101c830b332783afec98a40eefcdc663dca3f34e8f48609a4670 + checksum: fd10ebddd305743f4388ad939b90fed155b6c3a755e96a73f72d38d9afe2546a22be0c9a5d83b8b6d91742dd7be5d2e7dfcbbd630b2fa97e4ef7dde00f0824b0 languageName: node linkType: hard @@ -8924,6 +9033,21 @@ __metadata: languageName: node linkType: hard +"@storybook/theming@npm:6.5.9": + version: 6.5.9 + resolution: "@storybook/theming@npm:6.5.9" + dependencies: + "@storybook/client-logger": 6.5.9 + core-js: ^3.8.2 + memoizerific: ^1.11.3 + regenerator-runtime: ^0.13.7 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 28b2626ab2ef4396d3e8d0fad651bf13b323318028e7b01a99c9b999f368655d7aa78dd8154396753828746d934cfbaee1575c890307893d6a3cca9655c9a60e + languageName: node + linkType: hard + "@storybook/ui@6.5.0-rc.1, @storybook/ui@workspace:*, @storybook/ui@workspace:lib/ui": version: 0.0.0-use.local resolution: "@storybook/ui@workspace:lib/ui" @@ -12959,7 +13083,7 @@ __metadata: "@storybook/babel-plugin-require-context-hook": 1.0.1 "@storybook/jest": ^0.0.5 "@storybook/source-loader": 6.5.0-rc.1 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@types/core-js": ^2.5.4 "@types/jest": ^26.0.16 "@types/node": ^14.14.20 || ^16.0.0 @@ -34018,7 +34142,7 @@ __metadata: "@storybook/react": 6.5.0-rc.1 "@storybook/router": 6.5.0-rc.1 "@storybook/source-loader": 6.5.0-rc.1 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@storybook/theming": 6.5.0-rc.1 "@testing-library/dom": ^7.31.2 "@testing-library/user-event": ^13.1.9 @@ -42980,7 +43104,7 @@ __metadata: "@storybook/jest": ^0.0.5 "@storybook/source-loader": 6.5.0-rc.1 "@storybook/svelte": 6.5.0-rc.1 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 global: ^4.4.0 svelte-jester: 1.3.0 svelte-preprocess: 4.6.8 @@ -45921,7 +46045,7 @@ __metadata: "@storybook/addon-links": 6.5.0-rc.1 "@storybook/addon-storyshots": 6.5.0-rc.1 "@storybook/jest": ^0.0.5 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@storybook/vue3": 6.5.0-rc.1 "@vue/cli-plugin-babel": ~4.5.0 "@vue/cli-plugin-typescript": ~4.5.0 @@ -46018,7 +46142,7 @@ __metadata: "@storybook/addons": 6.5.0-rc.1 "@storybook/jest": ^0.0.5 "@storybook/source-loader": 6.5.0-rc.1 - "@storybook/testing-library": ^0.0.7 + "@storybook/testing-library": 0.0.14-next.0 "@storybook/vue": 6.5.0-rc.1 "@vue/babel-preset-jsx": ^1.2.4 babel-loader: ^8.0.0