diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md
index 077e70147763..05f683fc4658 100644
--- a/CHANGELOG.prerelease.md
+++ b/CHANGELOG.prerelease.md
@@ -1,3 +1,20 @@
+## 8.0.0-alpha.8
+
+- Addon Links: Remove LinkTo from direct import - [#25418](https://github.com/storybookjs/storybook/pull/25418), thanks [@yannbf](https://github.com/yannbf)!
+- Addon docs: Remove deprecated parameters - [#25469](https://github.com/storybookjs/storybook/pull/25469), thanks [@yannbf](https://github.com/yannbf)!
+- Builder Vite: Remove StorybookViteConfig type in favor of StorybookConfig - [#25441](https://github.com/storybookjs/storybook/pull/25441), thanks [@yannbf](https://github.com/yannbf)!
+- Core: Error on explicit actions while rendering or playing - [#25238](https://github.com/storybookjs/storybook/pull/25238), thanks [@kasperpeulen](https://github.com/kasperpeulen)!
+- Core: Remove collapseAll and expandAll methods - [#25486](https://github.com/storybookjs/storybook/pull/25486), thanks [@yannbf](https://github.com/yannbf)!
+- Core: Remove storyIndexers in favor of experimental_indexers - [#25468](https://github.com/storybookjs/storybook/pull/25468), thanks [@yannbf](https://github.com/yannbf)!
+- Core: Remove unused staticDir type - [#25415](https://github.com/storybookjs/storybook/pull/25415), thanks [@yannbf](https://github.com/yannbf)!
+- Doc blocks: Remove deprecated props from Description block - [#25457](https://github.com/storybookjs/storybook/pull/25457), thanks [@yannbf](https://github.com/yannbf)!
+- Manager API: Remove deprecated navigateToSettingsPage method - [#25467](https://github.com/storybookjs/storybook/pull/25467), thanks [@yannbf](https://github.com/yannbf)!
+- React: Remove deprecated setGlobalConfig portable stories api - [#25442](https://github.com/storybookjs/storybook/pull/25442), thanks [@yannbf](https://github.com/yannbf)!
+- TypeScript: Remove deprecated addons module types - [#25485](https://github.com/storybookjs/storybook/pull/25485), thanks [@yannbf](https://github.com/yannbf)!
+- Types: Remove DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta types - [#25477](https://github.com/storybookjs/storybook/pull/25477), thanks [@yannbf](https://github.com/yannbf)!
+- Types: Remove Framework in favor of Renderer types - [#25476](https://github.com/storybookjs/storybook/pull/25476), thanks [@yannbf](https://github.com/yannbf)!
+- UI: Remove deprecated WithTooltip props - [#25440](https://github.com/storybookjs/storybook/pull/25440), thanks [@yannbf](https://github.com/yannbf)!
+
## 8.0.0-alpha.7
- Addon-Docs: Upgrade to MDX3 - [#25303](https://github.com/storybookjs/storybook/pull/25303), thanks [@yannbf](https://github.com/yannbf)!
diff --git a/MIGRATION.md b/MIGRATION.md
index 6e673bbea530..9d894c1b89cd 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -29,6 +29,17 @@
- [Require Svelte 4 and up](#require-svelte-4-and-up)
- [Deprecations which are now removed](#deprecations-which-are-now-removed)
- [--use-npm flag in storybook CLI](#--use-npm-flag-in-storybook-cli)
+ - [`setGlobalConfig` from `@storybook/react`](#setglobalconfig-from-storybookreact)
+ - [StorybookViteConfig type from @storybook/builder-vite](#storybookviteconfig-type-from-storybookbuilder-vite)
+ - [props from WithTooltipComponent from @storybook/components](#props-from-withtooltipcomponent-from-storybookcomponents)
+ - [LinkTo direct import from addon-links](#linkto-direct-import-from-addon-links)
+ - [DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta TypeScript types](#decoratorfn-story-componentstory-componentstoryobj-componentstoryfn-and-componentmeta-typescript-types)
+ - ["Framework" TypeScript types](#framework-typescript-types)
+ - [`navigateToSettingsPage` method from Storybook's manager-api](#navigatetosettingspage-method-from-storybooks-manager-api)
+ - [storyIndexers](#storyindexers)
+ - [Deprecated docs parameters](#deprecated-docs-parameters)
+ - [Description Doc block properties](#description-doc-block-properties)
+ - [Manager API expandAll and collapseAll methods](#manager-api-expandall-and-collapseall-methods)
- [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)
@@ -573,6 +584,112 @@ Starting in 8.0, Storybook requires Svelte 4 and up.
The `--use-npm` is now removed. Use `--package-manager=npm` instead. [More info here](#cli-option---use-npm-deprecated).
+#### `setGlobalConfig` from `@storybook/react`
+
+The `setGlobalConfig` (used for reusing stories in your tests) is now removed in favor of `setProjectAnnotations`.
+
+```ts
+import { setProjectAnnotations } from `@storybook/testing-react`.
+```
+
+#### StorybookViteConfig type from @storybook/builder-vite
+
+The `StorybookViteConfig` type is now removed in favor of `StorybookConfig`:
+
+```ts
+import type { StorybookConfig } from '@storybook/react-vite';
+```
+
+#### props from WithTooltipComponent from @storybook/components
+
+The deprecated properties `tooltipShown`, `closeOnClick`, and `onVisibilityChange` of `WithTooltipComponent` from `@storybook/components` are now removed. Please replace them:
+
+```tsx
+
+ ...
+
+```
+
+#### LinkTo direct import from addon-links
+
+The `LinkTo` (React component) direct import from `@storybook/addon-links` is now removed. You have to import it from `@storybook/addon-links/react` instead.
+
+```ts
+// before
+import LinkTo from '@storybook/addon-links';
+
+// after
+import LinkTo from '@storybook/addon-links/react';
+```
+
+#### DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta TypeScript types
+
+The `Story` type is now removed in favor of `StoryFn` and `StoryObj`. More info [here](#story-type-deprecated).
+
+The `DecoratorFn` type is now removed in favor of `Decorator`. [More info](#renamed-decoratorfn-to-decorator).
+
+For React, the `ComponentStory`, `ComponentStoryObj`, `ComponentStoryFn` and `ComponentMeta` types are now removed in favor of `StoryFn`, `StoryObj` and `Meta`. [More info](#componentstory-componentstoryobj-componentstoryfn-and-componentmeta-types-are-deprecated).
+
+#### "Framework" TypeScript types
+
+The Framework types such as `ReactFramework` are now removed in favor of Renderer types such as `ReactRenderer`. This affects all frameworks. [More info](#renamed-xframework-to-xrenderer).
+
+#### `navigateToSettingsPage` method from Storybook's manager-api
+
+The `navigateToSettingsPage` method from manager-api is now removed in favor of `changeSettingsTab`.
+
+```ts
+export const Component = () => {
+ const api = useStorybookApi();
+
+ const someHandler = () => {
+ // Old method: api.navigateToSettingsPage('/settings/about');
+ api.changeSettingsTab('about'); // the /settings path is not necessary anymore
+ };
+
+ // ...
+}
+```
+
+#### storyIndexers
+
+The Storybook's main.js configuration property `storyIndexers` is now removed in favor of `experimental_indexers`. [More info](#storyindexers-is-replaced-with-experimental_indexers).
+
+#### Deprecated docs parameters
+
+The following story and meta parameters are now removed:
+
+```ts
+parameters.docs.iframeHeight // becomes docs.story.iframeHeight
+parameters.docs.inlineStories // becomes docs.story.inline
+parameters.jsx.transformSource // becomes parameters.docs.source.transform
+parameters.docs.transformSource // becomes parameters.docs.source.transform
+parameters.docs.source.transformSource // becomes parameters.docs.source.transform
+```
+
+More info [here](#autodocs-changes) and [here](#source-block).
+
+#### Description Doc block properties
+
+`children`, `markdown` and `type` are now removed in favor of the `of` property. [More info](#doc-blocks).
+
+#### Manager API expandAll and collapseAll methods
+
+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';
+
+const api = useStorybookApi()
+api.collapseAll() // becomes api.emit(STORIES_COLLAPSE_ALL)
+api.expandAll() // becomes api.emit(STORIES_EXPAND_ALL)
+```
+
## From version 7.5.0 to 7.6.0
#### CommonJS with Vite is deprecated
@@ -2168,6 +2285,8 @@ During the 7.0 dev cycle we will be preparing recommendations and utilities to m
#### `Story` type deprecated
+_Has codemod_
+
In 6.x you were able to do this:
```ts
@@ -2176,24 +2295,43 @@ import type { Story } from '@storybook/react';
export const MyStory: Story = () =>
;
```
-But this will produce a deprecation warning in 7.0 because `Story` has been deprecated.
-To fix the deprecation warning, use the `StoryFn` type:
+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 } from '@storybook/react';
+import type { StoryFn, StoryObj } from '@storybook/react';
-export const MyStory: StoryFn = () => ;
+export const MyCsf2Story: StoryFn = () => ;
+export const MyCsf3Story: StoryObj = {
+ render: () =>
+};
```
This change is part of our move to CSF3, which uses objects instead of functions to represent stories.
You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
+We have set up a codemod that attempts to automatically migrate your code for you (update the glob to suit your needs):
+
+```
+npx storybook@next migrate upgrade-deprecated-types --glob="**/*.stories.tsx"
+```
+
#### `ComponentStory`, `ComponentStoryObj`, `ComponentStoryFn` and `ComponentMeta` types are deprecated
-The type of StoryObj and StoryFn have been changed in 7.0 so that both the "component" as "the props of the component" will be accepted as the generic parameter.
+_Has codemod_
+
+The type of `StoryObj` and `StoryFn` have been changed in 7.0 so that both the "component" as "the props of the component" will be accepted as the generic parameter. You can now replace the types:
+
+```
+ComponentStory -> StoryFn (CSF2) or StoryObj (CSF3)
+ComponentStoryObj -> StoryObj
+ComponentStoryFn -> StoryFn
+ComponentMeta -> Meta
+```
+
+Here are a few examples:
```ts
-import type { Story } from '@storybook/react';
+import type { StoryFn, StoryObj } from '@storybook/react';
import { Button, ButtonProps } from './Button';
// This works in 7.0, making the ComponentX types redundant.
@@ -2213,6 +2351,12 @@ export const CSF2Story: StoryFn = (args) => ;
CSF2Story.args = { label: 'Label' };
```
+We have set up a codemod that attempts to automatically migrate your code for you (update the glob to suit your needs):
+
+```
+npx storybook@next migrate upgrade-deprecated-types --glob="**/*.stories.tsx"
+```
+
#### Renamed `renderToDOM` to `renderToCanvas`
The "rendering" function that renderers (ex-frameworks) must export (`renderToDOM`) has been renamed to `renderToCanvas` to acknowledge that some consumers of frameworks/the preview do not work with DOM elements.
diff --git a/code/addons/docs/docs/docspage.md b/code/addons/docs/docs/docspage.md
index 8a8da1fc773a..3fef9898f955 100644
--- a/code/addons/docs/docs/docspage.md
+++ b/code/addons/docs/docs/docspage.md
@@ -154,7 +154,7 @@ addParameters({
});
```
-With that function, anyone using the docs addon for `@storybook/vue` can make their stories render inline, either globally with the `inlineStories` docs parameter, or on a per-story-basis using the `inline` prop on the `` doc block. If you come up with an elegant and flexible implementation for the `prepareForInline` function for your own framework, let us know! We'd love to make it the default configuration, to make inline stories more accessible for a larger variety of frameworks!
+With that function, anyone using the docs addon for `@storybook/vue` can make their stories render inline, either globally with the `docs.story.inline` parameter, or on a per-story-basis using the `inline` prop on the `` doc block. If you come up with an elegant and flexible implementation for the `prepareForInline` function for your own framework, let us know! We'd love to make it the default configuration, to make inline stories more accessible for a larger variety of frameworks!
## Show/Hide code
diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json
index 7fec0d5520ee..6645021a4ed7 100644
--- a/code/addons/docs/package.json
+++ b/code/addons/docs/package.json
@@ -121,6 +121,7 @@
"devDependencies": {
"@mdx-js/mdx": "^3.0.0",
"@rollup/pluginutils": "^5.0.2",
+ "@storybook/test": "workspace:*",
"typescript": "^5.3.2",
"vite": "^4.0.4"
},
diff --git a/code/addons/docs/template/stories/docspage/basic.stories.ts b/code/addons/docs/template/stories/docspage/basic.stories.ts
index 6eb3f19523bd..9982b444a487 100644
--- a/code/addons/docs/template/stories/docspage/basic.stories.ts
+++ b/code/addons/docs/template/stories/docspage/basic.stories.ts
@@ -1,9 +1,10 @@
import { global as globalThis } from '@storybook/global';
+import { fn } from '@storybook/test';
export default {
component: globalThis.Components.Button,
tags: ['autodocs'],
- args: { label: 'Click Me!' },
+ args: { label: 'Click Me!', onClick: fn() },
parameters: { chromatic: { disable: true } },
};
diff --git a/code/addons/interactions/src/Panel.tsx b/code/addons/interactions/src/Panel.tsx
index 3d5733710d19..3523c64bf5f7 100644
--- a/code/addons/interactions/src/Panel.tsx
+++ b/code/addons/interactions/src/Panel.tsx
@@ -4,10 +4,10 @@ import React, { Fragment, memo, useEffect, useMemo, useRef, useState } from 'rea
import { useAddonState, useChannel, useParameter } from '@storybook/manager-api';
import {
FORCE_REMOUNT,
- IGNORED_EXCEPTION,
STORY_RENDER_PHASE_CHANGED,
STORY_THREW_EXCEPTION,
PLAY_FUNCTION_THREW_EXCEPTION,
+ UNHANDLED_ERRORS_WHILE_PLAYING,
} from '@storybook/core-events';
import { EVENTS, type Call, CallStates, type LogItem } from '@storybook/instrumenter';
@@ -91,6 +91,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
hasException: false,
caughtException: undefined,
interactionsCount: 0,
+ unhandledErrors: undefined,
});
// local state
@@ -104,6 +105,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
interactions = [],
isPlaying = false,
caughtException = undefined,
+ unhandledErrors = undefined,
} = addonState;
// Log and calls are tracked in a ref so we don't needlessly rerender.
@@ -157,6 +159,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
hasException: false,
caughtException: undefined,
interactionsCount: 0,
+ unhandledErrors: undefined,
});
return;
}
@@ -180,11 +183,10 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
set((s) => ({ ...s, isErrored: true }));
},
[PLAY_FUNCTION_THREW_EXCEPTION]: (e) => {
- if (e?.message !== IGNORED_EXCEPTION.message) {
- set((s) => ({ ...s, caughtException: e }));
- } else {
- set((s) => ({ ...s, caughtException: undefined }));
- }
+ set((s) => ({ ...s, caughtException: e }));
+ },
+ [UNHANDLED_ERRORS_WHILE_PLAYING]: (e) => {
+ set((s) => ({ ...s, unhandledErrors: e }));
},
},
[collapsed]
@@ -224,7 +226,10 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
const [fileName] = storyFilePath.toString().split('/').slice(-1);
const scrollToTarget = () => scrollTarget?.scrollIntoView({ behavior: 'smooth', block: 'end' });
- const hasException = !!caughtException || interactions.some((v) => v.status === CallStates.ERROR);
+ const hasException =
+ !!caughtException ||
+ !!unhandledErrors ||
+ interactions.some((v) => v.status === CallStates.ERROR);
if (isErrored) {
return ;
@@ -240,6 +245,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
fileName={fileName}
hasException={hasException}
caughtException={caughtException}
+ unhandledErrors={unhandledErrors}
isPlaying={isPlaying}
pausedAt={pausedAt}
endRef={endRef}
diff --git a/code/addons/interactions/src/components/Interaction.stories.tsx b/code/addons/interactions/src/components/Interaction.stories.tsx
index ea03a78431d5..4ae080dac30a 100644
--- a/code/addons/interactions/src/components/Interaction.stories.tsx
+++ b/code/addons/interactions/src/components/Interaction.stories.tsx
@@ -1,4 +1,4 @@
-import type { ComponentStoryObj, ComponentMeta } from '@storybook/react';
+import type { StoryObj, Meta } from '@storybook/react';
import { expect } from '@storybook/jest';
import { CallStates } from '@storybook/instrumenter';
import { userEvent, within } from '@storybook/testing-library';
@@ -7,7 +7,7 @@ import { getCalls } from '../mocks';
import { Interaction } from './Interaction';
import SubnavStories from './Subnav.stories';
-type Story = ComponentStoryObj;
+type Story = StoryObj;
export default {
title: 'Addons/Interactions/Interaction',
@@ -17,7 +17,7 @@ export default {
controls: SubnavStories.args.controls,
controlStates: SubnavStories.args.controlStates,
},
-} as ComponentMeta;
+} as Meta;
export const Active: Story = {
args: {
diff --git a/code/addons/interactions/src/components/Interaction.tsx b/code/addons/interactions/src/components/Interaction.tsx
index 5c817e71a0aa..c5e5e41f3d5e 100644
--- a/code/addons/interactions/src/components/Interaction.tsx
+++ b/code/addons/interactions/src/components/Interaction.tsx
@@ -10,6 +10,7 @@ import { MethodCall } from './MethodCall';
import { StatusIcon } from './StatusIcon';
import type { Controls } from './InteractionsPanel';
+import { isJestError } from '../utils';
const MethodCallWrapper = styled.div(() => ({
fontFamily: typography.fonts.mono,
@@ -112,8 +113,8 @@ const RowMessage = styled('div')(({ theme }) => ({
},
}));
-const Exception = ({ exception }: { exception: Call['exception'] }) => {
- if (exception.message.startsWith('expect(')) {
+export const Exception = ({ exception }: { exception: Call['exception'] }) => {
+ if (isJestError(exception)) {
return ;
}
const paragraphs = exception.message.split('\n\n');
@@ -121,7 +122,6 @@ const Exception = ({ exception }: { exception: Call['exception'] }) => {
return (
{paragraphs[0]}
-
{exception.showDiff && exception.diff ? (
<>
diff --git a/code/addons/interactions/src/components/InteractionsPanel.tsx b/code/addons/interactions/src/components/InteractionsPanel.tsx
index 6fad03daaf48..3f56926af3a8 100644
--- a/code/addons/interactions/src/components/InteractionsPanel.tsx
+++ b/code/addons/interactions/src/components/InteractionsPanel.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/no-array-index-key */
import * as React from 'react';
import { Link, Placeholder } from '@storybook/components';
import { type Call, CallStates, type ControlStates } from '@storybook/instrumenter';
@@ -7,6 +8,7 @@ import { transparentize } from 'polished';
import { Subnav } from './Subnav';
import { Interaction } from './Interaction';
+import { isTestAssertionError } from '../utils';
export interface Controls {
start: (args: any) => void;
@@ -30,6 +32,7 @@ interface InteractionsPanelProps {
fileName?: string;
hasException?: boolean;
caughtException?: Error;
+ unhandledErrors?: SerializedError[];
isPlaying?: boolean;
pausedAt?: Call['id'];
calls: Map;
@@ -37,16 +40,15 @@ interface InteractionsPanelProps {
onScrollToEnd?: () => void;
}
-const Container = styled.div<{ withException: boolean }>(({ theme, withException }) => ({
+const Container = styled.div(({ theme }) => ({
minHeight: '100%',
background: theme.background.content,
- ...(withException && {
- backgroundColor:
- theme.base === 'dark' ? transparentize(0.93, theme.color.negative) : theme.background.warning,
- }),
}));
const CaughtException = styled.div(({ theme }) => ({
+ borderBottom: `1px solid ${theme.appBorderColor}`,
+ backgroundColor:
+ theme.base === 'dark' ? transparentize(0.93, theme.color.negative) : theme.background.warning,
padding: 15,
fontSize: theme.typography.size.s2 - 1,
lineHeight: '19px',
@@ -69,9 +71,13 @@ const CaughtExceptionDescription = styled.p({
margin: 0,
padding: '0 0 20px',
});
+
const CaughtExceptionStack = styled.pre(({ theme }) => ({
margin: 0,
padding: 0,
+ '&:not(:last-child)': {
+ paddingBottom: 16,
+ },
fontSize: theme.typography.size.s1 - 1,
}));
@@ -84,13 +90,14 @@ export const InteractionsPanel: React.FC = React.memo(
fileName,
hasException,
caughtException,
+ unhandledErrors,
isPlaying,
pausedAt,
onScrollToEnd,
endRef,
}) {
return (
-
+
{(interactions.length > 0 || hasException) && (
= React.memo(
/>
))}
- {caughtException && !caughtException.message?.startsWith('ignoredException') && (
+ {caughtException && !isTestAssertionError(caughtException) && (
Caught exception in play function
-
- This story threw an error after it finished rendering which means your interactions
- couldn' t be run.Go to this story' s play function in {fileName} to fix.
-
- {caughtException.stack || `${caughtException.name}: ${caughtException.message}`}
+ {printSerializedError(caughtException)}
)}
+ {unhandledErrors && (
+
+ Unhandled Errors
+
+ Found {unhandledErrors.length} unhandled error{unhandledErrors.length > 1 ? 's' : ''}{' '}
+ while running the play function. This might cause false positive assertions. Resolve
+ unhandled errors or ignore unhandled errors with setting the
+ test.dangerouslyIgnoreUnhandledErrors{' '}
+ parameter to true.
+
+
+ {unhandledErrors.map((error, i) => (
+
+ {printSerializedError(error)}
+
+ ))}
+
+ )}
{!isPlaying && !caughtException && interactions.length === 0 && (
@@ -150,3 +171,13 @@ export const InteractionsPanel: React.FC = React.memo(
);
}
);
+
+interface SerializedError {
+ name: string;
+ stack?: string;
+ message: string;
+}
+
+function printSerializedError(error: SerializedError) {
+ return error.stack || `${error.name}: ${error.message}`;
+}
diff --git a/code/addons/interactions/src/preview.ts b/code/addons/interactions/src/preview.ts
index 54c7c18faab5..80515b644dab 100644
--- a/code/addons/interactions/src/preview.ts
+++ b/code/addons/interactions/src/preview.ts
@@ -1,61 +1,22 @@
-/* eslint-disable no-param-reassign,no-underscore-dangle */
-///
-
-import { addons } from '@storybook/preview-api';
-import { global } from '@storybook/global';
-import { FORCE_REMOUNT, STORY_RENDER_PHASE_CHANGED } from '@storybook/core-events';
+/* eslint-disable no-underscore-dangle */
import type {
- Renderer,
- ArgsEnhancer,
+ Args,
+ LoaderFunction,
PlayFunction,
PlayFunctionContext,
StepLabel,
- Args,
} from '@storybook/types';
import { instrument } from '@storybook/instrumenter';
-import { ModuleMocker } from 'jest-mock';
-
-const JestMock = new ModuleMocker(global);
-const fn = JestMock.fn.bind(JestMock);
-
-// Aliasing `fn` to `action` here, so we get a more descriptive label in the UI.
-const { action } = instrument({ action: fn }, { retain: true });
-const channel = addons.getChannel();
-const spies: any[] = [];
-
-channel.on(FORCE_REMOUNT, () => spies.forEach((mock) => mock?.mockClear?.()));
-channel.on(STORY_RENDER_PHASE_CHANGED, ({ newPhase }) => {
- if (newPhase === 'loading') spies.forEach((mock) => mock?.mockClear?.());
-});
-const addSpies = (id: string, val: any, key?: string): any => {
- try {
- if (Object.prototype.toString.call(val) === '[object Object]') {
- // We have to mutate the original object for this to survive HMR.
- // eslint-disable-next-line no-restricted-syntax
- for (const [k, v] of Object.entries(val)) val[k] = addSpies(id, v, k);
- return val;
- }
- if (Array.isArray(val)) {
- return val.map((item, index) => addSpies(id, item, `${key}[${index}]`));
- }
- if (typeof val === 'function' && val.isAction && !val._isMockFunction) {
- Object.defineProperty(val, 'name', { value: key, writable: false });
- Object.defineProperty(val, '__storyId__', { value: id, writable: false });
- const spy = action(val);
- spies.push(spy);
- return spy;
- }
- } catch (e) {
- // ignore
- }
- return val;
-};
-
-const addActionsFromArgTypes: ArgsEnhancer = ({ id, initialArgs }) =>
- addSpies(id, initialArgs);
+export const { step: runStep } = instrument(
+ {
+ step: (label: StepLabel, play: PlayFunction, context: PlayFunctionContext) =>
+ play(context),
+ },
+ { intercept: true }
+);
-const instrumentSpies: ArgsEnhancer = ({ initialArgs }) => {
+const instrumentSpies: LoaderFunction = ({ initialArgs }) => {
const argTypesWithAction = Object.entries(initialArgs).filter(
([, value]) =>
typeof value === 'function' &&
@@ -68,20 +29,13 @@ const instrumentSpies: ArgsEnhancer = ({ initialArgs }) => {
const instrumented = instrument({ [key]: () => value }, { retain: true })[key];
acc[key] = instrumented();
// this enhancer is being called multiple times
+ // eslint-disable-next-line no-param-reassign
value._instrumented = true;
return acc;
}, {} as Args);
};
-export const argsEnhancers = [addActionsFromArgTypes, instrumentSpies];
-
-export const { step: runStep } = instrument(
- {
- step: (label: StepLabel, play: PlayFunction, context: PlayFunctionContext) =>
- play(context),
- },
- { intercept: true }
-);
+export const argsEnhancers = [instrumentSpies];
export const parameters = {
throwPlayFunctionExceptions: false,
diff --git a/code/addons/interactions/src/utils.ts b/code/addons/interactions/src/utils.ts
new file mode 100644
index 000000000000..1b08eca12a24
--- /dev/null
+++ b/code/addons/interactions/src/utils.ts
@@ -0,0 +1,23 @@
+export function isTestAssertionError(error: unknown) {
+ return isChaiError(error) || isJestError(error);
+}
+
+export function isChaiError(error: unknown) {
+ return (
+ error &&
+ typeof error === 'object' &&
+ 'name' in error &&
+ typeof error.name === 'string' &&
+ error.name === 'AssertionError'
+ );
+}
+
+export function isJestError(error: unknown) {
+ return (
+ error &&
+ typeof error === 'object' &&
+ 'message' in error &&
+ typeof error.message === 'string' &&
+ error.message.startsWith('expect(')
+ );
+}
diff --git a/code/addons/interactions/template/stories/basics.stories.ts b/code/addons/interactions/template/stories/basics.stories.ts
index e8c14245aa90..cf6e34eddf2c 100644
--- a/code/addons/interactions/template/stories/basics.stories.ts
+++ b/code/addons/interactions/template/stories/basics.stories.ts
@@ -1,17 +1,18 @@
import { global as globalThis } from '@storybook/global';
import {
- within,
- waitFor,
+ expect,
+ fn,
fireEvent,
userEvent,
+ waitFor,
waitForElementToBeRemoved,
-} from '@storybook/testing-library';
-import { expect } from '@storybook/jest';
+ within,
+} from '@storybook/test';
export default {
component: globalThis.Components.Form,
- argTypes: {
- onSuccess: { type: 'function' },
+ args: {
+ onSuccess: fn(),
},
};
@@ -101,15 +102,14 @@ export const UserEventSetup = {
const { args, canvasElement, step } = context;
const user = userEvent.setup();
const canvas = within(canvasElement);
- await step('Select, type and paste on input using user-event v14 setup', async () => {
- const input = await canvas.getByRole('textbox');
+ await step('Select and type on input using user-event v14 setup', async () => {
+ const input = canvas.getByRole('textbox');
await user.click(input);
- await user.type(input, 'Pasting: ');
- await user.paste('foobar');
+ await user.type(input, 'Typing ...');
});
await step('Tab and press enter on submit button', async () => {
await user.pointer([
- { keys: '[TouchA>]', target: await canvas.getByRole('textbox') },
+ { keys: '[TouchA>]', target: canvas.getByRole('textbox') },
{ keys: '[/TouchA]' },
]);
await user.tab();
diff --git a/code/addons/interactions/template/stories/unhandled-errors.stories.ts b/code/addons/interactions/template/stories/unhandled-errors.stories.ts
new file mode 100644
index 000000000000..fcaf0144ccd4
--- /dev/null
+++ b/code/addons/interactions/template/stories/unhandled-errors.stories.ts
@@ -0,0 +1,23 @@
+import { global as globalThis } from '@storybook/global';
+import { userEvent, within } from '@storybook/test';
+
+export default {
+ component: globalThis.Components.Button,
+ args: {
+ label: 'Button',
+ },
+ argTypes: {
+ onClick: { type: 'function' },
+ },
+ parameters: {
+ actions: { argTypesRegex: '^on[A-Z].*' },
+ },
+};
+
+export const Default = {
+ play: async (context) => {
+ const { args, canvasElement } = context;
+ const canvas = within(canvasElement);
+ await userEvent.click(canvas.getByRole('button'));
+ },
+};
diff --git a/code/addons/links/src/index.ts b/code/addons/links/src/index.ts
index 47751e599680..524558abc6c6 100644
--- a/code/addons/links/src/index.ts
+++ b/code/addons/links/src/index.ts
@@ -1,20 +1 @@
-import { dedent } from 'ts-dedent';
-
-let hasWarned = false;
-
-/**
- * @deprecated please import this specific function from @storybook/addon-links/react
- */
-export function LinkTo(): null {
- if (!hasWarned) {
- // eslint-disable-next-line no-console
- console.error(dedent`
- LinkTo has moved to addon-links/react:
- import LinkTo from '@storybook/addon-links/react';
- `);
- hasWarned = true;
- }
- return null;
-}
-
export { linkTo, hrefTo, withLinks, navigate } from './utils';
diff --git a/code/addons/themes/src/theme-switcher.tsx b/code/addons/themes/src/theme-switcher.tsx
index 4fc7ffa89256..7e366fe8359e 100644
--- a/code/addons/themes/src/theme-switcher.tsx
+++ b/code/addons/themes/src/theme-switcher.tsx
@@ -57,7 +57,7 @@ export const ThemeSwitcher = () => {
{
return (
(input: I): I =>
dirname(require.resolve(join(input, 'package.json'))) as any;
diff --git a/code/e2e-tests/addon-interactions.spec.ts b/code/e2e-tests/addon-interactions.spec.ts
index d77ef67beeca..5169f3fe7332 100644
--- a/code/e2e-tests/addon-interactions.spec.ts
+++ b/code/e2e-tests/addon-interactions.spec.ts
@@ -1,4 +1,4 @@
-/* eslint-disable jest/no-disabled-tests */
+/* eslint-disable jest/no-disabled-tests,jest/valid-title */
import { test, expect } from '@playwright/test';
import process from 'process';
import { SbPage } from './util';
@@ -15,7 +15,6 @@ test.describe('addon-interactions', () => {
test('should have interactions', async ({ page }) => {
// templateName is e.g. 'vue-cli/default-js'
test.skip(
- // eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
`Skipping ${templateName}, which does not support addon-interactions`
);
@@ -44,7 +43,6 @@ test.describe('addon-interactions', () => {
test('should step through interactions', async ({ page }) => {
// templateName is e.g. 'vue-cli/default-js'
test.skip(
- // eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
`Skipping ${templateName}, which does not support addon-interactions`
);
@@ -116,4 +114,23 @@ test.describe('addon-interactions', () => {
await expect(interactionsTab).toBeVisible();
await expect(formInput).toHaveValue('final value');
});
+
+ test('should show unhandled errors', async ({ page }) => {
+ test.skip(
+ /^(lit)/i.test(`${templateName}`),
+ `Skipping ${templateName}, which does not support addon-interactions`
+ );
+ // We trigger the implicit action error here, but angular works a bit different with implicit actions.
+ test.skip(/^(angular)/i.test(`${templateName}`));
+
+ const sbPage = new SbPage(page);
+
+ await sbPage.deepLinkToStory(storybookUrl, 'addons/interactions/unhandled-errors', 'default');
+ await sbPage.viewAddonPanel('Interactions');
+
+ const panel = sbPage.panelContent();
+ await expect(panel).toContainText(/Fail/);
+ await expect(panel).toContainText(/Found 1 unhandled error/);
+ await expect(panel).toBeVisible();
+ });
});
diff --git a/code/frameworks/angular/src/client/public-types.ts b/code/frameworks/angular/src/client/public-types.ts
index 7d81b1dfbd65..e96e3d89c151 100644
--- a/code/frameworks/angular/src/client/public-types.ts
+++ b/code/frameworks/angular/src/client/public-types.ts
@@ -9,6 +9,7 @@ import {
StrictArgs,
ProjectAnnotations,
} from '@storybook/types';
+import { EventEmitter } from '@angular/core';
import { AngularRenderer } from './types';
export type { Args, ArgTypes, Parameters, StrictArgs } from '@storybook/types';
@@ -20,21 +21,21 @@ export type { AngularRenderer };
*
* @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export)
*/
-export type Meta = ComponentAnnotations;
+export type Meta = ComponentAnnotations>;
/**
* Story function that represents a CSFv2 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
-export type StoryFn = AnnotatedStoryFn;
+export type StoryFn = AnnotatedStoryFn>;
/**
* Story function that represents a CSFv3 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
-export type StoryObj = StoryAnnotations;
+export type StoryObj = StoryAnnotations>;
/**
* @deprecated Use `StoryFn` instead.
@@ -51,3 +52,7 @@ export type Decorator = DecoratorFunction = LoaderFunction;
export type StoryContext = GenericStoryContext;
export type Preview = ProjectAnnotations;
+
+type TransformEventType = {
+ [K in keyof T]: T[K] extends EventEmitter ? (e: E) => void : T[K];
+};
diff --git a/code/frameworks/angular/src/client/types.ts b/code/frameworks/angular/src/client/types.ts
index ef3c4428c21e..100b3e912312 100644
--- a/code/frameworks/angular/src/client/types.ts
+++ b/code/frameworks/angular/src/client/types.ts
@@ -37,10 +37,6 @@ export interface StoryFnAngularReturnType {
userDefinedTemplate?: boolean;
}
-/**
- * @deprecated Use `AngularRenderer` instead.
- */
-export type AngularFramework = AngularRenderer;
export interface AngularRenderer extends WebRenderer {
component: any;
storyResult: StoryFnAngularReturnType;
diff --git a/code/frameworks/angular/template/cli/button.stories.ts b/code/frameworks/angular/template/cli/button.stories.ts
index 19661b149fdb..886310bed9ad 100644
--- a/code/frameworks/angular/template/cli/button.stories.ts
+++ b/code/frameworks/angular/template/cli/button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/angular';
-
+import { fn } from '@storybook/test';
import { ButtonComponent } from './button.component';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -7,17 +7,13 @@ const meta: Meta = {
title: 'Example/Button',
component: ButtonComponent,
tags: ['autodocs'],
- render: (args: ButtonComponent) => ({
- props: {
- backgroundColor: null,
- ...args,
- },
- }),
argTypes: {
backgroundColor: {
control: 'color',
},
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
export default meta;
diff --git a/code/frameworks/ember/src/client/preview/types.ts b/code/frameworks/ember/src/client/preview/types.ts
index 5df0b2632aa5..147f4928f240 100644
--- a/code/frameworks/ember/src/client/preview/types.ts
+++ b/code/frameworks/ember/src/client/preview/types.ts
@@ -13,10 +13,6 @@ export interface OptionsArgs {
element: any;
}
-/**
- * @deprecated Use `EmberRenderer` instead.
- */
-export type EmberFramework = EmberRenderer;
export interface EmberRenderer extends WebRenderer {
component: any;
storyResult: OptionsArgs;
diff --git a/code/frameworks/nextjs/template/cli/js/Button.stories.js b/code/frameworks/nextjs/template/cli/js/Button.stories.js
index 3a3f67ec8fb4..97b9ec0ed85d 100644
--- a/code/frameworks/nextjs/template/cli/js/Button.stories.js
+++ b/code/frameworks/nextjs/template/cli/js/Button.stories.js
@@ -1,3 +1,4 @@
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
@@ -14,6 +15,8 @@ export default {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
diff --git a/code/frameworks/nextjs/template/cli/ts-3-8/Button.stories.ts b/code/frameworks/nextjs/template/cli/ts-3-8/Button.stories.ts
index b65080126a44..2054fc59231e 100644
--- a/code/frameworks/nextjs/template/cli/ts-3-8/Button.stories.ts
+++ b/code/frameworks/nextjs/template/cli/ts-3-8/Button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
-
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
@@ -16,6 +16,8 @@ const meta: Meta = {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
export default meta;
diff --git a/code/frameworks/nextjs/template/cli/ts-3-8/Header.tsx b/code/frameworks/nextjs/template/cli/ts-3-8/Header.tsx
index 01504601311d..c806ddf023e8 100644
--- a/code/frameworks/nextjs/template/cli/ts-3-8/Header.tsx
+++ b/code/frameworks/nextjs/template/cli/ts-3-8/Header.tsx
@@ -9,9 +9,9 @@ type User = {
interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
diff --git a/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts
index 742c3aa7b029..455a9d8601c9 100644
--- a/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts
+++ b/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
-
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
@@ -16,6 +16,8 @@ const meta = {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
} satisfies Meta;
export default meta;
diff --git a/code/frameworks/nextjs/template/cli/ts-4-9/Header.tsx b/code/frameworks/nextjs/template/cli/ts-4-9/Header.tsx
index 01504601311d..c806ddf023e8 100644
--- a/code/frameworks/nextjs/template/cli/ts-4-9/Header.tsx
+++ b/code/frameworks/nextjs/template/cli/ts-4-9/Header.tsx
@@ -9,9 +9,9 @@ type User = {
interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json
index d7a40cefbda9..5dac6552c584 100644
--- a/code/frameworks/svelte-vite/package.json
+++ b/code/frameworks/svelte-vite/package.json
@@ -58,7 +58,7 @@
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@types/node": "^18.0.0",
- "svelte": "^5.0.0-next.16",
+ "svelte": "^5.0.0-next.28",
"typescript": "^5.3.2",
"vite": "^4.0.0"
},
diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts
index 70daf5764dd7..75d12dc01499 100644
--- a/code/lib/cli/src/generators/baseGenerator.ts
+++ b/code/lib/cli/src/generators/baseGenerator.ts
@@ -167,9 +167,7 @@ const getFrameworkDetails = (
const stripVersions = (addons: string[]) => addons.map((addon) => getPackageDetails(addon)[0]);
const hasInteractiveStories = (rendererId: SupportedRenderers) =>
- ['react', 'angular', 'preact', 'svelte', 'vue', 'vue3', 'html', 'solid', 'qwik'].includes(
- rendererId
- );
+ ['react', 'angular', 'preact', 'svelte', 'vue3', 'html', 'solid', 'qwik'].includes(rendererId);
const hasFrameworkTemplates = (framework?: SupportedFrameworks) =>
framework ? ['angular', 'nextjs'].includes(framework) : false;
@@ -263,16 +261,16 @@ export async function baseGenerator(
...(extraAddonsToInstall || []),
].filter(Boolean);
+ // TODO: migrate template stories in solid and qwik to use @storybook/test
+ if (['solid', 'qwik'].includes(rendererId)) {
+ addonPackages.push('@storybook/testing-library');
+ } else {
+ addonPackages.push('@storybook/test');
+ }
+
if (hasInteractiveStories(rendererId)) {
addons.push('@storybook/addon-interactions');
addonPackages.push('@storybook/addon-interactions');
-
- // TODO: migrate template stories in solid and qwik to use @storybook/test
- if (['solid', 'qwik'].includes(rendererId)) {
- addonPackages.push('@storybook/testing-library');
- } else {
- addonPackages.push('@storybook/test');
- }
}
const files = await fse.readdir(process.cwd());
diff --git a/code/lib/cli/src/generators/configure.test.ts b/code/lib/cli/src/generators/configure.test.ts
index 3e4076f4da43..c65710124faf 100644
--- a/code/lib/cli/src/generators/configure.test.ts
+++ b/code/lib/cli/src/generators/configure.test.ts
@@ -128,7 +128,6 @@ describe('configurePreview', () => {
"/** @type { import('@storybook/react').Preview } */
const preview = {
parameters: {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
@@ -159,7 +158,6 @@ describe('configurePreview', () => {
const preview: Preview = {
parameters: {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
@@ -210,7 +208,6 @@ describe('configurePreview', () => {
const preview: Preview = {
parameters: {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
diff --git a/code/lib/cli/src/generators/configure.ts b/code/lib/cli/src/generators/configure.ts
index bbc9992be1ed..38cd265df83c 100644
--- a/code/lib/cli/src/generators/configure.ts
+++ b/code/lib/cli/src/generators/configure.ts
@@ -152,7 +152,6 @@ export async function configurePreview(options: ConfigurePreviewOptions) {
: ''
}const preview${isTypescript ? ': Preview' : ''} = {
parameters: {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
diff --git a/code/lib/core-events/src/errors/preview-errors.ts b/code/lib/core-events/src/errors/preview-errors.ts
index 50cb0609861a..26544d7efd8e 100644
--- a/code/lib/core-events/src/errors/preview-errors.ts
+++ b/code/lib/core-events/src/errors/preview-errors.ts
@@ -63,7 +63,7 @@ export class ImplicitActionsDuringRendering extends StorybookError {
template() {
return dedent`
- We detected that you use an implicit action arg during ${this.data.phase} of your story.
+ We detected that you use an implicit action arg while ${this.data.phase} of your story.
${this.data.deprecated ? `\nThis is deprecated and won't work in Storybook 8 anymore.\n` : ``}
Please provide an explicit spy to your args like this:
import { fn } from '@storybook/test';
diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts
index 5f9f98d7ec8e..efdf01f0a45d 100644
--- a/code/lib/core-events/src/errors/server-errors.ts
+++ b/code/lib/core-events/src/errors/server-errors.ts
@@ -120,6 +120,8 @@ export class CouldNotEvaluateFrameworkError extends StorybookError {
}
}
+// this error is not used anymore, but we keep it to maintain unique its error code
+// which is used for telemetry
export class ConflictingStaticDirConfigError extends StorybookError {
readonly category = Category.CORE_SERVER;
@@ -138,7 +140,6 @@ export class ConflictingStaticDirConfigError extends StorybookError {
`;
}
}
-
export class InvalidStoriesEntryError extends StorybookError {
readonly category = Category.CORE_COMMON;
diff --git a/code/lib/core-events/src/index.ts b/code/lib/core-events/src/index.ts
index d8d6c41c01d3..6d98e6291200 100644
--- a/code/lib/core-events/src/index.ts
+++ b/code/lib/core-events/src/index.ts
@@ -38,6 +38,8 @@ enum events {
STORY_RENDER_PHASE_CHANGED = 'storyRenderPhaseChanged',
// Emitted when the play function throws
PLAY_FUNCTION_THREW_EXCEPTION = 'playFunctionThrewException',
+ // Emitted when there were unhandled errors while playing the story
+ UNHANDLED_ERRORS_WHILE_PLAYING = 'unhandledErrorsWhilePlaying',
// Tell the story store to update (a subset of) a stories arg values
UPDATE_STORY_ARGS = 'updateStoryArgs',
// The values of a stories args just changed
@@ -88,6 +90,7 @@ export const {
GLOBALS_UPDATED,
NAVIGATE_URL,
PLAY_FUNCTION_THREW_EXCEPTION,
+ UNHANDLED_ERRORS_WHILE_PLAYING,
PRELOAD_ENTRIES,
PREVIEW_BUILDER_PROGRESS,
PREVIEW_KEYDOWN,
@@ -124,10 +127,6 @@ export const {
TELEMETRY_ERROR,
} = events;
-// Used to break out of the current render without showing a redbox
-// eslint-disable-next-line local-rules/no-uncategorized-errors
-export const IGNORED_EXCEPTION = new Error('ignoredException');
-
export interface WhatsNewCache {
lastDismissedPost?: string;
lastReadPost?: string;
diff --git a/code/lib/core-server/src/build-static.ts b/code/lib/core-server/src/build-static.ts
index 683da79eb0f1..2ae75f747e5d 100644
--- a/code/lib/core-server/src/build-static.ts
+++ b/code/lib/core-server/src/build-static.ts
@@ -94,16 +94,14 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption
build,
});
- const [features, core, staticDirs, indexers, deprecatedStoryIndexers, stories, docsOptions] =
- await Promise.all([
- presets.apply('features'),
- presets.apply('core'),
- presets.apply('staticDirs'),
- presets.apply('experimental_indexers', []),
- presets.apply('storyIndexers', []),
- presets.apply('stories'),
- presets.apply('docs', {}),
- ]);
+ const [features, core, staticDirs, indexers, stories, docsOptions] = await Promise.all([
+ presets.apply('features'),
+ presets.apply('core'),
+ presets.apply('staticDirs'),
+ presets.apply('experimental_indexers', []),
+ presets.apply('stories'),
+ presets.apply('docs', {}),
+ ]);
if (features?.storyStoreV7 === false) {
deprecate(
@@ -150,7 +148,6 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption
const normalizedStories = normalizeStories(stories, directories);
const generator = new StoryIndexGenerator(normalizedStories, {
...directories,
- storyIndexers: deprecatedStoryIndexers,
indexers,
docs: docsOptions,
storyStoreV7: !!features?.storyStoreV7,
diff --git a/code/lib/core-server/src/presets/common-preset.ts b/code/lib/core-server/src/presets/common-preset.ts
index e1248f1f8dd1..cb68267391fe 100644
--- a/code/lib/core-server/src/presets/common-preset.ts
+++ b/code/lib/core-server/src/presets/common-preset.ts
@@ -46,7 +46,7 @@ export const staticDirs: PresetPropertyFn<'staticDirs'> = async (values = []) =>
export const favicon = async (
value: string | undefined,
- options: Pick
+ options: Pick
) => {
if (value) {
return value;
@@ -191,7 +191,7 @@ export const features: PresetProperty<'features'> = async (existing) => ({
storyStoreV7: true,
argTypeTargetsV7: true,
legacyDecoratorFileOrder: false,
- disallowImplicitActionsInRenderV8: false,
+ disallowImplicitActionsInRenderV8: true,
});
export const csfIndexer: Indexer = {
diff --git a/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts b/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
index 1fa90d63d8b8..bc161fff6ffb 100644
--- a/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
+++ b/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
@@ -42,7 +42,6 @@ const getStorySortParameterMock = vi.mocked(getStorySortParameter);
const options: StoryIndexGeneratorOptions = {
configDir: path.join(__dirname, '__mockdata__'),
workingDir: path.join(__dirname, '__mockdata__'),
- storyIndexers: [],
indexers: [csfIndexer],
storyStoreV7: true,
docs: { defaultName: 'docs', autodocs: false },
diff --git a/code/lib/core-server/src/utils/StoryIndexGenerator.ts b/code/lib/core-server/src/utils/StoryIndexGenerator.ts
index d8f4e8ba95ed..96e72091073a 100644
--- a/code/lib/core-server/src/utils/StoryIndexGenerator.ts
+++ b/code/lib/core-server/src/utils/StoryIndexGenerator.ts
@@ -11,20 +11,17 @@ import type {
DocsIndexEntry,
ComponentTitle,
NormalizedStoriesSpecifier,
- StoryIndexer,
DocsOptions,
Path,
Tag,
StoryIndex,
StoryName,
Indexer,
- IndexerOptions,
- DeprecatedIndexer,
StorybookConfigRaw,
} from '@storybook/types';
import { userOrAutoTitleFromSpecifier, sortStoriesV7 } from '@storybook/preview-api';
import { commonGlobOptions, normalizeStoryPath } from '@storybook/core-common';
-import { deprecate, logger, once } from '@storybook/node-logger';
+import { logger, once } from '@storybook/node-logger';
import { getStorySortParameter } from '@storybook/csf-tools';
import { storyNameFromExport, toId } from '@storybook/csf';
import { analyze } from '@storybook/docs-mdx';
@@ -53,7 +50,6 @@ export type StoryIndexGeneratorOptions = {
workingDir: Path;
configDir: Path;
storyStoreV7: boolean;
- storyIndexers: StoryIndexer[];
indexers: Indexer[];
docs: DocsOptions;
build?: StorybookConfigRaw['build'];
@@ -284,25 +280,10 @@ export class StoryIndexGenerator {
return title;
};
- const indexer = (this.options.indexers as StoryIndexer[])
- .concat(this.options.storyIndexers)
- .find((ind) => ind.test.exec(absolutePath));
+ const indexer = this.options.indexers.find((ind) => ind.test.exec(absolutePath));
invariant(indexer, `No matching indexer found for ${absolutePath}`);
- if (indexer.indexer) {
- deprecate(
- dedent`'storyIndexers' is deprecated, please use 'experimental_indexers' instead. Found a deprecated indexer with matcher: ${indexer.test}
- - Refer to the migration guide at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storyindexers-is-replaced-with-experimental_indexers`
- );
- return this.extractStoriesFromDeprecatedIndexer({
- indexer: indexer.indexer,
- indexerOptions: { makeTitle: defaultMakeTitle },
- absolutePath,
- importPath,
- });
- }
-
const indexInputs = await indexer.createIndex(absolutePath, { makeTitle: defaultMakeTitle });
const entries: ((StoryIndexEntryWithMetaId | DocsCacheEntry) & { tags: Tag[] })[] =
@@ -362,69 +343,6 @@ export class StoryIndexGenerator {
};
}
- async extractStoriesFromDeprecatedIndexer({
- indexer,
- indexerOptions,
- absolutePath,
- importPath,
- }: {
- indexer: DeprecatedIndexer['indexer'];
- indexerOptions: IndexerOptions;
- absolutePath: Path;
- importPath: Path;
- }) {
- const csf = await indexer(absolutePath, indexerOptions);
-
- const entries = [];
-
- const componentTags = csf.meta.tags || [];
- csf.stories.forEach(({ id, name, tags: storyTags, parameters }) => {
- if (!parameters?.docsOnly) {
- const tags = (csf.meta.tags ?? []).concat(storyTags ?? [], 'story');
- invariant(csf.meta.title);
- entries.push({
- id,
- title: csf.meta.title,
- name,
- importPath,
- tags,
- type: 'story',
- // We need to keep track of the csf meta id so we know the component id when referencing docs below in `extractDocs`
- metaId: csf.meta.id,
- });
- }
- });
-
- if (csf.stories.length) {
- const { autodocs } = this.options.docs;
- const componentAutodocs = componentTags.includes(AUTODOCS_TAG);
- const autodocsOptedIn = autodocs === true || (autodocs === 'tag' && componentAutodocs);
- // We need a docs entry attached to the CSF file if either:
- // a) it is a stories.mdx transpiled to CSF, OR
- // b) we have docs page enabled for this file
- if (componentTags.includes(STORIES_MDX_TAG) || autodocsOptedIn) {
- const name = this.options.docs.defaultName ?? 'Docs';
- invariant(csf.meta.title, 'expected a title property in csf.meta');
- const id = toId(csf.meta.id || csf.meta.title, name);
- entries.unshift({
- id,
- title: csf.meta.title,
- name,
- importPath,
- type: 'docs',
- tags: [
- ...componentTags,
- 'docs',
- ...(autodocsOptedIn && !componentAutodocs ? [AUTODOCS_TAG] : []),
- ],
- storiesImports: [],
- });
- }
- }
-
- return { entries, type: 'stories', dependents: [] } as StoriesCacheEntry;
- }
-
async extractDocs(specifier: NormalizedStoriesSpecifier, absolutePath: Path) {
const relativePath = path.relative(this.options.workingDir, absolutePath);
try {
diff --git a/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts b/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
index e76fd6b277b6..451a350755b2 100644
--- a/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
+++ b/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
@@ -15,7 +15,6 @@ vi.mock('@storybook/node-logger');
const options: StoryIndexGeneratorOptions = {
configDir: path.join(__dirname, '..', '__mockdata__'),
workingDir: path.join(__dirname, '..', '__mockdata__'),
- storyIndexers: [],
indexers: [],
storyStoreV7: true,
docs: { defaultName: 'docs', autodocs: false },
diff --git a/code/lib/core-server/src/utils/getStoryIndexGenerator.ts b/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
index 810b95244c72..078ddcb012d4 100644
--- a/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
+++ b/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
@@ -23,14 +23,12 @@ export async function getStoryIndexGenerator(
workingDir,
};
const stories = options.presets.apply('stories');
- const deprecatedStoryIndexers = options.presets.apply('storyIndexers', []);
const indexers = options.presets.apply('experimental_indexers', []);
const docsOptions = options.presets.apply('docs', {});
const normalizedStories = normalizeStories(await stories, directories);
const generator = new StoryIndexGenerator(normalizedStories, {
...directories,
- storyIndexers: await deprecatedStoryIndexers,
indexers: await indexers,
docs: await docsOptions,
workingDir,
diff --git a/code/lib/core-server/src/utils/server-statics.ts b/code/lib/core-server/src/utils/server-statics.ts
index aa687c5bcc88..2a0b93e1ca41 100644
--- a/code/lib/core-server/src/utils/server-statics.ts
+++ b/code/lib/core-server/src/utils/server-statics.ts
@@ -69,7 +69,7 @@ export const parseStaticDir = async (arg: string) => {
throw new Error(
dedent(chalk`
Failed to load static files, no such directory: {cyan ${staticPath}}
- Make sure this directory exists, or omit the {bold -s (--static-dir)} option.
+ Make sure this directory exists.
`)
);
}
diff --git a/code/lib/core-server/src/utils/stories-json.test.ts b/code/lib/core-server/src/utils/stories-json.test.ts
index 61fb64b71649..8d1849e40380 100644
--- a/code/lib/core-server/src/utils/stories-json.test.ts
+++ b/code/lib/core-server/src/utils/stories-json.test.ts
@@ -42,7 +42,6 @@ const getInitializedStoryIndexGenerator = async (
inputNormalizedStories = normalizedStories
) => {
const options: StoryIndexGeneratorOptions = {
- storyIndexers: [],
indexers: [csfIndexer],
configDir: workingDir,
workingDir,
diff --git a/code/lib/csf-tools/src/enrichCsf.test.ts b/code/lib/csf-tools/src/enrichCsf.test.ts
index d9871e935226..562cacd8c04b 100644
--- a/code/lib/csf-tools/src/enrichCsf.test.ts
+++ b/code/lib/csf-tools/src/enrichCsf.test.ts
@@ -641,7 +641,7 @@ describe('enrichCsf', () => {
title: 'Button',
parameters: {
foo: 'bar',
- docs: { inlineStories: true }
+ docs: { story: { inline: true } }
}
}
export const Basic = () => React.createElement(Button);
@@ -652,7 +652,7 @@ describe('enrichCsf', () => {
title: 'Button',
parameters: {
foo: 'bar',
- docs: { inlineStories: true }
+ docs: { story: { inline: true } }
}
}
export const Basic = () =>
@@ -665,7 +665,9 @@ describe('enrichCsf', () => {
parameters: {
foo: 'bar',
docs: {
- inlineStories: true,
+ story: {
+ inline: true
+ },
description: {
component: "The most basic button"
}
diff --git a/code/lib/csf-tools/src/getStorySortParameter.test.ts b/code/lib/csf-tools/src/getStorySortParameter.test.ts
index 4d6a8b8cc817..bd34207de7c0 100644
--- a/code/lib/csf-tools/src/getStorySortParameter.test.ts
+++ b/code/lib/csf-tools/src/getStorySortParameter.test.ts
@@ -292,7 +292,6 @@ export default {
expect(
getStorySortParameter(dedent`
const config = {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
@@ -310,7 +309,6 @@ export default {
expect(
getStorySortParameter(dedent`
const parameters = {
- actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
diff --git a/code/lib/instrumenter/src/instrumenter.test.ts b/code/lib/instrumenter/src/instrumenter.test.ts
index a2266ba8ac8c..980c930ab3b2 100644
--- a/code/lib/instrumenter/src/instrumenter.test.ts
+++ b/code/lib/instrumenter/src/instrumenter.test.ts
@@ -1,7 +1,6 @@
/* eslint-disable no-underscore-dangle */
import { addons, mockChannel } from '@storybook/preview-api';
import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest';
-import { logger } from '@storybook/client-logger';
import {
FORCE_REMOUNT,
SET_CURRENT_STORY,
@@ -418,23 +417,23 @@ describe('Instrumenter', () => {
);
});
- it('catches thrown errors and throws an ignoredException instead', () => {
+ it('rethrows errors', () => {
const { fn } = instrument({
fn: () => {
throw new Error('Boom!');
},
});
- expect(fn).toThrow('ignoredException');
+ expect(fn).toThrow('Boom!');
});
- it('catches nested exceptions and throws an ignoredException instead', () => {
+ it('catches nested exceptions and rethrows', () => {
const { fn1, fn2 } = instrument({
fn1: (_: any) => {},
fn2: () => {
throw new Error('Boom!');
},
});
- expect(() => fn1(fn2())).toThrow('ignoredException');
+ expect(() => fn1(fn2())).toThrow('Boom!');
});
it('bubbles child exceptions up to parent (in callback)', () => {
@@ -448,15 +447,19 @@ describe('Instrumenter', () => {
vi.spyOn(instrumented, 'fn1');
const { fn1, fn2 } = instrumented;
- expect(() =>
+ let error;
+ try {
fn1(() => {
fn2();
- })
- ).toThrow('ignoredException');
+ });
+ } catch (e) {
+ error = e;
+ }
expect(fn1).toHaveBeenCalled();
- expect(logger.warn).toHaveBeenCalledWith(new Error('Boom!'));
- expect((logger.warn as any).mock.calls[0][0].callId).toBe('kind--story [0] fn1 [0] fn2');
+ expect(error).toEqual(new Error('Boom!'));
+ // @ts-expect-error callId is what is tested
+ expect(error.callId).toBe('kind--story [0] fn1 [0] fn2');
});
it("re-throws anything that isn't an error", () => {
diff --git a/code/lib/instrumenter/src/instrumenter.ts b/code/lib/instrumenter/src/instrumenter.ts
index 51d6989a9c7a..ef171b4bcd09 100644
--- a/code/lib/instrumenter/src/instrumenter.ts
+++ b/code/lib/instrumenter/src/instrumenter.ts
@@ -2,11 +2,10 @@
import type { Channel } from '@storybook/channels';
import { addons } from '@storybook/preview-api';
import type { StoryId } from '@storybook/types';
-import { once, logger } from '@storybook/client-logger';
+import { once } from '@storybook/client-logger';
import './typings.d.ts';
import {
FORCE_REMOUNT,
- IGNORED_EXCEPTION,
SET_CURRENT_STORY,
STORY_RENDER_PHASE_CHANGED,
} from '@storybook/core-events';
@@ -403,10 +402,6 @@ export class Instrumenter {
}
invoke(fn: Function, object: Record, call: Call, options: Options) {
- // TODO this doesnt work because the abortSignal we have here is the newly created one
- // const { abortSignal } = global.window.__STORYBOOK_PREVIEW__ || {};
- // if (abortSignal && abortSignal.aborted) throw IGNORED_EXCEPTION;
-
const { callRefsByResult, renderPhase } = this.getState(call.storyId);
// Map complex values to a JSON-serializable representation.
@@ -475,7 +470,7 @@ export class Instrumenter {
diff = undefined,
actual = undefined,
expected = undefined,
- } = processError(e);
+ } = e.name === 'AssertionError' ? processError(e) : e;
const exception = { name, message, stack, callId, showDiff, diff, actual, expected };
this.update({ ...info, status: CallStates.ERROR, exception });
@@ -495,13 +490,6 @@ export class Instrumenter {
}
throw e;
}
-
- // We need to throw to break out of the play function, but we don't want to trigger a redbox
- // so we throw an ignoredException, which is caught and silently ignored by Storybook.
- if (e !== alreadyCompletedException) {
- logger.warn(e);
- throw IGNORED_EXCEPTION;
- }
}
throw e;
};
diff --git a/code/lib/manager-api/src/modules/channel.ts b/code/lib/manager-api/src/modules/channel.ts
index 0ab1dc910087..64df9b32a4ce 100644
--- a/code/lib/manager-api/src/modules/channel.ts
+++ b/code/lib/manager-api/src/modules/channel.ts
@@ -1,5 +1,4 @@
/* eslint-disable no-param-reassign */
-import { STORIES_COLLAPSE_ALL, STORIES_EXPAND_ALL } from '@storybook/core-events';
import type { Listener } from '@storybook/channels';
import type { API_Provider } from '@storybook/types';
@@ -38,16 +37,6 @@ export interface SubAPI {
* @param handler - The callback function to be called when the event is emitted.
*/
once: (type: string, handler: Listener) => void;
- /**
- * Emits an event to collapse all stories in the UI.
- * @deprecated Use `emit(STORIES_COLLAPSE_ALL)` instead. This API will be removed in Storybook 8.0.
- */
- collapseAll: () => void;
- /**
- * Emits an event to expand all stories in the UI.
- * @deprecated Use `emit(STORIES_EXPAND_ALL)` instead. This API will be removed in Storybook 8.0.
- */
- expandAll: () => void;
}
export type SubState = Record;
@@ -75,12 +64,6 @@ export const init: ModuleFn = ({ provider }) => {
}
provider.channel?.emit(type, data, ...args);
},
- collapseAll: () => {
- api.emit(STORIES_COLLAPSE_ALL, {});
- },
- expandAll: () => {
- api.emit(STORIES_EXPAND_ALL);
- },
};
return { api, state: {} };
};
diff --git a/code/lib/manager-api/src/modules/settings.ts b/code/lib/manager-api/src/modules/settings.ts
index aa4924474cd2..34a06c6c6dcd 100644
--- a/code/lib/manager-api/src/modules/settings.ts
+++ b/code/lib/manager-api/src/modules/settings.ts
@@ -19,13 +19,6 @@ export interface SubAPI {
* @returns A boolean indicating whether the settings screen is active.
*/
isSettingsScreenActive: () => boolean;
- /**
- * Navigates to the specified settings page.
- * @param path - The path of the settings page to navigate to. The path should include the `/settings` prefix.
- * @example navigateToSettingsPage(`/settings/about`).
- * @deprecated Use `changeSettingsTab` instead.
- */
- navigateToSettingsPage: (path: string) => Promise;
}
export interface SubState {
@@ -53,17 +46,6 @@ export const init: ModuleFn = ({ store, navigate, fullAPI }):
navigate(`/settings/${path}`);
},
isSettingsScreenActive,
- navigateToSettingsPage: async (path) => {
- if (!isSettingsScreenActive()) {
- const { settings, storyId } = store.getState();
-
- await store.setState({
- settings: { ...settings, lastTrackedStoryId: storyId },
- });
- }
-
- navigate(path);
- },
retrieveSelection() {
const { settings } = store.getState();
diff --git a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
index 84a5bd782522..79188c8c8d92 100644
--- a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
+++ b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
@@ -12,7 +12,6 @@ import {
FORCE_REMOUNT,
FORCE_RE_RENDER,
GLOBALS_UPDATED,
- IGNORED_EXCEPTION,
PREVIEW_KEYDOWN,
RESET_STORY_ARGS,
SET_CURRENT_STORY,
@@ -130,6 +129,9 @@ beforeEach(() => {
projectAnnotations.decorators[0].mockClear();
docsRenderer.render.mockClear();
vi.mocked(logger.warn).mockClear();
+ // eslint-disable-next-line no-console
+ vi.mocked(console.error).mockReset();
+
mockStoryIndex.mockReset().mockReturnValue(storyIndex);
addons.setChannel(mockChannel as any);
@@ -629,24 +631,6 @@ describe('PreviewWeb', () => {
expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');
});
-
- it('does not show error display if the render function throws IGNORED_EXCEPTION', async () => {
- document.location.search = '?id=component-one--a';
- projectAnnotations.renderToCanvas.mockImplementation(() => {
- throw IGNORED_EXCEPTION;
- });
-
- const preview = new PreviewWeb();
- await preview.initialize({ importFn, getProjectAnnotations });
-
- await waitForRender();
-
- expect(mockChannel.emit).toHaveBeenCalledWith(
- STORY_THREW_EXCEPTION,
- serializeError(IGNORED_EXCEPTION)
- );
- expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();
- });
});
describe('CSF docs entries', () => {
diff --git a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts
index b50489ecb785..ad704d43382b 100644
--- a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts
+++ b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts
@@ -1,3 +1,4 @@
+/* eslint-disable no-console */
import type {
Renderer,
RenderContext,
@@ -12,11 +13,11 @@ import type {
ViewMode,
} from '@storybook/types';
import type { Channel } from '@storybook/channels';
-import { logger } from '@storybook/client-logger';
import {
STORY_RENDER_PHASE_CHANGED,
STORY_RENDERED,
PLAY_FUNCTION_THREW_EXCEPTION,
+ UNHANDLED_ERRORS_WHILE_PLAYING,
} from '@storybook/core-events';
import type { StoryStore } from '../../store';
import type { Render, RenderType } from './Render';
@@ -218,22 +219,43 @@ export class StoryRender implements Render = new Set();
+ const onError = (event: ErrorEvent | PromiseRejectionEvent) =>
+ unhandledErrors.add('error' in event ? event.error : event.reason);
+
// The phase should be 'rendering' but it might be set to 'aborted' by another render cycle
if (this.renderOptions.autoplay && forceRemount && playFunction && this.phase !== 'errored') {
+ window.addEventListener('error', onError);
+ window.addEventListener('unhandledrejection', onError);
this.disableKeyListeners = true;
try {
await this.runPhase(abortSignal, 'playing', async () => {
await playFunction(renderContext.storyContext);
});
- await this.runPhase(abortSignal, 'played');
+ if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {
+ await this.runPhase(abortSignal, 'errored');
+ } else {
+ await this.runPhase(abortSignal, 'played');
+ }
} catch (error) {
- logger.error(error);
await this.runPhase(abortSignal, 'errored', async () => {
this.channel.emit(PLAY_FUNCTION_THREW_EXCEPTION, serializeError(error));
});
if (this.story.parameters.throwPlayFunctionExceptions !== false) throw error;
+ console.error(error);
+ }
+ if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {
+ this.channel.emit(
+ UNHANDLED_ERRORS_WHILE_PLAYING,
+ Array.from(unhandledErrors).map(serializeError)
+ );
}
this.disableKeyListeners = false;
+ window.removeEventListener('unhandledrejection', onError);
+ window.removeEventListener('error', onError);
if (abortSignal.aborted) return;
}
diff --git a/code/lib/preview-api/vitest.config.ts b/code/lib/preview-api/vitest.config.ts
index ddec70e554d4..622642938f21 100644
--- a/code/lib/preview-api/vitest.config.ts
+++ b/code/lib/preview-api/vitest.config.ts
@@ -6,7 +6,7 @@ export default mergeConfig(
vitestCommonConfig,
defineConfig({
test: {
- environment: 'node',
+ environment: 'jsdom',
name: __dirname.split(sep).slice(-2).join(posix.sep),
},
})
diff --git a/code/lib/types/src/modules/addons.ts b/code/lib/types/src/modules/addons.ts
index 6002d713e52c..49d97e4c3a11 100644
--- a/code/lib/types/src/modules/addons.ts
+++ b/code/lib/types/src/modules/addons.ts
@@ -305,11 +305,6 @@ export type BaseStory =
export interface Addon_RenderOptions {
active: boolean;
- /**
- * @deprecated You should not use key anymore as of Storybook 7.2 this render method is invoked as a React component.
- * This property will be removed in 8.0.
- * */
- key?: unknown;
}
export type Addon_Type =
@@ -533,9 +528,4 @@ export enum Addon_TypesEnum {
* @unstable This will get replaced with a new API in 8.0, use at your own risk.
*/
experimental_SIDEBAR_TOP = 'sidebar-top',
-
- /**
- * @deprecated This property does nothing, and will be removed in Storybook 8.0.
- */
- NOTES_ELEMENT = 'notes-element',
}
diff --git a/code/lib/types/src/modules/core-common.ts b/code/lib/types/src/modules/core-common.ts
index 1affaa649a9b..a189c8fe5f54 100644
--- a/code/lib/types/src/modules/core-common.ts
+++ b/code/lib/types/src/modules/core-common.ts
@@ -7,7 +7,7 @@ import type { Router } from 'express';
import type { Server } from 'http';
import type { PackageJson as PackageJsonFromTypeFest } from 'type-fest';
-import type { StoriesEntry, Indexer, StoryIndexer } from './indexer';
+import type { StoriesEntry, Indexer } from './indexer';
/**
* ⚠️ This file contains internal WIP types they MUST NOT be exported outside this package for now!
@@ -172,10 +172,6 @@ export interface CLIOptions {
host?: string;
initialPath?: string;
exactPort?: boolean;
- /**
- * @deprecated Use 'staticDirs' Storybook Configuration option instead
- */
- staticDir?: string[];
configDir?: string;
https?: boolean;
sslCa?: string[];
@@ -420,8 +416,6 @@ export interface StorybookConfigRaw {
previewAnnotations?: Entry[];
- storyIndexers?: StoryIndexer[];
-
experimental_indexers?: Indexer[];
docs?: DocsOptions;
@@ -513,12 +507,6 @@ export interface StorybookConfig {
*/
previewAnnotations?: PresetValue;
- /**
- * Process CSF files for the story index.
- * @deprecated use {@link experimental_indexers} instead
- */
- storyIndexers?: PresetValue;
-
/**
* Process CSF files for the story index.
*/
diff --git a/code/lib/types/src/modules/indexer.ts b/code/lib/types/src/modules/indexer.ts
index 4f0838bba05e..56d435cdb533 100644
--- a/code/lib/types/src/modules/indexer.ts
+++ b/code/lib/types/src/modules/indexer.ts
@@ -67,22 +67,8 @@ export type Indexer = BaseIndexer & {
* @returns A promise that resolves to an array of {@link IndexInput} objects.
*/
createIndex: (fileName: string, options: IndexerOptions) => Promise;
- /**
- * @deprecated Use {@link index} instead
- */
- indexer?: never;
-};
-
-export type DeprecatedIndexer = BaseIndexer & {
- indexer: (fileName: string, options: IndexerOptions) => Promise;
- createIndex?: never;
};
-/**
- * @deprecated Use {@link Indexer} instead
- */
-export type StoryIndexer = Indexer | DeprecatedIndexer;
-
export interface BaseIndexEntry {
id: StoryId;
name: StoryName;
diff --git a/code/package.json b/code/package.json
index 4d5db16e620c..d9c52efe757e 100644
--- a/code/package.json
+++ b/code/package.json
@@ -229,6 +229,7 @@
"react-dom": "^18.2.0",
"semver": "^7.3.7",
"serve-static": "^1.14.1",
+ "svelte": "^5.0.0-next.28",
"trash": "^7.0.0",
"ts-dedent": "^2.0.0",
"ts-node": "^10.9.1",
@@ -308,5 +309,6 @@
"Dependency Upgrades"
]
]
- }
+ },
+ "deferredNextVersion": "8.0.0-alpha.8"
}
diff --git a/code/renderers/html/src/public-types.ts b/code/renderers/html/src/public-types.ts
index e0b41f5bc620..2dff13d9aa9b 100644
--- a/code/renderers/html/src/public-types.ts
+++ b/code/renderers/html/src/public-types.ts
@@ -35,17 +35,6 @@ export type StoryFn = AnnotatedStoryFn;
*/
export type StoryObj = StoryAnnotations;
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
export type StoryContext = GenericStoryContext;
diff --git a/code/renderers/html/src/types.ts b/code/renderers/html/src/types.ts
index e8f264aed808..c6152653b11b 100644
--- a/code/renderers/html/src/types.ts
+++ b/code/renderers/html/src/types.ts
@@ -14,10 +14,6 @@ export interface ShowErrorArgs {
description: string;
}
-/**
- * @deprecated Use `HtmlRenderer` instead.
- */
-export type HtmlFramework = HtmlRenderer;
export interface HtmlRenderer extends WebRenderer {
component: string | HTMLElement | ArgsStoryFn;
storyResult: StoryFnHtmlReturnType;
diff --git a/code/renderers/html/template/cli/js/Button.stories.js b/code/renderers/html/template/cli/js/Button.stories.js
index 81d0ba1fb150..5898325eb572 100644
--- a/code/renderers/html/template/cli/js/Button.stories.js
+++ b/code/renderers/html/template/cli/js/Button.stories.js
@@ -1,3 +1,4 @@
+import { fn } from '@storybook/test';
import { createButton } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -19,6 +20,8 @@ export default {
options: ['small', 'medium', 'large'],
},
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
diff --git a/code/renderers/html/template/cli/ts-3-8/Button.stories.ts b/code/renderers/html/template/cli/ts-3-8/Button.stories.ts
index f91d91ae731e..90ce057cae50 100644
--- a/code/renderers/html/template/cli/ts-3-8/Button.stories.ts
+++ b/code/renderers/html/template/cli/ts-3-8/Button.stories.ts
@@ -1,4 +1,5 @@
import type { StoryObj, Meta } from '@storybook/html';
+import { fn } from '@storybook/test';
import type { ButtonProps } from './Button';
import { createButton } from './Button';
@@ -21,6 +22,8 @@ const meta: Meta = {
options: ['small', 'medium', 'large'],
},
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
export default meta;
diff --git a/code/renderers/html/template/cli/ts-3-8/Header.ts b/code/renderers/html/template/cli/ts-3-8/Header.ts
index 7bee76259651..5c6cec5c81bc 100644
--- a/code/renderers/html/template/cli/ts-3-8/Header.ts
+++ b/code/renderers/html/template/cli/ts-3-8/Header.ts
@@ -3,9 +3,9 @@ import { createButton } from './Button';
export interface HeaderProps {
user?: { name: string };
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const createHeader = ({ user, onLogout, onLogin, onCreateAccount }: HeaderProps) => {
diff --git a/code/renderers/html/template/cli/ts-4-9/Button.stories.ts b/code/renderers/html/template/cli/ts-4-9/Button.stories.ts
index 2a86ecbec3b0..a9a7ff7b3bc5 100644
--- a/code/renderers/html/template/cli/ts-4-9/Button.stories.ts
+++ b/code/renderers/html/template/cli/ts-4-9/Button.stories.ts
@@ -1,4 +1,5 @@
import type { StoryObj, Meta } from '@storybook/html';
+import { fn } from '@storybook/test';
import type { ButtonProps } from './Button';
import { createButton } from './Button';
@@ -21,6 +22,8 @@ const meta = {
options: ['small', 'medium', 'large'],
},
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
} satisfies Meta;
export default meta;
diff --git a/code/renderers/html/template/cli/ts-4-9/Header.ts b/code/renderers/html/template/cli/ts-4-9/Header.ts
index 7bee76259651..5c6cec5c81bc 100644
--- a/code/renderers/html/template/cli/ts-4-9/Header.ts
+++ b/code/renderers/html/template/cli/ts-4-9/Header.ts
@@ -3,9 +3,9 @@ import { createButton } from './Button';
export interface HeaderProps {
user?: { name: string };
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const createHeader = ({ user, onLogout, onLogin, onCreateAccount }: HeaderProps) => {
diff --git a/code/renderers/preact/src/public-types.ts b/code/renderers/preact/src/public-types.ts
index b8f62d0dfca6..bb0f10559e95 100644
--- a/code/renderers/preact/src/public-types.ts
+++ b/code/renderers/preact/src/public-types.ts
@@ -35,17 +35,6 @@ export type StoryFn = AnnotatedStoryFn;
*/
export type StoryObj = StoryAnnotations;
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
export type StoryContext = GenericStoryContext;
diff --git a/code/renderers/preact/src/types.ts b/code/renderers/preact/src/types.ts
index 233528349a1e..1a8e545c8540 100644
--- a/code/renderers/preact/src/types.ts
+++ b/code/renderers/preact/src/types.ts
@@ -10,13 +10,6 @@ export interface ShowErrorArgs {
description: string;
}
-/**
- * @dep
- */
-/**
- * @deprecated Use `PreactRenderer` instead.
- */
-export type PreactFramework = PreactRenderer;
export interface PreactRenderer extends WebRenderer {
component: AnyComponent;
storyResult: StoryFnPreactReturnType;
diff --git a/code/renderers/preact/template/cli/Button.stories.jsx b/code/renderers/preact/template/cli/Button.stories.jsx
index 53ce0d71dd44..5017c7144bee 100644
--- a/code/renderers/preact/template/cli/Button.stories.jsx
+++ b/code/renderers/preact/template/cli/Button.stories.jsx
@@ -1,3 +1,4 @@
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -9,6 +10,8 @@ export default {
backgroundColor: { control: 'color' },
onClick: { action: 'onClick' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
diff --git a/code/renderers/react/src/public-types.test.tsx b/code/renderers/react/src/public-types.test.tsx
index adf800d85280..2f112ec9f078 100644
--- a/code/renderers/react/src/public-types.test.tsx
+++ b/code/renderers/react/src/public-types.test.tsx
@@ -88,7 +88,7 @@ describe('Args can be provided in multiple ways', () => {
});
});
-it('✅ All void functions are optional', () => {
+it('✅ Void functions are not changed', () => {
interface CmpProps {
label: string;
disabled: boolean;
@@ -106,13 +106,16 @@ it('✅ All void functions are optional', () => {
});
const Basic: StoryObj = {
- args: { disabled: false, onLoading: () =>
,
+ onKeyDown: fn(),
+ onClick: fn(),
+ submitAction: fn(),
+ },
};
- type Expected = ReactStory<
- CmpProps,
- SetOptional
- >;
+ type Expected = ReactStory>;
expectTypeOf(Basic).toEqualTypeOf();
});
diff --git a/code/renderers/react/src/public-types.ts b/code/renderers/react/src/public-types.ts
index 95ad7111a3ea..eaacc7fa14d4 100644
--- a/code/renderers/react/src/public-types.ts
+++ b/code/renderers/react/src/public-types.ts
@@ -11,15 +11,13 @@ import type {
StrictArgs,
ProjectAnnotations,
} from '@storybook/types';
-import type { ComponentProps, ComponentType, JSXElementConstructor } from 'react';
+import type { ComponentProps, ComponentType } from 'react';
import type { SetOptional, Simplify } from 'type-fest';
import type { ReactRenderer } from './types';
export type { Args, ArgTypes, Parameters, StrictArgs } from '@storybook/types';
export type { ReactRenderer };
-type JSXElement = keyof JSX.IntrinsicElements | JSXElementConstructor;
-
/**
* Metadata to configure the stories for a component.
*
@@ -57,7 +55,7 @@ export type StoryObj = [TMetaOrCmpOrArgs] extends [
? StoryAnnotations<
ReactRenderer,
AddMocks,
- SetOptional)>
+ SetOptional
>
: never
: TMetaOrCmpOrArgs extends ComponentType
@@ -74,84 +72,6 @@ type AddMocks = Simplify<{
: TArgs[T];
}>;
-type ActionArgs = {
- // This can be read as: filter TArgs on functions where we can assign a void function to that function.
- // The docs addon argsEnhancers can only safely provide a default value for void functions.
- // Other kind of required functions should be provided by the user.
- [P in keyof TArgs as TArgs[P] extends (...args: any[]) => any
- ? ((...args: any[]) => void) extends TArgs[P]
- ? P
- : never
- : never]: TArgs[P];
-};
-
-/**
- * @deprecated Use `Meta` instead, e.g. ComponentMeta -> Meta.
- *
- * For the common case where a component's stories are simple components that receives args as props:
- *
- * ```tsx
- * export default { ... } as ComponentMeta;
- * ```
- */
-export type ComponentMeta = Meta>;
-
-/**
- * @deprecated Use `StoryFn` instead, e.g. ComponentStoryFn -> StoryFn.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * For the common case where a (CSFv2) story is a simple component that receives args as props:
- *
- * ```tsx
- * const Template: ComponentStoryFn = (args) =>
- * ```
- */
-export type ComponentStoryFn = StoryFn>;
-
-/**
- * @deprecated Use `StoryObj` instead, e.g. ComponentStoryObj -> StoryObj.
- *
- * For the common case where a (CSFv3) story is a simple component that receives args as props:
- *
- * ```tsx
- * const MyStory: ComponentStoryObj = {
- * args: { buttonArg1: 'val' },
- * }
- * ```
- */
-export type ComponentStoryObj = StoryObj>;
-
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
-/**
- * @deprecated Use `StoryFn` instead, e.g. ComponentStory -> StoryFn.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/.
- *
- * For the common case where a (CSFv3) story is a simple component that receives args as props:
- *
- * ```tsx
- * const MyStory: ComponentStory = {
- * args: { buttonArg1: 'val' },
- * }
- * ```
- */
-export type ComponentStory = ComponentStoryFn;
-
-/**
- * @deprecated Use Decorator instead.
- */
-export type DecoratorFn = DecoratorFunction;
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
export type StoryContext = GenericStoryContext;
diff --git a/code/renderers/react/src/testing-api.ts b/code/renderers/react/src/testing-api.ts
index 545147fab2db..385e0dc4c804 100644
--- a/code/renderers/react/src/testing-api.ts
+++ b/code/renderers/react/src/testing-api.ts
@@ -10,7 +10,6 @@ import type {
Store_CSFExports,
StoriesWithPartialProps,
} from '@storybook/types';
-import { deprecate } from '@storybook/client-logger';
import { render } from './render';
import type { Meta } from './public-types';
@@ -37,17 +36,6 @@ export function setProjectAnnotations(
originalSetProjectAnnotations(projectAnnotations);
}
-/** Preserved for users migrating from `@storybook/testing-react`.
- *
- * @deprecated Use setProjectAnnotations instead
- */
-export function setGlobalConfig(
- projectAnnotations: ProjectAnnotations | ProjectAnnotations[]
-) {
- deprecate(`setGlobalConfig is deprecated. Use setProjectAnnotations instead.`);
- setProjectAnnotations(projectAnnotations);
-}
-
// This will not be necessary once we have auto preset loading
const defaultProjectAnnotations: ProjectAnnotations = {
render,
diff --git a/code/renderers/react/src/types.ts b/code/renderers/react/src/types.ts
index 637f1b5a5ebc..b90766013de5 100644
--- a/code/renderers/react/src/types.ts
+++ b/code/renderers/react/src/types.ts
@@ -3,10 +3,6 @@ import type { WebRenderer } from '@storybook/types';
export type { RenderContext, StoryContext } from '@storybook/types';
-/**
- * @deprecated Use `ReactRenderer` instead.
- */
-export type ReactFramework = ReactRenderer;
export interface ReactRenderer extends WebRenderer {
component: ComponentType;
storyResult: StoryFnReactReturnType;
diff --git a/code/renderers/react/template/cli/js/Button.stories.js b/code/renderers/react/template/cli/js/Button.stories.js
index 3a3f67ec8fb4..97b9ec0ed85d 100644
--- a/code/renderers/react/template/cli/js/Button.stories.js
+++ b/code/renderers/react/template/cli/js/Button.stories.js
@@ -1,3 +1,4 @@
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
@@ -14,6 +15,8 @@ export default {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
diff --git a/code/renderers/react/template/cli/ts-3-8/Button.stories.ts b/code/renderers/react/template/cli/ts-3-8/Button.stories.ts
index b65080126a44..18be3ab1aa1d 100644
--- a/code/renderers/react/template/cli/ts-3-8/Button.stories.ts
+++ b/code/renderers/react/template/cli/ts-3-8/Button.stories.ts
@@ -1,4 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
+import { fn } from '@storybook/test';
import { Button } from './Button';
@@ -16,6 +17,8 @@ const meta: Meta = {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
export default meta;
diff --git a/code/renderers/react/template/cli/ts-3-8/Header.tsx b/code/renderers/react/template/cli/ts-3-8/Header.tsx
index 01504601311d..c806ddf023e8 100644
--- a/code/renderers/react/template/cli/ts-3-8/Header.tsx
+++ b/code/renderers/react/template/cli/ts-3-8/Header.tsx
@@ -9,9 +9,9 @@ type User = {
interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
diff --git a/code/renderers/react/template/cli/ts-4-9/Button.stories.ts b/code/renderers/react/template/cli/ts-4-9/Button.stories.ts
index 742c3aa7b029..455a9d8601c9 100644
--- a/code/renderers/react/template/cli/ts-4-9/Button.stories.ts
+++ b/code/renderers/react/template/cli/ts-4-9/Button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
-
+import { fn } from '@storybook/test';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
@@ -16,6 +16,8 @@ const meta = {
argTypes: {
backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
} satisfies Meta;
export default meta;
diff --git a/code/renderers/react/template/cli/ts-4-9/Header.tsx b/code/renderers/react/template/cli/ts-4-9/Header.tsx
index 01504601311d..c806ddf023e8 100644
--- a/code/renderers/react/template/cli/ts-4-9/Header.tsx
+++ b/code/renderers/react/template/cli/ts-4-9/Header.tsx
@@ -9,9 +9,9 @@ type User = {
interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
diff --git a/code/renderers/server/src/public-types.ts b/code/renderers/server/src/public-types.ts
index 17a947a51d3b..5e36d7a64391 100644
--- a/code/renderers/server/src/public-types.ts
+++ b/code/renderers/server/src/public-types.ts
@@ -34,17 +34,6 @@ export type StoryFn = AnnotatedStoryFn;
*/
export type StoryObj = StoryAnnotations;
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
export type { ServerRenderer };
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
diff --git a/code/renderers/server/src/types.ts b/code/renderers/server/src/types.ts
index 4b562f771fb7..c386ec965df0 100644
--- a/code/renderers/server/src/types.ts
+++ b/code/renderers/server/src/types.ts
@@ -5,10 +5,6 @@ export type { RenderContext } from '@storybook/types';
export type StoryFnServerReturnType = any;
export type StoryContext = StoryContextBase;
-/**
- * @deprecated Use `ServerRenderer` instead.
- */
-export type ServerFramework = ServerRenderer;
export interface ServerRenderer extends WebRenderer {
component: string;
storyResult: StoryFnServerReturnType;
diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json
index 2fa0829227db..fa35804f1f78 100644
--- a/code/renderers/svelte/package.json
+++ b/code/renderers/svelte/package.json
@@ -64,7 +64,7 @@
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"expect-type": "^0.15.0",
- "svelte": "^5.0.0-next.22",
+ "svelte": "^5.0.0-next.28",
"svelte-check": "^3.6.1",
"typescript": "^5.3.2"
},
diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts
index b1821b692358..05fc9daf852f 100644
--- a/code/renderers/svelte/src/render.ts
+++ b/code/renderers/svelte/src/render.ts
@@ -36,7 +36,7 @@ function teardown(canvasElement: SvelteRenderer['canvasElement']) {
function createRoot(target: HTMLElement, props: any) {
if ((svelte as any).createRoot) {
// Svelte v5
- return svelte.createRoot(PreviewRender, {
+ return (svelte as any).createRoot(PreviewRender, {
target,
props,
});
diff --git a/code/renderers/svelte/template/cli/ts-3-8/Button.stories.ts b/code/renderers/svelte/template/cli/ts-3-8/Button.stories.ts
index 55f3b1c8e50a..3db95e9d53f3 100644
--- a/code/renderers/svelte/template/cli/ts-3-8/Button.stories.ts
+++ b/code/renderers/svelte/template/cli/ts-3-8/Button.stories.ts
@@ -1,5 +1,4 @@
import type { Meta, StoryObj } from '@storybook/svelte';
-
import Button from './Button.svelte';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
diff --git a/code/renderers/svelte/template/cli/ts-4-9/Button.stories.ts b/code/renderers/svelte/template/cli/ts-4-9/Button.stories.ts
index 119cb87f61d5..1132dd8f75f9 100644
--- a/code/renderers/svelte/template/cli/ts-4-9/Button.stories.ts
+++ b/code/renderers/svelte/template/cli/ts-4-9/Button.stories.ts
@@ -1,5 +1,4 @@
import type { Meta, StoryObj } from '@storybook/svelte';
-
import Button from './Button.svelte';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
diff --git a/code/renderers/vue3/src/public-types.ts b/code/renderers/vue3/src/public-types.ts
index 51e58dc0b089..2bc2653eb0c7 100644
--- a/code/renderers/vue3/src/public-types.ts
+++ b/code/renderers/vue3/src/public-types.ts
@@ -74,17 +74,6 @@ type ComponentPropsOrProps = TCmpOrArgs extends Constructor
? ComponentPropsAndSlots
: TCmpOrArgs;
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
export type StoryContext = GenericStoryContext;
diff --git a/code/renderers/vue3/src/render.ts b/code/renderers/vue3/src/render.ts
index cf27f67357c8..c7051ac847f5 100644
--- a/code/renderers/vue3/src/render.ts
+++ b/code/renderers/vue3/src/render.ts
@@ -1,9 +1,10 @@
-/* eslint-disable local-rules/no-uncategorized-errors */
+/* eslint-disable local-rules/no-uncategorized-errors,no-underscore-dangle */
/* eslint-disable no-param-reassign */
import type { App } from 'vue';
-import { createApp, h, reactive, isVNode, isReactive } from 'vue';
+import { createApp, h, isReactive, isVNode, reactive } from 'vue';
import type { ArgsStoryFn, RenderContext } from '@storybook/types';
import type { Args, StoryContext } from '@storybook/csf';
+import type { PreviewWeb } from '@storybook/preview-api';
import type { StoryFnVueReturnType, StoryID, VueRenderer } from './types';
export const render: ArgsStoryFn = (props, context) => {
@@ -79,7 +80,22 @@ export async function renderToCanvas(
},
});
- vueApp.config.errorHandler = (e: unknown) => showException(e as Error);
+ vueApp.config.errorHandler = (e: unknown, instance, info) => {
+ const preview = (window as Record)
+ .__STORYBOOK_PREVIEW__ as PreviewWeb;
+ const isPlaying = preview?.storyRenders.some(
+ (renderer) => renderer.id === id && renderer.phase === 'playing'
+ );
+ // Errors thrown during playing need be shown in the interactions panel.
+ if (isPlaying) {
+ // Make sure that Vue won't swallow this error, by stacking it as a different event.
+ setTimeout(() => {
+ throw e;
+ }, 0);
+ } else {
+ showException(e as Error);
+ }
+ };
await runSetupFunctions(vueApp, storyContext);
vueApp.mount(canvasElement);
diff --git a/code/renderers/vue3/src/types.ts b/code/renderers/vue3/src/types.ts
index 1094f6780625..dfa6bed7870c 100644
--- a/code/renderers/vue3/src/types.ts
+++ b/code/renderers/vue3/src/types.ts
@@ -16,10 +16,6 @@ export type StoryContext = StoryContextBase;
export type StorybookVueApp = { vueApp: App; storyContext: StoryContext };
-/**
- * @deprecated Use `VueRenderer` instead.
- */
-export type VueFramework = VueRenderer;
export interface VueRenderer extends WebRenderer {
// We are omitting props, as we don't use it internally, and more importantly, it completely changes the assignability of meta.component.
// Try not omitting, and check the type errros in the test file, if you want to learn more.
diff --git a/code/renderers/vue3/template/cli/js/Button.stories.js b/code/renderers/vue3/template/cli/js/Button.stories.js
index 5dc3bbc92b12..8374e0636bc6 100644
--- a/code/renderers/vue3/template/cli/js/Button.stories.js
+++ b/code/renderers/vue3/template/cli/js/Button.stories.js
@@ -1,3 +1,4 @@
+import { fn } from '@storybook/test';
import MyButton from './Button.vue';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -6,17 +7,11 @@ export default {
component: MyButton,
tags: ['autodocs'],
argTypes: {
- backgroundColor: {
- control: 'color',
- },
- onClick: {},
- size: {
- control: {
- type: 'select',
- },
- options: ['small', 'medium', 'large'],
- },
+ size: { control: { type: 'select' }, options: ['small', 'medium', 'large'] },
+ backgroundColor: { control: 'color' },
},
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ args: { onClick: fn() },
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
diff --git a/code/renderers/vue3/template/cli/ts-3-8/Button.stories.ts b/code/renderers/vue3/template/cli/ts-3-8/Button.stories.ts
index c368a36d078d..60d4690fa465 100644
--- a/code/renderers/vue3/template/cli/ts-3-8/Button.stories.ts
+++ b/code/renderers/vue3/template/cli/ts-3-8/Button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/vue3';
-
+import { fn } from '@storybook/test';
import Button from './Button.vue';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -11,9 +11,12 @@ const meta: Meta = {
argTypes: {
size: { control: 'select', options: ['small', 'medium', 'large'] },
backgroundColor: { control: 'color' },
- onClick: { action: 'clicked' },
},
- args: { primary: false }, // default value
+ args: {
+ primary: false,
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ onClick: fn(),
+ },
};
export default meta;
diff --git a/code/renderers/vue3/template/cli/ts-4-9/Button.stories.ts b/code/renderers/vue3/template/cli/ts-4-9/Button.stories.ts
index 39013172fbe6..a69991a58bf7 100644
--- a/code/renderers/vue3/template/cli/ts-4-9/Button.stories.ts
+++ b/code/renderers/vue3/template/cli/ts-4-9/Button.stories.ts
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/vue3';
-
+import { fn } from '@storybook/test';
import Button from './Button.vue';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
@@ -11,9 +11,12 @@ const meta = {
argTypes: {
size: { control: 'select', options: ['small', 'medium', 'large'] },
backgroundColor: { control: 'color' },
- onClick: { action: 'clicked' },
},
- args: { primary: false }, // default value
+ args: {
+ primary: false,
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
+ onClick: fn(),
+ },
} satisfies Meta;
export default meta;
diff --git a/code/renderers/web-components/src/public-types.ts b/code/renderers/web-components/src/public-types.ts
index 9beed94f4443..19ccdf4b27a3 100644
--- a/code/renderers/web-components/src/public-types.ts
+++ b/code/renderers/web-components/src/public-types.ts
@@ -35,17 +35,6 @@ export type StoryFn = AnnotatedStoryFn = StoryAnnotations;
-/**
- * @deprecated Use `StoryFn` instead.
- * Use `StoryObj` if you want to migrate to CSF3, which uses objects instead of functions to represent stories.
- * You can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/
- *
- * Story function that represents a CSFv2 component example.
- *
- * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
- */
-export type Story = StoryFn;
-
export type Decorator = DecoratorFunction;
export type Loader = LoaderFunction;
export type StoryContext = GenericStoryContext;
diff --git a/code/renderers/web-components/src/types.ts b/code/renderers/web-components/src/types.ts
index 32cbce64c690..f58e7eaa01f4 100644
--- a/code/renderers/web-components/src/types.ts
+++ b/code/renderers/web-components/src/types.ts
@@ -10,10 +10,6 @@ export type StoryFnHtmlReturnType =
export type StoryContext = StoryContextBase;
-/**
- * @deprecated Use `WebComponentsRenderer` instead.
- */
-export type WebComponentsFramework = WebComponentsRenderer;
export interface WebComponentsRenderer extends WebRenderer {
component: string;
storyResult: StoryFnHtmlReturnType;
diff --git a/code/renderers/web-components/template/cli/ts-3-8/Header.ts b/code/renderers/web-components/template/cli/ts-3-8/Header.ts
index d1ca01450c8a..7c3c8b89375a 100644
--- a/code/renderers/web-components/template/cli/ts-3-8/Header.ts
+++ b/code/renderers/web-components/template/cli/ts-3-8/Header.ts
@@ -9,9 +9,9 @@ type User = {
export interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html`
diff --git a/code/renderers/web-components/template/cli/ts-3-8/Page.ts b/code/renderers/web-components/template/cli/ts-3-8/Page.ts
index 74711e4aa7e7..62be582343fa 100644
--- a/code/renderers/web-components/template/cli/ts-3-8/Page.ts
+++ b/code/renderers/web-components/template/cli/ts-3-8/Page.ts
@@ -8,9 +8,9 @@ type User = {
export interface PageProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html`
diff --git a/code/renderers/web-components/template/cli/ts-4-9/Header.ts b/code/renderers/web-components/template/cli/ts-4-9/Header.ts
index d1ca01450c8a..7c3c8b89375a 100644
--- a/code/renderers/web-components/template/cli/ts-4-9/Header.ts
+++ b/code/renderers/web-components/template/cli/ts-4-9/Header.ts
@@ -9,9 +9,9 @@ type User = {
export interface HeaderProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html`
diff --git a/code/renderers/web-components/template/cli/ts-4-9/Page.ts b/code/renderers/web-components/template/cli/ts-4-9/Page.ts
index 74711e4aa7e7..62be582343fa 100644
--- a/code/renderers/web-components/template/cli/ts-4-9/Page.ts
+++ b/code/renderers/web-components/template/cli/ts-4-9/Page.ts
@@ -8,9 +8,9 @@ type User = {
export interface PageProps {
user?: User;
- onLogin: () => void;
- onLogout: () => void;
- onCreateAccount: () => void;
+ onLogin?: () => void;
+ onLogout?: () => void;
+ onCreateAccount?: () => void;
}
export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html`
diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json
index b231db2f281a..a8199801e1a8 100644
--- a/code/ui/blocks/package.json
+++ b/code/ui/blocks/package.json
@@ -71,6 +71,7 @@
},
"devDependencies": {
"@storybook/addon-actions": "workspace:*",
+ "@storybook/test": "workspace:*",
"@types/color-convert": "^2.0.0"
},
"peerDependencies": {
diff --git a/code/ui/blocks/src/blocks/Description.tsx b/code/ui/blocks/src/blocks/Description.tsx
index a6cda58ca930..99b9cf7ce75b 100644
--- a/code/ui/blocks/src/blocks/Description.tsx
+++ b/code/ui/blocks/src/blocks/Description.tsx
@@ -1,11 +1,5 @@
import type { FC } from 'react';
-import React, { useContext } from 'react';
-import { str } from '@storybook/docs-tools';
-import { deprecate } from '@storybook/client-logger';
-
-import type { DocsContextProps } from './DocsContext';
-import { DocsContext } from './DocsContext';
-import type { Component } from './types';
+import React from 'react';
import type { Of } from './useOf';
import { useOf } from './useOf';
import { Markdown } from './Markdown';
@@ -17,39 +11,14 @@ export enum DescriptionType {
AUTO = 'auto',
}
-type Notes = string | any;
-type Info = string | any;
-
-const DEPRECATION_MIGRATION_LINK =
- 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo';
-
interface DescriptionProps {
/**
* Specify where to get the description from. Can be a component, a CSF file or a story.
* If not specified, the description will be extracted from the meta of the attached CSF file.
*/
of?: Of;
- /**
- * @deprecated Manually specifying description type is deprecated. See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo
- */
- type?: DescriptionType;
- /**
- * @deprecated The 'markdown' prop on the Description block is deprecated. See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo
- */
- markdown?: string;
- /**
- * @deprecated The 'children' prop on the Description block is deprecated. See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo
- */
- children?: string;
}
-const getNotes = (notes?: Notes) =>
- notes && (typeof notes === 'string' ? notes : str(notes.markdown) || str(notes.text));
-
-const getInfo = (info?: Info) => info && (typeof info === 'string' ? info : str(info.text));
-
-const noDescription = (component?: Component): string | null => null;
-
const getDescriptionFromResolvedOf = (resolvedOf: ReturnType): string | null => {
switch (resolvedOf.type) {
case 'story': {
@@ -88,73 +57,15 @@ const getDescriptionFromResolvedOf = (resolvedOf: ReturnType): str
}
};
-const getDescriptionFromDeprecatedProps = (
- { type, markdown, children }: DescriptionProps,
- { storyById }: DocsContextProps
-): string => {
- const { component, parameters } = storyById();
- if (children || markdown) {
- return children || markdown;
- }
- const { notes, info, docs } = parameters;
- if (Boolean(notes) || Boolean(info)) {
- deprecate(
- `Using 'parameters.notes' or 'parameters.info' properties to describe stories is deprecated. See ${DEPRECATION_MIGRATION_LINK}`
- );
- }
-
- const { extractComponentDescription = noDescription, description } = docs || {};
-
- // override component description
- const componentDescriptionParameter = description?.component;
- if (componentDescriptionParameter) {
- return componentDescriptionParameter;
- }
-
- switch (type) {
- case DescriptionType.INFO:
- return getInfo(info);
- case DescriptionType.NOTES:
- return getNotes(notes);
- case DescriptionType.DOCGEN:
- case DescriptionType.AUTO:
- default:
- return extractComponentDescription(component, { component, ...parameters });
- }
-};
-
const DescriptionContainer: FC = (props) => {
- const { of, type, markdown: markdownProp, children } = props;
+ const { of } = props;
if ('of' in props && of === undefined) {
throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');
}
- const context = useContext(DocsContext);
const resolvedOf = useOf(of || 'meta');
- let markdown;
- if (type || markdownProp || children) {
- // pre 7.0 mode with deprecated props
- markdown = getDescriptionFromDeprecatedProps(props, context);
- } else {
- // 7.0 mode with new 'of' prop
- // pre 7.0 with only 'of' prop only supported referencing a component, which 7.0 supports as well here
- markdown = getDescriptionFromResolvedOf(resolvedOf);
- }
- if (type) {
- deprecate(
- `Manually specifying description type is deprecated. See ${DEPRECATION_MIGRATION_LINK}`
- );
- }
- if (markdownProp) {
- deprecate(
- `The 'markdown' prop on the Description block is deprecated. See ${DEPRECATION_MIGRATION_LINK}`
- );
- }
- if (children) {
- deprecate(
- `The 'children' prop on the Description block is deprecated. See ${DEPRECATION_MIGRATION_LINK}`
- );
- }
+ const markdown = getDescriptionFromResolvedOf(resolvedOf);
+
return markdown ? {markdown} : null;
};
diff --git a/code/ui/blocks/src/blocks/Source.tsx b/code/ui/blocks/src/blocks/Source.tsx
index 30b279d1e9af..033dfd718571 100644
--- a/code/ui/blocks/src/blocks/Source.tsx
+++ b/code/ui/blocks/src/blocks/Source.tsx
@@ -31,12 +31,6 @@ type SourceParameters = SourceCodeProps & {
* Where to read the source code from, see `SourceType`
*/
type?: SourceType;
- /**
- * Transform the detected source for display
- *
- * @deprecated use `transform` prop instead
- */
- transformSource?: (code: string, storyContext: StoryContextForLoaders) => string;
/**
* Transform the detected source for display
*/
@@ -126,31 +120,7 @@ const getSnippet = ({
const code = useSnippet ? snippet : sourceParameters.originalSource || '';
- if (sourceParameters.transformSource) {
- deprecate(dedent`The \`transformSource\` parameter at \`parameters.docs.source.transformSource\` is deprecated, please use \`parameters.docs.source.transform\` instead.
-
- Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#source-block
- `);
- }
- if (storyContext.parameters.docs?.transformSource) {
- deprecate(dedent`The \`transformSource\` parameter at \`parameters.docs.transformSource\` is deprecated, please use \`parameters.docs.source.transform\` instead.
-
- Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#source-block
- `);
- }
- if (storyContext.parameters.jsx?.transformSource) {
- deprecate(dedent`The \`transformSource\` parameter at \`parameters.jsx.transformSource\` is deprecated, please use \`parameters.docs.source.transform\` instead.
-
- Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#source-block
- `);
- }
-
- const transformer =
- transformFromProps ??
- sourceParameters.transform ??
- sourceParameters.transformSource ?? // deprecated
- storyContext.parameters.docs?.transformSource ?? // deprecated
- storyContext.parameters.jsx?.transformSource; // deprecated - used to be implemented in the React renderer's jsxDecorator
+ const transformer = transformFromProps ?? sourceParameters.transform;
return transformer?.(code, storyContext) || code;
};
diff --git a/code/ui/blocks/src/blocks/Story.stories.tsx b/code/ui/blocks/src/blocks/Story.stories.tsx
index dce6292a643c..b3f8108feb23 100644
--- a/code/ui/blocks/src/blocks/Story.stories.tsx
+++ b/code/ui/blocks/src/blocks/Story.stories.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
+import { expect, waitFor } from '@storybook/test';
import { Story as StoryBlock } from './Story';
import * as ButtonStories from '../examples/Button.stories';
@@ -86,6 +87,24 @@ export const IFrameProps: Story = {
of: StoryParametersStories.NoParameters,
inline: false,
},
+ parameters: {
+ chromatic: {
+ delay: 3000,
+ },
+ },
+ play: async ({ canvasElement }) => {
+ // this is mostly to fix flakiness in chromatic, specifically on Safari
+ // where the scrollbar appears inconsistently and causes the snapshot to be different
+ await waitFor(
+ async () => {
+ const iframeEl = canvasElement.querySelector('iframe');
+ await expect(
+ iframeEl!.contentDocument!.querySelector('[data-testid="sb-iframe-text"]')
+ ).toBeVisible();
+ },
+ { timeout: 10000 }
+ );
+ },
};
export const IFrameWithParameter: Story = {
diff --git a/code/ui/blocks/src/blocks/Story.tsx b/code/ui/blocks/src/blocks/Story.tsx
index 2211bcc54cd6..9480d8946eba 100644
--- a/code/ui/blocks/src/blocks/Story.tsx
+++ b/code/ui/blocks/src/blocks/Story.tsx
@@ -8,9 +8,7 @@ import type {
StoryAnnotations,
StoryId,
} from '@storybook/types';
-import { deprecate } from '@storybook/client-logger';
-import dedent from 'ts-dedent';
import { Story as PureStory, StorySkeleton } from '../components';
import type { DocsContextProps } from './DocsContext';
import { DocsContext } from './DocsContext';
@@ -114,25 +112,7 @@ export const getStoryProps = (
// prefer block props, then story parameters defined by the framework-specific settings
// and optionally overridden by users
- // Deprecated parameters
- const { inlineStories, iframeHeight } = docs as {
- inlineStories?: boolean;
- iframeHeight?: string;
- autoplay?: boolean;
- };
- if (typeof inlineStories !== 'undefined')
- deprecate(dedent`The \`docs.inlineStories\` parameter is deprecated, use \`docs.story.inline\` instead.
-
- Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#autodocs-changes'
- `);
- const inline = props.inline ?? storyParameters.inline ?? inlineStories ?? false;
-
- if (typeof iframeHeight !== 'undefined') {
- deprecate(dedent`The \`docs.iframeHeight\` parameter is deprecated, use \`docs.story.iframeHeight\` instead.
-
- Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#autodocs-changes'
- `);
- }
+ const inline = props.inline ?? storyParameters.inline ?? false;
if (inline) {
const height = props.height ?? storyParameters.height;
@@ -150,12 +130,7 @@ export const getStoryProps = (
};
}
- const height =
- props.height ??
- storyParameters.height ??
- storyParameters.iframeHeight ??
- iframeHeight ??
- '100px';
+ const height = props.height ?? storyParameters.height ?? storyParameters.iframeHeight ?? '100px';
return {
story,
inline: false,
diff --git a/code/ui/blocks/src/blocks/internal/InternalDescription.stories.tsx b/code/ui/blocks/src/blocks/internal/InternalDescription.stories.tsx
deleted file mode 100644
index da4c87728947..000000000000
--- a/code/ui/blocks/src/blocks/internal/InternalDescription.stories.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-import type { Meta, StoryObj } from '@storybook/react';
-import { Description, DescriptionType } from '../Description';
-import { Button } from '../../examples/Button';
-
-const meta: Meta = {
- component: Description,
- parameters: {
- relativeCsfPaths: ['../examples/Button.stories'],
- docsStyles: true,
- },
- args: {
- of: Button,
- },
-};
-export default meta;
-
-type Story = StoryObj;
-
-export const InfoType: Story = {
- args: {
- type: DescriptionType.INFO,
- },
-};
-export const NotesType: Story = {
- args: {
- type: DescriptionType.NOTES,
- },
-};
-export const DocgenType: Story = {
- args: {
- type: DescriptionType.DOCGEN,
- },
-};
-export const AutoType: Story = {
- args: {
- type: DescriptionType.AUTO,
- },
-};
-export const Markdown: Story = {
- args: {
- markdown: `# My Example Markdown
-
-An \`inline\` codeblock
-
-\`\`\`tsx
-// TypeScript React code block
-export const MyStory = () => {
-return ;
-};
-\`\`\`
-
-\`\`\`
-code block with with no language
-const a = fn({
-b: 2,
-});
-\`\`\`
-`,
- },
-};
-export const Children: Story = {
- render: (args) => (
-
- {`# My Example Markdown
-
-An \`inline\` codeblock
-
-\`\`\`tsx
-// TypeScript React code block
-export const MyStory = () => {
-return ;
-};
-\`\`\`
-
-\`\`\`
-code block with with no language
-const a = fn({
-b: 2,
-});
-\`\`\`
-`}
-
- ),
-};
diff --git a/code/ui/blocks/src/blocks/internal/InternalSource.stories.tsx b/code/ui/blocks/src/blocks/internal/InternalSource.stories.tsx
index 7490f1d72184..035f1c5e1086 100644
--- a/code/ui/blocks/src/blocks/internal/InternalSource.stories.tsx
+++ b/code/ui/blocks/src/blocks/internal/InternalSource.stories.tsx
@@ -1,5 +1,4 @@
import type { Meta, StoryObj } from '@storybook/react';
-import * as ParametersStories from '../../examples/SourceParameters.stories';
import { Source } from '../Source';
@@ -29,21 +28,3 @@ export const Ids: Story = {
],
},
};
-
-export const SourceTransformSourceParameter: Story = {
- args: {
- of: ParametersStories.SourceTransformSource,
- },
-};
-
-export const DocsTransformSourceParameter: Story = {
- args: {
- of: ParametersStories.DocsTransformSource,
- },
-};
-
-export const JsxTransformSourceParameter: Story = {
- args: {
- of: ParametersStories.JsxTransformSource,
- },
-};
diff --git a/code/ui/blocks/src/examples/SimpleSizeTest.tsx b/code/ui/blocks/src/examples/SimpleSizeTest.tsx
index 72e43ab45855..34021666c625 100644
--- a/code/ui/blocks/src/examples/SimpleSizeTest.tsx
+++ b/code/ui/blocks/src/examples/SimpleSizeTest.tsx
@@ -12,7 +12,7 @@ export const SimpleSizeTest = () => {
margin: '-4rem -20px',
}}
>
-
+
This story does nothing. Its only purpose is to show how its size renders in different
conditions (inline/iframe/fixed height) when used in a {''} block.
diff --git a/code/ui/blocks/src/examples/SourceParameters.stories.tsx b/code/ui/blocks/src/examples/SourceParameters.stories.tsx
index 08ebaf5cb46f..ec832b109e88 100644
--- a/code/ui/blocks/src/examples/SourceParameters.stories.tsx
+++ b/code/ui/blocks/src/examples/SourceParameters.stories.tsx
@@ -50,56 +50,6 @@ export const Transform = {
},
};
-// deprecated
-export const SourceTransformSource = {
- args: { something: 'else' },
- parameters: {
- docs: {
- source: {
- transformSource: (
- src: string,
- storyContext: StoryContext
- ) => dedent`// this comment has been added via parameters.docs.source.transformSource!
- // this is the story id: ${storyContext.id}
- // these are the current args: ${JSON.stringify(storyContext.args)}
- ${src}`,
- },
- },
- },
-};
-
-// deprecated
-export const DocsTransformSource = {
- args: { something: 'else' },
- parameters: {
- docs: {
- transformSource: (
- src: string,
- storyContext: StoryContext
- ) => dedent`// this comment has been added via parameters.docs.transformSource!
- // this is the story id: ${storyContext.id}
- // these are the current args: ${JSON.stringify(storyContext.args)}
- ${src}`,
- },
- },
-};
-
-// deprecated
-export const JsxTransformSource = {
- args: { something: 'else' },
- parameters: {
- jsx: {
- transformSource: (
- src: string,
- storyContext: StoryContext
- ) => dedent`// this comment has been added via parameters.jsx.transformSource!
- // this is the story id: ${storyContext.id}
- // these are the current args: ${JSON.stringify(storyContext.args)}
- ${src}`,
- },
- },
-};
-
export const Code = {
parameters: { docs: { source: { code } } },
};
diff --git a/code/ui/components/package.json b/code/ui/components/package.json
index 148a6097ae54..74d3f290d88a 100644
--- a/code/ui/components/package.json
+++ b/code/ui/components/package.json
@@ -72,6 +72,7 @@
"devDependencies": {
"@popperjs/core": "^2.6.0",
"@radix-ui/react-scroll-area": "^1.0.5",
+ "@storybook/test": "workspace:*",
"@types/react-syntax-highlighter": "11.0.5",
"@types/util-deprecate": "^1.0.0",
"css": "^3.0.0",
diff --git a/code/ui/components/src/components/tooltip/WithTooltip.stories.tsx b/code/ui/components/src/components/tooltip/WithTooltip.stories.tsx
index 76eab8d7c113..8ccb459095a0 100644
--- a/code/ui/components/src/components/tooltip/WithTooltip.stories.tsx
+++ b/code/ui/components/src/components/tooltip/WithTooltip.stories.tsx
@@ -1,6 +1,7 @@
import type { FunctionComponent, ComponentProps } from 'react';
import React from 'react';
import type { StoryObj } from '@storybook/react';
+import { expect, screen } from '@storybook/test';
import { styled } from '@storybook/theming';
import { TooltipMessage } from './TooltipMessage';
import { WithToolTipState as WithTooltip } from './WithTooltip';
@@ -104,6 +105,9 @@ export const SimpleClickStartOpen: StoryObj>
Click me!
),
+ play: async () => {
+ await expect(await screen.findByText('Lorem ipsum dolor sit')).toBeInTheDocument();
+ },
};
export const SimpleClickCloseOnClick: StoryObj> = {
diff --git a/code/ui/components/src/components/tooltip/WithTooltip.tsx b/code/ui/components/src/components/tooltip/WithTooltip.tsx
index bece4bc64278..e76c898d6dd0 100644
--- a/code/ui/components/src/components/tooltip/WithTooltip.tsx
+++ b/code/ui/components/src/components/tooltip/WithTooltip.tsx
@@ -36,18 +36,6 @@ export interface WithTooltipPureProps
tooltip: ReactNode | ((p: WithHideFn) => ReactNode);
children: ReactNode;
onDoubleClick?: () => void;
- /**
- * @deprecated use `defaultVisible` property instead. This property will be removed in SB 8.0
- */
- tooltipShown?: boolean;
- /**
- * @deprecated use `closeOnOutsideClick` property instead. This property will be removed in SB 8.0
- */
- closeOnClick?: boolean;
- /**
- * @deprecated use `onVisibleChange` property instead. This property will be removed in SB 8.0
- */
- onVisibilityChange?: (visibility: boolean) => void | boolean;
/**
* If `true`, a click outside the trigger element closes the tooltip
* @default false
@@ -68,9 +56,6 @@ const WithTooltipPure: FC = ({
children,
closeOnTriggerHidden,
mutationObserverOptions,
- closeOnClick,
- tooltipShown,
- onVisibilityChange,
defaultVisible,
delayHide,
visible,
@@ -94,15 +79,12 @@ const WithTooltipPure: FC = ({
{
trigger,
placement,
- defaultVisible: defaultVisible ?? tooltipShown,
+ defaultVisible,
delayHide,
interactive,
- closeOnOutsideClick: closeOnOutsideClick ?? closeOnClick,
+ closeOnOutsideClick,
closeOnTriggerHidden,
- onVisibleChange: (_isVisible) => {
- onVisibilityChange?.(_isVisible);
- onVisibleChange?.(_isVisible);
- },
+ onVisibleChange,
delayShow,
followCursor,
mutationObserverOptions,
diff --git a/code/ui/manager/src/components/layout/Layout.stories.tsx b/code/ui/manager/src/components/layout/Layout.stories.tsx
index 593e83dea5ab..aea6f4a1a5f2 100644
--- a/code/ui/manager/src/components/layout/Layout.stories.tsx
+++ b/code/ui/manager/src/components/layout/Layout.stories.tsx
@@ -4,6 +4,7 @@ import React, { useState } from 'react';
import { styled } from '@storybook/theming';
import type { Meta, StoryObj } from '@storybook/react';
+import { fn } from '@storybook/test';
import { Layout } from './Layout';
import { LayoutProvider } from './LayoutProvider';
import MobileNavigationStoriesMeta from '../mobile/navigation/MobileNavigation.stories';
@@ -58,6 +59,7 @@ const meta = {
slotSidebar: ,
slotPanel: ,
slotPages: ,
+ setManagerLayoutState: fn(),
},
parameters: {
theme: 'light',
diff --git a/code/ui/manager/src/components/preview/Preview.stories.tsx b/code/ui/manager/src/components/preview/Preview.stories.tsx
index 624542b2f68c..0a639c9db64e 100644
--- a/code/ui/manager/src/components/preview/Preview.stories.tsx
+++ b/code/ui/manager/src/components/preview/Preview.stories.tsx
@@ -7,7 +7,7 @@ import { Location, BaseLocationProvider } from '@storybook/router';
import { ThemeProvider, ensure as ensureTheme, themes } from '@storybook/theming';
-import type { DecoratorFn } from '@storybook/react';
+import type { Decorator } from '@storybook/react';
import { Preview } from './Preview';
import { PrettyFakeProvider } from '../../FakeProvider';
@@ -80,7 +80,7 @@ export default {
);
- }) as DecoratorFn,
+ }) as Decorator,
],
};
diff --git a/code/ui/manager/src/components/sidebar/Heading.stories.tsx b/code/ui/manager/src/components/sidebar/Heading.stories.tsx
index b958ebe2e1b1..34e08e7c02ea 100644
--- a/code/ui/manager/src/components/sidebar/Heading.stories.tsx
+++ b/code/ui/manager/src/components/sidebar/Heading.stories.tsx
@@ -1,7 +1,7 @@
/* eslint-disable storybook/use-storybook-testing-library */
// @TODO: use addon-interactions and remove the rule disable above
import React from 'react';
-import type { ComponentMeta, ComponentStoryObj, ComponentStoryFn } from '@storybook/react';
+import type { Meta, StoryObj, StoryFn } from '@storybook/react';
import { ThemeProvider, useTheme } from '@storybook/theming';
import type { Theme } from '@storybook/theming';
import { action } from '@storybook/addon-actions';
@@ -9,7 +9,7 @@ import { screen } from '@testing-library/dom';
import { Heading } from './Heading';
-type Story = ComponentStoryFn;
+type Story = StoryFn;
export default {
component: Heading,
@@ -19,7 +19,7 @@ export default {
decorators: [
(storyFn) =>
- )) as DecoratorFn,
+ )) as Decorator,
],
};
diff --git a/code/ui/manager/src/settings/shortcuts.stories.tsx b/code/ui/manager/src/settings/shortcuts.stories.tsx
index 47d7397584e4..555f5b6b0b6a 100644
--- a/code/ui/manager/src/settings/shortcuts.stories.tsx
+++ b/code/ui/manager/src/settings/shortcuts.stories.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { actions as makeActions } from '@storybook/addon-actions';
-import type { DecoratorFn } from '@storybook/react';
+import type { Decorator } from '@storybook/react';
import { ShortcutsScreen } from './shortcuts';
import { defaultShortcuts } from './defaultShortcuts';
@@ -26,7 +26,7 @@ export default {
>
- )) as DecoratorFn,
+ )) as Decorator,
],
};
diff --git a/code/yarn.lock b/code/yarn.lock
index bddedd2eaaec..d97a6fb453c3 100644
--- a/code/yarn.lock
+++ b/code/yarn.lock
@@ -4708,6 +4708,7 @@ __metadata:
"@storybook/node-logger": "workspace:*"
"@storybook/preview-api": "workspace:*"
"@storybook/react-dom-shim": "workspace:*"
+ "@storybook/test": "workspace:*"
"@storybook/theming": "workspace:*"
"@storybook/types": "workspace:*"
fs-extra: "npm:^11.1.0"
@@ -5069,6 +5070,7 @@ __metadata:
"@storybook/icons": "npm:^1.2.1"
"@storybook/manager-api": "workspace:*"
"@storybook/preview-api": "workspace:*"
+ "@storybook/test": "workspace:*"
"@storybook/theming": "workspace:*"
"@storybook/types": "workspace:*"
"@types/color-convert": "npm:^2.0.0"
@@ -5342,6 +5344,7 @@ __metadata:
"@storybook/csf": "npm:^0.1.2"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.1"
+ "@storybook/test": "workspace:*"
"@storybook/theming": "workspace:*"
"@storybook/types": "workspace:*"
"@types/react-syntax-highlighter": "npm:11.0.5"
@@ -6393,6 +6396,7 @@ __metadata:
react-dom: "npm:^18.2.0"
semver: "npm:^7.3.7"
serve-static: "npm:^1.14.1"
+ svelte: "npm:^5.0.0-next.28"
trash: "npm:^7.0.0"
ts-dedent: "npm:^2.0.0"
ts-node: "npm:^10.9.1"
@@ -6492,7 +6496,7 @@ __metadata:
"@sveltejs/vite-plugin-svelte": "npm:^3.0.1"
"@types/node": "npm:^18.0.0"
magic-string: "npm:^0.30.0"
- svelte: "npm:^5.0.0-next.16"
+ svelte: "npm:^5.0.0-next.28"
svelte-preprocess: "npm:^5.1.1"
sveltedoc-parser: "npm:^4.2.1"
ts-dedent: "npm:^2.2.0"
@@ -6535,7 +6539,7 @@ __metadata:
"@storybook/types": "workspace:*"
"@sveltejs/vite-plugin-svelte": "npm:^3.0.1"
expect-type: "npm:^0.15.0"
- svelte: "npm:^5.0.0-next.22"
+ svelte: "npm:^5.0.0-next.28"
svelte-check: "npm:^3.6.1"
sveltedoc-parser: "npm:^4.2.1"
ts-dedent: "npm:^2.0.0"
@@ -27314,29 +27318,9 @@ __metadata:
languageName: node
linkType: hard
-"svelte@npm:^5.0.0-next.16":
- version: 5.0.0-next.22
- resolution: "svelte@npm:5.0.0-next.22"
- dependencies:
- "@ampproject/remapping": "npm:^2.2.1"
- "@jridgewell/sourcemap-codec": "npm:^1.4.15"
- acorn: "npm:^8.10.0"
- acorn-typescript: "npm:^1.4.11"
- aria-query: "npm:^5.3.0"
- axobject-query: "npm:^4.0.0"
- esm-env: "npm:^1.0.0"
- esrap: "npm:^1.2.1"
- is-reference: "npm:^3.0.1"
- locate-character: "npm:^3.0.0"
- magic-string: "npm:^0.30.4"
- zimmerframe: "npm:^1.1.0"
- checksum: 121c0ffe925f3393581742a970d58588ac642f15d17062af16f46b4729064d48214ee158261fbcdff78b6ee143f4da361d3e696507c8c7c31580e2040e366539
- languageName: node
- linkType: hard
-
-"svelte@npm:^5.0.0-next.22":
- version: 5.0.0-next.26
- resolution: "svelte@npm:5.0.0-next.26"
+"svelte@npm:^5.0.0-next.28":
+ version: 5.0.0-next.28
+ resolution: "svelte@npm:5.0.0-next.28"
dependencies:
"@ampproject/remapping": "npm:^2.2.1"
"@jridgewell/sourcemap-codec": "npm:^1.4.15"
@@ -27350,7 +27334,7 @@ __metadata:
locate-character: "npm:^3.0.0"
magic-string: "npm:^0.30.4"
zimmerframe: "npm:^1.1.0"
- checksum: 76e5874b7afd8f9770b716ea3422c5d0e7e45a85c01bc1fa7daa43b3ae4d38ee073da7a958e3826d0370718fbdf9477769785754b8606a7403460e027f034b60
+ checksum: d309cd3d1a9fe16c67a626af867288b02f6e7c49311c851aeb0f36feb5ab9603ca5594338fb933dbbada41b26faea6dcef52ed6ab3e86f54626545e53059eb28
languageName: node
linkType: hard
diff --git a/docs/api/doc-block-description.md b/docs/api/doc-block-description.md
index 1c188a239349..ce8254d7f572 100644
--- a/docs/api/doc-block-description.md
+++ b/docs/api/doc-block-description.md
@@ -37,30 +37,6 @@ Specifies where to pull the description from. It can either point to a story or
Descriptions are pulled from the JSDoc comments or parameters, and they are rendered as markdown. See [Writing descriptions](#writing-descriptions) for more details.
-### `children`
-
-(⛔️ **Deprecated**)
-
-Type: `string`
-
-See [Migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo).
-
-### `markdown`
-
-(⛔️ **Deprecated**)
-
-Type: `string`
-
-See [Migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo).
-
-### `type`
-
-(⛔️ **Deprecated**)
-
-Type: `'info' | 'notes' | 'docgen' | 'auto'`
-
-See [Migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#description-block-parametersnotes-and-parametersinfo).
-
## Writing descriptions
There are multiple places to write the description of a component/story, depending on what you want to achieve. Descriptions can be written at the story level to describe each story of a component, or they can be written at the meta or component level to describe the component in general.
diff --git a/docs/configure/styling-and-css.md b/docs/configure/styling-and-css.md
index f2e70a9b6729..630e6e25ab7d 100644
--- a/docs/configure/styling-and-css.md
+++ b/docs/configure/styling-and-css.md
@@ -2,15 +2,18 @@
title: 'Styling and CSS'
---
+
+
+
There are many ways to include CSS in a web application, and correspondingly there are many ways to include CSS in Storybook. Usually, it is best to try and replicate what your application does with styling in Storybook’s configuration.
-If you're using Vite to build your Storybook, you're covered! Storybook will use your vite config file which supports most popular styling tools out-of-the-box 🎉. However, if you're using Webpack, you may need some extra configuration. To make this easier, we recommend using [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/).
+## CSS
-**Note**: If you're using Storybook with Angular or Next.js, you can skip this section. Storybook will automatically use the same styling configuration as your application.
+Storybook supports importing CSS files in a few different ways. Storybook will inject these tags into the preview iframe where your components render, not the Storybook Manager UI. The best way to import CSS depends on your project's configuration and your preferences.
-## Importing CSS files
+### Import bundled CSS (Recommended)
-Storybook is pre-configured to recognize imports for CSS files. To add global CSS for all your stories, import it in [`.storybook/preview.js`](./index.md#configure-story-rendering).
+All Storybooks are pre-configured to recognize imports for CSS files. To add global CSS for all your stories, import it in [`.storybook/preview.ts`](./overview.md#configure-story-rendering). These files will be subject to HMR, so you can see your changes without restarting your Storybook server.
@@ -23,13 +26,89 @@ Storybook is pre-configured to recognize imports for CSS files. To add global CS
-If your component files import their CSS files, this will work too. The noticeable exception to this is if you're using CSS processor tools like Sass or Postcss.
+If your component files import their CSS files, this will work too. However, if you're using CSS processor tools like Sass or Postcss, you may need some more configuration.
+
+### Include static CSS
+
+If you have a global CSS file that you want to include in all your stories, you can import it in [`.storybook/preview-head.html`](./story-rendering.md#adding-to-head).
+However, these files will not be subject to HMR, so you'll need to restart your Storybook server to see your changes.
+
+
+
+
+
+
-## CSS processors
+## CSS modules
-If you're using Vite as your builder, you're covered! Vite supports Sass and PostCSS out-of-the-box 🎉
+### Vite
-However, if you're using Webpack and want to use Sass and PostCss, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools. Or if you'd prefer, you can customize [Storybook's webpack configuration yourself](../builders/webpack.md#override-the-default-configuration) to include the appropriate loader(s).
+Vite comes with CSS modules support out-of-the-box. If you have customized the CSS modules configuration in your `vite.config.js` this will automatically be applied to your Storybook as well. Read more about [Vite's CSS modules support](https://vitejs.dev/guide/features.html#css-modules).
+
+### Webpack
+
+
+
+
+Storybook recreates your Next.js configuration, so you can use CSS modules in your stories without any extra configuration.
+
+
+
+
+If you're using Webpack and want to use CSS modules, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools.
+
+## PostCSS
+
+### Vite
+
+Vite comes with PostCSS support out-of-the-box. If you have customized the PostCSS configuration in your `vite.config.js` this will automatically be applied to your Storybook as well. Read more about [Vite's PostCSS support](https://vitejs.dev/guide/features.html#postcss).
+
+### Webpack
+
+
+
+
+Storybook recreates your Next.js configuration, so you can use PostCSS in your stories without any extra configuration.
+
+
+
+
+If you're using Webpack and want to use PostCSS, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools.
+
+## CSS pre-processors
+
+### Vite
+
+Vite comes with Sass, Less, and Stylus support out-of-the-box. Read more about [Vite's CSS Pre-processor support](https://vitejs.dev/guide/features.html#css-pre-processors).
+
+### Webpack
+
+
+
+
+Storybook recreates your Next.js configuration, so you can use Sass in your stories without any extra configuration.
+
+
+
+
+If you're using Webpack and want to use Sass or less, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools. Or if you'd prefer, you can customize [Storybook's webpack configuration yourself](../builders/webpack.md#override-the-default-configuration) to include the appropriate loader(s).
## CSS-in-JS
@@ -37,51 +116,77 @@ CSS-in-JS libraries are designed to use basic JavaScript, and they often work in
## Adding webfonts
+### `.storybook/preview-head.html`
+
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).
-
+### `.storybook/preview.ts`
-## Troubleshooting
+If you're using something like [`fontsource`](https://fontsource.org/) for your fonts, you can import the needed css files in your [`.storybook/preview.ts`](./overview.md#configure-story-rendering) file.
-### Styles aren't being applied with Angular
+
-The latest Angular releases introduced significant changes in configuring and styling projects. If you're working with an Angular version greater than 13 and your styles aren't being applied, you may need to check your `angular.json` and adjust the `builder` configuration to import your CSS:
+
+
-```json
-{
- "my-project": {
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "styles": ["src/styles.css", "src/styles.scss"]
- }
- }
- }
- }
-}
-```
+Storybook for Angular relies on the Angular CLI to build your stories. This means that you can use any CSS preprocessor that the Angular CLI supports. You can read more about this in the [Angular CLI documentation](https://angular.io/guide/workspace-config#style-script-config).
-Additionally, if you need Storybook-specific styles that are separate from your application, you can configure the styles with [Storybook's custom builder](../get-started/install.md#troubleshooting), which will override the application's styles:
+## Global styles
+
+To add global styles to your Storybook, you can add them to the `styles` array in your `angular.json` file. This will add the styles to the preview iframe where your components render, not the Storybook Manager UI.
+
+Don't forget to also add your global styles to your `build-storybook` target in your `angular.json` file. This will ensure that your global styles are included in the static build of your Storybook as well.
```json
-{
+ {
"storybook": {
"builder": "@storybook/angular:start-storybook",
"options": {
- "browserTarget": "my-default-project:build",
- "styles": [".storybook/custom-styles.scss"]
+ "configDir": ".storybook",
+ "browserTarget": "angular-latest:build",
+ "compodoc": true,
+ "compodocArgs": ["-e", "json", "-d", "."],
+ "port": 6006,
+ "styles": [
+ // Add your global styles here
+ "@angular/material/prebuilt-themes/indigo-pink.css",
+ "@fontsource/roboto/300.css",
+ "@fontsource/roboto/400.css",
+ "@fontsource/roboto/500.css",
+ "@fontsource/roboto/700.css",
+ "@fontsource/material-icons",
+ "src/styles.scss"
+ ]
+ }
+ },
+ "build-storybook": {
+ "builder": "@storybook/angular:build-storybook",
+ "options": {
+ "configDir": ".storybook",
+ "browserTarget": "angular-latest:build",
+ "compodoc": true,
+ "compodocArgs": ["-e", "json", "-d", "."],
+ "styles": [
+ // Add your global styles here
+ "@angular/material/prebuilt-themes/indigo-pink.css",
+ "@fontsource/roboto/300.css",
+ "@fontsource/roboto/400.css",
+ "@fontsource/roboto/500.css",
+ "@fontsource/roboto/700.css",
+ "@fontsource/material-icons",
+ "src/styles.scss"
+ ],
+ "outputDir": "storybook-static"
}
}
}
```
-### NX component libraries not loading styles
+## Troubleshooting
-If you're working with Storybook and [Nx libraries](https://nx.dev/structure/library-types),
-you can extend your project's configuration (i.e., `project.json`) and provide the application's styles.
+If you're working with Storybook and [Nx libraries](https://nx.dev/structure/library-types), you can extend your project's configuration (i.e., project.json) and provide the application's styles.
-For earlier Nx versions (before `14.1.8`), your configuration would look like this:
+For earlier Nx versions (before 14.1.8), your configuration would look like this:
```json
"build-storybook": {
@@ -99,7 +204,7 @@ For earlier Nx versions (before `14.1.8`), your configuration would look like th
}
```
-Starting with version `14.1.8`, Nx uses the Storybook builder directly, which means any configuration supplied to the builder also applies to the NX setup. If you're working with a library, you'll need to configure the styling options ( e.g., preprocessors) inside the `build-storybook` `options` configuration object. For example:
+Starting with version 14.1.8, Nx uses the Storybook builder directly, which means any configuration supplied to the builder also applies to the NX setup. If you're working with a library, you'll need to configure the styling options ( e.g., preprocessors) inside the `build-storybook` options configuration object. For example:
```json
"storybook": {
@@ -126,6 +231,7 @@ Starting with version `14.1.8`, Nx uses the Storybook builder directly, which me
}
```
-When Nx runs, it will load Storybook's configuration and styling based on [`storybook`'s `browserTarget`](https://nx.dev/storybook/extra-topics-for-angular-projects#setting-up-browsertarget).
+When Nx runs, it will load Storybook's configuration and styling based on [`storybook.browserTarget`](https://nx.dev/storybook/extra-topics-for-angular-projects#setting-up-browsertarget).
+
diff --git a/docs/sharing/storybook-composition.md b/docs/sharing/storybook-composition.md
index 987d453e51df..50a78daadf6b 100644
--- a/docs/sharing/storybook-composition.md
+++ b/docs/sharing/storybook-composition.md
@@ -17,7 +17,7 @@ You’ll see the composed Storybook’s stories in the sidebar alongside your ow
## Compose published Storybooks
-In your [`.storybook/main.js`](../configure/index.md#configure-story-rendering) file add a `refs` field with information about the reference Storybook. Pass in a URL to a statically built Storybook.
+In your [`.storybook/main.js|ts`](../configure/index.md#configure-story-rendering) file add a `refs` field with information about the reference Storybook. Pass in a URL to a statically built Storybook.
@@ -30,15 +30,15 @@ In your [`.storybook/main.js`](../configure/index.md#configure-story-rendering)
-
+
-Limitation: Addons in composed Storybooks will not work as they normally do in a non-composed Storybook.
+Addons in composed Storybooks will not work as they normally do in a non-composed Storybook.
## Compose local Storybooks
-You can also compose multiple Storybooks that are running locally. For instance, if you have a React Storybook and an Angular Storybook running on different ports, you can update your configuration file (i.e., `.storybook/main.js`) and reference them;
+You can also compose multiple Storybooks that are running locally. For instance, if you have a React Storybook and an Angular Storybook running on different ports, you can update your configuration file (i.e., `.storybook/main.js|ts`) and reference them as follows:
@@ -70,17 +70,13 @@ You can also compose Storybooks based on the current development environment (e.
-Similar to the other fields available in Storybook’s configuration file, the `refs` field can also be a function that accepts a config parameter containing Storybook’s configuration object. Check the [Webpack documentation](../builders/webpack.md#override-the-default-configuration) to learn more about it.
+Similar to other fields available in Storybook’s configuration file, the `refs` field can also be a function that accepts a `config` parameter containing Storybook’s configuration object. See the [API reference](../api/main-config-refs.md) for more information.
## Improve your Storybook composition
-So far, we've seen how we can use composition with local or published Storybooks. As your Storybook will grow in time with your stories or through composition with other Storybooks, you can optimize the deployment process using various methods.
-
-### With feature flags
-
-If you're using Storybook 6.4, or higher, you can optimize your composition via the `buildStoriesJson` feature flag, allowing you to generate `index.json` and `stories.json` files with the required information, providing you with a seamless integration without the need for additional dependencies. For example:
+Out of the box, Storybook allows you to compose Storybooks both locally and remotely with a minor change to your configuration. However, as your Storybook grows, you might want to optimize the composition process to improve the overall performance and user experience of your Storybook by enabling the `buildStoriesJson` feature flag that will generate the `index.json` and `stories.json` files with the required information to populate the UI with your composed Storybook stories automatically. For example:
@@ -93,62 +89,32 @@ If you're using Storybook 6.4, or higher, you can optimize your composition via
-
+
-If you already enabled automatic code splitting via the [`storyStoreV7`](https://storybook.js.org/docs/builders/webpack#code-splitting), you won't need this flag as it will automatically generate the `index.json` file.
+If you're working with a Storybook version 7.0 or higher, this flag is enabled by default. However, if you're working with an older version and you configured your Storybook to use the [`storyStoreV7`](../api/main-config-features.md#storystorev7) feature flag, you won't need this flag as it will automatically generate the required `index.json` file for you to use.
-When you compose a Storybook featuring this flag, it will use the information retrieved from the file to populate the UI with your composed Storybook stories automatically. Here's an example of the output generated by the `index.json` file:
-
-
-
-
-
-
+## Troubleshooting
-### With the CLI
+### Storybook composition is not working with my project
-If you're working with an outdated Storybook version or have a project-specific requirement that prevents you from enabling the `buildStoriesJson` feature flag. In that case, you can use Storybook's CLI to automatically generate the `index.json` file when you deploy your Storybook. For example:
-
-```shell
-npx storybook extract
-```
-
-
-
-`storybook extract` uses [Puppeteer](https://www.npmjs.com/package/puppeteer), which downloads and installs Chromium. Set the environment `SB_CHROMIUM_PATH` to configure your local Chromium installation.
-
-
-
-Although a good approach to improve composition, it comes with a cost, as it will require an additional dependency being added and increased build times. Once it finishes executing, it will generate an `index.json` file in the default build directory (`storybook-static`) with the information related to your Storybook. Here’s an example of the file contents:
+If you're working with an outdated Storybook version or have a project-specific requirement that prevents you from updating your Storybook to the latest version, you can rely on the Storybook CLI to generate the `index.json` file when you deploy your Storybook. For example:
-Linking to a Storybook deployed using this approach will yield all the stories and other relevant information displayed in the UI.
-
-If you need, you can also add additional arguments to this command. For instance, if you want to generate the `index.json` file into a custom directory, you can use the following:
-
-```shell
-npx storybook extract my-built-storybook-directory my-other-directory/index.json
-```
-
-When executed, it will look up a built Storybook in the `my-built-storybook-directory` and create the `index.json` file in the `my-other-directory` with all the necessary information.
-
-
+
-If you need to use the arguments, you’ll need to include both of them, or the command will fail.
+The usage of a specific version of the CLI is intended as the `extract` command is not available in Storybook 8.0 or higher. It also requires you to provide additional configuration to generate the `index.json` file accurately. See the [previous documentation](../../../release-7-5/docs/sharing/storybook-composition.md) for more information.
diff --git a/docs/snippets/common/storybook-extract-result.json.mdx b/docs/snippets/common/storybook-extract-result.json.mdx
deleted file mode 100644
index 0bf8a886f784..000000000000
--- a/docs/snippets/common/storybook-extract-result.json.mdx
+++ /dev/null
@@ -1,38 +0,0 @@
-```json
-{
- "v": 2,
- "globalParameters": {},
- "kindParameters": {
- "components/myComponent": {
- "fileName": 445,
- "framework": "react"
- },
- "components/myOtherComponent": {
- "fileName": 447,
- "framework": "react"
- }
- },
- "stories": {
- "components-mycomponent--simple": {
- "id": "components-mycomponent--simple",
- "name": "Simple",
- "kind": "components/myComponent",
- "story": "Simple",
- "parameters": {
- "__id": "components-mycomponent--simple",
- "__isArgsStory": true
- }
- },
- "components-myothercomponent--simple": {
- "id": "components-myothercomponent--simple",
- "name": "Simple",
- "kind": "components/myothercomponent",
- "story": "Simple",
- "parameters": {
- "__id": "components-myothercomponent--simple",
- "__isArgsStory": true
- }
- }
- }
-}
-```
diff --git a/docs/snippets/common/storybook-extract-specific-version.npx.js.mdx b/docs/snippets/common/storybook-extract-specific-version.npx.js.mdx
new file mode 100644
index 000000000000..828643a532c0
--- /dev/null
+++ b/docs/snippets/common/storybook-extract-specific-version.npx.js.mdx
@@ -0,0 +1,3 @@
+```shell
+npx storybook@7.5.3 extract
+```
diff --git a/docs/snippets/common/storybook-extract-specific-version.pnpm.js.mdx b/docs/snippets/common/storybook-extract-specific-version.pnpm.js.mdx
new file mode 100644
index 000000000000..55b882441147
--- /dev/null
+++ b/docs/snippets/common/storybook-extract-specific-version.pnpm.js.mdx
@@ -0,0 +1,3 @@
+```shell
+pnpm dlx storybook@7.5.3 extract
+```
diff --git a/docs/snippets/common/storybook-extract-specific-version.yarn.js.mdx b/docs/snippets/common/storybook-extract-specific-version.yarn.js.mdx
new file mode 100644
index 000000000000..b821fcd2357a
--- /dev/null
+++ b/docs/snippets/common/storybook-extract-specific-version.yarn.js.mdx
@@ -0,0 +1,3 @@
+```shell
+yarn dlx storybook@7.5.3 extract
+```
diff --git a/docs/snippets/common/storybook-storiesjsonflag-result.json.mdx b/docs/snippets/common/storybook-storiesjsonflag-result.json.mdx
deleted file mode 100644
index bc8c9814631a..000000000000
--- a/docs/snippets/common/storybook-storiesjsonflag-result.json.mdx
+++ /dev/null
@@ -1,33 +0,0 @@
-```json
-{
- "v": 3,
- "stories": {
- "components-mycomponent--simple": {
- "id": "components-mycomponent--simple",
- "title": "Components/MyComponent",
- "name": "Simple",
- "importPath": "./src/components/MyComponent.stories.jsx",
- "kind": "Components/MyComponent",
- "story": "Simple",
- "parameters": {
- "__id": "components-mycomponent--simple",
- "docsOnly": false,
- "fileName": "./src/components/MyComponent.stories.jsx"
- }
- },
- "components-myothercomponent--simple": {
- "id": "components-myothercomponent--simple",
- "title": "Components/MyOtherComponent",
- "name": "Simple",
- "importPath": "./src/components/MyOtherComponent.stories.jsx",
- "kind": "Example/Button",
- "story": "Simple",
- "parameters": {
- "__id": "components-myothercomponent--simple",
- "docsOnly": false,
- "fileName": "./src/components/MyOtherComponent.stories.jsx"
- }
- }
- }
-}
-```
diff --git a/docs/versions/next.json b/docs/versions/next.json
index fcd9f1cce99a..7de16aa408a1 100644
--- a/docs/versions/next.json
+++ b/docs/versions/next.json
@@ -1 +1 @@
-{"version":"8.0.0-alpha.7","info":{"plain":"- Addon-Docs: Upgrade to MDX3 - [#25303](https://github.com/storybookjs/storybook/pull/25303), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Add Storyshots migration notice - [#25327](https://github.com/storybookjs/storybook/pull/25327), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Fix regex used in upgrade command - [#25284](https://github.com/storybookjs/storybook/pull/25284), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Remove --use-npm flag - [#25414](https://github.com/storybookjs/storybook/pull/25414), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove unused warnOnLegacyHierarchySeparator type - [#25416](https://github.com/storybookjs/storybook/pull/25416), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove vite plugins and drop Vite 3 support - [#25427](https://github.com/storybookjs/storybook/pull/25427), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Maintenance: Add comment to deprecation notice in Button component - [#25411](https://github.com/storybookjs/storybook/pull/25411), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix about page layout - [#25396](https://github.com/storybookjs/storybook/pull/25396), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Viewport: Store viewport, rotation in globals - [#25423](https://github.com/storybookjs/storybook/pull/25423), thanks [@shilman](https://github.com/shilman)!\n- Vite: Fix Vite 5 CJS warnings - [#25005](https://github.com/storybookjs/storybook/pull/25005), thanks [@JReinhold](https://github.com/JReinhold)!"}}
+{"version":"8.0.0-alpha.8","info":{"plain":"- Addon Links: Remove LinkTo from direct import - [#25418](https://github.com/storybookjs/storybook/pull/25418), thanks [@yannbf](https://github.com/yannbf)!\n- Addon docs: Remove deprecated parameters - [#25469](https://github.com/storybookjs/storybook/pull/25469), thanks [@yannbf](https://github.com/yannbf)!\n- Builder Vite: Remove StorybookViteConfig type in favor of StorybookConfig - [#25441](https://github.com/storybookjs/storybook/pull/25441), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Error on explicit actions while rendering or playing - [#25238](https://github.com/storybookjs/storybook/pull/25238), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Core: Remove collapseAll and expandAll methods - [#25486](https://github.com/storybookjs/storybook/pull/25486), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove storyIndexers in favor of experimental_indexers - [#25468](https://github.com/storybookjs/storybook/pull/25468), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove unused staticDir type - [#25415](https://github.com/storybookjs/storybook/pull/25415), thanks [@yannbf](https://github.com/yannbf)!\n- Doc blocks: Remove deprecated props from Description block - [#25457](https://github.com/storybookjs/storybook/pull/25457), thanks [@yannbf](https://github.com/yannbf)!\n- Manager API: Remove deprecated navigateToSettingsPage method - [#25467](https://github.com/storybookjs/storybook/pull/25467), thanks [@yannbf](https://github.com/yannbf)!\n- React: Remove deprecated setGlobalConfig portable stories api - [#25442](https://github.com/storybookjs/storybook/pull/25442), thanks [@yannbf](https://github.com/yannbf)!\n- TypeScript: Remove deprecated addons module types - [#25485](https://github.com/storybookjs/storybook/pull/25485), thanks [@yannbf](https://github.com/yannbf)!\n- Types: Remove DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta types - [#25477](https://github.com/storybookjs/storybook/pull/25477), thanks [@yannbf](https://github.com/yannbf)!\n- Types: Remove Framework in favor of Renderer types - [#25476](https://github.com/storybookjs/storybook/pull/25476), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Remove deprecated WithTooltip props - [#25440](https://github.com/storybookjs/storybook/pull/25440), thanks [@yannbf](https://github.com/yannbf)!"}}
diff --git a/scripts/release/__tests__/ensure-next-ahead.test.ts b/scripts/release/__tests__/ensure-next-ahead.test.ts
index 7e7aa3e18666..d7a3f99c03b7 100644
--- a/scripts/release/__tests__/ensure-next-ahead.test.ts
+++ b/scripts/release/__tests__/ensure-next-ahead.test.ts
@@ -1,4 +1,3 @@
-/* eslint-disable global-require */
/* eslint-disable no-underscore-dangle */
import path from 'path';
import { vi, describe, it, expect, beforeEach } from 'vitest';
diff --git a/scripts/release/__tests__/label-patches.test.ts b/scripts/release/__tests__/label-patches.test.ts
index 8f221f88b961..29da21758c6e 100644
--- a/scripts/release/__tests__/label-patches.test.ts
+++ b/scripts/release/__tests__/label-patches.test.ts
@@ -138,7 +138,7 @@ it('should label the PR associated with cherry picks in the current branch', asy
.trim()
: text
)
- .filter((it) => it !== '');
+ .filter((text) => text !== '');
expect(stderrCalls).toMatchInlineSnapshot(`
[
diff --git a/scripts/release/__tests__/version.test.ts b/scripts/release/__tests__/version.test.ts
index cfe382b15aee..2f5ffb8ea9b0 100644
--- a/scripts/release/__tests__/version.test.ts
+++ b/scripts/release/__tests__/version.test.ts
@@ -1,4 +1,3 @@
-/* eslint-disable global-require */
/* eslint-disable no-underscore-dangle */
import { describe, it, expect, vi } from 'vitest';
import path from 'path';
diff --git a/scripts/release/__tests__/write-changelog.test.ts b/scripts/release/__tests__/write-changelog.test.ts
index 80c7f036508f..5aa4c8319054 100644
--- a/scripts/release/__tests__/write-changelog.test.ts
+++ b/scripts/release/__tests__/write-changelog.test.ts
@@ -1,5 +1,5 @@
/* eslint-disable jest/no-mocks-import */
-/* eslint-disable global-require */
+
/* eslint-disable no-underscore-dangle */
import path from 'path';
import dedent from 'ts-dedent';
diff --git a/test-storybooks/external-docs/components/AccountForm.stories.tsx b/test-storybooks/external-docs/components/AccountForm.stories.tsx
index c4579abaf5e3..10280adb253a 100644
--- a/test-storybooks/external-docs/components/AccountForm.stories.tsx
+++ b/test-storybooks/external-docs/components/AccountForm.stories.tsx
@@ -1,6 +1,6 @@
/* eslint-disable storybook/use-storybook-testing-library */
// @TODO: use addon-interactions and remove the rule disable above
-import type { ComponentStoryObj, ComponentMeta } from '@storybook/react';
+import type { StoryObj, Meta } from '@storybook/react';
import { screen } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { AccountForm } from './AccountForm';
@@ -12,9 +12,9 @@ export default {
parameters: {
layout: 'centered',
},
-} as ComponentMeta;
+} as Meta;
-type Story = ComponentStoryObj;
+type Story = StoryObj;
export const Standard: Story = {
args: { passwordVerification: false },
@@ -54,7 +54,7 @@ export const StandardFailHover: Story = {
},
};
-export const Verification: ComponentStoryObj = {
+export const Verification: StoryObj = {
args: { passwordVerification: true },
};