diff --git a/code/builders/builder-vite/src/build.ts b/code/builders/builder-vite/src/build.ts index ebf4f030e8b8..ff8f46c8bed3 100644 --- a/code/builders/builder-vite/src/build.ts +++ b/code/builders/builder-vite/src/build.ts @@ -41,7 +41,7 @@ export async function build(options: Options) { const turbosnapPluginName = 'rollup-plugin-turbosnap'; const hasTurbosnapPlugin = - finalConfig.plugins && hasVitePlugins(finalConfig.plugins, [turbosnapPluginName]); + finalConfig.plugins && (await hasVitePlugins(finalConfig.plugins, [turbosnapPluginName])); if (hasTurbosnapPlugin) { logger.warn(dedent`Found '${turbosnapPluginName}' which is now included by default in Storybook 8. Removing from your plugins list. Ensure you pass \`--webpack-stats-json\` to generate stats. @@ -53,6 +53,9 @@ export async function build(options: Options) { await viteBuild(await sanitizeEnvVars(options, finalConfig)); - const statsPlugin = findPlugin(finalConfig, 'rollup-plugin-webpack-stats') as WebpackStatsPlugin; + const statsPlugin = findPlugin( + finalConfig, + 'storybook:rollup-plugin-webpack-stats' + ) as WebpackStatsPlugin; return statsPlugin?.storybookGetStats(); } diff --git a/code/e2e-tests/addon-docs.spec.ts b/code/e2e-tests/addon-docs.spec.ts index 9be08c4b674a..4ae3da33e99e 100644 --- a/code/e2e-tests/addon-docs.spec.ts +++ b/code/e2e-tests/addon-docs.spec.ts @@ -34,8 +34,7 @@ test.describe('addon-docs', () => { await expect(anotherStory).toContainText('Another button, just to show multiple stories'); }); - // FIXME - get rid of the flake - test.skip('should show source=code view for stories', async ({ page }) => { + test('should show source=code view for stories', async ({ page }) => { const skipped = [ // SSv6 does not render stories in the correct order in our sandboxes 'internal\\/ssv6', diff --git a/code/e2e-tests/tags.spec.ts b/code/e2e-tests/tags.spec.ts index e3d79723c8f8..37fb76fb814c 100644 --- a/code/e2e-tests/tags.spec.ts +++ b/code/e2e-tests/tags.spec.ts @@ -3,8 +3,7 @@ import { SbPage } from './util'; const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; -// FIXME - get rid of the flake -test.describe.skip('tags', () => { +test.describe('tags', () => { test.beforeEach(async ({ page }) => { await page.goto(storybookUrl); await new SbPage(page).waitUntilLoaded(); diff --git a/code/frameworks/nextjs/src/preset.ts b/code/frameworks/nextjs/src/preset.ts index bb7ac0ddf153..e76db8104d1b 100644 --- a/code/frameworks/nextjs/src/preset.ts +++ b/code/frameworks/nextjs/src/preset.ts @@ -117,7 +117,8 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig, }); const babelRCPath = join(getProjectRoot(), '.babelrc'); - const hasBabelConfig = fs.existsSync(babelRCPath); + const babelConfigPath = join(getProjectRoot(), 'babel.config.js'); + const hasBabelConfig = fs.existsSync(babelRCPath) || fs.existsSync(babelConfigPath); const nextjsVersion = getNextjsVersion(); const isDevelopment = options.configType !== 'PRODUCTION'; diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index aee4d038a5e1..fe4feb023148 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -56,6 +56,7 @@ "prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts" }, "dependencies": { + "@babel/core": "^7.23.0", "@babel/types": "^7.23.0", "@ndelangen/get-tarball": "^3.0.7", "@storybook/codemod": "workspace:*", diff --git a/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts b/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts index 9bf74a288416..d57fbd28a10c 100644 --- a/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts +++ b/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts @@ -10,7 +10,7 @@ interface AngularBuildersMultiprojectRunOptions {} export const angularBuildersMultiproject: Fix = { id: 'angular-builders-multiproject', - promptOnly: true, + promptType: 'manual', async check({ packageManager, mainConfig }) { // Skip in case of NX diff --git a/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts b/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts index ce9d01ccd96a..469383834cc1 100644 --- a/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts +++ b/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts @@ -9,7 +9,7 @@ interface IncompatibleAddonsOptions { export const incompatibleAddons: Fix = { id: 'incompatible-addons', - promptOnly: true, + promptType: 'manual', async check({ mainConfig, packageManager }) { const incompatibleAddonList = await getIncompatibleAddons(mainConfig, packageManager); diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index 030e31baa6dc..263abf85cf6f 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -21,6 +21,8 @@ import { wrapRequire } from './wrap-require'; import { reactDocgen } from './react-docgen'; import { removeReactDependency } from './prompt-remove-react'; import { storyshotsMigration } from './storyshots-migration'; +import { removeArgtypesRegex } from './remove-argtypes-regex'; +import { webpack5CompilerSetup } from './webpack5-compiler-setup'; import { removeJestTestingLibrary } from './remove-jest-testing-library'; export * from '../types'; @@ -37,6 +39,7 @@ export const allFixes: Fix[] = [ sbBinary, sbScripts, incompatibleAddons, + removeArgtypesRegex, removeJestTestingLibrary, removedGlobalClientAPIs, mdx1to2, @@ -48,6 +51,7 @@ export const allFixes: Fix[] = [ reactDocgen, storyshotsMigration, removeReactDependency, + webpack5CompilerSetup, ]; export const initFixes: Fix[] = [eslintPlugin]; diff --git a/code/lib/cli/src/automigrate/fixes/prompt-remove-react.ts b/code/lib/cli/src/automigrate/fixes/prompt-remove-react.ts index eb93ce015b08..a7586a03ff15 100644 --- a/code/lib/cli/src/automigrate/fixes/prompt-remove-react.ts +++ b/code/lib/cli/src/automigrate/fixes/prompt-remove-react.ts @@ -5,7 +5,7 @@ import type { Fix } from '../types'; export const removeReactDependency: Fix<{}> = { id: 'remove-react-dependency', - promptOnly: true, + promptType: 'manual', async check({ packageManager, mainConfig, storybookVersion }) { // when the user is using the react renderer, we should not prompt them to remove react diff --git a/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts b/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts new file mode 100644 index 000000000000..6a517fc0be0c --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts @@ -0,0 +1,81 @@ +import type { Fix } from '../types'; +import * as fs from 'node:fs/promises'; +import * as babel from '@babel/core'; +import type { BabelFile, NodePath } from '@babel/core'; +import { babelParse } from '@storybook/csf-tools'; +import dedent from 'ts-dedent'; +import chalk from 'chalk'; + +export const removeArgtypesRegex: Fix<{ argTypesRegex: NodePath; previewConfigPath: string }> = { + id: 'remove-argtypes-regex', + promptType: 'manual', + async check({ previewConfigPath }) { + if (!previewConfigPath) return null; + + const previewFile = await fs.readFile(previewConfigPath, { encoding: 'utf-8' }); + + // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 + const file: BabelFile = new babel.File( + { filename: previewConfigPath }, + { code: previewFile, ast: babelParse(previewFile) } + ); + + let argTypesRegex; + + file.path.traverse({ + Identifier: (path) => { + if (path.node.name === 'argTypesRegex') { + argTypesRegex = path; + } + }, + }); + + return argTypesRegex ? { argTypesRegex, previewConfigPath } : null; + }, + prompt({ argTypesRegex, previewConfigPath }) { + const snippet = dedent` + import { fn } from '@storybook/test'; + export default { + args: { onClick: fn() }, // will log to the action panel when clicked + };`; + + // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 + const file: BabelFile = new babel.File( + { file: 'story.tsx' }, + { code: snippet, ast: babelParse(snippet) } + ); + + let formattedSnippet; + file.path.traverse({ + Identifier: (path) => { + if (path.node.name === 'fn') { + formattedSnippet = path.buildCodeFrameError(``).message; + } + }, + }); + + return dedent` + ${chalk.bold('Attention')}: We've detected that you're using argTypesRegex: + + ${argTypesRegex.buildCodeFrameError(`${previewConfigPath}`).message} + + In Storybook 8, we recommend removing this regex. + Assign explicit spies with the ${chalk.cyan('fn')} function instead: + ${formattedSnippet} + + The above pattern is needed when using spies in the play function, ${chalk.bold( + 'even' + )} if you keep using argTypesRegex. + Implicit spies (based on a combination of argTypesRegex and docgen) is not supported in Storybook 8. + + Use the following command to check for spy usages in your play functions: + ${chalk.cyan( + 'npx storybook migrate find-implicit-spies --glob="**/*.stories.@(js|jsx|ts|tsx)"' + )} + + Make sure to assign an explicit ${chalk.cyan('fn')} to your args for those usages. + + For more information please visit our migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#implicit-actions-can-not-be-used-during-rendering-for-example-in-the-play-function + `; + }, +}; diff --git a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts index 4a1304dae1a6..2f25e5277096 100644 --- a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts +++ b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts @@ -19,7 +19,7 @@ interface GlobalClientAPIOptions { export const removedGlobalClientAPIs: Fix = { id: 'removedglobalclientapis', - promptOnly: true, + promptType: 'manual', async check({ previewConfigPath }) { if (previewConfigPath) { diff --git a/code/lib/cli/src/automigrate/fixes/remove-jest-testing-library.ts b/code/lib/cli/src/automigrate/fixes/remove-jest-testing-library.ts index 87cf964468b3..ba238dd2740a 100644 --- a/code/lib/cli/src/automigrate/fixes/remove-jest-testing-library.ts +++ b/code/lib/cli/src/automigrate/fixes/remove-jest-testing-library.ts @@ -4,7 +4,7 @@ import type { Fix } from '../types'; export const removeJestTestingLibrary: Fix<{ incompatiblePackages: string[] }> = { id: 'remove-jest-testing-library', - promptOnly: true, + promptType: 'manual', async check({ mainConfig, packageManager }) { const deps = await packageManager.getAllDependencies(); diff --git a/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts b/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts index 6d047f88449f..6d132037c3e0 100644 --- a/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts +++ b/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts @@ -4,7 +4,7 @@ import type { Fix } from '../types'; export const storyshotsMigration: Fix = { id: 'storyshots-migration', - promptOnly: true, + promptType: 'manual', async check({ mainConfig, packageManager }) { const allDeps = await packageManager.getAllDependencies(); diff --git a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts index f8047a839af9..1719035fc220 100644 --- a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts +++ b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts @@ -5,7 +5,7 @@ import { getFrameworkPackageName } from '../helpers/mainConfigFile'; import { frameworkToRenderer } from '../../helpers'; import { frameworkPackages } from '@storybook/core-common'; -interface Webpack5RunOptions { +interface ViteConfigFileRunOptions { plugins: string[]; existed: boolean; } @@ -108,4 +108,4 @@ export const viteConfigFile = { This change was necessary to support newer versions of Vite. `; }, -} satisfies Fix; +} satisfies Fix; diff --git a/code/lib/cli/src/automigrate/fixes/vite4.ts b/code/lib/cli/src/automigrate/fixes/vite4.ts index d04c4abd10d7..f85cc4d57cef 100644 --- a/code/lib/cli/src/automigrate/fixes/vite4.ts +++ b/code/lib/cli/src/automigrate/fixes/vite4.ts @@ -5,7 +5,7 @@ import type { Fix } from '../types'; const logger = console; -interface Webpack5RunOptions { +interface Vite4RunOptions { viteVersion: string | null; } @@ -40,4 +40,4 @@ export const vite4 = { await packageManager.addDependencies({ installAsDevDependencies: true }, deps); } }, -} satisfies Fix; +} satisfies Fix; diff --git a/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.test.ts b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.test.ts new file mode 100644 index 000000000000..dcebc1f28b8b --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.test.ts @@ -0,0 +1,518 @@ +import { vi, describe, it, expect } from 'vitest'; +import type { StorybookConfig } from '@storybook/types'; +import type { JsPackageManager } from '@storybook/core-common'; +import { webpack5CompilerSetup } from './webpack5-compiler-setup'; +import { CoreWebpackCompilers } from '../../project_types'; + +const check = async ({ + packageManager, + mainConfig, + storybookVersion = '8.0.0', +}: { + packageManager?: Partial; + main?: Partial & Record; + storybookVersion?: string; + mainConfig?: Partial; +}) => { + return webpack5CompilerSetup.check({ + packageManager: packageManager as any, + configDir: '', + storybookVersion, + mainConfig: mainConfig as any, + }); +}; + +const promptMocks = vi.hoisted(() => { + return { + default: vi.fn(), + }; +}); + +vi.mock('prompts', () => { + return { + default: promptMocks.default, + }; +}); + +// mock chalk yellow and cyan +vi.mock('chalk', () => { + return { + default: { + yellow: (str: string) => str, + cyan: (str: string) => str, + }, + }; +}); + +describe('webpack5Migration check function', () => { + describe('return null', async () => { + it('should return null if one of the addons is already installed', async () => { + const result = check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + addons: ['@storybook/addon-webpack5-compiler-swc'], + framework: { + name: '@storybook/react-webpack5', + options: { + builder: { + useSWC: true, + }, + }, + }, + }, + }); + + expect(result).resolves.toBeNull(); + }); + + it('should return null if the builder is not webpack5', async () => { + const result = check({ + mainConfig: { + framework: { + name: '@storybook/react-vite', + }, + }, + }); + + await expect(result).resolves.toBeNull(); + }); + + it('should return null if the framework is Angular', async () => { + const result = check({ + mainConfig: { + framework: '@storybook/angular', + }, + }); + + await expect(result).resolves.toBeNull(); + // ... + }); + + it('should return null if the framework is Ember', async () => { + const result = check({ + mainConfig: { + framework: { + name: '@storybook/ember', + }, + }, + }); + + await expect(result).resolves.toBeNull(); + }); + + it('should return null if the framework is Webpack5 based but a different framework builder is used', async () => { + const result = check({ + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + options: { + builder: '@storybook/builder-vite', + }, + }, + }, + }); + + await expect(result).resolves.toBeNull(); + }); + + it('should return null if the framework is Webpack5 based but a different core builder is used', async () => { + const result = check({ + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + }, + core: { + builder: '@storybook/builder-vite', + }, + }, + }); + + await expect(result).resolves.toBeNull(); + }); + + it('should return null if the framework is CRA based', async () => { + const result = check({ + packageManager: { + getPackageVersion: (name) => { + if (name === 'react-scripts') { + return Promise.resolve('5.0.0'); + } + + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + }, + }, + }); + + await expect(result).resolves.toBeNull(); + }); + }); + + describe('useSWC', () => { + it('should return shouldRemoveSWCFlag: true when useSWC flag is set to true', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + options: { + builder: { + useSWC: true, + }, + }, + }, + }, + }); + + expect(result).contains({ + shouldRemoveSWCFlag: true, + }); + }); + + it('should return shouldRemoveSWCFlag: true when useSWC flag is set to false', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + options: { + builder: { + useSWC: false, + }, + }, + }, + }, + }); + + expect(result).contains({ + shouldRemoveSWCFlag: true, + }); + }); + + it('should return shouldRemoveSWCFlag: false when useSWC flag is not set', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + options: { + builder: {}, + }, + }, + }, + }); + + expect(result).contains({ + shouldRemoveSWCFlag: false, + }); + }); + }); + + describe('Next.js', () => { + it('should return isNextJs: true when the framework is nextjs', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/nextjs', + }, + }, + }); + + expect(result).contains({ + isNextJs: true, + }); + }); + + it('should return isNextJs: true AND should return shouldRemoveSWCFlag: true when useSWC flag is set', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/nextjs', + options: { + builder: { + useSWC: true, + }, + }, + }, + }, + }); + + expect(result).contains({ + isNextJs: true, + shouldRemoveSWCFlag: true, + }); + }); + + it('should return isNextJs: false when the framework is not nextjs', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + }, + }, + }); + + expect(result).contains({ + isNextJs: false, + }); + }); + }); + + describe('return options', () => { + it('should return defaultCompiler: babel when useSWC flag is not set', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + }, + }, + }); + + expect(result).contains({ + defaultCompiler: CoreWebpackCompilers.Babel, + }); + }); + + describe('user selects swc', () => { + it('should return defaultCompiler: swc when useSWC flag is set', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/react-webpack5', + options: { + builder: { + useSWC: true, + }, + }, + }, + }, + }); + + expect(result).contains({ + defaultCompiler: CoreWebpackCompilers.SWC, + }); + }); + }); + + it('should return options if the framework is unknown but webpack5 was detected', async () => { + const result = await check({ + packageManager: { + getPackageVersion: (name) => { + if (name === 'webpack') { + return Promise.resolve('5.0.0'); + } + + return Promise.resolve(null); + }, + }, + mainConfig: { + framework: { + name: '@storybook/unknown', + }, + }, + }); + + expect(result).not.toBeNull(); + }); + }); +}); + +describe('promptOnly', () => { + it('should return notification if isNextJs = true and shouldRemoveSWCFlag = false', () => { + const promptType = webpack5CompilerSetup.promptType({ + isNextJs: true, + shouldRemoveSWCFlag: false, + defaultCompiler: undefined, + }); + + expect(promptType).toBe('notification'); + }); + + it('should return auto if isNextJs = false', () => { + const promptType = webpack5CompilerSetup.promptType({ + isNextJs: false, + shouldRemoveSWCFlag: false, + defaultCompiler: undefined, + }); + + expect(promptType).toBe('auto'); + }); + + it('should return auto if shouldRemoveSWCFlag is true', () => { + const promptType = webpack5CompilerSetup.promptType({ + isNextJs: true, + shouldRemoveSWCFlag: true, + defaultCompiler: undefined, + }); + + expect(promptType).toBe('auto'); + }); +}); + +describe('prompt', () => { + it('shouldRemoveSWCFlag = true', async () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: true, + isNextJs: false, + defaultCompiler: CoreWebpackCompilers.SWC, + }); + + expect(prompt).toMatchInlineSnapshot(` + "We need to update your Storybook configuration for Webpack 5. + The framework.options.builder.useSWC flag will be removed. + + Storybook's Webpack5 builder is now compiler agnostic, meaning you have to install an additional addon to set up a compiler for Webpack5. + + We have detected, that you want to use SWC as the compiler for Webpack5. + + In the next step, Storybook will install @storybook/addon-webpack5-compiler-swc and will add it to your addons list in your Storybook config. + + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: https://storybook.js.org/docs/8.0/builders/webpack#compiler-support" + `); + }); + + it('shouldRemoveSWCFlag = false', async () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: false, + isNextJs: false, + defaultCompiler: CoreWebpackCompilers.SWC, + }); + + expect(prompt).toMatchInlineSnapshot(` + "Storybook's Webpack5 builder is now compiler agnostic, meaning you have to install an additional addon to set up a compiler for Webpack5. + + We have detected, that you want to use SWC as the compiler for Webpack5. + + In the next step, Storybook will install @storybook/addon-webpack5-compiler-swc and will add it to your addons list in your Storybook config. + + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: https://storybook.js.org/docs/8.0/builders/webpack#compiler-support" + `); + }); + + it('defaultCompiler = babel', async () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: false, + isNextJs: false, + defaultCompiler: CoreWebpackCompilers.Babel, + }); + + expect(prompt).toMatchInlineSnapshot(` + "Storybook's Webpack5 builder is now compiler agnostic, meaning you can choose a compiler addon that best fits your project: + + - Babel: A vast ecosystem and is battle-tested. It's a robust choice if you have an extensive Babel setup or need specific Babel plugins for your project. + - SWC: Fast and easy to configure. Ideal if you want faster builds and have a straightforward configuration without the need for Babel's extensibility. + + In the next step, Storybook will ask you to choose a compiler to automatically set it up for you. + + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: https://storybook.js.org/docs/8.0/builders/webpack#compiler-support" + `); + }); + + it('isNextJs = true', () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: true, + isNextJs: true, + defaultCompiler: CoreWebpackCompilers.SWC, + }); + + expect(prompt).toMatchInlineSnapshot(` + "We need to update your Storybook configuration for Webpack 5. + The framework.options.builder.useSWC flag will be removed. + + Storybook now detects whether it should use Babel or SWC as a compiler by applying the same logic as Next.js itself: + + - If you have a .babelrc (or babel.config.js) file in your project, Storybook will use Babel as the compiler. + - If you have a .babelrc (or babel.config.js) file in your project and you have set + experimental.forceSwcTransforms = true in your next.config.js file, + Storybook will use SWC as the compiler. + - If you don't have a .babelrc (or babel.config.js) file in your project, Storybook will use SWC as the compiler." + `); + }); + + it('isNextjs = false AND defaultCompiler = swc', () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: false, + isNextJs: false, + defaultCompiler: CoreWebpackCompilers.SWC, + }); + + expect(prompt).toMatchInlineSnapshot(` + "Storybook's Webpack5 builder is now compiler agnostic, meaning you have to install an additional addon to set up a compiler for Webpack5. + + We have detected, that you want to use SWC as the compiler for Webpack5. + + In the next step, Storybook will install @storybook/addon-webpack5-compiler-swc and will add it to your addons list in your Storybook config. + + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: https://storybook.js.org/docs/8.0/builders/webpack#compiler-support" + `); + }); + + it('isNextjs = false AND defaultCompiler = babel', () => { + const prompt = webpack5CompilerSetup.prompt({ + shouldRemoveSWCFlag: false, + isNextJs: false, + defaultCompiler: CoreWebpackCompilers.Babel, + }); + + expect(prompt).toMatchInlineSnapshot(` + "Storybook's Webpack5 builder is now compiler agnostic, meaning you can choose a compiler addon that best fits your project: + + - Babel: A vast ecosystem and is battle-tested. It's a robust choice if you have an extensive Babel setup or need specific Babel plugins for your project. + - SWC: Fast and easy to configure. Ideal if you want faster builds and have a straightforward configuration without the need for Babel's extensibility. + + In the next step, Storybook will ask you to choose a compiler to automatically set it up for you. + + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: https://storybook.js.org/docs/8.0/builders/webpack#compiler-support" + `); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts new file mode 100644 index 000000000000..a22f8a55fdd0 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts @@ -0,0 +1,210 @@ +import prompts from 'prompts'; +import type { SupportedFrameworks } from '@storybook/types'; +import { frameworkPackages } from '@storybook/core-common'; +import type { Fix } from '../types'; +import { + getAddonNames, + getBuilderPackageName, + getFrameworkOptions, + getFrameworkPackageName, + updateMainConfig, +} from '../helpers/mainConfigFile'; +import { frameworkToDefaultBuilder } from '../../helpers'; +import { + CoreBuilder, + CoreWebpackCompilers, + builderNameToCoreBuilder, + compilerNameToCoreCompiler, +} from '../../project_types'; +import dedent from 'ts-dedent'; +import chalk from 'chalk'; +import { add } from '../../add'; + +type Options = { + defaultCompiler?: CoreWebpackCompilers; + shouldRemoveSWCFlag: boolean; + isNextJs: boolean; +}; + +export const webpack5CompilerSetup = { + id: 'webpack5-compiler-setup', + + promptType(result) { + return result.isNextJs && !result.shouldRemoveSWCFlag ? 'notification' : 'auto'; + }, + + async check({ mainConfig, packageManager }) { + const addons = getAddonNames(mainConfig); + + if ( + addons.find( + (addon) => + addon.includes(CoreWebpackCompilers.Babel) || addon.includes(CoreWebpackCompilers.SWC) + ) + ) { + return null; + } + + const frameworkName = Object.entries(frameworkPackages).find( + ([name]) => name === getFrameworkPackageName(mainConfig) + )?.[1]; + + const builderPackageName = getBuilderPackageName(mainConfig); + const customCoreBuilder = builderPackageName + ? builderNameToCoreBuilder[builderPackageName] + : null; + + const defaultCoreBuilder = frameworkName + ? frameworkToDefaultBuilder[frameworkName] + : await (async () => { + const webpackVersion = await packageManager.getPackageVersion('webpack'); + return !!webpackVersion ? CoreBuilder.Webpack5 : CoreBuilder.Vite; + })(); + + const builder = customCoreBuilder || defaultCoreBuilder; + + if (builder !== CoreBuilder.Webpack5) { + return null; + } + + const excludedFrameworks: SupportedFrameworks[] = ['angular', 'ember']; + + const isExcludedFramework = frameworkName ? excludedFrameworks.includes(frameworkName) : false; + + if (isExcludedFramework) { + return null; + } + + const hasReactScriptsDependency = !!(await packageManager.getPackageVersion('react-scripts')); + + if (hasReactScriptsDependency) { + return null; + } + + const frameworkOptions = getFrameworkOptions(mainConfig); + + const defaultCompiler = frameworkOptions?.builder?.useSWC + ? CoreWebpackCompilers.SWC + : CoreWebpackCompilers.Babel; + + const shouldRemoveSWCFlag = frameworkOptions?.builder + ? 'useSWC' in frameworkOptions.builder + : false; + + if (frameworkName === 'nextjs') { + return { + compiler: undefined, + compilerPackageName: undefined, + shouldRemoveSWCFlag, + isNextJs: true, + }; + } + + return { + defaultCompiler, + shouldRemoveSWCFlag, + isNextJs: false, + }; + }, + + prompt({ defaultCompiler, shouldRemoveSWCFlag, isNextJs }) { + const message = []; + + if (shouldRemoveSWCFlag) { + message.push(dedent` + We need to update your Storybook configuration for Webpack 5. + The ${chalk.yellow('framework.options.builder.useSWC')} flag will be removed.`); + } + + if (isNextJs) { + message.push(dedent` + Storybook now detects whether it should use Babel or SWC as a compiler by applying the same logic as Next.js itself:\n + - If you have a ${chalk.yellow('.babelrc')} (or ${chalk.yellow( + 'babel.config.js' + )}) file in your project, Storybook will use Babel as the compiler. + - If you have a ${chalk.yellow('.babelrc')} (or ${chalk.yellow( + 'babel.config.js' + )}) file in your project and you have set + ${chalk.yellow('experimental.forceSwcTransforms = true')} in your ${chalk.yellow( + 'next.config.js' + )} file, + Storybook will use SWC as the compiler. + - If you don't have a ${chalk.yellow('.babelrc')} (or ${chalk.yellow( + 'babel.config.js' + )}) file in your project, Storybook will use SWC as the compiler. + `); + } else if (defaultCompiler === CoreWebpackCompilers.Babel) { + message.push(dedent` + Storybook's Webpack5 builder is now compiler agnostic, meaning you can choose a compiler addon that best fits your project:\n + - Babel: A vast ecosystem and is battle-tested. It's a robust choice if you have an extensive Babel setup or need specific Babel plugins for your project. + - SWC: Fast and easy to configure. Ideal if you want faster builds and have a straightforward configuration without the need for Babel's extensibility.\n + In the next step, Storybook will ask you to choose a compiler to automatically set it up for you.\n + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: ${chalk.yellow( + 'https://storybook.js.org/docs/8.0/builders/webpack#compiler-support' + )} + `); + } else { + message.push(dedent` + Storybook's Webpack5 builder is now compiler agnostic, meaning you have to install an additional addon to set up a compiler for Webpack5.\n + We have detected, that you want to use SWC as the compiler for Webpack5.\n + In the next step, Storybook will install @storybook/addon-webpack5-compiler-swc and will add it to your addons list in your Storybook config.\n + After the migration, you can switch Webpack5 compilers by swapping the addon in your project. + You can find more information here: ${chalk.yellow( + 'https://storybook.js.org/docs/8.0/builders/webpack#compiler-support' + )} + `); + } + + return message.join('\n\n'); + }, + + async run({ result, mainConfigPath, packageManager, skipInstall, dryRun }) { + const { defaultCompiler, shouldRemoveSWCFlag, isNextJs } = result; + + if (shouldRemoveSWCFlag) { + await updateMainConfig({ mainConfigPath, dryRun: !!dryRun }, (main) => { + main.removeField(['framework', 'options', 'builder', 'useSWC']); + }); + } + + if (!isNextJs) { + const compiler: CoreWebpackCompilers = + defaultCompiler === CoreWebpackCompilers.Babel + ? await askUserForCompilerChoice() + : CoreWebpackCompilers.SWC; + + const compilerPackageName = Object.entries(compilerNameToCoreCompiler).find( + ([, coreCompiler]) => coreCompiler === compiler + )![0]; + + await add(compilerPackageName, { + packageManager: packageManager.type, + skipPostinstall: !!skipInstall, + }); + } + }, +} satisfies Fix; + +async function askUserForCompilerChoice() { + const response = await prompts<'compiler'>({ + type: 'select', + name: 'compiler', + message: `Which compiler would you like to use?`, + choices: [ + { + title: 'Babel', + description: 'Choose Babel for a vast ecosystem and battle-tested reliability.', + value: CoreWebpackCompilers.Babel, + }, + { + title: 'SWC', + description: 'Choose SWC for fast builds and simple configuration.', + value: CoreWebpackCompilers.SWC, + }, + ], + initial: 0, + }); + + return response.compiler as CoreWebpackCompilers; +} diff --git a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts index c721dae39a31..2ba805c95614 100644 --- a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts @@ -42,11 +42,20 @@ export const getFrameworkPackageName = (mainConfig?: StorybookConfigRaw) => { * @returns - The package name of the builder. If not found, returns null. */ export const getBuilderPackageName = (mainConfig?: StorybookConfigRaw) => { - const packageNameOrPath = + const frameworkOptions = getFrameworkOptions(mainConfig); + + const frameworkBuilder = frameworkOptions?.builder; + + const frameworkBuilderName = + typeof frameworkBuilder === 'string' ? frameworkBuilder : frameworkBuilder?.options?.name; + + const coreBuilderName = typeof mainConfig?.core?.builder === 'string' ? mainConfig.core.builder : mainConfig?.core?.builder?.name; + const packageNameOrPath = coreBuilderName ?? frameworkBuilderName; + if (!packageNameOrPath) { return null; } @@ -56,6 +65,17 @@ export const getBuilderPackageName = (mainConfig?: StorybookConfigRaw) => { return builderPackages.find((pkg) => normalizedPath.endsWith(pkg)) || packageNameOrPath; }; +/** + * Given a Storybook configuration object, retrieves the configuration for the framework. + * @param mainConfig - The main Storybook configuration object to lookup. + * @returns - The configuration for the framework. If not found, returns null. + */ +export const getFrameworkOptions = ( + mainConfig?: StorybookConfigRaw +): Record | null => { + return typeof mainConfig?.framework === 'string' ? null : mainConfig?.framework?.options ?? null; +}; + /** * Returns a renderer package name given a framework package name. * @param frameworkPackageName - The package name of the framework to lookup. diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index 19d4ee8922e9..1e78d57863ce 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -20,6 +20,7 @@ import type { FixSummary, PreCheckFailure, AutofixOptionsFromCLI, + Prompt, } from './fixes'; import { FixStatus, allFixes } from './fixes'; import { cleanLog } from './helpers/cleanLog'; @@ -217,15 +218,29 @@ export async function runFixes({ } if (result) { + const promptType: Prompt = + typeof f.promptType === 'function' ? await f.promptType(result) : f.promptType ?? 'auto'; + logger.info(`\nšŸ”Ž found a '${chalk.cyan(f.id)}' migration:`); const message = f.prompt(result); + const getTitle = () => { + switch (promptType) { + case 'auto': + return 'Automigration detected'; + case 'manual': + return 'Manual migration detected'; + case 'notification': + return 'Migration notification'; + } + }; + logger.info( boxen(message, { borderStyle: 'round', padding: 1, borderColor: '#F1618C', - title: f.promptOnly ? 'Manual migration detected' : 'Automigration detected', + title: getTitle(), }) ); @@ -236,11 +251,11 @@ export async function runFixes({ runAnswer = { fix: false }; } else if (yes) { runAnswer = { fix: true }; - if (f.promptOnly) { + if (promptType === 'manual') { fixResults[f.id] = FixStatus.MANUAL_SUCCEEDED; fixSummary.manual.push(f.id); } - } else if (f.promptOnly) { + } else if (promptType === 'manual') { fixResults[f.id] = FixStatus.MANUAL_SUCCEEDED; fixSummary.manual.push(f.id); @@ -266,7 +281,7 @@ export async function runFixes({ fixResults[f.id] = FixStatus.MANUAL_SKIPPED; break; } - } else { + } else if (promptType === 'auto') { runAnswer = await prompts( { type: 'confirm', @@ -280,12 +295,26 @@ export async function runFixes({ }, } ); + } else if (promptType === 'notification') { + runAnswer = await prompts( + { + type: 'confirm', + name: 'fix', + message: `Do you want to continue?`, + initial: true, + }, + { + onCancel: () => { + throw new Error(); + }, + } + ); } } catch (err) { break; } - if (!f.promptOnly) { + if (promptType === 'auto') { invariant(runAnswer, 'runAnswer must be defined if not promptOnly'); if (runAnswer.fix) { try { diff --git a/code/lib/cli/src/automigrate/types.ts b/code/lib/cli/src/automigrate/types.ts index 97d20c09dc45..510cdcda24c1 100644 --- a/code/lib/cli/src/automigrate/types.ts +++ b/code/lib/cli/src/automigrate/types.ts @@ -19,9 +19,17 @@ export interface RunOptions { skipInstall?: boolean; } +/** + * promptType defines how the user will be prompted to apply an automigration fix + * - auto: the fix will be applied automatically + * - manual: the user will be prompted to apply the fix + * - notification: the user will be notified about the some changes. A fix isn't required + */ +export type Prompt = 'auto' | 'manual' | 'notification'; + export interface Fix { id: string; - promptOnly?: boolean; + promptType?: Prompt | ((result: ResultType) => Promise | Prompt); check: (options: CheckOptions) => Promise; prompt: (result: ResultType) => string; run?: (options: RunOptions) => Promise; diff --git a/code/lib/cli/src/dirs.ts b/code/lib/cli/src/dirs.ts index 213b1877aaee..1f41620b4ea6 100644 --- a/code/lib/cli/src/dirs.ts +++ b/code/lib/cli/src/dirs.ts @@ -6,9 +6,10 @@ import * as tempy from 'tempy'; import invariant from 'tiny-invariant'; import { externalFrameworks } from './project_types'; -import type { SupportedFrameworks, SupportedRenderers } from './project_types'; +import type { SupportedRenderers } from './project_types'; import type { JsPackageManager } from '@storybook/core-common'; import { versions } from '@storybook/core-common'; +import type { SupportedFrameworks } from '@storybook/types'; export function getCliDir() { return dirname(require.resolve('@storybook/cli/package.json')); diff --git a/code/lib/cli/src/generate.ts b/code/lib/cli/src/generate.ts index 250cd200d206..b4e02c322b46 100644 --- a/code/lib/cli/src/generate.ts +++ b/code/lib/cli/src/generate.ts @@ -6,13 +6,19 @@ import { sync as readUpSync } from 'read-pkg-up'; import invariant from 'tiny-invariant'; import { logger } from '@storybook/node-logger'; -import { addToGlobalContext } from '@storybook/telemetry'; -import { parseList, getEnvConfig, JsPackageManagerFactory, versions } from '@storybook/core-common'; +import { addToGlobalContext, telemetry } from '@storybook/telemetry'; +import { + parseList, + getEnvConfig, + JsPackageManagerFactory, + versions, + removeAddon as remove, +} from '@storybook/core-common'; +import { withTelemetry } from '@storybook/core-server'; import type { CommandOptions } from './generators/types'; import { initiate } from './initiate'; import { add } from './add'; -import { removeAddon as remove } from '@storybook/core-common'; import { migrate } from './migrate'; import { upgrade, type UpgradeOptions } from './upgrade'; import { sandbox } from './sandbox'; @@ -71,7 +77,14 @@ command('remove ') '--package-manager ', 'Force package manager for installing dependencies' ) - .action((addonName: string, options: any) => remove(addonName, options)); + .action((addonName: string, options: any) => + withTelemetry('remove', { cliOptions: options }, async () => { + await remove(addonName, options); + if (!options.disableTelemetry) { + await telemetry('remove', { addon: addonName, source: 'cli' }); + } + }) + ); command('upgrade') .description(`Upgrade your Storybook packages to v${versions.storybook}`) diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index 3c3cae9e5e5e..2f85d0af4549 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -5,8 +5,9 @@ import ora from 'ora'; import invariant from 'tiny-invariant'; import type { JsPackageManager } from '@storybook/core-common'; import { getPackageDetails, versions as packageVersions } from '@storybook/core-common'; +import type { SupportedFrameworks } from '@storybook/types'; import type { NpmOptions } from '../NpmOptions'; -import type { SupportedRenderers, SupportedFrameworks, Builder } from '../project_types'; +import type { SupportedRenderers, Builder } from '../project_types'; import { SupportedLanguage, externalFrameworks } from '../project_types'; import { copyTemplateFiles } from '../helpers'; import { configureMain, configurePreview } from './configure'; diff --git a/code/lib/cli/src/helpers.ts b/code/lib/cli/src/helpers.ts index bbf81816a061..ed273831eefb 100644 --- a/code/lib/cli/src/helpers.ts +++ b/code/lib/cli/src/helpers.ts @@ -13,7 +13,9 @@ import type { PackageJson, PackageJsonWithDepsAndDevDeps, } from '@storybook/core-common'; -import type { SupportedFrameworks, SupportedRenderers } from './project_types'; +import type { SupportedFrameworks } from '@storybook/types'; +import type { SupportedRenderers } from './project_types'; +import { CoreBuilder } from './project_types'; import { SupportedLanguage } from './project_types'; import { versions as storybookMonorepoPackages } from '@storybook/core-common'; @@ -134,22 +136,59 @@ export const frameworkToRenderer: Record< SupportedFrameworks | SupportedRenderers, SupportedRenderers | 'vue' > = { + // frameworks angular: 'angular', ember: 'ember', - html: 'html', + 'html-vite': 'html', + 'html-webpack5': 'html', nextjs: 'react', - preact: 'preact', + 'preact-vite': 'preact', + 'preact-webpack5': 'preact', qwik: 'qwik', - react: 'react', - 'react-native': 'react', - server: 'react', + 'react-vite': 'react', + 'react-webpack5': 'react', + 'server-webpack5': 'server', solid: 'solid', - svelte: 'svelte', + 'svelte-vite': 'svelte', + 'svelte-webpack5': 'svelte', sveltekit: 'svelte', - vue3: 'vue', + 'vue3-vite': 'vue3', + 'vue3-webpack5': 'vue3', + 'web-components-vite': 'web-components', + 'web-components-webpack5': 'web-components', + // renderers + html: 'html', + preact: 'preact', + 'react-native': 'react-native', + react: 'react', + server: 'server', + svelte: 'svelte', + vue3: 'vue3', 'web-components': 'web-components', }; +export const frameworkToDefaultBuilder: Record = { + angular: CoreBuilder.Webpack5, + ember: CoreBuilder.Webpack5, + 'html-vite': CoreBuilder.Vite, + 'html-webpack5': CoreBuilder.Webpack5, + nextjs: CoreBuilder.Webpack5, + 'preact-vite': CoreBuilder.Vite, + 'preact-webpack5': CoreBuilder.Webpack5, + qwik: CoreBuilder.Vite, + 'react-vite': CoreBuilder.Vite, + 'react-webpack5': CoreBuilder.Webpack5, + 'server-webpack5': CoreBuilder.Webpack5, + solid: CoreBuilder.Vite, + 'svelte-vite': CoreBuilder.Vite, + 'svelte-webpack5': CoreBuilder.Webpack5, + sveltekit: CoreBuilder.Vite, + 'vue3-vite': CoreBuilder.Vite, + 'vue3-webpack5': CoreBuilder.Webpack5, + 'web-components-vite': CoreBuilder.Vite, + 'web-components-webpack5': CoreBuilder.Webpack5, +}; + export async function copyTemplateFiles({ packageManager, renderer, diff --git a/code/lib/cli/src/project_types.ts b/code/lib/cli/src/project_types.ts index 0a0073d84664..3a5cda3781ef 100644 --- a/code/lib/cli/src/project_types.ts +++ b/code/lib/cli/src/project_types.ts @@ -1,4 +1,5 @@ import { minVersion, validRange } from 'semver'; +import type { SupportedFrameworks } from '@storybook/types'; function eqMajor(versionRange: string, major: number) { // Uses validRange to avoid a throw from minVersion if an invalid range gets passed @@ -21,9 +22,6 @@ export const externalFrameworks: ExternalFramework[] = [ { name: 'solid', frameworks: ['storybook-solidjs-vite'], renderer: 'storybook-solidjs' }, ]; -// Should match @storybook/ -export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik' | 'solid' | 'ember'; - // Should match @storybook/ export type SupportedRenderers = | 'react' @@ -79,6 +77,21 @@ export enum CoreBuilder { Vite = 'vite', } +export enum CoreWebpackCompilers { + Babel = 'babel', + SWC = 'swc', +} + +export const compilerNameToCoreCompiler: Record = { + '@storybook/addon-webpack5-compiler-babel': CoreWebpackCompilers.Babel, + '@storybook/addon-webpack5-compiler-swc': CoreWebpackCompilers.SWC, +}; + +export const builderNameToCoreBuilder: Record = { + '@storybook/builder-webpack5': CoreBuilder.Webpack5, + '@storybook/builder-vite': CoreBuilder.Vite, +}; + // The `& {}` bit allows for auto-complete, see: https://github.com/microsoft/TypeScript/issues/29729 export type Builder = CoreBuilder | (string & {}); diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index f7736511b81d..2769b93ca65a 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -29,6 +29,7 @@ "./dist/transforms/add-component-parameters.js": "./dist/transforms/add-component-parameters.js", "./dist/transforms/csf-2-to-3.js": "./dist/transforms/csf-2-to-3.js", "./dist/transforms/csf-hoist-story-annotations.js": "./dist/transforms/csf-hoist-story-annotations.js", + "./dist/transforms/find-implicit-spies.js": "./dist/transforms/find-implicit-spies.js", "./dist/transforms/move-builtin-addons.js": "./dist/transforms/move-builtin-addons.js", "./dist/transforms/mdx-to-csf.js": "./dist/transforms/mdx-to-csf.js", "./dist/transforms/migrate-to-test-package.js": "./dist/transforms/migrate-to-test-package.js", @@ -93,6 +94,7 @@ "./src/transforms/add-component-parameters.js", "./src/transforms/csf-2-to-3.ts", "./src/transforms/csf-hoist-story-annotations.js", + "./src/transforms/find-implicit-spies.ts", "./src/transforms/mdx-to-csf.ts", "./src/transforms/migrate-to-test-package.ts", "./src/transforms/move-builtin-addons.js", diff --git a/code/lib/codemod/src/transforms/__tests__/find-implicit-spies.test.ts b/code/lib/codemod/src/transforms/__tests__/find-implicit-spies.test.ts new file mode 100644 index 000000000000..c3885605e8ed --- /dev/null +++ b/code/lib/codemod/src/transforms/__tests__/find-implicit-spies.test.ts @@ -0,0 +1,71 @@ +import { beforeEach, expect, test, vi } from 'vitest'; +import transform from '../find-implicit-spies'; +import dedent from 'ts-dedent'; +import ansiRegex from 'ansi-regex'; + +expect.addSnapshotSerializer({ + print: (val, print) => print((val as string).replace(ansiRegex(), '')), + test: (value) => typeof value === 'string' && ansiRegex().test(value), +}); + +const tsTransform = async (source: string) => transform({ source, path: 'Component.stories.tsx' }); + +const warn = vi.spyOn(console, 'warn'); + +beforeEach(() => { + warn.mockImplementation(() => {}); +}); + +test('Warn for possible implicit actions', async () => { + const input = dedent` + export default { title: 'foo/bar', args: {onClick: fn() }, argTypes: { onHover: {action: true} } }; + const Template = (args) => { }; + export const A = Template.bind({}); + A.args = { onBla: fn() }; + A.play = async ({ args }) => { + await userEvent.click(screen.getByRole("button")); + await expect(args.onImplicit).toHaveBeenCalled(); + await expect(args.onClick).toHaveBeenCalled(); + await expect(args.onHover).toHaveBeenCalled(); + await expect(args.onBla).toHaveBeenCalled(); + }; + + export const B = { + args: {onBla: fn() }, + play: async ({ args }) => { + await userEvent.click(screen.getByRole("button")); + await expect(args.onImplicit).toHaveBeenCalled(); + await expect(args.onClick).toHaveBeenCalled(); + await expect(args.onHover).toHaveBeenCalled(); + await expect(args.onBla).toHaveBeenCalled(); + } + }; + `; + + await tsTransform(input); + + expect(warn.mock.calls).toMatchInlineSnapshot(` + [ + [ + "Component.stories.tsx Possible implicit spy found + 5 | A.play = async ({ args }) => { + 6 | await userEvent.click(screen.getByRole("button")); + > 7 | await expect(args.onImplicit).toHaveBeenCalled(); + | ^^^^^^^^^^ + 8 | await expect(args.onClick).toHaveBeenCalled(); + 9 | await expect(args.onHover).toHaveBeenCalled(); + 10 | await expect(args.onBla).toHaveBeenCalled();", + ], + [ + "Component.stories.tsx Possible implicit spy found + 15 | play: async ({ args }) => { + 16 | await userEvent.click(screen.getByRole("button")); + > 17 | await expect(args.onImplicit).toHaveBeenCalled(); + | ^^^^^^^^^^ + 18 | await expect(args.onClick).toHaveBeenCalled(); + 19 | await expect(args.onHover).toHaveBeenCalled(); + 20 | await expect(args.onBla).toHaveBeenCalled();", + ], + ] + `); +}); diff --git a/code/lib/codemod/src/transforms/find-implicit-spies.ts b/code/lib/codemod/src/transforms/find-implicit-spies.ts new file mode 100644 index 000000000000..558cde383aa7 --- /dev/null +++ b/code/lib/codemod/src/transforms/find-implicit-spies.ts @@ -0,0 +1,144 @@ +/* eslint-disable no-underscore-dangle */ +import type { FileInfo } from 'jscodeshift'; +import { loadCsf } from '@storybook/csf-tools'; +import type { BabelFile } from '@babel/core'; +import * as babel from '@babel/core'; +import { isIdentifier, isObjectExpression, isObjectProperty } from '@babel/types'; + +function findImplicitSpies(path: babel.NodePath, file: string, keys: string[]) { + path.traverse({ + Identifier: (identifier) => { + if (!keys.includes(identifier.node.name) && /^on[A-Z].*/.test(identifier.node.name)) { + console.warn(identifier.buildCodeFrameError(`${file} Possible implicit spy found`).message); + } + }, + }); +} + +function getAnnotationKeys(file: BabelFile, storyName: string, annotationName: string) { + const argKeys: string[] = []; + + file.path.traverse({ + // CSF2 play function Story.args = + AssignmentExpression: (path) => { + const left = path.get('left'); + if (!left.isMemberExpression()) return; + const object = left.get('object'); + + if (!(object.isIdentifier() && object.node.name === storyName)) return; + + const property = left.get('property'); + const right = path.get('right'); + if ( + property.isIdentifier() && + property.node.name === annotationName && + right.isObjectExpression() + ) { + argKeys.push( + ...right.node.properties.flatMap((value) => + isObjectProperty(value) && isIdentifier(value.key) ? [value.key.name] : [] + ) + ); + } + }, + // CSF3 const Story = {args: () => {} }; + VariableDeclarator: (path) => { + const id = path.get('id'); + const init = path.get('init'); + if (!(id.isIdentifier() && id.node.name === storyName) || !init.isObjectExpression()) return; + + const args = init + .get('properties') + .flatMap((it) => (it.isObjectProperty() ? [it] : [])) + .find((it) => { + const argKey = it.get('key'); + return argKey.isIdentifier() && argKey.node.name === annotationName; + }); + + if (!args) return; + const argsValue = args.get('value'); + + if (!argsValue || !argsValue.isObjectExpression()) return; + argKeys.push( + ...argsValue.node.properties.flatMap((value) => + isObjectProperty(value) && isIdentifier(value.key) ? [value.key.name] : [] + ) + ); + }, + }); + + return argKeys; +} + +const getObjectExpressionKeys = (node: babel.Node | undefined) => { + return isObjectExpression(node) + ? node.properties.flatMap((value) => + isObjectProperty(value) && isIdentifier(value.key) ? [value.key.name] : [] + ) + : []; +}; + +export default async function transform(info: FileInfo) { + const csf = loadCsf(info.source, { makeTitle: (title) => title }); + const fileNode = csf._ast; + // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 + const file: BabelFile = new babel.File( + { filename: info.path }, + { code: info.source, ast: fileNode } + ); + + csf.parse(); + + const metaKeys = [ + ...getObjectExpressionKeys(csf._metaAnnotations.args), + ...getObjectExpressionKeys(csf._metaAnnotations.argTypes), + ]; + + Object.entries(csf.stories).forEach(([key, { name }]) => { + if (!name) return; + const allKeys = [ + ...metaKeys, + ...getAnnotationKeys(file, name, 'args'), + ...getAnnotationKeys(file, name, 'argTypes'), + ]; + + file.path.traverse({ + // CSF2 play function Story.play = + AssignmentExpression: (path) => { + const left = path.get('left'); + if (!left.isMemberExpression()) return; + const object = left.get('object'); + + if (!(object.isIdentifier() && object.node.name === name)) return; + + const property = left.get('property'); + if (property.isIdentifier() && property.node.name === 'play') { + findImplicitSpies(path, info.path, allKeys); + } + }, + + // CSF3 play function: const Story = {play: () => {} }; + VariableDeclarator: (path) => { + const id = path.get('id'); + const init = path.get('init'); + if (!(id.isIdentifier() && id.node.name === name) || !init.isObjectExpression()) return; + + const play = init + .get('properties') + .flatMap((it) => (it.isObjectProperty() ? [it] : [])) + .find((it) => { + const argKey = it.get('key'); + return argKey.isIdentifier() && argKey.node.name === 'play'; + }); + + if (play) { + findImplicitSpies(play, info.path, allKeys); + } + }, + }); + }); + + return; +} + +export const parser = 'tsx'; diff --git a/code/lib/core-common/src/utils/get-storybook-info.ts b/code/lib/core-common/src/utils/get-storybook-info.ts index acf5aae77b91..2c90d90fd674 100644 --- a/code/lib/core-common/src/utils/get-storybook-info.ts +++ b/code/lib/core-common/src/utils/get-storybook-info.ts @@ -1,6 +1,6 @@ import path from 'path'; import fse from 'fs-extra'; -import type { CoreCommon_StorybookInfo, PackageJson } from '@storybook/types'; +import type { CoreCommon_StorybookInfo, PackageJson, SupportedFrameworks } from '@storybook/types'; import { getStorybookConfiguration } from './get-storybook-configuration'; export const rendererPackages: Record = { @@ -25,7 +25,7 @@ export const rendererPackages: Record = { '@storybook/vue': 'vue', }; -export const frameworkPackages: Record = { +export const frameworkPackages: Record = { '@storybook/angular': 'angular', '@storybook/ember': 'ember', '@storybook/html-vite': 'html-vite', @@ -94,7 +94,7 @@ export const findConfigFile = (prefix: string, configDir: string) => { return extension ? `${filePrefix}.${extension}` : null; }; -const getConfigInfo = (packageJson: PackageJson, configDir?: string) => { +export const getConfigInfo = (packageJson: PackageJson, configDir?: string) => { let storybookConfigDir = configDir ?? '.storybook'; const storybookScript = packageJson.scripts?.['storybook']; if (storybookScript && !configDir) { diff --git a/code/lib/core-server/package.json b/code/lib/core-server/package.json index ac629c9e7099..dc024488a7f8 100644 --- a/code/lib/core-server/package.json +++ b/code/lib/core-server/package.json @@ -56,6 +56,7 @@ }, "dependencies": { "@aw-web-design/x-default-browser": "1.4.126", + "@babel/core": "^7.23.9", "@discoveryjs/json-ext": "^0.5.3", "@storybook/builder-manager": "workspace:*", "@storybook/channels": "workspace:*", @@ -83,7 +84,7 @@ "express": "^4.17.3", "fs-extra": "^11.1.0", "globby": "^11.0.2", - "ip": "^2.0.0", + "ip": "^2.0.1", "lodash": "^4.17.21", "open": "^8.4.0", "pretty-hrtime": "^1.0.3", diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index 67990ff2d430..cfab99ef9f2e 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -11,7 +11,7 @@ import { import prompts from 'prompts'; import invariant from 'tiny-invariant'; import { global } from '@storybook/global'; -import { telemetry, oneWayHash } from '@storybook/telemetry'; +import { oneWayHash, telemetry } from '@storybook/telemetry'; import { join, relative, resolve } from 'path'; import { deprecate } from '@storybook/node-logger'; @@ -22,9 +22,10 @@ import { storybookDevServer } from './dev-server'; import { outputStats } from './utils/output-stats'; import { outputStartupInformation } from './utils/output-startup-information'; import { updateCheck } from './utils/update-check'; -import { getServerPort, getServerChannelUrl } from './utils/server-address'; +import { getServerChannelUrl, getServerPort } from './utils/server-address'; import { getManagerBuilder, getPreviewBuilder } from './utils/get-builders'; import { warnOnIncompatibleAddons } from './utils/warnOnIncompatibleAddons'; +import { warnWhenUsingArgTypesRegex } from './utils/warnWhenUsingArgTypesRegex'; import { buildOrThrow } from './utils/build-or-throw'; export async function buildDevStandalone( @@ -93,6 +94,10 @@ export async function buildDevStandalone( console.warn('Storybook failed to check addon compatibility', e); } + try { + await warnWhenUsingArgTypesRegex(packageJson, configDir, config); + } catch (e) {} + // Load first pass: We need to determine the builder // We need to do this because builders might introduce 'overridePresets' which we need to take into account // We hope to remove this in SB8 diff --git a/code/lib/core-server/src/presets/common-preset.ts b/code/lib/core-server/src/presets/common-preset.ts index 4e0c183ea7c1..6dcd6366eff0 100644 --- a/code/lib/core-server/src/presets/common-preset.ts +++ b/code/lib/core-server/src/presets/common-preset.ts @@ -7,7 +7,7 @@ import { getPreviewBodyTemplate, getPreviewHeadTemplate, loadEnvs, - removeAddon, + removeAddon as removeAddonBase, } from '@storybook/core-common'; import type { CLIOptions, @@ -162,10 +162,16 @@ const optionalEnvToBoolean = (input: string | undefined): boolean | undefined => }; // eslint-disable-next-line @typescript-eslint/naming-convention -export const experimental_serverAPI = (extension: Record) => ({ - ...extension, - removeAddon, -}); +export const experimental_serverAPI = (extension: Record, options: Options) => { + let removeAddon = removeAddonBase; + if (!options.disableTelemetry) { + removeAddon = async (id: string, opts: any) => { + await telemetry('remove', { addon: id, source: 'api' }); + return removeAddonBase(id, opts); + }; + } + return { ...extension, removeAddon }; +}; /** * If for some reason this config is not applied, the reason is that diff --git a/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts b/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts new file mode 100644 index 000000000000..fa336373a8a4 --- /dev/null +++ b/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts @@ -0,0 +1,56 @@ +import type { PackageJson, StorybookConfig } from '@storybook/types'; +import { getConfigInfo } from '@storybook/core-common'; +import { readFile } from 'fs-extra'; +import * as babel from '@babel/core'; +import type { BabelFile } from '@babel/core'; +import { babelParse } from '@storybook/csf-tools'; +import dedent from 'ts-dedent'; +import chalk from 'chalk'; + +export async function warnWhenUsingArgTypesRegex( + packageJson: PackageJson, + configDir: string, + config: StorybookConfig +) { + const { previewConfig } = getConfigInfo(packageJson, configDir); + const previewContent = previewConfig ? await readFile(previewConfig, 'utf8') : ''; + + const hasVisualTestAddon = + config?.addons?.some((it) => + typeof it === 'string' + ? it === '@chromatic-com/storybook' + : it.name === '@chromatic-com/storybook' + ) ?? false; + + if (hasVisualTestAddon && previewConfig && previewContent.includes('argTypesRegex')) { + // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 + const file: BabelFile = new babel.File( + { filename: previewConfig }, + { code: previewContent, ast: babelParse(previewContent) } + ); + + file.path.traverse({ + Identifier: (path) => { + if (path.node.name === 'argTypesRegex') { + const message = dedent` + ${chalk.bold('Attention')}: We've detected that you're using ${chalk.cyan( + 'actions.argTypesRegex' + )} together with the visual test addon: + + ${path.buildCodeFrameError(previewConfig).message} + + We recommend removing the ${chalk.cyan( + 'argTypesRegex' + )} and assigning explicit action with the ${chalk.cyan( + 'fn' + )} function from ${chalk.cyan('@storybook/test')} instead: + https://storybook.js.org/docs/essentials/actions#via-storybooktest-fn-spy-function + + The build used by the addon for snapshot testing doesn't take the regex into account, which can cause hard to debug problems when a snapshot depends on the presence of action props. + `; + console.warn(message); + } + }, + }); + } +} diff --git a/code/lib/preview-api/README-client-api.md b/code/lib/preview-api/README-client-api.md deleted file mode 100644 index c459b4c8d425..000000000000 --- a/code/lib/preview-api/README-client-api.md +++ /dev/null @@ -1,16 +0,0 @@ -# `@storybook/client-api` -- Deprecated Story APIs (`storiesOf`) - -**NOTE** This API is deprecated, and the CSF format is preferred for all stories. - -## `storiesOf` API - -The `@storybook/client` API provides the [`storiesOf()` API](./docs/storiesOf.md), which is proxied through to the CSF API. - -### Internals - -In order to appear to the store like the CSF API, a call to `storiesOf().add()` does the following: - -- Tracks the story added in a synthetic `StoryIndex` data structure -- Constructs a `moduleExports` object that is equivalent to the exports from a CSF file that produced the same stories. - -In order to achieve the old `storySort` functionality, the client API also needs access to the project annotations. diff --git a/code/lib/preview-api/README.md b/code/lib/preview-api/README.md index 864bbbb11e7f..cb5788bbb0f4 100644 --- a/code/lib/preview-api/README.md +++ b/code/lib/preview-api/README.md @@ -7,7 +7,6 @@ TODO write proper documentation of this package This package used to be multiple packages (they have been combined into this one): - `@storybook/addons` [read (old) docs](./README-addons.md) -- `@storybook/client-api` [read (old) docs](./README-client-api.md) - `@storybook/core-client` [read (old) docs](./README-core-client.md) - `@storybook/preview-web` [read (old) docs](./README-preview-web.md) - `@storybook/store` [read (old) docs](./README-store.md) diff --git a/code/lib/preview-api/docs/storiesOf.md b/code/lib/preview-api/docs/storiesOf.md deleted file mode 100644 index 08e7009a9d0d..000000000000 --- a/code/lib/preview-api/docs/storiesOf.md +++ /dev/null @@ -1,97 +0,0 @@ -## storiesOf (Legacy) API - -`storiesOf` is Storybook's Legacy API for adding stories. Up until Storybook 5.2, it has been the primary way to create stories in Storybook. - -In Storybook 5.2 we introduced a simpler and more portable [Component Story Format](https://storybook.js.org/docs/react/api/csf), and all future tools and infrastructure will be oriented towards CSF. Therefore, we recommend migrating your stories out of `storiesOf` API, and even provide [automated tools to do this](#component-story-format-migration). - -That said, the `storiesOf` API is no longer actively maintained and has been removed as part of the Storybook 8 release. If you're working with a custom indexer or similar tooling that implements this API, we encourage using custom story indexers instead. Read our [Indexer API documentation](https://storybook.js.org/docs/api/main-config-indexers) for more information. - -## storiesOf API - -A Storybook is a collection of stories. Each story represents a single visual state of a component. - -Here's a basic story file in the `storiesOf` API: - -```js -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { action } from '@storybook/addon-actions'; -import Button from '../components/Button'; - -storiesOf('Button', module) - .add('with text', () => ) - .add('with some emoji', () => ( - - )); -``` - -The string argument to `storiesOf` is the component title. If you pass a string like `'Widgets|Button/Button'` it can also be used to position your component's story within Storybook's story hierarchy. - -The second argument of `storiesOf` is a webpack `module`, which is available on the global (per-file) scope. Storybook needs it to enable hot-module-replacement. If it's not included you'll need to refresh your browser with each change you make. - -Each `.add` call takes a story name, a story function that returns a renderable object (JSX in the case of React), and optionally some parameters, which are described below. - -## Decorators and parameters - -[Decorators](https://storybook.js.org/docs/react/writing-stories/decorators) and [parameters](https://storybook.js.org/docs/react/writing-stories/parameters) can be specified globally, at the component level, or locally at the story level. - -In the `storiesOf` API, story-level parameters are provided as a third argument to `.add`: - -```js -storiesOf('Button', module).add( - 'with text', - () => , - { notes: someNotes } -); -``` - -Story-level decorators are provided via parameters: - -```js -storiesOf('Button', module).add( - 'with text', - () => , - { decorators: [withKnobs] } -); -``` - -We can control how the component's stories will render with parameters and decorators. You can use as many `.addDecorators` as you need (but make sure you add them all before your first story), but you can only use one `.addParameters`, as you can see in the example below: - -```js -storiesOf('Button', module) - .addParameters({ backgrounds: { values: [{ name: 'red', value: '#f00' }] } }) - .addDecorator((Story) => ( -
- -
- )) - .addDecorator((Story) => ( -
- -
- )) - .add('with text', () => ) - .add('with some emoji', () => ( - - )); -``` - -Parameters and decorators can also be used globally, you can define them in your .storybook/preview.js. Take a look [here](https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters) to learn more about global parameters and [here](https://storybook.js.org/docs/react/writing-stories/decorators#global-decorators) for global decorators. - -## Component Story Format migration - -To make it easier to adopt the new [Component Story Format (CSF)](https://storybook.js.org/docs/react/api/csf), we've created an automatic migration tool to transform `storiesOf` API to Module format. - -```sh -sb migrate storiesof-to-csf --glob=src/**/*.stories.js -``` - -For more information, see the CLI's [Codemod README](https://github.com/storybookjs/storybook/tree/next/code/lib/codemod). diff --git a/code/lib/telemetry/src/types.ts b/code/lib/telemetry/src/types.ts index 8f091703bcae..846e7adb9556 100644 --- a/code/lib/telemetry/src/types.ts +++ b/code/lib/telemetry/src/types.ts @@ -15,7 +15,8 @@ export type EventType = | 'error' | 'error-metadata' | 'version-update' - | 'core-config'; + | 'core-config' + | 'remove'; export interface Dependency { version: string | undefined; diff --git a/code/lib/types/package.json b/code/lib/types/package.json index 8cf31032d038..0cc32a79a9b8 100644 --- a/code/lib/types/package.json +++ b/code/lib/types/package.json @@ -58,6 +58,7 @@ "access": "public" }, "bundler": { + "pre": "./scripts/generate-available-frameworks.js", "entries": [ "./src/index.ts" ] diff --git a/code/lib/types/scripts/generate-available-frameworks.js b/code/lib/types/scripts/generate-available-frameworks.js new file mode 100644 index 000000000000..dced66c06707 --- /dev/null +++ b/code/lib/types/scripts/generate-available-frameworks.js @@ -0,0 +1,35 @@ +// read ./code/frameworks subfolders and generate a list of available frameworks +// save this list into ./code/lib/cli/src/frameworks.ts and export it as a union type. The name of the type is `SupportedFrameworks`. Add additionally 'qwik' and `solid` to that list. + +import { readdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import prettier from 'prettier'; +import dedent from 'ts-dedent'; + +const thirdPartyFrameworks = ['qwik', 'solid']; + +const run = async () => { + const frameworks = await readdir(path.join(__dirname, '..', '..', '..', 'frameworks')); + const supportedFrameworks = frameworks.map((framework) => `'${framework}'`).join(' | '); + const fileContent = dedent` + // auto generated file, do not edit + // the file gets generated by the script ./code/lib/types/scripts/generate-available-frameworks.js + export type SupportedFrameworks = ${supportedFrameworks} | ${thirdPartyFrameworks + .map((framework) => `'${framework}'`) + .join(' | ')}; +`; + const frameworksFile = path.join(__dirname, '..', 'src', 'modules', 'frameworks.ts'); + const prettierConfig = await prettier.resolveConfig(frameworksFile); + + const formattedFileContent = await prettier.format(fileContent, { + ...prettierConfig, + parser: 'typescript', + }); + + await writeFile(frameworksFile, formattedFileContent); +}; + +run().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/code/lib/types/src/index.ts b/code/lib/types/src/index.ts index 756b3d2634cb..0eb7547ccb6b 100644 --- a/code/lib/types/src/index.ts +++ b/code/lib/types/src/index.ts @@ -10,3 +10,4 @@ export * from './modules/api-stories'; export * from './modules/indexer'; export * from './modules/composedStory'; export * from './modules/channelApi'; +export * from './modules/frameworks'; diff --git a/code/lib/types/src/modules/frameworks.ts b/code/lib/types/src/modules/frameworks.ts new file mode 100644 index 000000000000..c1ea25abe7b0 --- /dev/null +++ b/code/lib/types/src/modules/frameworks.ts @@ -0,0 +1,22 @@ +// auto generated file, do not edit +// the file gets generated by the script ./code/lib/types/scripts/generate-available-frameworks.js +export type SupportedFrameworks = + | 'angular' + | 'ember' + | 'html-vite' + | 'html-webpack5' + | 'nextjs' + | 'preact-vite' + | 'preact-webpack5' + | 'react-vite' + | 'react-webpack5' + | 'server-webpack5' + | 'svelte-vite' + | 'svelte-webpack5' + | 'sveltekit' + | 'vue3-vite' + | 'vue3-webpack5' + | 'web-components-vite' + | 'web-components-webpack5' + | 'qwik' + | 'solid'; diff --git a/code/ui/blocks/src/components/TableOfContents.tsx b/code/ui/blocks/src/components/TableOfContents.tsx index 479f589411e4..b3b2e7b1f4a3 100644 --- a/code/ui/blocks/src/components/TableOfContents.tsx +++ b/code/ui/blocks/src/components/TableOfContents.tsx @@ -142,14 +142,13 @@ export const TableOfContents = ({ tocSelector: '.toc-wrapper', contentSelector: contentsSelector ?? '.sbdocs-content', headingSelector: headingSelector ?? 'h3', - ignoreSelector: ignoreSelector ?? '.skip-toc', - headingsOffset: 40, - scrollSmoothOffset: -40, /** * Ignore headings that did not * come from the main markdown code. */ - // ignoreSelector: ':not(.sbdocs), .hide-from-toc', + ignoreSelector: ignoreSelector ?? '.docs-story *, .skip-toc', + headingsOffset: 40, + scrollSmoothOffset: -40, orderedList: false, /** * Prevent default linking behavior, diff --git a/code/vitest.workspace.ts b/code/vitest.workspace.ts index f09d1adbfd44..9adcc717f753 100644 --- a/code/vitest.workspace.ts +++ b/code/vitest.workspace.ts @@ -25,7 +25,7 @@ const threadCount = process.env.CI ? 8 : undefined; export const vitestCommonConfig = defineConfig({ test: { clearMocks: true, - setupFiles: [resolve('./vitest-setup.ts')], + setupFiles: [resolve(__dirname, './vitest-setup.ts')], globals: true, poolOptions: { threads: { diff --git a/code/yarn.lock b/code/yarn.lock index 2c786bd21e03..7eee2bbe5fe4 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -467,6 +467,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/core@npm:7.23.9" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.23.9" + "@babel/parser": "npm:^7.23.9" + "@babel/template": "npm:^7.23.9" + "@babel/traverse": "npm:^7.23.9" + "@babel/types": "npm:^7.23.9" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 03883300bf1252ab4c9ba5b52f161232dd52873dbe5cde9289bb2bb26e935c42682493acbac9194a59a3b6cbd17f4c4c84030db8d6d482588afe64531532ff9b + languageName: node + linkType: hard + "@babel/generator@npm:7.23.0": version: 7.23.0 resolution: "@babel/generator@npm:7.23.0" @@ -740,6 +763,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/helpers@npm:7.23.9" + dependencies: + "@babel/template": "npm:^7.23.9" + "@babel/traverse": "npm:^7.23.9" + "@babel/types": "npm:^7.23.9" + checksum: f69fd0aca96a6fb8bd6dd044cd8a5c0f1851072d4ce23355345b9493c4032e76d1217f86b70df795e127553cf7f3fcd1587ede9d1b03b95e8b62681ca2165b87 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.23.4": version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" @@ -760,6 +794,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/parser@npm:7.23.9" + bin: + parser: ./bin/babel-parser.js + checksum: 7df97386431366d4810538db4b9ec538f4377096f720c0591c7587a16f6810e62747e9fbbfa1ff99257fd4330035e4fb1b5b77c7bd3b97ce0d2e3780a6618975 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15, @babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" @@ -2220,6 +2263,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/template@npm:7.23.9" + dependencies: + "@babel/code-frame": "npm:^7.23.5" + "@babel/parser": "npm:^7.23.9" + "@babel/types": "npm:^7.23.9" + checksum: 0e8b60119433787742bc08ae762bbd8d6755611c4cabbcb7627b292ec901a55af65d93d1c88572326069efb64136ef151ec91ffb74b2df7689bbab237030833a + languageName: node + linkType: hard + "@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.7, @babel/traverse@npm:^7.4.5": version: 7.23.7 resolution: "@babel/traverse@npm:7.23.7" @@ -2238,6 +2292,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/traverse@npm:7.23.9" + dependencies: + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/parser": "npm:^7.23.9" + "@babel/types": "npm:^7.23.9" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: d1615d1d02f04d47111a7ea4446a1a6275668ca39082f31d51f08380de9502e19862be434eaa34b022ce9a17dbb8f9e2b73a746c654d9575f3a680a7ffdf5630 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": version: 7.23.6 resolution: "@babel/types@npm:7.23.6" @@ -2249,6 +2321,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/types@npm:7.23.9" + dependencies: + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: edc7bb180ce7e4d2aea10c6972fb10474341ac39ba8fdc4a27ffb328368dfdfbf40fca18e441bbe7c483774500d5c05e222cec276c242e952853dcaf4eb884f7 + languageName: node + linkType: hard + "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" @@ -5354,6 +5437,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/cli@workspace:lib/cli" dependencies: + "@babel/core": "npm:^7.23.0" "@babel/types": "npm:^7.23.0" "@ndelangen/get-tarball": "npm:^3.0.7" "@storybook/codemod": "workspace:*" @@ -5538,6 +5622,7 @@ __metadata: resolution: "@storybook/core-server@workspace:lib/core-server" dependencies: "@aw-web-design/x-default-browser": "npm:1.4.126" + "@babel/core": "npm:^7.23.9" "@discoveryjs/json-ext": "npm:^0.5.3" "@storybook/addon-docs": "workspace:*" "@storybook/builder-manager": "workspace:*" @@ -5571,7 +5656,7 @@ __metadata: express: "npm:^4.17.3" fs-extra: "npm:^11.1.0" globby: "npm:^11.0.2" - ip: "npm:^2.0.0" + ip: "npm:^2.0.1" lodash: "npm:^4.17.21" node-fetch: "npm:^3.3.1" open: "npm:^8.4.0" @@ -17277,6 +17362,13 @@ __metadata: languageName: node linkType: hard +"ip@npm:^2.0.1": + version: 2.0.1 + resolution: "ip@npm:2.0.1" + checksum: cab8eb3e88d0abe23e4724829621ec4c4c5cb41a7f936a2e626c947128c1be16ed543448d42af7cca95379f9892bfcacc1ccd8d09bc7e8bea0e86d492ce33616 + languageName: node + linkType: hard + "ipaddr.js@npm:1.9.1": version: 1.9.1 resolution: "ipaddr.js@npm:1.9.1" diff --git a/docs/api/main-config-indexers.md b/docs/api/main-config-indexers.md index 256dd9b2c990..79e7fa2f2651 100644 --- a/docs/api/main-config-indexers.md +++ b/docs/api/main-config-indexers.md @@ -351,9 +351,7 @@ function JsonStoriesPlugin(): PluginOption { Generating stories with an alternative API -You can use a custom indexer and builder plugin to create your own API for defining stories, such as imperatively defining stories similar to the legacy [`storiesOf`](https://github.com/storybookjs/storybook/blob/main/code/lib/preview-api/docs/storiesOf.md) format. - -The [dynamic stories proof of concept](https://stackblitz.com/edit/github-h2rgfk?file=README.md) is an elaborate, functional example of doing just that. It contains everything needed to support such a feature, including the indexer, a Vite plugin and a Webpack loader. +You can use a custom indexer and builder plugin to create your API to define stories extending the CSF format. To learn more, see the following [proof of concept](https://stackblitz.com/edit/github-h2rgfk?file=README.md) to set up a custom indexer to generate stories dynamically. It contains everything needed to support such a feature, including the indexer, a Vite plugin, and a Webpack loader. diff --git a/docs/configure/frameworks-feature-support.md b/docs/configure/frameworks-feature-support.md index 7ae41614e248..79013ad8fc4b 100644 --- a/docs/configure/frameworks-feature-support.md +++ b/docs/configure/frameworks-feature-support.md @@ -110,8 +110,8 @@ Community frameworks have fewer contributors which means they may not be as up t To align the Storybook ecosystem with the current state of frontend development, the following features and addons are now deprecated, no longer maintained, and will be removed in future versions of Storybook -| Feature | Status | -| -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Knobs](https://github.com/storybookjs/addon-knobs) | The Knobs addon was officially deprecated with the release of Storybook 6.3 and is no longer actively maintained. We recommend using the [controls](../essentials/controls.md) instead. | -| [Storyshots](../writing-tests/snapshot-testing.md) | The Storyshots addon was officially deprecated with the release of Storybook 7.6, is no longer actively maintained and was removed in Storybook 8. See the [migration guide](../writing-tests/storyshots-migration-guide.md) for the available alternatives. | -| [`StoriesOf`](https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/docs/storiesOf.md) | The `storiesOf` API was officially removed with the release of Storybook 8 and is no longer maintained. We recommend using the [CSF API](../api/csf.md) instead for writing stories.
See the [migration guide](../migration-guide.md#storiesof-to-csf) for more information. | +| Feature | Status | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Knobs](https://github.com/storybookjs/addon-knobs) | The Knobs addon was officially deprecated with the release of Storybook 6.3 and is no longer actively maintained. We recommend using the [controls](../essentials/controls.md) instead. | +| [Storyshots](../writing-tests/snapshot-testing.md) | The Storyshots addon was officially deprecated with the release of Storybook 7.6, is no longer actively maintained and was removed in Storybook 8. See the [migration guide](../writing-tests/storyshots-migration-guide.md) for the available alternatives. | +| StoriesOf | The `storiesOf` API was officially removed with the release of Storybook 8 and is no longer maintained. We recommend using the [CSF API](../api/csf.md) instead for writing stories.
See the [migration guide](../migration-guide.md#storiesof-to-csf) for more information. | diff --git a/docs/faq.md b/docs/faq.md index 6e6ce176787a..1cceba208102 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -230,112 +230,110 @@ With the release of version 6.0, we updated our documentation as well. That does We're only covering versions 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo. -| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | -| ---------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| N/A | Why Storybook | [See current documentation](./why-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Get started | Install | [See current documentation](./get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | -| | What's a story | [See current documentation](./get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | -| | Browse Stories | [See current documentation](./get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | -| | Setup | [See current documentation](./get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | -| Write stories | Introduction | [See current documentation](./writing-stories/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Parameters | [See current documentation](./writing-stories/parameters.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters) | Non existing feature or undocumented | -| | Decorators | [See current documentation](./writing-stories/decorators.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) | -| | Naming components and hierarchy | [See current documentation](./writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Build pages and screens | [See current documentation](./writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Stories for multiple components | [See current documentation](./writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Write docs | Autodocs | [See current documentation](./writing-docs/autodocs.md) | See versioned addon documentation | Non existing feature or undocumented | -| | MDX | [See current documentation](./writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | -| | Doc Blocks | [See current documentation](./writing-docs/doc-blocks.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Preview and build docs | [See current documentation](./writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Testing | Visual tests | [See current documentation](./writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | -| | Accessibility tests | [See current documentation](./writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Interaction tests | [See current documentation](./writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | -| | Snapshot tests | [See current documentation](./writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | -| | Import stories in tests/Unit tests | [See current documentation](./writing-tests/stories-in-unit-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | -| | Import stories in tests/End-to-end testing | [See current documentation](./writing-tests/stories-in-end-to-end-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | -| Sharing | Publish Storybook | [See current documentation](./sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | -| | Embed | [See current documentation](./sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Composition | [See current documentation](./sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Package Composition | [See current documentation](./sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Essential addons | Controls | [See current documentation](./essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | -| | Actions | [See current documentation](./essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | -| | Viewport | [See current documentation](./essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | -| | Backgrounds | [See current documentation](./essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | -| | Toolbars and globals | [See current documentation](./essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | -| Configure | Overview | [See current documentation](./configure/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Integration/Frameworks | [See current documentation](./configure/frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Integration/Framework support for frameworks | [See current documentation](./configure/frameworks-feature-support.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Integration/Compilers | [See current documentation](./configure/compilers.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | -| | Integration/Typescript | [See current documentation](./configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | -| | Integration/Styling and CSS | [See current documentation](./configure/styling-and-css.md) | See versioned documentation | See versioned documentation | -| | Integration/Images and assets | [See current documentation](./configure/images-and-assets.md) | See versioned documentation | See versioned documentation | -| | Story rendering | [See current documentation](./configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | -| | Story Layout | [See current documentation](./configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | User Interface/Features and behavior | [See current documentation](./configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | User Interface/Theming | [See current documentation](./configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | -| | User Interface/Sidebar & URLS | [See current documentation](./configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | Environment variables | [See current documentation](./configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | -| Builders | Introduction | [See current documentation](./builders/index.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Vite | [See current documentation](./builders/vite.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Webpack | [See current documentation](./builders/webpack.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md) | -| | Builder API | [See current documentation](./builders/builder-api.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Addons | Introduction | [See current documentation](./addons/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Install addons | [See current documentation](./addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/) | -| | Writing Addons | [See current documentation](./addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Writing Presets | [See current documentation](./addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | -| | Addons Knowledge Base | [See current documentation](./addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Types of addons | [See current documentation](./addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Addons API | [See current documentation](./addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | -| API | @storybook/blocks/ArgTypes | [See current documentation](./api/doc-block-argtypes.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Canvas | [See current documentation](./api/doc-block-canvas.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/ColorPalette | [See current documentation](./api/doc-block-colorpalette.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Controls | [See current documentation](./api/doc-block-controls.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Description | [See current documentation](./api/doc-description.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/IconGallery | [See current documentation](./api/doc-block-icongallery.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Markdown | [See current documentation](./api/doc-block-markdown.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Meta | [See current documentation](./api/doc-block-meta.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Primary | [See current documentation](./api/doc-block-primary.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Source | [See current documentation](./api/doc-block-source.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Stories | [See current documentation](./api/doc-block-stories.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Story | [See current documentation](./api/doc-block-story.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Subtitle | [See current documentation](./api/doc-block-subtitle.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Title | [See current documentation](./api/doc-block-title.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Typeset | [See current documentation](./api/doc-block-typeset.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/Unstyled | [See current documentation](./api/doc-block-unstyled.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | @storybook/blocks/useOf | [See current documentation](./api/doc-block-useof.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Stories/Component Story Format | [See current documentation](./api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | -| | Stories/StoriesOF format (see note below) | [See current documentation](https://github.com/storybookjs/storybook/blob/main/code/lib/preview-api/docs/storiesOf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/storiesof-api) | Non existing feature or undocumented | -| | ArgTypes | [See current documentation](./api/arg-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/Overview | [See current documentation](./api/main-config.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/framework | [See current documentation](./api/main-config-framework.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/stories | [See current documentation](./api/main-config-stories.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/addons | [See current documentation](./api/main-config-addons.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/babel | [See current documentation](./api/main-config-babel.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/babelDefault | [See current documentation](./api/main-config-babel-default.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/build | [See current documentation](./api/main-config-build.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/core | [See current documentation](./api/main-config-core.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/docs | [See current documentation](./api/main-config-docs.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/env | [See current documentation](./api/main-config-env.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/features | [See current documentation](./api/main-config-features.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/indexers | [See current documentation](./api/main-config-indexers.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/logLevel | [See current documentation](./api/main-config-log-level.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/managerHead | [See current documentation](./api/main-config-manager-head.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/previewAnnotations | [See current documentation](./api/main-config-preview-annotations.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/previewBody | [See current documentation](./api/main-config-preview-body.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/previewHead | [See current documentation](./api/main-config-preview-head.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/refs | [See current documentation](./api/main-config-refs.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/staticDirs | [See current documentation](./api/main-config-static-dirs.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/swc | [See current documentation](./api/main-config-swc.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/typescript | [See current documentation](./api/main-config-typescript.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/viteFinal | [See current documentation](./api/main-config-vite-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/webpackFinal | [See current documentation](./api/main-config-webpack-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Frameworks | [See current documentation](./api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | CLI options | [See current documentation](./api/cli-options.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options) | - - +| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | +| ---------------- | ----------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| N/A | Why Storybook | [See current documentation](./why-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Get started | Install | [See current documentation](./get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | +| | What's a story | [See current documentation](./get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| | Browse Stories | [See current documentation](./get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | +| | Setup | [See current documentation](./get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| Write stories | Introduction | [See current documentation](./writing-stories/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Parameters | [See current documentation](./writing-stories/parameters.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters) | Non existing feature or undocumented | +| | Decorators | [See current documentation](./writing-stories/decorators.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) | +| | Naming components and hierarchy | [See current documentation](./writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Build pages and screens | [See current documentation](./writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Stories for multiple components | [See current documentation](./writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Write docs | Autodocs | [See current documentation](./writing-docs/autodocs.md) | See versioned addon documentation | Non existing feature or undocumented | +| | MDX | [See current documentation](./writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | +| | Doc Blocks | [See current documentation](./writing-docs/doc-blocks.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Preview and build docs | [See current documentation](./writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Testing | Visual tests | [See current documentation](./writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | +| | Accessibility tests | [See current documentation](./writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Interaction tests | [See current documentation](./writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | +| | Snapshot tests | [See current documentation](./writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | +| | Import stories in tests/Unit tests | [See current documentation](./writing-tests/stories-in-unit-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | +| | Import stories in tests/End-to-end testing | [See current documentation](./writing-tests/stories-in-end-to-end-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | +| Sharing | Publish Storybook | [See current documentation](./sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | +| | Embed | [See current documentation](./sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Composition | [See current documentation](./sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Package Composition | [See current documentation](./sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Essential addons | Controls | [See current documentation](./essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | +| | Actions | [See current documentation](./essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | +| | Viewport | [See current documentation](./essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | +| | Backgrounds | [See current documentation](./essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | +| | Toolbars and globals | [See current documentation](./essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | +| Configure | Overview | [See current documentation](./configure/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Integration/Frameworks | [See current documentation](./configure/frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Integration/Framework support for frameworks | [See current documentation](./configure/frameworks-feature-support.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Integration/Compilers | [See current documentation](./configure/compilers.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | +| | Integration/Typescript | [See current documentation](./configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | +| | Integration/Styling and CSS | [See current documentation](./configure/styling-and-css.md) | See versioned documentation | See versioned documentation | +| | Integration/Images and assets | [See current documentation](./configure/images-and-assets.md) | See versioned documentation | See versioned documentation | +| | Story rendering | [See current documentation](./configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | +| | Story Layout | [See current documentation](./configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | User Interface/Features and behavior | [See current documentation](./configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | User Interface/Theming | [See current documentation](./configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | +| | User Interface/Sidebar & URLS | [See current documentation](./configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | Environment variables | [See current documentation](./configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | +| Builders | Introduction | [See current documentation](./builders/index.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Vite | [See current documentation](./builders/vite.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Webpack | [See current documentation](./builders/webpack.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md) | +| | Builder API | [See current documentation](./builders/builder-api.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Addons | Introduction | [See current documentation](./addons/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Install addons | [See current documentation](./addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/) | +| | Writing Addons | [See current documentation](./addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Writing Presets | [See current documentation](./addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | +| | Addons Knowledge Base | [See current documentation](./addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Types of addons | [See current documentation](./addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Addons API | [See current documentation](./addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | +| API | @storybook/blocks/ArgTypes | [See current documentation](./api/doc-block-argtypes.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Canvas | [See current documentation](./api/doc-block-canvas.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/ColorPalette | [See current documentation](./api/doc-block-colorpalette.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Controls | [See current documentation](./api/doc-block-controls.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Description | [See current documentation](./api/doc-description.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/IconGallery | [See current documentation](./api/doc-block-icongallery.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Markdown | [See current documentation](./api/doc-block-markdown.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Meta | [See current documentation](./api/doc-block-meta.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Primary | [See current documentation](./api/doc-block-primary.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Source | [See current documentation](./api/doc-block-source.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Stories | [See current documentation](./api/doc-block-stories.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Story | [See current documentation](./api/doc-block-story.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Subtitle | [See current documentation](./api/doc-block-subtitle.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Title | [See current documentation](./api/doc-block-title.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Typeset | [See current documentation](./api/doc-block-typeset.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/Unstyled | [See current documentation](./api/doc-block-unstyled.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | @storybook/blocks/useOf | [See current documentation](./api/doc-block-useof.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Stories/Component Story Format (see note below) | [See current documentation](./api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | +| | ArgTypes | [See current documentation](./api/arg-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/Overview | [See current documentation](./api/main-config.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/framework | [See current documentation](./api/main-config-framework.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/stories | [See current documentation](./api/main-config-stories.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/addons | [See current documentation](./api/main-config-addons.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/babel | [See current documentation](./api/main-config-babel.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/babelDefault | [See current documentation](./api/main-config-babel-default.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/build | [See current documentation](./api/main-config-build.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/core | [See current documentation](./api/main-config-core.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/docs | [See current documentation](./api/main-config-docs.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/env | [See current documentation](./api/main-config-env.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/features | [See current documentation](./api/main-config-features.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/indexers | [See current documentation](./api/main-config-indexers.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/logLevel | [See current documentation](./api/main-config-log-level.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/managerHead | [See current documentation](./api/main-config-manager-head.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/previewAnnotations | [See current documentation](./api/main-config-preview-annotations.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/previewBody | [See current documentation](./api/main-config-preview-body.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/previewHead | [See current documentation](./api/main-config-preview-head.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/refs | [See current documentation](./api/main-config-refs.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/staticDirs | [See current documentation](./api/main-config-static-dirs.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/swc | [See current documentation](./api/main-config-swc.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/typescript | [See current documentation](./api/main-config-typescript.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/viteFinal | [See current documentation](./api/main-config-vite-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | `main.js` configuration/webpackFinal | [See current documentation](./api/main-config-webpack-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Frameworks | [See current documentation](./api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | CLI options | [See current documentation](./api/cli-options.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options) | + -With the release of version 5.3, we've updated how you can write your stories more compactly and easily. It doesn't mean that the `storiesOf` format has been removed. For the time being, we're still supporting it, and we have documentation for it. But be advised that this is bound to change in the future. +If you have stories written with the older `storiesOf` format, it was removed in Storybook 8.0 and is no longer maintained. We recommend that you migrate your stories to CSF. See the [migration guide](./migration-guide.md#storiesof-to-csf) for more information. However, if you need, you can still access the old `storiesOf` [documentation](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/formats/storiesof-api/index.md) for reference. diff --git a/docs/writing-docs/autodocs.md b/docs/writing-docs/autodocs.md index a89dd0a51d2f..cad2b6e901d4 100644 --- a/docs/writing-docs/autodocs.md +++ b/docs/writing-docs/autodocs.md @@ -133,14 +133,14 @@ Storybook's auto-generated documentation pages can be quite long and difficult t By default, the table of contents on the documentation page will only show the `h3` headings that are automatically generated. However, if you want to customize the table of contents, you can add more parameters to the `toc` property. The following options and examples of how to use them are available. -| Option | Description | -| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `contentsSelector` | Defines the container's CSS selector for search for the headings
`toc: { contentsSelector: '.sbdocs-content' }` | -| `disable` | Hides the table of contents for the documentation pages
`toc: { disable: true }` | -| `headingSelector` | Defines the list of headings to feature in the table of contents
`toc: { headingSelector: 'h1, h2, h3' }` | -| `ignoreSelector` | Configures the table of contents to ignore specific headings or stories
`toc: { ignoreSelector: 'h2' }` | -| `title` | Defines a title caption for the table of contents.
Accepts one of: `string`, `null`, React element
`toc: { title: 'Table of Contents' }` | -| `unsafeTocbotOptions` | Provides additional [`TocBot`](https://tscanlin.github.io/tocbot/) configuration options
`toc: { unsafeTocbotOptions: { orderedList: true } }` | +| Option | Description | +| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `contentsSelector` | Defines the container's CSS selector for search for the headings
`toc: { contentsSelector: '.sbdocs-content' }` | +| `disable` | Hides the table of contents for the documentation pages
`toc: { disable: true }` | +| `headingSelector` | Defines the list of headings to feature in the table of contents
`toc: { headingSelector: 'h1, h2, h3' }` | +| `ignoreSelector` | Configures the table of contents to ignore specific headings or stories. By default, the table of contents will ignore all content placed within Story blocks
`toc: { ignoreSelector: '.docs-story h2' }` | +| `title` | Defines a title caption for the table of contents.
Accepts one of: `string`, `null`, React element
`toc: { title: 'Table of Contents' }` | +| `unsafeTocbotOptions` | Provides additional [`TocBot`](https://tscanlin.github.io/tocbot/) configuration options
`toc: { unsafeTocbotOptions: { orderedList: true } }` |