diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a0689881ff9..7fcd6003f4e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 10.1.6 + +- Manager: Do not display non-existing shortcuts in the settings page - [#32711](https://github.com/storybookjs/storybook/pull/32711), thanks @DKER2! +- Preview: Enforce inert body if manager is focus-trapped - [#33186](https://github.com/storybookjs/storybook/pull/33186), thanks @Sidnioulz! +- Telemetry: Await pending operations in getLastEvents to prevent race conditions - [#33285](https://github.com/storybookjs/storybook/pull/33285), thanks @valentinpalkovic! +- UI: Fix keyboard navigation bug for "reset" option in `Select` - [#33268](https://github.com/storybookjs/storybook/pull/33268), thanks @Sidnioulz! + ## 10.1.5 - Addon-Vitest: Isolate error reasons during postinstall - [#33295](https://github.com/storybookjs/storybook/pull/33295), thanks @valentinpalkovic! diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 8266aa3fd22e..a0f656be416f 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,12 @@ +## 10.2.0-alpha.6 + +- Controls: Fix displaying as object instead of select for optional union types - [#33200](https://github.com/storybookjs/storybook/pull/33200), thanks @tanujbhaud! +- Controls: Force object control JSON mode to reset - [#33330](https://github.com/storybookjs/storybook/pull/33330), thanks @Sidnioulz! +- Docs-Blocks: Fix broken tooltip in ArgValue details - [#33264](https://github.com/storybookjs/storybook/pull/33264), thanks @Sidnioulz! +- Manager: Ensure reset item only appears in globals toolbar when specified - [#33276](https://github.com/storybookjs/storybook/pull/33276), thanks @mrginglymus! +- Nextjs-Vite: Install `vite` during migration if not installed yet - [#33316](https://github.com/storybookjs/storybook/pull/33316), thanks @ghengeveld! +- UI: Make vertical alignment of TestStatusIcon more robust - [#33305](https://github.com/storybookjs/storybook/pull/33305), thanks @Sidnioulz! + ## 10.2.0-alpha.5 - Addon-Vitest: Added timeout for fetching localhost 6006 during global setup. - [#33232](https://github.com/storybookjs/storybook/pull/33232), thanks @snippy4! diff --git a/MIGRATION.md b/MIGRATION.md index ba81b2731579..adb41e1c2f99 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -204,17 +204,17 @@ - [Tab addons cannot manually route, Tool addons can filter their visibility via tabId](#tab-addons-cannot-manually-route-tool-addons-can-filter-their-visibility-via-tabid) - [Removed `config` preset](#removed-config-preset-1) - [From version 7.5.0 to 7.6.0](#from-version-750-to-760) - - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) - - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) - - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) - - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) - - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) + - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) + - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) + - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) + - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) + - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) - [From version 7.4.0 to 7.5.0](#from-version-740-to-750) - - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) - - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) + - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) + - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) - [From version 7.0.0 to 7.2.0](#from-version-700-to-720) - - [Addon API is more type-strict](#addon-api-is-more-type-strict) - - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) + - [Addon API is more type-strict](#addon-api-is-more-type-strict) + - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) - [From version 6.5.x to 7.0.0](#from-version-65x-to-700) - [7.0 breaking changes](#70-breaking-changes) - [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below) @@ -240,7 +240,7 @@ - [Deploying build artifacts](#deploying-build-artifacts) - [Dropped support for file URLs](#dropped-support-for-file-urls) - [Serving with nginx](#serving-with-nginx) - - [Ignore story files from node\_modules](#ignore-story-files-from-node_modules) + - [Ignore story files from node_modules](#ignore-story-files-from-node_modules) - [7.0 Core changes](#70-core-changes) - [7.0 feature flags removed](#70-feature-flags-removed) - [Story context is prepared before for supporting fine grained updates](#story-context-is-prepared-before-for-supporting-fine-grained-updates) @@ -254,7 +254,7 @@ - [Addon-interactions: Interactions debugger is now default](#addon-interactions-interactions-debugger-is-now-default) - [7.0 Vite changes](#70-vite-changes) - [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically) - - [Vite cache moved to node\_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) + - [Vite cache moved to node_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) - [7.0 Webpack changes](#70-webpack-changes) - [Webpack4 support discontinued](#webpack4-support-discontinued) - [Babel mode v7 exclusively](#babel-mode-v7-exclusively) @@ -305,7 +305,7 @@ - [Dropped addon-docs manual babel configuration](#dropped-addon-docs-manual-babel-configuration) - [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration) - [Autoplay in docs](#autoplay-in-docs) - - [Removed STORYBOOK\_REACT\_CLASSES global](#removed-storybook_react_classes-global) + - [Removed STORYBOOK_REACT_CLASSES global](#removed-storybook_react_classes-global) - [7.0 Deprecations and default changes](#70-deprecations-and-default-changes) - [storyStoreV7 enabled by default](#storystorev7-enabled-by-default) - [`Story` type deprecated](#story-type-deprecated) @@ -518,7 +518,6 @@ - [Packages renaming](#packages-renaming) - [Deprecated embedded addons](#deprecated-embedded-addons) - ## From version 10.0.0 to 10.1.0 ### API and Component Changes @@ -526,6 +525,7 @@ #### Button Component API Changes ##### Added: ariaLabel + The Button component now has an `ariaLabel` prop, to ensure that Storybook UI code is accessible to screenreader users. The prop will become mandatory in Storybook 11. When buttons have text content as children, and when that text content does not rely on visual context to be understood, you may pass `false` to the `ariaLabel` prop to indicate that an ARIA label is not necessary. @@ -557,15 +557,16 @@ IconButton will be removed in future versions. The `Bar` component's internal layout has changed, to fix a height bug in scrollable bars. It now applies flex positioning and applies a default item gap, that can be controlled with the `innerStyle` prop. You may see slight changes in default padding as a result of this change. ##### Added: innerStyle + When `scrollable` is set to `true`, `Bar` now adds an inner container that is used to ensure the scrollbar size does not impact the height of the bar. This inner container displays as 'flex' and has the following default style: ```css - width: 100%; - min-height: 40; - display: flex; - align-items: center; - gap: 6px; - padding-inline: 6px; +width: 100%; +min-height: 40; +display: flex; +align-items: center; +gap: 6px; +padding-inline: 6px; ``` The inner container's style can be overridden by passing CSS properties to `innerStyle`. @@ -597,18 +598,23 @@ The `TabBar` component, a styled bar used inside `Tabs` and not intended to be p #### Modal Component API Changes ##### Deprecated: onInteractOutside + The `onInteractOutside` prop is deprecated in favor of `dismissOnClickOutside`, because it was only used to close the modal when clicking outside. Use `dismissOnClickOutside` to control whether clicking outside the modal should close it or not. ##### Deprecated: onEscapeKeyDown + The `onEscapeKeyDown` prop is deprecated in favor of `dismissOnEscape`, because it was only used to close the modal when pressing Escape. Use `dismissOnEscape` to control whether pressing Escape should close it or not. ##### Added: `ariaLabel` + Modal elements must have a title to be accessible. Set that title through the `ariaLabel` prop. It will become mandatory in Storybook 11. ##### Renamed: Modal.Dialog.Close and Modal.CloseButton + The `Modal.Dialog.Close` component and `Modal.CloseButton` components are replaced by `Modal.Close` for consistency with other components. Those names are deprecated and will be removed in Storybook 11. You may call `` for a default close button, or `...` to wrap your own custom button. The `Modal.Close` component no longer requires an `onClick` handler to close the modal. It will automatically close the modal when clicked. If you need to perform additional actions when the close button is clicked, you can still provide an `onClick` handler, and it will be called in addition to closing the modal. + #### ListItem, TooltipLinkList and TooltipMessage are deprecated The ListItem and TooltipLinkList components were used in Storybook to make menus, and TooltipMessage to make message popovers. However, WithTooltip does not support keyboard interactions, so these components were not accessible. @@ -626,34 +632,41 @@ PopoverProvider is based on react-aria. It must have a single child that acts as The WithTooltip component has been reimplemented from the ground up, under the new name `TooltipProvider`. The new implementation will replace `WithTooltip` entirely in Storybook 11. Below is a summary of the changes between both APIs, which will take full effect in Storybook 11. ##### Removed: trigger + The `trigger` prop was removed to enforce better accessibility compliance. WithTooltip must not be triggered on click, as it is not reachable by keyboard. Buttons that open a popover, menu or select must use appropriate components instead. #### Added: triggerOnFocusOnly + The `triggerOnFocusOnly` prop was added. When set, tooltips will only show on focus. Use this to provide keyboard navigation hints to keyboard users. Do not use it for other purposes. #### Renamed: startOpen + The `startOpen` prop was renamed `defaultVisible` to match naming in other components that expose both controlled and uncontrolled visibility. The `startOpen` prop will be removed in future versions. #### Removed: svg, strategy, withArrows, mutationObserverOptions -These prop were not used inside Storybook and have been removed. + +These props were not used inside Storybook and have been removed. #### Removed: hasChrome + The `hasChrome` prop was removed because it should be handled by the tooltip being shown instead. Popover and Tooltip both have a `hasChrome` prop. TooltipNote never needs this prop and does not have it. #### Removed: closeOnTriggerHidden, followCursor, closeOnOutsideClick -The `closeOnTriggerHidden`, `followCursor` and `closeOnOutsideClick` prop has been removed. WithTooltip will now authoritatively decide when and where to show or hide its tooltip. It will always close on clicks outside the tooltip, because tooltips should never be modal. + +The `closeOnTriggerHidden`, `followCursor` and `closeOnOutsideClick` props have been removed. WithTooltip will now authoritatively decide when and where to show or hide its tooltip. It will always close on clicks outside the tooltip, because tooltips should never be modal. #### Removed: interactive -Thed `interactive` prop has been removed as it does not align with our vision for accessible components with a well-defined role. Use PopoverProvider instead of WithTooltip to show interactive overlays. + +The `interactive` prop has been removed as it does not align with our vision for accessible components with a well-defined role. Use PopoverProvider instead of WithTooltip to show interactive overlays. ##### Other changes + The underlying implementation was switched from Popper.js to react-aria. Due to these changes, WithTooltip must now have a single child that has a focusable role and that can receive React refs. Wrap your trigger component in `forwardRef` if you notice placement issues for your tooltip. #### WithTooltipPure and WithTooltipState are deprecated Instead, use `WithTooltipNew` in Storybook 10, or `WithTooltip` in Storybook 11 or newer. For a controlled tooltip, use the `onVisibleChange` and `visible` props. For an uncontrolled tooltip with a default open state, use the `defaultVisible` prop. - ## From version 9.x to 10.0.0 ### Core Changes @@ -666,7 +679,7 @@ In Storybook 9 it was possible to do reference local addons by a relative path, // main.ts export default { - addons: ["./my-addon.ts"], + addons: ['./my-addon.ts'], }; ``` @@ -676,7 +689,7 @@ In Storybook 10 this relative path, should be fully resolved, like so: // main.ts export default { - addons: [import.meta.resolve("./my-addon.ts")], + addons: [import.meta.resolve('./my-addon.ts')], }; ``` @@ -688,7 +701,7 @@ For example: // main.ts export default { managerEntries(entry = []) { - return [...entry, require.resolve("./iframe.js")]; + return [...entry, require.resolve('./iframe.js')]; }, }; ``` @@ -697,11 +710,11 @@ Would become: ```ts // main.ts -import { fileURLToPath } from "node:url"; +import { fileURLToPath } from 'node:url'; export default { managerEntries(entry = []) { - return [...entry, fileURLToPath(import.meta.resolve("./iframe.js"))]; + return [...entry, fileURLToPath(import.meta.resolve('./iframe.js'))]; }, }; ``` @@ -714,9 +727,9 @@ Thus CJS constants (`require`, `__dirname`, `__filename`) will not be defined. You can define these constants yourself, like so: ```ts -import { createRequire } from "node:module"; -import { dirname } from "node:path"; -import { fileURLToPath } from "node:url"; +import { createRequire } from 'node:module'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -728,12 +741,14 @@ A `main.ts` file that's CJS is no longer supported. The same applies to any cust Additionally, **extensionless relative imports are no longer supported** in JavaScript-based configuration files (`.storybook/main.js`) and custom presets. All relative imports must now include explicit file extensions. **Before (no longer works):** + ```js // .storybook/main.js import myPreset from './my-file'; ``` **After:** + ```js // .storybook/main.js import myPreset from './my-file.js'; @@ -742,6 +757,7 @@ import myPreset from './my-file.js'; This change aligns with Node.js ESM requirements, where relative imports must specify the full file extension. This applies to `.storybook/main.js` and any custom preset files. While TypeScript-based files (`.storybook/main.ts`) will continue to work with extensionless imports for now through automatic resolution, we recommend migrating to explicit extensions for consistency and better compatibility. **Recommended approach for all files:** + - Use `.js` for JavaScript files - Use `.mjs` for ES modules - Use `.ts` for TypeScript files @@ -799,8 +815,8 @@ export const core = { ``` #### Removed x-only builtin tags + During development of Storybook [Tags](https://storybook.js.org/docs/writing-stories/tags), we created `dev-only`, `docs-only`, and `test-only` built-in tags. These tags were never documented and superseded by the currently-documented `dev`, `autodocs`, and `test` tags which provide more precise control. The outdated `x-only` tags are removed in 10.0. -During development of Storybook [Tags](https://storybook.js.org/docs/writing-stories/tags), we created `dev-only`, `docs-only`, and `test-only` built-in tags. These tags were never documented and superceded by the currently-documented `dev`, `autodocs`, and `test` tags which provide more precise control. The outdated `x-only` tags are removed in 10.0. ## From version 8.x to 9.0.0 @@ -916,7 +932,7 @@ If you're using framework-specific Vite plugins, ensure they are compatible with - `@sveltejs/vite-plugin-svelte` - etc. -For more information on upgrading to Vite 5, see the [Vite Migration Guide](https://vitejs.dev/guide/migration). +For more information on upgrading to Vite 5, see the [Vite Migration Guide](https://v6.vite.dev/guide/migration). ##### TypeScript < 4.9 @@ -1298,12 +1314,12 @@ export default { docs: { source: { transform: async (source) => { - const prettier = await import("prettier/standalone"); - const prettierPluginBabel = await import("prettier/plugins/babel"); - const prettierPluginEstree = await import("prettier/plugins/estree"); + const prettier = await import('prettier/standalone'); + const prettierPluginBabel = await import('prettier/plugins/babel'); + const prettierPluginEstree = await import('prettier/plugins/estree'); return prettier.format(source, { - parser: "babel", + parser: 'babel', plugins: [prettierPluginBabel, prettierPluginEstree], }); }, @@ -1322,7 +1338,7 @@ export const MyStory = { parameters: { docs: { source: { - format: "html", + format: 'html', }, }, }, @@ -1496,7 +1512,7 @@ For all affected frameworks, update your configuration to use the Vite builder: ```tsx export default { framework: { - name: "@storybook/[framework]-vite", // replace [framework] with preact, vue3, or web-components + name: '@storybook/[framework]-vite', // replace [framework] with preact, vue3, or web-components options: {}, }, // ... other configurations @@ -1595,7 +1611,7 @@ Previously, once you made changes to a component's props, the controls and args const config = { // ... typescript: { - reactDocgen: "react-docgen-typescript", + reactDocgen: 'react-docgen-typescript', reactDocgenTypescriptOptions: { EXPERIMENTAL_useWatchProgram: true, }, @@ -1842,8 +1858,8 @@ export default { In order to properly mock the `next/router`, `next/header`, `next/navigation` and `next/cache` APIs, the `@storybook/nextjs` framework includes internal Webpack aliases to those modules. If you use portable stories in your Jest tests, you should set the aliases in your Jest config files `moduleNameMapper` property using the `getPackageAliases` helper from `@storybook/nextjs/export-mocks`: ```js -const nextJest = require("next/jest.js"); -const { getPackageAliases } = require("@storybook/nextjs/export-mocks"); +const nextJest = require('next/jest.js'); +const { getPackageAliases } = require('@storybook/nextjs/export-mocks'); const createJestConfig = nextJest(); const customJestConfig = { moduleNameMapper: { @@ -1872,7 +1888,7 @@ Starting in 8.1, to generate autodocs for every component (`docs.autodocs = true ```js // .storybook/preview.js export default { - tags: ["autodocs"], + tags: ['autodocs'], }; ``` @@ -1882,7 +1898,7 @@ Tags cascade, so setting `'autodocs'` at the project level automatically propaga // Button.stories.ts export default { component: Button, - tags: ["!autodocs"], + tags: ['!autodocs'], }; ``` @@ -1915,12 +1931,8 @@ It still accepts being passed `children`. When passing project annotations overrides via `composeStory` such as: ```tsx -const projectAnnotationOverrides = { parameters: { foo: "bar" } }; -const Primary = composeStory( - stories.Primary, - stories, - projectAnnotationOverrides -); +const projectAnnotationOverrides = { parameters: { foo: 'bar' } }; +const Primary = composeStory(stories.Primary, stories, projectAnnotationOverrides); ``` they are now merged with the annotations passed via `setProjectAnnotations` rather than completely overwriting them. This was seen as a bug and it's now fixed. If you have a use case where you really need this, please open an issue to elaborate. @@ -1986,12 +1998,12 @@ The UI added to the manager via addons is now rendered with React 18. Example: ```tsx -import { addons, types } from "@storybook/manager-api"; +import { addons, types } from '@storybook/manager-api'; -addons.register("my-addon", () => { - addons.add("my-addon/panel", { +addons.register('my-addon', () => { + addons.add('my-addon/panel', { type: types.PANEL, - title: "My Addon", + title: 'My Addon', // This will be called as a JSX element by react 18 render: ({ active }) => (active ?
Hello World
: null), }); @@ -2043,8 +2055,8 @@ In Storybook 8 those plugins have to be added explicitly in the user's `vite.con #### For React: ```ts -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; export default defineConfig({ plugins: [react()], @@ -2054,8 +2066,8 @@ export default defineConfig({ #### For Vue: ```ts -import { defineConfig } from "vite"; -import vue from "@vitejs/plugin-vue"; +import vue from '@vitejs/plugin-vue'; +import { defineConfig } from 'vite'; export default defineConfig({ plugins: [vue()], @@ -2065,8 +2077,8 @@ export default defineConfig({ #### For Svelte (without Sveltekit): ```ts -import { defineConfig } from "vite"; -import { svelte } from "@sveltejs/vite-plugin-svelte"; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import { defineConfig } from 'vite'; export default defineConfig({ plugins: [svelte()], @@ -2076,8 +2088,8 @@ export default defineConfig({ #### For Preact: ```ts -import { defineConfig } from "vite"; -import preact from "@preact/preset-vite"; +import preact from '@preact/preset-vite'; +import { defineConfig } from 'vite'; export default defineConfig({ plugins: [preact()], @@ -2087,8 +2099,8 @@ export default defineConfig({ #### For Solid: ```ts -import { defineConfig } from "vite"; -import solid from "vite-plugin-solid"; +import { defineConfig } from 'vite'; +import solid from 'vite-plugin-solid'; export default defineConfig({ plugins: [solid()], @@ -2098,8 +2110,8 @@ export default defineConfig({ #### For Qwik: ```ts -import { defineConfig } from "vite"; -import qwik from "vite-plugin-qwik"; +import { defineConfig } from 'vite'; +import qwik from 'vite-plugin-qwik'; export default defineConfig({ plugins: [qwik()], @@ -2129,7 +2141,7 @@ export default { export const ButtonClick = { play: async ({ args, canvasElement }) => { - await userEvent.click(within(canvasElement).getByRole("button")); + await userEvent.click(within(canvasElement).getByRole('button')); // args.onClick is a jest spy in 7.0 await expect(args.onClick).toHaveBeenCalled(); }, @@ -2139,7 +2151,7 @@ export const ButtonClick = { In Storybook 8 this feature is removed, and spies have to added explicitly: ```ts -import { fn } from "@storybook/test"; +import { fn } from '@storybook/test'; export default { component: Button, @@ -2150,7 +2162,7 @@ export default { export const ButtonClick = { play: async ({ args, canvasElement }) => { - await userEvent.click(within(canvasElement).getByRole("button")); + await userEvent.click(within(canvasElement).getByRole('button')); await expect(args.onClick).toHaveBeenCalled(); }, }; @@ -2173,14 +2185,22 @@ Storybook now uses MDX3 under the hood. This change contains many improvements a #### Dropping support for \*.stories.mdx (CSF in MDX) format and MDX1 support -In Storybook 7, we deprecated the ability of using MDX both for documentation and for defining stories in the same .stories.mdx file. It is now removed, and Storybook won't support .stories.mdx files anymore. We provide migration scripts to help you onto the new format. +In Storybook 7, we deprecated the ability to use MDX for both documentation and story definition in the same .stories.mdx file. It is now removed, and Storybook won't support `.stories.mdx` files anymore. We provide migration scripts to help you onto the new format. To migrate your `.stories.mdx` files to the new format, you can run the following command: + +```sh +# Convert stories in MDX to CSF +npx storybook@latest migrate mdx-to-csf --glob "src/**/*.stories.mdx" +``` + +> To ensure a smooth migration, you'll also need to: +> +> - Update your stories glob in your `.storybook/main.js` configuration to include the newly created `.mdx` and `.stories.js|ts` files. +> - Manually remove the stories from the original `.stories.mdx` files, as by default the codemod won't delete them. If you were using the [legacy MDX1 format](#legacy-mdx1-support), you will have to remove the `legacyMdx1` main.js feature flag and the `@storybook/mdx1-csf` package. Alongside with this change, the `jsxOptions` configuration was removed as it is not used anymore. -[More info here](https://storybook.js.org/docs/migration-guide#storiesmdx-to-mdxcsf). - #### Dropping support for id, name and story in Story block Referencing stories by `id`, `name` or `story` in the Story block is not possible anymore. [More info here](#story-block). @@ -2290,11 +2310,11 @@ In Storybook 7, the file name `path/to/foo.bar.stories.js` would result in the [ ```js export default { - title: "path/to/foo", + title: 'path/to/foo', }; ``` -Alternatively, if you need to achieve a different behavior for a large number of files, you can provide a [custom indexer](https://storybook.js.org/docs/7.0/vue/configure/sidebar-and-urls#processing-custom-titles) to generate the titles dynamically. +Alternatively, if you need to achieve a different behavior for a large number of files, you can provide a [custom indexer](https://storybook.js.org/docs/8/configure/user-interface/sidebar-and-urls#story-index) to generate the titles dynamically. #### Storyshots has been removed @@ -2319,7 +2339,7 @@ Please check the [migration guide](https://storybook.js.org/docs/writing-tests/s #### UI layout state has changed shape -In Storybook 7 it was possible to use `addons.setConfig({...});` to configure Storybook UI features and behavior as documented [here (v7)](https://storybook.js.org/docs/7.3/react/configure/features-and-behavior), [(latest)](https://storybook.js.org/docs/react/configure/features-and-behavior). The state and API for the UI layout has changed: +In Storybook 7 it was possible to use `addons.setConfig({...});` to configure Storybook UI features and behavior as documented [here (v7)](https://github.com/storybookjs/storybook/blob/release-7-3/docs/configure/features-and-behavior.md), [(latest)](https://storybook.js.org/docs/react/configure/features-and-behavior). The state and API for the UI layout has changed: - `showNav: boolean` is now `navSize: number`, where the number represents the size of the sidebar in pixels. - `showPanel: boolean` is now split into `bottomPanelHeight: number` and `rightPanelWidth: number`, where the numbers represents the size of the panel in pixels. @@ -2386,7 +2406,7 @@ We feel `react-docgen` is the right tradeoff for most React projects. However, i ```js export default { typescript: { - reactDocgen: "react-docgen-typescript", + reactDocgen: 'react-docgen-typescript', }, }; ``` @@ -2619,7 +2639,7 @@ import { setProjectAnnotations } from `@storybook/react`. The `StorybookViteConfig` type is now removed in favor of `StorybookConfig`: ```ts -import type { StorybookConfig } from "@storybook/react-vite"; +import type { StorybookConfig } from '@storybook/react-vite'; ``` #### props from WithTooltipComponent from @storybook/components @@ -2633,7 +2653,7 @@ The deprecated properties `tooltipShown`, `closeOnClick`, and `onVisibilityChang onVisibilityChange // becomes onVisibleChange > ... - +; ``` #### LinkTo direct import from addon-links @@ -2642,10 +2662,10 @@ The `LinkTo` (React component) direct import from `@storybook/addon-links` is no ```ts // before -import LinkTo from "@storybook/addon-links"; +import LinkTo from '@storybook/addon-links'; // after -import LinkTo from "@storybook/addon-links/react"; +import LinkTo from '@storybook/addon-links/react'; ``` #### DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta TypeScript types @@ -2670,7 +2690,7 @@ export const Component = () => { const someHandler = () => { // Old method: api.navigateToSettingsPage('/settings/about'); - api.changeSettingsTab("about"); // the /settings path is not necessary anymore + api.changeSettingsTab('about'); // the /settings path is not necessary anymore }; // ... @@ -2710,11 +2730,8 @@ Additionally, given that CSF in MDX is not supported anymore, the following prop The `collapseAll` and `expandAll` APIs (possibly used by addons) are now removed. Please emit events for these actions instead: ```ts -import { - STORIES_COLLAPSE_ALL, - STORIES_EXPAND_ALL, -} from "@storybook/core-events"; -import { useStorybookApi } from "@storybook/manager-api"; +import { STORIES_COLLAPSE_ALL, STORIES_EXPAND_ALL } from '@storybook/core-events'; +import { useStorybookApi } from '@storybook/manager-api'; const api = useStorybookApi(); api.collapseAll(); // becomes api.emit(STORIES_COLLAPSE_ALL) @@ -2775,12 +2792,12 @@ Instead storybook will automatically show the addon's rendered content when the Example: ```tsx -import { addons, types } from "@storybook/manager-api"; +import { addons, types } from '@storybook/manager-api'; -addons.register("my-addon", () => { - addons.add("my-addon/tab", { +addons.register('my-addon', () => { + addons.add('my-addon/tab', { type: types.TAB, - title: "My Addon", + title: 'My Addon', render: () =>
Hello World
, }); }); @@ -2794,13 +2811,13 @@ When the canvas is shown, the `tabId` will be set to `undefined`. Example: ```tsx -import { addons, types } from "@storybook/manager-api"; +import { addons, types } from '@storybook/manager-api'; -addons.register("my-addon", () => { - addons.add("my-addon/tool", { +addons.register('my-addon', () => { + addons.add('my-addon/tool', { type: types.TOOL, - title: "My Addon", - match: ({ tabId }) => tabId === "my-addon/tab", + title: 'My Addon', + match: ({ tabId }) => tabId === 'my-addon/tab', render: () =>
👀
, }); }); @@ -2840,7 +2857,7 @@ export default { export const ButtonClick = { play: async ({ args, canvasElement }) => { - await userEvent.click(within(canvasElement).getByRole("button")); + await userEvent.click(within(canvasElement).getByRole('button')); // args.onClick is a jest spy in 7.0 await expect(args.onClick).toHaveBeenCalled(); }, @@ -2850,7 +2867,7 @@ export const ButtonClick = { In Storybook 8 this feature will be removed, and spies have to added explicitly: ```ts -import { fn } from "@storybook/test"; +import { fn } from '@storybook/test'; export default { component: Button, @@ -2861,7 +2878,7 @@ export default { export const ButtonClick = { play: async ({ args, canvasElement }) => { - await userEvent.click(within(canvasElement).getByRole("button")); + await userEvent.click(within(canvasElement).getByRole('button')); await expect(args.onClick).toHaveBeenCalled(); }, }; @@ -2897,9 +2914,8 @@ As of Storybook 7.6.0 the list of globalized packages can be imported like this: ```ts // tsup.config.ts - -import { globalPackages as globalManagerPackages } from "@storybook/manager/globals"; -import { globalPackages as globalPreviewPackages } from "@storybook/preview/globals"; +import { globalPackages as globalManagerPackages } from '@storybook/manager/globals'; +import { globalPackages as globalPreviewPackages } from '@storybook/preview/globals'; const allGlobalPackages = [...globalManagerPackages, ...globalPreviewPackages]; ``` @@ -2984,12 +3000,12 @@ The `type` property is now a required field, and the `id` property should not be Here's a correct example: ```tsx -import { addons, types } from "@storybook/manager-api"; +import { addons, types } from '@storybook/manager-api'; -addons.register("my-addon", () => { - addons.add("my-addon/panel", { +addons.register('my-addon', () => { + addons.add('my-addon/panel', { type: types.PANEL, - title: "My Addon", + title: 'My Addon', render: ({ active }) => (active ?
Hello World
: null), }); }); @@ -3029,7 +3045,7 @@ If your `preview.js` file looks like this: ```js export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, }; ``` @@ -3038,7 +3054,7 @@ Please migrate it to use a default export instead: ```js const preview = { parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, }, }; export default preview; @@ -3049,11 +3065,11 @@ Additionally, we introduced typings for that default export (Preview), so you ca The `Preview` type will come from the Storybook package for the **renderer** you are using. For example, if you are using Angular, you will import it from `@storybook/angular`, or if you're using Vue3, you will import it from `@storybook/vue3`: ```ts -import { Preview } from "@storybook/react"; +import { Preview } from '@storybook/react'; const preview: Preview = { parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, }, }; export default preview; @@ -3062,10 +3078,10 @@ export default preview; In JavaScript projects using `preview.js`, it's also possible to use the `Preview` type (for autocompletion, not type safety), via the JSDoc @type tag: ```js -/** @type { import('@storybook/react').Preview } */ +/** @type {import('@storybook/react').Preview} */ const preview = { parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, }, }; export default preview; @@ -3079,33 +3095,24 @@ If your main.js file looks like this: ```js module.exports = { - stories: [ - "../stories/**/*.stories.mdx", - "../stories/**/*.stories.@(js|jsx|ts|tsx)", - ], - framework: { name: "@storybook/react-vite" }, + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, }; ``` Or like this: ```js -export const stories = [ - "../stories/**/*.stories.mdx", - "../stories/**/*.stories.@(js|jsx|ts|tsx)", -]; -export const framework = { name: "@storybook/react-vite" }; +export const stories = ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)']; +export const framework = { name: '@storybook/react-vite' }; ``` Please migrate it to use a default export instead: ```js const config = { - stories: [ - "../stories/**/*.stories.mdx", - "../stories/**/*.stories.@(js|jsx|ts|tsx)", - ], - framework: { name: "@storybook/react-vite" }, + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, }; export default config; ``` @@ -3115,14 +3122,11 @@ Additionally, we introduced typings for that default export (StorybookConfig), s The `StorybookConfig` type will come from the Storybook package for the **framework** you are using, which relates to the package in the "framework" field you have in your main.ts file. For example, if you are using React Vite, you will import it from `@storybook/react-vite`: ```ts -import { StorybookConfig } from "@storybook/react-vite"; +import { StorybookConfig } from '@storybook/react-vite'; const config: StorybookConfig = { - stories: [ - "../stories/**/*.stories.mdx", - "../stories/**/*.stories.@(js|jsx|ts|tsx)", - ], - framework: { name: "@storybook/react-vite" }, + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, }; export default config; ``` @@ -3130,13 +3134,10 @@ export default config; In JavaScript projects using `main.js`, it's also possible to use the `StorybookConfig` type (for autocompletion, not type safety), via the JSDoc @type tag: ```ts -/** @type { import('@storybook/react-vite').StorybookConfig } */ +/** @type {import('@storybook/react-vite').StorybookConfig} */ const config = { - stories: [ - "../stories/**/*.stories.mdx", - "../stories/**/*.stories.@(js|jsx|ts|tsx)", - ], - framework: { name: "@storybook/react-vite" }, + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, }; export default config; ``` @@ -3162,13 +3163,13 @@ To fix these errors, the addon will have to be re-released with a newer browser- module.exports = { presets: [ [ - "@babel/preset-env", + '@babel/preset-env', { shippedProposals: true, - useBuiltIns: "usage", - corejs: "3", + useBuiltIns: 'usage', + corejs: '3', modules: false, - targets: { chrome: "100" }, + targets: { chrome: '100' }, }, ], ], @@ -3297,7 +3298,7 @@ Here's an example, in case you picked `@storybook/react-vite`: export default { // ... your configuration framework: { - name: "@storybook/react-vite", + name: '@storybook/react-vite', options: {}, }, }; @@ -3313,7 +3314,7 @@ For React, what used to be: export default { reactOptions: { fastRefresh: true }, framework: { - name: "@storybook/react-webpack5", + name: '@storybook/react-webpack5', options: {}, }, }; @@ -3324,7 +3325,7 @@ Becomes: ```js export default { framework: { - name: "@storybook/react-webpack5", + name: '@storybook/react-webpack5', options: { fastRefresh: true }, }, }; @@ -3336,7 +3337,7 @@ For Angular, what used to be: export default { angularOptions: { enableIvy: true }, framework: { - name: "@storybook/angular", + name: '@storybook/angular', options: {}, }, }; @@ -3347,7 +3348,7 @@ Becomes: ```js export default { framework: { - name: "@storybook/angular", + name: '@storybook/angular', options: { enableIvy: true }, }, }; @@ -3379,7 +3380,7 @@ Becomes: ```js export default { framework: { - name: "@storybook/react-webpack5", + name: '@storybook/react-webpack5', options: { builder: { lazyCompilation: true }, }, @@ -3397,10 +3398,11 @@ If you are using TypeScript you should import the `StorybookConfig` type from yo For example: ```ts -import type { StorybookConfig } from "@storybook/react-vite"; +import type { StorybookConfig } from '@storybook/react-vite'; + const config: StorybookConfig = { framework: { - name: "@storybook/react-vite", + name: '@storybook/react-vite', options: {}, }, // ... your configuration @@ -3456,17 +3458,17 @@ In 7.0 the location of the standalone node API has moved to `@storybook/core-ser If you used the React standalone API, for example, you might have written: ```js -const buildStandalone = require("@storybook/react/standalone"); +const buildStandalone = require('@storybook/react/standalone'); const options = {}; -buildStandalone(options).then(() => console.log("done")); +buildStandalone(options).then(() => console.log('done')); ``` In 7.0, you would now use: ```js -const { build } = require("@storybook/core-server"); +const { build } = require('@storybook/core-server'); const options = {}; -build(options).then(() => console.log("done")); +build(options).then(() => console.log('done')); ``` #### Change of root html IDs @@ -3495,8 +3497,8 @@ In 7.0, this pattern will also match `.mdx` files (the new extension for docs fi export default { stories: [ { - directory: "../path/to/directory", - files: "**/*.stories.@(mdx|tsx|ts|jsx|js)", + directory: '../path/to/directory', + files: '**/*.stories.@(mdx|tsx|ts|jsx|js)', }, ], }; @@ -3572,7 +3574,7 @@ Given the following `main.js`: ```js export default { - stories: ["../**/*.stories.*"], + stories: ['../**/*.stories.*'], }; ``` @@ -3580,7 +3582,7 @@ If you want to restore the previous behavior to include `node_modules`, you can ```js export default { - stories: ["../**/*.stories.*", "../**/node_modules/**/*.stories.*"], + stories: ['../**/*.stories.*', '../**/node_modules/**/*.stories.*'], }; ``` @@ -3820,11 +3822,11 @@ export const Default: Story = { You can also use the `provide-style` decorator to provide an application-wide service: ```js -import { provideAnimations } from "@angular/platform-browser/animations"; -import { moduleMetadata } from "@storybook/angular"; +import { moduleMetadata } from '@storybook/angular'; +import { provideAnimations } from '@angular/platform-browser/animations'; export default { - title: "Example", + title: 'Example', decorators: [ applicationConfig({ providers: [provideAnimations()], @@ -3861,7 +3863,7 @@ For existing users, SvelteKit projects need to use the `@storybook/sveltekit` fr ```js // .storybook/main.js export default { - framework: "@storybook/sveltekit", + framework: '@storybook/sveltekit', }; ``` @@ -3874,20 +3876,20 @@ In 6.x `@storybook/vue3` exported a Vue application instance called `app`. In 7. Before: ```js -import { app } from "@storybook/vue3"; -import Button from "./Button.vue"; +import { app } from '@storybook/vue3'; +import Button from './Button.vue'; -app.component("GlobalButton", Button); +app.component('GlobalButton', Button); ``` After: ```js -import { setup } from "@storybook/vue3"; -import Button from "./Button.vue"; +import { setup } from '@storybook/vue3'; +import Button from './Button.vue'; setup((app) => { - app.component("GlobalButton", Button); + app.component('GlobalButton', Button); }); ``` @@ -3915,10 +3917,10 @@ These 2 packages replace `@storybook/addons`. When adding addons to storybook, you can (for example) add panels: ```js -import { addons } from "@storybook/manager-api"; +import { addons } from '@storybook/manager-api'; -addons.addPanel("my-panel", { - title: "My Panel", +addons.addPanel('my-panel', { + title: 'My Panel', render: ({ active, key }) =>
My Panel
, }); ``` @@ -3942,11 +3944,11 @@ Here's an example of using the new API: The `@storybook/preview-api` is used here, because the `useEffect` hook is used in a decorator. ```js -import { useEffect, makeDecorator } from "@storybook/preview-api"; +import { useEffect, makeDecorator } from '@storybook/preview-api'; export const withMyAddon = makeDecorator({ - name: "withMyAddon", - parameterName: "myAddon", + name: 'withMyAddon', + parameterName: 'myAddon', wrapper: (getStory) => { useEffect(() => { // do something with the options @@ -4025,7 +4027,7 @@ If your `.manager.js` config references `register.js` of any of the following ad The default export from `@storybook/addons` has been removed. Please use the named exports instead: ```js -import { addons } from "@storybook/addons"; +import { addons } from '@storybook/addons'; ``` The named export has been available since 6.0 or earlier, so your updated code will be backwards-compatible with older versions of Storybook. @@ -4092,7 +4094,7 @@ You can configure Autodocs in `main.js`: module.exports = { docs: { autodocs: true, // see below for alternatives - defaultName: "Docs", // set to change the name of generated docs entries + defaultName: 'Docs', // set to change the name of generated docs entries }, }; ``` @@ -4124,8 +4126,8 @@ Previously `.stories.mdx` files were used to both define and document stories. I If you were using `.stories.mdx` files to write stories, we encourage you to move the stories to a CSF file, and _attach_ an `.mdx` file to that CSF file to document them. You can use the `Meta` block to attach a MDX file to a CSF file, and the `Story` block to render the stories: ```mdx -import { Meta, Story } from "@storybook/blocks"; -import * as ComponentStories from "./some-component.stories"; +import { Meta, Story } from '@storybook/blocks'; +import * as ComponentStories from './some-component.stories'; @@ -4143,7 +4145,7 @@ By default docs entries are listed first for the component. You can sort them us In Storybook 6.x, to create a unattached docs MDX file (that is, one not attached to story or a CSF file), you'd have to create a `.stories.mdx` file, and describe its location with the `Meta` doc block: ```mdx -import { Meta } from "@storybook/addon-docs"; +import { Meta } from '@storybook/addon-docs'; ``` @@ -4192,8 +4194,8 @@ Notice the `?raw` suffix in the markdown import is needed for this to work. To reference a story in a MDX file, you should reference it with `of`: ```mdx -import { Meta, Story } from "@storybook/blocks"; -import * as ComponentStories from "./some-component.stories"; +import { Meta, Story } from '@storybook/blocks'; +import * as ComponentStories from './some-component.stories'; @@ -4203,9 +4205,9 @@ import * as ComponentStories from "./some-component.stories"; You can also reference a story from a different component: ```mdx -import { Meta, Story } from "@storybook/blocks"; -import * as ComponentStories from "./some-component.stories"; -import * as SecondComponentStories from "./second-component.stories"; +import { Meta, Story } from '@storybook/blocks'; +import * as SecondComponentStories from './second-component.stories'; +import * as ComponentStories from './some-component.stories'; @@ -4237,8 +4239,8 @@ That also means the Canvas block no longer supports containing multiple stories Here's a full example of the new API: ```mdx -import { Meta, Canvas } from "@storybook/blocks"; -import * as ComponentStories from "./some-component.stories"; +import { Meta, Canvas } from '@storybook/blocks'; +import * as ComponentStories from './some-component.stories'; @@ -4304,9 +4306,9 @@ To override the theme, you can continue to use the `docs.theme` parameter. If you want to override the MDX components supplied to your docs page, use the `MDXProvider` from `@mdx-js/react`: ```js -import { MDXProvider } from "@mdx-js/react"; -import { DocsContainer } from "@storybook/blocks"; -import * as DesignSystem from "your-design-system"; +import { DocsContainer } from '@storybook/blocks'; +import { MDXProvider } from '@mdx-js/react'; +import * as DesignSystem from 'your-design-system'; export const MyDocsContainer = (props) => (
; ``` @@ -4480,7 +4482,7 @@ export const MyStory: Story = () =>
; However with the introduction of CSF3, the `Story` type has been deprecated in favor of two other types: `StoryFn` for CSF2 and `StoryObj` for CSF3. ```ts -import type { StoryFn, StoryObj } from "@storybook/react"; +import type { StoryFn, StoryObj } from '@storybook/react'; export const MyCsf2Story: StoryFn = () =>
; export const MyCsf3Story: StoryObj = { @@ -4513,24 +4515,24 @@ ComponentMeta -> Meta Here are a few examples: ```ts -import type { StoryFn, StoryObj } from "@storybook/react"; -import { Button, ButtonProps } from "./Button"; +import type { StoryFn, StoryObj } from '@storybook/react'; +import { Button, ButtonProps } from './Button'; // This works in 7.0, making the ComponentX types redundant. const meta: Meta = { component: Button }; -export const CSF3Story: StoryObj = { args: { label: "Label" } }; +export const CSF3Story: StoryObj = { args: { label: 'Label' } }; export const CSF2Story: StoryFn = (args) =>