From 50f84033e35f9c256101f31d0b4b5a066dea848f Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:17:13 +0100 Subject: [PATCH 001/213] feat: migrate from chalk to picocolors This migrates away from chalk to picocolors instead, primarily because the latter is _much_ lighter. Keep in mind, `node-logger` still uses chalk as we use `hex(code)` which doesn't have an alternative in picocolors. This means it will still be in the dependency tree for many packages (for now). This seems preferable over upgrading chalk since the latest version of chalk will still be heavier, and is ESM-only (not sure if we're able to adopt ESM only deps in SB yet). --- code/lib/cli/package.json | 2 +- .../autoblock/block-dependencies-versions.ts | 10 +- .../cli/src/autoblock/block-node-version.ts | 4 +- .../cli/src/autoblock/block-storystorev6.ts | 6 +- code/lib/cli/src/autoblock/index.ts | 6 +- .../src/automigrate/fixes/addon-postcss.ts | 8 +- .../cli/src/automigrate/fixes/addons-api.ts | 12 +-- .../fixes/angular-builders-multiproject.ts | 10 +- .../src/automigrate/fixes/angular-builders.ts | 4 +- .../src/automigrate/fixes/autodocs-tags.ts | 26 ++--- .../src/automigrate/fixes/autodocs-true.ts | 10 +- .../cli/src/automigrate/fixes/builder-vite.ts | 8 +- code/lib/cli/src/automigrate/fixes/cra5.ts | 8 +- .../src/automigrate/fixes/eslint-plugin.ts | 6 +- .../src/automigrate/fixes/initial-globals.ts | 12 ++- .../cli/src/automigrate/fixes/mdx-1-to-3.ts | 6 +- .../cli/src/automigrate/fixes/mdx-to-csf.ts | 14 +-- .../src/automigrate/fixes/new-frameworks.ts | 102 ++++++++++-------- .../cli/src/automigrate/fixes/react-docgen.ts | 16 +-- .../fixes/remove-argtypes-regex.ts | 8 +- .../fixes/remove-global-client-apis.ts | 14 +-- .../fixes/remove-jest-testing-library.ts | 8 +- .../cli/src/automigrate/fixes/sb-binary.ts | 8 +- .../cli/src/automigrate/fixes/sb-scripts.ts | 16 +-- .../automigrate/fixes/storyshots-migration.ts | 6 +- .../upgrade-storybook-related-dependencies.ts | 2 +- code/lib/cli/src/automigrate/fixes/vta.ts | 4 +- code/lib/cli/src/automigrate/fixes/vue3.ts | 10 +- .../fixes/webpack5-compiler-setup.test.ts | 4 +- .../fixes/webpack5-compiler-setup.ts | 20 ++-- .../lib/cli/src/automigrate/fixes/webpack5.ts | 8 +- .../cli/src/automigrate/fixes/wrap-require.ts | 4 +- .../helpers/checkWebpack5Builder.ts | 6 +- .../src/automigrate/helpers/eslintPlugin.ts | 4 +- .../helpers/getMigrationSummary.ts | 28 ++--- .../src/automigrate/helpers/mainConfigFile.ts | 8 +- code/lib/cli/src/automigrate/index.ts | 18 ++-- .../src/doctor/getDuplicatedDepsWarnings.ts | 14 +-- .../getIncompatibleStorybookPackages.test.ts | 2 +- .../getIncompatibleStorybookPackages.ts | 10 +- .../doctor/getMismatchingVersionsWarning.ts | 14 +-- code/lib/cli/src/doctor/index.ts | 8 +- code/lib/cli/src/generate.ts | 10 +- code/lib/cli/src/helpers.ts | 4 +- code/lib/cli/src/initiate.ts | 32 +++--- code/lib/cli/src/link.ts | 4 +- code/lib/cli/src/sandbox.ts | 36 +++---- code/lib/cli/src/scaffold-new-project.ts | 18 ++-- code/lib/cli/src/upgrade.ts | 20 ++-- code/lib/core-common/package.json | 2 +- .../js-package-manager/JsPackageManager.ts | 6 +- code/lib/core-common/src/utils/log-config.ts | 4 +- code/lib/core-common/src/utils/log.ts | 14 +-- .../core-common/src/utils/notify-telemetry.ts | 8 +- code/lib/core-events/package.json | 2 +- .../core-events/src/errors/server-errors.ts | 8 +- code/lib/core-server/package.json | 2 +- code/lib/core-server/src/build-static.ts | 6 +- .../src/utils/StoryIndexGenerator.ts | 6 +- .../src/utils/copy-all-static-files.ts | 12 ++- .../src/utils/output-startup-information.ts | 16 +-- .../lib/core-server/src/utils/output-stats.ts | 6 +- .../core-server/src/utils/server-statics.ts | 10 +- .../lib/core-server/src/utils/update-check.ts | 10 +- .../src/utils/warnWhenUsingArgTypesRegex.ts | 10 +- code/lib/telemetry/package.json | 2 +- code/lib/telemetry/src/notify.ts | 8 +- code/yarn.lock | 17 ++- 68 files changed, 408 insertions(+), 359 deletions(-) diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index d36b17a533e3..e5dd2d3eac8e 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -70,7 +70,6 @@ "@types/semver": "^7.3.4", "@yarnpkg/fslib": "2.10.3", "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", "commander": "^6.2.1", "cross-spawn": "^7.0.3", "detect-indent": "^6.1.0", @@ -84,6 +83,7 @@ "jscodeshift": "^0.15.1", "leven": "^3.1.0", "ora": "^5.4.1", + "picocolors": "^1.0.1", "prettier": "^3.1.1", "prompts": "^2.4.0", "read-pkg-up": "^7.0.1", diff --git a/code/lib/cli/src/autoblock/block-dependencies-versions.ts b/code/lib/cli/src/autoblock/block-dependencies-versions.ts index 45db54bac794..aef3a490f237 100644 --- a/code/lib/cli/src/autoblock/block-dependencies-versions.ts +++ b/code/lib/cli/src/autoblock/block-dependencies-versions.ts @@ -1,7 +1,7 @@ import { createBlocker } from './types'; import { dedent } from 'ts-dedent'; import { lt } from 'semver'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; const minimalVersionsMap = { '@angular/core': '15.0.0', @@ -51,7 +51,7 @@ export const blocker = createBlocker({ return dedent` Support for react-script < 5.0.0 has been removed. Please see the migration guide for more information: - ${chalk.yellow( + ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#create-react-app-dropped-cra4-support' )} @@ -61,7 +61,7 @@ export const blocker = createBlocker({ return dedent` Support for Vue 2 has been removed. Please see the migration guide for more information: - ${chalk.yellow('https://v3-migration.vuejs.org/')} + ${picocolors.yellow('https://v3-migration.vuejs.org/')} Please upgrade to the latest version of Vue. `; @@ -69,7 +69,7 @@ export const blocker = createBlocker({ return dedent` Support for Angular < 15 has been removed. Please see the migration guide for more information: - ${chalk.yellow('https://angular.io/guide/update-to-version-15')} + ${picocolors.yellow('https://angular.io/guide/update-to-version-15')} Please upgrade to the latest version of Angular. `; @@ -77,7 +77,7 @@ export const blocker = createBlocker({ return dedent` Support for Next.js < 13.5 has been removed. Please see the migration guide for more information: - ${chalk.yellow( + ${picocolors.yellow( 'https://nextjs.org/docs/pages/building-your-application/upgrading/version-13' )} diff --git a/code/lib/cli/src/autoblock/block-node-version.ts b/code/lib/cli/src/autoblock/block-node-version.ts index 49c9744b08f0..a54736db960c 100644 --- a/code/lib/cli/src/autoblock/block-node-version.ts +++ b/code/lib/cli/src/autoblock/block-node-version.ts @@ -1,7 +1,7 @@ import { createBlocker } from './types'; import { dedent } from 'ts-dedent'; import { lt } from 'semver'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; export const blocker = createBlocker({ id: 'minimumNode16', @@ -17,7 +17,7 @@ export const blocker = createBlocker({ We've detected you're using Node.js v${data.nodeVersion}. Storybook needs Node.js 18 or higher. - ${chalk.yellow('https://nodejs.org/en/download')} + ${picocolors.yellow('https://nodejs.org/en/download')} `; }, }); diff --git a/code/lib/cli/src/autoblock/block-storystorev6.ts b/code/lib/cli/src/autoblock/block-storystorev6.ts index d284584c9fbc..5041fbd56374 100644 --- a/code/lib/cli/src/autoblock/block-storystorev6.ts +++ b/code/lib/cli/src/autoblock/block-storystorev6.ts @@ -1,7 +1,7 @@ import { createBlocker } from './types'; import { dedent } from 'ts-dedent'; import type { StorybookConfigRaw } from '@storybook/types'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; export const blocker = createBlocker({ id: 'storyStoreV7removal', @@ -20,7 +20,7 @@ export const blocker = createBlocker({ StoryStoreV7 feature must be removed from your Storybook configuration. This feature was removed in Storybook 8.0.0. Please see the migration guide for more information: - ${chalk.yellow( + ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev6-and-storiesof-is-deprecated' )} @@ -28,7 +28,7 @@ export const blocker = createBlocker({ export default = { features: { - ${chalk.cyan(`storyStoreV7: false`)}, <--- ${chalk.bold('remove this line')} + ${picocolors.cyan(`storyStoreV7: false`)}, <--- ${picocolors.bold('remove this line')} }, }; diff --git a/code/lib/cli/src/autoblock/index.ts b/code/lib/cli/src/autoblock/index.ts index 6e71266926f6..82e7200f0d23 100644 --- a/code/lib/cli/src/autoblock/index.ts +++ b/code/lib/cli/src/autoblock/index.ts @@ -1,6 +1,6 @@ import type { AutoblockOptions, Blocker } from './types'; import { logger } from '@storybook/node-logger'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import boxen from 'boxen'; const excludesFalse = (x: T | false): x is T => x !== false; @@ -47,7 +47,9 @@ export const autoblock = async ( if (faults.length > 0) { const messages = { welcome: `Storybook has found potential blockers in your project that need to be resolved before upgrading:`, - reminder: chalk.yellow('Fix the above issues and try running the upgrade command again.'), + reminder: picocolors.yellow( + 'Fix the above issues and try running the upgrade command again.' + ), }; const borderColor = '#FC521F'; diff --git a/code/lib/cli/src/automigrate/fixes/addon-postcss.ts b/code/lib/cli/src/automigrate/fixes/addon-postcss.ts index f8d134183c0b..f3ba17f8cbf9 100644 --- a/code/lib/cli/src/automigrate/fixes/addon-postcss.ts +++ b/code/lib/cli/src/automigrate/fixes/addon-postcss.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; import { getAddonNames } from '../helpers/mainConfigFile'; @@ -27,13 +27,13 @@ export const addonPostCSS: Fix = { prompt() { return dedent` - ${chalk.bold( + ${picocolors.bold( 'Attention' )}: We've detected that you're using the following package which is incompatible with Storybook 8 and beyond: - - ${chalk.cyan(`@storybook/addon-postcss`)} + - ${picocolors.cyan(`@storybook/addon-postcss`)} - Please migrate to ${chalk.cyan( + Please migrate to ${picocolors.cyan( `@storybook/addon-styling-webpack` )} once you're done upgrading. `; diff --git a/code/lib/cli/src/automigrate/fixes/addons-api.ts b/code/lib/cli/src/automigrate/fixes/addons-api.ts index f193898aa82f..910f2d90c1de 100644 --- a/code/lib/cli/src/automigrate/fixes/addons-api.ts +++ b/code/lib/cli/src/automigrate/fixes/addons-api.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; @@ -26,18 +26,18 @@ export const addonsAPI: Fix = { prompt() { return dedent` - ${chalk.bold( + ${picocolors.bold( 'Attention' )}: We've detected that you're using the following package which is removed in Storybook 8 and beyond: - - ${chalk.cyan(`@storybook/addons`)} + - ${picocolors.cyan(`@storybook/addons`)} - This package has been deprecated and replaced with ${chalk.cyan( + This package has been deprecated and replaced with ${picocolors.cyan( `@storybook/preview-api` - )} and ${chalk.cyan(`@storybook/manager-api`)}. + )} and ${picocolors.cyan(`@storybook/manager-api`)}. You can find more information about the new addons API in the migration guide: - ${chalk.yellow( + ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-addons-api' )} `; 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 3f72411be011..539800e12406 100644 --- a/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts +++ b/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts @@ -1,6 +1,6 @@ import { dedent } from 'ts-dedent'; import semver from 'semver'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import type { Fix } from '../types'; import { isNxProject } from '../../helpers'; import { AngularJSON } from '../../generators/ANGULAR/helpers'; @@ -46,13 +46,13 @@ export const angularBuildersMultiproject: Fix:storybook')} to start Storybook. + )} and execute ${picocolors.yellow('ng run :storybook')} to start Storybook. - ❌ Your Angular workspace uses multiple projects defined in the ${chalk.yellow( + ❌ Your Angular workspace uses multiple projects defined in the ${picocolors.yellow( 'angular.json' - )} file and we were not able to detect a root project. Therefore we are not able to automigrate to use Angular Storybook builder. Instead, please visit ${chalk.yellow( + )} file and we were not able to detect a root project. Therefore we are not able to automigrate to use Angular Storybook builder. Instead, please visit ${picocolors.yellow( 'https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular' )} to do the migration manually. `; diff --git a/code/lib/cli/src/automigrate/fixes/angular-builders.ts b/code/lib/cli/src/automigrate/fixes/angular-builders.ts index ac2f2af99d2e..95a3298a81c8 100644 --- a/code/lib/cli/src/automigrate/fixes/angular-builders.ts +++ b/code/lib/cli/src/automigrate/fixes/angular-builders.ts @@ -1,6 +1,6 @@ import { dedent } from 'ts-dedent'; import type { StorybookConfig } from '@storybook/types'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import prompts from 'prompts'; import type { Fix } from '../types'; import { isNxProject } from '../../helpers'; @@ -59,7 +59,7 @@ export const angularBuilders: Fix = { Also feel free to remove the Compodoc script from your package.json file if you don't use it apart from Storybook anymore. Storybook uses Compodoc internally and you don't have to call in separately anymore. - Read more about the Angular builder here: ${chalk.yellow( + Read more about the Angular builder here: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular#how-do-i-migrate-to-an-angular-storybook-builder' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts b/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts index 531bcc0ec69d..3b2416af91fd 100644 --- a/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts +++ b/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts @@ -1,5 +1,5 @@ import { dedent } from 'ts-dedent'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import type { DocsOptions } from '@storybook/types'; import { readConfig, writeConfig } from '@storybook/csf-tools'; import { updateMainConfig } from '../helpers/mainConfigFile'; @@ -27,13 +27,13 @@ export const autodocsTags: Fix = { if (autodocs === true && !previewConfigPath) { throw Error(dedent` - ❌ Failed to remove the deprecated ${chalk.cyan('docs.autodocs')} setting from ${chalk.cyan( - mainConfigPath - )}. + ❌ Failed to remove the deprecated ${picocolors.cyan( + 'docs.autodocs' + )} setting from ${picocolors.cyan(mainConfigPath)}. - There is no preview config file in which to add the ${chalk.cyan('autodocs')} tag. + There is no preview config file in which to add the ${picocolors.cyan('autodocs')} tag. - Please perform the migration by hand: ${chalk.yellow(MIGRATION)} + Please perform the migration by hand: ${picocolors.yellow(MIGRATION)} `); return null; } @@ -49,21 +49,23 @@ export const autodocsTags: Fix = { falseMessage = dedent` - There is no ${chalk.cyan('docs.autodocs = false')} equivalent. - You'll need to check your stories to ensure none are tagged with ${chalk.cyan('autodocs')}. + There is no ${picocolors.cyan('docs.autodocs = false')} equivalent. + You'll need to check your stories to ensure none are tagged with ${picocolors.cyan( + 'autodocs' + )}. `; } else if (autodocs === true) { - trueMessage = ` and update ${chalk.cyan(previewConfigPath)}`; + trueMessage = ` and update ${picocolors.cyan(previewConfigPath)}`; } return dedent` - The ${chalk.cyan('docs.autodocs')} setting in ${chalk.cyan( + The ${picocolors.cyan('docs.autodocs')} setting in ${picocolors.cyan( mainConfigPath )} is deprecated.${falseMessage} - Learn more: ${chalk.yellow(MIGRATION)} + Learn more: ${picocolors.yellow(MIGRATION)} - Remove ${chalk.cyan('docs.autodocs')}${trueMessage}? + Remove ${picocolors.cyan('docs.autodocs')}${trueMessage}? `; }, diff --git a/code/lib/cli/src/automigrate/fixes/autodocs-true.ts b/code/lib/cli/src/automigrate/fixes/autodocs-true.ts index e5c2aceda7c2..d9cac1583b41 100644 --- a/code/lib/cli/src/automigrate/fixes/autodocs-true.ts +++ b/code/lib/cli/src/automigrate/fixes/autodocs-true.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; @@ -44,7 +44,9 @@ export const autodocsTrue: Fix = { }, prompt({ value }) { - const autodocsFormatted = chalk.cyan(`docs: { autodocs: ${JSON.stringify(value ?? true)} }`); + const autodocsFormatted = picocolors.cyan( + `docs: { autodocs: ${JSON.stringify(value ?? true)} }` + ); const tagWarning = dedent` NOTE: if you're upgrading from an older 7.0-beta using the 'docsPage' tag, please update your story files to use the 'autodocs' tag instead. @@ -61,7 +63,7 @@ export const autodocsTrue: Fix = { ${autodocsFormatted} ${value === 'tag' ? tagWarning : ''} - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#autodocs-changes' )} `; @@ -74,7 +76,7 @@ export const autodocsTrue: Fix = { ${autodocsFormatted} - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#autodocs-changes' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/builder-vite.ts b/code/lib/cli/src/automigrate/fixes/builder-vite.ts index b38cf9ccb677..66e573a0e75c 100644 --- a/code/lib/cli/src/automigrate/fixes/builder-vite.ts +++ b/code/lib/cli/src/automigrate/fixes/builder-vite.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import { writeConfig } from '@storybook/csf-tools'; @@ -42,18 +42,18 @@ export const builderVite: Fix = { }, prompt({ builder }) { - const builderFormatted = chalk.cyan(JSON.stringify(builder, null, 2)); + const builderFormatted = picocolors.cyan(JSON.stringify(builder, null, 2)); return dedent` We've detected you're using the community vite builder: ${builderFormatted} - 'storybook-builder-vite' is deprecated and now located at ${chalk.cyan( + 'storybook-builder-vite' is deprecated and now located at ${picocolors.cyan( '@storybook/builder-vite' )}. We can upgrade your project to use the new builder automatically. - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vite-builder-renamed' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/cra5.ts b/code/lib/cli/src/automigrate/fixes/cra5.ts index 468fbe90947b..ef831e2b1865 100644 --- a/code/lib/cli/src/automigrate/fixes/cra5.ts +++ b/code/lib/cli/src/automigrate/fixes/cra5.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import semver from 'semver'; import type { Fix } from '../types'; @@ -34,17 +34,17 @@ export const cra5: Fix = { }, prompt({ craVersion }) { - const craFormatted = chalk.cyan(`Create React App (CRA) ${craVersion}`); + const craFormatted = picocolors.cyan(`Create React App (CRA) ${craVersion}`); return dedent` We've detected you are running ${craFormatted} which is powered by webpack5. Your Storybook's main.js files specifies webpack4, which is incompatible. - In order to work with your version of CRA, we need to install Storybook's ${chalk.cyan( + In order to work with your version of CRA, we need to install Storybook's ${picocolors.cyan( '@storybook/builder-webpack5' )}. - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#cra5-upgrade' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts b/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts index de81e08008d8..b726818899bb 100644 --- a/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts +++ b/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import { @@ -57,7 +57,9 @@ export const eslintPlugin: Fix = { In order to have the best experience with Storybook and follow best practices, we advise you to install eslint-plugin-storybook. - More info: ${chalk.yellow('https://github.com/storybookjs/eslint-plugin-storybook#readme')} + More info: ${picocolors.yellow( + 'https://github.com/storybookjs/eslint-plugin-storybook#readme' + )} `; }, diff --git a/code/lib/cli/src/automigrate/fixes/initial-globals.ts b/code/lib/cli/src/automigrate/fixes/initial-globals.ts index c9fac6d4cdbf..fd13157ca5bc 100644 --- a/code/lib/cli/src/automigrate/fixes/initial-globals.ts +++ b/code/lib/cli/src/automigrate/fixes/initial-globals.ts @@ -1,5 +1,5 @@ import { dedent } from 'ts-dedent'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { readFile, writeFile } from 'fs-extra'; import type { Expression } from '@babel/types'; import type { ConfigFile } from '@storybook/csf-tools'; @@ -33,12 +33,14 @@ export const initialGlobals: Fix = { prompt({ previewConfigPath }) { return dedent` - The ${chalk.cyan('globals')} setting in ${chalk.cyan(previewConfigPath)} is deprecated - and has been renamed to ${chalk.cyan('initialGlobals')}. + The ${picocolors.cyan('globals')} setting in ${picocolors.cyan( + previewConfigPath + )} is deprecated + and has been renamed to ${picocolors.cyan('initialGlobals')}. - Learn more: ${chalk.yellow(MIGRATION)} + Learn more: ${picocolors.yellow(MIGRATION)} - Rename ${chalk.cyan('globals')} to ${chalk.cyan('initalGlobals')}? + Rename ${picocolors.cyan('globals')} to ${picocolors.cyan('initalGlobals')}? `; }, diff --git a/code/lib/cli/src/automigrate/fixes/mdx-1-to-3.ts b/code/lib/cli/src/automigrate/fixes/mdx-1-to-3.ts index 8b556033a6ac..b66b4cb8da4e 100644 --- a/code/lib/cli/src/automigrate/fixes/mdx-1-to-3.ts +++ b/code/lib/cli/src/automigrate/fixes/mdx-1-to-3.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import { basename } from 'path'; import fse from 'fs-extra'; @@ -56,7 +56,7 @@ export const mdx1to3: Fix = { prompt({ storiesMdxFiles }) { return dedent` - We've found ${chalk.yellow(storiesMdxFiles.length)} '.stories.mdx' files in your project. + We've found ${picocolors.yellow(storiesMdxFiles.length)} '.stories.mdx' files in your project. Storybook has upgraded to MDX3 (https://mdxjs.com/blog/v3/). MDX3 itself doesn't contain disruptive breaking changes, whereas the transition from MDX1 to MDX2 was a significant change. We can try to automatically upgrade your MDX files to MDX3 format using some common patterns. @@ -64,7 +64,7 @@ export const mdx1to3: Fix = { After this install completes, and before you start Storybook, we strongly recommend reading the MDX2 section of the 7.0 migration guide. It contains useful tools for detecting and fixing any remaining issues. - ${chalk.cyan('https://storybook.js.org/migration-guides/7.0')} + ${picocolors.cyan('https://storybook.js.org/migration-guides/7.0')} `; }, diff --git a/code/lib/cli/src/automigrate/fixes/mdx-to-csf.ts b/code/lib/cli/src/automigrate/fixes/mdx-to-csf.ts index 72dc4ddbde00..74793efdb0c1 100644 --- a/code/lib/cli/src/automigrate/fixes/mdx-to-csf.ts +++ b/code/lib/cli/src/automigrate/fixes/mdx-to-csf.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import type { StoriesEntry } from '@storybook/types'; import { updateMainConfig } from '../helpers/mainConfigFile'; @@ -40,9 +40,9 @@ export const mdxToCSF: Fix = { if (!existingStoriesEntries) { throw new Error(dedent` - ❌ Unable to determine Storybook stories globs in ${chalk.blue( + ❌ Unable to determine Storybook stories globs in ${picocolors.blue( mainConfig - )}, skipping ${chalk.cyan(this.id)} fix. + )}, skipping ${picocolors.cyan(this.id)} fix. In Storybook 7, we have deprecated defining stories in MDX files, and consequently have changed the suffix to simply .mdx. @@ -50,7 +50,7 @@ export const mdxToCSF: Fix = { We were unable to automatically migrate your 'stories' config to include any .mdx file instead of just .stories.mdx. We suggest you make this change manually. - To learn more about this change, see: ${chalk.yellow( + To learn more about this change, see: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mdx-docs-files' )} `); @@ -94,7 +94,7 @@ export const mdxToCSF: Fix = { .join('\n'); return dedent` We've detected your project has one or more globs in your 'stories' config that matches .stories.mdx files: - ${chalk.cyan(prettyExistingStoriesEntries)} + ${picocolors.cyan(prettyExistingStoriesEntries)} In Storybook 7, we have deprecated defining stories in MDX files, and consequently have changed the suffix to simply .mdx. Since Storybook 8, we have removed the support of story definition in MDX files entirely. Therefore '.stories.mdx' files aren't supported anymore. @@ -102,11 +102,11 @@ export const mdxToCSF: Fix = { We can automatically migrate your 'stories' config to include any .mdx file instead of just .stories.mdx. That would result in the following 'stories' config: - ${chalk.cyan(prettyNextStoriesEntries)} + ${picocolors.cyan(prettyNextStoriesEntries)} Additionally, we will run the 'mdx-to-csf' codemod for you, which tries to transform '*.stories.mdx' files to '*.stories.js' and '*.mdx' files. - To learn more about this change, see: ${chalk.yellow( + To learn more about this change, see: ${picocolors.yellow( 'https://storybook.js.org/docs/migration-guide#storiesmdx-to-mdxcsf' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts index 97ace48c8ee9..e18c5c137a4c 100644 --- a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts +++ b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import semver from 'semver'; import { frameworkPackages, rendererPackages } from '@storybook/core-common'; @@ -206,13 +206,13 @@ export const newFrameworks: Fix = { if (viteVersion && semver.lt(viteVersion, '3.0.0')) { throw new Error(dedent` - ❌ Your project should be upgraded to use the framework package ${chalk.bold( + ❌ Your project should be upgraded to use the framework package ${picocolors.bold( newFrameworkPackage - )}, but we detected that you are using Vite ${chalk.bold( + )}, but we detected that you are using Vite ${picocolors.bold( viteVersion - )}, which is unsupported since ${chalk.bold( + )}, which is unsupported since ${picocolors.bold( 'Storybook 7.0' - )}. Please upgrade Vite to ${chalk.bold('3.0.0 or higher')} and rerun this migration. + )}. Please upgrade Vite to ${picocolors.bold('3.0.0 or higher')} and rerun this migration. `); } @@ -258,41 +258,47 @@ export const newFrameworks: Fix = { if (dependenciesToRemove.length > 0) { migrationSteps += `- Remove the following dependencies: - ${dependenciesToRemove.map((dep) => `- * ${chalk.cyan(dep)}`).join('\n')}\n`; + ${dependenciesToRemove.map((dep) => `- * ${picocolors.cyan(dep)}`).join('\n')}\n`; } if (dependenciesToAdd.length > 0) { migrationSteps += `- Add the following dependencies: - ${dependenciesToAdd.map((dep) => `- * ${chalk.cyan(dep)}`).join('\n')}\n`; + ${dependenciesToAdd.map((dep) => `- * ${picocolors.cyan(dep)}`).join('\n')}\n`; } if (!hasFrameworkInMainConfig) { - migrationSteps += `- Update or specify the ${chalk.yellow('framework')} field in ${chalk.blue( - mainConfigPath - )} with the value of "${chalk.cyan(frameworkPackage)}".\n`; + migrationSteps += `- Update or specify the ${picocolors.yellow( + 'framework' + )} field in ${picocolors.blue(mainConfigPath)} with the value of "${picocolors.cyan( + frameworkPackage + )}".\n`; } if (Object.keys(rendererOptions).length > 0) { - migrationSteps += `- Move the ${chalk.yellow(`${renderer}Options`)} field in ${chalk.blue( - mainConfigPath - )} to ${chalk.yellow('framework.options')}, and remove that field entirely. - More info: ${chalk.yellow( + migrationSteps += `- Move the ${picocolors.yellow( + `${renderer}Options` + )} field in ${picocolors.blue(mainConfigPath)} to ${picocolors.yellow( + 'framework.options' + )}, and remove that field entirely. + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#frameworkoptions-renamed' )}\n`; } if (addonsToRemove.length > 0) { - migrationSteps += `- Remove the following addons from your ${chalk.blue( + migrationSteps += `- Remove the following addons from your ${picocolors.blue( mainConfigPath )}, as the new framework also supports features provided by them: - ${addonsToRemove.map((dep) => `- * ${chalk.cyan(dep)}`).join('\n')} + ${addonsToRemove.map((dep) => `- * ${picocolors.cyan(dep)}`).join('\n')} `; } if (Object.keys(addonOptions).length > 0) { - migrationSteps += `- Move the addon options "${chalk.yellow( + migrationSteps += `- Move the addon options "${picocolors.yellow( Object.keys(addonOptions).join(', ') - )}" in ${chalk.blue(mainConfigPath)} to the ${chalk.yellow('framework.options')} field.\n`; + )}" in ${picocolors.blue(mainConfigPath)} to the ${picocolors.yellow( + 'framework.options' + )} field.\n`; } if (builderConfig) { @@ -300,14 +306,16 @@ export const newFrameworks: Fix = { typeof builderConfig === 'object' && Object.keys(builderConfig.options || {}).length > 0 ) { - migrationSteps += `- Move the ${chalk.yellow('core.builder.options')} field in ${chalk.blue( - mainConfigPath - )} to ${chalk.yellow('framework.options.builder')}\n`; + migrationSteps += `- Move the ${picocolors.yellow( + 'core.builder.options' + )} field in ${picocolors.blue(mainConfigPath)} to ${picocolors.yellow( + 'framework.options.builder' + )}\n`; } - migrationSteps += `- Remove the ${chalk.yellow('core.builder')} field in ${chalk.blue( - mainConfigPath - )}.\n`; + migrationSteps += `- Remove the ${picocolors.yellow( + 'core.builder' + )} field in ${picocolors.blue(mainConfigPath)}.\n`; } if ( @@ -315,47 +323,49 @@ export const newFrameworks: Fix = { dependenciesToRemove.includes('@storybook/manager-webpack4') ) { disclaimer = dedent`\n\n - ${chalk.underline(chalk.bold(chalk.cyan('Webpack 4 users')))} + ${picocolors.underline(picocolors.bold(picocolors.cyan('Webpack 4 users')))} Unless you're using Storybook's Vite builder, this automigration will install a Webpack 5 based framework. Given you were using Storybook's Webpack 4 builder (default in 6.x, discontinued in 7.0), this could be a breaking change -- especially if your project has a custom webpack configuration. - To learn more about migrating from Webpack4, see: ${chalk.yellow( + To learn more about migrating from Webpack4, see: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack4-support-discontinued' )}`; } if (metaFramework === 'nextjs') { if (dependenciesToRemove.includes('storybook-addon-next-router')) { - migrationSteps += `- Migrate the usage of the ${chalk.cyan( + migrationSteps += `- Migrate the usage of the ${picocolors.cyan( 'storybook-addon-next-router' - )} addon to use the APIs from the ${chalk.magenta( + )} addon to use the APIs from the ${picocolors.magenta( '@storybook/nextjs' )} framework package instead. Follow the instructions below.`; } if (frameworkPackage === '@storybook/react-vite') { disclaimer = dedent`\n\n - ${chalk.bold('Important')}: We've detected you are using Storybook in a Next.js project. + ${picocolors.bold( + 'Important' + )}: We've detected you are using Storybook in a Next.js project. - This migration is set to update your project to use the ${chalk.magenta( + This migration is set to update your project to use the ${picocolors.magenta( '@storybook/react-vite' - )} framework, but Storybook provides a framework package specifically for Next.js projects: ${chalk.magenta( + )} framework, but Storybook provides a framework package specifically for Next.js projects: ${picocolors.magenta( '@storybook/nextjs' )}. This package provides a better, out of the box experience for Next.js users, however it is only compatible with the Webpack 5 builder, so we can't automigrate for you, as you are using the Vite builder. If you switch this project to use Webpack 5 and rerun this migration, we can update your project. - If you are interested in using this package, see: ${chalk.yellow( + If you are interested in using this package, see: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md' )} `; } else if (frameworkPackage === '@storybook/nextjs') { disclaimer = dedent`\n\n - The ${chalk.magenta( + The ${picocolors.magenta( '@storybook/nextjs' - )} package provides great user experience for Next.js users, and we highly recommend you to read more about it at ${chalk.yellow( + )} package provides great user experience for Next.js users, and we highly recommend you to read more about it at ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md' )} `; @@ -365,31 +375,33 @@ export const newFrameworks: Fix = { if (metaFramework === 'sveltekit') { if (frameworkPackage === '@storybook/svelte-webpack5') { disclaimer = dedent`\n\n - ${chalk.bold('Important')}: We've detected you are using Storybook in a SvelteKit project. + ${picocolors.bold( + 'Important' + )}: We've detected you are using Storybook in a SvelteKit project. - This migration is set to update your project to use the ${chalk.magenta( + This migration is set to update your project to use the ${picocolors.magenta( '@storybook/svelte-webpack5' - )} framework, but Storybook provides a framework package specifically for SvelteKit projects: ${chalk.magenta( + )} framework, but Storybook provides a framework package specifically for SvelteKit projects: ${picocolors.magenta( '@storybook/sveltekit' )}. This package provides a better experience for SvelteKit users, however it is only compatible with the Vite builder, so we can't automigrate for you, as you are using the Webpack builder. - If you are interested in using this package, see: ${chalk.yellow( + If you are interested in using this package, see: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/code/frameworks/sveltekit/README.md' )} `; } else { - migrationSteps += `- Remove the ${chalk.yellow( + migrationSteps += `- Remove the ${picocolors.yellow( `${renderer}Options` - )} field from ${chalk.blue(mainConfigPath)}. - More info: ${chalk.yellow( + )} field from ${picocolors.blue(mainConfigPath)}. + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vite-builder-uses-vite-config-automatically' )}\n`; disclaimer = dedent`\n\n - The ${chalk.magenta( + The ${picocolors.magenta( '@storybook/sveltekit' - )} package provides great user experience for SvelteKit users, and we highly recommend you to read more about it at ${chalk.yellow( + )} package provides great user experience for SvelteKit users, and we highly recommend you to read more about it at ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/code/frameworks/sveltekit/README.md' )} `; @@ -401,14 +413,14 @@ export const newFrameworks: Fix = { Storybook 7 introduced the concept of frameworks, which abstracts configuration for renderers (e.g. React, Vue), builders (e.g. Webpack, Vite) and defaults to make integrations easier. - Your project should be updated to use Storybook's framework: ${chalk.magenta( + Your project should be updated to use Storybook's framework: ${picocolors.magenta( frameworkPackage )}. We can attempt to do this for you automatically. Here are the steps this migration will do to migrate your project: ${migrationSteps} - To learn more about the new framework format, see: ${chalk.yellow( + To learn more about the new framework format, see: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-framework-api' )}${disclaimer} `; diff --git a/code/lib/cli/src/automigrate/fixes/react-docgen.ts b/code/lib/cli/src/automigrate/fixes/react-docgen.ts index 9359a96bacd9..ee883c512dda 100644 --- a/code/lib/cli/src/automigrate/fixes/react-docgen.ts +++ b/code/lib/cli/src/automigrate/fixes/react-docgen.ts @@ -1,7 +1,7 @@ import { dedent } from 'ts-dedent'; import { getRendererName, updateMainConfig } from '../helpers/mainConfigFile'; import type { Fix } from '../types'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; const logger = console; @@ -46,25 +46,25 @@ export const reactDocgen: Fix = { `; } else { return dedent` - Since Storybook 8.0, ${chalk.cyan( + Since Storybook 8.0, ${picocolors.cyan( 'react-docgen' - )} is now the default for generating component controls, replacing ${chalk.cyan( + )} is now the default for generating component controls, replacing ${picocolors.cyan( 'react-docgen-typescript' )}. This offers better performance and suits most cases. However, for complex TypeScript types or specific type features, the generated controls might not be as precise. For more on this change, check the migration guide: - ${chalk.yellow( + ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#react-docgen-component-analysis-by-default' )} For known "react-docgen" limitations, see: - ${chalk.yellow('https://github.com/storybookjs/storybook/issues/26606')} + ${picocolors.yellow('https://github.com/storybookjs/storybook/issues/26606')} - Press Y to revert to ${chalk.cyan('react-docgen-typescript')}, press N to use ${chalk.cyan( - 'react-docgen' - )} + Press Y to revert to ${picocolors.cyan( + 'react-docgen-typescript' + )}, press N to use ${picocolors.cyan('react-docgen')} `; } }, diff --git a/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts b/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts index 3220bbeeec9d..67b0ce73c5db 100644 --- a/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts +++ b/code/lib/cli/src/automigrate/fixes/remove-argtypes-regex.ts @@ -4,7 +4,7 @@ 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'; +import picocolors from 'picocolors'; export const removeArgtypesRegex: Fix<{ argTypesRegex: NodePath; previewConfigPath: string }> = { id: 'remove-argtypes-regex', @@ -35,7 +35,7 @@ export const removeArgtypesRegex: Fix<{ argTypesRegex: NodePath; previewConfigPa }, prompt({ argTypesRegex, previewConfigPath }) { return dedent` - ${chalk.bold('Attention')}: We've detected that you're using argTypesRegex: + ${picocolors.bold('Attention')}: We've detected that you're using argTypesRegex: ${argTypesRegex.buildCodeFrameError(`${previewConfigPath}`).message} @@ -48,12 +48,12 @@ export const removeArgtypesRegex: Fix<{ argTypesRegex: NodePath; previewConfigPa (fn) function to mock your component's methods instead. Use the following command to check for implied mocked actions in your play functions: - ${chalk.cyan( + ${picocolors.cyan( 'npx storybook migrate find-implicit-spies --glob="**/*.stories.@(js|jsx|ts|tsx)"' )} Then, refer to our docs to migrate your play functions to Storybook 8: - ${chalk.yellow( + ${picocolors.yellow( 'https://storybook.js.org/docs/8.0/essentials/actions#via-storybooktest-fn-spy-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 64de15f9a4b4..97327507af6a 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 @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import { readFile } from 'fs-extra'; import type { Fix } from '../types'; @@ -46,16 +46,18 @@ export const removedGlobalClientAPIs: Fix = { }, prompt({ usedAPIs, previewPath }) { return dedent` - ${chalk.bold( - chalk.red('Attention') + ${picocolors.bold( + picocolors.red('Attention') )}: We could not automatically make this change. You'll need to do it manually. - The following APIs (used in "${chalk.yellow(previewPath)}") have been removed from Storybook: + The following APIs (used in "${picocolors.yellow( + previewPath + )}") have been removed from Storybook: - ${usedAPIs.map((api) => `- ${chalk.cyan(api)}`).join('\n')} + ${usedAPIs.map((api) => `- ${picocolors.cyan(api)}`).join('\n')} Please see the migration guide for more information: - ${chalk.yellow( + ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#removed-global-client-apis' )} `; 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 59ce82d3cbbe..e1a189e70a6c 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 @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import type { Fix } from '../types'; import { getStorybookVersionSpecifier } from '../../helpers'; @@ -21,13 +21,13 @@ export const removeJestTestingLibrary: Fix<{ incompatiblePackages: string[] }> = }, prompt({ incompatiblePackages }) { return dedent` - ${chalk.bold( + ${picocolors.bold( 'Attention' )}: We've detected that you're using the following packages which are known to be incompatible since Storybook 8: - ${incompatiblePackages.map((name) => `- ${chalk.cyan(`${name}`)}`).join('\n')} + ${incompatiblePackages.map((name) => `- ${picocolors.cyan(`${name}`)}`).join('\n')} - We will uninstall them for you and install ${chalk.cyan('@storybook/test')} instead. + We will uninstall them for you and install ${picocolors.cyan('@storybook/test')} instead. Also, we can help you migrate your stories to use the new package. `; diff --git a/code/lib/cli/src/automigrate/fixes/sb-binary.ts b/code/lib/cli/src/automigrate/fixes/sb-binary.ts index 53b583b8a58f..3d28edfcbd81 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-binary.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-binary.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; import { getStorybookVersionSpecifier } from '../../helpers'; @@ -53,10 +53,10 @@ export const sbBinary: Fix = { }, prompt({ storybookVersion, hasSbBinary, hasStorybookBinary }) { - const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + const sbFormatted = picocolors.cyan(`Storybook ${storybookVersion}`); const storybookBinaryMessage = !hasStorybookBinary - ? `We've detected you are using ${sbFormatted} without Storybook's ${chalk.magenta( + ? `We've detected you are using ${sbFormatted} without Storybook's ${picocolors.magenta( 'storybook' )} binary. Starting in Storybook 7.0, it has to be installed.` : ''; @@ -69,7 +69,7 @@ export const sbBinary: Fix = { ${storybookBinaryMessage} ${extraMessage} - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#start-storybook--build-storybook-binaries-removed' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts index aad1796b9a38..374c5c6745bd 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import semver from 'semver'; import type { PackageJson } from '@storybook/types'; @@ -98,16 +98,16 @@ export const sbScripts: Fix = { }, prompt({ storybookVersion, storybookScripts }) { - const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + const sbFormatted = picocolors.cyan(`Storybook ${storybookVersion}`); const newScriptsMessage = Object.keys(storybookScripts).reduce((acc: string[], scriptKey) => { acc.push( [ - chalk.bold(scriptKey), + picocolors.bold(scriptKey), 'from:', - chalk.cyan(storybookScripts[scriptKey].before), + picocolors.cyan(storybookScripts[scriptKey].before), 'to:', - chalk.cyan(storybookScripts[scriptKey].after), + picocolors.cyan(storybookScripts[scriptKey].after), ].join('\n') ); return acc; @@ -115,16 +115,16 @@ export const sbScripts: Fix = { return dedent` We've detected you are using ${sbFormatted} with scripts from previous versions of Storybook. - Starting in Storybook 7, the ${chalk.yellow('start-storybook')} and ${chalk.yellow( + Starting in Storybook 7, the ${picocolors.yellow('start-storybook')} and ${picocolors.yellow( 'build-storybook' - )} binaries have changed to ${chalk.magenta('storybook dev')} and ${chalk.magenta( + )} binaries have changed to ${picocolors.magenta('storybook dev')} and ${picocolors.magenta( 'storybook build' )} respectively. In order to work with ${sbFormatted}, your storybook scripts have to be adjusted to use the binary. We can adjust them for you: ${newScriptsMessage.join('\n\n')} - In case this migration did not cover all of your scripts, or you'd like more info: ${chalk.yellow( + In case this migration did not cover all of your scripts, or you'd like more info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#start-storybook--build-storybook-binaries-removed' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts b/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts index deba1b9df901..8045a696a46e 100644 --- a/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts +++ b/code/lib/cli/src/automigrate/fixes/storyshots-migration.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import type { Fix } from '../types'; @@ -20,12 +20,12 @@ export const storyshotsMigration: Fix = { }, prompt() { return dedent` - ${chalk.bold( + ${picocolors.bold( 'Attention' )}: Storyshots is now officially deprecated, is no longer being maintained, and was removed in Storybook 8. We recommend following the migration guide we've prepared to help you during this transition period: - ${chalk.yellow('https://storybook.js.org/docs/writing-tests/storyshots-migration-guide')} + ${picocolors.yellow('https://storybook.js.org/docs/writing-tests/storyshots-migration-guide')} `; }, }; diff --git a/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.ts b/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.ts index c5a9d4218bb5..434204ef0e86 100644 --- a/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.ts +++ b/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.ts @@ -1,5 +1,5 @@ import { dedent } from 'ts-dedent'; -import { cyan, yellow } from 'chalk'; +import { cyan, yellow } from 'picocolors'; import { gt } from 'semver'; import type { JsPackageManager } from '@storybook/core-common'; import { isCorePackage } from '@storybook/core-common'; diff --git a/code/lib/cli/src/automigrate/fixes/vta.ts b/code/lib/cli/src/automigrate/fixes/vta.ts index 468cfacf3238..eaebf13301fa 100644 --- a/code/lib/cli/src/automigrate/fixes/vta.ts +++ b/code/lib/cli/src/automigrate/fixes/vta.ts @@ -1,5 +1,5 @@ import { dedent } from 'ts-dedent'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { getAddonNames, updateMainConfig } from '../helpers/mainConfigFile'; import type { Fix } from '../types'; @@ -32,7 +32,7 @@ export const vta: Fix = { return dedent` New to Storybook 8: Storybook's Visual Tests addon helps you catch unintentional changes/bugs in your stories. The addon is powered by Chromatic, a cloud-based testing tool developed by Storybook's core team. - Learn more: ${chalk.yellow('https://storybook.js.org/docs/writing-tests/visual-testing')} + Learn more: ${picocolors.yellow('https://storybook.js.org/docs/writing-tests/visual-testing')} Install Visual Tests addon in your project? `; diff --git a/code/lib/cli/src/automigrate/fixes/vue3.ts b/code/lib/cli/src/automigrate/fixes/vue3.ts index f641b30373de..69038c5a17cd 100644 --- a/code/lib/cli/src/automigrate/fixes/vue3.ts +++ b/code/lib/cli/src/automigrate/fixes/vue3.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import semver from 'semver'; import type { Fix } from '../types'; @@ -33,17 +33,17 @@ export const vue3: Fix = { }, prompt({ vueVersion, storybookVersion }) { - const vueFormatted = chalk.cyan(`Vue ${vueVersion}`); - const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + const vueFormatted = picocolors.cyan(`Vue ${vueVersion}`); + const sbFormatted = picocolors.cyan(`Storybook ${storybookVersion}`); return dedent` We've detected you are running ${vueFormatted} with Storybook. ${sbFormatted} runs webpack4 by default, which is incompatible. - In order to work with your version of Vue, we need to install Storybook's ${chalk.cyan( + In order to work with your version of Vue, we need to install Storybook's ${picocolors.cyan( 'webpack5 builder' )}. - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vue3-upgrade' )} `; 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 index dcebc1f28b8b..373096a3c214 100644 --- a/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.test.ts +++ b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.test.ts @@ -34,8 +34,8 @@ vi.mock('prompts', () => { }; }); -// mock chalk yellow and cyan -vi.mock('chalk', () => { +// mock picocolors yellow and cyan +vi.mock('picocolors', () => { return { default: { yellow: (str: string) => str, diff --git a/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts index d899ee5df3dd..c2dae6bc632b 100644 --- a/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts +++ b/code/lib/cli/src/automigrate/fixes/webpack5-compiler-setup.ts @@ -17,7 +17,7 @@ import { compilerNameToCoreCompiler, } from '../../project_types'; import dedent from 'ts-dedent'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { add } from '../../add'; type Options = { @@ -113,23 +113,23 @@ export const webpack5CompilerSetup = { 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.`); + The ${picocolors.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( + - If you have a ${picocolors.yellow('.babelrc')} (or ${picocolors.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( + - If you have a ${picocolors.yellow('.babelrc')} (or ${picocolors.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, + ${picocolors.yellow( + 'experimental.forceSwcTransforms = true' + )} in your ${picocolors.yellow('next.config.js')} file, Storybook will use SWC as the compiler. - - If you don't have a ${chalk.yellow('.babelrc')} (or ${chalk.yellow( + - If you don't have a ${picocolors.yellow('.babelrc')} (or ${picocolors.yellow( 'babel.config.js' )}) file in your project, Storybook will use SWC as the compiler. `); @@ -140,7 +140,7 @@ export const webpack5CompilerSetup = { - 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( + You can find more information here: ${picocolors.yellow( 'https://storybook.js.org/docs/8.0/builders/webpack#compiler-support' )} `); @@ -150,7 +150,7 @@ export const webpack5CompilerSetup = { 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( + You can find more information here: ${picocolors.yellow( 'https://storybook.js.org/docs/8.0/builders/webpack#compiler-support' )} `); diff --git a/code/lib/cli/src/automigrate/fixes/webpack5.ts b/code/lib/cli/src/automigrate/fixes/webpack5.ts index a2072be41eb9..734c22afb23d 100644 --- a/code/lib/cli/src/automigrate/fixes/webpack5.ts +++ b/code/lib/cli/src/automigrate/fixes/webpack5.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import semver from 'semver'; import type { Fix } from '../types'; @@ -42,17 +42,17 @@ export const webpack5 = { }, prompt({ webpackVersion }) { - const webpackFormatted = chalk.cyan(`webpack ${webpackVersion}`); + const webpackFormatted = picocolors.cyan(`webpack ${webpackVersion}`); return dedent` We've detected you're running ${webpackFormatted}. Your Storybook's main.js files specifies webpack4, which is incompatible. - To run Storybook in webpack5-mode, we can install Storybook's ${chalk.cyan( + To run Storybook in webpack5-mode, we can install Storybook's ${picocolors.cyan( '@storybook/builder-webpack5' )} for you. - More info: ${chalk.yellow( + More info: ${picocolors.yellow( 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack-5-manager-build' )} `; diff --git a/code/lib/cli/src/automigrate/fixes/wrap-require.ts b/code/lib/cli/src/automigrate/fixes/wrap-require.ts index e241f05858ab..aa0114b5a6ff 100644 --- a/code/lib/cli/src/automigrate/fixes/wrap-require.ts +++ b/code/lib/cli/src/automigrate/fixes/wrap-require.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; import { readConfig } from '@storybook/csf-tools'; import type { Fix } from '../types'; @@ -48,7 +48,7 @@ export const wrapRequire: Fix = { }, prompt({ storybookVersion, isStorybookInMonorepo }) { - const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + const sbFormatted = picocolors.cyan(`Storybook ${storybookVersion}`); return dedent`We have detected that you're using ${sbFormatted} in a ${ isStorybookInMonorepo ? 'monorepo' : 'PnP' diff --git a/code/lib/cli/src/automigrate/helpers/checkWebpack5Builder.ts b/code/lib/cli/src/automigrate/helpers/checkWebpack5Builder.ts index a350b23fd82b..72aec1db8336 100644 --- a/code/lib/cli/src/automigrate/helpers/checkWebpack5Builder.ts +++ b/code/lib/cli/src/automigrate/helpers/checkWebpack5Builder.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import semver from 'semver'; import dedent from 'ts-dedent'; import type { StorybookConfigRaw } from '@storybook/types'; @@ -20,11 +20,11 @@ export const checkWebpack5Builder = async ({ To upgrade to the latest stable release, run this from your project directory: - ${chalk.cyan('npx storybook@latest upgrade')} + ${picocolors.cyan('npx storybook@latest upgrade')} To upgrade to the latest pre-release, run this from your project directory: - ${chalk.cyan('npx storybook@next upgrade')} + ${picocolors.cyan('npx storybook@next upgrade')} `.trim() ); return null; diff --git a/code/lib/cli/src/automigrate/helpers/eslintPlugin.ts b/code/lib/cli/src/automigrate/helpers/eslintPlugin.ts index 7f238a4f5dbd..f74ca37ec216 100644 --- a/code/lib/cli/src/automigrate/helpers/eslintPlugin.ts +++ b/code/lib/cli/src/automigrate/helpers/eslintPlugin.ts @@ -2,7 +2,7 @@ import fse, { readFile, readJson, writeJson } from 'fs-extra'; import { dedent } from 'ts-dedent'; import detectIndent from 'detect-indent'; import prompts from 'prompts'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { readConfig, writeConfig } from '@storybook/csf-tools'; import type { JsPackageManager } from '@storybook/core-common'; @@ -95,7 +95,7 @@ export const suggestESLintPlugin = async (): Promise => { type: 'confirm', name: 'shouldInstall', message: dedent` - We have detected that you're using ESLint. Storybook provides a plugin that gives the best experience with Storybook and helps follow best practices: ${chalk.yellow( + We have detected that you're using ESLint. Storybook provides a plugin that gives the best experience with Storybook and helps follow best practices: ${picocolors.yellow( 'https://github.com/storybookjs/eslint-plugin-storybook#readme' )} diff --git a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts index e0f708543bef..71d4b12ab0da 100644 --- a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts +++ b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import boxen from 'boxen'; import dedent from 'ts-dedent'; import { type InstallationMetadata } from '@storybook/core-common'; @@ -15,34 +15,36 @@ function getGlossaryMessages( ) { const messages = []; if (fixSummary.succeeded.length > 0) { - messages.push(chalk.bold('Successful migrations:')); - messages.push(fixSummary.succeeded.map((m) => chalk.green(m)).join(', ')); + messages.push(picocolors.bold('Successful migrations:')); + messages.push(fixSummary.succeeded.map((m) => picocolors.green(m)).join(', ')); } if (Object.keys(fixSummary.failed).length > 0) { - messages.push(chalk.bold('Failed migrations:')); + messages.push(picocolors.bold('Failed migrations:')); messages.push( Object.entries(fixSummary.failed) .map(([id, error]) => { - return `${chalk.redBright(id)}:\n${error}`; + return `${picocolors.redBright(id)}:\n${error}`; }) .join('\n') ); - messages.push(`You can find the full logs in ${chalk.cyan(logFile)}`); + messages.push(`You can find the full logs in ${picocolors.cyan(logFile)}`); } if (fixSummary.manual.length > 0) { - messages.push(chalk.bold('Manual migrations:')); + messages.push(picocolors.bold('Manual migrations:')); messages.push( fixSummary.manual - .map((m) => (fixResults[m] === FixStatus.MANUAL_SUCCEEDED ? chalk.green(m) : chalk.blue(m))) + .map((m) => + fixResults[m] === FixStatus.MANUAL_SUCCEEDED ? picocolors.green(m) : picocolors.blue(m) + ) .join(', ') ); } if (fixSummary.skipped.length > 0) { - messages.push(chalk.bold('Skipped migrations:')); - messages.push(fixSummary.skipped.map((m) => chalk.cyan(m)).join(', ')); + messages.push(picocolors.bold('Skipped migrations:')); + messages.push(fixSummary.skipped.map((m) => picocolors.cyan(m)).join(', ')); } return messages; @@ -62,16 +64,16 @@ export function getMigrationSummary({ const messages = []; messages.push(getGlossaryMessages(fixSummary, fixResults, logFile).join(messageDivider)); - messages.push(dedent`If you'd like to run the migrations again, you can do so by running '${chalk.cyan( + messages.push(dedent`If you'd like to run the migrations again, you can do so by running '${picocolors.cyan( 'npx storybook automigrate' )}' The automigrations try to migrate common patterns in your project, but might not contain everything needed to migrate to the latest version of Storybook. - Please check the changelog and migration guide for manual migrations and more information: ${chalk.yellow( + Please check the changelog and migration guide for manual migrations and more information: ${picocolors.yellow( 'https://storybook.js.org/docs/8.0/migration-guide' )} - And reach out on Discord if you need help: ${chalk.yellow('https://discord.gg/storybook')} + And reach out on Discord if you need help: ${picocolors.yellow('https://discord.gg/storybook')} `); const hasNoFixes = Object.values(fixResults).every((r) => r === FixStatus.UNNECESSARY); diff --git a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts index 11a13c127e0e..bd0152d9eca5 100644 --- a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts @@ -9,7 +9,7 @@ import { import type { StorybookConfigRaw, StorybookConfig } from '@storybook/types'; import type { ConfigFile } from '@storybook/csf-tools'; import { readConfig, writeConfig as writeConfigFile } from '@storybook/csf-tools'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import path from 'path'; import type { JsPackageManager } from '@storybook/core-common'; @@ -137,7 +137,7 @@ export const getStorybookData = async ({ mainConfig = (await loadMainConfig({ configDir, noCache: true })) as StorybookConfigRaw; } catch (err) { throw new Error( - dedent`Unable to find or evaluate ${chalk.blue(mainConfigPath)}: ${String(err)}` + dedent`Unable to find or evaluate ${picocolors.blue(mainConfigPath)}: ${String(err)}` ); } @@ -178,13 +178,13 @@ export const updateMainConfig = async ( } } catch (e) { logger.info( - `❌ The migration failed to update your ${chalk.blue( + `❌ The migration failed to update your ${picocolors.blue( mainConfigPath )} on your behalf because of the following error: ${e}\n` ); logger.info( - `⚠️ Storybook automigrations are based on AST parsing and it's possible that your ${chalk.blue( + `⚠️ Storybook automigrations are based on AST parsing and it's possible that your ${picocolors.blue( mainConfigPath )} file contains a non-standard format (e.g. your export is not an object) or that there was an error when parsing dynamic values (e.g. "require" calls, or usage of environment variables). When your main config is non-standard, automigrations are unfortunately not possible. Please follow the instructions given previously and follow the documentation to make the updates manually.` ); diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index c5353602dbaa..153ae14198f0 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -1,5 +1,5 @@ import prompts from 'prompts'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import boxen from 'boxen'; import { createWriteStream, move, remove } from 'fs-extra'; import { join } from 'path'; @@ -60,7 +60,7 @@ const cleanup = () => { const logAvailableMigrations = () => { const availableFixes = allFixes - .map((f) => chalk.yellow(f.id)) + .map((f) => picocolors.yellow(f.id)) .map((x) => `- ${x}`) .join('\n'); @@ -153,7 +153,7 @@ export const automigrate = async ({ const fixes: Fix[] = fixId ? selectedFixes.filter((f) => f.id === fixId) : selectedFixes; if (fixId && fixes.length === 0) { - logger.info(`📭 No migrations found for ${chalk.magenta(fixId)}.`); + logger.info(`📭 No migrations found for ${picocolors.magenta(fixId)}.`); logAvailableMigrations(); return null; } @@ -264,7 +264,7 @@ export async function runFixes({ }); } } catch (error) { - logger.info(`⚠️ failed to check fix ${chalk.bold(f.id)}`); + logger.info(`⚠️ failed to check fix ${picocolors.bold(f.id)}`); if (error instanceof Error) { logger.error(`\n${error.stack}`); fixSummary.failed[f.id] = error.message; @@ -276,7 +276,7 @@ export async function runFixes({ const promptType: Prompt = typeof f.promptType === 'function' ? await f.promptType(result) : f.promptType ?? 'auto'; - logger.info(`\n🔎 found a '${chalk.cyan(f.id)}' migration:`); + logger.info(`\n🔎 found a '${picocolors.cyan(f.id)}' migration:`); const message = f.prompt(result); const getTitle = () => { @@ -341,7 +341,9 @@ export async function runFixes({ { type: 'confirm', name: 'fix', - message: `Do you want to run the '${chalk.cyan(f.id)}' migration on your project?`, + message: `Do you want to run the '${picocolors.cyan( + f.id + )}' migration on your project?`, initial: f.promptDefaultValue ?? true, }, { @@ -382,7 +384,7 @@ export async function runFixes({ mainConfigPath, skipInstall, }); - logger.info(`✅ ran ${chalk.cyan(f.id)} migration`); + logger.info(`✅ ran ${picocolors.cyan(f.id)} migration`); fixResults[f.id] = FixStatus.SUCCEEDED; fixSummary.succeeded.push(f.id); @@ -391,7 +393,7 @@ export async function runFixes({ fixSummary.failed[f.id] = error instanceof Error ? error.message : 'Failed to run migration'; - logger.info(`❌ error when running ${chalk.cyan(f.id)} migration`); + logger.info(`❌ error when running ${picocolors.cyan(f.id)} migration`); logger.info(error); logger.info(); } diff --git a/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts b/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts index 272313300728..a447ff97eacf 100644 --- a/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts +++ b/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { frameworkPackages, rendererPackages } from '@storybook/core-common'; import type { InstallationMetadata } from '@storybook/core-common'; import { hasMultipleVersions } from './hasMultipleVersions'; @@ -67,9 +67,9 @@ export function getDuplicatedDepsWarnings( const hasMultipleMajorVersions = hasMultipleVersions(packageVersions); if (disallowList.includes(dep) && hasMultipleMajorVersions) { - acc.critical.push(`${chalk.redBright(dep)}:\n${packageVersions.join(', ')}`); + acc.critical.push(`${picocolors.redBright(dep)}:\n${packageVersions.join(', ')}`); } else { - acc.trivial.push(`${chalk.hex('#ff9800')(dep)}:\n${packageVersions.join(', ')}`); + acc.trivial.push(`${picocolors.hex('#ff9800')(dep)}:\n${packageVersions.join(', ')}`); } return acc; @@ -83,7 +83,7 @@ export function getDuplicatedDepsWarnings( if (critical.length > 0) { messages.push( - `${chalk.bold( + `${picocolors.bold( 'Critical:' )} The following dependencies are duplicated and WILL cause unexpected behavior:` ); @@ -92,7 +92,7 @@ export function getDuplicatedDepsWarnings( if (trivial.length > 0) { messages.push( - `${chalk.bold( + `${picocolors.bold( 'Attention:' )} The following dependencies are duplicated which might cause unexpected behavior:` ); @@ -101,14 +101,14 @@ export function getDuplicatedDepsWarnings( messages.push( '\n', - `Please try de-duplicating these dependencies by running ${chalk.cyan( + `Please try de-duplicating these dependencies by running ${picocolors.cyan( `${installationMetadata.dedupeCommand}` )}` ); messages.push( '\n', - `You can find more information for a given dependency by running ${chalk.cyan( + `You can find more information for a given dependency by running ${picocolors.cyan( `${installationMetadata.infoCommand} ` )}` ); diff --git a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts index 5d5a2d8a6e87..f38326e4dd70 100644 --- a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts @@ -7,7 +7,7 @@ import { } from './getIncompatibleStorybookPackages'; import type { JsPackageManager } from '@storybook/core-common'; -vi.mock('chalk', () => { +vi.mock('picocolors', () => { return { default: { yellow: (str: string) => str, diff --git a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts index 09f0c40d5bb9..6fe2e5bb3797 100644 --- a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts @@ -1,5 +1,5 @@ /* eslint-disable local-rules/no-uncategorized-errors */ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import semver from 'semver'; import type { JsPackageManager } from '@storybook/core-common'; import { JsPackageManagerFactory, versions as storybookCorePackages } from '@storybook/core-common'; @@ -103,15 +103,15 @@ export const getIncompatiblePackagesSummary = ( if (incompatiblePackages.length > 0) { summaryMessage.push( - `The following packages are incompatible with Storybook ${chalk.bold( + `The following packages are incompatible with Storybook ${picocolors.bold( currentStorybookVersion )} as they depend on different major versions of Storybook packages:` ); incompatiblePackages.forEach( ({ packageName: addonName, packageVersion: addonVersion, homepage, availableUpdate }) => { - const packageDescription = `${chalk.cyan(addonName)}@${chalk.cyan(addonVersion)}`; + const packageDescription = `${picocolors.cyan(addonName)}@${picocolors.cyan(addonVersion)}`; const updateMessage = availableUpdate ? ` (${availableUpdate} available!)` : ''; - const packageRepo = homepage ? `\n Repo: ${chalk.yellow(homepage)}` : ''; + const packageRepo = homepage ? `\n Repo: ${picocolors.yellow(homepage)}` : ''; summaryMessage.push(`- ${packageDescription}${updateMessage}${packageRepo}`); } @@ -121,7 +121,7 @@ export const getIncompatiblePackagesSummary = ( '\n', 'Please consider updating your packages or contacting the maintainers for compatibility details.', 'For more on Storybook 8 compatibility, see the linked GitHub issue:', - chalk.yellow('https://github.com/storybookjs/storybook/issues/26031') + picocolors.yellow('https://github.com/storybookjs/storybook/issues/26031') ); } diff --git a/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts b/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts index f8c9e0874a0f..11545df30184 100644 --- a/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts +++ b/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import semver from 'semver'; import { frameworkPackages, versions as storybookCorePackages } from '@storybook/core-common'; import type { InstallationMetadata } from '@storybook/core-common'; @@ -40,7 +40,7 @@ export function getMismatchingVersionsWarnings( } messages.push( - `${chalk.bold( + `${picocolors.bold( 'Attention:' )} There seems to be a mismatch between your Storybook package versions. This can result in a broken Storybook installation.` ); @@ -56,9 +56,9 @@ export function getMismatchingVersionsWarnings( } messages.push( - `The version of your storybook core packages should align with ${chalk.yellow( + `The version of your storybook core packages should align with ${picocolors.yellow( versionToCompare - )} (from the ${chalk.cyan(packageToDisplay)} package) or higher.` + )} (from the ${picocolors.cyan(packageToDisplay)} package) or higher.` ); const filteredDependencies = Object.entries(installationMetadata?.dependencies || []).filter( @@ -79,7 +79,7 @@ export function getMismatchingVersionsWarnings( filteredDependencies .map( ([name, dep]) => - `${chalk.hex('#ff9800')(name)}: ${dep[0].version} ${ + `${picocolors.hex('#ff9800')(name)}: ${dep[0].version} ${ allDependencies?.[name] ? packageJsonSuffix : '' }` ) @@ -92,11 +92,11 @@ export function getMismatchingVersionsWarnings( } messages.push( - `You can run ${chalk.cyan( + `You can run ${picocolors.cyan( 'npx storybook@latest upgrade' )} to upgrade all of your Storybook packages to the latest version. - Alternatively you can try manually changing the versions to match in your package.json. We also recommend regenerating your lockfile, or running the following command to possibly deduplicate your Storybook package versions: ${chalk.cyan( + Alternatively you can try manually changing the versions to match in your package.json. We also recommend regenerating your lockfile, or running the following command to possibly deduplicate your Storybook package versions: ${picocolors.cyan( installationMetadata?.dedupeCommand )}` ); diff --git a/code/lib/cli/src/doctor/index.ts b/code/lib/cli/src/doctor/index.ts index 22e47ce7d32c..ef1e23bdeb24 100644 --- a/code/lib/cli/src/doctor/index.ts +++ b/code/lib/cli/src/doctor/index.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import boxen from 'boxen'; import { createWriteStream, move, remove } from 'fs-extra'; import dedent from 'ts-dedent'; @@ -82,7 +82,7 @@ export const doctor = async ({ } catch (err: any) { if (err.message.includes('No configuration files have been found')) { logger.info( - dedent`[Storybook doctor] Could not find or evaluate your Storybook main.js config directory at ${chalk.blue( + dedent`[Storybook doctor] Could not find or evaluate your Storybook main.js config directory at ${picocolors.blue( userSpecifiedConfigDir || '.storybook' )} so the doctor command cannot proceed. You might be running this command in a monorepo or a non-standard project structure. If that is the case, please rerun this command by specifying the path to your Storybook config directory via the --config-dir option.` ); @@ -140,7 +140,7 @@ export const doctor = async ({ } } - const commandMessage = `You can always recheck the health of your project by running:\n${chalk.cyan( + const commandMessage = `You can always recheck the health of your project by running:\n${picocolors.cyan( 'npx storybook doctor' )}`; logger.info(); @@ -149,7 +149,7 @@ export const doctor = async ({ logger.info(commandMessage); logger.info(); - logger.info(`Full logs are available in ${chalk.cyan(LOG_FILE_PATH)}`); + logger.info(`Full logs are available in ${picocolors.cyan(LOG_FILE_PATH)}`); await move(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME), { overwrite: true }); } else { diff --git a/code/lib/cli/src/generate.ts b/code/lib/cli/src/generate.ts index a1a3d83ddfbb..3e3b4c755629 100644 --- a/code/lib/cli/src/generate.ts +++ b/code/lib/cli/src/generate.ts @@ -1,5 +1,5 @@ import program from 'commander'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import envinfo from 'envinfo'; import leven from 'leven'; import { sync as readUpSync } from 'read-pkg-up'; @@ -114,7 +114,7 @@ command('upgrade') command('info') .description('Prints debugging information about the local environment') .action(async () => { - consoleLogger.log(chalk.bold('\nStorybook Environment Info:')); + consoleLogger.log(picocolors.bold('\nStorybook Environment Info:')); const pkgManager = await JsPackageManagerFactory.getPackageManager(); const activePackageManager = pkgManager.type.replace(/\d/, ''); // 'yarn1' -> 'yarn' const output = await envinfo.run({ @@ -128,7 +128,7 @@ command('info') consoleLogger.log( output.replace( activePackageManagerLine, - chalk.bold(`${activePackageManagerLine} <----- active`) + picocolors.bold(`${activePackageManagerLine} <----- active`) ) ); }); @@ -254,7 +254,7 @@ command('dev') ) .action(async (options) => { logger.setLevel(program.loglevel); - consoleLogger.log(chalk.bold(`${pkg.name} v${pkg.version}`) + chalk.reset('\n')); + consoleLogger.log(picocolors.bold(`${pkg.name} v${pkg.version}`) + picocolors.reset('\n')); // The key is the field created in `options` variable for // each command line argument. Value is the env variable. @@ -294,7 +294,7 @@ command('build') .action(async (options) => { process.env.NODE_ENV = process.env.NODE_ENV || 'production'; logger.setLevel(program.loglevel); - consoleLogger.log(chalk.bold(`${pkg.name} v${pkg.version}\n`)); + consoleLogger.log(picocolors.bold(`${pkg.name} v${pkg.version}\n`)); // The key is the field created in `options` variable for // each command line argument. Value is the env variable. diff --git a/code/lib/cli/src/helpers.ts b/code/lib/cli/src/helpers.ts index 5c8351cca7b0..b665c52619d6 100644 --- a/code/lib/cli/src/helpers.ts +++ b/code/lib/cli/src/helpers.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import fs from 'fs'; import fse from 'fs-extra'; import path, { join } from 'path'; @@ -33,7 +33,7 @@ export function readFileAsJson(jsonPath: string, allowComments?: boolean) { try { return JSON.parse(jsonContent); } catch (e) { - logger.error(chalk.red(`Invalid json in file: ${filePath}`)); + logger.error(picocolors.red(`Invalid json in file: ${filePath}`)); throw e; } } diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index dabe81cb2fcb..8c764c778851 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -1,6 +1,6 @@ import { appendFile, readFile } from 'fs/promises'; import findUp from 'find-up'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import prompts from 'prompts'; import { telemetry } from '@storybook/telemetry'; import { withTelemetry } from '@storybook/core-server'; @@ -184,7 +184,7 @@ const installStorybook = async ( return await runGenerator(); } catch (err: any) { if (err?.message !== 'Canceled by the user' && err?.stack) { - logger.error(`\n ${chalk.red(err.stack)}`); + logger.error(`\n ${picocolors.red(err.stack)}`); } throw new HandledError(err); } @@ -249,15 +249,15 @@ export async function doInitiate(options: CommandOptions): Promise< const borderColor = isOutdated ? '#FC521F' : '#F1618C'; const messages = { - welcome: `Adding Storybook version ${chalk.bold(currentVersion)} to your project..`, - notLatest: chalk.red(dedent` - This version is behind the latest release, which is: ${chalk.bold(latestVersion)}! + welcome: `Adding Storybook version ${picocolors.bold(currentVersion)} to your project..`, + notLatest: picocolors.red(dedent` + This version is behind the latest release, which is: ${picocolors.bold(latestVersion)}! You likely ran the init command through npx, which can use a locally cached version, to get the latest please run: - ${chalk.bold('npx storybook@latest init')} + ${picocolors.bold('npx storybook@latest init')} You may want to CTRL+C to stop, and run with the latest version instead. `), - prelease: chalk.yellow('This is a pre-release version.'), + prelease: picocolors.yellow('This is a pre-release version.'), }; logger.log( @@ -353,22 +353,22 @@ export async function doInitiate(options: CommandOptions): Promise< if (projectType === ProjectType.REACT_NATIVE) { logger.log(dedent` - ${chalk.yellow('NOTE: installation is not 100% automated.')} + ${picocolors.yellow('NOTE: installation is not 100% automated.')} To run Storybook, you will need to: 1. Replace the contents of your app entry with the following - ${chalk.inverse(' ' + "export {default} from './.storybook';" + ' ')} + ${picocolors.inverse(' ' + "export {default} from './.storybook';" + ' ')} 2. Enable transformer.unstable_allowRequireContext in your metro config For a more detailed guide go to: - ${chalk.cyan('https://github.com/storybookjs/react-native#existing-project')} + ${picocolors.cyan('https://github.com/storybookjs/react-native#existing-project')} Then to run your Storybook, type: - ${chalk.inverse(' ' + packageManager.getRunCommand('start') + ' ')} + ${picocolors.inverse(' ' + packageManager.getRunCommand('start') + ' ')} `); @@ -393,12 +393,14 @@ export async function doInitiate(options: CommandOptions): Promise< boxen( dedent` Storybook was successfully installed in your project! 🎉 - To run Storybook manually, run ${chalk.yellow( - chalk.bold(storybookCommand) + To run Storybook manually, run ${picocolors.yellow( + picocolors.bold(storybookCommand) )}. CTRL+C to stop. - Wanna know more about Storybook? Check out ${chalk.cyan('https://storybook.js.org/')} - Having trouble or want to chat? Join us at ${chalk.cyan('https://discord.gg/storybook/')} + Wanna know more about Storybook? Check out ${picocolors.cyan('https://storybook.js.org/')} + Having trouble or want to chat? Join us at ${picocolors.cyan( + 'https://discord.gg/storybook/' + )} `, { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } ) diff --git a/code/lib/cli/src/link.ts b/code/lib/cli/src/link.ts index 3af08643874b..4e242cdb12af 100644 --- a/code/lib/cli/src/link.ts +++ b/code/lib/cli/src/link.ts @@ -2,7 +2,7 @@ import fse from 'fs-extra'; import path from 'path'; import { sync as spawnSync, spawn as spawnAsync } from 'cross-spawn'; import { logger } from '@storybook/node-logger'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; type ExecOptions = Parameters[2]; @@ -44,7 +44,7 @@ export const exec = async ( if (code === 0) { resolve(undefined); } else { - logger.error(chalk.red(`An error occurred while executing: \`${command}\``)); + logger.error(picocolors.red(`An error occurred while executing: \`${command}\``)); if (errorMessage) { logger.info(errorMessage); } diff --git a/code/lib/cli/src/sandbox.ts b/code/lib/cli/src/sandbox.ts index 621d62976c10..08809c31cd37 100644 --- a/code/lib/cli/src/sandbox.ts +++ b/code/lib/cli/src/sandbox.ts @@ -1,6 +1,6 @@ import prompts from 'prompts'; import path from 'path'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import boxen from 'boxen'; import { dedent } from 'ts-dedent'; import { downloadTemplate } from 'giget'; @@ -56,18 +56,18 @@ export const sandbox = async ({ const branch = isPrerelease ? 'next' : 'main'; const messages = { - welcome: `Creating a Storybook ${chalk.bold(currentVersion)} sandbox..`, - notLatest: chalk.red(dedent` - This version is behind the latest release, which is: ${chalk.bold(latestVersion)}! + welcome: `Creating a Storybook ${picocolors.bold(currentVersion)} sandbox..`, + notLatest: picocolors.red(dedent` + This version is behind the latest release, which is: ${picocolors.bold(latestVersion)}! You likely ran the init command through npx, which can use a locally cached version, to get the latest please run: - ${chalk.bold('npx storybook@latest sandbox')} + ${picocolors.bold('npx storybook@latest sandbox')} You may want to CTRL+C to stop, and run with the latest version instead. `), - longInitTime: chalk.yellow( + longInitTime: picocolors.yellow( 'The creation of the sandbox will take longer, because we will need to run init.' ), - prerelease: chalk.yellow('This is a pre-release version.'), + prerelease: picocolors.yellow('This is a pre-release version.'), }; logger.log( @@ -114,12 +114,12 @@ export const sandbox = async ({ dedent` 🔎 You filtered out all templates. 🔍 - After filtering all the templates with "${chalk.yellow( + After filtering all the templates with "${picocolors.yellow( filterValue )}", we found no results. Please try again with a different filter. Available templates: - ${keys.map((key) => chalk.blue`- ${key}`).join('\n')} + ${keys.map((key) => picocolors.blue`- ${key}`).join('\n')} `.trim(), { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any ) @@ -133,9 +133,9 @@ export const sandbox = async ({ logger.info( boxen( dedent` - 🤗 Welcome to ${chalk.yellow('sb sandbox')}! 🤗 + 🤗 Welcome to ${picocolors.yellow('sb sandbox')}! 🤗 - Create a ${chalk.green('new project')} to minimally reproduce Storybook issues. + Create a ${picocolors.green('new project')} to minimally reproduce Storybook issues. 1. select an environment that most closely matches your project setup. 2. select a location for the reproduction, outside of your project. @@ -198,7 +198,7 @@ export const sandbox = async ({ logger.info(`🏃 Adding ${selectedConfig.name} into ${templateDestination}`); - logger.log(`📦 Downloading sandbox template (${chalk.bold(downloadType)})...`); + logger.log(`📦 Downloading sandbox template (${picocolors.bold(downloadType)})...`); try { // Download the sandbox based on subfolder "after-storybook" and selected branch const gitPath = `github:storybookjs/sandboxes/${templateId}/${downloadType}#${branch}`; @@ -208,9 +208,9 @@ export const sandbox = async ({ }); // throw an error if templateDestination is an empty directory using fs-extra if ((await readdir(templateDestination)).length === 0) { - const selected = chalk.yellow(templateId); + const selected = picocolors.yellow(templateId); throw new Error(dedent` - Template downloaded from ${chalk.blue(gitPath)} is empty. + Template downloaded from ${picocolors.blue(gitPath)} is empty. Are you use it exists? Or did you want to set ${selected} to inDevelopment first? `); } @@ -236,23 +236,23 @@ export const sandbox = async ({ } const initMessage = init - ? chalk.yellow(dedent` + ? picocolors.yellow(dedent` yarn install yarn storybook `) - : `Recreate your setup, then ${chalk.yellow(`npx storybook@latest init`)}`; + : `Recreate your setup, then ${picocolors.yellow(`npx storybook@latest init`)}`; logger.info( boxen( dedent` 🎉 Your Storybook reproduction project is ready to use! 🎉 - ${chalk.yellow(`cd ${selectedDirectory}`)} + ${picocolors.yellow(`cd ${selectedDirectory}`)} ${initMessage} Once you've recreated the problem you're experiencing, please: - 1. Document any additional steps in ${chalk.cyan('README.md')} + 1. Document any additional steps in ${picocolors.cyan('README.md')} 2. Publish the repository to github 3. Link to the repro repository in your issue diff --git a/code/lib/cli/src/scaffold-new-project.ts b/code/lib/cli/src/scaffold-new-project.ts index 16ca8b7d444c..49d79e720b6a 100644 --- a/code/lib/cli/src/scaffold-new-project.ts +++ b/code/lib/cli/src/scaffold-new-project.ts @@ -1,5 +1,5 @@ import boxen from 'boxen'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import execa from 'execa'; import { readdirSync, remove } from 'fs-extra'; import prompts from 'prompts'; @@ -103,7 +103,7 @@ const packageManagerToCoercedName = ( const buildProjectDisplayNameForPrint = ({ displayName }: SupportedProject) => { const { type, builder, language } = displayName; - return `${chalk.bold.blue(type)} ${builder ? `+ ${builder} ` : ''}(${language})`; + return `${picocolors.bold.blue(type)} ${builder ? `+ ${builder} ` : ''}(${language})`; }; /** @@ -122,14 +122,14 @@ export const scaffoldNewProject = async ( dedent` Would you like to generate a new project from the following list? - ${chalk.bold('Note:')} + ${picocolors.bold('Note:')} Storybook supports many more frameworks and bundlers than listed below. If you don't see your preferred setup, you can still generate a project then rerun this command to add Storybook. - ${chalk.bold('Press ^C at any time to quit.')} + ${picocolors.bold('Press ^C at any time to quit.')} `, { - title: chalk.bold('🔎 Empty directory detected'), + title: picocolors.bold('🔎 Empty directory detected'), padding: 1, borderStyle: 'double', borderColor: 'yellow', @@ -167,7 +167,7 @@ export const scaffoldNewProject = async ( logger.line(1); logger.plain( - `Creating a new "${projectDisplayName}" project with ${chalk.bold(packageManagerName)}...` + `Creating a new "${projectDisplayName}" project with ${picocolors.bold(packageManagerName)}...` ); logger.line(1); @@ -203,12 +203,14 @@ export const scaffoldNewProject = async ( logger.plain( boxen( dedent` - "${projectDisplayName}" project with ${chalk.bold(packageManagerName)} created successfully! + "${projectDisplayName}" project with ${picocolors.bold( + packageManagerName + )} created successfully! Continuing with Storybook installation... `, { - title: chalk.bold('✅ Success!'), + title: picocolors.bold('✅ Success!'), padding: 1, borderStyle: 'double', borderColor: 'green', diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index 204e24710c6b..507488b80981 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -10,7 +10,7 @@ import { UpgradeStorybookUnknownCurrentVersionError, } from '@storybook/core-events/server-errors'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import dedent from 'ts-dedent'; import boxen from 'boxen'; import type { JsPackageManager, PackageManagerName } from '@storybook/core-common'; @@ -165,17 +165,19 @@ export const doUpgrade = async ({ const borderColor = isCLIOutdated ? '#FC521F' : '#F1618C'; const messages = { - welcome: `Upgrading Storybook from version ${chalk.bold(beforeVersion)} to version ${chalk.bold( - currentCLIVersion - )}..`, - notLatest: chalk.red(dedent` - This version is behind the latest release, which is: ${chalk.bold(latestCLIVersionOnNPM)}! + welcome: `Upgrading Storybook from version ${picocolors.bold( + beforeVersion + )} to version ${picocolors.bold(currentCLIVersion)}..`, + notLatest: picocolors.red(dedent` + This version is behind the latest release, which is: ${picocolors.bold( + latestCLIVersionOnNPM + )}! You likely ran the upgrade command through npx, which can use a locally cached version, to upgrade to the latest version please run: - ${chalk.bold('npx storybook@latest upgrade')} + ${picocolors.bold('npx storybook@latest upgrade')} You may want to CTRL+C to stop, and run with the latest version instead. `), - prerelease: chalk.yellow('This is a pre-release version.'), + prerelease: picocolors.yellow('This is a pre-release version.'), }; logger.plain( @@ -246,7 +248,7 @@ export const doUpgrade = async ({ const upgradedDependencies = toUpgradedDependencies(packageJson.dependencies); const upgradedDevDependencies = toUpgradedDependencies(packageJson.devDependencies); - logger.info(`Updating dependencies in ${chalk.cyan('package.json')}..`); + logger.info(`Updating dependencies in ${picocolors.cyan('package.json')}..`); if (upgradedDependencies.length > 0) { await packageManager.addDependencies( { installAsDevDependencies: false, skipInstall: true, packageJson }, diff --git a/code/lib/core-common/package.json b/code/lib/core-common/package.json index e92ee9948da7..aeb46590a1ea 100644 --- a/code/lib/core-common/package.json +++ b/code/lib/core-common/package.json @@ -50,7 +50,6 @@ "@storybook/types": "workspace:*", "@yarnpkg/fslib": "2.10.3", "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", "cross-spawn": "^7.0.3", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", "esbuild-register": "^3.5.0", @@ -63,6 +62,7 @@ "handlebars": "^4.7.7", "lazy-universal-dotenv": "^4.0.0", "node-fetch": "^2.0.0", + "picocolors": "^1.0.1", "picomatch": "^2.3.0", "pkg-dir": "^5.0.0", "prettier-fallback": "npm:prettier@^3", diff --git a/code/lib/core-common/src/js-package-manager/JsPackageManager.ts b/code/lib/core-common/src/js-package-manager/JsPackageManager.ts index 8f306850b032..ee748f66b604 100644 --- a/code/lib/core-common/src/js-package-manager/JsPackageManager.ts +++ b/code/lib/core-common/src/js-package-manager/JsPackageManager.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { gt, satisfies } from 'semver'; import type { CommonOptions } from 'execa'; import { command as execaCommand, sync as execaCommandSync } from 'execa'; @@ -392,11 +392,11 @@ export abstract class JsPackageManager { latest = await this.latestVersion(packageName, constraint); } catch (e) { if (current) { - logger.warn(`\n ${chalk.yellow(String(e))}`); + logger.warn(`\n ${picocolors.yellow(String(e))}`); return current; } - logger.error(`\n ${chalk.red(String(e))}`); + logger.error(`\n ${picocolors.red(String(e))}`); throw new HandledError(e); } diff --git a/code/lib/core-common/src/utils/log-config.ts b/code/lib/core-common/src/utils/log-config.ts index 5d50f0285298..aab43e9b29ec 100644 --- a/code/lib/core-common/src/utils/log-config.ts +++ b/code/lib/core-common/src/utils/log-config.ts @@ -1,6 +1,6 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; export function logConfig(caption: unknown, config: unknown) { - console.log(chalk.cyan(caption)); + console.log(picocolors.cyan(String(caption))); console.dir(config, { depth: null }); } diff --git a/code/lib/core-common/src/utils/log.ts b/code/lib/core-common/src/utils/log.ts index 43119e616b24..3f7e8d51cb72 100644 --- a/code/lib/core-common/src/utils/log.ts +++ b/code/lib/core-common/src/utils/log.ts @@ -1,15 +1,15 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; const logger = console; export const commandLog = (message: string) => { - process.stdout.write(chalk.cyan(' • ') + message); + process.stdout.write(picocolors.cyan(' • ') + message); // Need `void` to be able to use this function in a then of a Promise return (errorMessage?: string | void, errorInfo?: string) => { if (errorMessage) { - process.stdout.write(`. ${chalk.red('✖')}\n`); - logger.error(`\n ${chalk.red(errorMessage)}`); + process.stdout.write(`. ${picocolors.red('✖')}\n`); + logger.error(`\n ${picocolors.red(errorMessage)}`); if (!errorInfo) { return; @@ -17,13 +17,13 @@ export const commandLog = (message: string) => { const newErrorInfo = errorInfo .split('\n') - .map((line) => ` ${chalk.dim(line)}`) + .map((line) => ` ${picocolors.dim(line)}`) .join('\n'); logger.error(`${newErrorInfo}\n`); return; } - process.stdout.write(`. ${chalk.green('✓')}\n`); + process.stdout.write(`. ${picocolors.green('✓')}\n`); }; }; @@ -56,7 +56,7 @@ export function codeLog(codeLines: string[], leftPadAmount?: number) { .map((line) => { const rightPadAmount = maxLength - line.length; let newLine = line + getChars(' ', rightPadAmount); - newLine = getChars(' ', leftPadAmount || 2) + chalk.inverse(` ${newLine} `); + newLine = getChars(' ', leftPadAmount || 2) + picocolors.inverse(` ${newLine} `); return newLine; }) .join('\n'); diff --git a/code/lib/core-common/src/utils/notify-telemetry.ts b/code/lib/core-common/src/utils/notify-telemetry.ts index 53b291b4b6a8..38703a3f09fe 100644 --- a/code/lib/core-common/src/utils/notify-telemetry.ts +++ b/code/lib/core-common/src/utils/notify-telemetry.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { cache } from './cache'; const TELEMETRY_KEY_NOTIFY_DATE = 'telemetry-notification-date'; @@ -18,14 +18,14 @@ export const notifyTelemetry = async () => { cache.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now().toString()); logger.log( - `${chalk.magenta.bold( - 'Attention' + `${picocolors.magenta( + picocolors.bold('Attention') )}: Storybook now collects completely anonymous telemetry regarding usage.` ); logger.log(`This information is used to shape Storybook's roadmap and prioritize features.`); logger.log( `You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:` ); - logger.log(chalk.cyan('https://storybook.js.org/telemetry')); + logger.log(picocolors.cyan('https://storybook.js.org/telemetry')); logger.log(); }; diff --git a/code/lib/core-events/package.json b/code/lib/core-events/package.json index 24fefcf9b258..0caf1250bbd1 100644 --- a/code/lib/core-events/package.json +++ b/code/lib/core-events/package.json @@ -82,7 +82,7 @@ "ts-dedent": "^2.0.0" }, "devDependencies": { - "chalk": "^4.1.0", + "picocolors": "^1.0.1", "typescript": "^5.3.2" }, "publishConfig": { diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index e6719945d3f6..7a0cd12522a3 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -1,4 +1,4 @@ -import { bold, gray, grey, white, yellow, underline } from 'chalk'; +import { bold, gray, white, yellow, underline, cyan } from 'picocolors'; import dedent from 'ts-dedent'; import { StorybookError } from './storybook-error'; @@ -421,11 +421,11 @@ export class MainFileESMOnlyImportError extends StorybookError { if (this.data.line) { message.push( white( - `In your ${yellow(this.data.location)} file, line ${bold.cyan( - this.data.num + `In your ${yellow(this.data.location)} file, line ${bold( + cyan(this.data.num) )} threw an error:` ), - grey(this.data.line) + gray(this.data.line) ); } diff --git a/code/lib/core-server/package.json b/code/lib/core-server/package.json index ae1462790348..222f42b04b22 100644 --- a/code/lib/core-server/package.json +++ b/code/lib/core-server/package.json @@ -79,7 +79,6 @@ "@types/pretty-hrtime": "^1.0.0", "@types/semver": "^7.3.4", "better-opn": "^3.0.2", - "chalk": "^4.1.0", "cli-table3": "^0.6.1", "compression": "^1.7.4", "detect-port": "^1.3.0", @@ -89,6 +88,7 @@ "globby": "^14.0.1", "lodash": "^4.17.21", "open": "^8.4.0", + "picocolors": "^1.0.1", "pretty-hrtime": "^1.0.3", "prompts": "^2.4.0", "read-pkg-up": "^7.0.1", diff --git a/code/lib/core-server/src/build-static.ts b/code/lib/core-server/src/build-static.ts index f1f842eaea28..fb945e98bc9b 100644 --- a/code/lib/core-server/src/build-static.ts +++ b/code/lib/core-server/src/build-static.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { copy, emptyDir, ensureDir } from 'fs-extra'; import { dirname, join, relative, resolve } from 'path'; import { global } from '@storybook/global'; @@ -36,7 +36,9 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption options.outputDir = resolve(options.outputDir); options.configDir = resolve(options.configDir); - logger.info(chalk`=> Cleaning outputDir: {cyan ${relative(process.cwd(), options.outputDir)}}`); + logger.info( + `=> Cleaning outputDir: ${picocolors.cyan(relative(process.cwd(), options.outputDir))}` + ); if (options.outputDir === '/') { throw new Error("Won't remove directory '/'. Check your outputDir!"); } diff --git a/code/lib/core-server/src/utils/StoryIndexGenerator.ts b/code/lib/core-server/src/utils/StoryIndexGenerator.ts index 487447d18f4f..9c9565545911 100644 --- a/code/lib/core-server/src/utils/StoryIndexGenerator.ts +++ b/code/lib/core-server/src/utils/StoryIndexGenerator.ts @@ -1,5 +1,5 @@ import path from 'path'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import fs from 'fs-extra'; import slash from 'slash'; import invariant from 'tiny-invariant'; @@ -131,7 +131,7 @@ export class StoryIndexGenerator { if (files.length === 0) { once.warn( - `No story files found for the specified pattern: ${chalk.blue( + `No story files found for the specified pattern: ${picocolors.blue( path.join(specifier.directory, specifier.files) )}` ); @@ -495,7 +495,7 @@ export class StoryIndexGenerator { } catch (err) { if (err && (err as { source: any }).source?.match(/mdast-util-mdx-jsx/g)) { logger.warn( - `💡 This seems to be an MDX2 syntax error. Please refer to the MDX section in the following resource for assistance on how to fix this: ${chalk.yellow( + `💡 This seems to be an MDX2 syntax error. Please refer to the MDX section in the following resource for assistance on how to fix this: ${picocolors.yellow( 'https://storybook.js.org/migration-guides/7.0' )}` ); diff --git a/code/lib/core-server/src/utils/copy-all-static-files.ts b/code/lib/core-server/src/utils/copy-all-static-files.ts index 5b0fb5227353..d21b395ce772 100644 --- a/code/lib/core-server/src/utils/copy-all-static-files.ts +++ b/code/lib/core-server/src/utils/copy-all-static-files.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import fs from 'fs-extra'; import { join, relative } from 'path'; import { logger } from '@storybook/node-logger'; @@ -16,9 +16,9 @@ export async function copyAllStaticFiles(staticDirs: any[] | undefined, outputDi // we copy prebuild static files from node_modules/@storybook/manager & preview if (!staticDir.includes('node_modules')) { logger.info( - chalk`=> Copying static files: {cyan ${print(staticDir)}} => {cyan ${print( - targetDir - )}}` + `=> Copying static files: ${picocolors.cyan(print(staticDir))} => ${picocolors.cyan( + print(targetDir) + )}` ); } @@ -61,7 +61,9 @@ export async function copyAllStaticFilesRelativeToMain( const skipPaths = ['index.html', 'iframe.html'].map((f) => join(targetPath, f)); if (!from.includes('node_modules')) { logger.info( - chalk`=> Copying static files: {cyan ${print(from)}} at {cyan ${print(targetPath)}}` + `=> Copying static files: ${picocolors.cyan(print(from))} at ${picocolors.cyan( + print(targetPath) + )}` ); } await fs.copy(from, targetPath, { diff --git a/code/lib/core-server/src/utils/output-startup-information.ts b/code/lib/core-server/src/utils/output-startup-information.ts index bc4af06174ca..12c736331d52 100644 --- a/code/lib/core-server/src/utils/output-startup-information.ts +++ b/code/lib/core-server/src/utils/output-startup-information.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { colors } from '@storybook/node-logger'; import boxen from 'boxen'; import { dedent } from 'ts-dedent'; @@ -47,13 +47,13 @@ export function outputStartupInformation(options: { }); serveMessage.push( - ['Local:', chalk.cyan(address)], - ['On your network:', chalk.cyan(networkAddress)] + ['Local:', picocolors.cyan(address)], + ['On your network:', picocolors.cyan(networkAddress)] ); const timeStatement = [ - managerTotalTime && `${chalk.underline(prettyTime(managerTotalTime))} for manager`, - previewTotalTime && `${chalk.underline(prettyTime(previewTotalTime))} for preview`, + managerTotalTime && `${picocolors.underline(prettyTime(managerTotalTime))} for manager`, + previewTotalTime && `${picocolors.underline(prettyTime(previewTotalTime))} for preview`, ] .filter(Boolean) .join(' and '); @@ -61,8 +61,10 @@ export function outputStartupInformation(options: { console.log( boxen( dedent` - ${colors.green(`Storybook ${chalk.bold(version)} for ${chalk.bold(name)} started`)} - ${chalk.gray(timeStatement)} + ${colors.green( + `Storybook ${picocolors.bold(version)} for ${picocolors.bold(name)} started` + )} + ${picocolors.gray(timeStatement)} ${serveMessage.toString()}${updateMessage ? `\n\n${updateMessage}` : ''} `, diff --git a/code/lib/core-server/src/utils/output-stats.ts b/code/lib/core-server/src/utils/output-stats.ts index dd560c661bb5..907e8ae2e76a 100644 --- a/code/lib/core-server/src/utils/output-stats.ts +++ b/code/lib/core-server/src/utils/output-stats.ts @@ -1,18 +1,18 @@ import { stringifyStream } from '@discoveryjs/json-ext'; import { logger } from '@storybook/node-logger'; import type { Stats } from '@storybook/types'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import fs from 'fs-extra'; import path from 'path'; export async function outputStats(directory: string, previewStats?: any, managerStats?: any) { if (previewStats) { const filePath = await writeStats(directory, 'preview', previewStats as Stats); - logger.info(`=> preview stats written to ${chalk.cyan(filePath)}`); + logger.info(`=> preview stats written to ${picocolors.cyan(filePath)}`); } if (managerStats) { const filePath = await writeStats(directory, 'manager', managerStats as Stats); - logger.info(`=> manager stats written to ${chalk.cyan(filePath)}`); + logger.info(`=> manager stats written to ${picocolors.cyan(filePath)}`); } } diff --git a/code/lib/core-server/src/utils/server-statics.ts b/code/lib/core-server/src/utils/server-statics.ts index 2a0b93e1ca41..47dff83e0ca9 100644 --- a/code/lib/core-server/src/utils/server-statics.ts +++ b/code/lib/core-server/src/utils/server-statics.ts @@ -1,7 +1,7 @@ import { logger } from '@storybook/node-logger'; import type { Options } from '@storybook/types'; import { getDirectoryFromWorkingDir } from '@storybook/core-common'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import type { Router } from 'express'; import express from 'express'; import { pathExists } from 'fs-extra'; @@ -34,7 +34,9 @@ export async function useStatics(router: Router, options: Options) { // Don't log for the internal static dir if (!targetEndpoint.startsWith('/sb-')) { logger.info( - chalk`=> Serving static files from {cyan ${staticDir}} at {cyan ${targetEndpoint}}` + `=> Serving static files from ${picocolors.cyan(staticDir)} at ${picocolors.cyan( + targetEndpoint + )}` ); } @@ -67,8 +69,8 @@ export const parseStaticDir = async (arg: string) => { if (!(await pathExists(staticPath))) { throw new Error( - dedent(chalk` - Failed to load static files, no such directory: {cyan ${staticPath}} + dedent(` + Failed to load static files, no such directory: ${picocolors.cyan(staticPath)} Make sure this directory exists. `) ); diff --git a/code/lib/core-server/src/utils/update-check.ts b/code/lib/core-server/src/utils/update-check.ts index bb387e6e75f2..076127c52983 100644 --- a/code/lib/core-server/src/utils/update-check.ts +++ b/code/lib/core-server/src/utils/update-check.ts @@ -1,5 +1,5 @@ import fetch from 'node-fetch'; -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { colors } from '@storybook/node-logger'; import semver from 'semver'; import { dedent } from 'ts-dedent'; @@ -43,13 +43,13 @@ export function createUpdateMessage(updateInfo: VersionCheck, version: string): updateInfo.success && semver.lt(version, updateInfo.data.latest.version) ? dedent` ${colors.orange( - `A new version (${chalk.bold(updateInfo.data.latest.version)}) is available!` + `A new version (${picocolors.bold(updateInfo.data.latest.version)}) is available!` )} - ${chalk.gray('Upgrade now:')} ${colors.green(upgradeCommand)} + ${picocolors.gray('Upgrade now:')} ${colors.green(upgradeCommand)} - ${chalk.gray('Read full changelog:')} ${chalk.gray.underline( - 'https://github.com/storybookjs/storybook/blob/main/CHANGELOG.md' + ${picocolors.gray('Read full changelog:')} ${picocolors.gray( + picocolors.underline('https://github.com/storybookjs/storybook/blob/main/CHANGELOG.md') )} ` : ''; diff --git a/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts b/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts index fa336373a8a4..af87f3d92c93 100644 --- a/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts +++ b/code/lib/core-server/src/utils/warnWhenUsingArgTypesRegex.ts @@ -5,7 +5,7 @@ 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'; +import picocolors from 'picocolors'; export async function warnWhenUsingArgTypesRegex( packageJson: PackageJson, @@ -33,17 +33,17 @@ export async function warnWhenUsingArgTypesRegex( Identifier: (path) => { if (path.node.name === 'argTypesRegex') { const message = dedent` - ${chalk.bold('Attention')}: We've detected that you're using ${chalk.cyan( + ${picocolors.bold('Attention')}: We've detected that you're using ${picocolors.cyan( 'actions.argTypesRegex' )} together with the visual test addon: ${path.buildCodeFrameError(previewConfig).message} - We recommend removing the ${chalk.cyan( + We recommend removing the ${picocolors.cyan( 'argTypesRegex' - )} and assigning explicit action with the ${chalk.cyan( + )} and assigning explicit action with the ${picocolors.cyan( 'fn' - )} function from ${chalk.cyan('@storybook/test')} instead: + )} function from ${picocolors.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. diff --git a/code/lib/telemetry/package.json b/code/lib/telemetry/package.json index c98d7fc7da3d..7a936749163f 100644 --- a/code/lib/telemetry/package.json +++ b/code/lib/telemetry/package.json @@ -47,10 +47,10 @@ "@storybook/client-logger": "workspace:*", "@storybook/core-common": "workspace:*", "@storybook/csf-tools": "workspace:*", - "chalk": "^4.1.0", "detect-package-manager": "^2.0.1", "fetch-retry": "^5.0.2", "fs-extra": "^11.1.0", + "picocolors": "^1.0.1", "read-pkg-up": "^7.0.1" }, "devDependencies": { diff --git a/code/lib/telemetry/src/notify.ts b/code/lib/telemetry/src/notify.ts index dc57c7ff0003..856617a2e923 100644 --- a/code/lib/telemetry/src/notify.ts +++ b/code/lib/telemetry/src/notify.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import picocolors from 'picocolors'; import { cache } from '@storybook/core-common'; const TELEMETRY_KEY_NOTIFY_DATE = 'telemetry-notification-date'; @@ -19,14 +19,14 @@ export const notify = async () => { logger.log(); logger.log( - `${chalk.magenta.bold( - 'attention' + `${picocolors.magenta( + picocolors.bold('attention') )} => Storybook now collects completely anonymous telemetry regarding usage.` ); logger.log(`This information is used to shape Storybook's roadmap and prioritize features.`); logger.log( `You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:` ); - logger.log(chalk.cyan('https://storybook.js.org/telemetry')); + logger.log(picocolors.cyan('https://storybook.js.org/telemetry')); logger.log(); }; diff --git a/code/yarn.lock b/code/yarn.lock index da5523a1023d..3f471ba3d000 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5757,7 +5757,6 @@ __metadata: "@yarnpkg/fslib": "npm:2.10.3" "@yarnpkg/libzip": "npm:2.3.0" boxen: "npm:^7.1.1" - chalk: "npm:^4.1.0" commander: "npm:^6.2.1" cross-spawn: "npm:^7.0.3" detect-indent: "npm:^6.1.0" @@ -5771,6 +5770,7 @@ __metadata: jscodeshift: "npm:^0.15.1" leven: "npm:^3.1.0" ora: "npm:^5.4.1" + picocolors: "npm:^1.0.1" prettier: "npm:^3.1.1" prompts: "npm:^2.4.0" read-pkg-up: "npm:^7.0.1" @@ -5884,7 +5884,6 @@ __metadata: "@types/pretty-hrtime": "npm:^1.0.0" "@yarnpkg/fslib": "npm:2.10.3" "@yarnpkg/libzip": "npm:2.3.0" - chalk: "npm:^4.1.0" cross-spawn: "npm:^7.0.3" esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0" esbuild-register: "npm:^3.5.0" @@ -5898,6 +5897,7 @@ __metadata: lazy-universal-dotenv: "npm:^4.0.0" mock-fs: "npm:^5.2.0" node-fetch: "npm:^2.0.0" + picocolors: "npm:^1.0.1" picomatch: "npm:^2.3.0" pkg-dir: "npm:^5.0.0" prettier-fallback: "npm:prettier@^3" @@ -5925,7 +5925,7 @@ __metadata: resolution: "@storybook/core-events@workspace:lib/core-events" dependencies: "@storybook/csf": "npm:^0.1.8" - chalk: "npm:^4.1.0" + picocolors: "npm:^1.0.1" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" languageName: unknown @@ -5965,7 +5965,6 @@ __metadata: better-opn: "npm:^3.0.2" boxen: "npm:^7.1.1" camelcase: "npm:^8.0.0" - chalk: "npm:^4.1.0" cli-table3: "npm:^0.6.1" compression: "npm:^1.7.4" detect-port: "npm:^1.3.0" @@ -5976,6 +5975,7 @@ __metadata: lodash: "npm:^4.17.21" node-fetch: "npm:^3.3.1" open: "npm:^8.4.0" + picocolors: "npm:^1.0.1" pretty-hrtime: "npm:^1.0.3" prompts: "npm:^2.4.0" read-pkg-up: "npm:^7.0.1" @@ -7023,12 +7023,12 @@ __metadata: "@storybook/client-logger": "workspace:*" "@storybook/core-common": "workspace:*" "@storybook/csf-tools": "workspace:*" - chalk: "npm:^4.1.0" detect-package-manager: "npm:^2.0.1" fetch-retry: "npm:^5.0.2" fs-extra: "npm:^11.1.0" nanoid: "npm:^4.0.2" node-fetch: "npm:^3.3.1" + picocolors: "npm:^1.0.1" read-pkg-up: "npm:^7.0.1" typescript: "npm:^5.3.2" languageName: unknown @@ -22479,6 +22479,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.0.1": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 + languageName: node + linkType: hard + "picomatch@npm:4.0.1": version: 4.0.1 resolution: "picomatch@npm:4.0.1" From 050044f47c6e4cf0a9d324784e054a3f74b282eb Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sun, 23 Jun 2024 01:08:35 +0100 Subject: [PATCH 002/213] feat: migrate from qs Moves the `manager-api`, `preview-api` and `ui/amanger` to use `picoquery` instead of `qs` - a much smaller and faster alternative. Note that we still have `qs` in our overall monorepo tree, but that can be tackled in a follow-up PR. --- code/lib/manager-api/package.json | 1 - code/lib/preview-api/package.json | 3 +- .../src/modules/preview-web/SelectionStore.ts | 2 +- .../src/modules/preview-web/UrlStore.test.ts | 4 +-- .../src/modules/preview-web/UrlStore.ts | 36 ++++++++++--------- code/lib/router/package.json | 2 +- code/ui/manager/package.json | 2 +- .../preview/utils/stringifyQueryParams.tsx | 4 +-- code/yarn.lock | 28 +++++++++++---- 9 files changed, 49 insertions(+), 33 deletions(-) diff --git a/code/lib/manager-api/package.json b/code/lib/manager-api/package.json index 49270d11882d..5868ec58a2a9 100644 --- a/code/lib/manager-api/package.json +++ b/code/lib/manager-api/package.json @@ -62,7 +62,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.167", - "@types/qs": "^6", "@types/semver": "^7.3.4", "flush-promises": "^1.0.2", "react": "^18.2.0", diff --git a/code/lib/preview-api/package.json b/code/lib/preview-api/package.json index 75415839d0d2..27d13a212ad8 100644 --- a/code/lib/preview-api/package.json +++ b/code/lib/preview-api/package.json @@ -50,11 +50,10 @@ "@storybook/csf": "^0.1.8", "@storybook/global": "^5.0.0", "@storybook/types": "workspace:*", - "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", "memoizerific": "^1.11.3", - "qs": "^6.10.0", + "picoquery": "^1.0.0", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" diff --git a/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts b/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts index 4faa9cb1089f..4b11ced29088 100644 --- a/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts @@ -20,5 +20,5 @@ export interface SelectionStore { setSelection(selection: Selection): void; - setQueryParams(queryParams: qs.ParsedQs): void; + setQueryParams(queryParams: Record): void; } diff --git a/code/lib/preview-api/src/modules/preview-web/UrlStore.test.ts b/code/lib/preview-api/src/modules/preview-web/UrlStore.test.ts index cc6e57171968..ca1472e9ff42 100644 --- a/code/lib/preview-api/src/modules/preview-web/UrlStore.test.ts +++ b/code/lib/preview-api/src/modules/preview-web/UrlStore.test.ts @@ -39,7 +39,7 @@ describe('UrlStore', () => { ); }); it('should replace legacy parameters but preserve others', () => { - document.location.search = 'foo=bar&selectedStory=selStory&selectedKind=selKind'; + document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind'; setPath({ storyId: 'story--id', viewMode: 'story' }); expect(history.replaceState).toHaveBeenCalledWith( {}, @@ -48,7 +48,7 @@ describe('UrlStore', () => { ); }); it('should ignore + keep hashes', () => { - document.location.search = 'foo=bar&selectedStory=selStory&selectedKind=selKind'; + document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind'; document.location.hash = '#foobar'; setPath({ storyId: 'story--id', viewMode: 'story' }); expect(history.replaceState).toHaveBeenCalledWith( diff --git a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts index b7890cc3687a..5b211235ef99 100644 --- a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts @@ -1,5 +1,5 @@ import { global } from '@storybook/global'; -import qs from 'qs'; +import * as pq from 'picoquery'; import type { ViewMode } from '@storybook/types'; import { parseArgsParam } from './parseArgsParam'; @@ -20,19 +20,20 @@ const getQueryString = ({ extraParams, }: { selection?: Selection; - extraParams?: qs.ParsedQs; + extraParams?: Record; }) => { - const search = typeof document !== 'undefined' ? document.location.search : ''; - const { path, selectedKind, selectedStory, ...rest } = qs.parse(search, { - ignoreQueryPrefix: true, - }); - return qs.stringify( - { + const search = + typeof document !== 'undefined' && document.location.search + ? document.location.search.slice(1) + : ''; + const { path, selectedKind, selectedStory, ...rest } = pq.parse(search); + return ( + '?' + + pq.stringify({ ...rest, ...extraParams, ...(selection && { id: selection.storyId, viewMode: selection.viewMode }), - }, - { encode: false, addQueryPrefix: true } + }) ); }; @@ -45,10 +46,10 @@ export const setPath = (selection?: Selection) => { }; type ValueOf = T[keyof T]; -const isObject = (val: Record) => +const isObject = (val: Record): val is object => val != null && typeof val === 'object' && Array.isArray(val) === false; -const getFirstString = (v: ValueOf): string | void => { +const getFirstString = (v: ValueOf>): string | void => { if (v === undefined) { return undefined; } @@ -58,15 +59,18 @@ const getFirstString = (v: ValueOf): string | void => { if (Array.isArray(v)) { return getFirstString(v[0]); } - if (isObject(v)) { - return getFirstString(Object.values(v).filter(Boolean) as string[]); + if (isObject(v as Record)) { + return getFirstString( + Object.values(v as Record).filter(Boolean) as string[] + ); } return undefined; }; export const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => { if (typeof document !== 'undefined') { - const query = qs.parse(document.location.search, { ignoreQueryPrefix: true }); + const queryStr = document.location.search ? document.location.search.slice(1) : ''; + const query = pq.parse(queryStr); const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined; const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined; @@ -100,7 +104,7 @@ export class UrlStore implements SelectionStore { setPath(this.selection); } - setQueryParams(queryParams: qs.ParsedQs) { + setQueryParams(queryParams: Record) { const query = getQueryString({ extraParams: queryParams }); const { hash = '' } = document.location; history.replaceState({}, '', `${document.location.pathname}${query}${hash}`); diff --git a/code/lib/router/package.json b/code/lib/router/package.json index c9a4b1bf2888..312a61f703fa 100644 --- a/code/lib/router/package.json +++ b/code/lib/router/package.json @@ -51,7 +51,7 @@ "dependencies": { "@storybook/client-logger": "workspace:*", "memoizerific": "^1.11.3", - "qs": "^6.10.0" + "picoquery": "^1.0.0" }, "devDependencies": { "@storybook/global": "^5.0.0", diff --git a/code/ui/manager/package.json b/code/ui/manager/package.json index a976dab95595..62cbcf87ac97 100644 --- a/code/ui/manager/package.json +++ b/code/ui/manager/package.json @@ -97,8 +97,8 @@ "lodash": "^4.17.21", "markdown-to-jsx": "^7.4.5", "memoizerific": "^1.11.3", + "picoquery": "^1.0.0", "polished": "^4.2.2", - "qs": "^6.10.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-draggable": "^4.4.5", diff --git a/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx b/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx index 4175503808bb..f98f5aed2066 100644 --- a/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx +++ b/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx @@ -1,4 +1,4 @@ -import qs from 'qs'; +import { stringify } from 'picoquery'; export const stringifyQueryParams = (queryParams: Record) => - qs.stringify(queryParams, { addQueryPrefix: true, encode: false }).replace(/^\?/, '&'); + '&' + stringify(queryParams); diff --git a/code/yarn.lock b/code/yarn.lock index da5523a1023d..6eedbb821c1e 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6232,7 +6232,6 @@ __metadata: "@storybook/theming": "workspace:*" "@storybook/types": "workspace:*" "@types/lodash": "npm:^4.14.167" - "@types/qs": "npm:^6" "@types/semver": "npm:^7.3.4" dequal: "npm:^2.0.2" flush-promises: "npm:^1.0.2" @@ -6277,8 +6276,8 @@ __metadata: lodash: "npm:^4.17.21" markdown-to-jsx: "npm:^7.4.5" memoizerific: "npm:^1.11.3" + picoquery: "npm:^1.0.0" polished: "npm:^4.2.2" - qs: "npm:^6.10.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" react-draggable: "npm:^4.4.5" @@ -6568,12 +6567,11 @@ __metadata: "@storybook/csf": "npm:^0.1.8" "@storybook/global": "npm:^5.0.0" "@storybook/types": "workspace:*" - "@types/qs": "npm:^6.9.5" ansi-to-html: "npm:^0.6.11" dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" + picoquery: "npm:^1.0.0" slash: "npm:^5.0.0" tiny-invariant: "npm:^1.3.1" ts-dedent: "npm:^2.0.0" @@ -6877,7 +6875,7 @@ __metadata: dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" + picoquery: "npm:^1.0.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" react-router-dom: "npm:6.0.2" @@ -8191,7 +8189,7 @@ __metadata: languageName: node linkType: hard -"@types/qs@npm:*, @types/qs@npm:^6, @types/qs@npm:^6.9.5": +"@types/qs@npm:*": version: 6.9.10 resolution: "@types/qs@npm:6.9.10" checksum: 10c0/6be12e5f062d1b41eb037d59bf9cb65bc9410cedd5e6da832dfd7c8e2b3f4c91e81c9b90b51811140770e5052c6c4e8361181bd9437ddcd4515dc128b7c00353 @@ -14953,6 +14951,13 @@ __metadata: languageName: node linkType: hard +"fast-decode-uri-component@npm:^1.0.1": + version: 1.0.1 + resolution: "fast-decode-uri-component@npm:1.0.1" + checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -22493,6 +22498,15 @@ __metadata: languageName: node linkType: hard +"picoquery@npm:^1.0.0": + version: 1.0.0 + resolution: "picoquery@npm:1.0.0" + dependencies: + fast-decode-uri-component: "npm:^1.0.1" + checksum: 10c0/d5d89ca0ce6f150db02175b072eb881460bb3dc2a7a50d55be1b4f05d953136efc3815504d93045c8ba014c318f4a4e1f523b1a960db9db0bde357bca28aacde + languageName: node + linkType: hard + "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -23340,7 +23354,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.0, qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0": +"qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0": version: 6.11.2 resolution: "qs@npm:6.11.2" dependencies: From 2b8156a716732d8f74fe00f36eb0e42479df073b Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 23 Jun 2024 21:52:36 +0800 Subject: [PATCH 003/213] Use destructured imports --- code/lib/preview-api/src/modules/preview-web/UrlStore.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts index 5b211235ef99..b5089b3fd33a 100644 --- a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts @@ -1,5 +1,5 @@ import { global } from '@storybook/global'; -import * as pq from 'picoquery'; +import { parse, stringify } from 'picoquery'; import type { ViewMode } from '@storybook/types'; import { parseArgsParam } from './parseArgsParam'; @@ -26,10 +26,10 @@ const getQueryString = ({ typeof document !== 'undefined' && document.location.search ? document.location.search.slice(1) : ''; - const { path, selectedKind, selectedStory, ...rest } = pq.parse(search); + const { path, selectedKind, selectedStory, ...rest } = parse(search); return ( '?' + - pq.stringify({ + stringify({ ...rest, ...extraParams, ...(selection && { id: selection.storyId, viewMode: selection.viewMode }), @@ -70,7 +70,7 @@ const getFirstString = (v: ValueOf>): string | void export const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => { if (typeof document !== 'undefined') { const queryStr = document.location.search ? document.location.search.slice(1) : ''; - const query = pq.parse(queryStr); + const query = parse(queryStr); const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined; const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined; From 23f28dcd799405167168a1b36e7a19acc8a89b2c Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 23 Jun 2024 22:26:34 +0800 Subject: [PATCH 004/213] qs => picoquery --- code/lib/preview-api/src/modules/preview-web/WebView.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/code/lib/preview-api/src/modules/preview-web/WebView.ts b/code/lib/preview-api/src/modules/preview-web/WebView.ts index 82c6a294bf05..3f317701d087 100644 --- a/code/lib/preview-api/src/modules/preview-web/WebView.ts +++ b/code/lib/preview-api/src/modules/preview-web/WebView.ts @@ -2,7 +2,7 @@ import { global } from '@storybook/global'; import { logger } from '@storybook/client-logger'; import AnsiToHtml from 'ansi-to-html'; import { dedent } from 'ts-dedent'; -import qs from 'qs'; +import { parse } from 'picoquery'; import type { PreparedStory } from '@storybook/types'; import type { View } from './View'; @@ -48,9 +48,7 @@ export class WebView implements View { // Special code for testing situations if (typeof document !== 'undefined') { // eslint-disable-next-line @typescript-eslint/naming-convention - const { __SPECIAL_TEST_PARAMETER__ } = qs.parse(document.location.search, { - ignoreQueryPrefix: true, - }); + const { __SPECIAL_TEST_PARAMETER__ } = parse(document.location.search); switch (__SPECIAL_TEST_PARAMETER__) { case 'preparing-story': { this.showPreparingStory(); From 3c04a1e524069de068226faf93a044fb31ce3fbc Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Mon, 24 Jun 2024 18:03:24 +0100 Subject: [PATCH 005/213] feat: use js syntax in query strings Uses the `foo.bar[0]` syntax picoquery provides, rather than dot-syntax (`foo.bar.0`). --- code/lib/preview-api/package.json | 2 +- code/lib/router/package.json | 2 +- code/lib/router/src/utils.test.ts | 26 ++++++++++++------------- code/lib/router/src/utils.ts | 32 +++++++++++++++++-------------- code/ui/manager/package.json | 2 +- code/yarn.lock | 14 +++++++------- 6 files changed, 41 insertions(+), 37 deletions(-) diff --git a/code/lib/preview-api/package.json b/code/lib/preview-api/package.json index 27d13a212ad8..17e2aace0f67 100644 --- a/code/lib/preview-api/package.json +++ b/code/lib/preview-api/package.json @@ -53,7 +53,7 @@ "dequal": "^2.0.2", "lodash": "^4.17.21", "memoizerific": "^1.11.3", - "picoquery": "^1.0.0", + "picoquery": "^1.3.0", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" diff --git a/code/lib/router/package.json b/code/lib/router/package.json index 312a61f703fa..663deceab519 100644 --- a/code/lib/router/package.json +++ b/code/lib/router/package.json @@ -51,7 +51,7 @@ "dependencies": { "@storybook/client-logger": "workspace:*", "memoizerific": "^1.11.3", - "picoquery": "^1.0.0" + "picoquery": "^1.3.0" }, "devDependencies": { "@storybook/global": "^5.0.0", diff --git a/code/lib/router/src/utils.test.ts b/code/lib/router/src/utils.test.ts index e12d257aa316..5eb0571b8f3a 100644 --- a/code/lib/router/src/utils.test.ts +++ b/code/lib/router/src/utils.test.ts @@ -137,12 +137,12 @@ describe('buildArgsParam', () => { it('builds arrays', () => { const param = buildArgsParam({}, { arr: ['1', '2', '3'] }); - expect(param).toEqual('arr[0]:1;arr[1]:2;arr[2]:3'); + expect(param).toEqual('arr%5B0%5D:1;arr%5B1%5D:2;arr%5B2%5D:3'); }); it('builds sparse arrays', () => { const param = buildArgsParam({}, { arr: ['1', , '3'] }); - expect(param).toEqual('arr[0]:1;arr[2]:3'); + expect(param).toEqual('arr%5B0%5D:1;arr%5B2%5D:3'); }); it('builds simple objects', () => { @@ -157,22 +157,22 @@ describe('buildArgsParam', () => { it('builds arrays in objects', () => { const param = buildArgsParam({}, { obj: { foo: ['1', , '3'] } }); - expect(param).toEqual('obj.foo[0]:1;obj.foo[2]:3'); + expect(param).toEqual('obj.foo%5B0%5D:1;obj.foo%5B2%5D:3'); }); it('builds single object in array', () => { const param = buildArgsParam({}, { arr: [{ one: '1', two: '2' }] }); - expect(param).toEqual('arr[0].one:1;arr[0].two:2'); + expect(param).toEqual('arr%5B0%5D.one:1;arr%5B0%5D.two:2'); }); it('builds multiple objects in array', () => { const param = buildArgsParam({}, { arr: [{ one: '1' }, { two: '2' }] }); - expect(param).toEqual('arr[0].one:1;arr[1].two:2'); + expect(param).toEqual('arr%5B0%5D.one:1;arr%5B1%5D.two:2'); }); it('builds nested object in array', () => { const param = buildArgsParam({}, { arr: [{ foo: { bar: 'val' } }] }); - expect(param).toEqual('arr[0].foo.bar:val'); + expect(param).toEqual('arr%5B0%5D.foo.bar:val'); }); it('encodes space as +', () => { @@ -187,7 +187,7 @@ describe('buildArgsParam', () => { it('encodes nested null values as !null', () => { const param = buildArgsParam({}, { foo: { bar: [{ key: null }], baz: null } }); - expect(param).toEqual('foo.bar[0].key:!null;foo.baz:!null'); + expect(param).toEqual('foo.bar%5B0%5D.key:!null;foo.baz:!null'); }); it('encodes hex color values as !hex(value)', () => { @@ -197,17 +197,17 @@ describe('buildArgsParam', () => { it('encodes rgba color values by prefixing and compacting', () => { const param = buildArgsParam({}, { rgb: 'rgb(255, 71, 133)', rgba: 'rgba(255, 71, 133, 0.5)' }); - expect(param).toEqual('rgb:!rgb(255,71,133);rgba:!rgba(255,71,133,0.5)'); + expect(param).toEqual('rgb:!rgb(255%2C71%2C133);rgba:!rgba(255%2C71%2C133%2C0.5)'); }); it('encodes hsla color values by prefixing and compacting', () => { const param = buildArgsParam({}, { hsl: 'hsl(45, 99%, 70%)', hsla: 'hsla(45, 99%, 70%, 0.5)' }); - expect(param).toEqual('hsl:!hsl(45,99,70);hsla:!hsla(45,99,70,0.5)'); + expect(param).toEqual('hsl:!hsl(45%2C99%2C70);hsla:!hsla(45%2C99%2C70%2C0.5)'); }); it('encodes Date objects as !date(ISO string)', () => { const param = buildArgsParam({}, { key: new Date('2001-02-03T04:05:06.789Z') }); - expect(param).toEqual('key:!date(2001-02-03T04:05:06.789Z)'); + expect(param).toEqual('key:!date(2001-02-03T04%3A05%3A06.789Z)'); }); describe('with initial state', () => { @@ -223,7 +223,7 @@ describe('buildArgsParam', () => { it('sets !undefined for removed array values', () => { const param = buildArgsParam({ arr: [1] }, { arr: [] }); - expect(param).toEqual('arr[0]:!undefined'); + expect(param).toEqual('arr%5B0%5D:!undefined'); }); it('sets !undefined for removed object properties', () => { @@ -233,7 +233,7 @@ describe('buildArgsParam', () => { it('omits unchanged array values (yielding sparse arrays)', () => { const param = buildArgsParam({ arr: [1, 2, 3] }, { arr: [1, 3, 4] }); - expect(param).toEqual('arr[1]:3;arr[2]:4'); + expect(param).toEqual('arr%5B1%5D:3;arr%5B2%5D:4'); }); it('omits nested unchanged object properties and array values', () => { @@ -241,7 +241,7 @@ describe('buildArgsParam', () => { { obj: { nested: [{ one: 1 }, { two: 2 }] } }, { obj: { nested: [{ one: 1 }, { two: 2, three: 3 }] } } ); - expect(param).toEqual('obj.nested[1].three:3'); + expect(param).toEqual('obj.nested%5B1%5D.three:3'); }); }); }); diff --git a/code/lib/router/src/utils.ts b/code/lib/router/src/utils.ts index c7cefd89bad3..596188609e0c 100644 --- a/code/lib/router/src/utils.ts +++ b/code/lib/router/src/utils.ts @@ -2,8 +2,8 @@ import { once } from '@storybook/client-logger'; import { dequal as deepEqual } from 'dequal'; import isPlainObject from 'lodash/isPlainObject.js'; import memoize from 'memoizerific'; -import type { IStringifyOptions } from 'qs'; -import qs from 'qs'; +import type { Options as QueryOptions } from 'picoquery'; +import { stringify, parse } from 'picoquery'; import { dedent } from 'ts-dedent'; export interface StoryData { @@ -105,6 +105,10 @@ const encodeSpecialValues = (value: unknown): any => { return `!${value}`; } + if (value instanceof Date) { + return `!date(${value.toISOString()})`; + } + if (Array.isArray(value)) return value.map(encodeSpecialValues); if (isPlainObject(value)) { return Object.entries(value as Record).reduce( @@ -115,12 +119,10 @@ const encodeSpecialValues = (value: unknown): any => { return value; }; -const QS_OPTIONS: IStringifyOptions = { - encode: false, // we handle URL encoding ourselves +const QS_OPTIONS: Partial = { delimiter: ';', // we don't actually create multiple query params - allowDots: true, // encode objects using dot notation: obj.key=val - format: 'RFC1738', // encode spaces using the + sign - serializeDate: (date: Date) => `!date(${date.toISOString()})`, + nesting: true, + nestingSyntax: 'js', // encode objects using dot notation: obj.key=val }; export const buildArgsParam = (initialArgs: Args | undefined, args: Args): string => { const update = deepDiff(initialArgs, args); @@ -136,9 +138,8 @@ export const buildArgsParam = (initialArgs: Args | undefined, args: Args): strin return acc; }, {} as Args); - return qs - .stringify(encodeSpecialValues(object), QS_OPTIONS) - .replace(/ /g, '+') + return stringify(encodeSpecialValues(object), QS_OPTIONS) + .replace(/%20/g, '+') .split(';') .map((part: string) => part.replace('=', ':')) .join(';'); @@ -149,11 +150,14 @@ interface Query { } export const queryFromString = memoize(1000)( - (s?: string): Query => (s !== undefined ? qs.parse(s, { ignoreQueryPrefix: true }) : {}) + (s?: string): Query => (s !== undefined ? parse(s) : {}) ); -export const queryFromLocation = (location: Partial) => queryFromString(location.search); -export const stringifyQuery = (query: Query) => - qs.stringify(query, { addQueryPrefix: true, encode: false }); +export const queryFromLocation = (location: Partial) => + queryFromString(location.search ? location.search.slice(1) : ''); +export const stringifyQuery = (query: Query) => { + const queryStr = stringify(query); + return queryStr ? '?' + queryStr : ''; +}; type Match = { path: string }; diff --git a/code/ui/manager/package.json b/code/ui/manager/package.json index 62cbcf87ac97..05a20747c5e9 100644 --- a/code/ui/manager/package.json +++ b/code/ui/manager/package.json @@ -97,7 +97,7 @@ "lodash": "^4.17.21", "markdown-to-jsx": "^7.4.5", "memoizerific": "^1.11.3", - "picoquery": "^1.0.0", + "picoquery": "^1.3.0", "polished": "^4.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/code/yarn.lock b/code/yarn.lock index 4ae5456b9ac5..c304fd27c3e9 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6276,7 +6276,7 @@ __metadata: lodash: "npm:^4.17.21" markdown-to-jsx: "npm:^7.4.5" memoizerific: "npm:^1.11.3" - picoquery: "npm:^1.0.0" + picoquery: "npm:^1.3.0" polished: "npm:^4.2.2" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" @@ -6571,7 +6571,7 @@ __metadata: dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - picoquery: "npm:^1.0.0" + picoquery: "npm:^1.3.0" slash: "npm:^5.0.0" tiny-invariant: "npm:^1.3.1" ts-dedent: "npm:^2.0.0" @@ -6875,7 +6875,7 @@ __metadata: dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - picoquery: "npm:^1.0.0" + picoquery: "npm:^1.3.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" react-router-dom: "npm:6.0.2" @@ -22481,12 +22481,12 @@ __metadata: languageName: node linkType: hard -"picoquery@npm:^1.0.0": - version: 1.0.0 - resolution: "picoquery@npm:1.0.0" +"picoquery@npm:^1.3.0": + version: 1.3.0 + resolution: "picoquery@npm:1.3.0" dependencies: fast-decode-uri-component: "npm:^1.0.1" - checksum: 10c0/d5d89ca0ce6f150db02175b072eb881460bb3dc2a7a50d55be1b4f05d953136efc3815504d93045c8ba014c318f4a4e1f523b1a960db9db0bde357bca28aacde + checksum: 10c0/7bbd692d3996caff8e19bb0590b925d673ec87bc3c005cce55610c64a7348129bfc6b4f47dcd578ebcf4ea12db958fb004439cf827b67741b927a17f32af00d4 languageName: node linkType: hard From 4474a040197def77a4f53cff86a3904a9197f75b Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:27:49 +0100 Subject: [PATCH 006/213] feat (preview-api): move to picoquery Moves the preview api to use picoquery. Note that tests will not pass yet. --- .../src/modules/preview-web/parseArgsParam.ts | 25 ++++++++----------- code/lib/router/src/utils.ts | 3 +++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/code/lib/preview-api/src/modules/preview-web/parseArgsParam.ts b/code/lib/preview-api/src/modules/preview-web/parseArgsParam.ts index 3212a95b3e96..2e618a82cfc7 100644 --- a/code/lib/preview-api/src/modules/preview-web/parseArgsParam.ts +++ b/code/lib/preview-api/src/modules/preview-web/parseArgsParam.ts @@ -1,4 +1,4 @@ -import qs from 'qs'; +import { parse, type Options } from 'picoquery'; import { dedent } from 'ts-dedent'; import type { Args } from '@storybook/types'; import { once } from '@storybook/client-logger'; @@ -30,17 +30,14 @@ const validateArgs = (key = '', value: unknown): boolean => { return false; }; -const QS_OPTIONS = { +const QS_OPTIONS: Partial = { delimiter: ';', // we're parsing a single query param - allowDots: true, // objects are encoded using dot notation - allowSparse: true, // arrays will be merged on top of their initial value - decoder( - str: string, - defaultDecoder: (str: string, decoder?: any, charset?: string) => string, - charset: string, - type: 'key' | 'value' - ) { - if (type === 'value' && str.startsWith('!')) { + nesting: true, + arrayRepeat: true, + arrayRepeatSyntax: 'bracket', + nestingSyntax: 'js', // objects are encoded using dot notation + valueDeserializer(str: string) { + if (str.startsWith('!')) { if (str === '!undefined') return undefined; if (str === '!null') return null; if (str === '!true') return true; @@ -59,13 +56,13 @@ const QS_OPTIONS = { : `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%)`; } } - if (type === 'value' && NUMBER_REGEXP.test(str)) return Number(str); - return defaultDecoder(str, defaultDecoder, charset); + if (NUMBER_REGEXP.test(str)) return Number(str); + return str; }, }; export const parseArgsParam = (argsString: string): Args => { const parts = argsString.split(';').map((part) => part.replace('=', '~').replace(':', '=')); - return Object.entries(qs.parse(parts.join(';'), QS_OPTIONS)).reduce((acc, [key, value]) => { + return Object.entries(parse(parts.join(';'), QS_OPTIONS)).reduce((acc, [key, value]) => { if (validateArgs(key, value)) return Object.assign(acc, { [key]: value }); once.warn(dedent` Omitted potentially unsafe URL args. diff --git a/code/lib/router/src/utils.ts b/code/lib/router/src/utils.ts index 596188609e0c..b7d1097e27e3 100644 --- a/code/lib/router/src/utils.ts +++ b/code/lib/router/src/utils.ts @@ -92,6 +92,9 @@ const validateArgs = (key = '', value: unknown): boolean => { return false; }; +// Note this isn't a picoquery serializer because pq will turn any object +// into a nested key internally. So we need to deal witth things like `Date` +// up front. const encodeSpecialValues = (value: unknown): any => { if (value === undefined) return '!undefined'; if (value === null) return '!null'; From fcce3bbb3882e820cb883064451e6bce28747d5c Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:31:44 +0100 Subject: [PATCH 007/213] fix: decode some known query string chars Decodes certain chars we want to keep in our URIs (e.g. `[`). --- .../src/modules/preview-web/UrlStore.ts | 21 ++++++--------- code/lib/router/src/utils.test.ts | 26 +++++++++---------- code/lib/router/src/utils.ts | 24 ++++++++++++++++- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts index b5089b3fd33a..72da8f23fe72 100644 --- a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts @@ -22,19 +22,14 @@ const getQueryString = ({ selection?: Selection; extraParams?: Record; }) => { - const search = - typeof document !== 'undefined' && document.location.search - ? document.location.search.slice(1) - : ''; + const search = document?.location.search.slice(1); const { path, selectedKind, selectedStory, ...rest } = parse(search); - return ( - '?' + - stringify({ - ...rest, - ...extraParams, - ...(selection && { id: selection.storyId, viewMode: selection.viewMode }), - }) - ); + const queryStr = stringify({ + ...rest, + ...extraParams, + ...(selection && { id: selection.storyId, viewMode: selection.viewMode }), + }); + return `?${queryStr}`; }; export const setPath = (selection?: Selection) => { @@ -69,7 +64,7 @@ const getFirstString = (v: ValueOf>): string | void export const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => { if (typeof document !== 'undefined') { - const queryStr = document.location.search ? document.location.search.slice(1) : ''; + const queryStr = document.location.search.slice(1); const query = parse(queryStr); const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined; const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined; diff --git a/code/lib/router/src/utils.test.ts b/code/lib/router/src/utils.test.ts index 5eb0571b8f3a..e12d257aa316 100644 --- a/code/lib/router/src/utils.test.ts +++ b/code/lib/router/src/utils.test.ts @@ -137,12 +137,12 @@ describe('buildArgsParam', () => { it('builds arrays', () => { const param = buildArgsParam({}, { arr: ['1', '2', '3'] }); - expect(param).toEqual('arr%5B0%5D:1;arr%5B1%5D:2;arr%5B2%5D:3'); + expect(param).toEqual('arr[0]:1;arr[1]:2;arr[2]:3'); }); it('builds sparse arrays', () => { const param = buildArgsParam({}, { arr: ['1', , '3'] }); - expect(param).toEqual('arr%5B0%5D:1;arr%5B2%5D:3'); + expect(param).toEqual('arr[0]:1;arr[2]:3'); }); it('builds simple objects', () => { @@ -157,22 +157,22 @@ describe('buildArgsParam', () => { it('builds arrays in objects', () => { const param = buildArgsParam({}, { obj: { foo: ['1', , '3'] } }); - expect(param).toEqual('obj.foo%5B0%5D:1;obj.foo%5B2%5D:3'); + expect(param).toEqual('obj.foo[0]:1;obj.foo[2]:3'); }); it('builds single object in array', () => { const param = buildArgsParam({}, { arr: [{ one: '1', two: '2' }] }); - expect(param).toEqual('arr%5B0%5D.one:1;arr%5B0%5D.two:2'); + expect(param).toEqual('arr[0].one:1;arr[0].two:2'); }); it('builds multiple objects in array', () => { const param = buildArgsParam({}, { arr: [{ one: '1' }, { two: '2' }] }); - expect(param).toEqual('arr%5B0%5D.one:1;arr%5B1%5D.two:2'); + expect(param).toEqual('arr[0].one:1;arr[1].two:2'); }); it('builds nested object in array', () => { const param = buildArgsParam({}, { arr: [{ foo: { bar: 'val' } }] }); - expect(param).toEqual('arr%5B0%5D.foo.bar:val'); + expect(param).toEqual('arr[0].foo.bar:val'); }); it('encodes space as +', () => { @@ -187,7 +187,7 @@ describe('buildArgsParam', () => { it('encodes nested null values as !null', () => { const param = buildArgsParam({}, { foo: { bar: [{ key: null }], baz: null } }); - expect(param).toEqual('foo.bar%5B0%5D.key:!null;foo.baz:!null'); + expect(param).toEqual('foo.bar[0].key:!null;foo.baz:!null'); }); it('encodes hex color values as !hex(value)', () => { @@ -197,17 +197,17 @@ describe('buildArgsParam', () => { it('encodes rgba color values by prefixing and compacting', () => { const param = buildArgsParam({}, { rgb: 'rgb(255, 71, 133)', rgba: 'rgba(255, 71, 133, 0.5)' }); - expect(param).toEqual('rgb:!rgb(255%2C71%2C133);rgba:!rgba(255%2C71%2C133%2C0.5)'); + expect(param).toEqual('rgb:!rgb(255,71,133);rgba:!rgba(255,71,133,0.5)'); }); it('encodes hsla color values by prefixing and compacting', () => { const param = buildArgsParam({}, { hsl: 'hsl(45, 99%, 70%)', hsla: 'hsla(45, 99%, 70%, 0.5)' }); - expect(param).toEqual('hsl:!hsl(45%2C99%2C70);hsla:!hsla(45%2C99%2C70%2C0.5)'); + expect(param).toEqual('hsl:!hsl(45,99,70);hsla:!hsla(45,99,70,0.5)'); }); it('encodes Date objects as !date(ISO string)', () => { const param = buildArgsParam({}, { key: new Date('2001-02-03T04:05:06.789Z') }); - expect(param).toEqual('key:!date(2001-02-03T04%3A05%3A06.789Z)'); + expect(param).toEqual('key:!date(2001-02-03T04:05:06.789Z)'); }); describe('with initial state', () => { @@ -223,7 +223,7 @@ describe('buildArgsParam', () => { it('sets !undefined for removed array values', () => { const param = buildArgsParam({ arr: [1] }, { arr: [] }); - expect(param).toEqual('arr%5B0%5D:!undefined'); + expect(param).toEqual('arr[0]:!undefined'); }); it('sets !undefined for removed object properties', () => { @@ -233,7 +233,7 @@ describe('buildArgsParam', () => { it('omits unchanged array values (yielding sparse arrays)', () => { const param = buildArgsParam({ arr: [1, 2, 3] }, { arr: [1, 3, 4] }); - expect(param).toEqual('arr%5B1%5D:3;arr%5B2%5D:4'); + expect(param).toEqual('arr[1]:3;arr[2]:4'); }); it('omits nested unchanged object properties and array values', () => { @@ -241,7 +241,7 @@ describe('buildArgsParam', () => { { obj: { nested: [{ one: 1 }, { two: 2 }] } }, { obj: { nested: [{ one: 1 }, { two: 2, three: 3 }] } } ); - expect(param).toEqual('obj.nested%5B1%5D.three:3'); + expect(param).toEqual('obj.nested[1].three:3'); }); }); }); diff --git a/code/lib/router/src/utils.ts b/code/lib/router/src/utils.ts index b7d1097e27e3..ac141c3a0b3b 100644 --- a/code/lib/router/src/utils.ts +++ b/code/lib/router/src/utils.ts @@ -127,6 +127,28 @@ const QS_OPTIONS: Partial = { nesting: true, nestingSyntax: 'js', // encode objects using dot notation: obj.key=val }; + +// Replaces some url-encoded characters with their decoded equivalents. +// The URI RFC specifies these should be encoded, but all browsers will +// tolerate them being decoded, so we opt to go with it for cleaner looking +// URIs. +const decodeKnownQueryChar = (chr: string) => { + switch (chr) { + case '%20': + return '+'; + case '%5B': + return '['; + case '%5D': + return ']'; + case '%2C': + return ','; + case '%3A': + return ':'; + } + return chr; +}; +const knownQueryChar = /%[0-9A-F]{2}/g; + export const buildArgsParam = (initialArgs: Args | undefined, args: Args): string => { const update = deepDiff(initialArgs, args); if (!update || update === DEEPLY_EQUAL) return ''; @@ -142,7 +164,7 @@ export const buildArgsParam = (initialArgs: Args | undefined, args: Args): strin }, {} as Args); return stringify(encodeSpecialValues(object), QS_OPTIONS) - .replace(/%20/g, '+') + .replace(knownQueryChar, decodeKnownQueryChar) .split(';') .map((part: string) => part.replace('=', ':')) .join(';'); From 13053d7a2deb1535b34bc52e6d49f625c50cbd95 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sun, 28 Jul 2024 10:49:07 +0100 Subject: [PATCH 008/213] test: fix parseArgsParam tests --- code/core/package.json | 2 +- .../preview-web/parseArgsParam.test.ts | 21 +- code/yarn.lock | 189 ++++++++++++++++-- 3 files changed, 181 insertions(+), 31 deletions(-) diff --git a/code/core/package.json b/code/core/package.json index 2882c273f465..42d351ffc5e8 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -352,7 +352,7 @@ "npmlog": "^7.0.0", "open": "^8.4.0", "picomatch": "^2.3.0", - "picoquery": "^1.3.0", + "picoquery": "^1.4.0", "polished": "^4.2.2", "prettier": "^3.2.5", "pretty-hrtime": "^1.0.3", diff --git a/code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts b/code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts index f72df087ddcd..e484b511d3cd 100644 --- a/code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts +++ b/code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts @@ -57,7 +57,7 @@ describe('parseArgsParam', () => { }); it('parses Date with timezone offset', () => { - const args = parseArgsParam('key:!date(2001-02-03T04:05:06.789+09:00)'); + const args = parseArgsParam('key:!date(2001-02-03T04:05:06.789%2B09:00)'); expect(args).toStrictEqual({ key: new Date('2001-02-03T04:05:06.789+09:00') }); }); @@ -126,7 +126,7 @@ describe('parseArgsParam', () => { }); it('parses single object in array', () => { - const args = parseArgsParam('arr[].one:A;arr[].two:B'); + const args = parseArgsParam('arr[0].one:A;arr[0].two:B'); expect(args).toStrictEqual({ arr: [{ one: 'A', two: 'B' }] }); }); @@ -134,14 +134,10 @@ describe('parseArgsParam', () => { expect(parseArgsParam('arr[0].key:A;arr[1].key:B')).toStrictEqual({ arr: [{ key: 'A' }, { key: 'B' }], }); - expect(parseArgsParam('arr[0][key]:A;arr[1][key]:B')).toStrictEqual({ - arr: [{ key: 'A' }, { key: 'B' }], - }); }); it('parses nested object in array', () => { - expect(parseArgsParam('arr[].foo.bar:val')).toStrictEqual({ arr: [{ foo: { bar: 'val' } }] }); - expect(parseArgsParam('arr[][foo][bar]:val')).toStrictEqual({ arr: [{ foo: { bar: 'val' } }] }); + expect(parseArgsParam('arr[0].foo.bar:val')).toStrictEqual({ arr: [{ foo: { bar: 'val' } }] }); }); describe('key sanitization', () => { @@ -163,8 +159,6 @@ describe('parseArgsParam', () => { expect(parseArgsParam('a/b:val')).toStrictEqual({}); expect(parseArgsParam('a\\b:val')).toStrictEqual({}); expect(parseArgsParam('a|b:val')).toStrictEqual({}); - expect(parseArgsParam('a[b:val')).toStrictEqual({}); - expect(parseArgsParam('a]b:val')).toStrictEqual({}); expect(parseArgsParam('a{b:val')).toStrictEqual({}); expect(parseArgsParam('a}b:val')).toStrictEqual({}); expect(parseArgsParam('a?b:val')).toStrictEqual({}); @@ -184,14 +178,10 @@ describe('parseArgsParam', () => { it('also applies to nested object keys', () => { expect(parseArgsParam('obj.a!b:val')).toStrictEqual({}); - expect(parseArgsParam('obj[a!b]:val')).toStrictEqual({}); - expect(parseArgsParam('arr[][a!b]:val')).toStrictEqual({}); - expect(parseArgsParam('arr[0][a!b]:val')).toStrictEqual({}); }); it('completely omits an arg when a (deeply) nested key is invalid', () => { expect(parseArgsParam('obj.foo.a!b:val;obj.foo.bar:val;obj.baz:val')).toStrictEqual({}); - expect(parseArgsParam('obj.foo[][a!b]:val;obj.foo.bar:val;obj.baz:val')).toStrictEqual({}); expect(parseArgsParam('obj.foo.a!b:val;key:val')).toStrictEqual({ key: 'val' }); }); }); @@ -246,9 +236,6 @@ describe('parseArgsParam', () => { it('also applies to nested object and array values', () => { expect(parseArgsParam('obj.key:a!b')).toStrictEqual({}); - expect(parseArgsParam('obj[key]:a!b')).toStrictEqual({}); - expect(parseArgsParam('arr[][key]:a!b')).toStrictEqual({}); - expect(parseArgsParam('arr[0][key]:a!b')).toStrictEqual({}); expect(parseArgsParam('arr[]:a!b')).toStrictEqual({}); expect(parseArgsParam('arr[0]:a!b')).toStrictEqual({}); }); @@ -257,7 +244,7 @@ describe('parseArgsParam', () => { expect(parseArgsParam('obj.key:a!b;obj.foo:val;obj.bar.baz:val')).toStrictEqual({}); expect(parseArgsParam('obj.arr[]:a!b;obj.foo:val;obj.bar.baz:val')).toStrictEqual({}); expect(parseArgsParam('obj.arr[0]:val;obj.arr[1]:a!b;obj.foo:val')).toStrictEqual({}); - expect(parseArgsParam('obj.arr[][one]:a!b;obj.arr[][two]:val')).toStrictEqual({}); + expect(parseArgsParam('obj.arr[]:a!b;obj.arr[]:val')).toStrictEqual({}); expect(parseArgsParam('arr[]:val;arr[]:a!b;key:val')).toStrictEqual({ key: 'val' }); expect(parseArgsParam('arr[0]:val;arr[1]:a!1;key:val')).toStrictEqual({ key: 'val' }); expect(parseArgsParam('arr[0]:val;arr[2]:a!1;key:val')).toStrictEqual({ key: 'val' }); diff --git a/code/yarn.lock b/code/yarn.lock index af1e1c14190b..092f5969f580 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -370,6 +370,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.24.1": + version: 7.24.2 + resolution: "@babel/code-frame@npm:7.24.2" + dependencies: + "@babel/highlight": "npm:^7.24.2" + picocolors: "npm:^1.0.0" + checksum: 10c0/d1d4cba89475ab6aab7a88242e1fd73b15ecb9f30c109b69752956434d10a26a52cbd37727c4eca104b6d45227bd1dfce39a6a6f4a14c9b2f07f871e968cf406 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4, @babel/compat-data@npm:^7.24.7": version: 7.24.7 resolution: "@babel/compat-data@npm:7.24.7" @@ -470,6 +480,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.24.1": + version: 7.24.4 + resolution: "@babel/generator@npm:7.24.4" + dependencies: + "@babel/types": "npm:^7.24.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10c0/67a1b2f7cc985aaaa11b01e8ddd4fffa4f285837bc7a209738eb8203aa34bdafeb8507ed75fd883ddbabd641a036ca0a8d984e760f28ad4a9d60bff29d0a60bb + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -582,6 +604,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" + dependencies: + "@babel/template": "npm:^7.22.15" + "@babel/types": "npm:^7.23.0" + checksum: 10c0/d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428 + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-function-name@npm:7.24.7" @@ -592,6 +624,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" + dependencies: + "@babel/types": "npm:^7.22.5" + checksum: 10c0/60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-hoist-variables@npm:7.24.7" @@ -645,7 +686,14 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-plugin-utils@npm:7.24.7" checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 @@ -698,7 +746,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:7.22.6": +"@babel/helper-split-export-declaration@npm:7.22.6, @babel/helper-split-export-declaration@npm:^7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: @@ -716,6 +764,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: 10c0/f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-string-parser@npm:7.24.7" @@ -723,6 +778,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" @@ -759,6 +821,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/highlight@npm:7.24.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10c0/98ce00321daedeed33a4ed9362dc089a70375ff1b3b91228b9f05e6591d387a81a8cba68886e207861b8871efa0bc997ceabdd9c90f6cce3ee1b2f7f941b42db + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -780,6 +854,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.1": + version: 7.24.4 + resolution: "@babel/parser@npm:7.24.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/8381e1efead5069cb7ed2abc3a583f4a86289b2f376c75cecc69f59a8eb36df18274b1886cecf2f97a6a0dff5334b27330f58535be9b3e4e26102cc50e12eac8 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4": version: 7.24.4 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4" @@ -2238,6 +2321,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.22.15": + version: 7.24.0 + resolution: "@babel/template@npm:7.24.0" + dependencies: + "@babel/code-frame": "npm:^7.23.5" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10c0/9d3dd8d22fe1c36bc3bdef6118af1f4b030aaf6d7d2619f5da203efa818a2185d717523486c111de8d99a8649ddf4bbf6b2a7a64962d8411cf6a8fa89f010e54 + languageName: node + linkType: hard + "@babel/template@npm:^7.23.9, @babel/template@npm:^7.24.0, @babel/template@npm:^7.24.7": version: 7.24.7 resolution: "@babel/template@npm:7.24.7" @@ -2249,7 +2343,25 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.9, @babel/traverse@npm:^7.24.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.4.5": +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.9, @babel/traverse@npm:^7.24.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.4.5": + version: 7.24.1 + resolution: "@babel/traverse@npm:7.24.1" + dependencies: + "@babel/code-frame": "npm:^7.24.1" + "@babel/generator": "npm:^7.24.1" + "@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.24.1" + "@babel/types": "npm:^7.24.0" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/c087b918f6823776537ba246136c70e7ce0719fc05361ebcbfd16f4e6f2f6f1f8f4f9167f1d9b675f27d12074839605189cc9d689de20b89a85e7c140f23daab + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.24.7": version: 7.24.7 resolution: "@babel/traverse@npm:7.24.7" dependencies: @@ -2278,6 +2390,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.23.0": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" + 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: 10c0/777a0bb5dbe038ca4c905fdafb1cdb6bdd10fe9d63ce13eca0bd91909363cbad554a53dc1f902004b78c1dcbc742056f877f2c99eeedff647333b1fadf51235d + 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" @@ -5838,7 +5961,7 @@ __metadata: npmlog: "npm:^7.0.0" open: "npm:^8.4.0" picomatch: "npm:^2.3.0" - picoquery: "npm:^1.3.0" + picoquery: "npm:^1.4.0" polished: "npm:^4.2.2" prettier: "npm:^3.2.5" pretty-hrtime: "npm:^1.0.3" @@ -9244,7 +9367,16 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.10.0, acorn@npm:^8.11.2, acorn@npm:^8.11.3, acorn@npm:^8.12.1, acorn@npm:^8.4.1, acorn@npm:^8.6.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn@npm:^8.0.0, acorn@npm:^8.10.0, acorn@npm:^8.11.2, acorn@npm:^8.11.3, acorn@npm:^8.4.1, acorn@npm:^8.6.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" + bin: + acorn: bin/acorn + checksum: 10c0/3ff155f8812e4a746fee8ecff1f227d527c4c45655bb1fad6347c3cb58e46190598217551b1500f18542d2bbe5c87120cb6927f5a074a59166fbdd9468f0a299 + languageName: node + linkType: hard + +"acorn@npm:^8.12.1": version: 8.12.1 resolution: "acorn@npm:8.12.1" bin: @@ -9935,7 +10067,7 @@ __metadata: languageName: node linkType: hard -"available-typed-arrays@npm:^1.0.7": +"available-typed-arrays@npm:^1.0.6, available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" dependencies: @@ -10462,7 +10594,16 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.2, braces@npm:^3.0.3, braces@npm:~3.0.2": +"braces@npm:^3.0.2, braces@npm:~3.0.2": + version: 3.0.2 + resolution: "braces@npm:3.0.2" + dependencies: + fill-range: "npm:^7.0.1" + checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 + languageName: node + linkType: hard + +"braces@npm:^3.0.3": version: 3.0.3 resolution: "braces@npm:3.0.3" dependencies: @@ -14789,6 +14930,15 @@ __metadata: languageName: node linkType: hard +"fill-range@npm:^7.0.1": + version: 7.0.1 + resolution: "fill-range@npm:7.0.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f + languageName: node + linkType: hard + "fill-range@npm:^7.1.1": version: 7.1.1 resolution: "fill-range@npm:7.1.1" @@ -16022,7 +16172,7 @@ __metadata: languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.1, has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" dependencies: @@ -22034,12 +22184,12 @@ __metadata: languageName: node linkType: hard -"picoquery@npm:^1.3.0": - version: 1.3.0 - resolution: "picoquery@npm:1.3.0" +"picoquery@npm:^1.4.0": + version: 1.4.0 + resolution: "picoquery@npm:1.4.0" dependencies: fast-decode-uri-component: "npm:^1.0.1" - checksum: 10c0/7bbd692d3996caff8e19bb0590b925d673ec87bc3c005cce55610c64a7348129bfc6b4f47dcd578ebcf4ea12db958fb004439cf827b67741b927a17f32af00d4 + checksum: 10c0/8c2bdb85eabb51ce1534d0a70ac288dac8d241a32e5d1ee960ee1ed7c5f522752db23cdc63318ac69ce892bdbcc465f4e2d25a5b970b7a29ffa36455cc2d022c languageName: node linkType: hard @@ -28507,7 +28657,20 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": + version: 1.1.14 + resolution: "which-typed-array@npm:1.1.14" + dependencies: + available-typed-arrays: "npm:^1.0.6" + call-bind: "npm:^1.0.5" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.1" + checksum: 10c0/0960f1e77807058819451b98c51d4cd72031593e8de990b24bd3fc22e176f5eee22921d68d852297c786aec117689f0423ed20aa4fde7ce2704d680677891f56 + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.15": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: From 5171010d595d9f7f29c623fe0b7c8b401bd12a7c Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sun, 28 Jul 2024 12:59:47 +0100 Subject: [PATCH 009/213] test: add prefix to test queries --- code/core/src/manager-api/tests/url.test.js | 12 ++++++------ code/core/src/router/utils.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/core/src/manager-api/tests/url.test.js b/code/core/src/manager-api/tests/url.test.js index 53946d7ab6b9..ef9e70482dc2 100644 --- a/code/core/src/manager-api/tests/url.test.js +++ b/code/core/src/manager-api/tests/url.test.js @@ -18,7 +18,7 @@ describe('initial state', () => { describe('config query parameters', () => { it('handles full parameter', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ full: '1' }).toString() }; + const location = { search: '?' + new URLSearchParams({ full: '1' }).toString() }; const { state: { layout }, @@ -33,7 +33,7 @@ describe('initial state', () => { it('handles nav parameter', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ nav: '0' }).toString() }; + const location = { search: '?' + new URLSearchParams({ nav: '0' }).toString() }; const { state: { layout }, @@ -44,7 +44,7 @@ describe('initial state', () => { it('handles shortcuts parameter', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ shortcuts: '0' }).toString() }; + const location = { search: '?' + new URLSearchParams({ shortcuts: '0' }).toString() }; const { state: { ui }, @@ -55,7 +55,7 @@ describe('initial state', () => { it('handles panel parameter, bottom', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ panel: 'bottom' }).toString() }; + const location = { search: '?' + new URLSearchParams({ panel: 'bottom' }).toString() }; const { state: { layout }, @@ -66,7 +66,7 @@ describe('initial state', () => { it('handles panel parameter, right', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ panel: 'right' }).toString() }; + const location = { search: '?' + new URLSearchParams({ panel: 'right' }).toString() }; const { state: { layout }, @@ -77,7 +77,7 @@ describe('initial state', () => { it('handles panel parameter, 0', () => { const navigate = vi.fn(); - const location = { search: new URLSearchParams({ panel: '0' }).toString() }; + const location = { search: '?' + new URLSearchParams({ panel: '0' }).toString() }; const { state: { layout }, diff --git a/code/core/src/router/utils.ts b/code/core/src/router/utils.ts index c670c5aea790..e8a357b06f29 100644 --- a/code/core/src/router/utils.ts +++ b/code/core/src/router/utils.ts @@ -175,7 +175,7 @@ interface Query { } export const queryFromString = memoize(1000)( - (s?: string): Query => (s !== undefined ? parse(s) : {}) + (s?: string): Query => (s !== undefined ? parse(s, QS_OPTIONS) : {}) ); export const queryFromLocation = (location: Partial) => queryFromString(location.search ? location.search.slice(1) : ''); From 8f6ff036d1313c8b981993a9df9b6baabc9b14ea Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 2 Aug 2024 22:56:45 +0200 Subject: [PATCH 010/213] dedupe --- code/yarn.lock | 179 +++---------------------------------------------- 1 file changed, 8 insertions(+), 171 deletions(-) diff --git a/code/yarn.lock b/code/yarn.lock index f38ef7f57730..0c6f112474b9 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -370,16 +370,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.24.1": - version: 7.24.2 - resolution: "@babel/code-frame@npm:7.24.2" - dependencies: - "@babel/highlight": "npm:^7.24.2" - picocolors: "npm:^1.0.0" - checksum: 10c0/d1d4cba89475ab6aab7a88242e1fd73b15ecb9f30c109b69752956434d10a26a52cbd37727c4eca104b6d45227bd1dfce39a6a6f4a14c9b2f07f871e968cf406 - languageName: node - linkType: hard - "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4, @babel/compat-data@npm:^7.24.7": version: 7.24.7 resolution: "@babel/compat-data@npm:7.24.7" @@ -480,18 +470,6 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.24.1": - version: 7.24.4 - resolution: "@babel/generator@npm:7.24.4" - dependencies: - "@babel/types": "npm:^7.24.0" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^2.5.1" - checksum: 10c0/67a1b2f7cc985aaaa11b01e8ddd4fffa4f285837bc7a209738eb8203aa34bdafeb8507ed75fd883ddbabd641a036ca0a8d984e760f28ad4a9d60bff29d0a60bb - languageName: node - linkType: hard - "@babel/helper-annotate-as-pure@npm:7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -604,16 +582,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-function-name@npm:7.23.0" - dependencies: - "@babel/template": "npm:^7.22.15" - "@babel/types": "npm:^7.23.0" - checksum: 10c0/d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428 - languageName: node - linkType: hard - "@babel/helper-function-name@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-function-name@npm:7.24.7" @@ -624,15 +592,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-hoist-variables@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 - languageName: node - linkType: hard - "@babel/helper-hoist-variables@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-hoist-variables@npm:7.24.7" @@ -686,14 +645,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.0 - resolution: "@babel/helper-plugin-utils@npm:7.24.0" - checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.24.7": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.24.7 resolution: "@babel/helper-plugin-utils@npm:7.24.7" checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 @@ -746,7 +698,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:7.22.6, @babel/helper-split-export-declaration@npm:^7.22.6": +"@babel/helper-split-export-declaration@npm:7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: @@ -764,13 +716,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/helper-string-parser@npm:7.23.4" - checksum: 10c0/f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac - languageName: node - linkType: hard - "@babel/helper-string-parser@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-string-parser@npm:7.24.7" @@ -778,13 +723,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e - languageName: node - linkType: hard - "@babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" @@ -821,18 +759,6 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.24.2": - version: 7.24.2 - resolution: "@babel/highlight@npm:7.24.2" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.22.20" - chalk: "npm:^2.4.2" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.0.0" - checksum: 10c0/98ce00321daedeed33a4ed9362dc089a70375ff1b3b91228b9f05e6591d387a81a8cba68886e207861b8871efa0bc997ceabdd9c90f6cce3ee1b2f7f941b42db - languageName: node - linkType: hard - "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -854,15 +780,6 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.24.1": - version: 7.24.4 - resolution: "@babel/parser@npm:7.24.4" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/8381e1efead5069cb7ed2abc3a583f4a86289b2f376c75cecc69f59a8eb36df18274b1886cecf2f97a6a0dff5334b27330f58535be9b3e4e26102cc50e12eac8 - languageName: node - linkType: hard - "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4": version: 7.24.4 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4" @@ -2321,17 +2238,6 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.22.15": - version: 7.24.0 - resolution: "@babel/template@npm:7.24.0" - dependencies: - "@babel/code-frame": "npm:^7.23.5" - "@babel/parser": "npm:^7.24.0" - "@babel/types": "npm:^7.24.0" - checksum: 10c0/9d3dd8d22fe1c36bc3bdef6118af1f4b030aaf6d7d2619f5da203efa818a2185d717523486c111de8d99a8649ddf4bbf6b2a7a64962d8411cf6a8fa89f010e54 - languageName: node - linkType: hard - "@babel/template@npm:^7.23.9, @babel/template@npm:^7.24.0, @babel/template@npm:^7.24.7": version: 7.24.7 resolution: "@babel/template@npm:7.24.7" @@ -2343,25 +2249,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.9, @babel/traverse@npm:^7.24.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.4.5": - version: 7.24.1 - resolution: "@babel/traverse@npm:7.24.1" - dependencies: - "@babel/code-frame": "npm:^7.24.1" - "@babel/generator": "npm:^7.24.1" - "@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.24.1" - "@babel/types": "npm:^7.24.0" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10c0/c087b918f6823776537ba246136c70e7ce0719fc05361ebcbfd16f4e6f2f6f1f8f4f9167f1d9b675f27d12074839605189cc9d689de20b89a85e7c140f23daab - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.24.7": +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.9, @babel/traverse@npm:^7.24.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.4.5": version: 7.24.7 resolution: "@babel/traverse@npm:7.24.7" dependencies: @@ -2390,17 +2278,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.23.0": - version: 7.24.0 - resolution: "@babel/types@npm:7.24.0" - 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: 10c0/777a0bb5dbe038ca4c905fdafb1cdb6bdd10fe9d63ce13eca0bd91909363cbad554a53dc1f902004b78c1dcbc742056f877f2c99eeedff647333b1fadf51235d - 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" @@ -9379,16 +9256,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.10.0, acorn@npm:^8.11.2, acorn@npm:^8.11.3, acorn@npm:^8.4.1, acorn@npm:^8.6.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.11.3 - resolution: "acorn@npm:8.11.3" - bin: - acorn: bin/acorn - checksum: 10c0/3ff155f8812e4a746fee8ecff1f227d527c4c45655bb1fad6347c3cb58e46190598217551b1500f18542d2bbe5c87120cb6927f5a074a59166fbdd9468f0a299 - languageName: node - linkType: hard - -"acorn@npm:^8.12.1": +"acorn@npm:^8.0.0, acorn@npm:^8.10.0, acorn@npm:^8.11.2, acorn@npm:^8.11.3, acorn@npm:^8.12.1, acorn@npm:^8.4.1, acorn@npm:^8.6.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.12.1 resolution: "acorn@npm:8.12.1" bin: @@ -10079,7 +9947,7 @@ __metadata: languageName: node linkType: hard -"available-typed-arrays@npm:^1.0.6, available-typed-arrays@npm:^1.0.7": +"available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" dependencies: @@ -10606,16 +10474,7 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.2, braces@npm:~3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" - dependencies: - fill-range: "npm:^7.0.1" - checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 - languageName: node - linkType: hard - -"braces@npm:^3.0.3": +"braces@npm:^3.0.2, braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" dependencies: @@ -14942,15 +14801,6 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f - languageName: node - linkType: hard - "fill-range@npm:^7.1.1": version: 7.1.1 resolution: "fill-range@npm:7.1.1" @@ -16184,7 +16034,7 @@ __metadata: languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.1, has-tostringtag@npm:^1.0.2": +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" dependencies: @@ -28675,20 +28525,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": - version: 1.1.14 - resolution: "which-typed-array@npm:1.1.14" - dependencies: - available-typed-arrays: "npm:^1.0.6" - call-bind: "npm:^1.0.5" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.1" - checksum: 10c0/0960f1e77807058819451b98c51d4cd72031593e8de990b24bd3fc22e176f5eee22921d68d852297c786aec117689f0423ed20aa4fde7ce2704d680677891f56 - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.15": +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: From 2bdd9dc9692f04276d1809f0917af3342fc45ce7 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Mon, 19 Aug 2024 23:00:11 -0600 Subject: [PATCH 011/213] WIP: Docs for Test runner with Vitest - Includes sidebar order updates - Use non-zero-indexed orders --- .../portable-stories-jest.mdx | 2 +- .../portable-stories-playwright.mdx | 2 +- .../portable-stories-vitest.mdx | 2 +- docs/writing-tests/accessibility-testing.mdx | 2 +- docs/writing-tests/addon-vitest.mdx | 346 ++++++++++++++++++ .../import-stories-in-tests/index.mdx | 2 +- .../stories-in-end-to-end-tests.mdx | 2 +- .../stories-in-unit-tests.mdx | 2 +- docs/writing-tests/interaction-testing.mdx | 2 +- docs/writing-tests/snapshot-testing/index.mdx | 2 +- .../snapshot-testing/snapshot-testing.mdx | 2 + .../storyshots-migration-guide.mdx | 2 + docs/writing-tests/test-coverage.mdx | 2 +- docs/writing-tests/visual-testing.mdx | 2 +- 14 files changed, 361 insertions(+), 11 deletions(-) create mode 100644 docs/writing-tests/addon-vitest.mdx diff --git a/docs/api/portable-stories/portable-stories-jest.mdx b/docs/api/portable-stories/portable-stories-jest.mdx index 64038d44dd7a..209aa2942e49 100644 --- a/docs/api/portable-stories/portable-stories-jest.mdx +++ b/docs/api/portable-stories/portable-stories-jest.mdx @@ -2,7 +2,7 @@ title: 'Portable stories in Jest' sidebar: title: Jest - order: 1 + order: 2 --- diff --git a/docs/api/portable-stories/portable-stories-playwright.mdx b/docs/api/portable-stories/portable-stories-playwright.mdx index 2cbae20f3dd9..a2becdc78b74 100644 --- a/docs/api/portable-stories/portable-stories-playwright.mdx +++ b/docs/api/portable-stories/portable-stories-playwright.mdx @@ -2,7 +2,7 @@ title: 'Portable stories in Playwright CT' sidebar: title: Playwright - order: 2 + order: 3 --- (⚠️ **Experimental**) diff --git a/docs/api/portable-stories/portable-stories-vitest.mdx b/docs/api/portable-stories/portable-stories-vitest.mdx index 11aa9b99475d..281d18b1adf9 100644 --- a/docs/api/portable-stories/portable-stories-vitest.mdx +++ b/docs/api/portable-stories/portable-stories-vitest.mdx @@ -2,7 +2,7 @@ title: 'Portable stories in Vitest' sidebar: title: Vitest - order: 0 + order: 1 --- diff --git a/docs/writing-tests/accessibility-testing.mdx b/docs/writing-tests/accessibility-testing.mdx index 5942811bfb27..2c2eebbe506a 100644 --- a/docs/writing-tests/accessibility-testing.mdx +++ b/docs/writing-tests/accessibility-testing.mdx @@ -1,7 +1,7 @@ --- title: 'Accessibility tests' sidebar: - order: 3 + order: 4 title: Accessibility tests --- diff --git a/docs/writing-tests/addon-vitest.mdx b/docs/writing-tests/addon-vitest.mdx new file mode 100644 index 000000000000..139f9e6d170e --- /dev/null +++ b/docs/writing-tests/addon-vitest.mdx @@ -0,0 +1,346 @@ +--- +title: 'Test runner with Vitest' +sidebar: + order: 2 + title: Test runner with Vitest +--- + +TK - Intro + +## Set up + +To get started, run the following command to install and configure the addon: + +{/* TODO: Snippetize */} +```sh +npx storybook@latest add @storybook/experimental-addon-vitest +``` + +That command will do the following: + +1. Install and register the Vitest addon, which contains the plugin to run your stories as tests +1. Inspect your project's Vite and Vitest setup + 1. If Vite is not installed and you're using the [`nextjs` framework](../get-started/frameworks/nextjs.mdx), it will install and configure Vite for you, as well as `vite-plugin-storybook-nextjs` (necessary to have your Next.js components function in Vitest). + 1. Otherwise, if Vite is not installed, it will stop and point you to these instructions to continue setting it up in your project. + 1. If Vite is installed, it will then check for Vitest. + 1. If Vitest is not installed, it will: + 1. Install `vitest`, `@vitest/browser`, and `playwright` + 1. Run `npx playwright install chromium` to install the Chromium browser engine + 1. Create a Vitest config file (`vitest.config.ts`) and a Vitest setup file (`storybook.setup.ts`) + 1. If Vitest is installed, it will stop and point you to these instructions to continue setting it up in your project. + + + + If your stories use template-based Vue components, you may need to [alias the `vue` module](https://vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation) to resolve correctly in the Playwright CT environment. You can do this via the [`ctViteConfig` property](https://playwright.dev/docs/test-components#i-have-a-project-that-already-uses-vite-can-i-reuse-the-config): + +
+ Example Playwright configuration + +```ts +// playwright-config.ts +import { defineConfig } from '@playwright/experimental-ct-vue'; + +export default defineConfig({ + ctViteConfig: { + resolve: { + alias: { + vue: 'vue/dist/vue.esm-bundler.js', + }, + }, + }, +}); +``` +
+
+
+ +The configuration produced by the `add` command will attempt to set some sensible defaults for your project. However, you may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. + +### Example configuration files + +Here are configuration files generated by the `add` command. You can use these as a reference when setting up your project. + +
+ Example Vitest setup file + +```ts title="storybook.setup.ts" +TK +``` +
+ +
+ Example Vitest config file + +```ts title="vitest.config.ts" +import { defineConfig, mergeConfig } from 'vitest/config' +import viteConfig from '../vite.config' +import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' + +export default mergeConfig( + viteConfig, + defineConfig({ + // ... TK + }) +) +``` +
+ +
+ Example Vitest workspace file + +{/* TODO: Nextjs & SvelteKit examples */} +```ts title="vitest.workspace.ts" +import { defineWorkspace } from 'vitest/config' +import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' + +export default defineWorkspace([ + // This is the path to your existing Vitest config files + './vitest.config.ts', + { + name: 'storybook', + plugins: [ + storybookTest({ + storybookScript: 'yarn storybook --ci', + }), + ], + // Glob pattern to find story files + include: ['../src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + setupFiles: ['./storybook.setup.ts'], + } +]) +``` +
+ +## How it works + +Before running tests using the plugin, it's helpful to understand how it works. + +First, the plugin does not need to run or build Storybook to test your stories. Instead, it transforms your stories into tests using Vite and [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Portable stories are a mechanism to compose all of a story's configuration ([parameters](../writing-stories/parameters.mdx), [decorators](../writing-stories/decorators.mdx), etc.) with the story itself. This allows you to run your stories as tests without needing to run Storybook. + +Those tests are then run using Vitest. We recommend (and configure, by default) running Vitest in browser mode, using Playwright's Chromium browser. Browser mode ensures your components are tested in a real browser environment, which is more accurate than simulations like JSDom or HappyDom. This is especially important for testing components that rely on browser APIs or features. + +Stories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../writing-stories/play-function.mdx) is defined, that function is run and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. + +### Debugging + +While the plugin does not require Storybook to run when testing, you may still want to run Storybook to debug your tests. To enable this, provide the [`storybookScript` option](#storybookscript) in the plugin configuration. When you run Vitest in watch mode, the plugin will start Storybook using this script and provide links to the story in the output on test failures. This allows you to quickly jump to the story in Storybook to debug the issue. + +You can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running. + +TK - Screenshot of test output with links to SB + +## Usage + +There are three primary ways to run tests using the Vitest plugin: + +### CLI + +The plugin transforms your stories into real Vitest tests, so you run those tests just like you run any other Vitest tests in your project. Typically, you will have a `test` script in your `package.json` that runs Vitest. When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: + +{/* TODO: Snippetize */} +```sh +npm run test +``` + +### Editor extension + +Transforming your stories into Vitest tests with the plugin also enables you to run and debug tests using Vitest [IDE integrations](https://vitest.dev/guide/ide.html). This allows you to run tests directly from your editor, such as VSCode and JetBrains IDE. + +TK - Screenshot of VS Code + +### In CI + +For the most part, running your Storybook tests in CI is done [via the CLI](#cli). However, to have the test output link to your published Storybook on test failures, you need to provide the [`storybookUrl` option](#storybookurl) in the plugin configuration. + +Here's an example using GitHub Actions. The steps are similar for other CI providers, though details in the syntax or configuration may vary. + +First, we run a command to build and publish Storybook. In this case, we'll use Chromatic. This gives us a URL to the published Storybook instance. We then pass that URL to the plugin configuration using an environment variable. Finally, we update the plugin configuration to use that environment variable in the `storybookUrl` option. + +```yaml +TK +``` + +```js title="vitest.workspace.ts" +process.env.SB_URL +``` + +## Configuration + +Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. + +In this example, the Default story will not be tested, and the Primary story will. + +{/* TODO: Snippetize */} +```js title="Button.stories.tsx" +import { Button } from './Button' + +export default { + component: Button, + // 👇 Apply `test` tag to all stories in this file + tags: ['test'], +} + +export const Default = { + // 👇 Remove `test` tag from this story + tags: ['!test'], +} + +export const Primary = { + args: { primary: true } +} +``` + +By default, the plugin will run all stories with the `test` tag. You can adjust this behavior by providing the [`tags` option](#tags) in the plugin configuration. This allows you to include, exclude, or skip stories based on their tags. + +Here's an example of how you might configure the plugin to only run stories with the `test` and `spec` tags, while excluding stories with the `docs-only` tag: + +{/* TODO: Snippetize */} +```js title="vitest.workspace.ts" +{ + plugins: [ + storybookTest({ + tags: { + include: ['test', 'spec'], + exclude: ['docs-only'], + }, + }), + ], +} +``` + +If the same tag is in both the `include` and `exclude` arrays, the `exclude` behavior takes precedence. + +## FAQ + +### How to ensure my tests can find assets in the public directory? + +If your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the `publicDir` option in the Vitest configuration file. + +```ts +TK +``` + +### How to debug my tests in Storybook? + +The plugin will attempt to provide links to the story in Storybook when tests fail, for [debugging](#debugging) purposes. + +If the URLs are not working when running tests in watch mode, you should check two configuration options: + +- [`storybookUrl`](#storybookurl): Ensure this URL is correct and accessible. For example, the default is `http://localhost:6006`, which may not use the same port number you're using. +- [`storybookScript`](#storybookscript): Ensure this script is correctly starting Storybook. + +If the URLs are not working when running tests in CI, you should ensure the Storybook is built and published before running the tests. You can then provide the URL to the published Storybook using the `storybookUrl` option. See the [In CI](#in-ci) section for an example. + +### How to apply custom Vite configuration? + +If you have custom operations defined in [`viteFinal`](../api/main-config/main-config-vite-final.mdx) in your `.storybook/main.js|ts` file, you will need to translate those into the Vitest configuration. This is because the plugin does not use the Storybook Vite configuration. + +```ts +TK +``` + +### Why do we recommend browser mode? + +``` +1. It’s a real browser environment. JSDom/HappyDom are simulations with shortcomings. +2. https://vitest.dev/guide/browser/#motivation +``` + +### How to use WebDriver instead of Playwright? + +``` +https://vitest.dev/config/#browser-provider +``` + +### How to use a browser other than Chromium + +``` +https://vitest.dev/config/#browser-46-name +``` + +### How is this different from the test runner? + +``` +1. TR requires an SB instance to be running; this does not (except for debugging) +2. TR runs SB and listens to results; this transforms stories (using portable stories) into tests +3. TR is based on Jest; this is based on Vitest +4. This is more configurable and more simple than TR + 1. TR is always a separate command; this is just Vitest (`yarn test`) +5. This is faster than TR + 1. Needs benchmarks + 1. a sandbox run in our monorepo + 1. Vitest plugin: 1m 6s + 2. Test-runner: 1m 14s + SB build & publish time +``` + +### Why does the `add` command stop in some cases? + +TK + +## API + +### Exports + +`@storybook/experimental-addon-vitest/plugin` + +TK + +### Options + +#### `configDir` + +Type: `string` + +Default: `.storybook` + +The directory where the Storybook configuration is located, relative to CWD. If not provided, the plugin will use `.storybook` in the current working directory. + +#### `storybookScript` + +Type: `string` + +Optional script to run Storybook. If provided, Vitest will start Storybook using this script when run in watch mode. Only runs if the Storybook in `storybookUrl` is not already available. + +#### `storybookUrl` + +Type: `string` + +Default: `http://localhost:6006` + +The URL where Storybook is hosted. This is used for internal checks and to provide a link to the story in the test output on failures. + +#### `tags` + +Type: + +```ts +{ + include: string[]; + exclude: string[]; + skip: string[]; +} +``` + +Default: + +```ts +{ + include: ['test'], + exclude: [], + skip: [], +} +``` + +Tags to include, exclude, or skip. These tags are defined as annotations in your story, meta, or preview. + +- `include`: `string[]` - Tags to include. +- `exclude`: `string[]` - Tags to exclude. +- `skip`: `string[]` - Tags to skip. diff --git a/docs/writing-tests/import-stories-in-tests/index.mdx b/docs/writing-tests/import-stories-in-tests/index.mdx index c845f373267b..dc51d8da2e83 100644 --- a/docs/writing-tests/import-stories-in-tests/index.mdx +++ b/docs/writing-tests/import-stories-in-tests/index.mdx @@ -1,6 +1,6 @@ --- title: Import stories in tests sidebar: - order: 7 + order: 8 title: Import stories in tests --- \ No newline at end of file diff --git a/docs/writing-tests/import-stories-in-tests/stories-in-end-to-end-tests.mdx b/docs/writing-tests/import-stories-in-tests/stories-in-end-to-end-tests.mdx index 77167db0e88a..59997b7a38ee 100644 --- a/docs/writing-tests/import-stories-in-tests/stories-in-end-to-end-tests.mdx +++ b/docs/writing-tests/import-stories-in-tests/stories-in-end-to-end-tests.mdx @@ -2,7 +2,7 @@ title: 'Stories in end-to-end tests' sidebar: title: End-to-end tests - order: 1 + order: 2 --- Storybook seamlessly integrates with additional testing frameworks like [Cypress](https://www.cypress.io/) and [Playwright](https://playwright.dev/) to provide a comprehensive testing solution. By leveraging the Component Story Format (CSF), developers can write test cases that simulate user interactions and verify the behavior of individual components within the Storybook environment. This approach enables developers to thoroughly test their components' functionality, responsiveness, and visual appearance across different scenarios, resulting in more robust and reliable applications. diff --git a/docs/writing-tests/import-stories-in-tests/stories-in-unit-tests.mdx b/docs/writing-tests/import-stories-in-tests/stories-in-unit-tests.mdx index 7d16abf31b5f..67ab0e6585b2 100644 --- a/docs/writing-tests/import-stories-in-tests/stories-in-unit-tests.mdx +++ b/docs/writing-tests/import-stories-in-tests/stories-in-unit-tests.mdx @@ -2,7 +2,7 @@ title: 'Stories in unit tests' sidebar: title: Unit tests - order: 0 + order: 1 --- Teams test a variety of UI characteristics using different tools. Each tool requires you to replicate the same component state over and over. That’s a maintenance headache. Ideally, you’d set up your tests similarly and reuse that across tools. diff --git a/docs/writing-tests/interaction-testing.mdx b/docs/writing-tests/interaction-testing.mdx index a2ee5908316e..dee9c7409b11 100644 --- a/docs/writing-tests/interaction-testing.mdx +++ b/docs/writing-tests/interaction-testing.mdx @@ -1,7 +1,7 @@ --- title: 'Interaction tests' sidebar: - order: 4 + order: 5 title: Interaction tests --- diff --git a/docs/writing-tests/snapshot-testing/index.mdx b/docs/writing-tests/snapshot-testing/index.mdx index 6ec310332af2..4ce4b3630102 100644 --- a/docs/writing-tests/snapshot-testing/index.mdx +++ b/docs/writing-tests/snapshot-testing/index.mdx @@ -1,6 +1,6 @@ --- title: Snapshot testing sidebar: - order: 6 + order: 7 title: Snapshot testing --- \ No newline at end of file diff --git a/docs/writing-tests/snapshot-testing/snapshot-testing.mdx b/docs/writing-tests/snapshot-testing/snapshot-testing.mdx index bc9ca5b12225..7565090aff5a 100644 --- a/docs/writing-tests/snapshot-testing/snapshot-testing.mdx +++ b/docs/writing-tests/snapshot-testing/snapshot-testing.mdx @@ -1,5 +1,7 @@ --- title: 'Write snapshot tests' +sidebar: + order: 1 --- Snapshot tests compare the rendered markup of every story against known baselines. It’s a way to identify markup changes that trigger rendering errors and warnings. diff --git a/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx b/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx index 7c4e5ec96847..18c2b5022be3 100644 --- a/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx +++ b/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx @@ -1,5 +1,7 @@ --- title: 'Storyshots migration guide' +sidebar: + order: 2 --- diff --git a/docs/writing-tests/test-coverage.mdx b/docs/writing-tests/test-coverage.mdx index 63ae072264eb..0d09d2033565 100644 --- a/docs/writing-tests/test-coverage.mdx +++ b/docs/writing-tests/test-coverage.mdx @@ -1,7 +1,7 @@ --- title: 'Test coverage' sidebar: - order: 5 + order: 6 title: Test coverage --- diff --git a/docs/writing-tests/visual-testing.mdx b/docs/writing-tests/visual-testing.mdx index 33288d79a7f0..ba061e5f026f 100644 --- a/docs/writing-tests/visual-testing.mdx +++ b/docs/writing-tests/visual-testing.mdx @@ -2,7 +2,7 @@ title: Visual tests hideRendererSelector: true sidebar: - order: 2 + order: 3 title: Visual tests --- From 89be6a0b45870c4b60d9f5ebb249b2bbb0675623 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Wed, 21 Aug 2024 14:54:54 -0600 Subject: [PATCH 012/213] More updates --- docs/writing-tests/addon-vitest.mdx | 205 ++++++++++++++++------------ 1 file changed, 120 insertions(+), 85 deletions(-) diff --git a/docs/writing-tests/addon-vitest.mdx b/docs/writing-tests/addon-vitest.mdx index 139f9e6d170e..0f472f806364 100644 --- a/docs/writing-tests/addon-vitest.mdx +++ b/docs/writing-tests/addon-vitest.mdx @@ -5,47 +5,43 @@ sidebar: title: Test runner with Vitest --- -TK - Intro +(⚠️ **Experimental**) -## Set up +Storybook's test runner with Vitest uses a Vitest plugin to transform your [stories](../writing-stories/index.mdx) into tests. You can then run those tests just like any other in Vitest, which will check that the story renders without errors and, if a [play function](../writing-stories/play-function.mdx) is defined, that it runs as expected and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. -To get started, run the following command to install and configure the addon: +By using Vitest's browser mode, those tests are run in a real browser environment, which gives you more reliable results for UI components that commonly rely on browser APIs or features. + +## Setup + +Get started by installing and configuring the plugin in your project. + +### Automatic + +Run the following command to install and configure the addon, which contains the plugin to run your stories as tests using Vitest: {/* TODO: Snippetize */} ```sh npx storybook@latest add @storybook/experimental-addon-vitest ``` -That command will do the following: - -1. Install and register the Vitest addon, which contains the plugin to run your stories as tests -1. Inspect your project's Vite and Vitest setup - 1. If Vite is not installed and you're using the [`nextjs` framework](../get-started/frameworks/nextjs.mdx), it will install and configure Vite for you, as well as `vite-plugin-storybook-nextjs` (necessary to have your Next.js components function in Vitest). - 1. Otherwise, if Vite is not installed, it will stop and point you to these instructions to continue setting it up in your project. - 1. If Vite is installed, it will then check for Vitest. - 1. If Vitest is not installed, it will: - 1. Install `vitest`, `@vitest/browser`, and `playwright` - 1. Run `npx playwright install chromium` to install the Chromium browser engine - 1. Create a Vitest config file (`vitest.config.ts`) and a Vitest setup file (`storybook.setup.ts`) - 1. If Vitest is installed, it will stop and point you to these instructions to continue setting it up in your project. +That command will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them if necessary. - If your stories use template-based Vue components, you may need to [alias the `vue` module](https://vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation) to resolve correctly in the Playwright CT environment. You can do this via the [`ctViteConfig` property](https://playwright.dev/docs/test-components#i-have-a-project-that-already-uses-vite-can-i-reuse-the-config): + If your stories use template-based Vue components, you may need to [alias the `vue` module](https://vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation) to resolve correctly in the test environment:
- Example Playwright configuration + Example Vite configuration ```ts -// playwright-config.ts -import { defineConfig } from '@playwright/experimental-ct-vue'; +// vite.config.ts +import { defineConfig } from 'vite/config'; export default defineConfig({ - ctViteConfig: { - resolve: { - alias: { - vue: 'vue/dist/vue.esm-bundler.js', - }, + // ... + resolve: { + alias: { + vue: 'vue/dist/vue.esm-bundler.js', }, }, }); @@ -56,6 +52,47 @@ export default defineConfig({ The configuration produced by the `add` command will attempt to set some sensible defaults for your project. However, you may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. +### Manual + +For some project setups, the `add` command may be unable to automate the plugin setup and ask you to complete additional setup steps. Here's what to do: + +1. Install the addon, `@storybook/experimental-addon-vitest`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). +1. Make sure Vite and Vitest are configured in your project. +1. Make sure Vitest is configured to use [browser mode](https://vitest.dev/guide/browser/). +1. If you're using Next.js, make sure you're using [`vite-plugin-storybook-nextjs`](https://github.com/storybookjs/vite-plugin-storybook-nextjs). +1. If you're using SvelteKit, make sure you're using `@storybook/sveltekit/vite`. +1. Create a [test setup file](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), `storybook.setup.ts`, in the root of your project. +1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. Here's an example: + +{/* TODO: Nextjs & SvelteKit examples */} +```ts title="vitest.config.ts" +import { defineConfig, mergeConfig } from 'vitest/config' +import viteConfig from '../vite.config' +import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' + +export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest({ + storybookScript: 'yarn storybook --ci', + }), + ], + // Glob pattern to find story files + include: ['../src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + setupFiles: ['./storybook.setup.ts'], + }) +) +``` + ### Example configuration files Here are configuration files generated by the `add` command. You can use these as a reference when setting up your project. @@ -162,45 +199,51 @@ For the most part, running your Storybook tests in CI is done [via the CLI](#cli Here's an example using GitHub Actions. The steps are similar for other CI providers, though details in the syntax or configuration may vary. -First, we run a command to build and publish Storybook. In this case, we'll use Chromatic. This gives us a URL to the published Storybook instance. We then pass that URL to the plugin configuration using an environment variable. Finally, we update the plugin configuration to use that environment variable in the `storybookUrl` option. +When actions for services like Vercel, Netlify and others run a deployment job, they follow a pattern of emitting a `deployment_status` event containing the newly generated URL under `deployment_status.target_url`. This is the URL to the published Storybook instance. We then pass that URL to the plugin configuration using an environment variable, `SB_URL`. Finally, we update the plugin configuration to use that environment variable in the `storybookUrl` option. ```yaml -TK +name: Storybook Tests +on: deployment_status +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + if: github.event.deployment_status.state == 'success' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '18.x' + - name: Install dependencies + run: yarn + - name: Run Storybook tests + run: yarn test-storybook + env: + SB_URL: '${{ github.event.deployment_status.target_url }}' ``` ```js title="vitest.workspace.ts" -process.env.SB_URL +storybookTest({ + storybookScript: 'yarn storybook --ci', + storybookUrl: process.env.SB_URL +}), ``` ## Configuration Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. -In this example, the Default story will not be tested, and the Primary story will. +By default, the plugin will run all stories with the `test` tag. You can adjust this behavior by providing the [`tags` option](#tags) in the plugin configuration. This allows you to include, exclude, or skip stories based on their tags. -{/* TODO: Snippetize */} -```js title="Button.stories.tsx" -import { Button } from './Button' +In this example, we'll apply the `stable` tag to all of the Button component's stories, except for ExperimentalFeatureStory, which will have the `experimental` tag: -export default { - component: Button, - // 👇 Apply `test` tag to all stories in this file - tags: ['test'], -} +{/* prettier-ignore-start */} -export const Default = { - // 👇 Remove `test` tag from this story - tags: ['!test'], -} + -export const Primary = { - args: { primary: true } -} -``` - -By default, the plugin will run all stories with the `test` tag. You can adjust this behavior by providing the [`tags` option](#tags) in the plugin configuration. This allows you to include, exclude, or skip stories based on their tags. +{/* prettier-ignore-end */} -Here's an example of how you might configure the plugin to only run stories with the `test` and `spec` tags, while excluding stories with the `docs-only` tag: +To connect those tags to our test behavior, we can adjust the plugin configuration to exclude the `experimental` tag: {/* TODO: Snippetize */} ```js title="vitest.workspace.ts" @@ -208,8 +251,8 @@ Here's an example of how you might configure the plugin to only run stories with plugins: [ storybookTest({ tags: { - include: ['test', 'spec'], - exclude: ['docs-only'], + include: ['test'], + exclude: ['experimental'], }, }), ], @@ -222,11 +265,7 @@ If the same tag is in both the `include` and `exclude` arrays, the `exclude` beh ### How to ensure my tests can find assets in the public directory? -If your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the `publicDir` option in the Vitest configuration file. - -```ts -TK -``` +If your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the [`publicDir` option in the Vitest configuration file](https://vitejs.dev/config/shared-options.html#publicdir). ### How to debug my tests in Storybook? @@ -249,59 +288,55 @@ TK ### Why do we recommend browser mode? -``` -1. It’s a real browser environment. JSDom/HappyDom are simulations with shortcomings. -2. https://vitest.dev/guide/browser/#motivation -``` +Vitest's browser mode runs your tests in a real browser (Chromium, via Playwright, in the default configuration). The alternative is a simulated browser environment, like JSDom or HappyDom, which can have differences in behavior compared to a real browser. For UI components, which can often depend on browser APIs or features, running tests in a real browser is more accurate. + +For more, see [Vitest's guide on using browser mode effectively](https://vitest.dev/guide/browser/#motivation). ### How to use WebDriver instead of Playwright? -``` -https://vitest.dev/config/#browser-provider -``` +We recommend running tests in a browser using Playwright, but you can use WebDriverIO instead. To do so, you need to adjust the [browser provider in the Vitest configuration file](https://vitest.dev/config/#browser-provider). ### How to use a browser other than Chromium -``` -https://vitest.dev/config/#browser-46-name -``` +We recommend using Chromium, because it is most likely to best match the experience of a majority of your users. However, you can use other browsers by adjusting the [browser name in the Vitest configuration file](https://vitest.dev/config/#browser-name). Note that [Playwright and WebDriverIO support different browsers](https://vitest.dev/guide/browser/#browser-option-types). -### How is this different from the test runner? +### How is this different from the previous test runner? -``` -1. TR requires an SB instance to be running; this does not (except for debugging) -2. TR runs SB and listens to results; this transforms stories (using portable stories) into tests -3. TR is based on Jest; this is based on Vitest -4. This is more configurable and more simple than TR - 1. TR is always a separate command; this is just Vitest (`yarn test`) -5. This is faster than TR - 1. Needs benchmarks - 1. a sandbox run in our monorepo - 1. Vitest plugin: 1m 6s - 2. Test-runner: 1m 14s + SB build & publish time -``` +The [previous test runner](./test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. This plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Beyond that core difference, there are a few other distinctions: -### Why does the `add` command stop in some cases? +Additionally, the previous test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable. -TK +Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. ## API ### Exports -`@storybook/experimental-addon-vitest/plugin` +This addon contributes the following exports to Storybook: -TK +```js +import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' +``` + +#### `storybookTest` + +Type: `function` + +A [Vitest plugin](https://vitejs.dev/guide/api-plugin) that transforms your stories into tests. It accepts an [options object](#options) for configuration. ### Options +The plugin is configured using an options object. Here are the available properties: + #### `configDir` Type: `string` Default: `.storybook` -The directory where the Storybook configuration is located, relative to CWD. If not provided, the plugin will use `.storybook` in the current working directory. +The directory where the Storybook configuration is located, relative to the current working directory. + +If your [Storybook configuration](../configure/index.mdx) is not in the default location, you **must** specify the location here so the plugin can function correctly. #### `storybookScript` @@ -341,6 +376,6 @@ Default: Tags to include, exclude, or skip. These tags are defined as annotations in your story, meta, or preview. -- `include`: `string[]` - Tags to include. -- `exclude`: `string[]` - Tags to exclude. -- `skip`: `string[]` - Tags to skip. +- **`include`**: Stories with these tags will be tested +- **`exclude`**: Stories with these tags will not be tested, and will not be counted in the test results +- **`skip`**: Stories with these tags will not be tested, and will be counted in the test results From 877e4a335af93d57cf345467fd5aaff40a4ee5d7 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Wed, 21 Aug 2024 16:32:58 -0600 Subject: [PATCH 013/213] More updates --- ...vitest.mdx => test-runner-with-vitest.mdx} | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) rename docs/writing-tests/{addon-vitest.mdx => test-runner-with-vitest.mdx} (94%) diff --git a/docs/writing-tests/addon-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx similarity index 94% rename from docs/writing-tests/addon-vitest.mdx rename to docs/writing-tests/test-runner-with-vitest.mdx index 0f472f806364..ba8b3f46517d 100644 --- a/docs/writing-tests/addon-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -61,10 +61,31 @@ For some project setups, the `add` command may be unable to automate the plugin 1. Make sure Vitest is configured to use [browser mode](https://vitest.dev/guide/browser/). 1. If you're using Next.js, make sure you're using [`vite-plugin-storybook-nextjs`](https://github.com/storybookjs/vite-plugin-storybook-nextjs). 1. If you're using SvelteKit, make sure you're using `@storybook/sveltekit/vite`. -1. Create a [test setup file](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), `storybook.setup.ts`, in the root of your project. -1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. Here's an example: +1. Create a [test setup file](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), `.storybook/vitest.setup.ts`. +1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can reference examples, below. + +### Example configuration files + +Here are configuration files generated by the `add` command. You can use these as a reference when setting up your project. + +
+ Example Vitest setup file + +```ts title=".storybook/vitest.setup.ts" +import { beforeAll } from 'vitest'; +// Replace your-renderer with the renderer you are using (e.g., react, vue3, svelte, etc.) +import { setProjectAnnotations } from '@storybook/your-renderer'; +import * as projectAnnotations from './preview'; + +const project = setProjectAnnotations(projectAnnotations); + +beforeAll(project.beforeAll); +``` +
+ +
+ Example Vitest config file -{/* TODO: Nextjs & SvelteKit examples */} ```ts title="vitest.config.ts" import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from '../vite.config' @@ -88,35 +109,10 @@ export default mergeConfig( provider: 'playwright', headless: true, }, - setupFiles: ['./storybook.setup.ts'], - }) -) -``` - -### Example configuration files - -Here are configuration files generated by the `add` command. You can use these as a reference when setting up your project. - -
- Example Vitest setup file - -```ts title="storybook.setup.ts" -TK -``` -
- -
- Example Vitest config file - -```ts title="vitest.config.ts" -import { defineConfig, mergeConfig } from 'vitest/config' -import viteConfig from '../vite.config' -import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' - -export default mergeConfig( - viteConfig, - defineConfig({ - // ... TK + // Disabling isolation is faster and similar to how tests are isolated in Storybook itself. + // Consider removing this, if you have flaky tests. + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], }) ) ``` @@ -150,7 +146,10 @@ export default defineWorkspace([ provider: 'playwright', headless: true, }, - setupFiles: ['./storybook.setup.ts'], + // Disabling isolation is faster and similar to how tests are isolated in Storybook itself. + // Consider removing this, if you have flaky tests. + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], } ]) ``` From 8cdbbaf95adbbff8305fcb0b8127f32823e03533 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Mon, 26 Aug 2024 12:30:08 -0600 Subject: [PATCH 014/213] More polish --- docs/_snippets/addon-vitest-install.md | 11 +++ docs/_snippets/addon-vitest-run-tests.md | 11 +++ .../writing-tests/test-runner-with-vitest.mdx | 80 +++++++++++-------- 3 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 docs/_snippets/addon-vitest-install.md create mode 100644 docs/_snippets/addon-vitest-run-tests.md diff --git a/docs/_snippets/addon-vitest-install.md b/docs/_snippets/addon-vitest-install.md new file mode 100644 index 000000000000..d54a74ca17d1 --- /dev/null +++ b/docs/_snippets/addon-vitest-install.md @@ -0,0 +1,11 @@ +```shell renderer="common" language="js" packageManager="npx" +npx storybook@latest add @storybook/experimental-addon-vitest +``` + +```shell renderer="common" language="js" packageManager="pnpm" +pnpm dlx storybook@latest add @storybook/experimental-addon-vitest +``` + +```shell renderer="common" language="js" packageManager="yarn" +yarn dlx storybook@latest add @storybook/experimental-addon-vitest +``` diff --git a/docs/_snippets/addon-vitest-run-tests.md b/docs/_snippets/addon-vitest-run-tests.md new file mode 100644 index 000000000000..3b91e2d284ea --- /dev/null +++ b/docs/_snippets/addon-vitest-run-tests.md @@ -0,0 +1,11 @@ +```shell renderer="common" language="js" packageManager="npm" +npm run test +``` + +```shell renderer="common" language="js" packageManager="pnpm" +pnpm run test +``` + +```shell renderer="common" language="js" packageManager="yarn" +yarn test +``` diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index ba8b3f46517d..343a20555535 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -7,22 +7,25 @@ sidebar: (⚠️ **Experimental**) + + While this feature is experimental, it is published as the `@storybook/experimental-addon-vitest` package. + + Storybook's test runner with Vitest uses a Vitest plugin to transform your [stories](../writing-stories/index.mdx) into tests. You can then run those tests just like any other in Vitest, which will check that the story renders without errors and, if a [play function](../writing-stories/play-function.mdx) is defined, that it runs as expected and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. By using Vitest's browser mode, those tests are run in a real browser environment, which gives you more reliable results for UI components that commonly rely on browser APIs or features. -## Setup +## Install and set up + +Get started by upgrading to at least Storybook 8.3, then installing and configuring the plugin in your project. -Get started by installing and configuring the plugin in your project. + -### Automatic +### Automatic setup Run the following command to install and configure the addon, which contains the plugin to run your stories as tests using Vitest: -{/* TODO: Snippetize */} -```sh -npx storybook@latest add @storybook/experimental-addon-vitest -``` + That command will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them if necessary. @@ -52,7 +55,7 @@ export default defineConfig({ The configuration produced by the `add` command will attempt to set some sensible defaults for your project. However, you may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. -### Manual +### Manual setup For some project setups, the `add` command may be unable to automate the plugin setup and ask you to complete additional setup steps. Here's what to do: @@ -66,7 +69,7 @@ For some project setups, the `add` command may be unable to automate the plugin ### Example configuration files -Here are configuration files generated by the `add` command. You can use these as a reference when setting up your project. +Here are example configuration files generated by the `add` command. You can use these as a reference when setting up your project.
Example Vitest setup file @@ -171,7 +174,7 @@ While the plugin does not require Storybook to run when testing, you may still w You can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running. -TK - Screenshot of test output with links to SB +[TK - Screenshot of test output with links to SB] ## Usage @@ -181,16 +184,13 @@ There are three primary ways to run tests using the Vitest plugin: The plugin transforms your stories into real Vitest tests, so you run those tests just like you run any other Vitest tests in your project. Typically, you will have a `test` script in your `package.json` that runs Vitest. When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: -{/* TODO: Snippetize */} -```sh -npm run test -``` + ### Editor extension Transforming your stories into Vitest tests with the plugin also enables you to run and debug tests using Vitest [IDE integrations](https://vitest.dev/guide/ide.html). This allows you to run tests directly from your editor, such as VSCode and JetBrains IDE. -TK - Screenshot of VS Code +[TK - Screenshot of VS Code] ### In CI @@ -200,7 +200,7 @@ Here's an example using GitHub Actions. The steps are similar for other CI provi When actions for services like Vercel, Netlify and others run a deployment job, they follow a pattern of emitting a `deployment_status` event containing the newly generated URL under `deployment_status.target_url`. This is the URL to the published Storybook instance. We then pass that URL to the plugin configuration using an environment variable, `SB_URL`. Finally, we update the plugin configuration to use that environment variable in the `storybookUrl` option. -```yaml +```yaml title=".github/workflows/test-storybook.yml" name: Storybook Tests on: deployment_status jobs: @@ -222,10 +222,20 @@ jobs: ``` ```js title="vitest.workspace.ts" -storybookTest({ - storybookScript: 'yarn storybook --ci', - storybookUrl: process.env.SB_URL -}), +export default defineWorkspace([ + // ... + { + // ... + { + plugins: [ + storybookTest({ + storybookScript: 'yarn storybook --ci', + storybookUrl: process.env.SB_URL + }), + ], + }, + }, +]) ``` ## Configuration @@ -244,18 +254,24 @@ In this example, we'll apply the `stable` tag to all of the Button component's s To connect those tags to our test behavior, we can adjust the plugin configuration to exclude the `experimental` tag: -{/* TODO: Snippetize */} ```js title="vitest.workspace.ts" -{ - plugins: [ - storybookTest({ - tags: { - include: ['test'], - exclude: ['experimental'], - }, - }), - ], -} +export default defineWorkspace([ + // ... + { + // ... + { + plugins: [ + storybookTest({ + // ... + tags: { + include: ['test'], + exclude: ['experimental'], + }, + }), + ], + }, + }, +]) ``` If the same tag is in both the `include` and `exclude` arrays, the `exclude` behavior takes precedence. @@ -282,7 +298,7 @@ If the URLs are not working when running tests in CI, you should ensure the Stor If you have custom operations defined in [`viteFinal`](../api/main-config/main-config-vite-final.mdx) in your `.storybook/main.js|ts` file, you will need to translate those into the Vitest configuration. This is because the plugin does not use the Storybook Vite configuration. ```ts -TK +TK - Is there a good example we could offer here? ``` ### Why do we recommend browser mode? From b08238f919e8251fb238c4389ee414d71cd4f7d4 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 27 Aug 2024 15:16:43 +0200 Subject: [PATCH 015/213] no more lodash in core --- code/core/package.json | 3 +- .../core-server/utils/stories-json.test.ts | 6 +- .../src/core-server/utils/stories-json.ts | 2 +- .../argTypes/convert/convert.test.ts | 2 +- .../argTypes/convert/proptypes/convert.ts | 2 +- code/core/src/manager-api/lib/merge.ts | 60 +++++++++++++++++-- code/core/src/manager-api/lib/stories.ts | 7 +-- code/core/src/manager-api/modules/layout.ts | 18 +++--- .../src/manager-api/modules/notifications.ts | 2 +- code/core/src/manager-api/root.tsx | 12 +--- .../navigation/MobileNavigation.stories.tsx | 2 +- .../manager/components/preview/Preview.tsx | 2 +- .../manager/components/preview/Toolbar.tsx | 5 +- .../manager/components/sidebar/useExpanded.ts | 2 +- .../components/sidebar/useLastViewed.ts | 2 +- .../modules/preview-web/PreviewWeb.test.ts | 6 +- .../modules/preview-web/parseArgsParam.ts | 2 +- .../preview-api/modules/store/StoryStore.ts | 7 +-- .../src/preview-api/modules/store/args.ts | 3 +- .../modules/store/csf/normalizeInputTypes.ts | 2 +- .../modules/store/filterArgTypes.ts | 6 +- .../modules/store/inferArgTypes.ts | 2 +- .../modules/store/inferControls.ts | 4 +- .../preview-api/modules/store/parameters.ts | 2 +- code/core/src/router/utils.ts | 3 +- code/core/template/stories/args.stories.ts | 4 +- code/yarn.lock | 10 +++- 27 files changed, 114 insertions(+), 64 deletions(-) diff --git a/code/core/package.json b/code/core/package.json index d5f233d1eafc..6b6df37fa1b3 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -321,7 +321,6 @@ "@types/find-cache-dir": "^5.0.0", "@types/fs-extra": "^11.0.1", "@types/js-yaml": "^4.0.5", - "@types/lodash": "^4.14.167", "@types/node": "^22.0.0", "@types/npmlog": "^7.0.0", "@types/picomatch": "^2.3.0", @@ -360,6 +359,7 @@ "diff": "^5.2.0", "downshift": "^9.0.4", "ejs": "^3.1.10", + "es-toolkit": "^1.16.0", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", "esbuild-plugin-alias": "^0.2.1", "execa": "^8.0.1", @@ -380,7 +380,6 @@ "jsdoc-type-pratt-parser": "^4.0.0", "lazy-universal-dotenv": "^4.0.0", "leven": "^4.0.0", - "lodash": "^4.17.21", "markdown-to-jsx": "^7.4.5", "memfs": "^4.11.1", "memoizerific": "^1.11.3", diff --git a/code/core/src/core-server/utils/stories-json.test.ts b/code/core/src/core-server/utils/stories-json.test.ts index e9f5e73a7378..78ff3697c3d6 100644 --- a/code/core/src/core-server/utils/stories-json.test.ts +++ b/code/core/src/core-server/utils/stories-json.test.ts @@ -6,8 +6,8 @@ import { normalizeStoriesEntry } from '@storybook/core/common'; import { STORY_INDEX_INVALIDATED } from '@storybook/core/core-events'; +import { debounce } from 'es-toolkit'; import type { Request, Response, Router } from 'express'; -import debounce from 'lodash/debounce.js'; import Watchpack from 'watchpack'; import { csfIndexer } from '../presets/common-preset'; @@ -17,7 +17,7 @@ import type { ServerChannel } from './get-server-channel'; import { DEBOUNCE, useStoriesJson } from './stories-json'; vi.mock('watchpack'); -vi.mock('lodash/debounce'); +vi.mock('es-toolkit'); vi.mock('@storybook/core/node-logger'); const workingDir = join(__dirname, '__mockdata__'); @@ -472,7 +472,7 @@ describe('useStoriesJson', () => { it('debounces invalidation events', async () => { vi.mocked(debounce).mockImplementation( // @ts-expect-error it doesn't think default exists - (await vi.importActual('lodash/debounce.js')).default + (await vi.importActual('debounce')).default ); const mockServerChannel = { emit: vi.fn() } as any as ServerChannel; diff --git a/code/core/src/core-server/utils/stories-json.ts b/code/core/src/core-server/utils/stories-json.ts index 8956a4ed7ab1..21870aef79ad 100644 --- a/code/core/src/core-server/utils/stories-json.ts +++ b/code/core/src/core-server/utils/stories-json.ts @@ -4,9 +4,9 @@ import type { NormalizedStoriesSpecifier, StoryIndex } from '@storybook/core/typ import { STORY_INDEX_INVALIDATED } from '@storybook/core/core-events'; +import { debounce } from 'es-toolkit'; import type { Request, Response, Router } from 'express'; import { writeJSON } from 'fs-extra'; -import debounce from 'lodash/debounce.js'; import type { StoryIndexGenerator } from './StoryIndexGenerator'; import type { ServerChannel } from './get-server-channel'; diff --git a/code/core/src/docs-tools/argTypes/convert/convert.test.ts b/code/core/src/docs-tools/argTypes/convert/convert.test.ts index 25d1b04f01aa..11ca35291953 100644 --- a/code/core/src/docs-tools/argTypes/convert/convert.test.ts +++ b/code/core/src/docs-tools/argTypes/convert/convert.test.ts @@ -4,7 +4,7 @@ import { describe, expect, it } from 'vitest'; import { transformSync } from '@storybook/core/babel'; -import mapValues from 'lodash/mapValues.js'; +import { mapValues } from 'es-toolkit'; import requireFromString from 'require-from-string'; import { normalizeNewlines } from '../utils'; diff --git a/code/core/src/docs-tools/argTypes/convert/proptypes/convert.ts b/code/core/src/docs-tools/argTypes/convert/proptypes/convert.ts index 710ddfa449d5..c3426ecfd3e2 100644 --- a/code/core/src/docs-tools/argTypes/convert/proptypes/convert.ts +++ b/code/core/src/docs-tools/argTypes/convert/proptypes/convert.ts @@ -1,6 +1,6 @@ import type { SBType } from '@storybook/core/types'; -import mapValues from 'lodash/mapValues.js'; +import { mapValues } from 'es-toolkit'; import { parseLiteral } from '../utils'; import type { PTType } from './types'; diff --git a/code/core/src/manager-api/lib/merge.ts b/code/core/src/manager-api/lib/merge.ts index ec4c474942b0..6dc618ade6db 100644 --- a/code/core/src/manager-api/lib/merge.ts +++ b/code/core/src/manager-api/lib/merge.ts @@ -1,10 +1,13 @@ import { logger } from '@storybook/core/client-logger'; -import isEqual from 'lodash/isEqual.js'; -import mergeWith from 'lodash/mergeWith.js'; +import { isEqual, mergeWith } from 'es-toolkit'; -export default (a: TObj, b: Partial) => - mergeWith({}, a, b, (objValue: TObj, srcValue: Partial) => { +export default (a: TObj, ...b: Partial[]): TObj => { + // start with empty object + let target = {}; + + // merge object a unto target + target = mergeWith({}, a, (objValue: TObj, srcValue: Partial) => { if (Array.isArray(srcValue) && Array.isArray(objValue)) { srcValue.forEach((s) => { const existing = objValue.find((o) => o === s || isEqual(o, s)); @@ -19,5 +22,52 @@ export default (a: TObj, b: Partial) => logger.log(['the types mismatch, picking', objValue]); return objValue; } - return undefined; }); + + for (const obj of b) { + // merge object b unto target + target = mergeWith(target, obj, (objValue: TObj, srcValue: Partial) => { + if (Array.isArray(srcValue) && Array.isArray(objValue)) { + srcValue.forEach((s) => { + const existing = objValue.find((o) => o === s || isEqual(o, s)); + if (!existing) { + objValue.push(s); + } + }); + + return objValue; + } + if (Array.isArray(objValue)) { + logger.log(['the types mismatch, picking', objValue]); + return objValue; + } + }); + } + + return target as TObj; +}; + +export const noArrayMerge = (a: TObj, ...b: Partial[]): TObj => { + // start with empty object + let target = {}; + + // merge object a unto target + target = mergeWith({}, a, (objValue: TObj, srcValue: Partial) => { + // Treat arrays as scalars: + if (Array.isArray(srcValue)) { + return srcValue; + } + }); + + for (const obj of b) { + // merge object b unto target + target = mergeWith(target, obj, (objValue: TObj, srcValue: Partial) => { + // Treat arrays as scalars: + if (Array.isArray(srcValue)) { + return srcValue; + } + }); + } + + return target as TObj; +}; diff --git a/code/core/src/manager-api/lib/stories.ts b/code/core/src/manager-api/lib/stories.ts index a4ff209c3249..556acba0076d 100644 --- a/code/core/src/manager-api/lib/stories.ts +++ b/code/core/src/manager-api/lib/stories.ts @@ -19,8 +19,7 @@ import type { } from '@storybook/core/types'; import { sanitize } from '@storybook/csf'; -import countBy from 'lodash/countBy.js'; -import mapValues from 'lodash/mapValues.js'; +import { countBy, mapValues } from 'es-toolkit'; import memoize from 'memoizerific'; import { dedent } from 'ts-dedent'; @@ -41,7 +40,7 @@ export const denormalizeStoryParameters = ({ kindParameters[storyData.kind], storyData.parameters as unknown as Parameters ), - })); + })) as SetStoriesStoryData; }; export const transformSetStoriesStoryDataToStoriesHash = ( @@ -112,7 +111,7 @@ export const transformStoryIndexV2toV3 = (index: StoryIndexV2): StoryIndexV3 => }; export const transformStoryIndexV3toV4 = (index: StoryIndexV3): API_PreparedStoryIndex => { - const countByTitle = countBy(Object.values(index.stories), 'title'); + const countByTitle = countBy(Object.values(index.stories), (item) => item.title); return { v: 4, entries: Object.values(index.stories).reduce( diff --git a/code/core/src/manager-api/modules/layout.ts b/code/core/src/manager-api/modules/layout.ts index 642f78fc5813..71b5523e2969 100644 --- a/code/core/src/manager-api/modules/layout.ts +++ b/code/core/src/manager-api/modules/layout.ts @@ -5,8 +5,7 @@ import { global } from '@storybook/global'; import { SET_CONFIG } from '@storybook/core/core-events'; -import { dequal as deepEqual } from 'dequal'; -import pick from 'lodash/pick.js'; +import { isEqual as deepEqual, pick, toMerged } from 'es-toolkit'; import merge from '../lib/merge'; import type { ModuleFn } from '../lib/types'; @@ -320,12 +319,15 @@ export const init: ModuleFn = ({ store, provider, singleStory ...defaultLayoutState, layout: { ...defaultLayoutState.layout, - ...pick(options, Object.keys(defaultLayoutState.layout)), + ...toMerged( + defaultLayoutState.layout, + pick(options, Object.keys(defaultLayoutState.layout)) + ), ...(singleStory && { navSize: 0 }), }, ui: { ...defaultLayoutState.ui, - ...pick(options, Object.keys(defaultLayoutState.ui)), + ...toMerged(defaultLayoutState.ui, pick(options, Object.keys(defaultLayoutState.ui))), }, selectedPanel: selectedPanel || defaultLayoutState.selectedPanel, theme: theme || defaultLayoutState.theme, @@ -351,15 +353,15 @@ export const init: ModuleFn = ({ store, provider, singleStory const updatedLayout = { ...layout, - ...options.layout, - ...pick(options, Object.keys(layout)), + ...(options.layout || {}), + ...toMerged(options.layout || {}, pick(options, Object.keys(layout))), ...(singleStory && { navSize: 0 }), }; const updatedUi = { ...ui, ...options.ui, - ...pick(options, Object.keys(ui)), + ...toMerged(options.ui, pick(options, Object.keys(ui))), }; const updatedTheme = { @@ -388,7 +390,7 @@ export const init: ModuleFn = ({ store, provider, singleStory }, }; - const persisted = pick(store.getState(), 'layout', 'selectedPanel'); + const persisted = pick(store.getState(), ['layout', 'selectedPanel']); provider.channel?.on(SET_CONFIG, () => { api.setOptions(merge(api.getInitialOptions(), persisted)); diff --git a/code/core/src/manager-api/modules/notifications.ts b/code/core/src/manager-api/modules/notifications.ts index cda1025001ae..c1410cfbeb78 100644 --- a/code/core/src/manager-api/modules/notifications.ts +++ b/code/core/src/manager-api/modules/notifications.ts @@ -1,6 +1,6 @@ import type { API_Notification } from '@storybook/core/types'; -import partition from 'lodash/partition.js'; +import { partition } from 'es-toolkit'; import type { ModuleFn } from '../lib/types'; diff --git a/code/core/src/manager-api/root.tsx b/code/core/src/manager-api/root.tsx index bf992f1907a8..1c150b47f4b3 100644 --- a/code/core/src/manager-api/root.tsx +++ b/code/core/src/manager-api/root.tsx @@ -41,11 +41,12 @@ import { STORY_CHANGED, } from '@storybook/core/core-events'; -import mergeWith from 'lodash/mergeWith.js'; +import { mergeWith } from 'es-toolkit'; import { createContext } from './context'; import getInitialState from './initial-state'; import { types } from './lib/addons'; +import { noArrayMerge } from './lib/merge'; import type { ModuleFn } from './lib/types'; import * as addons from './modules/addons'; import * as channel from './modules/channel'; @@ -129,14 +130,7 @@ export type ManagerProviderProps = RouterData & // This is duplicated from @storybook/preview-api for the reasons mentioned in lib-addons/types.js export const combineParameters = (...parameterSets: Parameters[]) => - mergeWith({}, ...parameterSets, (objValue: any, srcValue: any) => { - // Treat arrays as scalars: - if (Array.isArray(srcValue)) { - return srcValue; - } - - return undefined; - }); + noArrayMerge({}, ...parameterSets); class ManagerProvider extends Component { api: API = {} as API; diff --git a/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx b/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx index e445d73dea23..37e18b66a1fe 100644 --- a/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx +++ b/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx @@ -5,7 +5,7 @@ import { within } from '@storybook/test'; import { ManagerContext } from '@storybook/core/manager-api'; -import { startCase } from 'lodash'; +import { startCase } from 'es-toolkit'; import { LayoutProvider, useLayout } from '../../layout/LayoutProvider'; import { MobileNavigation } from './MobileNavigation'; diff --git a/code/core/src/manager/components/preview/Preview.tsx b/code/core/src/manager/components/preview/Preview.tsx index 8a459276f0e7..ed73a059951f 100644 --- a/code/core/src/manager/components/preview/Preview.tsx +++ b/code/core/src/manager/components/preview/Preview.tsx @@ -202,7 +202,7 @@ export function filterTabs(panels: Addon_BaseType[], parameters?: Record ({ index, ...(typeof tabs[key] === 'string' ? { title: tabs[key] } : tabs[key]), diff --git a/code/core/src/manager/components/preview/Toolbar.tsx b/code/core/src/manager/components/preview/Toolbar.tsx index 2f81f309435d..5dd460e80e69 100644 --- a/code/core/src/manager/components/preview/Toolbar.tsx +++ b/code/core/src/manager/components/preview/Toolbar.tsx @@ -188,7 +188,10 @@ function toolbarItemHasBeenExcluded(item: Partial, entry: LeafEn const toolbarItemsFromStoryParameters = 'toolbar' in parameters ? parameters.toolbar : undefined; const { toolbar: toolbarItemsFromAddonsConfig } = addons.getConfig(); - const toolbarItems = merge(toolbarItemsFromAddonsConfig, toolbarItemsFromStoryParameters); + const toolbarItems = merge( + toolbarItemsFromAddonsConfig || {}, + toolbarItemsFromStoryParameters || {} + ); // @ts-expect-error (non strict) return toolbarItems ? !!toolbarItems[item?.id]?.hidden : false; diff --git a/code/core/src/manager/components/sidebar/useExpanded.ts b/code/core/src/manager/components/sidebar/useExpanded.ts index 5f9a479b3308..e216c2b2e0cc 100644 --- a/code/core/src/manager/components/sidebar/useExpanded.ts +++ b/code/core/src/manager/components/sidebar/useExpanded.ts @@ -7,7 +7,7 @@ import { STORIES_COLLAPSE_ALL, STORIES_EXPAND_ALL } from '@storybook/core/core-e import type { StoriesHash } from '@storybook/core/manager-api'; import { useStorybookApi } from '@storybook/core/manager-api'; -import throttle from 'lodash/throttle.js'; +import { throttle } from 'es-toolkit'; import { matchesKeyCode, matchesModifiers } from '../../keybinding'; import { getAncestorIds, getDescendantIds, isAncestor, scrollIntoView } from '../../utils/tree'; diff --git a/code/core/src/manager/components/sidebar/useLastViewed.ts b/code/core/src/manager/components/sidebar/useLastViewed.ts index da53f6645ba3..e4132d6f8f3a 100644 --- a/code/core/src/manager/components/sidebar/useLastViewed.ts +++ b/code/core/src/manager/components/sidebar/useLastViewed.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; -import debounce from 'lodash/debounce.js'; +import { debounce } from 'es-toolkit'; import store from 'store2'; import type { Selection, StoryRef } from './types'; diff --git a/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts b/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts index 7994173c2d07..3e31095abc27 100644 --- a/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts +++ b/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts @@ -31,7 +31,7 @@ import { UPDATE_STORY_ARGS, } from '@storybook/core/core-events'; -import merge from 'lodash/merge.js'; +import { merge, toMerged } from 'es-toolkit'; import { addons } from '../addons'; import type { StoryStore } from '../store'; @@ -2927,7 +2927,7 @@ describe('PreviewWeb', () => { }); describe('when the current story changes', () => { - const newComponentOneExports = merge({}, componentOneExports, { + const newComponentOneExports = toMerged(componentOneExports, { a: { args: { foo: 'edited' } }, }); const newImportFn = vi.fn(async (path) => { @@ -3282,7 +3282,7 @@ describe('PreviewWeb', () => { afterEach(() => { vi.useRealTimers(); }); - const newComponentOneExports = merge({}, componentOneExports, { + const newComponentOneExports = toMerged(componentOneExports, { a: { args: { bar: 'edited' }, argTypes: { bar: { type: { name: 'string' } } } }, }); const newImportFn = vi.fn(async (path) => { diff --git a/code/core/src/preview-api/modules/preview-web/parseArgsParam.ts b/code/core/src/preview-api/modules/preview-web/parseArgsParam.ts index 6cdffe7eae10..75be5bfb57e2 100644 --- a/code/core/src/preview-api/modules/preview-web/parseArgsParam.ts +++ b/code/core/src/preview-api/modules/preview-web/parseArgsParam.ts @@ -2,7 +2,7 @@ import type { Args } from '@storybook/core/types'; import { once } from '@storybook/core/client-logger'; -import isPlainObject from 'lodash/isPlainObject.js'; +import { isPlainObject } from 'es-toolkit'; import qs from 'qs'; import { dedent } from 'ts-dedent'; diff --git a/code/core/src/preview-api/modules/store/StoryStore.ts b/code/core/src/preview-api/modules/store/StoryStore.ts index 510373177fa9..6e753905ee04 100644 --- a/code/core/src/preview-api/modules/store/StoryStore.ts +++ b/code/core/src/preview-api/modules/store/StoryStore.ts @@ -31,8 +31,7 @@ import { MissingStoryFromCsfFileError, } from '@storybook/core/preview-errors'; -import mapValues from 'lodash/mapValues.js'; -import pick from 'lodash/pick.js'; +import { mapValues, pick, toMerged } from 'es-toolkit'; import memoize from 'memoizerific'; import { HooksContext } from '../addons'; @@ -354,7 +353,7 @@ export class StoryStore { const stories: Record = mapValues(value.stories, (story) => { const { importPath } = this.storyIndex.entries[story.id]; return { - ...pick(story, ['id', 'name', 'title']), + ...toMerged({}, pick(story, ['id', 'name', 'title'])), importPath, // These 3 fields were going to be dropped in v7, but instead we will keep them for the // 7.x cycle so that v7 Storybooks can be composed successfully in v6 Storybook. @@ -362,7 +361,7 @@ export class StoryStore { kind: story.title, story: story.name, parameters: { - ...pick(story.parameters, allowedParameters), + ...toMerged({}, pick(story.parameters, allowedParameters)), fileName: importPath, }, }; diff --git a/code/core/src/preview-api/modules/store/args.ts b/code/core/src/preview-api/modules/store/args.ts index e34df974c42c..ea678dd4d2df 100644 --- a/code/core/src/preview-api/modules/store/args.ts +++ b/code/core/src/preview-api/modules/store/args.ts @@ -9,8 +9,7 @@ import type { import { once } from '@storybook/core/client-logger'; -import { dequal as deepEqual } from 'dequal'; -import isPlainObject from 'lodash/isPlainObject.js'; +import { isEqual as deepEqual, isPlainObject } from 'es-toolkit'; import { dedent } from 'ts-dedent'; const INCOMPATIBLE = Symbol('incompatible'); diff --git a/code/core/src/preview-api/modules/store/csf/normalizeInputTypes.ts b/code/core/src/preview-api/modules/store/csf/normalizeInputTypes.ts index d0bdaabdfe1b..f4685dc83090 100644 --- a/code/core/src/preview-api/modules/store/csf/normalizeInputTypes.ts +++ b/code/core/src/preview-api/modules/store/csf/normalizeInputTypes.ts @@ -7,7 +7,7 @@ import type { StrictInputType, } from '@storybook/core/types'; -import mapValues from 'lodash/mapValues.js'; +import { mapValues } from 'es-toolkit'; const normalizeType = (type: InputType['type']): StrictInputType['type'] => { return typeof type === 'string' ? { name: type } : type; diff --git a/code/core/src/preview-api/modules/store/filterArgTypes.ts b/code/core/src/preview-api/modules/store/filterArgTypes.ts index 274489a67cf4..16c2dd3a6c51 100644 --- a/code/core/src/preview-api/modules/store/filterArgTypes.ts +++ b/code/core/src/preview-api/modules/store/filterArgTypes.ts @@ -1,6 +1,6 @@ import type { StrictArgTypes } from '@storybook/core/types'; -import pickBy from 'lodash/pickBy.js'; +import { pickBy } from 'es-toolkit'; export type PropDescriptor = string[] | RegExp; @@ -18,8 +18,8 @@ export const filterArgTypes = ( return ( argTypes && pickBy(argTypes, (argType, key) => { - const name = argType.name || key; - return (!include || matches(name, include)) && (!exclude || !matches(name, exclude)); + const name = argType.name || key.toString(); + return !!(!include || matches(name, include)) && (!exclude || !matches(name, exclude)); }) ); }; diff --git a/code/core/src/preview-api/modules/store/inferArgTypes.ts b/code/core/src/preview-api/modules/store/inferArgTypes.ts index ea8b45b75609..007b4971a173 100644 --- a/code/core/src/preview-api/modules/store/inferArgTypes.ts +++ b/code/core/src/preview-api/modules/store/inferArgTypes.ts @@ -2,7 +2,7 @@ import type { ArgTypesEnhancer, Renderer, SBType } from '@storybook/core/types'; import { logger } from '@storybook/core/client-logger'; -import mapValues from 'lodash/mapValues.js'; +import { mapValues } from 'es-toolkit'; import { dedent } from 'ts-dedent'; import { combineParameters } from './parameters'; diff --git a/code/core/src/preview-api/modules/store/inferControls.ts b/code/core/src/preview-api/modules/store/inferControls.ts index b4408d85921f..92447845cc92 100644 --- a/code/core/src/preview-api/modules/store/inferControls.ts +++ b/code/core/src/preview-api/modules/store/inferControls.ts @@ -7,7 +7,7 @@ import type { import { logger } from '@storybook/core/client-logger'; -import mapValues from 'lodash/mapValues.js'; +import { mapValues } from 'es-toolkit'; import { filterArgTypes } from './filterArgTypes'; import { combineParameters } from './parameters'; @@ -77,7 +77,7 @@ export const inferControls: ArgTypesEnhancer = (context) => { const filteredArgTypes = filterArgTypes(argTypes, include, exclude); const withControls = mapValues(filteredArgTypes, (argType, name) => { - return argType?.type && inferControl(argType, name, matchers); + return argType?.type && inferControl(argType, name.toString(), matchers); }); return combineParameters(withControls, filteredArgTypes); diff --git a/code/core/src/preview-api/modules/store/parameters.ts b/code/core/src/preview-api/modules/store/parameters.ts index 43dee876d71b..3b6077614801 100644 --- a/code/core/src/preview-api/modules/store/parameters.ts +++ b/code/core/src/preview-api/modules/store/parameters.ts @@ -1,7 +1,7 @@ // Utilities for handling parameters import type { Parameters } from '@storybook/core/types'; -import isPlainObject from 'lodash/isPlainObject.js'; +import { isPlainObject } from 'es-toolkit'; /** * Safely combine parameters recursively. Only copy objects when needed. Algorithm = always diff --git a/code/core/src/router/utils.ts b/code/core/src/router/utils.ts index 3859668c175e..c9cb79852661 100644 --- a/code/core/src/router/utils.ts +++ b/code/core/src/router/utils.ts @@ -1,7 +1,6 @@ import { once } from '@storybook/core/client-logger'; -import { dequal as deepEqual } from 'dequal'; -import isPlainObject from 'lodash/isPlainObject.js'; +import { isEqual as deepEqual, isPlainObject } from 'es-toolkit'; import memoize from 'memoizerific'; import type { IStringifyOptions } from 'qs'; import qs from 'qs'; diff --git a/code/core/template/stories/args.stories.ts b/code/core/template/stories/args.stories.ts index 4f3b766b5a30..b861f9cbb910 100644 --- a/code/core/template/stories/args.stories.ts +++ b/code/core/template/stories/args.stories.ts @@ -8,7 +8,7 @@ import { UPDATE_STORY_ARGS, } from '@storybook/core/core-events'; -import pick from 'lodash/pick'; +import { pick, toMerged } from 'es-toolkit'; export default { component: globalThis.Components.Pre, @@ -26,7 +26,7 @@ export default { (storyFn: PartialStoryFn, context: StoryContext) => { const { argNames } = context.parameters; const args = { ...context.args }; - const object = argNames ? pick(args, argNames) : args; + const object = argNames ? toMerged({}, pick(args, argNames)) : args; return storyFn({ args: { object } }); }, ], diff --git a/code/yarn.lock b/code/yarn.lock index 900a35673a5f..622e3c9f8213 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5932,7 +5932,6 @@ __metadata: "@types/find-cache-dir": "npm:^5.0.0" "@types/fs-extra": "npm:^11.0.1" "@types/js-yaml": "npm:^4.0.5" - "@types/lodash": "npm:^4.14.167" "@types/node": "npm:^22.0.0" "@types/npmlog": "npm:^7.0.0" "@types/picomatch": "npm:^2.3.0" @@ -5972,6 +5971,7 @@ __metadata: diff: "npm:^5.2.0" downshift: "npm:^9.0.4" ejs: "npm:^3.1.10" + es-toolkit: "npm:^1.16.0" esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0" esbuild-plugin-alias: "npm:^0.2.1" esbuild-register: "npm:^3.5.0" @@ -5993,7 +5993,6 @@ __metadata: jsdoc-type-pratt-parser: "npm:^4.0.0" lazy-universal-dotenv: "npm:^4.0.0" leven: "npm:^4.0.0" - lodash: "npm:^4.17.21" markdown-to-jsx: "npm:^7.4.5" memfs: "npm:^4.11.1" memoizerific: "npm:^1.11.3" @@ -13969,6 +13968,13 @@ __metadata: languageName: node linkType: hard +"es-toolkit@npm:^1.16.0": + version: 1.16.0 + resolution: "es-toolkit@npm:1.16.0" + checksum: 10c0/d2dc29a049e24583d31e5a4b3772ee157b598aaf99bb886d650c1bf52c2d7342101f5b52dbed663c39232f34eec59cade15d1b2c422df1489fa8f033b7be73ae + languageName: node + linkType: hard + "es6-promise@npm:^3.1.2": version: 3.3.1 resolution: "es6-promise@npm:3.3.1" From 74a0353fb77f5092697a72f97dd87f4afe99d5a9 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 27 Aug 2024 16:18:25 +0200 Subject: [PATCH 016/213] fixes --- code/core/src/core-server/utils/stories-json.ts | 4 +--- .../src/preview-api/modules/preview-web/PreviewWeb.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/core/src/core-server/utils/stories-json.ts b/code/core/src/core-server/utils/stories-json.ts index 21870aef79ad..9dd0005cdcb6 100644 --- a/code/core/src/core-server/utils/stories-json.ts +++ b/code/core/src/core-server/utils/stories-json.ts @@ -40,9 +40,7 @@ export function useStoriesJson({ configDir?: string; normalizedStories: NormalizedStoriesSpecifier[]; }) { - const maybeInvalidate = debounce(() => serverChannel.emit(STORY_INDEX_INVALIDATED), DEBOUNCE, { - leading: true, - }); + const maybeInvalidate = debounce(() => serverChannel.emit(STORY_INDEX_INVALIDATED), DEBOUNCE, {}); watchStorySpecifiers(normalizedStories, { workingDir }, async (specifier, path, removed) => { const generator = await initializedStoryIndexGenerator; generator.invalidate(specifier, path, removed); diff --git a/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts b/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts index 3e31095abc27..57e3b0357a44 100644 --- a/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts +++ b/code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts @@ -308,7 +308,7 @@ describe('PreviewWeb', () => { expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--missing'); mockChannel.emit.mockClear(); - const newComponentOneExports = merge({}, componentOneExports, { + const newComponentOneExports = toMerged(componentOneExports, { d: { args: { foo: 'd' }, play: vi.fn() }, }); const newImportFn = vi.fn(async (path) => { @@ -362,7 +362,7 @@ describe('PreviewWeb', () => { }); await waitForSetCurrentStory(); - const newComponentOneExports = merge({}, componentOneExports, { + const newComponentOneExports = toMerged(componentOneExports, { d: { args: { foo: 'd' }, play: vi.fn() }, }); const newImportFn = vi.fn(async (path) => { From 5d06f4d7507e6a866408efe83228bd2e7017e317 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 27 Aug 2024 09:02:09 -0600 Subject: [PATCH 017/213] Apply suggestions from code review Co-authored-by: Kasper Peulen --- docs/writing-tests/test-runner-with-vitest.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index 343a20555535..aaa24c3b58f8 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -91,7 +91,7 @@ beforeAll(project.beforeAll); ```ts title="vitest.config.ts" import { defineConfig, mergeConfig } from 'vitest/config' -import viteConfig from '../vite.config' +import viteConfig from './vite.config' import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' export default mergeConfig( @@ -103,7 +103,7 @@ export default mergeConfig( }), ], // Glob pattern to find story files - include: ['../src/**/*.stories.?(m)[jt]s?(x)'], + include: ['src/**/*.stories.?(m)[jt]s?(x)'], // Enable browser mode browser: { enabled: true, @@ -140,7 +140,7 @@ export default defineWorkspace([ }), ], // Glob pattern to find story files - include: ['../src/**/*.stories.?(m)[jt]s?(x)'], + include: ['src/**/*.stories.?(m)[jt]s?(x)'], // Enable browser mode browser: { enabled: true, From 4aeab563118f47f575088ef92f450b88a9be247d Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 27 Aug 2024 09:52:16 -0600 Subject: [PATCH 018/213] Further updates --- docs/_snippets/addon-vitest-install.md | 6 ++-- .../writing-tests/test-runner-with-vitest.mdx | 34 +++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/docs/_snippets/addon-vitest-install.md b/docs/_snippets/addon-vitest-install.md index d54a74ca17d1..06a229138d18 100644 --- a/docs/_snippets/addon-vitest-install.md +++ b/docs/_snippets/addon-vitest-install.md @@ -1,11 +1,11 @@ ```shell renderer="common" language="js" packageManager="npx" -npx storybook@latest add @storybook/experimental-addon-vitest +npx storybook add @storybook/experimental-addon-vitest ``` ```shell renderer="common" language="js" packageManager="pnpm" -pnpm dlx storybook@latest add @storybook/experimental-addon-vitest +pnpm exec storybook add @storybook/experimental-addon-vitest ``` ```shell renderer="common" language="js" packageManager="yarn" -yarn dlx storybook@latest add @storybook/experimental-addon-vitest +yarn exec storybook add @storybook/experimental-addon-vitest ``` diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index aaa24c3b58f8..ee470d740622 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -130,10 +130,12 @@ import { defineWorkspace } from 'vitest/config' import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' export default defineWorkspace([ - // This is the path to your existing Vitest config files + // This is the path to your existing Vitest config file './vitest.config.ts', { name: 'storybook', + // This is the path to your existing Vite config file + extends: './vite.config.ts', plugins: [ storybookTest({ storybookScript: 'yarn storybook --ci', @@ -182,7 +184,29 @@ There are three primary ways to run tests using the Vitest plugin: ### CLI -The plugin transforms your stories into real Vitest tests, so you run those tests just like you run any other Vitest tests in your project. Typically, you will have a `test` script in your `package.json` that runs Vitest. When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: +The plugin transforms your stories into real Vitest tests, so you run those tests just like you run any other Vitest tests in your project. Typically, you will have a `test` script in your `package.json` that runs your tests. + +If you don't already have a `test` script, you can add one that runs Vitest: + +```json title="package.json" +{ + "scripts": { + "test": "vitest" + } +} +``` + +If you already have a `test` script that runs something other than Vitest, you can either adjust it to run Vitest (as above) or add a new script that runs Vitest: + +```json title="package.json" +{ + "scripts": { + "test-storybook": "vitest" + } +} +``` + +When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: @@ -323,6 +347,12 @@ Additionally, the previous test runner ran your stories as orchestrated tests in Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. +### How to isolate Storybook tests from others? + +Some projects might contain a `test` property in their Vite configuration. Because the Vitest configuration used by this plugin extends that Vite config, the `test` properties are merged. This lack of isolation can cause issues with your Storybook tests. + +To isolate your Storybook tests from other tests, you need to move the `test` property from your Vite configuration to the Vitest configuration. The Vitest config used by the plugin can then safely extend your Vite config without merging the `test` property. + ## API ### Exports From f1f4724be226e7e924c313ffb90320a267f5b71f Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 27 Aug 2024 17:54:42 +0200 Subject: [PATCH 019/213] wip --- .../core/src/core-server/utils/stories-json.test.ts | 3 +-- code/core/src/manager-api/lib/merge.ts | 9 ++++++++- code/core/src/manager-api/modules/layout.ts | 8 ++++---- .../src/preview-api/modules/store/StoryStore.ts | 13 ++++++++++--- code/core/template/stories/args.stories.ts | 10 ++++++++-- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/code/core/src/core-server/utils/stories-json.test.ts b/code/core/src/core-server/utils/stories-json.test.ts index 78ff3697c3d6..9e876dd8d93f 100644 --- a/code/core/src/core-server/utils/stories-json.test.ts +++ b/code/core/src/core-server/utils/stories-json.test.ts @@ -471,8 +471,7 @@ describe('useStoriesJson', () => { it('debounces invalidation events', async () => { vi.mocked(debounce).mockImplementation( - // @ts-expect-error it doesn't think default exists - (await vi.importActual('debounce')).default + (await vi.importActual('es-toolkit')).debounce ); const mockServerChannel = { emit: vi.fn() } as any as ServerChannel; diff --git a/code/core/src/manager-api/lib/merge.ts b/code/core/src/manager-api/lib/merge.ts index 6dc618ade6db..92ada66badba 100644 --- a/code/core/src/manager-api/lib/merge.ts +++ b/code/core/src/manager-api/lib/merge.ts @@ -1,6 +1,6 @@ import { logger } from '@storybook/core/client-logger'; -import { isEqual, mergeWith } from 'es-toolkit'; +import { isEqual, mergeWith, omitBy, pick } from 'es-toolkit'; export default (a: TObj, ...b: Partial[]): TObj => { // start with empty object @@ -71,3 +71,10 @@ export const noArrayMerge = (a: TObj, ...b: Partial[]): TObj = return target as TObj; }; + +export function picky, K extends keyof T>( + obj: T, + keys: K[] +): Partial> { + return omitBy(pick(obj, keys), (v) => v === undefined); +} diff --git a/code/core/src/manager-api/modules/layout.ts b/code/core/src/manager-api/modules/layout.ts index 71b5523e2969..b90d552f4478 100644 --- a/code/core/src/manager-api/modules/layout.ts +++ b/code/core/src/manager-api/modules/layout.ts @@ -5,9 +5,9 @@ import { global } from '@storybook/global'; import { SET_CONFIG } from '@storybook/core/core-events'; -import { isEqual as deepEqual, pick, toMerged } from 'es-toolkit'; +import { isEqual as deepEqual, omitBy, pick, toMerged } from 'es-toolkit'; -import merge from '../lib/merge'; +import merge, { picky } from '../lib/merge'; import type { ModuleFn } from '../lib/types'; import type { State } from '../root'; @@ -354,14 +354,14 @@ export const init: ModuleFn = ({ store, provider, singleStory const updatedLayout = { ...layout, ...(options.layout || {}), - ...toMerged(options.layout || {}, pick(options, Object.keys(layout))), + ...picky(options, Object.keys(layout)), ...(singleStory && { navSize: 0 }), }; const updatedUi = { ...ui, ...options.ui, - ...toMerged(options.ui, pick(options, Object.keys(ui))), + ...toMerged(options.ui || {}, picky(options, Object.keys(ui))), }; const updatedTheme = { diff --git a/code/core/src/preview-api/modules/store/StoryStore.ts b/code/core/src/preview-api/modules/store/StoryStore.ts index 6e753905ee04..0d129f65400a 100644 --- a/code/core/src/preview-api/modules/store/StoryStore.ts +++ b/code/core/src/preview-api/modules/store/StoryStore.ts @@ -31,7 +31,7 @@ import { MissingStoryFromCsfFileError, } from '@storybook/core/preview-errors'; -import { mapValues, pick, toMerged } from 'es-toolkit'; +import { mapValues, omitBy, pick, toMerged } from 'es-toolkit'; import memoize from 'memoizerific'; import { HooksContext } from '../addons'; @@ -46,6 +46,13 @@ import { processCSFFile, } from './csf'; +export function picky, K extends keyof T>( + obj: T, + keys: K[] +): Partial> { + return omitBy(pick(obj, keys), (v) => v === undefined); +} + // TODO -- what are reasonable values for these? const CSF_CACHE_SIZE = 1000; const STORY_CACHE_SIZE = 10000; @@ -353,7 +360,7 @@ export class StoryStore { const stories: Record = mapValues(value.stories, (story) => { const { importPath } = this.storyIndex.entries[story.id]; return { - ...toMerged({}, pick(story, ['id', 'name', 'title'])), + ...picky(story, ['id', 'name', 'title']), importPath, // These 3 fields were going to be dropped in v7, but instead we will keep them for the // 7.x cycle so that v7 Storybooks can be composed successfully in v6 Storybook. @@ -361,7 +368,7 @@ export class StoryStore { kind: story.title, story: story.name, parameters: { - ...toMerged({}, pick(story.parameters, allowedParameters)), + ...picky(story.parameters, allowedParameters), fileName: importPath, }, }; diff --git a/code/core/template/stories/args.stories.ts b/code/core/template/stories/args.stories.ts index b861f9cbb910..4c83a98ca0ae 100644 --- a/code/core/template/stories/args.stories.ts +++ b/code/core/template/stories/args.stories.ts @@ -8,7 +8,13 @@ import { UPDATE_STORY_ARGS, } from '@storybook/core/core-events'; -import { pick, toMerged } from 'es-toolkit'; +function pick(obj, keys) { + const result = {}; + for (const key of keys) { + result[key] = obj[key]; + } + return result; +} export default { component: globalThis.Components.Pre, @@ -26,7 +32,7 @@ export default { (storyFn: PartialStoryFn, context: StoryContext) => { const { argNames } = context.parameters; const args = { ...context.args }; - const object = argNames ? toMerged({}, pick(args, argNames)) : args; + const object = argNames ? pick(args, argNames) : args; return storyFn({ args: { object } }); }, ], From e6d7ac5f56d04e9aac19ef68d8fc7ae7bdb99dc7 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Tue, 27 Aug 2024 20:14:51 +0200 Subject: [PATCH 020/213] Builder-Vite: Fix missing source map warning --- .../src/codegen-modern-iframe-script.ts | 3 ++- .../src/plugins/code-generator-plugin.ts | 23 +++++++++++-------- .../src/plugins/webpack-stats-plugin.ts | 7 +++++- .../builder-vite/src/utils/virtual-module.ts | 3 +++ .../src/plugins/vue-component-meta.ts | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 code/builders/builder-vite/src/utils/virtual-module.ts diff --git a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts index 2de92617befa..86756b002a27 100644 --- a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts +++ b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts @@ -2,6 +2,7 @@ import { getFrameworkName, loadPreviewOrConfigFile } from 'storybook/internal/co import type { Options, PreviewAnnotation } from 'storybook/internal/types'; import { processPreviewAnnotation } from './utils/process-preview-annotation'; +import { getResolvedVirtualModuleId } from './utils/virtual-module'; import { virtualAddonSetupFile, virtualStoriesFile } from './virtual-file-names'; export async function generateModernIframeScriptCode(options: Options, projectRoot: string) { @@ -45,7 +46,7 @@ export async function generateModernIframeScriptCode(options: Options, projectRo return ` if (import.meta.hot) { - import.meta.hot.accept('${virtualStoriesFile}', (newModule) => { + import.meta.hot.accept('${getResolvedVirtualModuleId(virtualStoriesFile)}', (newModule) => { // importFn has changed so we need to patch the new one in window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn }); }); diff --git a/code/builders/builder-vite/src/plugins/code-generator-plugin.ts b/code/builders/builder-vite/src/plugins/code-generator-plugin.ts index 89f6430f7584..1909ceda0988 100644 --- a/code/builders/builder-vite/src/plugins/code-generator-plugin.ts +++ b/code/builders/builder-vite/src/plugins/code-generator-plugin.ts @@ -8,6 +8,7 @@ import { generateImportFnScriptCode } from '../codegen-importfn-script'; import { generateModernIframeScriptCode } from '../codegen-modern-iframe-script'; import { generateAddonSetupCode } from '../codegen-set-addon-channel'; import { transformIframeHtml } from '../transform-iframe-html'; +import { getResolvedVirtualModuleId } from '../utils/virtual-module'; import { virtualAddonSetupFile, virtualFileId, @@ -28,11 +29,15 @@ export function codeGeneratorPlugin(options: Options): Plugin { // invalidate the whole vite-app.js script on every file change. // (this might be a little too aggressive?) server.watcher.on('change', () => { - const appModule = server.moduleGraph.getModuleById(virtualFileId); + const appModule = server.moduleGraph.getModuleById( + getResolvedVirtualModuleId(virtualFileId) + ); if (appModule) { server.moduleGraph.invalidateModule(appModule); } - const storiesModule = server.moduleGraph.getModuleById(virtualStoriesFile); + const storiesModule = server.moduleGraph.getModuleById( + getResolvedVirtualModuleId(virtualStoriesFile) + ); if (storiesModule) { server.moduleGraph.invalidateModule(storiesModule); } @@ -70,33 +75,33 @@ export function codeGeneratorPlugin(options: Options): Plugin { }, resolveId(source) { if (source === virtualFileId) { - return `${virtualFileId}`; + return getResolvedVirtualModuleId(virtualFileId); } if (source === iframePath) { return iframeId; } if (source === virtualStoriesFile) { - return `${virtualStoriesFile}`; + return getResolvedVirtualModuleId(virtualStoriesFile); } if (source === virtualPreviewFile) { - return virtualPreviewFile; + return getResolvedVirtualModuleId(virtualPreviewFile); } if (source === virtualAddonSetupFile) { - return `${virtualAddonSetupFile}`; + return getResolvedVirtualModuleId(virtualAddonSetupFile); } return undefined; }, async load(id, config) { - if (id === `${virtualStoriesFile}`) { + if (id === getResolvedVirtualModuleId(virtualStoriesFile)) { return generateImportFnScriptCode(options); } - if (id === `${virtualAddonSetupFile}`) { + if (id === getResolvedVirtualModuleId(virtualAddonSetupFile)) { return generateAddonSetupCode(); } - if (id === `${virtualFileId}`) { + if (id === getResolvedVirtualModuleId(virtualFileId)) { return generateModernIframeScriptCode(options, projectRoot); } diff --git a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts index 3b8deebc8111..9442291df2aa 100644 --- a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts +++ b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts @@ -6,6 +6,8 @@ import type { BuilderStats } from 'storybook/internal/types'; import slash from 'slash'; import type { Plugin } from 'vite'; +import { getResolvedVirtualModuleId } from '../utils/virtual-module'; + /* * Reason, Module are copied from chromatic types * https://github.com/chromaui/chromatic-cli/blob/145a5e295dde21042e96396c7e004f250d842182/bin-src/types.ts#L265-L276 @@ -50,7 +52,10 @@ export function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): W /** Convert an absolute path name to a path relative to the vite root, with a starting `./` */ function normalize(filename: string) { // Do not try to resolve virtual files - if (filename.startsWith('/virtual:')) { + if ( + filename.startsWith('/virtual:') || + filename.startsWith(getResolvedVirtualModuleId('/virtual:')) + ) { return filename; } // Otherwise, we need them in the format `./path/to/file.js`. diff --git a/code/builders/builder-vite/src/utils/virtual-module.ts b/code/builders/builder-vite/src/utils/virtual-module.ts new file mode 100644 index 000000000000..6f72ce19d650 --- /dev/null +++ b/code/builders/builder-vite/src/utils/virtual-module.ts @@ -0,0 +1,3 @@ +export function getResolvedVirtualModuleId(virtualModuleId: string) { + return `\0${virtualModuleId}`; +} diff --git a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts index bb06a958a771..036ab18945ae 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts @@ -26,7 +26,7 @@ export async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise< // exclude stories, virtual modules and storybook internals const exclude = - /\.stories\.(ts|tsx|js|jsx)$|^\/virtual:|^\/sb-preview\/|\.storybook\/.*\.(ts|js)$/; + /\.stories\.(ts|tsx|js|jsx)$|^\0\/virtual:|^\/virtual:|^\/sb-preview\/|\.storybook\/.*\.(ts|js)$/; const include = /\.(vue|ts|js|tsx|jsx)$/; const filter = createFilter(include, exclude); From cfd8912b2cc40de40e70768bdce95c655268e3cd Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 28 Aug 2024 08:55:38 +0200 Subject: [PATCH 021/213] fix lockfile --- code/yarn.lock | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/code/yarn.lock b/code/yarn.lock index 9c4f21999f31..007b51ef4f6d 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -23009,16 +23009,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:*, prettier@npm:^3.1.1": - version: 3.2.5 - resolution: "prettier@npm:3.2.5" - bin: - prettier: bin/prettier.cjs - checksum: 10c0/ea327f37a7d46f2324a34ad35292af2ad4c4c3c3355da07313339d7e554320f66f65f91e856add8530157a733c6c4a897dc41b577056be5c24c40f739f5ee8c6 - languageName: node - linkType: hard - -"prettier@npm:^3.2.5": +"prettier@npm:*, prettier@npm:^3.1.1, prettier@npm:^3.2.5": version: 3.3.3 resolution: "prettier@npm:3.3.3" bin: From 5768354461bce54aad24715cb4c9cf39a5a7d9dc Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 28 Aug 2024 08:55:48 +0200 Subject: [PATCH 022/213] fix --- code/core/src/preview-api/modules/store/StoryStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/src/preview-api/modules/store/StoryStore.ts b/code/core/src/preview-api/modules/store/StoryStore.ts index 0d129f65400a..cd7dc40a6ed1 100644 --- a/code/core/src/preview-api/modules/store/StoryStore.ts +++ b/code/core/src/preview-api/modules/store/StoryStore.ts @@ -371,7 +371,7 @@ export class StoryStore { ...picky(story.parameters, allowedParameters), fileName: importPath, }, - }; + } as V3CompatIndexEntry; }); return { From 7f56606607457b2861620c193691387bf3842c65 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 28 Aug 2024 09:42:26 +0200 Subject: [PATCH 023/213] fix linting --- code/core/src/common/js-package-manager/JsPackageManager.ts | 2 +- .../src/preview-api/modules/store/csf/portable-stories.ts | 2 +- code/e2e-tests/util.ts | 2 +- code/frameworks/angular/src/server/angular-cli-webpack.js | 2 +- code/frameworks/vue3-vite/src/preset.ts | 2 +- .../cli-storybook/src/automigrate/helpers/mainConfigFile.ts | 4 +++- .../src/automigrate/helpers/new-frameworks-utils.ts | 4 ++-- code/lib/cli-storybook/src/automigrate/index.ts | 2 +- code/lib/codemod/src/transforms/__tests__/mdx-to-csf.test.ts | 2 +- code/renderers/vue3/src/docs/extractArgTypes.ts | 2 +- 10 files changed, 13 insertions(+), 11 deletions(-) diff --git a/code/core/src/common/js-package-manager/JsPackageManager.ts b/code/core/src/common/js-package-manager/JsPackageManager.ts index 4b3e00c2f5e7..359c45351a01 100644 --- a/code/core/src/common/js-package-manager/JsPackageManager.ts +++ b/code/core/src/common/js-package-manager/JsPackageManager.ts @@ -60,7 +60,7 @@ export abstract class JsPackageManager { /** Get the INSTALLED version of a package from the package.json file */ async getPackageVersion(packageName: string, basePath = this.cwd): Promise { const packageJSON = await this.getPackageJSON(packageName, basePath); - return packageJSON ? packageJSON.version ?? null : null; + return packageJSON ? (packageJSON.version ?? null) : null; } constructor(options?: JsPackageManagerOptions) { diff --git a/code/core/src/preview-api/modules/store/csf/portable-stories.ts b/code/core/src/preview-api/modules/store/csf/portable-stories.ts index 1525b6e3e6d8..7f6dd737cadc 100644 --- a/code/core/src/preview-api/modules/store/csf/portable-stories.ts +++ b/code/core/src/preview-api/modules/store/csf/portable-stories.ts @@ -116,7 +116,7 @@ export function composeStory 0 ? defaultConfig - : globalThis.defaultProjectAnnotations ?? {}, + : (globalThis.defaultProjectAnnotations ?? {}), globalThis.globalProjectAnnotations ?? {}, projectAnnotations ?? {}, ]) diff --git a/code/e2e-tests/util.ts b/code/e2e-tests/util.ts index da0ff313431b..cd2936e4a99d 100644 --- a/code/e2e-tests/util.ts +++ b/code/e2e-tests/util.ts @@ -49,7 +49,7 @@ export class SbPage { await this.page.waitForURL((url) => url.search.includes( - `path=/${viewMode ?? name === 'docs' ? 'docs' : 'story'}/${titleId}--${storyId}` + `path=/${(viewMode ?? name === 'docs') ? 'docs' : 'story'}/${titleId}--${storyId}` ) ); diff --git a/code/frameworks/angular/src/server/angular-cli-webpack.js b/code/frameworks/angular/src/server/angular-cli-webpack.js index 92ed6225d19f..6be86712e5bc 100644 --- a/code/frameworks/angular/src/server/angular-cli-webpack.js +++ b/code/frameworks/angular/src/server/angular-cli-webpack.js @@ -68,7 +68,7 @@ exports.getWebpackConfig = async (baseConfig, { builderOptions, builderContext } outputPath: typeof builderOptions.outputPath === 'string' ? builderOptions.outputPath - : builderOptions.outputPath?.base ?? 'noop-out', + : (builderOptions.outputPath?.base ?? 'noop-out'), // Fixed options optimization: false, diff --git a/code/frameworks/vue3-vite/src/preset.ts b/code/frameworks/vue3-vite/src/preset.ts index 057b9a3d92a1..ea80b09bf3d7 100644 --- a/code/frameworks/vue3-vite/src/preset.ts +++ b/code/frameworks/vue3-vite/src/preset.ts @@ -21,7 +21,7 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) = const framework = await options.presets.apply('framework'); const frameworkOptions: FrameworkOptions = - typeof framework === 'string' ? {} : framework.options ?? {}; + typeof framework === 'string' ? {} : (framework.options ?? {}); const docgen = resolveDocgenOptions(frameworkOptions.docgen); diff --git a/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts index bf9daf36c7ae..c306d2578a13 100644 --- a/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts @@ -94,7 +94,9 @@ export const getBuilderPackageName = (mainConfig?: StorybookConfigRaw) => { export const getFrameworkOptions = ( mainConfig?: StorybookConfigRaw ): Record | null => { - return typeof mainConfig?.framework === 'string' ? null : mainConfig?.framework?.options ?? null; + return typeof mainConfig?.framework === 'string' + ? null + : (mainConfig?.framework?.options ?? null); }; /** diff --git a/code/lib/cli-storybook/src/automigrate/helpers/new-frameworks-utils.ts b/code/lib/cli-storybook/src/automigrate/helpers/new-frameworks-utils.ts index a4ab6ee34a4f..280bb2cf5034 100644 --- a/code/lib/cli-storybook/src/automigrate/helpers/new-frameworks-utils.ts +++ b/code/lib/cli-storybook/src/automigrate/helpers/new-frameworks-utils.ts @@ -77,14 +77,14 @@ export const detectBuilderInfo = async ({ const builderPackageName = getBuilderPackageName(mainConfig); const frameworkPackageName = getFrameworkPackageName(mainConfig) as string; - let builderOptions = typeof builder !== 'string' ? builder?.options ?? {} : {}; + let builderOptions = typeof builder !== 'string' ? (builder?.options ?? {}) : {}; if (builderPackageName) { builderOrFrameworkName = builderPackageName; } else if (framework) { if (Object.keys(frameworkPackages).includes(frameworkPackageName)) { builderOrFrameworkName = frameworkPackageName; - builderOptions = typeof framework === 'object' ? framework.options?.builder ?? {} : {}; + builderOptions = typeof framework === 'object' ? (framework.options?.builder ?? {}) : {}; } } diff --git a/code/lib/cli-storybook/src/automigrate/index.ts b/code/lib/cli-storybook/src/automigrate/index.ts index 690c3d1b15f7..f9b6f613d405 100644 --- a/code/lib/cli-storybook/src/automigrate/index.ts +++ b/code/lib/cli-storybook/src/automigrate/index.ts @@ -274,7 +274,7 @@ export async function runFixes({ if (result) { const promptType: Prompt = - typeof f.promptType === 'function' ? await f.promptType(result) : f.promptType ?? 'auto'; + 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); diff --git a/code/lib/codemod/src/transforms/__tests__/mdx-to-csf.test.ts b/code/lib/codemod/src/transforms/__tests__/mdx-to-csf.test.ts index 304fb0c40b05..6d41995d3e82 100644 --- a/code/lib/codemod/src/transforms/__tests__/mdx-to-csf.test.ts +++ b/code/lib/codemod/src/transforms/__tests__/mdx-to-csf.test.ts @@ -7,7 +7,7 @@ import { dedent } from 'ts-dedent'; import jscodeshift, { nameToValidExport } from '../mdx-to-csf'; expect.addSnapshotSerializer({ - print: (val: any) => (typeof val === 'string' ? val : JSON.stringify(val, null, 2) ?? ''), + print: (val: any) => (typeof val === 'string' ? val : (JSON.stringify(val, null, 2) ?? '')), test: () => true, }); diff --git a/code/renderers/vue3/src/docs/extractArgTypes.ts b/code/renderers/vue3/src/docs/extractArgTypes.ts index 7e76c731177f..f52f21c15255 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.ts @@ -129,7 +129,7 @@ export const extractFromVueDocgenApi = ( } } - const required = 'required' in docgenInfo ? docgenInfo.required ?? false : false; + const required = 'required' in docgenInfo ? (docgenInfo.required ?? false) : false; return { name: docgenInfo.name, From a92353857292eb83964588c21557b94c78e9dd28 Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Wed, 31 Jul 2024 10:19:34 +0200 Subject: [PATCH 024/213] fix: add missing prop controls --- code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts index bb06a958a771..2696f116ffbd 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts @@ -284,7 +284,11 @@ async function getTsConfigReferences(tsConfigPath: string) { * HTMLElement, MouseEvent) are used. */ function removeNestedSchemas(schema: PropertyMetaSchema) { - if (typeof schema !== 'object') { + if (typeof schema !== 'object') return; + if (schema.kind === 'enum') { + // for enum types, we do not want to remove the schemas because otherwise the controls will be missing + // instead we remove the nested schemas for the enum entries to prevent out of memory errors for types like "HTMLElement | MouseEvent" + schema.schema?.forEach((enumSchema) => removeNestedSchemas(enumSchema)); return; } delete schema.schema; From 78b22a96fe36a2331627a19523f9c89674c0be78 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Wed, 28 Aug 2024 14:35:38 -0600 Subject: [PATCH 025/213] Address feedback --- .../writing-tests/test-runner-with-vitest.mdx | 86 +++++++++---------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index ee470d740622..91244342922f 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -11,9 +11,11 @@ sidebar: While this feature is experimental, it is published as the `@storybook/experimental-addon-vitest` package. -Storybook's test runner with Vitest uses a Vitest plugin to transform your [stories](../writing-stories/index.mdx) into tests. You can then run those tests just like any other in Vitest, which will check that the story renders without errors and, if a [play function](../writing-stories/play-function.mdx) is defined, that it runs as expected and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. +Storybook's test runner with Vitest transforms your [stories](../writing-stories/index.mdx) into tests using a Vitest plugin and [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Those tests are then run using [Vitest](https://vitest.dev). This approach is faster and more flexible than the [previous test runner](./test-runner.mdx), which required a running Storybook instance to test your stories. -By using Vitest's browser mode, those tests are run in a real browser environment, which gives you more reliable results for UI components that commonly rely on browser APIs or features. +We recommend (and configure, by default) running Vitest in [browser mode](https://vitest.dev/guide/browser/), using [Playwright's](https://playwright.dev) Chromium browser. Browser mode ensures your components are tested in a real browser environment, which is more accurate than simulations like JSDom or HappyDom. This is especially important for testing components that rely on browser APIs or features. + +Stories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../writing-stories/play-function.mdx) is defined, that function is run and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. ## Install and set up @@ -27,7 +29,7 @@ Run the following command to install and configure the addon, which contains the -That command will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them if necessary. +That [`add` command](../addons/install-addons.mdx#automatic-installation) will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them with sensible defaults, if necessary. You may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. @@ -53,23 +55,21 @@ export default defineConfig({ -The configuration produced by the `add` command will attempt to set some sensible defaults for your project. However, you may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. - ### Manual setup For some project setups, the `add` command may be unable to automate the plugin setup and ask you to complete additional setup steps. Here's what to do: -1. Install the addon, `@storybook/experimental-addon-vitest`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). 1. Make sure Vite and Vitest are configured in your project. -1. Make sure Vitest is configured to use [browser mode](https://vitest.dev/guide/browser/). +1. Configure Vitest to use [browser mode](https://vitest.dev/guide/browser/). +1. Install the addon, `@storybook/experimental-addon-vitest`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). 1. If you're using Next.js, make sure you're using [`vite-plugin-storybook-nextjs`](https://github.com/storybookjs/vite-plugin-storybook-nextjs). 1. If you're using SvelteKit, make sure you're using `@storybook/sveltekit/vite`. 1. Create a [test setup file](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), `.storybook/vitest.setup.ts`. -1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can reference examples, below. +1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can use the example configuration files, below, as a guide. ### Example configuration files -Here are example configuration files generated by the `add` command. You can use these as a reference when setting up your project. +When the addon is set up automatically, it will create or adjust your Vitest configuration files for you. If you're setting up manually, you can use the following examples as a reference when configuring your project.
Example Vitest setup file @@ -112,8 +112,9 @@ export default mergeConfig( provider: 'playwright', headless: true, }, - // Disabling isolation is faster and similar to how tests are isolated in Storybook itself. - // Consider removing this, if you have flaky tests. + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests isolate: false, setupFiles: ['./.storybook/vitest.setup.ts'], }) @@ -151,8 +152,9 @@ export default defineWorkspace([ provider: 'playwright', headless: true, }, - // Disabling isolation is faster and similar to how tests are isolated in Storybook itself. - // Consider removing this, if you have flaky tests. + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests isolate: false, setupFiles: ['./.storybook/vitest.setup.ts'], } @@ -160,24 +162,6 @@ export default defineWorkspace([ ```
-## How it works - -Before running tests using the plugin, it's helpful to understand how it works. - -First, the plugin does not need to run or build Storybook to test your stories. Instead, it transforms your stories into tests using Vite and [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Portable stories are a mechanism to compose all of a story's configuration ([parameters](../writing-stories/parameters.mdx), [decorators](../writing-stories/decorators.mdx), etc.) with the story itself. This allows you to run your stories as tests without needing to run Storybook. - -Those tests are then run using Vitest. We recommend (and configure, by default) running Vitest in browser mode, using Playwright's Chromium browser. Browser mode ensures your components are tested in a real browser environment, which is more accurate than simulations like JSDom or HappyDom. This is especially important for testing components that rely on browser APIs or features. - -Stories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../writing-stories/play-function.mdx) is defined, that function is run and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. - -### Debugging - -While the plugin does not require Storybook to run when testing, you may still want to run Storybook to debug your tests. To enable this, provide the [`storybookScript` option](#storybookscript) in the plugin configuration. When you run Vitest in watch mode, the plugin will start Storybook using this script and provide links to the story in the output on test failures. This allows you to quickly jump to the story in Storybook to debug the issue. - -You can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running. - -[TK - Screenshot of test output with links to SB] - ## Usage There are three primary ways to run tests using the Vitest plugin: @@ -262,6 +246,14 @@ export default defineWorkspace([ ]) ``` +### Debugging + +While the plugin does not require Storybook to run when testing, you may still want to run Storybook to debug your tests. To enable this, provide the [`storybookScript` option](#storybookscript) in the plugin configuration. When you run Vitest in watch mode, the plugin will start Storybook using this script and provide links to the story in the output on test failures. This allows you to quickly jump to the story in Storybook to debug the issue. + +You can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running. + +[TK - Screenshot of test output with links to SB] + ## Configuration Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. @@ -302,11 +294,7 @@ If the same tag is in both the `include` and `exclude` arrays, the `exclude` beh ## FAQ -### How to ensure my tests can find assets in the public directory? - -If your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the [`publicDir` option in the Vitest configuration file](https://vitejs.dev/config/shared-options.html#publicdir). - -### How to debug my tests in Storybook? +### How do I debug my tests in Storybook? The plugin will attempt to provide links to the story in Storybook when tests fail, for [debugging](#debugging) purposes. @@ -317,7 +305,11 @@ If the URLs are not working when running tests in watch mode, you should check t If the URLs are not working when running tests in CI, you should ensure the Storybook is built and published before running the tests. You can then provide the URL to the published Storybook using the `storybookUrl` option. See the [In CI](#in-ci) section for an example. -### How to apply custom Vite configuration? +### How do I ensure my tests can find assets in the public directory? + +If your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the [`publicDir` option in the Vitest configuration file](https://vitejs.dev/config/shared-options.html#publicdir). + +### How do I apply custom Vite configuration? If you have custom operations defined in [`viteFinal`](../api/main-config/main-config-vite-final.mdx) in your `.storybook/main.js|ts` file, you will need to translate those into the Vitest configuration. This is because the plugin does not use the Storybook Vite configuration. @@ -325,17 +317,23 @@ If you have custom operations defined in [`viteFinal`](../api/main-config/main-c TK - Is there a good example we could offer here? ``` +### How do I isolate Storybook tests from others? + +Some projects might contain a `test` property in their Vite configuration. Because the Vitest configuration used by this plugin extends that Vite config, the `test` properties are merged. This lack of isolation can cause issues with your Storybook tests. + +To isolate your Storybook tests from other tests, you need to move the `test` property from your Vite configuration to the Vitest configuration. The Vitest config used by the plugin can then safely extend your Vite config without merging the `test` property. + ### Why do we recommend browser mode? Vitest's browser mode runs your tests in a real browser (Chromium, via Playwright, in the default configuration). The alternative is a simulated browser environment, like JSDom or HappyDom, which can have differences in behavior compared to a real browser. For UI components, which can often depend on browser APIs or features, running tests in a real browser is more accurate. For more, see [Vitest's guide on using browser mode effectively](https://vitest.dev/guide/browser/#motivation). -### How to use WebDriver instead of Playwright? +### How do I use WebDriver instead of Playwright? We recommend running tests in a browser using Playwright, but you can use WebDriverIO instead. To do so, you need to adjust the [browser provider in the Vitest configuration file](https://vitest.dev/config/#browser-provider). -### How to use a browser other than Chromium +### How do I use a browser other than Chromium We recommend using Chromium, because it is most likely to best match the experience of a majority of your users. However, you can use other browsers by adjusting the [browser name in the Vitest configuration file](https://vitest.dev/config/#browser-name). Note that [Playwright and WebDriverIO support different browsers](https://vitest.dev/guide/browser/#browser-option-types). @@ -347,12 +345,6 @@ Additionally, the previous test runner ran your stories as orchestrated tests in Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. -### How to isolate Storybook tests from others? - -Some projects might contain a `test` property in their Vite configuration. Because the Vitest configuration used by this plugin extends that Vite config, the `test` properties are merged. This lack of isolation can cause issues with your Storybook tests. - -To isolate your Storybook tests from other tests, you need to move the `test` property from your Vite configuration to the Vitest configuration. The Vitest config used by the plugin can then safely extend your Vite config without merging the `test` property. - ## API ### Exports @@ -395,7 +387,7 @@ Type: `string` Default: `http://localhost:6006` -The URL where Storybook is hosted. This is used for internal checks and to provide a link to the story in the test output on failures. +The URL where Storybook is hosted. This is used for internal checks and to provide a [link to the story in the test output on failures](#debugging). #### `tags` @@ -419,7 +411,7 @@ Default: } ``` -Tags to include, exclude, or skip. These tags are defined as annotations in your story, meta, or preview. +[Tags](../writing-stories/tags.mdx) to include, exclude, or skip. These tags are defined as annotations in your story, meta, or preview. - **`include`**: Stories with these tags will be tested - **`exclude`**: Stories with these tags will not be tested, and will not be counted in the test results From 1654ac5fa7c65a196fbe7d1d3bc9e7cb1de1cd68 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Thu, 29 Aug 2024 12:59:41 -0600 Subject: [PATCH 026/213] Fixes --- docs/writing-tests/index.mdx | 2 +- .../writing-tests/test-runner-with-vitest.mdx | 60 ++++++++++--------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/docs/writing-tests/index.mdx b/docs/writing-tests/index.mdx index e5f0524f7f7b..36f3ccefcfa7 100644 --- a/docs/writing-tests/index.mdx +++ b/docs/writing-tests/index.mdx @@ -25,4 +25,4 @@ Storybook also comes with tools, [a test runner](./test-runner.mdx), and handy i * [Test runner](./test-runner.mdx) to automate test execution * [Test coverage](./test-coverage.mdx) for measuring code coverage * [End-to-end tests](./import-stories-in-tests/stories-in-end-to-end-tests.mdx) for simulating real user scenarios -* [**Unit tests**](./import-stories-in-tests/stories-in-unit-tests.mdx) for functionality +* [Unit tests](./import-stories-in-tests/stories-in-unit-tests.mdx) for functionality diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index 91244342922f..5e2f69230215 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -102,21 +102,23 @@ export default mergeConfig( storybookScript: 'yarn storybook --ci', }), ], - // Glob pattern to find story files - include: ['src/**/*.stories.?(m)[jt]s?(x)'], - // Enable browser mode - browser: { - enabled: true, - name: 'chromium', - // Make sure to install Playwright - provider: 'playwright', - headless: true, + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], }, - // Speed up tests and better match how they run in Storybook itself - // https://vitest.dev/config/#isolate - // Consider removing this if you have flaky tests - isolate: false, - setupFiles: ['./.storybook/vitest.setup.ts'], }) ) ``` @@ -142,21 +144,23 @@ export default defineWorkspace([ storybookScript: 'yarn storybook --ci', }), ], - // Glob pattern to find story files - include: ['src/**/*.stories.?(m)[jt]s?(x)'], - // Enable browser mode - browser: { - enabled: true, - name: 'chromium', - // Make sure to install Playwright - provider: 'playwright', - headless: true, + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], }, - // Speed up tests and better match how they run in Storybook itself - // https://vitest.dev/config/#isolate - // Consider removing this if you have flaky tests - isolate: false, - setupFiles: ['./.storybook/vitest.setup.ts'], } ]) ``` From e233abea31a98edda96c310df48781b7b1fe1ec6 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:51:50 +0700 Subject: [PATCH 027/213] chore: update picocolors --- code/core/package.json | 2 +- code/lib/cli/package.json | 2 +- code/yarn.lock | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/code/core/package.json b/code/core/package.json index dc5948900296..955579cf82b2 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -380,7 +380,7 @@ "nanoid": "^4.0.2", "npmlog": "^7.0.0", "open": "^8.4.0", - "picocolors": "^1.0.1", + "picocolors": "^1.1.0", "picomatch": "^2.3.0", "polished": "^4.2.2", "prettier": "^3.2.5", diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index 327164dccaef..89b2e66c33e3 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -310,7 +310,7 @@ }, "dependencies": { "@storybook/core": "workspace:*", - "picocolors": "^1.0.1" + "picocolors": "^1.1.0" }, "devDependencies": { "typescript": "^5.3.2" diff --git a/code/yarn.lock b/code/yarn.lock index 0cd25257f93c..84280e3f1376 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6687,7 +6687,7 @@ __metadata: nanoid: "npm:^4.0.2" npmlog: "npm:^7.0.0" open: "npm:^8.4.0" - picocolors: "npm:^1.0.1" + picocolors: "npm:^1.1.0" picomatch: "npm:^2.3.0" polished: "npm:^4.2.2" prettier: "npm:^3.2.5" @@ -22949,13 +22949,20 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": +"picocolors@npm:^1.0.0": version: 1.0.1 resolution: "picocolors@npm:1.0.1" checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 languageName: node linkType: hard +"picocolors@npm:^1.1.0": + version: 1.1.0 + resolution: "picocolors@npm:1.1.0" + checksum: 10c0/86946f6032148801ef09c051c6fb13b5cf942eaf147e30ea79edb91dd32d700934edebe782a1078ff859fb2b816792e97ef4dab03d7f0b804f6b01a0df35e023 + languageName: node + linkType: hard + "picomatch@npm:4.0.1": version: 4.0.1 resolution: "picomatch@npm:4.0.1" @@ -26452,7 +26459,7 @@ __metadata: resolution: "storybook@workspace:lib/cli" dependencies: "@storybook/core": "workspace:*" - picocolors: "npm:^1.0.1" + picocolors: "npm:^1.1.0" typescript: "npm:^5.3.2" bin: getstorybook: ./bin/index.cjs From 59f926afa6311f95bdbac0ac6ac086fca2f75704 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 3 Sep 2024 12:04:12 -0600 Subject: [PATCH 028/213] Address comments and further changes - Limit to react, vue, and svelte renderers - `addon-vitest` -> `addon-test` - `addon-vitest/plugin` -> `addon-test/vite-plugin` - Add requirements - Add more details and examples about framework plugins - Add more detail about test setup file - Move comparison to previous test runner into its own section - Format snippets --- ...itest-install.md => addon-test-install.md} | 6 +- ...t-run-tests.md => addon-test-run-tests.md} | 0 .../writing-tests/test-runner-with-vitest.mdx | 178 +++++++++++++----- 3 files changed, 132 insertions(+), 52 deletions(-) rename docs/_snippets/{addon-vitest-install.md => addon-test-install.md} (53%) rename docs/_snippets/{addon-vitest-run-tests.md => addon-test-run-tests.md} (100%) diff --git a/docs/_snippets/addon-vitest-install.md b/docs/_snippets/addon-test-install.md similarity index 53% rename from docs/_snippets/addon-vitest-install.md rename to docs/_snippets/addon-test-install.md index 06a229138d18..b516f291b85f 100644 --- a/docs/_snippets/addon-vitest-install.md +++ b/docs/_snippets/addon-test-install.md @@ -1,11 +1,11 @@ ```shell renderer="common" language="js" packageManager="npx" -npx storybook add @storybook/experimental-addon-vitest +npx storybook add @storybook/experimental-addon-test ``` ```shell renderer="common" language="js" packageManager="pnpm" -pnpm exec storybook add @storybook/experimental-addon-vitest +pnpm exec storybook add @storybook/experimental-addon-test ``` ```shell renderer="common" language="js" packageManager="yarn" -yarn exec storybook add @storybook/experimental-addon-vitest +yarn exec storybook add @storybook/experimental-addon-test ``` diff --git a/docs/_snippets/addon-vitest-run-tests.md b/docs/_snippets/addon-test-run-tests.md similarity index 100% rename from docs/_snippets/addon-vitest-run-tests.md rename to docs/_snippets/addon-test-run-tests.md diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index 5e2f69230215..b1fb80d74a3f 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -5,10 +5,22 @@ sidebar: title: Test runner with Vitest --- + + + Test runner with Vitest is currently only supported in [React](?renderer=react), [Vue](?renderer=vue) and [Svelte](?renderer=svelte) projects. + + If you are using a different renderer, you can use the [previous test runner](./test-runner.mdx) to test your stories. + + + {/* End non-supported renderers */} + + + + (⚠️ **Experimental**) - While this feature is experimental, it is published as the `@storybook/experimental-addon-vitest` package. + While this feature is experimental, it is published as the `@storybook/experimental-addon-test` package. Storybook's test runner with Vitest transforms your [stories](../writing-stories/index.mdx) into tests using a Vitest plugin and [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Those tests are then run using [Vitest](https://vitest.dev). This approach is faster and more flexible than the [previous test runner](./test-runner.mdx), which required a running Storybook instance to test your stories. @@ -19,7 +31,15 @@ Stories are tested in two ways: a smoke test to ensure it renders and, if a [pla ## Install and set up -Get started by upgrading to at least Storybook 8.3, then installing and configuring the plugin in your project. +Before installing, make sure your project meets the following requirements: + +- Storybook ≥ 8.3 +- A Storybook framework that uses Vite (e.g. [`vue3-vite`](../get-started/frameworks/vue3-vite.mdx)), or the [Storybook Next.js framework](../get-started/frameworks/nextjs.mdx) +- Vitest ≥ 2.0 + - If you're not using Vitest, it will be installed and configured for you when you install the addon +- For Next.js projects, Next.js ≥ 14.0 + +If you're not yet using Storybook 8.3, you can [upgrade your Storybook](../configure/upgrading.mdx) to the latest version: @@ -27,45 +47,94 @@ Get started by upgrading to at least Storybook 8.3, then installing and configur Run the following command to install and configure the addon, which contains the plugin to run your stories as tests using Vitest: - + That [`add` command](../addons/install-addons.mdx#automatic-installation) will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them with sensible defaults, if necessary. You may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. +### Manual setup + +For some project setups, the `add` command may be unable to automate the plugin setup and ask you to complete additional setup steps. Here's what to do: + +1. Make sure Vite and Vitest are configured in your project. +1. Configure Vitest to use [browser mode](https://vitest.dev/guide/browser/). +1. Install the addon, `@storybook/experimental-addon-test`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). +1. Create a test setup file, `.storybook/vitest.setup.ts`. You can use the example setup file, below, as a guide +1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can use the example configuration files, below, as a guide. + +#### Framework plugins + +Some Storybook frameworks require additional setup to enable the framework's features to work with Vitest. Each of those frameworks exports a Vite plugin that you can use to configure your project correctly: + + + If you're using Next.js, use `@storybook/experimental-nextjs-vite/vite-plugin`: + + ```js title="vitest.config.ts" + import { defineConfig, mergeConfig } from 'vitest/config'; + import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookNextjsPlugin } from '@storybook/experimental-nextjs-vite/vite-plugin'; + + import viteConfig from './vite.config'; + + export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest(), + storybookNextjsPlugin(), // 👈 Use the plugin here + ], + // ... + }) + ); + ``` + + - - If your stories use template-based Vue components, you may need to [alias the `vue` module](https://vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation) to resolve correctly in the test environment: + Vue projects should use `@storybook/vue3-vite/vite-plugin`: -
- Example Vite configuration + ```js title="vitest.config.ts" + import { defineConfig, mergeConfig } from 'vitest/config'; + import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookVuePlugin } from '@storybook/vue3-vite/vite-plugin'; -```ts -// vite.config.ts -import { defineConfig } from 'vite/config'; + import viteConfig from './vite.config' -export default defineConfig({ - // ... - resolve: { - alias: { - vue: 'vue/dist/vue.esm-bundler.js', - }, - }, -}); -``` -
-
+ export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest(), + storybookVuePlugin(), // 👈 Use the plugin here + ], + // ... + }) + ); + ```
-### Manual setup + + If you're using SvelteKit, use `@storybook/sveltekit/vite-plugin`: -For some project setups, the `add` command may be unable to automate the plugin setup and ask you to complete additional setup steps. Here's what to do: + ```js title="vitest.config.ts" + import { defineConfig, mergeConfig } from 'vitest/config'; + import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookSveltekitPlugin } from '@storybook/sveltekit/vite-plugin'; -1. Make sure Vite and Vitest are configured in your project. -1. Configure Vitest to use [browser mode](https://vitest.dev/guide/browser/). -1. Install the addon, `@storybook/experimental-addon-vitest`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). -1. If you're using Next.js, make sure you're using [`vite-plugin-storybook-nextjs`](https://github.com/storybookjs/vite-plugin-storybook-nextjs). -1. If you're using SvelteKit, make sure you're using `@storybook/sveltekit/vite`. -1. Create a [test setup file](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), `.storybook/vitest.setup.ts`. -1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can use the example configuration files, below, as a guide. + import viteConfig from './vite.config'; + + export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest(), + storybookSveltekitPlugin(), // 👈 Use the plugin here + ], + // ... + }) + ); + ``` + + +The above example uses the framework's plugin in a Vitest configuration file. You can also use it in a Vitest workspace file, if that is how your project is configured. ### Example configuration files @@ -74,25 +143,33 @@ When the addon is set up automatically, it will create or adjust your Vitest con
Example Vitest setup file + Storybook stories contain configuration defined in `.storybook/preview.js|ts`. To ensure that configuration is available to your tests, you can apply it in a Vitest setup file. Here's an example of how to do that: + ```ts title=".storybook/vitest.setup.ts" import { beforeAll } from 'vitest'; // Replace your-renderer with the renderer you are using (e.g., react, vue3, svelte, etc.) import { setProjectAnnotations } from '@storybook/your-renderer'; + import * as projectAnnotations from './preview'; const project = setProjectAnnotations(projectAnnotations); beforeAll(project.beforeAll); ``` + + The `setProjectAnnotations` function is part of the portable stories API, which is used to transform your stories into tests. For more details, see the [portable stories API documentation](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations).
Example Vitest config file + The most simple application of the plugin is to include it in your Vitest configuration file: + ```ts title="vitest.config.ts" -import { defineConfig, mergeConfig } from 'vitest/config' -import viteConfig from './vite.config' -import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + +import viteConfig from './vite.config'; export default mergeConfig( viteConfig, @@ -120,17 +197,18 @@ export default mergeConfig( setupFiles: ['./.storybook/vitest.setup.ts'], }, }) -) +); ```
Example Vitest workspace file -{/* TODO: Nextjs & SvelteKit examples */} + If you're using a [Vitest workspace](https://vitest.dev/guide/workspace), you can define a new workspace project: + ```ts title="vitest.workspace.ts" -import { defineWorkspace } from 'vitest/config' -import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' +import { defineWorkspace } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; export default defineWorkspace([ // This is the path to your existing Vitest config file @@ -162,7 +240,7 @@ export default defineWorkspace([ setupFiles: ['./.storybook/vitest.setup.ts'], }, } -]) +]); ```
@@ -196,7 +274,7 @@ If you already have a `test` script that runs something other than Vitest, you c When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: - + ### Editor extension @@ -260,7 +338,7 @@ You can also provide a [`storybookUrl` option](#storybookurl) to the plugin conf ## Configuration -Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. +Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration and setup files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. By default, the plugin will run all stories with the `test` tag. You can adjust this behavior by providing the [`tags` option](#tags) in the plugin configuration. This allows you to include, exclude, or skip stories based on their tags. @@ -296,6 +374,14 @@ export default defineWorkspace([ If the same tag is in both the `include` and `exclude` arrays, the `exclude` behavior takes precedence. +## Comparison to the previous test runner + +The [previous test runner](./test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. This plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Beyond that core difference, there are a few other distinctions: + +Additionally, the previous test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable. + +Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. + ## FAQ ### How do I debug my tests in Storybook? @@ -341,14 +427,6 @@ We recommend running tests in a browser using Playwright, but you can use WebDri We recommend using Chromium, because it is most likely to best match the experience of a majority of your users. However, you can use other browsers by adjusting the [browser name in the Vitest configuration file](https://vitest.dev/config/#browser-name). Note that [Playwright and WebDriverIO support different browsers](https://vitest.dev/guide/browser/#browser-option-types). -### How is this different from the previous test runner? - -The [previous test runner](./test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. This plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Beyond that core difference, there are a few other distinctions: - -Additionally, the previous test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable. - -Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. - ## API ### Exports @@ -356,7 +434,7 @@ Finally, because of the simpler architecture and the use of Vitest, this plugin This addon contributes the following exports to Storybook: ```js -import { storybookTest } from '@storybook/experimental-addon-vitest/plugin' +import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin' ``` #### `storybookTest` @@ -420,3 +498,5 @@ Default: - **`include`**: Stories with these tags will be tested - **`exclude`**: Stories with these tags will not be tested, and will not be counted in the test results - **`skip`**: Stories with these tags will not be tested, and will be counted in the test results + +
\ No newline at end of file From 483325a656e9884d4322d0ed38a9a518b9ea1f8f Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 4 Sep 2024 10:20:57 +0200 Subject: [PATCH 029/213] Portable Stories: Improve Handling of React Updates and Errors Co-authored-by: Yann Braga Co-authored-by: Jeppe Reinhold --- .../modules/store/csf/portable-stories.ts | 4 + .../react-dom-shim/src/preventActChecks.tsx | 17 -- code/lib/react-dom-shim/src/react-16.tsx | 6 +- code/lib/react-dom-shim/src/react-18.tsx | 23 +- code/renderers/react/package.json | 4 + .../react/src/__test__/Button.stories.tsx | 9 +- .../__test__/ComponentWithError.stories.tsx | 13 + .../react/src/__test__/ComponentWithError.tsx | 4 + .../portable-stories-legacy.test.tsx.snap | 34 +++ .../__test__/portable-stories-legacy.test.tsx | 6 +- .../src/__test__/portable-stories.test.tsx | 90 +++--- code/renderers/react/src/act-compat.ts | 65 +++++ code/renderers/react/src/portable-stories.tsx | 80 +++++- code/renderers/react/src/renderToCanvas.tsx | 7 +- code/vitest-setup.ts | 1 + code/yarn.lock | 269 +++++++++++++++++- 16 files changed, 557 insertions(+), 75 deletions(-) delete mode 100644 code/lib/react-dom-shim/src/preventActChecks.tsx create mode 100644 code/renderers/react/src/__test__/ComponentWithError.stories.tsx create mode 100644 code/renderers/react/src/__test__/ComponentWithError.tsx create mode 100644 code/renderers/react/src/act-compat.ts diff --git a/code/core/src/preview-api/modules/store/csf/portable-stories.ts b/code/core/src/preview-api/modules/store/csf/portable-stories.ts index 1525b6e3e6d8..7adc83196eb1 100644 --- a/code/core/src/preview-api/modules/store/csf/portable-stories.ts +++ b/code/core/src/preview-api/modules/store/csf/portable-stories.ts @@ -74,6 +74,10 @@ export function setProjectAnnotations( | NamedOrDefaultProjectAnnotations[] ): NormalizedProjectAnnotations { const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations]; + if (globalThis.defaultProjectAnnotations) { + annotations.push(globalThis.defaultProjectAnnotations); + } + globalThis.globalProjectAnnotations = composeConfigs(annotations.map(extractAnnotation)); return globalThis.globalProjectAnnotations; diff --git a/code/lib/react-dom-shim/src/preventActChecks.tsx b/code/lib/react-dom-shim/src/preventActChecks.tsx deleted file mode 100644 index f35e2fb25dc5..000000000000 --- a/code/lib/react-dom-shim/src/preventActChecks.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export {}; - -declare const globalThis: { - IS_REACT_ACT_ENVIRONMENT?: boolean; -}; - -// TODO(9.0): We should actually wrap all those lines in `act`, but that might be a breaking change. -// We should make that breaking change for SB 9.0 -export function preventActChecks(callback: () => void): void { - const originalActEnvironment = globalThis.IS_REACT_ACT_ENVIRONMENT; - globalThis.IS_REACT_ACT_ENVIRONMENT = false; - try { - callback(); - } finally { - globalThis.IS_REACT_ACT_ENVIRONMENT = originalActEnvironment; - } -} diff --git a/code/lib/react-dom-shim/src/react-16.tsx b/code/lib/react-dom-shim/src/react-16.tsx index a1e7b1e97009..8c7b2c8f5a67 100644 --- a/code/lib/react-dom-shim/src/react-16.tsx +++ b/code/lib/react-dom-shim/src/react-16.tsx @@ -2,14 +2,12 @@ import type { ReactElement } from 'react'; import * as ReactDOM from 'react-dom'; -import { preventActChecks } from './preventActChecks'; - export const renderElement = async (node: ReactElement, el: Element) => { return new Promise((resolve) => { - preventActChecks(() => void ReactDOM.render(node, el, () => resolve(null))); + ReactDOM.render(node, el, () => resolve(null)); }); }; export const unmountElement = (el: Element) => { - preventActChecks(() => void ReactDOM.unmountComponentAtNode(el)); + ReactDOM.unmountComponentAtNode(el); }; diff --git a/code/lib/react-dom-shim/src/react-18.tsx b/code/lib/react-dom-shim/src/react-18.tsx index 5eb72b20eb17..f3398fc65ff0 100644 --- a/code/lib/react-dom-shim/src/react-18.tsx +++ b/code/lib/react-dom-shim/src/react-18.tsx @@ -1,15 +1,21 @@ /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */ -import type { FC, ReactElement } from 'react'; +import type { ReactElement } from 'react'; import * as React from 'react'; import type { Root as ReactRoot, RootOptions } from 'react-dom/client'; import * as ReactDOM from 'react-dom/client'; -import { preventActChecks } from './preventActChecks'; - // A map of all rendered React 18 nodes const nodes = new Map(); -const WithCallback: FC<{ callback: () => void; children: ReactElement }> = ({ +declare const globalThis: { + IS_REACT_ACT_ENVIRONMENT: boolean; +}; + +function getIsReactActEnvironment() { + return globalThis.IS_REACT_ACT_ENVIRONMENT; +} + +const WithCallback: React.FC<{ callback: () => void; children: ReactElement }> = ({ callback, children, }) => { @@ -43,8 +49,13 @@ export const renderElement = async (node: ReactElement, el: Element, rootOptions // Create Root Element conditionally for new React 18 Root Api const root = await getReactRoot(el, rootOptions); + if (getIsReactActEnvironment()) { + root.render(node); + return; + } + const { promise, resolve } = Promise.withResolvers(); - preventActChecks(() => root.render({node})); + root.render({node}); return promise; }; @@ -52,7 +63,7 @@ export const unmountElement = (el: Element, shouldUseNewRootApi?: boolean) => { const root = nodes.get(el); if (root) { - preventActChecks(() => root.unmount()); + root.unmount(); nodes.delete(el); } }; diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 4d370bbb8a1e..003466f1b182 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -94,12 +94,16 @@ "require-from-string": "^2.0.2" }, "peerDependencies": { + "@storybook/test": "workspace:*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "storybook": "workspace:^", "typescript": ">= 4.2.x" }, "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + }, "typescript": { "optional": true } diff --git a/code/renderers/react/src/__test__/Button.stories.tsx b/code/renderers/react/src/__test__/Button.stories.tsx index bde220fdf469..0e6e0d6e8c67 100644 --- a/code/renderers/react/src/__test__/Button.stories.tsx +++ b/code/renderers/react/src/__test__/Button.stories.tsx @@ -103,7 +103,6 @@ export const HooksStory: CSF3Story = { ); }, play: async ({ canvasElement, step }) => { - console.log('start of play function'); const canvas = within(canvasElement); await step('Step label', async () => { const inputEl = canvas.getByTestId('input'); @@ -112,8 +111,8 @@ export const HooksStory: CSF3Story = { await userEvent.type(inputEl, 'Hello world!'); await expect(inputEl).toHaveValue('Hello world!'); + await expect(buttonEl).toHaveTextContent('I am clicked'); }); - console.log('end of play function'); }, }; @@ -182,6 +181,12 @@ export const MountInPlayFunction: CSF3Story<{ mockFn: (val: string) => string }> }, }; +export const MountInPlayFunctionThrow: CSF3Story<{ mockFn: (val: string) => string }> = { + play: async () => { + throw new Error('Error thrown in play'); + }, +}; + export const WithActionArg: CSF3Story<{ someActionArg: HandlerFunction }> = { args: { someActionArg: action('some-action-arg'), diff --git a/code/renderers/react/src/__test__/ComponentWithError.stories.tsx b/code/renderers/react/src/__test__/ComponentWithError.stories.tsx new file mode 100644 index 000000000000..627055e2d965 --- /dev/null +++ b/code/renderers/react/src/__test__/ComponentWithError.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '..'; +import { ComponentWithError } from './ComponentWithError'; + +const meta = { + title: 'Example/ComponentWithError', + component: ComponentWithError as any, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const ThrowsError: Story = {}; diff --git a/code/renderers/react/src/__test__/ComponentWithError.tsx b/code/renderers/react/src/__test__/ComponentWithError.tsx new file mode 100644 index 000000000000..37f667cb4f2c --- /dev/null +++ b/code/renderers/react/src/__test__/ComponentWithError.tsx @@ -0,0 +1,4 @@ +export function ComponentWithError() { + // eslint-disable-next-line local-rules/no-uncategorized-errors + throw new Error('Error in render'); +} diff --git a/code/renderers/react/src/__test__/__snapshots__/portable-stories-legacy.test.tsx.snap b/code/renderers/react/src/__test__/__snapshots__/portable-stories-legacy.test.tsx.snap index b4753327aaf1..b690349bed8d 100644 --- a/code/renderers/react/src/__test__/__snapshots__/portable-stories-legacy.test.tsx.snap +++ b/code/renderers/react/src/__test__/__snapshots__/portable-stories-legacy.test.tsx.snap @@ -147,6 +147,40 @@ exports[`Legacy Portable Stories API > Renders Modal story 1`] = ` `; +exports[`Legacy Portable Stories API > Renders MountInPlayFunction story 1`] = ` + +
+
+ loaded data +
+
+ mockFn return value +
+
+ +`; + +exports[`Legacy Portable Stories API > Renders MountInPlayFunctionThrow story 1`] = ` + +
+
+ loaded data +
+
+ mockFn return value +
+
+ +`; + exports[`Legacy Portable Stories API > Renders WithActionArg story 1`] = `
diff --git a/code/renderers/react/src/__test__/portable-stories-legacy.test.tsx b/code/renderers/react/src/__test__/portable-stories-legacy.test.tsx index 3c7321cdfe63..5567b1fd9fbc 100644 --- a/code/renderers/react/src/__test__/portable-stories-legacy.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories-legacy.test.tsx @@ -200,7 +200,11 @@ describe('Legacy Portable Stories API', () => { it.each(testCases)('Renders %s story', async (_storyName, Story) => { cleanup(); - if (_storyName === 'CSF2StoryWithLocale' || _storyName === 'MountInPlayFunction') { + if ( + _storyName === 'CSF2StoryWithLocale' || + _storyName === 'MountInPlayFunction' || + _storyName === 'MountInPlayFunctionThrow' + ) { return; } diff --git a/code/renderers/react/src/__test__/portable-stories.test.tsx b/code/renderers/react/src/__test__/portable-stories.test.tsx index 90346edff991..94de89e093a5 100644 --- a/code/renderers/react/src/__test__/portable-stories.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories.test.tsx @@ -2,7 +2,7 @@ /* eslint-disable import/namespace */ import { cleanup, render, screen } from '@testing-library/react'; -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; import React from 'react'; @@ -16,23 +16,28 @@ import { expectTypeOf } from 'expect-type'; import { composeStories, composeStory, setProjectAnnotations } from '..'; import type { Button } from './Button'; -import * as stories from './Button.stories'; +import * as ButtonStories from './Button.stories'; +import * as ComponentWithErrorStories from './ComponentWithError.stories'; -setProjectAnnotations([]); +const HooksStory = composeStory(ButtonStories.HooksStory, ButtonStories.default); + +const projectAnnotations = setProjectAnnotations([]); // example with composeStories, returns an object with all stories composed with args/decorators -const { CSF3Primary, LoaderStory, MountInPlayFunction } = composeStories(stories); +const { CSF3Primary, LoaderStory, MountInPlayFunction, MountInPlayFunctionThrow } = + composeStories(ButtonStories); +const { ThrowsError } = composeStories(ComponentWithErrorStories); + +beforeAll(async () => { + await projectAnnotations.beforeAll?.(); +}); afterEach(() => { cleanup(); }); -declare const globalThis: { - IS_REACT_ACT_ENVIRONMENT?: boolean; -}; - // example with composeStory, returns a single story composed with args/decorators -const Secondary = composeStory(stories.CSF2Secondary, stories.default); +const Secondary = composeStory(ButtonStories.CSF2Secondary, ButtonStories.default); describe('renders', () => { it('renders primary button', () => { render(Hello world); @@ -60,6 +65,10 @@ describe('renders', () => { expect(buttonElement).not.toBeNull(); }); + it('should throw error when rendering a component with a render error', async () => { + await expect(() => ThrowsError.run()).rejects.toThrowError('Error in render'); + }); + it('should render component mounted in play function', async () => { await MountInPlayFunction.run(); @@ -67,6 +76,10 @@ describe('renders', () => { expect(screen.getByTestId('loaded-data').textContent).toEqual('loaded data'); }); + it('should throw an error in play function', () => { + expect(() => MountInPlayFunctionThrow.run()).rejects.toThrowError('Error thrown in play'); + }); + it('should call and compose loaders data', async () => { await LoaderStory.load(); const { getByTestId } = render(); @@ -78,10 +91,6 @@ describe('renders', () => { }); describe('projectAnnotations', () => { - afterEach(() => { - cleanup(); - }); - it('renders with default projectAnnotations', () => { setProjectAnnotations([ { @@ -91,7 +100,7 @@ describe('projectAnnotations', () => { }, }, ]); - const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default); + const WithEnglishText = composeStory(ButtonStories.CSF2StoryWithLocale, ButtonStories.default); const { getByText } = render(); const buttonElement = getByText('Hello!'); expect(buttonElement).not.toBeNull(); @@ -99,24 +108,31 @@ describe('projectAnnotations', () => { }); it('renders with custom projectAnnotations via composeStory params', () => { - const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, { - initialGlobals: { locale: 'pt' }, - }); + const WithPortugueseText = composeStory( + ButtonStories.CSF2StoryWithLocale, + ButtonStories.default, + { + initialGlobals: { locale: 'pt' }, + } + ); const { getByText } = render(); const buttonElement = getByText('Olá!'); expect(buttonElement).not.toBeNull(); }); it('has action arg from argTypes when addon-actions annotations are added', () => { - //@ts-expect-error our tsconfig.jsn#moduleResulution is set to 'node', which doesn't support this import - const Story = composeStory(stories.WithActionArgType, stories.default, addonActionsPreview); + const Story = composeStory( + ButtonStories.WithActionArgType, + ButtonStories.default, + addonActionsPreview + ); expect(Story.args.someActionArg).toHaveProperty('isAction', true); }); }); describe('CSF3', () => { it('renders with inferred globalRender', () => { - const Primary = composeStory(stories.CSF3Button, stories.default); + const Primary = composeStory(ButtonStories.CSF3Button, ButtonStories.default); render(Hello world); const buttonElement = screen.getByText(/Hello world/i); @@ -124,14 +140,17 @@ describe('CSF3', () => { }); it('renders with custom render function', () => { - const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default); + const Primary = composeStory(ButtonStories.CSF3ButtonWithRender, ButtonStories.default); render(); expect(screen.getByTestId('custom-render')).not.toBeNull(); }); it('renders with play function without canvas element', async () => { - const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); + const CSF3InputFieldFilled = composeStory( + ButtonStories.CSF3InputFieldFilled, + ButtonStories.default + ); await CSF3InputFieldFilled.run(); const input = screen.getByTestId('input') as HTMLInputElement; @@ -139,7 +158,10 @@ describe('CSF3', () => { }); it('renders with play function with canvas element', async () => { - const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); + const CSF3InputFieldFilled = composeStory( + ButtonStories.CSF3InputFieldFilled, + ButtonStories.default + ); const div = document.createElement('div'); document.body.appendChild(div); @@ -153,21 +175,16 @@ describe('CSF3', () => { }); it('renders with hooks', async () => { - // TODO find out why act is not working here - globalThis.IS_REACT_ACT_ENVIRONMENT = false; - const HooksStory = composeStory(stories.HooksStory, stories.default); - await HooksStory.run(); const input = screen.getByTestId('input') as HTMLInputElement; expect(input.value).toEqual('Hello world!'); - globalThis.IS_REACT_ACT_ENVIRONMENT = true; }); }); // common in addons that need to communicate between manager and preview it('should pass with decorators that need addons channel', () => { - const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, { + const PrimaryWithChannels = composeStory(ButtonStories.CSF3Primary, ButtonStories.default, { decorators: [ (StoryFn: any) => { addons.getChannel(); @@ -186,27 +203,24 @@ describe('ComposeStories types', () => { type ComposeStoriesParam = Parameters[0]; expectTypeOf({ - ...stories, - default: stories.default as Meta, + ...ButtonStories, + default: ButtonStories.default as Meta, }).toMatchTypeOf(); expectTypeOf({ - ...stories, - default: stories.default satisfies Meta, + ...ButtonStories, + default: ButtonStories.default satisfies Meta, }).toMatchTypeOf(); }); }); -// Batch snapshot testing -const testCases = Object.values(composeStories(stories)).map( +const testCases = Object.values(composeStories(ButtonStories)).map( (Story) => [Story.storyName, Story] as [string, typeof Story] ); it.each(testCases)('Renders %s story', async (_storyName, Story) => { - if (_storyName === 'CSF2StoryWithLocale') { + if (_storyName === 'CSF2StoryWithLocale' || _storyName === 'MountInPlayFunctionThrow') { return; } - globalThis.IS_REACT_ACT_ENVIRONMENT = false; await Story.run(); - globalThis.IS_REACT_ACT_ENVIRONMENT = true; expect(document.body).toMatchSnapshot(); }); diff --git a/code/renderers/react/src/act-compat.ts b/code/renderers/react/src/act-compat.ts new file mode 100644 index 000000000000..afe1cc902316 --- /dev/null +++ b/code/renderers/react/src/act-compat.ts @@ -0,0 +1,65 @@ +// Copied from +// https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/src/act-compat.js +import * as React from 'react'; + +import * as DeprecatedReactTestUtils from 'react-dom/test-utils'; + +declare const globalThis: { + IS_REACT_ACT_ENVIRONMENT: boolean; +}; + +// @ts-expect-error act might not be available in some versions of React +const reactAct = typeof React.act === 'function' ? React.act : DeprecatedReactTestUtils.act; + +export function setReactActEnvironment(isReactActEnvironment: boolean) { + globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment; +} + +export function getReactActEnvironment() { + return globalThis.IS_REACT_ACT_ENVIRONMENT; +} + +function withGlobalActEnvironment(actImplementation: (callback: () => void) => Promise) { + return (callback: () => any) => { + const previousActEnvironment = getReactActEnvironment(); + setReactActEnvironment(true); + try { + // The return value of `act` is always a thenable. + let callbackNeedsToBeAwaited = false; + const actResult = actImplementation(() => { + const result = callback(); + if (result !== null && typeof result === 'object' && typeof result.then === 'function') { + callbackNeedsToBeAwaited = true; + } + return result; + }); + if (callbackNeedsToBeAwaited) { + const thenable: Promise = actResult; + return { + then: (resolve: (param: any) => void, reject: (param: any) => void) => { + thenable.then( + (returnValue) => { + setReactActEnvironment(previousActEnvironment); + resolve(returnValue); + }, + (error) => { + setReactActEnvironment(previousActEnvironment); + reject(error); + } + ); + }, + }; + } else { + setReactActEnvironment(previousActEnvironment); + return actResult; + } + } catch (error) { + // Can't be a `finally {}` block since we don't know if we have to immediately restore IS_REACT_ACT_ENVIRONMENT + // or if we have to await the callback first. + setReactActEnvironment(previousActEnvironment); + throw error; + } + }; +} + +export const act = withGlobalActEnvironment(reactAct); diff --git a/code/renderers/react/src/portable-stories.tsx b/code/renderers/react/src/portable-stories.tsx index 2ea196e85b4b..ced0bbd289e3 100644 --- a/code/renderers/react/src/portable-stories.tsx +++ b/code/renderers/react/src/portable-stories.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import * as React from 'react'; import { composeStories as originalComposeStories, @@ -17,6 +17,7 @@ import type { StoryAnnotationsOrFn, } from 'storybook/internal/types'; +import { act, getReactActEnvironment, setReactActEnvironment } from './act-compat'; import * as reactProjectAnnotations from './entry-preview'; import type { Meta } from './public-types'; import type { ReactRenderer } from './types'; @@ -54,9 +55,66 @@ export function setProjectAnnotations( // This will not be necessary once we have auto preset loading export const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations = { ...reactProjectAnnotations, - renderToCanvas: (renderContext, canvasElement) => { + beforeAll: async function reactBeforeAll() { + try { + // copied from + // https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/src/pure.js + const { configure } = await import('@storybook/test'); + + configure({ + unstable_advanceTimersWrapper: (cb) => { + return act(cb); + }, + asyncWrapper: async (cb) => { + const previousActEnvironment = getReactActEnvironment(); + setReactActEnvironment(false); + try { + const result = await cb(); + // Drain microtask queue. + // Otherwise we'll restore the previous act() environment, before we resolve the `waitFor` call. + // The caller would have no chance to wrap the in-flight Promises in `act()` + await new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 0); + + if (jestFakeTimersAreEnabled()) { + // @ts-expect-error global jest + jest.advanceTimersByTime(0); + } + }); + + return result; + } finally { + setReactActEnvironment(previousActEnvironment); + } + }, + eventWrapper: (cb) => { + let result; + act(() => { + result = cb(); + }); + return result; + }, + }); + } catch (e) { + console.log(e); + // @storybook/test might not be available + } + }, + renderToCanvas: async (renderContext, canvasElement) => { if (renderContext.storyContext.testingLibraryRender == null) { - return reactProjectAnnotations.renderToCanvas(renderContext, canvasElement); + let unmount: () => void; + + await act(async () => { + unmount = await reactProjectAnnotations.renderToCanvas(renderContext, canvasElement); + }); + + return async () => { + await act(() => { + unmount(); + }); + }; } const { storyContext: { context, unboundStoryFn: Story, testingLibraryRender: render }, @@ -149,3 +207,19 @@ export function composeStories; } + +/** The function is used to configure jest's fake timers in environments where React's act is enabled */ +function jestFakeTimersAreEnabled() { + // @ts-expect-error global jest + if (typeof jest !== 'undefined' && jest !== null) { + return ( + // legacy timers + + // eslint-disable-next-line no-underscore-dangle + (setTimeout as any)._isMockFunction === true || // modern timers + Object.prototype.hasOwnProperty.call(setTimeout, 'clock') + ); + } + + return false; +} diff --git a/code/renderers/react/src/renderToCanvas.tsx b/code/renderers/react/src/renderToCanvas.tsx index f3a4231d078c..3ae6136f9582 100644 --- a/code/renderers/react/src/renderToCanvas.tsx +++ b/code/renderers/react/src/renderToCanvas.tsx @@ -5,6 +5,7 @@ import type { RenderContext } from 'storybook/internal/types'; import { global } from '@storybook/global'; +import { getReactActEnvironment } from './act-compat'; import type { ReactRenderer, StoryContext } from './types'; const { FRAMEWORK_OPTIONS } = global; @@ -57,7 +58,11 @@ export async function renderToCanvas( const { renderElement, unmountElement } = await import('@storybook/react-dom-shim'); const Story = unboundStoryFn as FC>; - const content = ( + const isActEnabled = getReactActEnvironment(); + + const content = isActEnabled ? ( + + ) : ( diff --git a/code/vitest-setup.ts b/code/vitest-setup.ts index 8edd64c36314..5eba16740d1d 100644 --- a/code/vitest-setup.ts +++ b/code/vitest-setup.ts @@ -7,6 +7,7 @@ const ignoreList = [ (error: any) => error.message.includes('":nth-child" is potentially unsafe'), (error: any) => error.message.includes('":first-child" is potentially unsafe'), (error: any) => error.message.match(/Browserslist: .* is outdated. Please run:/), + (error: any) => error.message.includes('Consider adding an error boundary'), (error: any) => error.message.includes('react-async-component-lifecycle-hooks') && error.stack.includes('addons/knobs/src/components/__tests__/Options.js'), diff --git a/code/yarn.lock b/code/yarn.lock index 9b8a426f6016..397b6cd54ff5 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -2490,7 +2490,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.1.1": +"@emnapi/runtime@npm:^1.1.1, @emnapi/runtime@npm:^1.2.0": version: 1.2.0 resolution: "@emnapi/runtime@npm:1.2.0" dependencies: @@ -3424,6 +3424,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@img/sharp-darwin-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-darwin-x64@npm:0.33.4" @@ -3436,6 +3448,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@img/sharp-libvips-darwin-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.2" @@ -3443,6 +3467,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@img/sharp-libvips-darwin-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.2" @@ -3450,6 +3481,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@img/sharp-libvips-linux-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.2" @@ -3457,6 +3495,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-arm@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-arm@npm:1.0.2" @@ -3464,6 +3509,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-s390x@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.2" @@ -3471,6 +3523,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-x64@npm:1.0.2" @@ -3478,6 +3537,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2" @@ -3485,6 +3551,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-libvips-linuxmusl-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.2" @@ -3492,6 +3565,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-linux-arm64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-arm64@npm:0.33.4" @@ -3504,6 +3584,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-arm@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-arm@npm:0.33.4" @@ -3516,6 +3608,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-s390x@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-s390x@npm:0.33.4" @@ -3528,6 +3632,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-x64@npm:0.33.4" @@ -3540,6 +3656,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linuxmusl-arm64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.4" @@ -3552,6 +3680,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-linuxmusl-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linuxmusl-x64@npm:0.33.4" @@ -3564,6 +3704,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-wasm32@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-wasm32@npm:0.33.4" @@ -3573,6 +3725,15 @@ __metadata: languageName: node linkType: hard +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": "npm:^1.2.0" + conditions: cpu=wasm32 + languageName: node + linkType: hard + "@img/sharp-win32-ia32@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-win32-ia32@npm:0.33.4" @@ -3580,6 +3741,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@img/sharp-win32-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-win32-x64@npm:0.33.4" @@ -3587,6 +3755,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@inquirer/confirm@npm:^3.0.0": version: 3.1.20 resolution: "@inquirer/confirm@npm:3.1.20" @@ -3903,13 +4078,20 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.2.5, @next/env@npm:^14.2.5": +"@next/env@npm:14.2.5": version: 14.2.5 resolution: "@next/env@npm:14.2.5" checksum: 10c0/63d8b88ac450b3c37940a9e2119a63a1074aca89908574ade6157a8aa295275dcb3ac5f69e00883fc55d0f12963b73b74e87ba32a5768a489f9609c6be57b699 languageName: node linkType: hard +"@next/env@npm:^14.2.5": + version: 14.2.7 + resolution: "@next/env@npm:14.2.7" + checksum: 10c0/1cda023007acda4d47036a25fba0e039d9b2df9c3770651dc289207e0537506675546c02b5b574fe92bb1adc1c887d948d5cb630673aa572754278b82d150b7e + languageName: node + linkType: hard + "@next/swc-darwin-arm64@npm:14.2.5": version: 14.2.5 resolution: "@next/swc-darwin-arm64@npm:14.2.5" @@ -6668,11 +6850,14 @@ __metadata: type-fest: "npm:~2.19" util-deprecate: "npm:^1.0.2" peerDependencies: + "@storybook/test": "workspace:*" react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta storybook: "workspace:^" typescript: ">= 4.2.x" peerDependenciesMeta: + "@storybook/test": + optional: true typescript: optional: true languageName: unknown @@ -25319,6 +25504,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.6.3": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + languageName: node + linkType: hard + "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -25470,7 +25664,7 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.33.3, sharp@npm:^0.33.4": +"sharp@npm:^0.33.3": version: 0.33.4 resolution: "sharp@npm:0.33.4" dependencies: @@ -25539,6 +25733,75 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.33.4": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.33.5" + "@img/sharp-darwin-x64": "npm:0.33.5" + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + "@img/sharp-linux-arm": "npm:0.33.5" + "@img/sharp-linux-arm64": "npm:0.33.5" + "@img/sharp-linux-s390x": "npm:0.33.5" + "@img/sharp-linux-x64": "npm:0.33.5" + "@img/sharp-linuxmusl-arm64": "npm:0.33.5" + "@img/sharp-linuxmusl-x64": "npm:0.33.5" + "@img/sharp-wasm32": "npm:0.33.5" + "@img/sharp-win32-ia32": "npm:0.33.5" + "@img/sharp-win32-x64": "npm:0.33.5" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.3" + semver: "npm:^7.6.3" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 + languageName: node + linkType: hard + "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" From da21bfecb75a64abeb40a23fa01ec32daccbb40d Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 4 Sep 2024 13:00:05 +0200 Subject: [PATCH 030/213] Next.js: Update webpack configuration to support react-dom/test-utils --- code/frameworks/nextjs/src/config/webpack.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/frameworks/nextjs/src/config/webpack.ts b/code/frameworks/nextjs/src/config/webpack.ts index 3860207e124e..3e0d758c1514 100644 --- a/code/frameworks/nextjs/src/config/webpack.ts +++ b/code/frameworks/nextjs/src/config/webpack.ts @@ -25,9 +25,17 @@ export const configureConfig = async ({ if (tryResolve('next/dist/compiled/react')) { addScopedAlias(baseConfig, 'react', 'next/dist/compiled/react'); } + if (tryResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js')) { + addScopedAlias( + baseConfig, + 'react-dom/test-utils', + 'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js' + ); + } if (tryResolve('next/dist/compiled/react-dom')) { - addScopedAlias(baseConfig, 'react-dom', 'next/dist/compiled/react-dom'); + addScopedAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom'); } + setupRuntimeConfig(baseConfig, nextConfig); return nextConfig; From 64fbe39ad01c17cff9ea4c18c69bb25509fc6b3b Mon Sep 17 00:00:00 2001 From: "yevhenii.honcharenko" Date: Tue, 3 Sep 2024 14:36:31 +0300 Subject: [PATCH 031/213] NextJS: fix sass-loader version for compatibility with nodejs > 20 --- code/frameworks/nextjs/package.json | 2 +- code/yarn.lock | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index e0f5cbb511e0..7a10bfa6e8e3 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -157,7 +157,7 @@ "postcss-loader": "^8.1.1", "react-refresh": "^0.14.0", "resolve-url-loader": "^5.0.0", - "sass-loader": "^12.4.0", + "sass-loader": "^13.2.0", "semver": "^7.3.5", "style-loader": "^3.3.1", "styled-jsx": "5.1.1", diff --git a/code/yarn.lock b/code/yarn.lock index 83b4b2ba2bdc..358cfc7dee3c 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6332,7 +6332,7 @@ __metadata: postcss-loader: "npm:^8.1.1" react-refresh: "npm:^0.14.0" resolve-url-loader: "npm:^5.0.0" - sass-loader: "npm:^12.4.0" + sass-loader: "npm:^13.2.0" semver: "npm:^7.3.5" sharp: "npm:^0.33.3" style-loader: "npm:^3.3.1" @@ -25159,15 +25159,14 @@ __metadata: languageName: node linkType: hard -"sass-loader@npm:^12.4.0": - version: 12.6.0 - resolution: "sass-loader@npm:12.6.0" +"sass-loader@npm:^13.2.0": + version: 13.3.3 + resolution: "sass-loader@npm:13.3.3" dependencies: - klona: "npm:^2.0.4" neo-async: "npm:^2.6.2" peerDependencies: fibers: ">= 3.1.0" - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 sass: ^1.3.0 sass-embedded: "*" webpack: ^5.0.0 @@ -25180,7 +25179,7 @@ __metadata: optional: true sass-embedded: optional: true - checksum: 10c0/e1ef655f3898cc4c45f02b3c627f8baf998139993a9a79c524153a80814282bfe20d8d8d703b8cf1d05457c1930940b65e2156d11285ed0861f9a1016f993e53 + checksum: 10c0/5e955a4ffce35ee0a46fce677ce51eaa69587fb5371978588c83af00f49e7edc36dcf3bb559cbae27681c5e24a71284463ebe03a1fb65e6ecafa1db0620e3fc8 languageName: node linkType: hard From e76df5823098a27f57f593f34c826023a2608f9e Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Wed, 4 Sep 2024 11:05:39 -0600 Subject: [PATCH 032/213] Update heading --- docs/writing-tests/test-runner-with-vitest.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index b1fb80d74a3f..c57c4cfde3f1 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -336,7 +336,7 @@ You can also provide a [`storybookUrl` option](#storybookurl) to the plugin conf [TK - Screenshot of test output with links to SB] -## Configuration +## Configuring tests Most of the configuration for the Vitest plugin's behavior is done in the Vitest configuration and setup files. However, you can also define configuration in your stories themselves, using [tags](../writing-stories/tags.mdx), to control how they are tested. From aff35807c5096eb8dcd4950b031007e28e686871 Mon Sep 17 00:00:00 2001 From: Alexander Chudesnov Date: Wed, 4 Sep 2024 19:28:35 +0200 Subject: [PATCH 033/213] Replace .at() call with [] in Vite Builder codegen Unblocks loading Storybook instances built with Vite devices with pre-2022 browser versions. Resolves #29030 --- code/builders/builder-vite/src/codegen-modern-iframe-script.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts index 2de92617befa..700adefffddb 100644 --- a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts +++ b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts @@ -27,7 +27,7 @@ export async function generateModernIframeScriptCode(options: Options, projectRo .map( (previewAnnotation, index) => // Prefer the updated module from an HMR update, otherwise import the original module - `hmrPreviewAnnotationModules.at(${index}) ?? import('${previewAnnotation}')` + `hmrPreviewAnnotationModules[${index}] ?? import('${previewAnnotation}')` ) .join(',\n')}]) return composeConfigs(configs); From 7a32c16cfd49ad25185ee216d36530d5ed775f5c Mon Sep 17 00:00:00 2001 From: Shota FUJI Date: Thu, 5 Sep 2024 15:30:37 +0900 Subject: [PATCH 034/213] Docs: Fix broken links ending with ".mdx" When I checked "How to contribute" page on storybook.js.org, a link titled "Continue reading our contributor covenant" pointed to GitHub's 404 page. The last item of the URL path was "CODE_OF_CONDUCT.mdx", which is not common filename people uses, therefore I suspected this is not the only broken link in the docs. And I was right. I ran the below command (rg = RipGrep) then found several 404 links. ``` $ cd docs $ rg "https?:[\S)]+mdx\)" --sort path ``` Git blame told me that some of ".md" to ".mdx" migration works accidentally changed non-docs URLs ending with ".md" too. StackBlitz URL in docs/api/main-config/main-config-indexers.mdx is not actually a dead link, as the service redirects to the `README.md`. However, the redirection takes loooong so I replaced that as well. There are still two links that match to the above regexp: * at docs/contribute/documentation/new-snippets.mdx L42 * at docs/writing-docs/mdx.mdx but those two are both valid (alive) URLs. --- docs/api/main-config/main-config-indexers.mdx | 2 +- docs/configure/upgrading.mdx | 2 +- docs/contribute/framework.mdx | 2 +- docs/contribute/index.mdx | 2 +- docs/faq.mdx | 6 +++--- docs/migration-guide/from-older-version.mdx | 2 +- docs/migration-guide/index.mdx | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/api/main-config/main-config-indexers.mdx b/docs/api/main-config/main-config-indexers.mdx index 9d31b0c169cc..67a6cf5c45b1 100644 --- a/docs/api/main-config/main-config-indexers.mdx +++ b/docs/api/main-config/main-config-indexers.mdx @@ -341,7 +341,7 @@ Some example usages of custom indexers include:
Generating stories with an alternative API - 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.mdx) 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. + 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/upgrading.mdx b/docs/configure/upgrading.mdx index ac75aff8a701..918182b7e931 100644 --- a/docs/configure/upgrading.mdx +++ b/docs/configure/upgrading.mdx @@ -31,7 +31,7 @@ After running the command, the script will: * Run the relevant [automigrations](../migration-guide/index.mdx#automatic-upgrade) factoring in the [breaking changes](../migration-guide/index.mdx#major-breaking-changes) between your current version and the specified version - In addition to running the command, we also recommend checking the [MIGRATION.md file](https://github.com/storybookjs/storybook/blob/next/MIGRATION.mdx), for the detailed log of relevant changes and deprecations that might affect your upgrade. + In addition to running the command, we also recommend checking the [MIGRATION.md file](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md), for the detailed log of relevant changes and deprecations that might affect your upgrade. ### Verifying the upgrade diff --git a/docs/contribute/framework.mdx b/docs/contribute/framework.mdx index 71ef9f1328cd..2b6cce765192 100644 --- a/docs/contribute/framework.mdx +++ b/docs/contribute/framework.mdx @@ -27,7 +27,7 @@ The library or libraries your framework supports may have different major versio ### 3. Write the documentation -Before writing any code, write a helpful README that contains installation instructions and a list of available features. Use the [README for `@storybook/nextjs`](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.mdx) as a template. Writing the documentation first helps guide your other work. +Before writing any code, write a helpful README that contains installation instructions and a list of available features. Use the [README for `@storybook/nextjs`](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md) as a template. Writing the documentation first helps guide your other work. ### 4. Author the framework itself diff --git a/docs/contribute/index.mdx b/docs/contribute/index.mdx index dd27c951753b..db8d512ca179 100644 --- a/docs/contribute/index.mdx +++ b/docs/contribute/index.mdx @@ -10,7 +10,7 @@ Storybook is a community-oriented open source project that welcomes contribution ## Contributor covenant -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. [Continue reading our contributor covenant »](https://github.com/storybookjs/storybook/blob/next/CODE_OF_CONDUCT.mdx) +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. [Continue reading our contributor covenant »](https://github.com/storybookjs/storybook/blob/next/CODE_OF_CONDUCT.md) ## Ways to contribute diff --git a/docs/faq.mdx b/docs/faq.mdx index 57c010639e1d..5bfab8ad93d1 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -195,7 +195,7 @@ We're actively working to provide a better way to address this situation, but in ## Is it possible to browse the documentation for past versions of Storybook? -With the release of version 6.0, we updated our documentation as well. That doesn't mean that the old documentation was removed. We kept it to help you with your Storybook migration process. Use the content from the table below in conjunction with our [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.mdx). +With the release of version 6.0, we updated our documentation as well. That doesn't mean that the old documentation was removed. We kept it to help you with your Storybook migration process. Use the content from the table below in conjunction with our [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md). 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. @@ -246,7 +246,7 @@ We're only covering versions 5.3 and 5.0 as they were important milestones for S | | Environment variables | [See current documentation](./configure/environment-variables.mdx) | [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.mdx) | Non existing feature or undocumented | Non existing feature or undocumented | | | Vite | [See current documentation](./builders/vite.mdx) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Webpack | [See current documentation](./builders/webpack.mdx) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.mdx) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.mdx) | +| | Webpack | [See current documentation](./builders/webpack.mdx) | [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.mdx) | Non existing feature or undocumented | Non existing feature or undocumented | | Addons | Introduction | [See current documentation](./addons/index.mdx) | [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.mdx) | [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/) | @@ -301,7 +301,7 @@ We're only covering versions 5.3 and 5.0 as they were important milestones for S | | CLI options | [See current documentation](./api/cli-options.mdx) | [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) | - 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/index.mdx#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.mdx) for reference. + 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/index.mdx#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. ## What icons are available for my toolbar or my addon? diff --git a/docs/migration-guide/from-older-version.mdx b/docs/migration-guide/from-older-version.mdx index a5fb7e4cfc6c..ae1f484c7988 100644 --- a/docs/migration-guide/from-older-version.mdx +++ b/docs/migration-guide/from-older-version.mdx @@ -119,7 +119,7 @@ The automatic upgrade should get your Storybook into a working state. If you enc If you prefer to debug yourself, here are a few useful things you can do to help narrow down the problem: 1. Try removing all addons that are not in the `@storybook` npm namespace (make sure you don't remove the `storybook` package). Community addons that work well with 7.x might not yet be compatible with 8.0, and this is the fastest way to isolate that possibility. If you find an addon that needs to be upgraded to work with Storybook 8, please post an issue on the addon’s repository, or better yet, a pull request to upgrade it! -2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `8.0.0-beta.56`, you could set the version to `8.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `7.6.x`). If it works, you could then try `8.0.0-beta.0`, then `8.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.mdx) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly. +2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `8.0.0-beta.56`, you could set the version to `8.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `7.6.x`). If it works, you could then try `8.0.0-beta.0`, then `8.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly. ## Optional migrations diff --git a/docs/migration-guide/index.mdx b/docs/migration-guide/index.mdx index 560d61b94cef..93e91a901910 100644 --- a/docs/migration-guide/index.mdx +++ b/docs/migration-guide/index.mdx @@ -133,7 +133,7 @@ The automatic upgrade should get your Storybook into a working state. If you enc If you prefer to debug yourself, here are a few useful things you can do to help narrow down the problem: 1. Try removing all addons that are not in the `@storybook` npm namespace (make sure you don't remove the `storybook` package). Community addons that work well with 7.x might not yet be compatible with 8.0, and this is the fastest way to isolate that possibility. If you find an addon that needs to be upgraded to work with Storybook 8, please post an issue on the addon’s repository, or better yet, a pull request to upgrade it! -2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `8.0.0-beta.56`, you could set the version to `8.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `7.6.x`). If it works, you could then try `8.0.0-beta.0`, then `8.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.mdx) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly. +2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `8.0.0-beta.56`, you could set the version to `8.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `7.6.x`). If it works, you could then try `8.0.0-beta.0`, then `8.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly. ## Package structure changes From da2aee4928b7cc5ba104df99ec9a62873a4b3b3b Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Thu, 5 Sep 2024 09:12:51 +0200 Subject: [PATCH 035/213] name decorators for easier debugging --- code/core/template/stories/preview.ts | 16 +- code/frameworks/sveltekit/src/preview.ts | 222 +++++++++++------------ 2 files changed, 119 insertions(+), 119 deletions(-) diff --git a/code/core/template/stories/preview.ts b/code/core/template/stories/preview.ts index 4cd4c64abff5..bba2716864bc 100644 --- a/code/core/template/stories/preview.ts +++ b/code/core/template/stories/preview.ts @@ -30,14 +30,14 @@ export const parameters = { export const loaders = [async () => ({ projectValue: 2 })]; -export const decorators = [ - (storyFn: PartialStoryFn, context: StoryContext) => { - if (context.parameters.useProjectDecorator) { - return storyFn({ args: { ...context.args, text: `project ${context.args.text}` } }); - } - return storyFn(); - }, -]; +const testProjectDecorator = (storyFn: PartialStoryFn, context: StoryContext) => { + if (context.parameters.useProjectDecorator) { + return storyFn({ args: { ...context.args, text: `project ${context.args.text}` } }); + } + return storyFn(); +}; + +export const decorators = [testProjectDecorator]; export const initialGlobals = { foo: 'fooValue', diff --git a/code/frameworks/sveltekit/src/preview.ts b/code/frameworks/sveltekit/src/preview.ts index f93c06862c29..c93cbde37a55 100644 --- a/code/frameworks/sveltekit/src/preview.ts +++ b/code/frameworks/sveltekit/src/preview.ts @@ -15,125 +15,125 @@ const normalizeHrefConfig = (hrefConfig: HrefConfig): NormalizedHrefConfig => { return hrefConfig; }; -export const decorators: Decorator[] = [ - (Story, ctx) => { - const svelteKitParameters: SvelteKitParameters = ctx.parameters?.sveltekit_experimental ?? {}; - setPage(svelteKitParameters?.stores?.page); - setNavigating(svelteKitParameters?.stores?.navigating); - setUpdated(svelteKitParameters?.stores?.updated); - setAfterNavigateArgument(svelteKitParameters?.navigation?.afterNavigate); +const svelteKitMocksDecorator = (Story, ctx) => { + const svelteKitParameters: SvelteKitParameters = ctx.parameters?.sveltekit_experimental ?? {}; + setPage(svelteKitParameters?.stores?.page); + setNavigating(svelteKitParameters?.stores?.navigating); + setUpdated(svelteKitParameters?.stores?.updated); + setAfterNavigateArgument(svelteKitParameters?.navigation?.afterNavigate); - onMount(() => { - const globalClickListener = (e: MouseEvent) => { - // we add a global click event listener and we check if there's a link in the composedPath - const path = e.composedPath(); - const element = path.findLast((el) => el instanceof HTMLElement && el.tagName === 'A'); - if (element && element instanceof HTMLAnchorElement) { - // if the element is an a-tag we get the href of the element - // and compare it to the hrefs-parameter set by the user - const to = element.getAttribute('href'); - if (!to) { - return; - } - e.preventDefault(); - const defaultActionCallback = () => action('navigate')(to, e); - if (!svelteKitParameters.hrefs) { - defaultActionCallback(); - return; - } - - let callDefaultCallback = true; - // we loop over every href set by the user and check if the href matches - // if it does we call the callback provided by the user and disable the default callback - Object.entries(svelteKitParameters.hrefs).forEach(([href, hrefConfig]) => { - const { callback, asRegex } = normalizeHrefConfig(hrefConfig); - const isMatch = asRegex ? new RegExp(href).test(to) : to === href; - if (isMatch) { - callDefaultCallback = false; - callback?.(to, e); - } - }); - if (callDefaultCallback) { - defaultActionCallback(); - } + onMount(() => { + const globalClickListener = (e: MouseEvent) => { + // we add a global click event listener and we check if there's a link in the composedPath + const path = e.composedPath(); + const element = path.findLast((el) => el instanceof HTMLElement && el.tagName === 'A'); + if (element && element instanceof HTMLAnchorElement) { + // if the element is an a-tag we get the href of the element + // and compare it to the hrefs-parameter set by the user + const to = element.getAttribute('href'); + if (!to) { + return; + } + e.preventDefault(); + const defaultActionCallback = () => action('navigate')(to, e); + if (!svelteKitParameters.hrefs) { + defaultActionCallback(); + return; } - }; - - /** - * Function that create and add listeners for the event that are emitted by the mocked - * functions. The event name is based on the function name - * - * Eg. storybook:goto, storybook:invalidateAll - * - * @param baseModule The base module where the function lives (navigation|forms) - * @param functions The list of functions in that module that emit events - * @param {boolean} [defaultToAction] The list of functions in that module that emit events - * @returns A function to remove all the listener added - */ - function createListeners( - baseModule: keyof SvelteKitParameters, - functions: string[], - defaultToAction?: boolean - ) { - // the array of every added listener, we can use this in the return function - // to clean them - const toRemove: Array<{ - eventType: string; - listener: (event: { detail: any[] }) => void; - }> = []; - functions.forEach((func) => { - // we loop over every function and check if the user actually passed - // a function in sveltekit_experimental[baseModule][func] eg. sveltekit_experimental.navigation.goto - const hasFunction = - (svelteKitParameters as any)[baseModule]?.[func] && - (svelteKitParameters as any)[baseModule][func] instanceof Function; - // if we default to an action we still add the listener (this will be the case for goto, invalidate, invalidateAll) - if (hasFunction || defaultToAction) { - // we create the listener that will just get the detail array from the custom element - // and call the user provided function spreading this args in...this will basically call - // the function that the user provide with the same arguments the function is invoked to - // eg. if it calls goto("/my-route") inside the component the function sveltekit_experimental.navigation.goto - // it provided to storybook will be called with "/my-route" - const listener = ({ detail = [] as any[] }) => { - const args = Array.isArray(detail) ? detail : []; - // if it has a function in the parameters we call that function - // otherwise we invoke the action - const fnToCall = hasFunction - ? (svelteKitParameters as any)[baseModule][func] - : action(func); - fnToCall(...args); - }; - const eventType = `storybook:${func}`; - toRemove.push({ eventType, listener }); - // add the listener to window - (window.addEventListener as any)(eventType, listener); + let callDefaultCallback = true; + // we loop over every href set by the user and check if the href matches + // if it does we call the callback provided by the user and disable the default callback + Object.entries(svelteKitParameters.hrefs).forEach(([href, hrefConfig]) => { + const { callback, asRegex } = normalizeHrefConfig(hrefConfig); + const isMatch = asRegex ? new RegExp(href).test(to) : to === href; + if (isMatch) { + callDefaultCallback = false; + callback?.(to, e); } }); - return () => { - // loop over every listener added and remove them - toRemove.forEach(({ eventType, listener }) => { - // @ts-expect-error apparently you can't remove a custom listener to the window with TS - window.removeEventListener(eventType, listener); - }); - }; + if (callDefaultCallback) { + defaultActionCallback(); + } } + }; - const removeNavigationListeners = createListeners( - 'navigation', - ['goto', 'invalidate', 'invalidateAll', 'pushState', 'replaceState'], - true - ); - const removeFormsListeners = createListeners('forms', ['enhance']); - window.addEventListener('click', globalClickListener); + /** + * Function that create and add listeners for the event that are emitted by the mocked + * functions. The event name is based on the function name + * + * Eg. storybook:goto, storybook:invalidateAll + * + * @param baseModule The base module where the function lives (navigation|forms) + * @param functions The list of functions in that module that emit events + * @param {boolean} [defaultToAction] The list of functions in that module that emit events + * @returns A function to remove all the listener added + */ + function createListeners( + baseModule: keyof SvelteKitParameters, + functions: string[], + defaultToAction?: boolean + ) { + // the array of every added listener, we can use this in the return function + // to clean them + const toRemove: Array<{ + eventType: string; + listener: (event: { detail: any[] }) => void; + }> = []; + functions.forEach((func) => { + // we loop over every function and check if the user actually passed + // a function in sveltekit_experimental[baseModule][func] eg. sveltekit_experimental.navigation.goto + const hasFunction = + (svelteKitParameters as any)[baseModule]?.[func] && + (svelteKitParameters as any)[baseModule][func] instanceof Function; + // if we default to an action we still add the listener (this will be the case for goto, invalidate, invalidateAll) + if (hasFunction || defaultToAction) { + // we create the listener that will just get the detail array from the custom element + // and call the user provided function spreading this args in...this will basically call + // the function that the user provide with the same arguments the function is invoked to + // eg. if it calls goto("/my-route") inside the component the function sveltekit_experimental.navigation.goto + // it provided to storybook will be called with "/my-route" + const listener = ({ detail = [] as any[] }) => { + const args = Array.isArray(detail) ? detail : []; + // if it has a function in the parameters we call that function + // otherwise we invoke the action + const fnToCall = hasFunction + ? (svelteKitParameters as any)[baseModule][func] + : action(func); + fnToCall(...args); + }; + const eventType = `storybook:${func}`; + toRemove.push({ eventType, listener }); + // add the listener to window + (window.addEventListener as any)(eventType, listener); + } + }); return () => { - window.removeEventListener('click', globalClickListener); - removeNavigationListeners(); - removeFormsListeners(); + // loop over every listener added and remove them + toRemove.forEach(({ eventType, listener }) => { + // @ts-expect-error apparently you can't remove a custom listener to the window with TS + window.removeEventListener(eventType, listener); + }); }; - }); + } + + const removeNavigationListeners = createListeners( + 'navigation', + ['goto', 'invalidate', 'invalidateAll', 'pushState', 'replaceState'], + true + ); + const removeFormsListeners = createListeners('forms', ['enhance']); + window.addEventListener('click', globalClickListener); + + return () => { + window.removeEventListener('click', globalClickListener); + removeNavigationListeners(); + removeFormsListeners(); + }; + }); + + return Story(); +}; - return Story(); - }, -]; +export const decorators: Decorator[] = [svelteKitMocksDecorator]; From 4f1b73d8ff7c5c49323912b9e420385cce45946c Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Thu, 5 Sep 2024 09:13:27 +0200 Subject: [PATCH 036/213] fix duplicate default annotations --- .../modules/store/csf/portable-stories.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/code/core/src/preview-api/modules/store/csf/portable-stories.ts b/code/core/src/preview-api/modules/store/csf/portable-stories.ts index 7adc83196eb1..1133e2e87a84 100644 --- a/code/core/src/preview-api/modules/store/csf/portable-stories.ts +++ b/code/core/src/preview-api/modules/store/csf/portable-stories.ts @@ -74,13 +74,19 @@ export function setProjectAnnotations( | NamedOrDefaultProjectAnnotations[] ): NormalizedProjectAnnotations { const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations]; - if (globalThis.defaultProjectAnnotations) { - annotations.push(globalThis.defaultProjectAnnotations); - } - globalThis.globalProjectAnnotations = composeConfigs(annotations.map(extractAnnotation)); - return globalThis.globalProjectAnnotations; + /* + We must return the composition of default and global annotations here + To ensure that the user has the full project annotations, eg. when running + + const projectAnnotations = setProjectAnnotations(...); + beforeAll(projectAnnotations.beforeAll) + */ + return composeConfigs([ + globalThis.defaultProjectAnnotations, + globalThis.globalProjectAnnotations, + ]); } const cleanups: CleanupCallback[] = []; From 8a7d8eee7ce16030111e009779b9fb15a70099c0 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Thu, 5 Sep 2024 10:53:11 +0200 Subject: [PATCH 037/213] fix decorator type --- code/frameworks/sveltekit/src/preview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/frameworks/sveltekit/src/preview.ts b/code/frameworks/sveltekit/src/preview.ts index c93cbde37a55..6eb8a816dd12 100644 --- a/code/frameworks/sveltekit/src/preview.ts +++ b/code/frameworks/sveltekit/src/preview.ts @@ -15,7 +15,7 @@ const normalizeHrefConfig = (hrefConfig: HrefConfig): NormalizedHrefConfig => { return hrefConfig; }; -const svelteKitMocksDecorator = (Story, ctx) => { +const svelteKitMocksDecorator: Decorator = (Story, ctx) => { const svelteKitParameters: SvelteKitParameters = ctx.parameters?.sveltekit_experimental ?? {}; setPage(svelteKitParameters?.stores?.page); setNavigating(svelteKitParameters?.stores?.navigating); From e4697f9d782700879ed2b4706965fcba8ff7a988 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Thu, 5 Sep 2024 13:25:27 +0200 Subject: [PATCH 038/213] fix composing undefined defaultProjectAnnotations --- .../src/preview-api/modules/store/csf/portable-stories.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/core/src/preview-api/modules/store/csf/portable-stories.ts b/code/core/src/preview-api/modules/store/csf/portable-stories.ts index 1133e2e87a84..fd50bd57c2dd 100644 --- a/code/core/src/preview-api/modules/store/csf/portable-stories.ts +++ b/code/core/src/preview-api/modules/store/csf/portable-stories.ts @@ -84,8 +84,8 @@ export function setProjectAnnotations( beforeAll(projectAnnotations.beforeAll) */ return composeConfigs([ - globalThis.defaultProjectAnnotations, - globalThis.globalProjectAnnotations, + globalThis.defaultProjectAnnotations ?? {}, + globalThis.globalProjectAnnotations ?? {}, ]); } From 758aaa1497d8ded23bc2f1c2e3662cf597ced881 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 5 Sep 2024 13:29:09 +0200 Subject: [PATCH 039/213] Next.js-Vite: Update vite-plugin-storybook-nextjs --- code/frameworks/experimental-nextjs-vite/package.json | 2 +- code/yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index c0a70eaecffd..83e8bfc35993 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -99,7 +99,7 @@ "@storybook/react": "workspace:*", "@storybook/test": "workspace:*", "styled-jsx": "5.1.6", - "vite-plugin-storybook-nextjs": "^1.0.10" + "vite-plugin-storybook-nextjs": "^1.0.11" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/code/yarn.lock b/code/yarn.lock index c3b25a45ce54..b7dcbf2eaa77 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6340,7 +6340,7 @@ __metadata: sharp: "npm:^0.33.3" styled-jsx: "npm:5.1.6" typescript: "npm:^5.3.2" - vite-plugin-storybook-nextjs: "npm:^1.0.10" + vite-plugin-storybook-nextjs: "npm:^1.0.11" peerDependencies: "@storybook/test": "workspace:*" next: ^14.1.0 @@ -28697,9 +28697,9 @@ __metadata: languageName: node linkType: hard -"vite-plugin-storybook-nextjs@npm:^1.0.10": - version: 1.0.10 - resolution: "vite-plugin-storybook-nextjs@npm:1.0.10" +"vite-plugin-storybook-nextjs@npm:^1.0.11": + version: 1.0.11 + resolution: "vite-plugin-storybook-nextjs@npm:1.0.11" dependencies: "@next/env": "npm:^14.2.5" image-size: "npm:^1.1.1" @@ -28715,7 +28715,7 @@ __metadata: dependenciesMeta: sharp: optional: true - checksum: 10c0/e0e373ef94e1761b871b2cc846c205a846901d93c7e61f9d9ee3c69740681e42e6403a7d61109c59f2d98d5829476c3e6d4e9d5a329c4bd51e758b763fa8ea9e + checksum: 10c0/9652b76c13a682b688d9a4f617b1a66263f25f395a99af8e258bedef4f3b3ce1c856ec1ff66cc0359d6aedc96adee9750fd6b0432514dd575ad7896cd1de70df languageName: node linkType: hard From 714913d6443c524666ef81de37d4e59709712b33 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 5 Sep 2024 15:33:36 +0200 Subject: [PATCH 040/213] Next.js: Fix react-dom/test-utils aliasing --- code/frameworks/nextjs/src/config/webpack.ts | 15 ++++++++++++++- code/renderers/react/src/act-compat.ts | 8 ++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/code/frameworks/nextjs/src/config/webpack.ts b/code/frameworks/nextjs/src/config/webpack.ts index 3e0d758c1514..57e7caa47bbe 100644 --- a/code/frameworks/nextjs/src/config/webpack.ts +++ b/code/frameworks/nextjs/src/config/webpack.ts @@ -20,6 +20,9 @@ export const configureConfig = async ({ nextConfigPath?: string; }): Promise => { const nextConfig = await resolveNextConfig({ nextConfigPath }); + baseConfig.resolve ??= {}; + baseConfig.resolve.alias ??= {}; + const aliasConfig = baseConfig.resolve.alias; addScopedAlias(baseConfig, 'next/config'); if (tryResolve('next/dist/compiled/react')) { @@ -31,9 +34,19 @@ export const configureConfig = async ({ 'react-dom/test-utils', 'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js' ); + } else { + const name = 'react-dom/test-utils'; + if (Array.isArray(aliasConfig)) { + aliasConfig.push({ + name, + alias: name, + }); + } else { + aliasConfig[name] = name; + } } if (tryResolve('next/dist/compiled/react-dom')) { - addScopedAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom'); + addScopedAlias(baseConfig, 'react-dom', 'next/dist/compiled/react-dom'); } setupRuntimeConfig(baseConfig, nextConfig); diff --git a/code/renderers/react/src/act-compat.ts b/code/renderers/react/src/act-compat.ts index afe1cc902316..31b4fb72e54f 100644 --- a/code/renderers/react/src/act-compat.ts +++ b/code/renderers/react/src/act-compat.ts @@ -8,8 +8,12 @@ declare const globalThis: { IS_REACT_ACT_ENVIRONMENT: boolean; }; -// @ts-expect-error act might not be available in some versions of React -const reactAct = typeof React.act === 'function' ? React.act : DeprecatedReactTestUtils.act; +const reactAct = + // @ts-expect-error act might not be available in some versions of React + typeof React.act === 'function' + ? // @ts-expect-error act might not be available in some versions of React + React.act + : DeprecatedReactTestUtils.act ?? (async (cb: () => Promise | void) => cb()); export function setReactActEnvironment(isReactActEnvironment: boolean) { globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment; From e6fdccdad3b31e954fb2dcdb6fcaa58e3dddcfdb Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 6 Sep 2024 14:27:32 +0200 Subject: [PATCH 041/213] skip source map generation for external globals --- .../builder-vite/src/plugins/external-globals-plugin.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts index 1c7ada46b7be..a71f9f3b0fe8 100644 --- a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts +++ b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts @@ -91,10 +91,7 @@ export async function externalGlobalsPlugin(externals: Record) { return { code: src.toString(), - map: src.generateMap({ - source: id, - hires: true, - }), + map: null, }; }, } satisfies Plugin; From 55d2ac1bdedff231b57a9b6895ece475e607bb88 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 6 Sep 2024 14:28:28 +0200 Subject: [PATCH 042/213] add test case for multi-line imports in external globals replacements --- .../src/plugins/external-globals-plugin.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/code/builders/builder-vite/src/plugins/external-globals-plugin.test.ts b/code/builders/builder-vite/src/plugins/external-globals-plugin.test.ts index 9555a4dd6b86..67b62690da43 100644 --- a/code/builders/builder-vite/src/plugins/external-globals-plugin.test.ts +++ b/code/builders/builder-vite/src/plugins/external-globals-plugin.test.ts @@ -12,6 +12,22 @@ const cases = [ input: `import { Rain, Jour as Day, Nuit as Night, Sun } from "${packageName}"`, output: `const { Rain, Jour: Day, Nuit: Night, Sun } = ${globals[packageName]}`, }, + { + globals, + packageName, + input: `import { + Rain, + Jour as Day, + Nuit as Night, + Sun + } from "${packageName}"`, + output: `const { + Rain, + Jour: Day, + Nuit: Night, + Sun + } = ${globals[packageName]}`, + }, { globals, packageName, From ea1a533a4b4e0017fb1a93baaf76c51be25fe66b Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 6 Sep 2024 11:46:32 +0200 Subject: [PATCH 043/213] Fix Webpack aliasing --- code/frameworks/nextjs/src/config/webpack.ts | 31 ++++++++++---------- code/frameworks/nextjs/src/utils.ts | 20 ++++++++----- code/renderers/react/src/act-compat.ts | 5 +--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/code/frameworks/nextjs/src/config/webpack.ts b/code/frameworks/nextjs/src/config/webpack.ts index 57e7caa47bbe..a0ea2d47bded 100644 --- a/code/frameworks/nextjs/src/config/webpack.ts +++ b/code/frameworks/nextjs/src/config/webpack.ts @@ -2,7 +2,7 @@ import type { NextConfig } from 'next'; import type { Configuration as WebpackConfig } from 'webpack'; import { DefinePlugin } from 'webpack'; -import { addScopedAlias, resolveNextConfig } from '../utils'; +import { addScopedAlias, resolveNextConfig, setAlias } from '../utils'; const tryResolve = (path: string) => { try { @@ -20,33 +20,32 @@ export const configureConfig = async ({ nextConfigPath?: string; }): Promise => { const nextConfig = await resolveNextConfig({ nextConfigPath }); - baseConfig.resolve ??= {}; - baseConfig.resolve.alias ??= {}; - const aliasConfig = baseConfig.resolve.alias; addScopedAlias(baseConfig, 'next/config'); + + // @ts-expect-error We know that alias is an object + if (baseConfig.resolve?.alias?.['react-dom']) { + // Removing the alias to react-dom to avoid conflicts with the alias we are setting + // because the react-dom alias is an exact match and we need to alias separate parts of react-dom + // in different places + // @ts-expect-error We know that alias is an object + delete baseConfig.resolve.alias?.['react-dom']; + } + if (tryResolve('next/dist/compiled/react')) { addScopedAlias(baseConfig, 'react', 'next/dist/compiled/react'); } if (tryResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js')) { - addScopedAlias( + setAlias( baseConfig, 'react-dom/test-utils', 'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js' ); - } else { - const name = 'react-dom/test-utils'; - if (Array.isArray(aliasConfig)) { - aliasConfig.push({ - name, - alias: name, - }); - } else { - aliasConfig[name] = name; - } } if (tryResolve('next/dist/compiled/react-dom')) { - addScopedAlias(baseConfig, 'react-dom', 'next/dist/compiled/react-dom'); + setAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom'); + setAlias(baseConfig, 'react-dom/client', 'next/dist/compiled/react-dom/client'); + setAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server'); } setupRuntimeConfig(baseConfig, nextConfig); diff --git a/code/frameworks/nextjs/src/utils.ts b/code/frameworks/nextjs/src/utils.ts index 9c8abc6c88c8..198917513166 100644 --- a/code/frameworks/nextjs/src/utils.ts +++ b/code/frameworks/nextjs/src/utils.ts @@ -27,23 +27,27 @@ export const resolveNextConfig = async ({ return loadConfig(PHASE_DEVELOPMENT_SERVER, dir, undefined); }; -// This is to help the addon in development -// Without it, webpack resolves packages in its node_modules instead of the example's node_modules -export const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?: string): void => { +export function setAlias(baseConfig: WebpackConfig, name: string, alias: string) { baseConfig.resolve ??= {}; baseConfig.resolve.alias ??= {}; const aliasConfig = baseConfig.resolve.alias; - const scopedAlias = scopedResolve(`${alias ?? name}`); - if (Array.isArray(aliasConfig)) { aliasConfig.push({ name, - alias: scopedAlias, + alias, }); } else { - aliasConfig[name] = scopedAlias; + aliasConfig[name] = alias; } +} + +// This is to help the addon in development +// Without it, webpack resolves packages in its node_modules instead of the example's node_modules +export const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?: string): void => { + const scopedAlias = scopedResolve(`${alias ?? name}`); + + setAlias(baseConfig, name, scopedAlias); }; /** @@ -64,7 +68,7 @@ export const scopedResolve = (id: string): string => { let scopedModulePath; try { - // TODO: Remove in next major release (SB 8.0) and use the statement in the catch block per default instead + // TODO: Remove in next major release (SB 9.0) and use the statement in the catch block per default instead scopedModulePath = require.resolve(id, { paths: [resolve()] }); } catch (e) { scopedModulePath = require.resolve(id); diff --git a/code/renderers/react/src/act-compat.ts b/code/renderers/react/src/act-compat.ts index 31b4fb72e54f..3eab722d3bb1 100644 --- a/code/renderers/react/src/act-compat.ts +++ b/code/renderers/react/src/act-compat.ts @@ -10,10 +10,7 @@ declare const globalThis: { const reactAct = // @ts-expect-error act might not be available in some versions of React - typeof React.act === 'function' - ? // @ts-expect-error act might not be available in some versions of React - React.act - : DeprecatedReactTestUtils.act ?? (async (cb: () => Promise | void) => cb()); + typeof React.act === 'function' ? React.act : DeprecatedReactTestUtils.act; export function setReactActEnvironment(isReactActEnvironment: boolean) { globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment; From 0a1d9e8dfb769054740e626e86f79fe4dde45ce5 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 6 Sep 2024 14:53:42 +0200 Subject: [PATCH 044/213] exclude sb-preview/runtime.js from stats-json --- .../src/plugins/webpack-stats-plugin.ts | 41 +- preview-stats-new-ids.json | 2914 +++++++++++++++++ 2 files changed, 2936 insertions(+), 19 deletions(-) create mode 100644 preview-stats-new-ids.json diff --git a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts index 9442291df2aa..658f8ea9c31e 100644 --- a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts +++ b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts @@ -42,7 +42,8 @@ function isUserCode(moduleName: string) { !moduleName.startsWith('\x00') && !moduleName.startsWith('\u0000') && moduleName !== 'react/jsx-runtime' && - !moduleName.match(/node_modules\//) + !moduleName.match(/node_modules\//) && + !moduleName.includes('sb-preview/runtime.js') ); } @@ -87,25 +88,27 @@ export function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): W // We want this to run after the vite build plugins (https://vitejs.dev/guide/api-plugin.html#plugin-ordering) enforce: 'post', moduleParsed: function (mod) { - if (isUserCode(mod.id)) { - mod.importedIds - .concat(mod.dynamicallyImportedIds) - .filter((name) => isUserCode(name)) - .forEach((depIdUnsafe) => { - const depId = normalize(depIdUnsafe); - if (statsMap.has(depId)) { - const m = statsMap.get(depId); - if (m) { - m.reasons = (m.reasons ?? []) - .concat(createReasons([mod.id])) - .filter((r) => r.moduleName !== depId); - statsMap.set(depId, m); - } - } else { - statsMap.set(depId, createStatsMapModule(depId, [mod.id])); - } - }); + if (!isUserCode(mod.id)) { + return; } + mod.importedIds + .concat(mod.dynamicallyImportedIds) + .filter((name) => isUserCode(name)) + .forEach((depIdUnsafe) => { + const depId = normalize(depIdUnsafe); + if (!statsMap.has(depId)) { + statsMap.set(depId, createStatsMapModule(depId, [mod.id])); + return; + } + const m = statsMap.get(depId); + if (!m) { + return; + } + m.reasons = (m.reasons ?? []) + .concat(createReasons([mod.id])) + .filter((r) => r.moduleName !== depId); + statsMap.set(depId, m); + }); }, storybookGetStats() { diff --git a/preview-stats-new-ids.json b/preview-stats-new-ids.json new file mode 100644 index 000000000000..9bc467c67f5b --- /dev/null +++ b/preview-stats-new-ids.json @@ -0,0 +1,2914 @@ +{ + "modules": [ + { + "id": "./iframe.html", + "name": "./iframe.html", + "reasons": [ + { + "moduleName": "./iframe.html" + } + ] + }, + { + "id": "./sb-preview/runtime.js", + "name": "./sb-preview/runtime.js", + "reasons": [ + { + "moduleName": "./iframe.html" + } + ] + }, + { + "id": "./renderers/react/template/components/Button.jsx", + "name": "./renderers/react/template/components/Button.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Form.jsx", + "name": "./renderers/react/template/components/Form.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Html.jsx", + "name": "./renderers/react/template/components/Html.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Pre.jsx", + "name": "./renderers/react/template/components/Pre.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./addons/interactions/src/mocks/index.ts", + "name": "./addons/interactions/src/mocks/index.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Interaction.tsx", + "name": "./addons/interactions/src/components/Interaction.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Subnav.stories.tsx", + "name": "./addons/interactions/src/components/Subnav.stories.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/brand/StorybookIcon.tsx", + "name": "./core/src/components/brand/StorybookIcon.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/StorybookIcon.stories.tsx" + } + ] + }, + { + "id": "./addons/controls/src/SaveStory.tsx", + "name": "./addons/controls/src/SaveStory.tsx", + "reasons": [ + { + "moduleName": "./addons/controls/src/SaveStory.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/brand/StorybookLogo.tsx", + "name": "./core/src/components/brand/StorybookLogo.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/StorybookLogo.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/index.ts", + "name": "./lib/blocks/src/components/index.ts", + "reasons": [ + { + "moduleName": "./.storybook/preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/mdx.tsx" + } + ] + }, + { + "id": "./.storybook/isChromatic.ts", + "name": "./.storybook/isChromatic.ts", + "reasons": [ + { + "moduleName": "./.storybook/preview.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/InteractionsPanel.tsx", + "name": "./addons/interactions/src/components/InteractionsPanel.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/MatcherResult.tsx", + "name": "./addons/interactions/src/components/MatcherResult.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/MatcherResult.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/StatusIcon.tsx", + "name": "./addons/interactions/src/components/StatusIcon.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/StatusIcon.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/MethodCall.tsx", + "name": "./addons/interactions/src/components/MethodCall.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/MethodCall.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/MatcherResult.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/StatusBadge.tsx", + "name": "./addons/interactions/src/components/StatusBadge.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/StatusBadge.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Subnav.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ActionBar/ActionBar.tsx", + "name": "./core/src/components/components/ActionBar/ActionBar.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ActionBar/ActionBar.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Subnav.tsx", + "name": "./addons/interactions/src/components/Subnav.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Subnav.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./core/src/components/components/form/index.tsx", + "name": "./core/src/components/components/form/index.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Button/Button.tsx", + "name": "./core/src/components/components/Button/Button.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Button/Button.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + }, + { + "moduleName": "./core/src/components/components/IconButton/IconButton.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/Button/Button.tsx", + "name": "./addons/onboarding/src/components/Button/Button.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/Button/Button.stories.tsx" + }, + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Badge/Badge.tsx", + "name": "./core/src/components/components/Badge/Badge.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Badge/Badge.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/Confetti/Confetti.tsx", + "name": "./addons/onboarding/src/components/Confetti/Confetti.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/Confetti/Confetti.stories.tsx" + } + ] + }, + { + "id": "./addons/docs/template/stories/docs2/button.stories.ts", + "name": "./addons/docs/template/stories/docs2/button.stories.ts", + "reasons": [ + { + "moduleName": "./addons/docs/template/stories/docs2/MetaOf.mdx" + }, + { + "moduleName": "./addons/docs/template/stories/docs2/MetaOfNamed.mdx" + } + ] + }, + { + "id": "./core/src/components/brand/SideBySide.tsx", + "name": "./core/src/components/brand/SideBySide.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/colorpalette.mdx" + } + ] + }, + { + "id": "./core/src/components/components/Button/Button.stories.tsx", + "name": "./core/src/components/components/Button/Button.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Docs.mdx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Unstyled.tsx", + "name": "./lib/blocks/src/blocks/Unstyled.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Unstyled.mdx" + }, + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", + "name": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", + "name": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", + "name": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/IconButton/IconButton.tsx", + "name": "./core/src/components/components/IconButton/IconButton.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/IconButton/IconButton.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Modal/Modal.styled.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Loader/Loader.tsx", + "name": "./core/src/components/components/Loader/Loader.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Loader/Loader.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/List.tsx", + "name": "./addons/onboarding/src/components/List/List.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", + "name": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", + "name": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Modal/Modal.tsx", + "name": "./core/src/components/components/Modal/Modal.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ScrollArea/ScrollArea.tsx", + "name": "./core/src/components/components/ScrollArea/ScrollArea.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ScrollArea/ScrollArea.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/bar/bar.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", + "name": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", + "reasons": [ + { + "moduleName": "./addons/docs/template/stories/docs2/ResolvedReact.mdx" + } + ] + }, + { + "id": "./core/src/components/components/form/field/field.tsx", + "name": "./core/src/components/components/form/field/field.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/form/form.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + } + ] + }, + { + "id": "./core/src/components/components/form/input/input.tsx", + "name": "./core/src/components/components/form/input/input.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/form/form.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/Zoom.tsx", + "name": "./core/src/components/components/Zoom/Zoom.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/icon/icon.tsx", + "name": "./core/src/components/components/icon/icon.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/icon/icon.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/typography/link/link.tsx", + "name": "./core/src/components/components/typography/link/link.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/typography/link/link.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.tsx" + } + ] + }, + { + "id": "./core/src/components/components/placeholder/placeholder.tsx", + "name": "./core/src/components/components/placeholder/placeholder.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/spaced/Spaced.tsx", + "name": "./core/src/components/components/spaced/Spaced.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/spaced/Spaced.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/EmptyTabContent.tsx", + "name": "./core/src/components/components/tabs/EmptyTabContent.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/EmptyTabContent.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.tsx", + "name": "./core/src/components/components/tabs/tabs.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/Tooltip.tsx", + "name": "./core/src/components/components/tooltip/Tooltip.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/Tooltip.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/ListItem.tsx", + "name": "./core/src/components/components/tooltip/ListItem.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/ListItem.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipLinkList.tsx", + "name": "./core/src/components/components/tooltip/TooltipLinkList.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/WithTooltip.tsx", + "name": "./core/src/components/components/tooltip/WithTooltip.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/assets/ellipse.png", + "name": "./core/src/components/components/tooltip/assets/ellipse.png", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipNote.tsx", + "name": "./core/src/components/components/tooltip/TooltipNote.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipMessage.tsx", + "name": "./core/src/components/components/tooltip/TooltipMessage.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", + "name": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/typography/DocumentWrapper.tsx", + "name": "./core/src/components/components/typography/DocumentWrapper.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/typography/DocumentWrapper.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/Layout.tsx", + "name": "./core/src/manager/components/layout/Layout.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/LayoutProvider.tsx", + "name": "./core/src/manager/components/layout/LayoutProvider.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + }, + { + "moduleName": "./core/src/manager/components/panel/Panel.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Menu.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/about/MobileAbout.tsx", + "name": "./core/src/manager/components/mobile/about/MobileAbout.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationItem.tsx", + "name": "./core/src/manager/components/notifications/NotificationItem.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationItem.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", + "name": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationList.tsx", + "name": "./core/src/manager/components/notifications/NotificationList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" + }, + { + "moduleName": "./core/src/manager/container/Notifications.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/preview/Iframe.tsx", + "name": "./core/src/manager/components/preview/Iframe.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/preview/Iframe.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/defaultShortcuts.tsx", + "name": "./core/src/manager/settings/defaultShortcuts.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" + }, + { + "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/panel/Panel.tsx", + "name": "./core/src/manager/components/panel/Panel.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Explorer.tsx", + "name": "./core/src/manager/components/sidebar/Explorer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/IconSymbols.tsx", + "name": "./core/src/manager/components/sidebar/IconSymbols.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/IconSymbols.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/utils/status.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Refs.stories.tsx", + "name": "./core/src/manager/components/sidebar/Refs.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/mockdata.ts", + "name": "./core/src/manager/components/sidebar/mockdata.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchList.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FilterToggle.tsx", + "name": "./core/src/manager/components/sidebar/FilterToggle.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FilterToggle.stories.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchModal.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchModal.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Heading.tsx", + "name": "./core/src/manager/components/sidebar/Heading.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Heading.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Search.tsx", + "name": "./core/src/manager/components/sidebar/Search.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SearchResults.tsx", + "name": "./core/src/manager/components/sidebar/SearchResults.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", + "name": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Sidebar.tsx", + "name": "./core/src/manager/components/sidebar/Sidebar.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + }, + { + "moduleName": "./core/src/manager/utils/tree.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/mockdata.large.ts", + "name": "./core/src/manager/components/sidebar/mockdata.large.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/container/Menu.tsx", + "name": "./core/src/manager/container/Menu.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/container/Menu.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Menu.tsx", + "name": "./core/src/manager/components/sidebar/Menu.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" + } + ] + }, + { + "id": "./core/src/manager/utils/tree.ts", + "name": "./core/src/manager/utils/tree.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" + }, + { + "moduleName": "./core/src/manager/utils/status.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/StatusContext.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Heading.stories.tsx", + "name": "./core/src/manager/components/sidebar/Heading.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Refs.tsx", + "name": "./core/src/manager/components/sidebar/Refs.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SidebarBottom.tsx", + "name": "./core/src/manager/components/sidebar/SidebarBottom.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Tree.tsx", + "name": "./core/src/manager/components/sidebar/Tree.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", + "name": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/settings/About.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/HighlightStyles.tsx", + "name": "./core/src/manager/components/sidebar/HighlightStyles.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/TreeNode.tsx", + "name": "./core/src/manager/components/sidebar/TreeNode.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/shortcuts.tsx", + "name": "./core/src/manager/settings/shortcuts.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/whats_new.tsx", + "name": "./core/src/manager/settings/whats_new.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/whats_new_footer.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", + "name": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/about.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/About.tsx", + "name": "./core/src/manager/settings/About.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/about.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/SettingsFooter.tsx", + "name": "./core/src/manager/settings/SettingsFooter.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/SettingsFooter.stories.tsx" + }, + { + "moduleName": "./core/src/manager/settings/shortcuts.tsx" + } + ] + }, + { + "id": "./core/template/stories/import.js", + "name": "./core/template/stories/import.js", + "reasons": [ + { + "moduleName": "./core/template/stories/interleavedExports.stories.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Anchor.tsx", + "name": "./lib/blocks/src/blocks/Anchor.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Anchor.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/EmptyBlock.tsx", + "name": "./lib/blocks/src/components/EmptyBlock.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/EmptyBlock.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/ArgTypes.tsx", + "name": "./lib/blocks/src/blocks/ArgTypes.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Button.stories.tsx", + "name": "./lib/blocks/src/examples/Button.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", + "name": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/SourceParameters.stories.tsx", + "name": "./lib/blocks/src/examples/SourceParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Canvas.tsx", + "name": "./lib/blocks/src/blocks/Canvas.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Source.stories.tsx", + "name": "./lib/blocks/src/blocks/Source.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/IconGallery.tsx", + "name": "./lib/blocks/src/components/IconGallery.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/IconGallery.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Markdown.tsx", + "name": "./lib/blocks/src/blocks/Markdown.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Markdown.stories.tsx", + "name": "./lib/blocks/src/blocks/Markdown.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/DocsPage.tsx", + "name": "./lib/blocks/src/components/DocsPage.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/Preview.stories.tsx", + "name": "./lib/blocks/src/components/Preview.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Source.stories.tsx", + "name": "./lib/blocks/src/components/Source.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", + "name": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Controls.tsx", + "name": "./lib/blocks/src/blocks/Controls.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Button.tsx", + "name": "./lib/blocks/src/examples/Button.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonReadonly.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/Button.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Description.tsx", + "name": "./lib/blocks/src/blocks/Description.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Source.tsx", + "name": "./lib/blocks/src/components/Source.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Markdown-content.md", + "name": "./lib/blocks/src/examples/Markdown-content.md", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Title.tsx", + "name": "./lib/blocks/src/components/Title.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Title.stories.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsPage.tsx", + "name": "./lib/blocks/src/blocks/DocsPage.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Preview.tsx", + "name": "./lib/blocks/src/components/Preview.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/Story.tsx", + "name": "./lib/blocks/src/components/Story.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Typeset.tsx", + "name": "./lib/blocks/src/components/Typeset.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Typeset.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", + "name": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Primary.tsx", + "name": "./lib/blocks/src/blocks/Primary.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Source.tsx", + "name": "./lib/blocks/src/blocks/Source.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/SourceContainer.tsx", + "name": "./lib/blocks/src/blocks/SourceContainer.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Stories.tsx", + "name": "./lib/blocks/src/blocks/Stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Boolean.tsx", + "name": "./lib/blocks/src/controls/Boolean.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Boolean.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Color.tsx", + "name": "./lib/blocks/src/controls/Color.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Color.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Files.tsx", + "name": "./lib/blocks/src/controls/Files.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Files.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Story.stories.tsx", + "name": "./lib/blocks/src/components/Story.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/StoryParameters.stories.tsx", + "name": "./lib/blocks/src/examples/StoryParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Story.tsx", + "name": "./lib/blocks/src/blocks/Story.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Date.tsx", + "name": "./lib/blocks/src/controls/Date.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Date.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Subtitle.tsx", + "name": "./lib/blocks/src/blocks/Subtitle.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Number.tsx", + "name": "./lib/blocks/src/controls/Number.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Number.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Range.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Title.tsx", + "name": "./lib/blocks/src/blocks/Title.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Object.tsx", + "name": "./lib/blocks/src/controls/Object.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Object.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Range.tsx", + "name": "./lib/blocks/src/controls/Range.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Range.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", + "name": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Text.tsx", + "name": "./lib/blocks/src/controls/Text.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Text.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", + "name": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Options.tsx", + "name": "./lib/blocks/src/controls/options/Options.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/CheckOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/RadioOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/SelectOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesParameters.tsx", + "name": "./lib/blocks/src/examples/ArgTypesParameters.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ColorPalette.tsx", + "name": "./lib/blocks/src/components/ColorPalette.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ColorPalette.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsParameters.tsx", + "name": "./lib/blocks/src/examples/ControlsParameters.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/ControlsParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/EmptyExample.tsx", + "name": "./lib/blocks/src/examples/EmptyExample.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/CanvasParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/DocsPageParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/SourceParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/StoriesParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/SimpleSizeTest.tsx", + "name": "./lib/blocks/src/examples/SimpleSizeTest.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/StoryParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/index.ts", + "name": "./lib/blocks/src/components/ArgsTable/index.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/IFrame.tsx", + "name": "./lib/blocks/src/components/IFrame.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Story.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/utils.ts", + "name": "./addons/interactions/src/utils.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/EmptyState.tsx", + "name": "./addons/interactions/src/components/EmptyState.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./core/src/components/components/shared/animation.ts", + "name": "./core/src/components/components/shared/animation.ts", + "reasons": [ + { + "moduleName": "./core/src/components/components/Loader/Loader.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", + "name": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/List.styled.tsx", + "name": "./addons/onboarding/src/components/List/List.styled.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", + "name": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Modal/Modal.styled.tsx", + "name": "./core/src/components/components/Modal/Modal.styled.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Modal/Modal.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/ZoomElement.tsx", + "name": "./core/src/components/components/Zoom/ZoomElement.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/ZoomIFrame.tsx", + "name": "./core/src/components/components/Zoom/ZoomIFrame.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", + "name": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/formatter.ts", + "name": "./core/src/components/components/syntaxhighlighter/formatter.ts", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./core/src/components/components/bar/bar.tsx", + "name": "./core/src/components/components/bar/bar.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/bar/button.tsx", + "name": "./core/src/components/components/bar/button.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.helpers.tsx", + "name": "./core/src/components/components/tabs/tabs.helpers.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.hooks.tsx", + "name": "./core/src/components/components/tabs/tabs.hooks.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/manager/constants.ts", + "name": "./core/src/manager/constants.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + }, + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + }, + { + "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/hooks/useMedia.tsx", + "name": "./core/src/manager/components/hooks/useMedia.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + } + ] + }, + { + "id": "./core/src/manager/container/Notifications.tsx", + "name": "./core/src/manager/container/Notifications.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/useDragging.ts", + "name": "./core/src/manager/components/layout/useDragging.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileList.tsx", + "name": "./core/src/manager/components/sidebar/FileList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useHighlighted.ts", + "name": "./core/src/manager/components/sidebar/useHighlighted.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/hooks/useMeasure.tsx", + "name": "./core/src/manager/hooks/useMeasure.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", + "name": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Brand.tsx", + "name": "./core/src/manager/components/sidebar/Brand.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useLastViewed.ts", + "name": "./core/src/manager/components/sidebar/useLastViewed.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/keybinding.ts", + "name": "./core/src/manager/keybinding.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" + } + ] + }, + { + "id": "./core/src/manager/utils/status.tsx", + "name": "./core/src/manager/utils/status.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/StatusButton.tsx", + "name": "./core/src/manager/components/sidebar/StatusButton.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/types.ts", + "name": "./core/src/manager/components/sidebar/types.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", + "name": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/RefBlocks.tsx", + "name": "./core/src/manager/components/sidebar/RefBlocks.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/RefIndicator.tsx", + "name": "./core/src/manager/components/sidebar/RefIndicator.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", + "name": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/StatusContext.tsx", + "name": "./core/src/manager/components/sidebar/StatusContext.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useExpanded.ts", + "name": "./core/src/manager/components/sidebar/useExpanded.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useOf.ts", + "name": "./lib/blocks/src/blocks/useOf.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/utils.ts", + "name": "./lib/blocks/src/blocks/utils.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", + "name": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/IconGallery.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Typeset.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ColorPalette.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/mdx.tsx", + "name": "./lib/blocks/src/blocks/mdx.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Markdown.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Heading.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subheading.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsContext.ts", + "name": "./lib/blocks/src/blocks/DocsContext.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/useOf.ts" + }, + { + "moduleName": "./lib/blocks/src/blocks/mdx.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useArgs.ts", + "name": "./lib/blocks/src/blocks/useArgs.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useGlobals.ts", + "name": "./lib/blocks/src/blocks/useGlobals.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Toolbar.tsx", + "name": "./lib/blocks/src/components/Toolbar.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ZoomContext.tsx", + "name": "./lib/blocks/src/components/ZoomContext.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsStory.tsx", + "name": "./lib/blocks/src/blocks/DocsStory.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Heading.tsx", + "name": "./lib/blocks/src/blocks/Heading.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/helpers.ts", + "name": "./lib/blocks/src/controls/helpers.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Boolean.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Files.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Color.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Number.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Date.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Object.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Range.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Text.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Select.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useStory.ts", + "name": "./lib/blocks/src/blocks/useStory.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", + "name": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Object.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/Empty.tsx", + "name": "./lib/blocks/src/components/ArgsTable/Empty.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", + "name": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Checkbox.tsx", + "name": "./lib/blocks/src/controls/options/Checkbox.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Radio.tsx", + "name": "./lib/blocks/src/controls/options/Radio.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Select.tsx", + "name": "./lib/blocks/src/controls/options/Select.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/types.ts", + "name": "./lib/blocks/src/components/ArgsTable/types.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./addons/interactions/src/constants.ts", + "name": "./addons/interactions/src/constants.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/EmptyState.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Loader.tsx", + "name": "./core/src/manager/components/sidebar/Loader.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/RefBlocks.tsx" + } + ] + }, + { + "id": "./core/src/manager/hooks/useDebounce.ts", + "name": "./core/src/manager/hooks/useDebounce.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Subheading.tsx", + "name": "./lib/blocks/src/blocks/Subheading.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/index.tsx", + "name": "./lib/blocks/src/controls/index.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", + "name": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/helpers.ts", + "name": "./lib/blocks/src/controls/options/helpers.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Select.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/types.ts", + "name": "./lib/blocks/src/controls/types.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/index.ts", + "name": "./lib/blocks/src/controls/options/index.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + } + ] +} \ No newline at end of file From c24f22182edb47bf7da8fa4230b0b37cc054db62 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 6 Sep 2024 15:21:04 +0200 Subject: [PATCH 045/213] Remove console.log --- code/renderers/react/src/portable-stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderers/react/src/portable-stories.tsx b/code/renderers/react/src/portable-stories.tsx index ced0bbd289e3..bc031a04717e 100644 --- a/code/renderers/react/src/portable-stories.tsx +++ b/code/renderers/react/src/portable-stories.tsx @@ -98,7 +98,7 @@ export const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations Date: Fri, 6 Sep 2024 15:56:46 +0200 Subject: [PATCH 046/213] keep virtual files backwards compatible in stats-json also cleanup code slightly --- .../src/codegen-modern-iframe-script.ts | 9 +- .../src/plugins/code-generator-plugin.ts | 36 +- .../src/plugins/webpack-stats-plugin.ts | 71 +- .../builder-vite/src/utils/virtual-module.ts | 3 - .../builder-vite/src/virtual-file-names.ts | 18 +- preview-stats-new-ids.json | 2914 +++++++++++++++++ 6 files changed, 2989 insertions(+), 62 deletions(-) delete mode 100644 code/builders/builder-vite/src/utils/virtual-module.ts create mode 100644 preview-stats-new-ids.json diff --git a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts index 86756b002a27..7ad50afec12f 100644 --- a/code/builders/builder-vite/src/codegen-modern-iframe-script.ts +++ b/code/builders/builder-vite/src/codegen-modern-iframe-script.ts @@ -2,8 +2,7 @@ import { getFrameworkName, loadPreviewOrConfigFile } from 'storybook/internal/co import type { Options, PreviewAnnotation } from 'storybook/internal/types'; import { processPreviewAnnotation } from './utils/process-preview-annotation'; -import { getResolvedVirtualModuleId } from './utils/virtual-module'; -import { virtualAddonSetupFile, virtualStoriesFile } from './virtual-file-names'; +import { SB_VIRTUAL_FILES, getResolvedVirtualModuleId } from './virtual-file-names'; export async function generateModernIframeScriptCode(options: Options, projectRoot: string) { const { presets, configDir } = options; @@ -46,7 +45,7 @@ export async function generateModernIframeScriptCode(options: Options, projectRo return ` if (import.meta.hot) { - import.meta.hot.accept('${getResolvedVirtualModuleId(virtualStoriesFile)}', (newModule) => { + import.meta.hot.accept('${getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE)}', (newModule) => { // importFn has changed so we need to patch the new one in window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn }); }); @@ -69,8 +68,8 @@ export async function generateModernIframeScriptCode(options: Options, projectRo */ const code = ` import { composeConfigs, PreviewWeb, ClientApi } from 'storybook/internal/preview-api'; - import '${virtualAddonSetupFile}'; - import { importFn } from '${virtualStoriesFile}'; + import '${SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE}'; + import { importFn } from '${SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE}'; ${getPreviewAnnotationsFunction} diff --git a/code/builders/builder-vite/src/plugins/code-generator-plugin.ts b/code/builders/builder-vite/src/plugins/code-generator-plugin.ts index 1909ceda0988..77509b97cf93 100644 --- a/code/builders/builder-vite/src/plugins/code-generator-plugin.ts +++ b/code/builders/builder-vite/src/plugins/code-generator-plugin.ts @@ -8,13 +8,7 @@ import { generateImportFnScriptCode } from '../codegen-importfn-script'; import { generateModernIframeScriptCode } from '../codegen-modern-iframe-script'; import { generateAddonSetupCode } from '../codegen-set-addon-channel'; import { transformIframeHtml } from '../transform-iframe-html'; -import { getResolvedVirtualModuleId } from '../utils/virtual-module'; -import { - virtualAddonSetupFile, - virtualFileId, - virtualPreviewFile, - virtualStoriesFile, -} from '../virtual-file-names'; +import { SB_VIRTUAL_FILES, getResolvedVirtualModuleId } from '../virtual-file-names'; export function codeGeneratorPlugin(options: Options): Plugin { const iframePath = require.resolve('@storybook/builder-vite/input/iframe.html'); @@ -30,13 +24,13 @@ export function codeGeneratorPlugin(options: Options): Plugin { // (this might be a little too aggressive?) server.watcher.on('change', () => { const appModule = server.moduleGraph.getModuleById( - getResolvedVirtualModuleId(virtualFileId) + getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_APP_FILE) ); if (appModule) { server.moduleGraph.invalidateModule(appModule); } const storiesModule = server.moduleGraph.getModuleById( - getResolvedVirtualModuleId(virtualStoriesFile) + getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE) ); if (storiesModule) { server.moduleGraph.invalidateModule(storiesModule); @@ -50,7 +44,7 @@ export function codeGeneratorPlugin(options: Options): Plugin { // TODO maybe use the stories declaration in main if (/\.stories\.([tj])sx?$/.test(path) || /\.mdx$/.test(path)) { // We need to emit a change event to trigger HMR - server.watcher.emit('change', virtualStoriesFile); + server.watcher.emit('change', SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE); } }); }, @@ -74,34 +68,34 @@ export function codeGeneratorPlugin(options: Options): Plugin { iframeId = `${config.root}/iframe.html`; }, resolveId(source) { - if (source === virtualFileId) { - return getResolvedVirtualModuleId(virtualFileId); + if (source === SB_VIRTUAL_FILES.VIRTUAL_APP_FILE) { + return getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_APP_FILE); } if (source === iframePath) { return iframeId; } - if (source === virtualStoriesFile) { - return getResolvedVirtualModuleId(virtualStoriesFile); + if (source === SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE) { + return getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE); } - if (source === virtualPreviewFile) { - return getResolvedVirtualModuleId(virtualPreviewFile); + if (source === SB_VIRTUAL_FILES.VIRTUAL_PREVIEW_FILE) { + return getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_PREVIEW_FILE); } - if (source === virtualAddonSetupFile) { - return getResolvedVirtualModuleId(virtualAddonSetupFile); + if (source === SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE) { + return getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE); } return undefined; }, async load(id, config) { - if (id === getResolvedVirtualModuleId(virtualStoriesFile)) { + if (id === getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE)) { return generateImportFnScriptCode(options); } - if (id === getResolvedVirtualModuleId(virtualAddonSetupFile)) { + if (id === getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE)) { return generateAddonSetupCode(); } - if (id === getResolvedVirtualModuleId(virtualFileId)) { + if (id === getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_APP_FILE)) { return generateModernIframeScriptCode(options, projectRoot); } diff --git a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts index 9442291df2aa..cacea74ccaf2 100644 --- a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts +++ b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts @@ -6,7 +6,11 @@ import type { BuilderStats } from 'storybook/internal/types'; import slash from 'slash'; import type { Plugin } from 'vite'; -import { getResolvedVirtualModuleId } from '../utils/virtual-module'; +import { + SB_VIRTUAL_FILES, + getOriginalVirtualModuleId, + getResolvedVirtualModuleId, +} from '../virtual-file-names'; /* * Reason, Module are copied from chromatic types @@ -37,12 +41,13 @@ function stripQueryParams(filePath: string): string { /** We only care about user code, not node_modules, vite files, or (most) virtual files. */ function isUserCode(moduleName: string) { return Boolean( - moduleName && - !moduleName.startsWith('vite/') && - !moduleName.startsWith('\x00') && - !moduleName.startsWith('\u0000') && - moduleName !== 'react/jsx-runtime' && - !moduleName.match(/node_modules\//) + (moduleName && + // keep Storybook's virtual files because they import the story files, so they are essential to the module graph + Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(moduleName))) || + (!moduleName.startsWith('vite/') && + !moduleName.startsWith('\0') && + moduleName !== 'react/jsx-runtime' && + !moduleName.match(/node_modules\//)) ); } @@ -52,12 +57,17 @@ export function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): W /** Convert an absolute path name to a path relative to the vite root, with a starting `./` */ function normalize(filename: string) { // Do not try to resolve virtual files - if ( - filename.startsWith('/virtual:') || - filename.startsWith(getResolvedVirtualModuleId('/virtual:')) - ) { + if (filename.startsWith('/virtual:')) { return filename; } + // ! Maintain backwards compatibility with the old virtual file names + // ! to ensure that the stats file doesn't change between the versions + // ! Turbosnap is also only compatible with the old virtual file names + // ! the old virtual file names did not start with the obligatory \0 character + if (Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(filename))) { + return getOriginalVirtualModuleId(filename); + } + // Otherwise, we need them in the format `./path/to/file.js`. else { const relativePath = relative(workingDir, stripQueryParams(filename)); @@ -87,25 +97,28 @@ export function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): W // We want this to run after the vite build plugins (https://vitejs.dev/guide/api-plugin.html#plugin-ordering) enforce: 'post', moduleParsed: function (mod) { - if (isUserCode(mod.id)) { - mod.importedIds - .concat(mod.dynamicallyImportedIds) - .filter((name) => isUserCode(name)) - .forEach((depIdUnsafe) => { - const depId = normalize(depIdUnsafe); - if (statsMap.has(depId)) { - const m = statsMap.get(depId); - if (m) { - m.reasons = (m.reasons ?? []) - .concat(createReasons([mod.id])) - .filter((r) => r.moduleName !== depId); - statsMap.set(depId, m); - } - } else { - statsMap.set(depId, createStatsMapModule(depId, [mod.id])); - } - }); + if (!isUserCode(mod.id)) { + return; } + mod.importedIds + .concat(mod.dynamicallyImportedIds) + .filter((name) => isUserCode(name)) + .forEach((depIdUnsafe) => { + const depId = normalize(depIdUnsafe); + console.log('LOG: normalization', { depIdUnsafe, depId }); + if (!statsMap.has(depId)) { + statsMap.set(depId, createStatsMapModule(depId, [mod.id])); + return; + } + const m = statsMap.get(depId); + if (!m) { + return; + } + m.reasons = (m.reasons ?? []) + .concat(createReasons([mod.id])) + .filter((r) => r.moduleName !== depId); + statsMap.set(depId, m); + }); }, storybookGetStats() { diff --git a/code/builders/builder-vite/src/utils/virtual-module.ts b/code/builders/builder-vite/src/utils/virtual-module.ts deleted file mode 100644 index 6f72ce19d650..000000000000 --- a/code/builders/builder-vite/src/utils/virtual-module.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getResolvedVirtualModuleId(virtualModuleId: string) { - return `\0${virtualModuleId}`; -} diff --git a/code/builders/builder-vite/src/virtual-file-names.ts b/code/builders/builder-vite/src/virtual-file-names.ts index 0da0c5517dec..c38cb7322db6 100644 --- a/code/builders/builder-vite/src/virtual-file-names.ts +++ b/code/builders/builder-vite/src/virtual-file-names.ts @@ -1,4 +1,14 @@ -export const virtualFileId = '/virtual:/@storybook/builder-vite/vite-app.js'; -export const virtualStoriesFile = '/virtual:/@storybook/builder-vite/storybook-stories.js'; -export const virtualPreviewFile = '/virtual:/@storybook/builder-vite/preview-entry.js'; -export const virtualAddonSetupFile = '/virtual:/@storybook/builder-vite/setup-addons.js'; +export const SB_VIRTUAL_FILES = { + VIRTUAL_APP_FILE: '/virtual:/@storybook/builder-vite/vite-app.js', + VIRTUAL_STORIES_FILE: '/virtual:/@storybook/builder-vite/storybook-stories.js', + VIRTUAL_PREVIEW_FILE: '/virtual:/@storybook/builder-vite/preview-entry.js', + VIRTUAL_ADDON_SETUP_FILE: '/virtual:/@storybook/builder-vite/setup-addons.js', +}; + +export function getResolvedVirtualModuleId(virtualModuleId: string) { + return `\0${virtualModuleId}`; +} + +export function getOriginalVirtualModuleId(resolvedVirtualModuleId: string) { + return resolvedVirtualModuleId.slice(1); +} diff --git a/preview-stats-new-ids.json b/preview-stats-new-ids.json new file mode 100644 index 000000000000..9bc467c67f5b --- /dev/null +++ b/preview-stats-new-ids.json @@ -0,0 +1,2914 @@ +{ + "modules": [ + { + "id": "./iframe.html", + "name": "./iframe.html", + "reasons": [ + { + "moduleName": "./iframe.html" + } + ] + }, + { + "id": "./sb-preview/runtime.js", + "name": "./sb-preview/runtime.js", + "reasons": [ + { + "moduleName": "./iframe.html" + } + ] + }, + { + "id": "./renderers/react/template/components/Button.jsx", + "name": "./renderers/react/template/components/Button.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Form.jsx", + "name": "./renderers/react/template/components/Form.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Html.jsx", + "name": "./renderers/react/template/components/Html.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./renderers/react/template/components/Pre.jsx", + "name": "./renderers/react/template/components/Pre.jsx", + "reasons": [ + { + "moduleName": "./renderers/react/template/components/index.js" + } + ] + }, + { + "id": "./addons/interactions/src/mocks/index.ts", + "name": "./addons/interactions/src/mocks/index.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Interaction.tsx", + "name": "./addons/interactions/src/components/Interaction.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Subnav.stories.tsx", + "name": "./addons/interactions/src/components/Subnav.stories.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/brand/StorybookIcon.tsx", + "name": "./core/src/components/brand/StorybookIcon.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/StorybookIcon.stories.tsx" + } + ] + }, + { + "id": "./addons/controls/src/SaveStory.tsx", + "name": "./addons/controls/src/SaveStory.tsx", + "reasons": [ + { + "moduleName": "./addons/controls/src/SaveStory.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/brand/StorybookLogo.tsx", + "name": "./core/src/components/brand/StorybookLogo.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/StorybookLogo.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/index.ts", + "name": "./lib/blocks/src/components/index.ts", + "reasons": [ + { + "moduleName": "./.storybook/preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/mdx.tsx" + } + ] + }, + { + "id": "./.storybook/isChromatic.ts", + "name": "./.storybook/isChromatic.ts", + "reasons": [ + { + "moduleName": "./.storybook/preview.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/InteractionsPanel.tsx", + "name": "./addons/interactions/src/components/InteractionsPanel.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/MatcherResult.tsx", + "name": "./addons/interactions/src/components/MatcherResult.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/MatcherResult.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/StatusIcon.tsx", + "name": "./addons/interactions/src/components/StatusIcon.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/StatusIcon.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/MethodCall.tsx", + "name": "./addons/interactions/src/components/MethodCall.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/MethodCall.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/MatcherResult.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/StatusBadge.tsx", + "name": "./addons/interactions/src/components/StatusBadge.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/StatusBadge.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/Subnav.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ActionBar/ActionBar.tsx", + "name": "./core/src/components/components/ActionBar/ActionBar.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ActionBar/ActionBar.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/Subnav.tsx", + "name": "./addons/interactions/src/components/Subnav.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Subnav.stories.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./core/src/components/components/form/index.tsx", + "name": "./core/src/components/components/form/index.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Button/Button.tsx", + "name": "./core/src/components/components/Button/Button.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Button/Button.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + }, + { + "moduleName": "./core/src/components/components/IconButton/IconButton.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/Button/Button.tsx", + "name": "./addons/onboarding/src/components/Button/Button.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/Button/Button.stories.tsx" + }, + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Badge/Badge.tsx", + "name": "./core/src/components/components/Badge/Badge.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Badge/Badge.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/Confetti/Confetti.tsx", + "name": "./addons/onboarding/src/components/Confetti/Confetti.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/Confetti/Confetti.stories.tsx" + } + ] + }, + { + "id": "./addons/docs/template/stories/docs2/button.stories.ts", + "name": "./addons/docs/template/stories/docs2/button.stories.ts", + "reasons": [ + { + "moduleName": "./addons/docs/template/stories/docs2/MetaOf.mdx" + }, + { + "moduleName": "./addons/docs/template/stories/docs2/MetaOfNamed.mdx" + } + ] + }, + { + "id": "./core/src/components/brand/SideBySide.tsx", + "name": "./core/src/components/brand/SideBySide.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/brand/colorpalette.mdx" + } + ] + }, + { + "id": "./core/src/components/components/Button/Button.stories.tsx", + "name": "./core/src/components/components/Button/Button.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Button/Docs.mdx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Unstyled.tsx", + "name": "./lib/blocks/src/blocks/Unstyled.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Unstyled.mdx" + }, + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", + "name": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", + "name": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", + "name": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/IconButton/IconButton.tsx", + "name": "./core/src/components/components/IconButton/IconButton.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/IconButton/IconButton.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/Modal/Modal.styled.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Loader/Loader.tsx", + "name": "./core/src/components/components/Loader/Loader.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Loader/Loader.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/List.tsx", + "name": "./addons/onboarding/src/components/List/List.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", + "name": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", + "name": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Modal/Modal.tsx", + "name": "./core/src/components/components/Modal/Modal.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/ScrollArea/ScrollArea.tsx", + "name": "./core/src/components/components/ScrollArea/ScrollArea.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/ScrollArea/ScrollArea.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/bar/bar.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", + "name": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", + "reasons": [ + { + "moduleName": "./addons/docs/template/stories/docs2/ResolvedReact.mdx" + } + ] + }, + { + "id": "./core/src/components/components/form/field/field.tsx", + "name": "./core/src/components/components/form/field/field.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/form/form.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + } + ] + }, + { + "id": "./core/src/components/components/form/input/input.tsx", + "name": "./core/src/components/components/form/input/input.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/form/form.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/form/index.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/Zoom.tsx", + "name": "./core/src/components/components/Zoom/Zoom.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/icon/icon.tsx", + "name": "./core/src/components/components/icon/icon.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/icon/icon.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/typography/link/link.tsx", + "name": "./core/src/components/components/typography/link/link.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/typography/link/link.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.tsx" + } + ] + }, + { + "id": "./core/src/components/components/placeholder/placeholder.tsx", + "name": "./core/src/components/components/placeholder/placeholder.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/spaced/Spaced.tsx", + "name": "./core/src/components/components/spaced/Spaced.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/spaced/Spaced.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/EmptyTabContent.tsx", + "name": "./core/src/components/components/tabs/EmptyTabContent.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/EmptyTabContent.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.tsx", + "name": "./core/src/components/components/tabs/tabs.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/Tooltip.tsx", + "name": "./core/src/components/components/tooltip/Tooltip.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/Tooltip.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/ListItem.tsx", + "name": "./core/src/components/components/tooltip/ListItem.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/ListItem.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipLinkList.tsx", + "name": "./core/src/components/components/tooltip/TooltipLinkList.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/WithTooltip.tsx", + "name": "./core/src/components/components/tooltip/WithTooltip.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/assets/ellipse.png", + "name": "./core/src/components/components/tooltip/assets/ellipse.png", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipNote.tsx", + "name": "./core/src/components/components/tooltip/TooltipNote.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tooltip/TooltipMessage.tsx", + "name": "./core/src/components/components/tooltip/TooltipMessage.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" + }, + { + "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", + "name": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx" + } + ] + }, + { + "id": "./core/src/components/components/typography/DocumentWrapper.tsx", + "name": "./core/src/components/components/typography/DocumentWrapper.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/typography/DocumentWrapper.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/Layout.tsx", + "name": "./core/src/manager/components/layout/Layout.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/LayoutProvider.tsx", + "name": "./core/src/manager/components/layout/LayoutProvider.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + }, + { + "moduleName": "./core/src/manager/components/panel/Panel.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Menu.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/about/MobileAbout.tsx", + "name": "./core/src/manager/components/mobile/about/MobileAbout.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationItem.tsx", + "name": "./core/src/manager/components/notifications/NotificationItem.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationItem.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", + "name": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/notifications/NotificationList.tsx", + "name": "./core/src/manager/components/notifications/NotificationList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" + }, + { + "moduleName": "./core/src/manager/container/Notifications.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/preview/Iframe.tsx", + "name": "./core/src/manager/components/preview/Iframe.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/preview/Iframe.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/defaultShortcuts.tsx", + "name": "./core/src/manager/settings/defaultShortcuts.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" + }, + { + "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/panel/Panel.tsx", + "name": "./core/src/manager/components/panel/Panel.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Explorer.tsx", + "name": "./core/src/manager/components/sidebar/Explorer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/IconSymbols.tsx", + "name": "./core/src/manager/components/sidebar/IconSymbols.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/IconSymbols.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/utils/status.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Refs.stories.tsx", + "name": "./core/src/manager/components/sidebar/Refs.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/mockdata.ts", + "name": "./core/src/manager/components/sidebar/mockdata.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchList.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FilterToggle.tsx", + "name": "./core/src/manager/components/sidebar/FilterToggle.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FilterToggle.stories.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchModal.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchModal.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Heading.tsx", + "name": "./core/src/manager/components/sidebar/Heading.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Heading.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Search.tsx", + "name": "./core/src/manager/components/sidebar/Search.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SearchResults.tsx", + "name": "./core/src/manager/components/sidebar/SearchResults.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", + "name": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Sidebar.tsx", + "name": "./core/src/manager/components/sidebar/Sidebar.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + }, + { + "moduleName": "./core/src/manager/utils/tree.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/mockdata.large.ts", + "name": "./core/src/manager/components/sidebar/mockdata.large.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/container/Menu.tsx", + "name": "./core/src/manager/container/Menu.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/container/Menu.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Menu.tsx", + "name": "./core/src/manager/components/sidebar/Menu.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" + } + ] + }, + { + "id": "./core/src/manager/utils/tree.ts", + "name": "./core/src/manager/utils/tree.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" + }, + { + "moduleName": "./core/src/manager/utils/status.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/StatusContext.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Heading.stories.tsx", + "name": "./core/src/manager/components/sidebar/Heading.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Refs.tsx", + "name": "./core/src/manager/components/sidebar/Refs.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/SidebarBottom.tsx", + "name": "./core/src/manager/components/sidebar/SidebarBottom.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Tree.tsx", + "name": "./core/src/manager/components/sidebar/Tree.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", + "name": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/settings/About.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/HighlightStyles.tsx", + "name": "./core/src/manager/components/sidebar/HighlightStyles.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/TreeNode.tsx", + "name": "./core/src/manager/components/sidebar/TreeNode.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/shortcuts.tsx", + "name": "./core/src/manager/settings/shortcuts.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/whats_new.tsx", + "name": "./core/src/manager/settings/whats_new.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/whats_new_footer.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", + "name": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/about.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/About.tsx", + "name": "./core/src/manager/settings/About.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/about.stories.tsx" + } + ] + }, + { + "id": "./core/src/manager/settings/SettingsFooter.tsx", + "name": "./core/src/manager/settings/SettingsFooter.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/settings/SettingsFooter.stories.tsx" + }, + { + "moduleName": "./core/src/manager/settings/shortcuts.tsx" + } + ] + }, + { + "id": "./core/template/stories/import.js", + "name": "./core/template/stories/import.js", + "reasons": [ + { + "moduleName": "./core/template/stories/interleavedExports.stories.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Anchor.tsx", + "name": "./lib/blocks/src/blocks/Anchor.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Anchor.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/EmptyBlock.tsx", + "name": "./lib/blocks/src/components/EmptyBlock.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/EmptyBlock.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/ArgTypes.tsx", + "name": "./lib/blocks/src/blocks/ArgTypes.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Button.stories.tsx", + "name": "./lib/blocks/src/examples/Button.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", + "name": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/SourceParameters.stories.tsx", + "name": "./lib/blocks/src/examples/SourceParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Canvas.tsx", + "name": "./lib/blocks/src/blocks/Canvas.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Source.stories.tsx", + "name": "./lib/blocks/src/blocks/Source.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/IconGallery.tsx", + "name": "./lib/blocks/src/components/IconGallery.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/IconGallery.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Markdown.tsx", + "name": "./lib/blocks/src/blocks/Markdown.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Markdown.stories.tsx", + "name": "./lib/blocks/src/blocks/Markdown.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/DocsPage.tsx", + "name": "./lib/blocks/src/components/DocsPage.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/Preview.stories.tsx", + "name": "./lib/blocks/src/components/Preview.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Source.stories.tsx", + "name": "./lib/blocks/src/components/Source.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", + "name": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", + "name": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Controls.tsx", + "name": "./lib/blocks/src/blocks/Controls.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Button.tsx", + "name": "./lib/blocks/src/examples/Button.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonReadonly.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/Button.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Description.tsx", + "name": "./lib/blocks/src/blocks/Description.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Source.tsx", + "name": "./lib/blocks/src/components/Source.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/Markdown-content.md", + "name": "./lib/blocks/src/examples/Markdown-content.md", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Title.tsx", + "name": "./lib/blocks/src/components/Title.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Title.stories.ts" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsPage.tsx", + "name": "./lib/blocks/src/blocks/DocsPage.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Preview.tsx", + "name": "./lib/blocks/src/components/Preview.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/Story.tsx", + "name": "./lib/blocks/src/components/Story.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Typeset.tsx", + "name": "./lib/blocks/src/components/Typeset.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Typeset.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", + "name": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Primary.tsx", + "name": "./lib/blocks/src/blocks/Primary.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Source.tsx", + "name": "./lib/blocks/src/blocks/Source.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/SourceContainer.tsx", + "name": "./lib/blocks/src/blocks/SourceContainer.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Stories.tsx", + "name": "./lib/blocks/src/blocks/Stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Boolean.tsx", + "name": "./lib/blocks/src/controls/Boolean.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Boolean.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Color.tsx", + "name": "./lib/blocks/src/controls/Color.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Color.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Files.tsx", + "name": "./lib/blocks/src/controls/Files.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Files.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Story.stories.tsx", + "name": "./lib/blocks/src/components/Story.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/StoryParameters.stories.tsx", + "name": "./lib/blocks/src/examples/StoryParameters.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Story.tsx", + "name": "./lib/blocks/src/blocks/Story.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Date.tsx", + "name": "./lib/blocks/src/controls/Date.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Date.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", + "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Subtitle.tsx", + "name": "./lib/blocks/src/blocks/Subtitle.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Number.tsx", + "name": "./lib/blocks/src/controls/Number.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Number.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Range.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Title.tsx", + "name": "./lib/blocks/src/blocks/Title.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Object.tsx", + "name": "./lib/blocks/src/controls/Object.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Object.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Range.tsx", + "name": "./lib/blocks/src/controls/Range.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Range.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", + "name": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/Text.tsx", + "name": "./lib/blocks/src/controls/Text.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Text.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", + "name": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Options.tsx", + "name": "./lib/blocks/src/controls/options/Options.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/CheckOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/RadioOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/SelectOptions.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ArgTypesParameters.tsx", + "name": "./lib/blocks/src/examples/ArgTypesParameters.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ColorPalette.tsx", + "name": "./lib/blocks/src/components/ColorPalette.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ColorPalette.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/examples/ControlsParameters.tsx", + "name": "./lib/blocks/src/examples/ControlsParameters.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/ControlsParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/EmptyExample.tsx", + "name": "./lib/blocks/src/examples/EmptyExample.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/CanvasParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/DocsPageParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/SourceParameters.stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/examples/StoriesParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/examples/SimpleSizeTest.tsx", + "name": "./lib/blocks/src/examples/SimpleSizeTest.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/examples/StoryParameters.stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/index.ts", + "name": "./lib/blocks/src/components/ArgsTable/index.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/index.ts" + } + ] + }, + { + "id": "./lib/blocks/src/components/IFrame.tsx", + "name": "./lib/blocks/src/components/IFrame.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/index.ts" + }, + { + "moduleName": "./lib/blocks/src/components/Story.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/utils.ts", + "name": "./addons/interactions/src/utils.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/Interaction.tsx" + }, + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./addons/interactions/src/components/EmptyState.tsx", + "name": "./addons/interactions/src/components/EmptyState.tsx", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" + } + ] + }, + { + "id": "./core/src/components/components/shared/animation.ts", + "name": "./core/src/components/components/shared/animation.ts", + "reasons": [ + { + "moduleName": "./core/src/components/components/Loader/Loader.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", + "name": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/List.styled.tsx", + "name": "./addons/onboarding/src/components/List/List.styled.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/List.tsx" + } + ] + }, + { + "id": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", + "name": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", + "reasons": [ + { + "moduleName": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Modal/Modal.styled.tsx", + "name": "./core/src/components/components/Modal/Modal.styled.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Modal/Modal.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/ZoomElement.tsx", + "name": "./core/src/components/components/Zoom/ZoomElement.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" + } + ] + }, + { + "id": "./core/src/components/components/Zoom/ZoomIFrame.tsx", + "name": "./core/src/components/components/Zoom/ZoomIFrame.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", + "name": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + }, + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./core/src/components/components/syntaxhighlighter/formatter.ts", + "name": "./core/src/components/components/syntaxhighlighter/formatter.ts", + "reasons": [ + { + "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" + } + ] + }, + { + "id": "./core/src/components/components/bar/bar.tsx", + "name": "./core/src/components/components/bar/bar.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/bar/button.tsx", + "name": "./core/src/components/components/bar/button.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + }, + { + "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.helpers.tsx", + "name": "./core/src/components/components/tabs/tabs.helpers.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/components/components/tabs/tabs.hooks.tsx", + "name": "./core/src/components/components/tabs/tabs.hooks.tsx", + "reasons": [ + { + "moduleName": "./core/src/components/components/tabs/tabs.tsx" + } + ] + }, + { + "id": "./core/src/manager/constants.ts", + "name": "./core/src/manager/constants.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" + }, + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + }, + { + "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + }, + { + "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.tsx" + }, + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/hooks/useMedia.tsx", + "name": "./core/src/manager/components/hooks/useMedia.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", + "name": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" + } + ] + }, + { + "id": "./core/src/manager/container/Notifications.tsx", + "name": "./core/src/manager/container/Notifications.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/layout/useDragging.ts", + "name": "./core/src/manager/components/layout/useDragging.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/layout/Layout.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileList.tsx", + "name": "./core/src/manager/components/sidebar/FileList.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useHighlighted.ts", + "name": "./core/src/manager/components/sidebar/useHighlighted.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" + } + ] + }, + { + "id": "./core/src/manager/hooks/useMeasure.tsx", + "name": "./core/src/manager/hooks/useMeasure.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", + "name": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Brand.tsx", + "name": "./core/src/manager/components/sidebar/Brand.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useLastViewed.ts", + "name": "./core/src/manager/components/sidebar/useLastViewed.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" + } + ] + }, + { + "id": "./core/src/manager/keybinding.ts", + "name": "./core/src/manager/keybinding.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" + }, + { + "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" + } + ] + }, + { + "id": "./core/src/manager/utils/status.tsx", + "name": "./core/src/manager/utils/status.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/StatusButton.tsx", + "name": "./core/src/manager/components/sidebar/StatusButton.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/types.ts", + "name": "./core/src/manager/components/sidebar/types.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", + "name": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Search.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/RefBlocks.tsx", + "name": "./core/src/manager/components/sidebar/RefBlocks.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/RefIndicator.tsx", + "name": "./core/src/manager/components/sidebar/RefIndicator.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", + "name": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" + }, + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/StatusContext.tsx", + "name": "./core/src/manager/components/sidebar/StatusContext.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/useExpanded.ts", + "name": "./core/src/manager/components/sidebar/useExpanded.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useOf.ts", + "name": "./lib/blocks/src/blocks/useOf.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Description.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Title.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/utils.ts", + "name": "./lib/blocks/src/blocks/utils.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", + "name": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/IconGallery.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Typeset.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/ColorPalette.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/mdx.tsx", + "name": "./lib/blocks/src/blocks/mdx.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Markdown.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Heading.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Subheading.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsContext.ts", + "name": "./lib/blocks/src/blocks/DocsContext.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Source.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/useOf.ts" + }, + { + "moduleName": "./lib/blocks/src/blocks/mdx.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useArgs.ts", + "name": "./lib/blocks/src/blocks/useArgs.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useGlobals.ts", + "name": "./lib/blocks/src/blocks/useGlobals.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Controls.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/Toolbar.tsx", + "name": "./lib/blocks/src/components/Toolbar.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ZoomContext.tsx", + "name": "./lib/blocks/src/components/ZoomContext.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/Preview.tsx" + }, + { + "moduleName": "./lib/blocks/src/components/Story.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/DocsStory.tsx", + "name": "./lib/blocks/src/blocks/DocsStory.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + }, + { + "moduleName": "./lib/blocks/src/blocks/Primary.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Heading.tsx", + "name": "./lib/blocks/src/blocks/Heading.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Stories.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/helpers.ts", + "name": "./lib/blocks/src/controls/helpers.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Boolean.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Files.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Color.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Number.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Date.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Object.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Range.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/Text.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Select.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/useStory.ts", + "name": "./lib/blocks/src/blocks/useStory.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/Story.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", + "name": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/Object.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", + "name": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/Empty.tsx", + "name": "./lib/blocks/src/components/ArgsTable/Empty.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", + "name": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Checkbox.tsx", + "name": "./lib/blocks/src/controls/options/Checkbox.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Radio.tsx", + "name": "./lib/blocks/src/controls/options/Radio.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/Select.tsx", + "name": "./lib/blocks/src/controls/options/Select.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Options.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/components/ArgsTable/types.ts", + "name": "./lib/blocks/src/components/ArgsTable/types.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" + } + ] + }, + { + "id": "./addons/interactions/src/constants.ts", + "name": "./addons/interactions/src/constants.ts", + "reasons": [ + { + "moduleName": "./addons/interactions/src/components/EmptyState.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/Loader.tsx", + "name": "./core/src/manager/components/sidebar/Loader.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/RefBlocks.tsx" + } + ] + }, + { + "id": "./core/src/manager/hooks/useDebounce.ts", + "name": "./core/src/manager/hooks/useDebounce.ts", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", + "name": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", + "reasons": [ + { + "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/blocks/Subheading.tsx", + "name": "./lib/blocks/src/blocks/Subheading.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/index.tsx", + "name": "./lib/blocks/src/controls/index.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", + "name": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", + "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/helpers.ts", + "name": "./lib/blocks/src/controls/options/helpers.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" + }, + { + "moduleName": "./lib/blocks/src/controls/options/Select.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/types.ts", + "name": "./lib/blocks/src/controls/types.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + }, + { + "id": "./lib/blocks/src/controls/options/index.ts", + "name": "./lib/blocks/src/controls/options/index.ts", + "reasons": [ + { + "moduleName": "./lib/blocks/src/controls/index.tsx" + } + ] + } + ] +} \ No newline at end of file From 298399351af83b00a90b72b3fd8d63cfcbfa6b4a Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 6 Sep 2024 16:00:21 +0200 Subject: [PATCH 047/213] cleanup --- preview-stats-new-ids.json | 2914 ------------------------------------ 1 file changed, 2914 deletions(-) delete mode 100644 preview-stats-new-ids.json diff --git a/preview-stats-new-ids.json b/preview-stats-new-ids.json deleted file mode 100644 index 9bc467c67f5b..000000000000 --- a/preview-stats-new-ids.json +++ /dev/null @@ -1,2914 +0,0 @@ -{ - "modules": [ - { - "id": "./iframe.html", - "name": "./iframe.html", - "reasons": [ - { - "moduleName": "./iframe.html" - } - ] - }, - { - "id": "./sb-preview/runtime.js", - "name": "./sb-preview/runtime.js", - "reasons": [ - { - "moduleName": "./iframe.html" - } - ] - }, - { - "id": "./renderers/react/template/components/Button.jsx", - "name": "./renderers/react/template/components/Button.jsx", - "reasons": [ - { - "moduleName": "./renderers/react/template/components/index.js" - } - ] - }, - { - "id": "./renderers/react/template/components/Form.jsx", - "name": "./renderers/react/template/components/Form.jsx", - "reasons": [ - { - "moduleName": "./renderers/react/template/components/index.js" - } - ] - }, - { - "id": "./renderers/react/template/components/Html.jsx", - "name": "./renderers/react/template/components/Html.jsx", - "reasons": [ - { - "moduleName": "./renderers/react/template/components/index.js" - } - ] - }, - { - "id": "./renderers/react/template/components/Pre.jsx", - "name": "./renderers/react/template/components/Pre.jsx", - "reasons": [ - { - "moduleName": "./renderers/react/template/components/index.js" - } - ] - }, - { - "id": "./addons/interactions/src/mocks/index.ts", - "name": "./addons/interactions/src/mocks/index.ts", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/Interaction.tsx", - "name": "./addons/interactions/src/components/Interaction.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/Subnav.stories.tsx", - "name": "./addons/interactions/src/components/Subnav.stories.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/Interaction.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/brand/StorybookIcon.tsx", - "name": "./core/src/components/brand/StorybookIcon.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/brand/StorybookIcon.stories.tsx" - } - ] - }, - { - "id": "./addons/controls/src/SaveStory.tsx", - "name": "./addons/controls/src/SaveStory.tsx", - "reasons": [ - { - "moduleName": "./addons/controls/src/SaveStory.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/brand/StorybookLogo.tsx", - "name": "./core/src/components/brand/StorybookLogo.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/brand/StorybookLogo.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/index.ts", - "name": "./lib/blocks/src/components/index.ts", - "reasons": [ - { - "moduleName": "./.storybook/preview.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Controls.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Preview.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Story.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Title.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/mdx.tsx" - } - ] - }, - { - "id": "./.storybook/isChromatic.ts", - "name": "./.storybook/isChromatic.ts", - "reasons": [ - { - "moduleName": "./.storybook/preview.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/InteractionsPanel.tsx", - "name": "./addons/interactions/src/components/InteractionsPanel.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.stories.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/MatcherResult.tsx", - "name": "./addons/interactions/src/components/MatcherResult.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/MatcherResult.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/Interaction.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/StatusIcon.tsx", - "name": "./addons/interactions/src/components/StatusIcon.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/StatusIcon.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/Interaction.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/MethodCall.tsx", - "name": "./addons/interactions/src/components/MethodCall.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/MethodCall.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/Interaction.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/MatcherResult.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/StatusBadge.tsx", - "name": "./addons/interactions/src/components/StatusBadge.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/StatusBadge.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/Subnav.tsx" - } - ] - }, - { - "id": "./core/src/components/components/ActionBar/ActionBar.tsx", - "name": "./core/src/components/components/ActionBar/ActionBar.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/ActionBar/ActionBar.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/Subnav.tsx", - "name": "./addons/interactions/src/components/Subnav.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/Subnav.stories.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" - } - ] - }, - { - "id": "./core/src/components/components/form/index.tsx", - "name": "./core/src/components/components/form/index.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Button/Button.tsx", - "name": "./core/src/components/components/Button/Button.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Button/Button.deprecated.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/Button/Button.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/form/index.tsx" - }, - { - "moduleName": "./core/src/components/components/IconButton/IconButton.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/Button/Button.tsx", - "name": "./addons/onboarding/src/components/Button/Button.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/Button/Button.stories.tsx" - }, - { - "moduleName": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Badge/Badge.tsx", - "name": "./core/src/components/components/Badge/Badge.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Badge/Badge.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/Confetti/Confetti.tsx", - "name": "./addons/onboarding/src/components/Confetti/Confetti.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/Confetti/Confetti.stories.tsx" - } - ] - }, - { - "id": "./addons/docs/template/stories/docs2/button.stories.ts", - "name": "./addons/docs/template/stories/docs2/button.stories.ts", - "reasons": [ - { - "moduleName": "./addons/docs/template/stories/docs2/MetaOf.mdx" - }, - { - "moduleName": "./addons/docs/template/stories/docs2/MetaOfNamed.mdx" - } - ] - }, - { - "id": "./core/src/components/brand/SideBySide.tsx", - "name": "./core/src/components/brand/SideBySide.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/brand/colorpalette.mdx" - } - ] - }, - { - "id": "./core/src/components/components/Button/Button.stories.tsx", - "name": "./core/src/components/components/Button/Button.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Button/Docs.mdx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Unstyled.tsx", - "name": "./lib/blocks/src/blocks/Unstyled.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Unstyled.mdx" - }, - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", - "name": "./core/src/components/components/ErrorFormatter/ErrorFormatter.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", - "name": "./addons/onboarding/src/components/HighlightElement/HighlightElement.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", - "name": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/IconButton/IconButton.tsx", - "name": "./core/src/components/components/IconButton/IconButton.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/IconButton/IconButton.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/Modal/Modal.styled.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Loader/Loader.tsx", - "name": "./core/src/components/components/Loader/Loader.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Loader/Loader.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/List/List.tsx", - "name": "./addons/onboarding/src/components/List/List.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", - "name": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/List/List.stories.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", - "name": "./addons/onboarding/src/features/SplashScreen/SplashScreen.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Modal/Modal.tsx", - "name": "./core/src/components/components/Modal/Modal.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Modal/Modal.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/ScrollArea/ScrollArea.tsx", - "name": "./core/src/components/components/ScrollArea/ScrollArea.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/ScrollArea/ScrollArea.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/bar/bar.tsx" - }, - { - "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx" - } - ] - }, - { - "id": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", - "name": "./addons/docs/template/stories/docs2/ResolvedReact.jsx", - "reasons": [ - { - "moduleName": "./addons/docs/template/stories/docs2/ResolvedReact.mdx" - } - ] - }, - { - "id": "./core/src/components/components/form/field/field.tsx", - "name": "./core/src/components/components/form/field/field.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/form/form.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/form/index.tsx" - } - ] - }, - { - "id": "./core/src/components/components/form/input/input.tsx", - "name": "./core/src/components/components/form/input/input.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/form/form.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/form/index.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Zoom/Zoom.tsx", - "name": "./core/src/components/components/Zoom/Zoom.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Zoom/Zoom.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/icon/icon.tsx", - "name": "./core/src/components/components/icon/icon.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/icon/icon.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/typography/link/link.tsx", - "name": "./core/src/components/components/typography/link/link.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/typography/link/link.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/TooltipMessage.tsx" - } - ] - }, - { - "id": "./core/src/components/components/placeholder/placeholder.tsx", - "name": "./core/src/components/components/placeholder/placeholder.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/placeholder/placeholder.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/spaced/Spaced.tsx", - "name": "./core/src/components/components/spaced/Spaced.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/spaced/Spaced.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tabs/EmptyTabContent.tsx", - "name": "./core/src/components/components/tabs/EmptyTabContent.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/EmptyTabContent.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tabs/tabs.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tabs/tabs.tsx", - "name": "./core/src/components/components/tabs/tabs.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/tabs.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/Tooltip.tsx", - "name": "./core/src/components/components/tooltip/Tooltip.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/Tooltip.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/WithTooltip.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/ListItem.tsx", - "name": "./core/src/components/components/tooltip/ListItem.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/ListItem.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/TooltipLinkList.tsx", - "name": "./core/src/components/components/tooltip/TooltipLinkList.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/WithTooltip.tsx", - "name": "./core/src/components/components/tooltip/WithTooltip.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/assets/ellipse.png", - "name": "./core/src/components/components/tooltip/assets/ellipse.png", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/TooltipLinkList.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/TooltipNote.tsx", - "name": "./core/src/components/components/tooltip/TooltipNote.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/TooltipNote.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tooltip/TooltipMessage.tsx", - "name": "./core/src/components/components/tooltip/TooltipMessage.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tooltip/TooltipMessage.stories.tsx" - }, - { - "moduleName": "./core/src/components/components/tooltip/WithTooltip.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", - "name": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx" - } - ] - }, - { - "id": "./core/src/components/components/typography/DocumentWrapper.tsx", - "name": "./core/src/components/components/typography/DocumentWrapper.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/typography/DocumentWrapper.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", - "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/layout/Layout.tsx", - "name": "./core/src/manager/components/layout/Layout.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/layout/LayoutProvider.tsx", - "name": "./core/src/manager/components/layout/LayoutProvider.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/Layout.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" - }, - { - "moduleName": "./core/src/manager/components/layout/Layout.tsx" - }, - { - "moduleName": "./core/src/manager/components/panel/Panel.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Menu.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/mobile/about/MobileAbout.tsx", - "name": "./core/src/manager/components/mobile/about/MobileAbout.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/notifications/NotificationItem.tsx", - "name": "./core/src/manager/components/notifications/NotificationItem.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/notifications/NotificationItem.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", - "name": "./core/src/manager/components/notifications/NotificationItem.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/notifications/NotificationList.tsx", - "name": "./core/src/manager/components/notifications/NotificationList.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/notifications/NotificationList.stories.tsx" - }, - { - "moduleName": "./core/src/manager/container/Notifications.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", - "name": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/layout/Layout.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/preview/Iframe.tsx", - "name": "./core/src/manager/components/preview/Iframe.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/preview/Iframe.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/settings/defaultShortcuts.tsx", - "name": "./core/src/manager/settings/defaultShortcuts.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" - }, - { - "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/panel/Panel.tsx", - "name": "./core/src/manager/components/panel/Panel.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/panel/Panel.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", - "name": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Explorer.tsx", - "name": "./core/src/manager/components/sidebar/Explorer.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/IconSymbols.tsx", - "name": "./core/src/manager/components/sidebar/IconSymbols.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/IconSymbols.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - }, - { - "moduleName": "./core/src/manager/utils/status.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Refs.stories.tsx", - "name": "./core/src/manager/components/sidebar/Refs.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/mockdata.ts", - "name": "./core/src/manager/components/sidebar/mockdata.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileSearchList.tsx", - "name": "./core/src/manager/components/sidebar/FileSearchList.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FilterToggle.tsx", - "name": "./core/src/manager/components/sidebar/FilterToggle.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FilterToggle.stories.ts" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", - "name": "./core/src/manager/components/sidebar/FileSearchList.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileSearchModal.tsx", - "name": "./core/src/manager/components/sidebar/FileSearchModal.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Heading.tsx", - "name": "./core/src/manager/components/sidebar/Heading.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Heading.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Search.tsx", - "name": "./core/src/manager/components/sidebar/Search.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/SearchResults.tsx", - "name": "./core/src/manager/components/sidebar/SearchResults.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", - "name": "./core/src/manager/components/sidebar/SearchResults.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Sidebar.tsx", - "name": "./core/src/manager/components/sidebar/Sidebar.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" - }, - { - "moduleName": "./core/src/manager/utils/tree.ts" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/mockdata.large.ts", - "name": "./core/src/manager/components/sidebar/mockdata.large.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/container/Menu.tsx", - "name": "./core/src/manager/container/Menu.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" - }, - { - "moduleName": "./core/src/manager/container/Menu.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Menu.tsx", - "name": "./core/src/manager/components/sidebar/Menu.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Menu.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" - } - ] - }, - { - "id": "./core/src/manager/utils/tree.ts", - "name": "./core/src/manager/utils/tree.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" - }, - { - "moduleName": "./core/src/manager/utils/status.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/StatusContext.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Heading.stories.tsx", - "name": "./core/src/manager/components/sidebar/Heading.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Refs.tsx", - "name": "./core/src/manager/components/sidebar/Refs.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Refs.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/SidebarBottom.tsx", - "name": "./core/src/manager/components/sidebar/SidebarBottom.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SidebarBottom.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Tree.tsx", - "name": "./core/src/manager/components/sidebar/Tree.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Tree.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", - "name": "./core/src/manager/components/upgrade/UpgradeBlock.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" - }, - { - "moduleName": "./core/src/manager/settings/About.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/HighlightStyles.tsx", - "name": "./core/src/manager/components/sidebar/HighlightStyles.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/TreeNode.tsx", - "name": "./core/src/manager/components/sidebar/TreeNode.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.stories.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./core/src/manager/settings/shortcuts.tsx", - "name": "./core/src/manager/settings/shortcuts.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/settings/shortcuts.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/settings/whats_new.tsx", - "name": "./core/src/manager/settings/whats_new.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/settings/whats_new_footer.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", - "name": "./core/src/manager/components/upgrade/UpgradeBlock.stories.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/settings/about.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/settings/About.tsx", - "name": "./core/src/manager/settings/About.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/settings/about.stories.tsx" - } - ] - }, - { - "id": "./core/src/manager/settings/SettingsFooter.tsx", - "name": "./core/src/manager/settings/SettingsFooter.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/settings/SettingsFooter.stories.tsx" - }, - { - "moduleName": "./core/src/manager/settings/shortcuts.tsx" - } - ] - }, - { - "id": "./core/template/stories/import.js", - "name": "./core/template/stories/import.js", - "reasons": [ - { - "moduleName": "./core/template/stories/interleavedExports.stories.ts" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Anchor.tsx", - "name": "./lib/blocks/src/blocks/Anchor.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Anchor.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/EmptyBlock.tsx", - "name": "./lib/blocks/src/components/EmptyBlock.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/EmptyBlock.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - }, - { - "moduleName": "./lib/blocks/src/components/Source.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", - "name": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", - "name": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/ArgTypes.tsx", - "name": "./lib/blocks/src/blocks/ArgTypes.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/Button.stories.tsx", - "name": "./lib/blocks/src/examples/Button.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Story.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", - "name": "./lib/blocks/src/examples/CanvasParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/SourceParameters.stories.tsx", - "name": "./lib/blocks/src/examples/SourceParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Canvas.tsx", - "name": "./lib/blocks/src/blocks/Canvas.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Source.stories.tsx", - "name": "./lib/blocks/src/blocks/Source.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/IconGallery.tsx", - "name": "./lib/blocks/src/components/IconGallery.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/IconGallery.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Markdown.tsx", - "name": "./lib/blocks/src/blocks/Markdown.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Description.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Markdown.stories.tsx", - "name": "./lib/blocks/src/blocks/Markdown.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/DocsPage.tsx", - "name": "./lib/blocks/src/components/DocsPage.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/components/Preview.stories.tsx", - "name": "./lib/blocks/src/components/Preview.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Source.stories.tsx", - "name": "./lib/blocks/src/components/Source.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/DocsPage.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", - "name": "./lib/blocks/src/examples/ControlsParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", - "name": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", - "name": "./lib/blocks/src/examples/EmptyArgTypes.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Controls.tsx", - "name": "./lib/blocks/src/blocks/Controls.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/Button.tsx", - "name": "./lib/blocks/src/examples/Button.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonReadonly.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/Button.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Description.tsx", - "name": "./lib/blocks/src/blocks/Description.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Description.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Source.tsx", - "name": "./lib/blocks/src/components/Source.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Source.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - }, - { - "moduleName": "./lib/blocks/src/blocks/Source.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/Markdown-content.md", - "name": "./lib/blocks/src/examples/Markdown-content.md", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Markdown.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Title.tsx", - "name": "./lib/blocks/src/components/Title.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Title.stories.ts" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/DocsPage.tsx", - "name": "./lib/blocks/src/blocks/DocsPage.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Preview.tsx", - "name": "./lib/blocks/src/components/Preview.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/components/Story.tsx", - "name": "./lib/blocks/src/components/Story.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Preview.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Story.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - }, - { - "moduleName": "./lib/blocks/src/components/Preview.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Typeset.tsx", - "name": "./lib/blocks/src/components/Typeset.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Typeset.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", - "name": "./lib/blocks/src/examples/StoriesParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Primary.tsx", - "name": "./lib/blocks/src/blocks/Primary.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Primary.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Source.tsx", - "name": "./lib/blocks/src/blocks/Source.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/SourceContainer.tsx", - "name": "./lib/blocks/src/blocks/SourceContainer.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Source.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Source.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Stories.tsx", - "name": "./lib/blocks/src/blocks/Stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Stories.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Boolean.tsx", - "name": "./lib/blocks/src/controls/Boolean.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Boolean.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Color.tsx", - "name": "./lib/blocks/src/controls/Color.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Color.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Files.tsx", - "name": "./lib/blocks/src/controls/Files.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Files.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Story.stories.tsx", - "name": "./lib/blocks/src/components/Story.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/StoryParameters.stories.tsx", - "name": "./lib/blocks/src/examples/StoryParameters.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Story.tsx", - "name": "./lib/blocks/src/blocks/Story.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Story.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Date.tsx", - "name": "./lib/blocks/src/controls/Date.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Date.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", - "name": "./lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Subtitle.tsx", - "name": "./lib/blocks/src/blocks/Subtitle.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Number.tsx", - "name": "./lib/blocks/src/controls/Number.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Number.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Range.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Title.tsx", - "name": "./lib/blocks/src/blocks/Title.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Title.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Object.tsx", - "name": "./lib/blocks/src/controls/Object.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Object.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Range.tsx", - "name": "./lib/blocks/src/controls/Range.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Range.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", - "name": "./lib/blocks/src/components/ArgsTable/SectionRow.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/SectionRow.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/Text.tsx", - "name": "./lib/blocks/src/controls/Text.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Text.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgRow.stories.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", - "name": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/TabbedArgsTable.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/Options.tsx", - "name": "./lib/blocks/src/controls/options/Options.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/options/CheckOptions.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/RadioOptions.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/SelectOptions.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ArgTypesParameters.tsx", - "name": "./lib/blocks/src/examples/ArgTypesParameters.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ArgTypesParameters.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ColorPalette.tsx", - "name": "./lib/blocks/src/components/ColorPalette.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ColorPalette.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/examples/ControlsParameters.tsx", - "name": "./lib/blocks/src/examples/ControlsParameters.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/examples/ControlsParameters.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/EmptyExample.tsx", - "name": "./lib/blocks/src/examples/EmptyExample.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/examples/CanvasParameters.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/DocsPageParameters.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/SourceParameters.stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/examples/StoriesParameters.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/examples/SimpleSizeTest.tsx", - "name": "./lib/blocks/src/examples/SimpleSizeTest.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/examples/StoryParameters.stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/index.ts", - "name": "./lib/blocks/src/components/ArgsTable/index.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/index.ts" - } - ] - }, - { - "id": "./lib/blocks/src/components/IFrame.tsx", - "name": "./lib/blocks/src/components/IFrame.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/index.ts" - }, - { - "moduleName": "./lib/blocks/src/components/Story.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/utils.ts", - "name": "./addons/interactions/src/utils.ts", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/Interaction.tsx" - }, - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" - } - ] - }, - { - "id": "./addons/interactions/src/components/EmptyState.tsx", - "name": "./addons/interactions/src/components/EmptyState.tsx", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/InteractionsPanel.tsx" - } - ] - }, - { - "id": "./core/src/components/components/shared/animation.ts", - "name": "./core/src/components/components/shared/animation.ts", - "reasons": [ - { - "moduleName": "./core/src/components/components/Loader/Loader.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", - "name": "./addons/onboarding/src/features/GuidedTour/Tooltip.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/features/GuidedTour/GuidedTour.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/List/List.styled.tsx", - "name": "./addons/onboarding/src/components/List/List.styled.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/List/List.tsx" - } - ] - }, - { - "id": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", - "name": "./addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx", - "reasons": [ - { - "moduleName": "./addons/onboarding/src/components/List/ListItem/ListItem.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Modal/Modal.styled.tsx", - "name": "./core/src/components/components/Modal/Modal.styled.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Modal/Modal.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Zoom/ZoomElement.tsx", - "name": "./core/src/components/components/Zoom/ZoomElement.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" - } - ] - }, - { - "id": "./core/src/components/components/Zoom/ZoomIFrame.tsx", - "name": "./core/src/components/components/Zoom/ZoomIFrame.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/Zoom/Zoom.tsx" - } - ] - }, - { - "id": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", - "name": "./core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" - }, - { - "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" - } - ] - }, - { - "id": "./core/src/components/components/syntaxhighlighter/formatter.ts", - "name": "./core/src/components/components/syntaxhighlighter/formatter.ts", - "reasons": [ - { - "moduleName": "./core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx" - } - ] - }, - { - "id": "./core/src/components/components/bar/bar.tsx", - "name": "./core/src/components/components/bar/bar.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/tabs.tsx" - } - ] - }, - { - "id": "./core/src/components/components/bar/button.tsx", - "name": "./core/src/components/components/bar/button.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/tabs.tsx" - }, - { - "moduleName": "./core/src/components/components/tabs/tabs.hooks.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tabs/tabs.helpers.tsx", - "name": "./core/src/components/components/tabs/tabs.helpers.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/tabs.tsx" - } - ] - }, - { - "id": "./core/src/components/components/tabs/tabs.hooks.tsx", - "name": "./core/src/components/components/tabs/tabs.hooks.tsx", - "reasons": [ - { - "moduleName": "./core/src/components/components/tabs/tabs.tsx" - } - ] - }, - { - "id": "./core/src/manager/constants.ts", - "name": "./core/src/manager/constants.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" - }, - { - "moduleName": "./core/src/manager/components/layout/Layout.tsx" - }, - { - "moduleName": "./core/src/manager/components/notifications/NotificationList.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/about/MobileAbout.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - }, - { - "moduleName": "./core/src/manager/components/upgrade/UpgradeBlock.tsx" - }, - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/hooks/useMedia.tsx", - "name": "./core/src/manager/components/hooks/useMedia.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/LayoutProvider.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", - "name": "./core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", - "name": "./core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/mobile/navigation/MobileNavigation.tsx" - } - ] - }, - { - "id": "./core/src/manager/container/Notifications.tsx", - "name": "./core/src/manager/container/Notifications.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/Layout.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/layout/useDragging.ts", - "name": "./core/src/manager/components/layout/useDragging.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/layout/Layout.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileList.tsx", - "name": "./core/src/manager/components/sidebar/FileList.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchListSkeleton.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/useHighlighted.ts", - "name": "./core/src/manager/components/sidebar/useHighlighted.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Explorer.tsx" - } - ] - }, - { - "id": "./core/src/manager/hooks/useMeasure.tsx", - "name": "./core/src/manager/hooks/useMeasure.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchModal.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", - "name": "./core/src/manager/components/sidebar/FIleSearchList.utils.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/FileSearchList.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Brand.tsx", - "name": "./core/src/manager/components/sidebar/Brand.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Heading.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/useLastViewed.ts", - "name": "./core/src/manager/components/sidebar/useLastViewed.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Sidebar.tsx" - } - ] - }, - { - "id": "./core/src/manager/keybinding.ts", - "name": "./core/src/manager/keybinding.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/useHighlighted.ts" - }, - { - "moduleName": "./core/src/manager/components/sidebar/useExpanded.ts" - } - ] - }, - { - "id": "./core/src/manager/utils/status.tsx", - "name": "./core/src/manager/utils/status.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/StatusButton.tsx", - "name": "./core/src/manager/components/sidebar/StatusButton.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/types.ts", - "name": "./core/src/manager/components/sidebar/types.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/SearchResults.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", - "name": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Search.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/RefBlocks.tsx", - "name": "./core/src/manager/components/sidebar/RefBlocks.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/RefIndicator.tsx", - "name": "./core/src/manager/components/sidebar/RefIndicator.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", - "name": "./core/src/manager/components/sidebar/components/CollapseIcon.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Refs.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/TreeNode.tsx" - }, - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/StatusContext.tsx", - "name": "./core/src/manager/components/sidebar/StatusContext.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/useExpanded.ts", - "name": "./core/src/manager/components/sidebar/useExpanded.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/Tree.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/useOf.ts", - "name": "./lib/blocks/src/blocks/useOf.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Description.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsPage.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Primary.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Subtitle.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Title.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/utils.ts", - "name": "./lib/blocks/src/blocks/utils.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/ArgTypes.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Controls.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", - "name": "./lib/blocks/src/components/BlockBackgroundStyles.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/IconGallery.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Typeset.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Preview.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/ColorPalette.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/mdx.tsx", - "name": "./lib/blocks/src/blocks/mdx.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Markdown.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Heading.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Subheading.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/DocsContext.ts", - "name": "./lib/blocks/src/blocks/DocsContext.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Canvas.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Controls.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Primary.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Source.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Story.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/useOf.ts" - }, - { - "moduleName": "./lib/blocks/src/blocks/mdx.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/useArgs.ts", - "name": "./lib/blocks/src/blocks/useArgs.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/useGlobals.ts", - "name": "./lib/blocks/src/blocks/useGlobals.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Controls.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/Toolbar.tsx", - "name": "./lib/blocks/src/components/Toolbar.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Preview.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ZoomContext.tsx", - "name": "./lib/blocks/src/components/ZoomContext.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/Preview.tsx" - }, - { - "moduleName": "./lib/blocks/src/components/Story.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/DocsStory.tsx", - "name": "./lib/blocks/src/blocks/DocsStory.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Stories.tsx" - }, - { - "moduleName": "./lib/blocks/src/blocks/Primary.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Heading.tsx", - "name": "./lib/blocks/src/blocks/Heading.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Stories.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/helpers.ts", - "name": "./lib/blocks/src/controls/helpers.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Boolean.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Files.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Color.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Number.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Date.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Object.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Range.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/Text.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/Select.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/useStory.ts", - "name": "./lib/blocks/src/blocks/useStory.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/Story.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", - "name": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/Object.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgJsDoc.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", - "name": "./lib/blocks/src/components/ArgsTable/ArgValue.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgRow.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/Empty.tsx", - "name": "./lib/blocks/src/components/ArgsTable/Empty.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", - "name": "./lib/blocks/src/components/ArgsTable/Skeleton.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgsTable.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/Checkbox.tsx", - "name": "./lib/blocks/src/controls/options/Checkbox.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/options/Options.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/Radio.tsx", - "name": "./lib/blocks/src/controls/options/Radio.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/options/Options.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/Select.tsx", - "name": "./lib/blocks/src/controls/options/Select.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/options/Options.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/components/ArgsTable/types.ts", - "name": "./lib/blocks/src/components/ArgsTable/types.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/index.ts" - } - ] - }, - { - "id": "./addons/interactions/src/constants.ts", - "name": "./addons/interactions/src/constants.ts", - "reasons": [ - { - "moduleName": "./addons/interactions/src/components/EmptyState.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/Loader.tsx", - "name": "./core/src/manager/components/sidebar/Loader.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/RefBlocks.tsx" - } - ] - }, - { - "id": "./core/src/manager/hooks/useDebounce.ts", - "name": "./core/src/manager/hooks/useDebounce.ts", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" - } - ] - }, - { - "id": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", - "name": "./core/src/manager/components/sidebar/FileSearchModal.utils.tsx", - "reasons": [ - { - "moduleName": "./core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/blocks/Subheading.tsx", - "name": "./lib/blocks/src/blocks/Subheading.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/blocks/DocsStory.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/index.tsx", - "name": "./lib/blocks/src/controls/index.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/components/ArgsTable/ArgControl.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", - "name": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/types/dataTypes.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/types/deltaTypes.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/types/inputUsageTypes.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/objectTypes.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/JsonNodes.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/parse.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", - "name": "./lib/blocks/src/controls/react-editable-json-tree/utils/styles.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/react-editable-json-tree/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/helpers.ts", - "name": "./lib/blocks/src/controls/options/helpers.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/options/Checkbox.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/Radio.tsx" - }, - { - "moduleName": "./lib/blocks/src/controls/options/Select.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/types.ts", - "name": "./lib/blocks/src/controls/types.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - }, - { - "id": "./lib/blocks/src/controls/options/index.ts", - "name": "./lib/blocks/src/controls/options/index.ts", - "reasons": [ - { - "moduleName": "./lib/blocks/src/controls/index.tsx" - } - ] - } - ] -} \ No newline at end of file From d982babd5571d163856cf7e80babca6a835bb564 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Fri, 6 Sep 2024 10:13:38 -0600 Subject: [PATCH 048/213] Apply suggestions from code review Co-authored-by: Yann Braga --- docs/writing-tests/test-runner-with-vitest.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/test-runner-with-vitest.mdx index c57c4cfde3f1..2b636ffd4a64 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/test-runner-with-vitest.mdx @@ -37,7 +37,7 @@ Before installing, make sure your project meets the following requirements: - A Storybook framework that uses Vite (e.g. [`vue3-vite`](../get-started/frameworks/vue3-vite.mdx)), or the [Storybook Next.js framework](../get-started/frameworks/nextjs.mdx) - Vitest ≥ 2.0 - If you're not using Vitest, it will be installed and configured for you when you install the addon -- For Next.js projects, Next.js ≥ 14.0 +- For Next.js projects, Next.js ≥ 14.1 If you're not yet using Storybook 8.3, you can [upgrade your Storybook](../configure/upgrading.mdx) to the latest version: @@ -152,7 +152,7 @@ import { setProjectAnnotations } from '@storybook/your-renderer'; import * as projectAnnotations from './preview'; -const project = setProjectAnnotations(projectAnnotations); +const project = setProjectAnnotations([projectAnnotations]); beforeAll(project.beforeAll); ``` @@ -222,6 +222,7 @@ export default defineWorkspace([ storybookScript: 'yarn storybook --ci', }), ], + name: 'storybook', test: { // Glob pattern to find story files include: ['src/**/*.stories.?(m)[jt]s?(x)'], From bdfd3a5246fd90900236c920477491149944b736 Mon Sep 17 00:00:00 2001 From: Lucas Bancroft-Baer <1879691+elbeezi@users.noreply.github.com> Date: Fri, 6 Sep 2024 19:42:14 -0400 Subject: [PATCH 049/213] Fix typo in setup.mdx --- docs/get-started/setup.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/setup.mdx b/docs/get-started/setup.mdx index 6794e694e35c..be35c28e11a2 100644 --- a/docs/get-started/setup.mdx +++ b/docs/get-started/setup.mdx @@ -77,4 +77,4 @@ Your project may have additional requirements before components can be rendered ## Load assets and resources -We recommend serving external resources and assets requested in your components statically with Storybook. It ensures that assets are always available to your stories. Read our [documentation](../configure/integration/images-and-assets.mdx) to learn how to hosting static files with Storybook. +We recommend serving external resources and assets requested in your components statically with Storybook. It ensures that assets are always available to your stories. Read our [documentation](../configure/integration/images-and-assets.mdx) to learn how to host static files with Storybook. From 6f19cac299d25ab3d935124c341522d05cf18923 Mon Sep 17 00:00:00 2001 From: Michael Cebrian Date: Sat, 7 Sep 2024 06:02:59 -0400 Subject: [PATCH 050/213] Fix Angular sourceDecorator to apply excludeDecorators flag --- .../frameworks/angular/src/client/docs/sourceDecorator.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/frameworks/angular/src/client/docs/sourceDecorator.ts b/code/frameworks/angular/src/client/docs/sourceDecorator.ts index cd3335c8efa2..cbd3f838b340 100644 --- a/code/frameworks/angular/src/client/docs/sourceDecorator.ts +++ b/code/frameworks/angular/src/client/docs/sourceDecorator.ts @@ -1,6 +1,6 @@ import { SNIPPET_RENDERED, SourceType } from 'storybook/internal/docs-tools'; import { addons, useEffect } from 'storybook/internal/preview-api'; -import { PartialStoryFn } from 'storybook/internal/types'; +import { ArgsStoryFn, PartialStoryFn } from 'storybook/internal/types'; import { computesTemplateSourceFromComponent } from '../../renderer'; import { AngularRenderer, StoryContext } from '../types'; @@ -32,9 +32,11 @@ export const sourceDecorator = ( return story; } const channel = addons.getChannel(); - const { props, template, userDefinedTemplate } = story; - + const { props, userDefinedTemplate } = story; const { component, argTypes, parameters } = context; + const template: string = parameters.docs?.source?.excludeDecorators + ? (context.originalStoryFn as ArgsStoryFn)(context.args, context).template + : story.template; let toEmit: string; From 06b30567926ebe7c09eb9901b1081800e4e715ad Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 9 Sep 2024 09:48:26 +0200 Subject: [PATCH 051/213] improve readability of case when matching internal virtual files. --- .../src/plugins/webpack-stats-plugin.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts index 701f7bd15b96..7e6f596e022f 100644 --- a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts +++ b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts @@ -40,14 +40,20 @@ function stripQueryParams(filePath: string): string { /** We only care about user code, not node_modules, vite files, or (most) virtual files. */ function isUserCode(moduleName: string) { + if (!moduleName) { + return false; + } + + // keep Storybook's virtual files because they import the story files, so they are essential to the module graph + if (Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(moduleName))) { + return true; + } + return Boolean( - (moduleName && - // keep Storybook's virtual files because they import the story files, so they are essential to the module graph - Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(moduleName))) || - (!moduleName.startsWith('vite/') && - !moduleName.startsWith('\0') && - moduleName !== 'react/jsx-runtime' && - !moduleName.match(/node_modules\//)) + !moduleName.startsWith('vite/') && + !moduleName.startsWith('\0') && + moduleName !== 'react/jsx-runtime' && + !moduleName.match(/node_modules\//) ); } From e672f1f2204d0f7769bab2d9270f30440ba5b170 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 9 Sep 2024 10:10:56 +0200 Subject: [PATCH 052/213] fix lock-file changes --- code/yarn.lock | 257 +------------------------------------------------ 1 file changed, 3 insertions(+), 254 deletions(-) diff --git a/code/yarn.lock b/code/yarn.lock index 2e596fc708a3..52f251440bb3 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -2490,7 +2490,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.1.1, @emnapi/runtime@npm:^1.2.0": +"@emnapi/runtime@npm:^1.1.1": version: 1.2.0 resolution: "@emnapi/runtime@npm:1.2.0" dependencies: @@ -3424,18 +3424,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-darwin-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-darwin-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-arm64": - optional: true - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@img/sharp-darwin-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-darwin-x64@npm:0.33.4" @@ -3448,18 +3436,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-darwin-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-darwin-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-darwin-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-x64": - optional: true - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@img/sharp-libvips-darwin-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.2" @@ -3467,13 +3443,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-darwin-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@img/sharp-libvips-darwin-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.2" @@ -3481,13 +3450,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-darwin-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@img/sharp-libvips-linux-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.2" @@ -3495,13 +3457,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linux-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - "@img/sharp-libvips-linux-arm@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-arm@npm:1.0.2" @@ -3509,13 +3464,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linux-arm@npm:1.0.5": - version: 1.0.5 - resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - "@img/sharp-libvips-linux-s390x@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.2" @@ -3523,13 +3471,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linux-s390x@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - "@img/sharp-libvips-linux-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linux-x64@npm:1.0.2" @@ -3537,13 +3478,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linux-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2" @@ -3551,13 +3485,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - "@img/sharp-libvips-linuxmusl-x64@npm:1.0.2": version: 1.0.2 resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.2" @@ -3565,13 +3492,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - "@img/sharp-linux-arm64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-arm64@npm:0.33.4" @@ -3584,18 +3504,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - "@img/sharp-linux-arm@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-arm@npm:0.33.4" @@ -3608,18 +3516,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-arm@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-arm@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-arm": "npm:1.0.5" - dependenciesMeta: - "@img/sharp-libvips-linux-arm": - optional: true - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - "@img/sharp-linux-s390x@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-s390x@npm:0.33.4" @@ -3632,18 +3528,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-s390x@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-s390x@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-s390x": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-s390x": - optional: true - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - "@img/sharp-linux-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linux-x64@npm:0.33.4" @@ -3656,18 +3540,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - "@img/sharp-linuxmusl-arm64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.4" @@ -3680,18 +3552,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linuxmusl-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - "@img/sharp-linuxmusl-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-linuxmusl-x64@npm:0.33.4" @@ -3704,18 +3564,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linuxmusl-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - "@img/sharp-wasm32@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-wasm32@npm:0.33.4" @@ -3725,15 +3573,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-wasm32@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-wasm32@npm:0.33.5" - dependencies: - "@emnapi/runtime": "npm:^1.2.0" - conditions: cpu=wasm32 - languageName: node - linkType: hard - "@img/sharp-win32-ia32@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-win32-ia32@npm:0.33.4" @@ -3741,13 +3580,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-win32-ia32@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-win32-ia32@npm:0.33.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - "@img/sharp-win32-x64@npm:0.33.4": version: 0.33.4 resolution: "@img/sharp-win32-x64@npm:0.33.4" @@ -3755,13 +3587,6 @@ __metadata: languageName: node linkType: hard -"@img/sharp-win32-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-win32-x64@npm:0.33.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@inquirer/confirm@npm:^3.0.0": version: 3.1.20 resolution: "@inquirer/confirm@npm:3.1.20" @@ -4078,20 +3903,13 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.2.5": +"@next/env@npm:14.2.5, @next/env@npm:^14.2.5": version: 14.2.5 resolution: "@next/env@npm:14.2.5" checksum: 10c0/63d8b88ac450b3c37940a9e2119a63a1074aca89908574ade6157a8aa295275dcb3ac5f69e00883fc55d0f12963b73b74e87ba32a5768a489f9609c6be57b699 languageName: node linkType: hard -"@next/env@npm:^14.2.5": - version: 14.2.7 - resolution: "@next/env@npm:14.2.7" - checksum: 10c0/1cda023007acda4d47036a25fba0e039d9b2df9c3770651dc289207e0537506675546c02b5b574fe92bb1adc1c887d948d5cb630673aa572754278b82d150b7e - languageName: node - linkType: hard - "@next/swc-darwin-arm64@npm:14.2.5": version: 14.2.5 resolution: "@next/swc-darwin-arm64@npm:14.2.5" @@ -25822,7 +25640,7 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.33.3": +"sharp@npm:^0.33.3, sharp@npm:^0.33.4": version: 0.33.4 resolution: "sharp@npm:0.33.4" dependencies: @@ -25891,75 +25709,6 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.33.4": - version: 0.33.5 - resolution: "sharp@npm:0.33.5" - dependencies: - "@img/sharp-darwin-arm64": "npm:0.33.5" - "@img/sharp-darwin-x64": "npm:0.33.5" - "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" - "@img/sharp-libvips-darwin-x64": "npm:1.0.4" - "@img/sharp-libvips-linux-arm": "npm:1.0.5" - "@img/sharp-libvips-linux-arm64": "npm:1.0.4" - "@img/sharp-libvips-linux-s390x": "npm:1.0.4" - "@img/sharp-libvips-linux-x64": "npm:1.0.4" - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" - "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" - "@img/sharp-linux-arm": "npm:0.33.5" - "@img/sharp-linux-arm64": "npm:0.33.5" - "@img/sharp-linux-s390x": "npm:0.33.5" - "@img/sharp-linux-x64": "npm:0.33.5" - "@img/sharp-linuxmusl-arm64": "npm:0.33.5" - "@img/sharp-linuxmusl-x64": "npm:0.33.5" - "@img/sharp-wasm32": "npm:0.33.5" - "@img/sharp-win32-ia32": "npm:0.33.5" - "@img/sharp-win32-x64": "npm:0.33.5" - color: "npm:^4.2.3" - detect-libc: "npm:^2.0.3" - semver: "npm:^7.6.3" - dependenciesMeta: - "@img/sharp-darwin-arm64": - optional: true - "@img/sharp-darwin-x64": - optional: true - "@img/sharp-libvips-darwin-arm64": - optional: true - "@img/sharp-libvips-darwin-x64": - optional: true - "@img/sharp-libvips-linux-arm": - optional: true - "@img/sharp-libvips-linux-arm64": - optional: true - "@img/sharp-libvips-linux-s390x": - optional: true - "@img/sharp-libvips-linux-x64": - optional: true - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - "@img/sharp-libvips-linuxmusl-x64": - optional: true - "@img/sharp-linux-arm": - optional: true - "@img/sharp-linux-arm64": - optional: true - "@img/sharp-linux-s390x": - optional: true - "@img/sharp-linux-x64": - optional: true - "@img/sharp-linuxmusl-arm64": - optional: true - "@img/sharp-linuxmusl-x64": - optional: true - "@img/sharp-wasm32": - optional: true - "@img/sharp-win32-ia32": - optional: true - "@img/sharp-win32-x64": - optional: true - checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 - languageName: node - linkType: hard - "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" From 63e46fa47b3e5a98f331f335f6a9c4052e09ad90 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Mon, 9 Sep 2024 13:31:16 -0600 Subject: [PATCH 053/213] Rename to 'Storybook Vitest plugin', and more --- .../vitest-plugin-test-failure.png | Bin 0 -> 213655 bytes .../writing-tests/vitest-plugin-vscode.png | Bin 0 -> 332373 bytes ...s-vitest-set-project-annotations-simple.md | 35 ++++ ...-stories-vitest-set-project-annotations.md | 18 +- ...un-tests.md => vitest-plugin-run-tests.md} | 0 .../vitest-plugin-vitest-config-alias.md | 29 +++ docs/_snippets/vitest-plugin-vitest-config.md | 118 ++++++++++++ .../vitest-plugin-vitest-workspace.md | 128 +++++++++++++ ...nner-with-vitest.mdx => vitest-plugin.mdx} | 181 +++++++----------- 9 files changed, 382 insertions(+), 127 deletions(-) create mode 100644 docs/_assets/writing-tests/vitest-plugin-test-failure.png create mode 100644 docs/_assets/writing-tests/vitest-plugin-vscode.png create mode 100644 docs/_snippets/portable-stories-vitest-set-project-annotations-simple.md rename docs/_snippets/{addon-test-run-tests.md => vitest-plugin-run-tests.md} (100%) create mode 100644 docs/_snippets/vitest-plugin-vitest-config-alias.md create mode 100644 docs/_snippets/vitest-plugin-vitest-config.md create mode 100644 docs/_snippets/vitest-plugin-vitest-workspace.md rename docs/writing-tests/{test-runner-with-vitest.mdx => vitest-plugin.mdx} (71%) diff --git a/docs/_assets/writing-tests/vitest-plugin-test-failure.png b/docs/_assets/writing-tests/vitest-plugin-test-failure.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2277c9e54729e6726acd28140c2ef2d846068d GIT binary patch literal 213655 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 z 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

G}E{&1s6>lQTz}vE+)5JSK!!1D$ERq!h)s5lB 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 { + return mergeConfig(viteConfig, { + resolve: { + alias: { + '@components': '/src/components', + // ... + }, + }, + }); + }, +}; +``` + +```js filename="vitest.config.ts" renderer="common" tabTitle="After" +export default defineConfig({ + // ... + resolve: { + alias: { + '@components': '/src/components', + // ... + }, + }, +}); +``` diff --git a/docs/_snippets/vitest-plugin-vitest-config.md b/docs/_snippets/vitest-plugin-vitest-config.md new file mode 100644 index 000000000000..fbd358b407b3 --- /dev/null +++ b/docs/_snippets/vitest-plugin-vitest-config.md @@ -0,0 +1,118 @@ +```ts filename="vitest.config.ts" renderer="react" +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +// 👇 If you're using Next.js, apply this framework plugin as well +// import { storybookNextjsPlugin } from '@storybook/experimental-nextjs-vite/vite-plugin'; + +import viteConfig from './vite.config'; + +export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + // storybookNextjsPlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }) +); +``` + +```ts filename="vitest.config.ts" renderer="vue" +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +import { storybookVuePlugin } from '@storybook/vue3-vite/vite-plugin'; + +import viteConfig from './vite.config'; + +export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + storybookVuePlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }) +); +``` + +```ts filename="vitest.config.ts" renderer="svelte" +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +// 👇 If you're using Sveltekit, apply this framework plugin as well +// import { storybookNextjsPlugin } from '@storybook/sveltekit/vite-plugin'; + +import viteConfig from './vite.config'; + +export default mergeConfig( + viteConfig, + defineConfig({ + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + // storybookSveltekitPlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }) +); +``` diff --git a/docs/_snippets/vitest-plugin-vitest-workspace.md b/docs/_snippets/vitest-plugin-vitest-workspace.md new file mode 100644 index 000000000000..909815ddc47e --- /dev/null +++ b/docs/_snippets/vitest-plugin-vitest-workspace.md @@ -0,0 +1,128 @@ +```ts title="vitest.workspace.ts" renderer="react" +import { defineWorkspace } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +// 👇 If you're using Next.js, apply this framework plugin as well +// import { storybookNextjsPlugin } from '@storybook/experimental-nextjs-vite/vite-plugin'; + +export default defineWorkspace([ + // This is the path to your existing Vitest config file + './vitest.config.ts', + { + name: 'storybook', + // This is the path to your existing Vite config file + extends: './vite.config.ts', + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + // storybookNextjsPlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }, +]); +``` + +```ts filename="vitest.config.ts" renderer="vue" +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +import { storybookVuePlugin } from '@storybook/vue3-vite/vite-plugin'; + +import viteConfig from './vite.config'; + +export default defineWorkspace([ + // This is the path to your existing Vitest config file + './vitest.config.ts', + { + name: 'storybook', + // This is the path to your existing Vite config file + extends: './vite.config.ts', + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + storybookVuePlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }, +]); +``` + +```ts filename="vitest.config.ts" renderer="svelte" +import { defineConfig, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; +// 👇 If you're using Sveltekit, apply this framework plugin as well +// import { storybookNextjsPlugin } from '@storybook/sveltekit/vite-plugin'; + +import viteConfig from './vite.config'; + +export default defineWorkspace([ + // This is the path to your existing Vitest config file + './vitest.config.ts', + { + name: 'storybook', + // This is the path to your existing Vite config file + extends: './vite.config.ts', + plugins: [ + storybookTest({ + // This should match your package.json script to run Storybook + // The --ci flag will skip prompts and not open a browser + storybookScript: 'yarn storybook --ci', + }), + // storybookSveltekitPlugin(), + ], + test: { + // Glob pattern to find story files + include: ['src/**/*.stories.?(m)[jt]s?(x)'], + // Enable browser mode + browser: { + enabled: true, + name: 'chromium', + // Make sure to install Playwright + provider: 'playwright', + headless: true, + }, + // Speed up tests and better match how they run in Storybook itself + // https://vitest.dev/config/#isolate + // Consider removing this if you have flaky tests + isolate: false, + setupFiles: ['./.storybook/vitest.setup.ts'], + }, + }, +]); +``` diff --git a/docs/writing-tests/test-runner-with-vitest.mdx b/docs/writing-tests/vitest-plugin.mdx similarity index 71% rename from docs/writing-tests/test-runner-with-vitest.mdx rename to docs/writing-tests/vitest-plugin.mdx index 2b636ffd4a64..20ad70ee341c 100644 --- a/docs/writing-tests/test-runner-with-vitest.mdx +++ b/docs/writing-tests/vitest-plugin.mdx @@ -1,15 +1,15 @@ --- -title: 'Test runner with Vitest' +title: 'Storybook Vitest plugin' sidebar: order: 2 - title: Test runner with Vitest + title: Vitest plugin --- - Test runner with Vitest is currently only supported in [React](?renderer=react), [Vue](?renderer=vue) and [Svelte](?renderer=svelte) projects. + The Storybook Vitest plugin is currently only supported in [React](?renderer=react), [Vue](?renderer=vue) and [Svelte](?renderer=svelte) projects, which use the [Vite builder](../builders/vite.mdx) (or the [Next.js framework](../get-started/frameworks/nextjs.mdx)). - If you are using a different renderer, you can use the [previous test runner](./test-runner.mdx) to test your stories. + If you are using a different renderer, you can use the [Storyboook test runner](./test-runner.mdx) to test your stories. {/* End non-supported renderers */} @@ -20,14 +20,14 @@ sidebar: (⚠️ **Experimental**) - While this feature is experimental, it is published as the `@storybook/experimental-addon-test` package. + While this feature is experimental, it is published within the `@storybook/experimental-addon-test` package and the API may change in future releases. We welcome feedback and contributions to help improve this feature. -Storybook's test runner with Vitest transforms your [stories](../writing-stories/index.mdx) into tests using a Vitest plugin and [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Those tests are then run using [Vitest](https://vitest.dev). This approach is faster and more flexible than the [previous test runner](./test-runner.mdx), which required a running Storybook instance to test your stories. +Storybook's Vitest plugin transforms your [stories](../writing-stories/index.mdx) into [Vitest](https://vitest.dev) tests using [portable stories](../api/portable-stories/portable-stories-vitest.mdx). Those tests can then be run alongside any other Vitest tests. This approach is faster and more flexible than the [test runner](./test-runner.mdx), which required a running Storybook instance to test your stories. We recommend (and configure, by default) running Vitest in [browser mode](https://vitest.dev/guide/browser/), using [Playwright's](https://playwright.dev) Chromium browser. Browser mode ensures your components are tested in a real browser environment, which is more accurate than simulations like JSDom or HappyDom. This is especially important for testing components that rely on browser APIs or features. -Stories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../writing-stories/play-function.mdx) is defined, that function is run and any [assertions made](../writing-tests/interaction-testing.mdx#assert-tests-with-vitests-apis) within it are validated. +Stories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../writing-tests/component-testing#write-a-component-test) is defined, that function is run and any [assertions made](../writing-tests/component-testing.mdx#assert-tests-with-vitests-apis) within it are validated. ## Install and set up @@ -49,7 +49,7 @@ Run the following command to install and configure the addon, which contains the -That [`add` command](../addons/install-addons.mdx#automatic-installation) will install and register the Vitest addon. It will also inspect your project's Vite and Vitest setup, and install and configure them with sensible defaults, if necessary. You may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. +That [`add` command](../addons/install-addons.mdx#automatic-installation) will install and register the test addon. It will also inspect your project's Vite and Vitest setup, and install and configure them with sensible defaults, if necessary. You may need to adjust the configuration to fit your project's needs. The full configuration options can be found in the [API section](#options), below. ### Manual setup @@ -58,19 +58,27 @@ For some project setups, the `add` command may be unable to automate the plugin 1. Make sure Vite and Vitest are configured in your project. 1. Configure Vitest to use [browser mode](https://vitest.dev/guide/browser/). 1. Install the addon, `@storybook/experimental-addon-test`, in your project and [register it in your Storybook configuration](http://storybook.js.org/docs/addons/install-addons#manual-installation). -1. Create a test setup file, `.storybook/vitest.setup.ts`. You can use the example setup file, below, as a guide -1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can use the example configuration files, below, as a guide. +1. Create a test setup file, `.storybook/vitest.setup.ts`. You can use the [example setup file](#example-vitest-setup) as a guide. +1. Adjust your Vitest configuration to include the plugin(s) and reference the setup file. You can use the [example configuration files](#example-configuration-files) as a guide. #### Framework plugins Some Storybook frameworks require additional setup to enable the framework's features to work with Vitest. Each of those frameworks exports a Vite plugin that you can use to configure your project correctly: - If you're using Next.js, use `@storybook/experimental-nextjs-vite/vite-plugin`: + If you're using Next.js, first install the `@storybook/experimental-nextjs-vite` package: + + {/* prettier-ignore-start */} + + + + {/* prettier-ignore-end */} + + Then apply the plugin from `@storybook/experimental-nextjs-vite/vite-plugin`: ```js title="vitest.config.ts" import { defineConfig, mergeConfig } from 'vitest/config'; - import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; import { storybookNextjsPlugin } from '@storybook/experimental-nextjs-vite/vite-plugin'; import viteConfig from './vite.config'; @@ -80,7 +88,7 @@ Some Storybook frameworks require additional setup to enable the framework's fea defineConfig({ plugins: [ storybookTest(), - storybookNextjsPlugin(), // 👈 Use the plugin here + storybookNextjsPlugin(), // 👈 Apply the framework plugin here ], // ... }) @@ -89,11 +97,11 @@ Some Storybook frameworks require additional setup to enable the framework's fea - Vue projects should use `@storybook/vue3-vite/vite-plugin`: + Vue projects should apply the plugin from `@storybook/vue3-vite/vite-plugin`: ```js title="vitest.config.ts" import { defineConfig, mergeConfig } from 'vitest/config'; - import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; import { storybookVuePlugin } from '@storybook/vue3-vite/vite-plugin'; import viteConfig from './vite.config' @@ -103,7 +111,7 @@ Some Storybook frameworks require additional setup to enable the framework's fea defineConfig({ plugins: [ storybookTest(), - storybookVuePlugin(), // 👈 Use the plugin here + storybookVuePlugin(), // 👈 Apply the framework plugin here ], // ... }) @@ -112,11 +120,11 @@ Some Storybook frameworks require additional setup to enable the framework's fea - If you're using SvelteKit, use `@storybook/sveltekit/vite-plugin`: + If you're using SvelteKit, apply the plugin from `@storybook/sveltekit/vite-plugin`: ```js title="vitest.config.ts" import { defineConfig, mergeConfig } from 'vitest/config'; - import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; import { storybookSveltekitPlugin } from '@storybook/sveltekit/vite-plugin'; import viteConfig from './vite.config'; @@ -126,7 +134,7 @@ Some Storybook frameworks require additional setup to enable the framework's fea defineConfig({ plugins: [ storybookTest(), - storybookSveltekitPlugin(), // 👈 Use the plugin here + storybookSveltekitPlugin(), // 👈 Apply the framework plugin here ], // ... }) @@ -140,109 +148,44 @@ The above example uses the framework's plugin in a Vitest configuration file. Yo When the addon is set up automatically, it will create or adjust your Vitest configuration files for you. If you're setting up manually, you can use the following examples as a reference when configuring your project. -

+
Example Vitest setup file Storybook stories contain configuration defined in `.storybook/preview.js|ts`. To ensure that configuration is available to your tests, you can apply it in a Vitest setup file. Here's an example of how to do that: -```ts title=".storybook/vitest.setup.ts" -import { beforeAll } from 'vitest'; -// Replace your-renderer with the renderer you are using (e.g., react, vue3, svelte, etc.) -import { setProjectAnnotations } from '@storybook/your-renderer'; + {/* prettier-ignore-start */} -import * as projectAnnotations from './preview'; + -const project = setProjectAnnotations([projectAnnotations]); + {/* prettier-ignore-end */} -beforeAll(project.beforeAll); -``` - - The `setProjectAnnotations` function is part of the portable stories API, which is used to transform your stories into tests. For more details, see the [portable stories API documentation](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations). + The `setProjectAnnotations` function is part of the [portable stories API](../api/portable-stories/portable-stories-vitest.mdx#setprojectannotations), which is used internally by the Vitest plugin to transform your stories into tests.
-
+
Example Vitest config file The most simple application of the plugin is to include it in your Vitest configuration file: -```ts title="vitest.config.ts" -import { defineConfig, mergeConfig } from 'vitest/config'; -import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; - -import viteConfig from './vite.config'; - -export default mergeConfig( - viteConfig, - defineConfig({ - plugins: [ - storybookTest({ - storybookScript: 'yarn storybook --ci', - }), - ], - test: { - // Glob pattern to find story files - include: ['src/**/*.stories.?(m)[jt]s?(x)'], - // Enable browser mode - browser: { - enabled: true, - name: 'chromium', - // Make sure to install Playwright - provider: 'playwright', - headless: true, - }, - // Speed up tests and better match how they run in Storybook itself - // https://vitest.dev/config/#isolate - // Consider removing this if you have flaky tests - isolate: false, - setupFiles: ['./.storybook/vitest.setup.ts'], - }, - }) -); -``` + {/* prettier-ignore-start */} + + + + {/* prettier-ignore-end */} +
-
+
Example Vitest workspace file If you're using a [Vitest workspace](https://vitest.dev/guide/workspace), you can define a new workspace project: -```ts title="vitest.workspace.ts" -import { defineWorkspace } from 'vitest/config'; -import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin'; + {/* prettier-ignore-start */} + + + + {/* prettier-ignore-end */} -export default defineWorkspace([ - // This is the path to your existing Vitest config file - './vitest.config.ts', - { - name: 'storybook', - // This is the path to your existing Vite config file - extends: './vite.config.ts', - plugins: [ - storybookTest({ - storybookScript: 'yarn storybook --ci', - }), - ], - name: 'storybook', - test: { - // Glob pattern to find story files - include: ['src/**/*.stories.?(m)[jt]s?(x)'], - // Enable browser mode - browser: { - enabled: true, - name: 'chromium', - // Make sure to install Playwright - provider: 'playwright', - headless: true, - }, - // Speed up tests and better match how they run in Storybook itself - // https://vitest.dev/config/#isolate - // Consider removing this if you have flaky tests - isolate: false, - setupFiles: ['./.storybook/vitest.setup.ts'], - }, - } -]); -```
## Usage @@ -273,15 +216,17 @@ If you already have a `test` script that runs something other than Vitest, you c } ``` -When you run that script, the addon will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: +When you run that script, the plugin will find and run your story-based tests. Here's an example of running your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI: - + ### Editor extension Transforming your stories into Vitest tests with the plugin also enables you to run and debug tests using Vitest [IDE integrations](https://vitest.dev/guide/ide.html). This allows you to run tests directly from your editor, such as VSCode and JetBrains IDE. -[TK - Screenshot of VS Code] +This screenshot shows how you can run your Vitest tests in VSCode using the [Vitest extension](https://marketplace.visualstudio.com/items?itemName=vitest.explorer). Stories are annotated with the test status, and, when a test fails, a link to the story is provided for [debugging](#debugging). + +![Screenshot of test failure in VSCode, showing a failure attached to a story](../_assets/writing-tests/vitest-plugin-vscode.png) ### In CI @@ -335,7 +280,7 @@ While the plugin does not require Storybook to run when testing, you may still w You can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running. -[TK - Screenshot of test output with links to SB] +![Screenshot of test failure in the console, showing a failure with a link to the story](../_assets/writing-tests/vitest-plugin-test-failure.png) ## Configuring tests @@ -375,13 +320,13 @@ export default defineWorkspace([ If the same tag is in both the `include` and `exclude` arrays, the `exclude` behavior takes precedence. -## Comparison to the previous test runner +## Comparison to the test runner -The [previous test runner](./test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. This plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Beyond that core difference, there are a few other distinctions: +The [test runner](./test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. This plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Beyond that core difference, there are a few other distinctions: -Additionally, the previous test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable. +Additionally, the test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable. -Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the previous test runner for most projects. We'll do more benchmarking to quantify this in the future. +Finally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the test runner for most projects. We'll do more benchmarking to quantify this in the future. ## FAQ @@ -404,9 +349,15 @@ If your stories use assets in the public directory and you're not using the defa If you have custom operations defined in [`viteFinal`](../api/main-config/main-config-vite-final.mdx) in your `.storybook/main.js|ts` file, you will need to translate those into the Vitest configuration. This is because the plugin does not use the Storybook Vite configuration. -```ts -TK - Is there a good example we could offer here? -``` +For example, to recreate an alias in Storybook's Vite configuration, you would need to apply that alias in the Vitest configuration: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +The above example places the Vite configuration in a Vitest configuration file. You can also place it in a Vitest workspace file, if that is how your project is configured. ### How do I isolate Storybook tests from others? @@ -432,10 +383,10 @@ We recommend using Chromium, because it is most likely to best match the experie ### Exports -This addon contributes the following exports to Storybook: +This plugin has the following exports: ```js -import { storybookTest } from '@storybook/experimental-addon-test/vite-plugin' +import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin' ``` #### `storybookTest` From de82bf05d40c2d6ea86643663dbce12f3e9930cf Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Mon, 9 Sep 2024 13:54:36 -0600 Subject: [PATCH 054/213] Fix sidebar order --- docs/writing-tests/accessibility-testing.mdx | 2 +- docs/writing-tests/visual-testing.mdx | 2 +- docs/writing-tests/vitest-plugin.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/writing-tests/accessibility-testing.mdx b/docs/writing-tests/accessibility-testing.mdx index 298b9cfc0f18..faa147e958c6 100644 --- a/docs/writing-tests/accessibility-testing.mdx +++ b/docs/writing-tests/accessibility-testing.mdx @@ -1,7 +1,7 @@ --- title: 'Accessibility tests' sidebar: - order: 4 + order: 3 title: Accessibility tests --- diff --git a/docs/writing-tests/visual-testing.mdx b/docs/writing-tests/visual-testing.mdx index c47da0024671..71765a828ccd 100644 --- a/docs/writing-tests/visual-testing.mdx +++ b/docs/writing-tests/visual-testing.mdx @@ -2,7 +2,7 @@ title: Visual tests hideRendererSelector: true sidebar: - order: 3 + order: 2 title: Visual tests --- diff --git a/docs/writing-tests/vitest-plugin.mdx b/docs/writing-tests/vitest-plugin.mdx index 20ad70ee341c..09940ef230d9 100644 --- a/docs/writing-tests/vitest-plugin.mdx +++ b/docs/writing-tests/vitest-plugin.mdx @@ -1,7 +1,7 @@ --- title: 'Storybook Vitest plugin' sidebar: - order: 2 + order: 6 title: Vitest plugin --- From 01d1ef28dcc2e1585eb8a8c65ca1b4f9cc2b4f7a Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Tue, 10 Sep 2024 10:00:44 +0200 Subject: [PATCH 055/213] fix linter formatting issues --- code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts index a384ab78700e..aea3d269a1e3 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts @@ -284,7 +284,9 @@ async function getTsConfigReferences(tsConfigPath: string) { * HTMLElement, MouseEvent) are used. */ function removeNestedSchemas(schema: PropertyMetaSchema) { - if (typeof schema !== 'object') return; + if (typeof schema !== 'object') { + return; + } if (schema.kind === 'enum') { // for enum types, we do not want to remove the schemas because otherwise the controls will be missing // instead we remove the nested schemas for the enum entries to prevent out of memory errors for types like "HTMLElement | MouseEvent" From 4280ec7d03fc444d191adc3d1897284fda542ed8 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 10 Sep 2024 23:52:12 -0600 Subject: [PATCH 056/213] Docs: Fixes for 8.3 --- code/addons/test/src/postinstall.ts | 20 +++++++++---------- docs/_snippets/vitest-plugin-vitest-config.md | 2 +- docs/writing-tests/component-testing.mdx | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/code/addons/test/src/postinstall.ts b/code/addons/test/src/postinstall.ts index a868330b94e7..695cbf90225f 100644 --- a/code/addons/test/src/postinstall.ts +++ b/code/addons/test/src/postinstall.ts @@ -114,14 +114,14 @@ export default async function postInstall(options: PostinstallOptions) { reasons.push( dedent` Please check the documentation for more information about its requirements and installation: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin`} ` ); } else { reasons.push( dedent` Fear not, however, you can follow the manual installation process instead at: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#manual`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`} ` ); } @@ -197,7 +197,7 @@ export default async function postInstall(options: PostinstallOptions) { ${colors.gray(vitestSetupFile)} Please refer to the documentation to complete the setup manually: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#manual`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`} ` ); logger.line(1); @@ -240,7 +240,7 @@ export default async function postInstall(options: PostinstallOptions) { your existing workspace file automatically, you must do it yourself. This was the last step. Please refer to the documentation to complete the setup manually: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#manual`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`} ` ); logger.line(1); @@ -262,7 +262,7 @@ export default async function postInstall(options: PostinstallOptions) { your existing workspace file automatically, you must do it yourself. This was the last step. Please refer to the documentation to complete the setup manually: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#manual`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`} ` ); logger.line(1); @@ -288,13 +288,13 @@ export default async function postInstall(options: PostinstallOptions) { import { defineWorkspace } from 'vitest/config'; import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';${vitestInfo.frameworkPluginImport} - // More info at: https://storybook.js.org/docs/writing-tests/test-runner-with-vitest + // More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin export default defineWorkspace([ '${relative(dirname(browserWorkspaceFile), rootConfig)}', { extends: '${viteConfigFile ? relative(dirname(browserWorkspaceFile), viteConfigFile) : ''}', plugins: [ - // See options at: https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#storybooktest + // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], test: { @@ -327,10 +327,10 @@ export default async function postInstall(options: PostinstallOptions) { import { defineConfig } from 'vitest/config'; import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';${vitestInfo.frameworkPluginImport} - // More info at: https://storybook.js.org/docs/writing-tests/test-runner-with-vitest + // More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin export default defineConfig({ plugins: [ - // See options at: https://storybook.js.org/docs/writing-tests/test-runner-with-vitest#storybooktest + // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], test: { @@ -362,7 +362,7 @@ export default async function postInstall(options: PostinstallOptions) { • When using the Vitest extension in your editor, all of your stories will be shown as tests! Check the documentation for more information about its features and options at: - ${c.cyan`https://storybook.js.org/docs/writing-tests/test-runner-with-vitest`} + ${c.cyan`https://storybook.js.org/docs/writing-tests/vitest-plugin`} ` ); logger.line(1); diff --git a/docs/_snippets/vitest-plugin-vitest-config.md b/docs/_snippets/vitest-plugin-vitest-config.md index fbd358b407b3..0ddc6054f9df 100644 --- a/docs/_snippets/vitest-plugin-vitest-config.md +++ b/docs/_snippets/vitest-plugin-vitest-config.md @@ -81,7 +81,7 @@ export default mergeConfig( import { defineConfig, mergeConfig } from 'vitest/config'; import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'; // 👇 If you're using Sveltekit, apply this framework plugin as well -// import { storybookNextjsPlugin } from '@storybook/sveltekit/vite-plugin'; +// import { storybookSveltekitPlugin } from '@storybook/sveltekit/vite-plugin'; import viteConfig from './vite.config'; diff --git a/docs/writing-tests/component-testing.mdx b/docs/writing-tests/component-testing.mdx index cda397d8de6f..7e2db96c874f 100644 --- a/docs/writing-tests/component-testing.mdx +++ b/docs/writing-tests/component-testing.mdx @@ -21,7 +21,7 @@ You start by writing a [**story**](../writing-stories/index.mdx) to set up the c * The test is written using Storybook-instrumented versions of [Vitest](https://vitest.dev/) and [Testing Library](https://testing-library.com/) coming from the [`@storybook/test`](https://npmjs.com/package/@storybook/test) package. * [`@storybook/addon-interactions`](https://storybook.js.org/addons/@storybook/addon-interactions/) visualizes the test in Storybook and provides a playback interface for convenient browser-based debugging. * [`@storybook/test-runner`](https://github.com/storybookjs/test-runner) is a standalone utility—powered by [Jest](https://jestjs.io/) and [Playwright](https://playwright.dev/)—that executes all of your interactions tests and catches broken stories. - * The experimental [test runner with Vitest](./test-runner-with-vitest.mdx) is also available, which transforms your stories into Vitest tests and runs them in a browser. + * The experimental [Vitest plugin](./vitest-plugin.mdx) is also available, which transforms your stories into Vitest tests and runs them in a browser. ## Set up the interactions addon From ceb8387e24f9b401bd3fc693dbb0f5b220a389d0 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 11 Sep 2024 11:25:00 +0200 Subject: [PATCH 057/213] Add comment explaining asyncWrapper --- code/renderers/react/src/portable-stories.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/renderers/react/src/portable-stories.tsx b/code/renderers/react/src/portable-stories.tsx index bc031a04717e..7b906c9f4bde 100644 --- a/code/renderers/react/src/portable-stories.tsx +++ b/code/renderers/react/src/portable-stories.tsx @@ -65,6 +65,8 @@ export const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations { return act(cb); }, + // For more context about why we need disable act warnings in waitFor: + // https://github.com/reactwg/react-18/discussions/102 asyncWrapper: async (cb) => { const previousActEnvironment = getReactActEnvironment(); setReactActEnvironment(false); From 46aa6e01ff4a4421a9899cc6f18edf2ff8fdee97 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 11 Sep 2024 11:26:34 +0200 Subject: [PATCH 058/213] Fix bug where @storybook/test is not imported but canvas is used directly from context --- code/addons/interactions/src/preview.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/addons/interactions/src/preview.ts b/code/addons/interactions/src/preview.ts index 6abc30f63b93..482b6933279f 100644 --- a/code/addons/interactions/src/preview.ts +++ b/code/addons/interactions/src/preview.ts @@ -1,6 +1,9 @@ import type { PlayFunction, StepLabel, StoryContext } from 'storybook/internal/types'; import { instrument } from '@storybook/instrumenter'; +// This makes sure that storybook test loaders are always loaded when addon-interactions is used +// For 9.0 we want to merge storybook/test and addon-interactions into one addon. +import '@storybook/test'; export const { step: runStep } = instrument( { From 04f98495d85b89d1d2beef4fb4867d27c20b8a89 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:59:18 +0000 Subject: [PATCH 059/213] Write changelog for 8.3.0-beta.5 [skip ci] --- CHANGELOG.prerelease.md | 6 ++++++ code/package.json | 3 ++- docs/versions/next.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 89ecd63012ae..414ba2162d77 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,9 @@ +## 8.3.0-beta.5 + +- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic! +- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic! +- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert! + ## 8.3.0-beta.4 - Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf! diff --git a/code/package.json b/code/package.json index aa4f7f09cf97..b3469a6994ea 100644 --- a/code/package.json +++ b/code/package.json @@ -295,5 +295,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.3.0-beta.5" } diff --git a/docs/versions/next.json b/docs/versions/next.json index 4d28c32e82f6..33043c2d6fdd 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.3.0-beta.4","info":{"plain":"- Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf!\n- UI: Fix sidebar not wrapping - [#29055](https://github.com/storybookjs/storybook/pull/29055), thanks @JReinhold!"}} +{"version":"8.3.0-beta.5","info":{"plain":"- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic!\n- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic!\n- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert!"}} From bce7d703aa34d1e9825d38e0fad343d5ab13a118 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:53:23 +0000 Subject: [PATCH 060/213] Bump version from "8.3.0-beta.4" to "8.3.0-beta.5" [skip ci] --- code/addons/a11y/package.json | 2 +- code/addons/actions/package.json | 2 +- code/addons/backgrounds/package.json | 2 +- code/addons/controls/package.json | 2 +- code/addons/docs/package.json | 2 +- code/addons/essentials/package.json | 2 +- code/addons/gfm/package.json | 2 +- code/addons/highlight/package.json | 2 +- code/addons/interactions/package.json | 2 +- code/addons/jest/package.json | 2 +- code/addons/links/package.json | 2 +- code/addons/measure/package.json | 2 +- code/addons/onboarding/package.json | 2 +- code/addons/outline/package.json | 2 +- code/addons/storysource/package.json | 2 +- code/addons/test/package.json | 2 +- code/addons/themes/package.json | 2 +- code/addons/toolbars/package.json | 2 +- code/addons/viewport/package.json | 2 +- code/builders/builder-vite/package.json | 2 +- code/builders/builder-webpack5/package.json | 2 +- code/core/package.json | 2 +- code/core/src/common/versions.ts | 168 +++++++++--------- code/core/src/manager-api/version.ts | 2 +- code/deprecated/builder-manager/package.json | 2 +- code/deprecated/channels/package.json | 2 +- code/deprecated/client-logger/package.json | 2 +- code/deprecated/components/package.json | 2 +- code/deprecated/core-common/package.json | 2 +- code/deprecated/core-events/package.json | 2 +- code/deprecated/core-server/package.json | 2 +- code/deprecated/csf-tools/package.json | 2 +- code/deprecated/docs-tools/package.json | 2 +- code/deprecated/manager-api/package.json | 2 +- code/deprecated/manager/package.json | 2 +- code/deprecated/node-logger/package.json | 2 +- code/deprecated/preview-api/package.json | 2 +- code/deprecated/preview/package.json | 2 +- code/deprecated/router/package.json | 2 +- code/deprecated/telemetry/package.json | 2 +- code/deprecated/theming/package.json | 2 +- code/deprecated/types/package.json | 2 +- code/frameworks/angular/package.json | 2 +- code/frameworks/ember/package.json | 2 +- .../experimental-nextjs-vite/package.json | 2 +- code/frameworks/html-vite/package.json | 2 +- code/frameworks/html-webpack5/package.json | 2 +- code/frameworks/nextjs/package.json | 2 +- code/frameworks/preact-vite/package.json | 2 +- code/frameworks/preact-webpack5/package.json | 2 +- code/frameworks/react-vite/package.json | 2 +- code/frameworks/react-webpack5/package.json | 2 +- code/frameworks/server-webpack5/package.json | 2 +- code/frameworks/svelte-vite/package.json | 2 +- code/frameworks/svelte-webpack5/package.json | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/frameworks/vue3-vite/package.json | 2 +- code/frameworks/vue3-webpack5/package.json | 2 +- .../web-components-vite/package.json | 2 +- .../web-components-webpack5/package.json | 2 +- code/lib/blocks/package.json | 2 +- code/lib/cli-sb/package.json | 2 +- code/lib/cli-storybook/package.json | 2 +- code/lib/cli/package.json | 2 +- code/lib/codemod/package.json | 2 +- code/lib/core-webpack/package.json | 2 +- code/lib/create-storybook/package.json | 2 +- code/lib/csf-plugin/package.json | 2 +- code/lib/instrumenter/package.json | 2 +- code/lib/react-dom-shim/package.json | 2 +- code/lib/source-loader/package.json | 2 +- code/lib/test/package.json | 2 +- code/package.json | 5 +- code/presets/create-react-app/package.json | 2 +- code/presets/html-webpack/package.json | 2 +- code/presets/preact-webpack/package.json | 2 +- code/presets/react-webpack/package.json | 2 +- code/presets/server-webpack/package.json | 2 +- code/presets/svelte-webpack/package.json | 2 +- code/presets/vue3-webpack/package.json | 2 +- code/renderers/html/package.json | 2 +- code/renderers/preact/package.json | 2 +- code/renderers/react/package.json | 2 +- code/renderers/server/package.json | 2 +- code/renderers/svelte/package.json | 2 +- code/renderers/vue3/package.json | 2 +- code/renderers/web-components/package.json | 2 +- 87 files changed, 171 insertions(+), 172 deletions(-) diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index a7b331a1e602..bdd3310cef25 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index 7c32e2532f50..179db8003635 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index bb75135aae4c..bbeacc4bdf68 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index c81747a6c571..838005e155ff 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index 83cab07858e4..10d0f83aac81 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index f89814a7d4e1..210efeceb7ff 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index 9e3a6ea89fdb..010b02f01462 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index e543d1ffe32b..dfd92f3d6554 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index 214d183f0a70..53b233dfe1a0 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index 73e977da3e4d..7bc2e7209fd6 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "React storybook addon that show component jest report", "keywords": [ "addon", diff --git a/code/addons/links/package.json b/code/addons/links/package.json index 7f339327da93..5d9eb11ae55f 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json index 59d95f5fcfb0..477cf4fdaf73 100644 --- a/code/addons/measure/package.json +++ b/code/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json index 70ff24eb52a4..28d38d8e82b0 100644 --- a/code/addons/onboarding/package.json +++ b/code/addons/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-onboarding", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Addon Onboarding - Introduces a new onboarding experience", "keywords": [ "storybook-addons", diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 21593b46384d..16817816d17e 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index 20ac10370da3..de3ce2cf2ad9 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", diff --git a/code/addons/test/package.json b/code/addons/test/package.json index ca52df1494d3..4346d6ea9b9c 100644 --- a/code/addons/test/package.json +++ b/code/addons/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-addon-test", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Integrate Vitest with Storybook", "keywords": [ "storybook-addons", diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json index e83374efdf5e..916775ac206b 100644 --- a/code/addons/themes/package.json +++ b/code/addons/themes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-themes", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Switch between multiple themes for you components in Storybook", "keywords": [ "css", diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index af631dca4c59..2c48c750d875 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index faafc88f0e63..3932f2907666 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index aa1239fd2f47..94a148570ac0 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "A plugin to run and build Storybooks with Vite", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme", "bugs": { diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index c0cb7ac2cff4..d9d1fcd1a4e9 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/package.json b/code/core/package.json index b6497ac7809a..0ca89f3ebd54 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/src/common/versions.ts b/code/core/src/common/versions.ts index ed064cc606f5..18a0e438366a 100644 --- a/code/core/src/common/versions.ts +++ b/code/core/src/common/versions.ts @@ -1,87 +1,87 @@ // auto generated file, do not edit export default { - '@storybook/addon-a11y': '8.3.0-beta.4', - '@storybook/addon-actions': '8.3.0-beta.4', - '@storybook/addon-backgrounds': '8.3.0-beta.4', - '@storybook/addon-controls': '8.3.0-beta.4', - '@storybook/addon-docs': '8.3.0-beta.4', - '@storybook/addon-essentials': '8.3.0-beta.4', - '@storybook/addon-mdx-gfm': '8.3.0-beta.4', - '@storybook/addon-highlight': '8.3.0-beta.4', - '@storybook/addon-interactions': '8.3.0-beta.4', - '@storybook/addon-jest': '8.3.0-beta.4', - '@storybook/addon-links': '8.3.0-beta.4', - '@storybook/addon-measure': '8.3.0-beta.4', - '@storybook/addon-onboarding': '8.3.0-beta.4', - '@storybook/addon-outline': '8.3.0-beta.4', - '@storybook/addon-storysource': '8.3.0-beta.4', - '@storybook/experimental-addon-test': '8.3.0-beta.4', - '@storybook/addon-themes': '8.3.0-beta.4', - '@storybook/addon-toolbars': '8.3.0-beta.4', - '@storybook/addon-viewport': '8.3.0-beta.4', - '@storybook/builder-vite': '8.3.0-beta.4', - '@storybook/builder-webpack5': '8.3.0-beta.4', - '@storybook/core': '8.3.0-beta.4', - '@storybook/builder-manager': '8.3.0-beta.4', - '@storybook/channels': '8.3.0-beta.4', - '@storybook/client-logger': '8.3.0-beta.4', - '@storybook/components': '8.3.0-beta.4', - '@storybook/core-common': '8.3.0-beta.4', - '@storybook/core-events': '8.3.0-beta.4', - '@storybook/core-server': '8.3.0-beta.4', - '@storybook/csf-tools': '8.3.0-beta.4', - '@storybook/docs-tools': '8.3.0-beta.4', - '@storybook/manager': '8.3.0-beta.4', - '@storybook/manager-api': '8.3.0-beta.4', - '@storybook/node-logger': '8.3.0-beta.4', - '@storybook/preview': '8.3.0-beta.4', - '@storybook/preview-api': '8.3.0-beta.4', - '@storybook/router': '8.3.0-beta.4', - '@storybook/telemetry': '8.3.0-beta.4', - '@storybook/theming': '8.3.0-beta.4', - '@storybook/types': '8.3.0-beta.4', - '@storybook/angular': '8.3.0-beta.4', - '@storybook/ember': '8.3.0-beta.4', - '@storybook/experimental-nextjs-vite': '8.3.0-beta.4', - '@storybook/html-vite': '8.3.0-beta.4', - '@storybook/html-webpack5': '8.3.0-beta.4', - '@storybook/nextjs': '8.3.0-beta.4', - '@storybook/preact-vite': '8.3.0-beta.4', - '@storybook/preact-webpack5': '8.3.0-beta.4', - '@storybook/react-vite': '8.3.0-beta.4', - '@storybook/react-webpack5': '8.3.0-beta.4', - '@storybook/server-webpack5': '8.3.0-beta.4', - '@storybook/svelte-vite': '8.3.0-beta.4', - '@storybook/svelte-webpack5': '8.3.0-beta.4', - '@storybook/sveltekit': '8.3.0-beta.4', - '@storybook/vue3-vite': '8.3.0-beta.4', - '@storybook/vue3-webpack5': '8.3.0-beta.4', - '@storybook/web-components-vite': '8.3.0-beta.4', - '@storybook/web-components-webpack5': '8.3.0-beta.4', - '@storybook/blocks': '8.3.0-beta.4', - storybook: '8.3.0-beta.4', - sb: '8.3.0-beta.4', - '@storybook/cli': '8.3.0-beta.4', - '@storybook/codemod': '8.3.0-beta.4', - '@storybook/core-webpack': '8.3.0-beta.4', - 'create-storybook': '8.3.0-beta.4', - '@storybook/csf-plugin': '8.3.0-beta.4', - '@storybook/instrumenter': '8.3.0-beta.4', - '@storybook/react-dom-shim': '8.3.0-beta.4', - '@storybook/source-loader': '8.3.0-beta.4', - '@storybook/test': '8.3.0-beta.4', - '@storybook/preset-create-react-app': '8.3.0-beta.4', - '@storybook/preset-html-webpack': '8.3.0-beta.4', - '@storybook/preset-preact-webpack': '8.3.0-beta.4', - '@storybook/preset-react-webpack': '8.3.0-beta.4', - '@storybook/preset-server-webpack': '8.3.0-beta.4', - '@storybook/preset-svelte-webpack': '8.3.0-beta.4', - '@storybook/preset-vue3-webpack': '8.3.0-beta.4', - '@storybook/html': '8.3.0-beta.4', - '@storybook/preact': '8.3.0-beta.4', - '@storybook/react': '8.3.0-beta.4', - '@storybook/server': '8.3.0-beta.4', - '@storybook/svelte': '8.3.0-beta.4', - '@storybook/vue3': '8.3.0-beta.4', - '@storybook/web-components': '8.3.0-beta.4', + '@storybook/addon-a11y': '8.3.0-beta.5', + '@storybook/addon-actions': '8.3.0-beta.5', + '@storybook/addon-backgrounds': '8.3.0-beta.5', + '@storybook/addon-controls': '8.3.0-beta.5', + '@storybook/addon-docs': '8.3.0-beta.5', + '@storybook/addon-essentials': '8.3.0-beta.5', + '@storybook/addon-mdx-gfm': '8.3.0-beta.5', + '@storybook/addon-highlight': '8.3.0-beta.5', + '@storybook/addon-interactions': '8.3.0-beta.5', + '@storybook/addon-jest': '8.3.0-beta.5', + '@storybook/addon-links': '8.3.0-beta.5', + '@storybook/addon-measure': '8.3.0-beta.5', + '@storybook/addon-onboarding': '8.3.0-beta.5', + '@storybook/addon-outline': '8.3.0-beta.5', + '@storybook/addon-storysource': '8.3.0-beta.5', + '@storybook/experimental-addon-test': '8.3.0-beta.5', + '@storybook/addon-themes': '8.3.0-beta.5', + '@storybook/addon-toolbars': '8.3.0-beta.5', + '@storybook/addon-viewport': '8.3.0-beta.5', + '@storybook/builder-vite': '8.3.0-beta.5', + '@storybook/builder-webpack5': '8.3.0-beta.5', + '@storybook/core': '8.3.0-beta.5', + '@storybook/builder-manager': '8.3.0-beta.5', + '@storybook/channels': '8.3.0-beta.5', + '@storybook/client-logger': '8.3.0-beta.5', + '@storybook/components': '8.3.0-beta.5', + '@storybook/core-common': '8.3.0-beta.5', + '@storybook/core-events': '8.3.0-beta.5', + '@storybook/core-server': '8.3.0-beta.5', + '@storybook/csf-tools': '8.3.0-beta.5', + '@storybook/docs-tools': '8.3.0-beta.5', + '@storybook/manager': '8.3.0-beta.5', + '@storybook/manager-api': '8.3.0-beta.5', + '@storybook/node-logger': '8.3.0-beta.5', + '@storybook/preview': '8.3.0-beta.5', + '@storybook/preview-api': '8.3.0-beta.5', + '@storybook/router': '8.3.0-beta.5', + '@storybook/telemetry': '8.3.0-beta.5', + '@storybook/theming': '8.3.0-beta.5', + '@storybook/types': '8.3.0-beta.5', + '@storybook/angular': '8.3.0-beta.5', + '@storybook/ember': '8.3.0-beta.5', + '@storybook/experimental-nextjs-vite': '8.3.0-beta.5', + '@storybook/html-vite': '8.3.0-beta.5', + '@storybook/html-webpack5': '8.3.0-beta.5', + '@storybook/nextjs': '8.3.0-beta.5', + '@storybook/preact-vite': '8.3.0-beta.5', + '@storybook/preact-webpack5': '8.3.0-beta.5', + '@storybook/react-vite': '8.3.0-beta.5', + '@storybook/react-webpack5': '8.3.0-beta.5', + '@storybook/server-webpack5': '8.3.0-beta.5', + '@storybook/svelte-vite': '8.3.0-beta.5', + '@storybook/svelte-webpack5': '8.3.0-beta.5', + '@storybook/sveltekit': '8.3.0-beta.5', + '@storybook/vue3-vite': '8.3.0-beta.5', + '@storybook/vue3-webpack5': '8.3.0-beta.5', + '@storybook/web-components-vite': '8.3.0-beta.5', + '@storybook/web-components-webpack5': '8.3.0-beta.5', + '@storybook/blocks': '8.3.0-beta.5', + storybook: '8.3.0-beta.5', + sb: '8.3.0-beta.5', + '@storybook/cli': '8.3.0-beta.5', + '@storybook/codemod': '8.3.0-beta.5', + '@storybook/core-webpack': '8.3.0-beta.5', + 'create-storybook': '8.3.0-beta.5', + '@storybook/csf-plugin': '8.3.0-beta.5', + '@storybook/instrumenter': '8.3.0-beta.5', + '@storybook/react-dom-shim': '8.3.0-beta.5', + '@storybook/source-loader': '8.3.0-beta.5', + '@storybook/test': '8.3.0-beta.5', + '@storybook/preset-create-react-app': '8.3.0-beta.5', + '@storybook/preset-html-webpack': '8.3.0-beta.5', + '@storybook/preset-preact-webpack': '8.3.0-beta.5', + '@storybook/preset-react-webpack': '8.3.0-beta.5', + '@storybook/preset-server-webpack': '8.3.0-beta.5', + '@storybook/preset-svelte-webpack': '8.3.0-beta.5', + '@storybook/preset-vue3-webpack': '8.3.0-beta.5', + '@storybook/html': '8.3.0-beta.5', + '@storybook/preact': '8.3.0-beta.5', + '@storybook/react': '8.3.0-beta.5', + '@storybook/server': '8.3.0-beta.5', + '@storybook/svelte': '8.3.0-beta.5', + '@storybook/vue3': '8.3.0-beta.5', + '@storybook/web-components': '8.3.0-beta.5', }; diff --git a/code/core/src/manager-api/version.ts b/code/core/src/manager-api/version.ts index 1c66037e4d34..78f7ab7e0bd1 100644 --- a/code/core/src/manager-api/version.ts +++ b/code/core/src/manager-api/version.ts @@ -1 +1 @@ -export const version = '8.3.0-beta.4'; +export const version = '8.3.0-beta.5'; diff --git a/code/deprecated/builder-manager/package.json b/code/deprecated/builder-manager/package.json index 7b388a902566..19fa9372b410 100644 --- a/code/deprecated/builder-manager/package.json +++ b/code/deprecated/builder-manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-manager", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook manager builder", "keywords": [ "storybook" diff --git a/code/deprecated/channels/package.json b/code/deprecated/channels/package.json index d00f6021aed4..ac793731b668 100644 --- a/code/deprecated/channels/package.json +++ b/code/deprecated/channels/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channels", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/client-logger/package.json b/code/deprecated/client-logger/package.json index 57c2cf4316d6..ba627661d64b 100644 --- a/code/deprecated/client-logger/package.json +++ b/code/deprecated/client-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-logger", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/components/package.json b/code/deprecated/components/package.json index f97b5c2aef14..409e692bd517 100644 --- a/code/deprecated/components/package.json +++ b/code/deprecated/components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/components", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/core-common/package.json b/code/deprecated/core-common/package.json index 89b42c158fe5..204adea56eb7 100644 --- a/code/deprecated/core-common/package.json +++ b/code/deprecated/core-common/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-common", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/core-events/package.json b/code/deprecated/core-events/package.json index 0a21e7d9e8c4..eafd34bf6be5 100644 --- a/code/deprecated/core-events/package.json +++ b/code/deprecated/core-events/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-events", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Event names used in storybook core", "keywords": [ "storybook" diff --git a/code/deprecated/core-server/package.json b/code/deprecated/core-server/package.json index 2a09a96d174d..7882b3aabbec 100644 --- a/code/deprecated/core-server/package.json +++ b/code/deprecated/core-server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-server", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/csf-tools/package.json b/code/deprecated/csf-tools/package.json index 2703425d8857..4caa8fac5a08 100644 --- a/code/deprecated/csf-tools/package.json +++ b/code/deprecated/csf-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-tools", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Parse and manipulate CSF and Storybook config files", "keywords": [ "storybook" diff --git a/code/deprecated/docs-tools/package.json b/code/deprecated/docs-tools/package.json index d952c1789ce4..928f90cc0804 100644 --- a/code/deprecated/docs-tools/package.json +++ b/code/deprecated/docs-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/docs-tools", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Shared utility functions for frameworks to implement docs", "keywords": [ "storybook" diff --git a/code/deprecated/manager-api/package.json b/code/deprecated/manager-api/package.json index 65449140e3d5..038144dd976d 100644 --- a/code/deprecated/manager-api/package.json +++ b/code/deprecated/manager-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager-api", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook Manager API & Context", "keywords": [ "storybook" diff --git a/code/deprecated/manager/package.json b/code/deprecated/manager/package.json index 30ec9ee1459d..3e0c991fb608 100644 --- a/code/deprecated/manager/package.json +++ b/code/deprecated/manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook UI", "keywords": [ "storybook" diff --git a/code/deprecated/node-logger/package.json b/code/deprecated/node-logger/package.json index d26f3d0fb207..8901ed7f14cf 100644 --- a/code/deprecated/node-logger/package.json +++ b/code/deprecated/node-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/node-logger", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview-api/package.json b/code/deprecated/preview-api/package.json index 1bcedb15c9ba..b254ebdd8768 100644 --- a/code/deprecated/preview-api/package.json +++ b/code/deprecated/preview-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview-api", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview/package.json b/code/deprecated/preview/package.json index 5e293120aa4d..7f7a51d27974 100644 --- a/code/deprecated/preview/package.json +++ b/code/deprecated/preview/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/router/package.json b/code/deprecated/router/package.json index 83b20c6f6b31..ffc3f6ccc850 100644 --- a/code/deprecated/router/package.json +++ b/code/deprecated/router/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/router", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook Router", "keywords": [ "storybook" diff --git a/code/deprecated/telemetry/package.json b/code/deprecated/telemetry/package.json index 909e98511df3..c82b46411d3e 100644 --- a/code/deprecated/telemetry/package.json +++ b/code/deprecated/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/telemetry", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Telemetry logging for crash reports and usage statistics", "keywords": [ "storybook" diff --git a/code/deprecated/theming/package.json b/code/deprecated/theming/package.json index 803249838852..b7f850ccb2bd 100644 --- a/code/deprecated/theming/package.json +++ b/code/deprecated/theming/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/theming", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/types/package.json b/code/deprecated/types/package.json index da38c9b0cea1..8bb2554675b5 100644 --- a/code/deprecated/types/package.json +++ b/code/deprecated/types/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/types", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Core Storybook TS Types", "keywords": [ "storybook" diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 1f299fad3865..1badd71aee97 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 0ccf6e3e8511..7e7c31e4facc 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index 455f179fc465..60b2442513ae 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-nextjs-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Next.js and Vite", "keywords": [ "storybook", diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index c96bb225cbb7..84d3bae80ef2 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index d942efb70359..f685e702ad3b 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 415e57c96964..57fe6ae80cf8 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/nextjs", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Next.js", "keywords": [ "storybook", diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 7901cc54ddb1..63dc9ed4a51f 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index 5924abce7021..e6a420633dbd 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index ffcab019deb2..a29a56f5dd79 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index 8fa2d42ff357..be86692ae401 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index b77941e0f4e7..79fe5e3e1b86 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index f2b87e3bc268..a767d1f6b6ba 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index f368810a808b..1425a0e579b9 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index f76c5e909f4e..c3800e1dad0c 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/sveltekit", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for SvelteKit", "keywords": [ "storybook", diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 081720b77961..4061d79cda74 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 965b4020a46f..9ea728ca905a 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 64ded4415b44..22de31145d6d 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-vite", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index b3fe2ca851a9..95429756f449 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-webpack5", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit", diff --git a/code/lib/blocks/package.json b/code/lib/blocks/package.json index c6f1f96d7fae..be218625886b 100644 --- a/code/lib/blocks/package.json +++ b/code/lib/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/blocks", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Doc Blocks", "keywords": [ "storybook" diff --git a/code/lib/cli-sb/package.json b/code/lib/cli-sb/package.json index 20382e2fec72..150628dabc1d 100644 --- a/code/lib/cli-sb/package.json +++ b/code/lib/cli-sb/package.json @@ -1,6 +1,6 @@ { "name": "sb", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index d37d1aaf529e..9e5be67e2b87 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/cli", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index bda6d2d79d6f..ec0ce5cbb3fc 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook's CLI - install, dev, build, upgrade, and more", "keywords": [ "cli", diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index d23937951533..6ec768d6cc68 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/codemod", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "A collection of codemod scripts written with JSCodeshift", "keywords": [ "storybook" diff --git a/code/lib/core-webpack/package.json b/code/lib/core-webpack/package.json index 3ff2f28e586e..11c1058d64c3 100644 --- a/code/lib/core-webpack/package.json +++ b/code/lib/core-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/create-storybook/package.json b/code/lib/create-storybook/package.json index 187bd286a799..1515c472cf6a 100644 --- a/code/lib/create-storybook/package.json +++ b/code/lib/create-storybook/package.json @@ -1,6 +1,6 @@ { "name": "create-storybook", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Initialize Storybook into your project", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook", "bugs": { diff --git a/code/lib/csf-plugin/package.json b/code/lib/csf-plugin/package.json index 721dab51a263..f79d8ca09086 100644 --- a/code/lib/csf-plugin/package.json +++ b/code/lib/csf-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-plugin", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Enrich CSF files via static analysis", "keywords": [ "storybook" diff --git a/code/lib/instrumenter/package.json b/code/lib/instrumenter/package.json index ff16fc3e7b01..57ff514b7d09 100644 --- a/code/lib/instrumenter/package.json +++ b/code/lib/instrumenter/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/instrumenter", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/lib/react-dom-shim/package.json b/code/lib/react-dom-shim/package.json index caaeed8cb007..80364b6bebf0 100644 --- a/code/lib/react-dom-shim/package.json +++ b/code/lib/react-dom-shim/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-dom-shim", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json index 22e617fc9c6b..308fab65ce8a 100644 --- a/code/lib/source-loader/package.json +++ b/code/lib/source-loader/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/source-loader", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Source loader", "keywords": [ "lib", diff --git a/code/lib/test/package.json b/code/lib/test/package.json index 6bcc55ef4574..0aa37cd6d5ac 100644 --- a/code/lib/test/package.json +++ b/code/lib/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/test", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "", "keywords": [ "storybook" diff --git a/code/package.json b/code/package.json index b3469a6994ea..1f7445d67f1b 100644 --- a/code/package.json +++ b/code/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/root", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "private": true, "description": "Storybook root", "homepage": "https://storybook.js.org/", @@ -295,6 +295,5 @@ "Dependency Upgrades" ] ] - }, - "deferredNextVersion": "8.3.0-beta.5" + } } diff --git a/code/presets/create-react-app/package.json b/code/presets/create-react-app/package.json index e77c0aad747a..12fca76a6bec 100644 --- a/code/presets/create-react-app/package.json +++ b/code/presets/create-react-app/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-create-react-app", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Create React App preset", "keywords": [ "storybook" diff --git a/code/presets/html-webpack/package.json b/code/presets/html-webpack/package.json index 40a127610a18..7a65af963106 100644 --- a/code/presets/html-webpack/package.json +++ b/code/presets/html-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-html-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json index 638ff695aca0..d6db6935db42 100644 --- a/code/presets/preact-webpack/package.json +++ b/code/presets/preact-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-preact-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index 76244cac1bf7..17476669f734 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-react-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading", "keywords": [ "storybook" diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json index b58cd2a73bf9..a4a7d1213947 100644 --- a/code/presets/server-webpack/package.json +++ b/code/presets/server-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-server-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json index 1c5ccf77b50b..b682ead94aee 100644 --- a/code/presets/svelte-webpack/package.json +++ b/code/presets/svelte-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-svelte-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/vue3-webpack/package.json b/code/presets/vue3-webpack/package.json index 6a692823e2d4..828c51524cbe 100644 --- a/code/presets/vue3-webpack/package.json +++ b/code/presets/vue3-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-vue3-webpack", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/renderers/html/package.json b/code/renderers/html/package.json index de24babe4b8e..573f32cae134 100644 --- a/code/renderers/html/package.json +++ b/code/renderers/html/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook HTML renderer", "keywords": [ "storybook" diff --git a/code/renderers/preact/package.json b/code/renderers/preact/package.json index cc83c3a83951..21013f4ab4c0 100644 --- a/code/renderers/preact/package.json +++ b/code/renderers/preact/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Preact renderer", "keywords": [ "storybook" diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 65e4fe6fdf49..36c00f774d0f 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook React renderer", "keywords": [ "storybook" diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json index f699fde6b410..da88a2a5ef65 100644 --- a/code/renderers/server/package.json +++ b/code/renderers/server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Server renderer", "keywords": [ "storybook" diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index e09bd81b0d32..ccb4b142aa8e 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Svelte renderer", "keywords": [ "storybook" diff --git a/code/renderers/vue3/package.json b/code/renderers/vue3/package.json index 77faa267b610..7c227869ca72 100644 --- a/code/renderers/vue3/package.json +++ b/code/renderers/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook Vue 3 renderer", "keywords": [ "storybook" diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json index f2c1b0b34caf..57edb9280a25 100644 --- a/code/renderers/web-components/package.json +++ b/code/renderers/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "8.3.0-beta.4", + "version": "8.3.0-beta.5", "description": "Storybook web-components renderer", "keywords": [ "lit", From ac2f4e5aefb30db2c0d868af64a773610d62bab6 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:13:22 +0000 Subject: [PATCH 061/213] Write changelog for 8.3.0 [skip ci] --- CHANGELOG.md | 3 +++ code/package.json | 3 ++- docs/versions/latest.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c899e2c2b3ad..eb244c0d4997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 8.3.0 + + ## 8.2.9 - CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! diff --git a/code/package.json b/code/package.json index 1f7445d67f1b..a6967711237b 100644 --- a/code/package.json +++ b/code/package.json @@ -295,5 +295,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.3.0" } diff --git a/docs/versions/latest.json b/docs/versions/latest.json index bc9c7b4e27d2..db378469890e 100644 --- a/docs/versions/latest.json +++ b/docs/versions/latest.json @@ -1 +1 @@ -{"version":"8.2.0","info":{"plain":""}} +{"version":"8.3.0","info":{"plain":""}} From 3623b13930b52bf7de0b9f95971dd970bf815b7e Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 11 Sep 2024 15:07:28 +0200 Subject: [PATCH 062/213] Update CHANGELOG.md for 8.3 --- CHANGELOG.md | 169 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 126 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb244c0d4997..0c1a3b330c00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,62 +1,145 @@ ## 8.3.0 +Fresh out of the oven! Storybook 8.3 brings you: -## 8.2.9 +- ⚡️ **First-class Vitest integration** to run stories as component tests +- 🔼 **Next.js-Vite framework** for Vitest compatibility and better DX +- 🗜️ **Further reduced bundle size** for a smaller install footprint +- 🌐 **Experimental Story globals** to standardize stories for themes, viewports, and locales +- 💯 **Hundreds** more improvements -- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! -- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! - -## 8.2.8 +
+List of all updates +- Addon Test: Improve messages and post install script handling - [#29036](https://github.com/storybookjs/storybook/pull/29036), thanks @yannbf! +- Addon Viewport: Add default options via parameters - [#28944](https://github.com/storybookjs/storybook/pull/28944), thanks @ndelangen! +- Addon Test: Add experimental vitest integration - [#28768](https://github.com/storybookjs/storybook/pull/28768), thanks @kasperpeulen! +- Addon Test: Fix error message logic in set up file - [#28906](https://github.com/storybookjs/storybook/pull/28906), thanks @yannbf! +- Addon Test: Fix indentation of 'vitePluginNext' in generated Vitest config file - [#29011](https://github.com/storybookjs/storybook/pull/29011), thanks @ghengeveld! +- Addon Test: Fix postinstall file types - [#28978](https://github.com/storybookjs/storybook/pull/28978), thanks @shilman! +- Addon Test: Fix tests potentially not existing in non-isolate mode - [#28993](https://github.com/storybookjs/storybook/pull/28993), thanks @yannbf! +- Addon Test: Improve transformation logic to avoid duplicate tests - [#28929](https://github.com/storybookjs/storybook/pull/28929), thanks @yannbf! +- Addon Test: Set default viewport if applicable - [#28905](https://github.com/storybookjs/storybook/pull/28905), thanks @yannbf! +- Addon Test: Set screenshotFailures to false by default - [#28908](https://github.com/storybookjs/storybook/pull/28908), thanks @yannbf! +- Addon Docs: Remove babel dependency - [#28915](https://github.com/storybookjs/storybook/pull/28915), thanks @shilman! +- Addon Interactions: Fix status in panel tab - [#28580](https://github.com/storybookjs/storybook/pull/28580), thanks @yannbf! +- Angular: Fix Angular template error for props with a circular reference - [#28498](https://github.com/storybookjs/storybook/pull/28498), thanks @Marklb! +- Angular: Fix template props not able to use dot notation - [#28588](https://github.com/storybookjs/storybook/pull/28588), thanks @Marklb! +- Backgrounds/Viewports: Make defaults overridable in `StoryGlobals`-mode - [#29025](https://github.com/storybookjs/storybook/pull/29025), thanks @JReinhold! +- Blocks: Fix scroll to non-ascii anchors - [#28826](https://github.com/storybookjs/storybook/pull/28826), thanks @SkReD! +- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! +- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! +- Build: Remove external overrides, use package.json as source of truth - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! +- Builder-Vite: Add null character prefix to virtual file IDs - [#28863](https://github.com/storybookjs/storybook/pull/28863), thanks @valentinpalkovic! +- Builder-Vite: Fix 'condition node never be used' warning - [#28989](https://github.com/storybookjs/storybook/pull/28989), thanks @valentinpalkovic! +- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! +- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! +- CLI: Add conditional logging for manager and preview start - [#28603](https://github.com/storybookjs/storybook/pull/28603), thanks @tobiasdiez! +- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! +- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! +- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! +- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! +- CLI: Fix dedent import in package managers - [#28980](https://github.com/storybookjs/storybook/pull/28980), thanks @shilman! +- CLI: Fix the initialization of Storybook in workspaces - [#28699](https://github.com/storybookjs/storybook/pull/28699), thanks @valentinpalkovic! +- CLI: Handle Yarn PnP wrapper scenario when adding an addon - [#29027](https://github.com/storybookjs/storybook/pull/29027), thanks @yannbf! +- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! +- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! +- CLI: Make PackageJson optional for starting a dev server - [#28594](https://github.com/storybookjs/storybook/pull/28594), thanks @tobiasdiez! - CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf! -- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! - -## 8.2.7 - -- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! +- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf! +- CLI: Update spawn options in proxy.ts to support Windows - [#28990](https://github.com/storybookjs/storybook/pull/28990), thanks @valentinpalkovic! +- Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! +- ConfigFile: Fix `as const satisfies` modifiers - [#29000](https://github.com/storybookjs/storybook/pull/29000), thanks @shilman! +- Controls: Add disableSave parameter - [#28734](https://github.com/storybookjs/storybook/pull/28734), thanks @valentinpalkovic! +- Core: Add Rsbuild frameworks to known frameworks - [#28694](https://github.com/storybookjs/storybook/pull/28694), thanks @fi3ework! +- Core: De-duplicate babel use in core - [#28972](https://github.com/storybookjs/storybook/pull/28972), thanks @ndelangen! +- Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! +- Core: Fix manager-builder `tsconfig` to emit `react-jsx` - [#28541](https://github.com/storybookjs/storybook/pull/28541), thanks @williamhelmrath! - Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen! - -## 8.2.6 - -- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! - -## 8.2.5 - +- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen! +- Core: Introduce setProjectAnnotations API to more renderers and frameworks - [#28907](https://github.com/storybookjs/storybook/pull/28907), thanks @yannbf! +- Core: Make sure CJS build always has lowest prio - [#28829](https://github.com/storybookjs/storybook/pull/28829), thanks @kasperpeulen! +- Core: Move `util` to regular dependency - [#29008](https://github.com/storybookjs/storybook/pull/29008), thanks @ndelangen! +- Core: Split Storybook CLI - [#28519](https://github.com/storybookjs/storybook/pull/28519), thanks @kasperpeulen! +- Core: Upgrade docs-mdx for smaller install - [#28552](https://github.com/storybookjs/storybook/pull/28552), thanks @shilman! +- CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen! +- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! +- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! +- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen! - CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen! - CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel! -- Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! -- Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! -- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! -- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! -- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! - -## 8.2.4 - -- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! -- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! +- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel! +- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen! - CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen! - -## 8.2.3 - -- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! -- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! -- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! - CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen! +- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen! +- CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen! +- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! +- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! +- CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen! +- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! +- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! - CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen! +- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen! +- CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen! +- CSF: Allow overridding globals at the story level - [#26654](https://github.com/storybookjs/storybook/pull/26654), thanks @tmeasday! +- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic! - CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic! +- Dependencies: Upgrade `commander` - [#28857](https://github.com/storybookjs/storybook/pull/28857), thanks @43081j! +- Fix: Add header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! +- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! +- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! +- Fix: Prevent iframe from capturing mouse events in composed Storybooks - [#28568](https://github.com/storybookjs/storybook/pull/28568), thanks @Vincentdevreede! +- Maintenance: Add `node:`-prefix to node core-modules - [#28860](https://github.com/storybookjs/storybook/pull/28860), thanks @ndelangen! +- Maintenance: Rename addon-vitest to addon-test - [#29014](https://github.com/storybookjs/storybook/pull/29014), thanks @yannbf! +- Next.js-Vite: Fix vite plugin exports - [#29046](https://github.com/storybookjs/storybook/pull/29046), thanks @valentinpalkovic! +- Next.js-Vite: Streamline Next.js dir option - [#28995](https://github.com/storybookjs/storybook/pull/28995), thanks @valentinpalkovic! +- Next.js-Vite: Update next and vite-plugin-storybook-nextjs dependencies - [#28994](https://github.com/storybookjs/storybook/pull/28994), thanks @valentinpalkovic! +- Next.js: Add @storybook/nextjs-vite package - [#28800](https://github.com/storybookjs/storybook/pull/28800), thanks @valentinpalkovic! +- Next.js: Fix wrong Next.js framework reference - [#28992](https://github.com/storybookjs/storybook/pull/28992), thanks @valentinpalkovic! +- Next.js: Make RSC portable-stories compatible - [#28756](https://github.com/storybookjs/storybook/pull/28756), thanks @valentinpalkovic! +- Next.js: Update dependencies - [#29052](https://github.com/storybookjs/storybook/pull/29052), thanks @valentinpalkovic! +- Nextjs-Vite: Re-export vite-plugin-storybook-nextjs - [#29012](https://github.com/storybookjs/storybook/pull/29012), thanks @valentinpalkovic! +- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! +- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! +- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic! +- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen! - Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen! +- React: Avoid 'Dynamic require of react is not possible' issue - [#28730](https://github.com/storybookjs/storybook/pull/28730), thanks @valentinpalkovic! +- React: Bundle in `lodash` - [#28609](https://github.com/storybookjs/storybook/pull/28609), thanks @ndelangen! +- Svelte: Fix events not being logged in Actions when a story has decorators - [#28247](https://github.com/storybookjs/storybook/pull/28247), thanks @JReinhold! +- SvelteKit: Introduce portable stories support - [#28918](https://github.com/storybookjs/storybook/pull/28918), thanks @yannbf! +- SvelteKit/Vue3: Refactor plugin export paths - [#29016](https://github.com/storybookjs/storybook/pull/29016), thanks @yannbf! +- Telemetry: Add globals stats - [#28822](https://github.com/storybookjs/storybook/pull/28822), thanks @shilman! +- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! +- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! +- Telemetry: Add portable stories - [#26764](https://github.com/storybookjs/storybook/pull/26764), thanks @shilman! +- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! +- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! +- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! +- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! +- Test: Fix support for TS < 4.7 - [#28887](https://github.com/storybookjs/storybook/pull/28887), thanks @ndelangen! +- Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf! +- Test: Upgrade Vitest to v2 - [#28788](https://github.com/storybookjs/storybook/pull/28788), thanks @yannbf! +- Types: Adjust beforeAll to be non-nullable in NormalizedProjectAnnotations - [#28671](https://github.com/storybookjs/storybook/pull/28671), thanks @kasperpeulen! +- Types: Update type signatures of objects and functions - [#28503](https://github.com/storybookjs/storybook/pull/28503), thanks @valentinpalkovic! +- UI: Fix collapse/expand all functionality - [#28582](https://github.com/storybookjs/storybook/pull/28582), thanks @filipemelo2002! +- UI: Fix conditional hooks usage in sidebar - [#28979](https://github.com/storybookjs/storybook/pull/28979), thanks @JReinhold! +- UI: Fix sidebar not wrapping - [#29055](https://github.com/storybookjs/storybook/pull/29055), thanks @JReinhold! +- Vite: Fix HMR - [#28876](https://github.com/storybookjs/storybook/pull/28876), thanks @ndelangen! +- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic! +- Vitest: Fix add command - [#28975](https://github.com/storybookjs/storybook/pull/28975), thanks @ghengeveld! +- Vitest: Fix default viewport - [#28943](https://github.com/storybookjs/storybook/pull/28943), thanks @kasperpeulen! +- Vitest: Implement add command for vitest addon - [#28920](https://github.com/storybookjs/storybook/pull/28920), thanks @kasperpeulen! +- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert! +- Vue: Fix out of memory error when using vue-component-meta - [#28589](https://github.com/storybookjs/storybook/pull/28589), thanks @larsrickert! +- Vue: Fix out of memory error when using vue-component-meta for events and slots - [#28674](https://github.com/storybookjs/storybook/pull/28674), thanks @larsrickert! +- Vue: Improve generated code snippets - [#27194](https://github.com/storybookjs/storybook/pull/27194), thanks @larsrickert! +- Vue3: Add vite plugin for portable stories - [#29004](https://github.com/storybookjs/storybook/pull/29004), thanks @yannbf! +- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic! - Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic! -## 8.2.2 - -- CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen! -- CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen! -- CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen! - -## 8.2.1 - -- CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen! -- Types: Update type signatures of objects and functions - [#28503](https://github.com/storybookjs/storybook/pull/28503), thanks @valentinpalkovic! +
## 8.2.0 From 65923455f132472e25e0280590644206933d4da9 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 11 Sep 2024 15:09:59 +0200 Subject: [PATCH 063/213] Remove duplicates --- CHANGELOG.md | 48 ------------------------------------------------ 1 file changed, 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c1a3b330c00..129e12568890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,26 +27,14 @@ Fresh out of the oven! Storybook 8.3 brings you: - Angular: Fix template props not able to use dot notation - [#28588](https://github.com/storybookjs/storybook/pull/28588), thanks @Marklb! - Backgrounds/Viewports: Make defaults overridable in `StoryGlobals`-mode - [#29025](https://github.com/storybookjs/storybook/pull/29025), thanks @JReinhold! - Blocks: Fix scroll to non-ascii anchors - [#28826](https://github.com/storybookjs/storybook/pull/28826), thanks @SkReD! -- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! -- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! - Build: Remove external overrides, use package.json as source of truth - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! - Builder-Vite: Add null character prefix to virtual file IDs - [#28863](https://github.com/storybookjs/storybook/pull/28863), thanks @valentinpalkovic! - Builder-Vite: Fix 'condition node never be used' warning - [#28989](https://github.com/storybookjs/storybook/pull/28989), thanks @valentinpalkovic! -- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! -- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! - CLI: Add conditional logging for manager and preview start - [#28603](https://github.com/storybookjs/storybook/pull/28603), thanks @tobiasdiez! -- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! -- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! -- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! -- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! - CLI: Fix dedent import in package managers - [#28980](https://github.com/storybookjs/storybook/pull/28980), thanks @shilman! - CLI: Fix the initialization of Storybook in workspaces - [#28699](https://github.com/storybookjs/storybook/pull/28699), thanks @valentinpalkovic! - CLI: Handle Yarn PnP wrapper scenario when adding an addon - [#29027](https://github.com/storybookjs/storybook/pull/29027), thanks @yannbf! -- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! -- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! - CLI: Make PackageJson optional for starting a dev server - [#28594](https://github.com/storybookjs/storybook/pull/28594), thanks @tobiasdiez! -- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf! -- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf! - CLI: Update spawn options in proxy.ts to support Windows - [#28990](https://github.com/storybookjs/storybook/pull/28990), thanks @valentinpalkovic! - Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! - ConfigFile: Fix `as const satisfies` modifiers - [#29000](https://github.com/storybookjs/storybook/pull/29000), thanks @shilman! @@ -55,40 +43,18 @@ Fresh out of the oven! Storybook 8.3 brings you: - Core: De-duplicate babel use in core - [#28972](https://github.com/storybookjs/storybook/pull/28972), thanks @ndelangen! - Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! - Core: Fix manager-builder `tsconfig` to emit `react-jsx` - [#28541](https://github.com/storybookjs/storybook/pull/28541), thanks @williamhelmrath! -- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen! -- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen! - Core: Introduce setProjectAnnotations API to more renderers and frameworks - [#28907](https://github.com/storybookjs/storybook/pull/28907), thanks @yannbf! - Core: Make sure CJS build always has lowest prio - [#28829](https://github.com/storybookjs/storybook/pull/28829), thanks @kasperpeulen! - Core: Move `util` to regular dependency - [#29008](https://github.com/storybookjs/storybook/pull/29008), thanks @ndelangen! - Core: Split Storybook CLI - [#28519](https://github.com/storybookjs/storybook/pull/28519), thanks @kasperpeulen! - Core: Upgrade docs-mdx for smaller install - [#28552](https://github.com/storybookjs/storybook/pull/28552), thanks @shilman! - CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen! -- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! -- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! -- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen! -- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen! -- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel! -- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel! -- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen! -- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen! -- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen! -- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen! - CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen! -- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! -- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! - CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen! -- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! -- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! -- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen! -- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen! - CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen! - CSF: Allow overridding globals at the story level - [#26654](https://github.com/storybookjs/storybook/pull/26654), thanks @tmeasday! -- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic! -- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic! - Dependencies: Upgrade `commander` - [#28857](https://github.com/storybookjs/storybook/pull/28857), thanks @43081j! - Fix: Add header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! -- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! -- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! - Fix: Prevent iframe from capturing mouse events in composed Storybooks - [#28568](https://github.com/storybookjs/storybook/pull/28568), thanks @Vincentdevreede! - Maintenance: Add `node:`-prefix to node core-modules - [#28860](https://github.com/storybookjs/storybook/pull/28860), thanks @ndelangen! - Maintenance: Rename addon-vitest to addon-test - [#29014](https://github.com/storybookjs/storybook/pull/29014), thanks @yannbf! @@ -100,24 +66,14 @@ Fresh out of the oven! Storybook 8.3 brings you: - Next.js: Make RSC portable-stories compatible - [#28756](https://github.com/storybookjs/storybook/pull/28756), thanks @valentinpalkovic! - Next.js: Update dependencies - [#29052](https://github.com/storybookjs/storybook/pull/29052), thanks @valentinpalkovic! - Nextjs-Vite: Re-export vite-plugin-storybook-nextjs - [#29012](https://github.com/storybookjs/storybook/pull/29012), thanks @valentinpalkovic! -- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! -- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! - Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic! -- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen! -- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen! - React: Avoid 'Dynamic require of react is not possible' issue - [#28730](https://github.com/storybookjs/storybook/pull/28730), thanks @valentinpalkovic! - React: Bundle in `lodash` - [#28609](https://github.com/storybookjs/storybook/pull/28609), thanks @ndelangen! - Svelte: Fix events not being logged in Actions when a story has decorators - [#28247](https://github.com/storybookjs/storybook/pull/28247), thanks @JReinhold! - SvelteKit: Introduce portable stories support - [#28918](https://github.com/storybookjs/storybook/pull/28918), thanks @yannbf! - SvelteKit/Vue3: Refactor plugin export paths - [#29016](https://github.com/storybookjs/storybook/pull/29016), thanks @yannbf! - Telemetry: Add globals stats - [#28822](https://github.com/storybookjs/storybook/pull/28822), thanks @shilman! -- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! -- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! - Telemetry: Add portable stories - [#26764](https://github.com/storybookjs/storybook/pull/26764), thanks @shilman! -- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! -- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! -- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! -- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! - Test: Fix support for TS < 4.7 - [#28887](https://github.com/storybookjs/storybook/pull/28887), thanks @ndelangen! - Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf! - Test: Upgrade Vitest to v2 - [#28788](https://github.com/storybookjs/storybook/pull/28788), thanks @yannbf! @@ -132,12 +88,8 @@ Fresh out of the oven! Storybook 8.3 brings you: - Vitest: Fix default viewport - [#28943](https://github.com/storybookjs/storybook/pull/28943), thanks @kasperpeulen! - Vitest: Implement add command for vitest addon - [#28920](https://github.com/storybookjs/storybook/pull/28920), thanks @kasperpeulen! - Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert! -- Vue: Fix out of memory error when using vue-component-meta - [#28589](https://github.com/storybookjs/storybook/pull/28589), thanks @larsrickert! -- Vue: Fix out of memory error when using vue-component-meta for events and slots - [#28674](https://github.com/storybookjs/storybook/pull/28674), thanks @larsrickert! - Vue: Improve generated code snippets - [#27194](https://github.com/storybookjs/storybook/pull/27194), thanks @larsrickert! - Vue3: Add vite plugin for portable stories - [#29004](https://github.com/storybookjs/storybook/pull/29004), thanks @yannbf! -- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic! -- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic!
From bb74606bc79270cfbba2198f4b40c1be0c5b80a4 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 11 Sep 2024 15:10:32 +0200 Subject: [PATCH 064/213] Add back patches --- CHANGELOG.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129e12568890..e0b00c7b7217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,63 @@ Fresh out of the oven! Storybook 8.3 brings you:
+## 8.2.9 + +- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen! +- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman! + +## 8.2.8 + +- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf! +- Fix: Invariant failed: Expected package.json#version to be defined in the "undefined" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku! + +## 8.2.7 + +- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen! +- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen! + +## 8.2.6 + +- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen! + +## 8.2.5 + +- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen! +- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel! +- Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen! +- Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim! +- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld! +- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman! +- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman! + +## 8.2.4 + +- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen! +- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf! +- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen! + +## 8.2.3 + +- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach! +- CLI: Add "missing-storybook-dependencies" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf! +- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen! +- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen! +- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen! +- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic! +- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen! +- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic! + +## 8.2.2 + +- CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen! +- CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen! +- CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen! + +## 8.2.1 + +- CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen! +- Types: Update type signatures of objects and functions - [#28503](https://github.com/storybookjs/storybook/pull/28503), thanks @valentinpalkovic! + ## 8.2.0 Hold onto your hats! Storybook 8.2 has dropped, packed with a treasure trove of new features and bug fixes: From 7e94ba615fc2c1863ca9130d8ed34ccd476b03c9 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:20:25 +0000 Subject: [PATCH 065/213] Bump version from "8.3.0-beta.5" to "8.3.0" [skip ci] --- code/addons/a11y/package.json | 2 +- code/addons/actions/package.json | 2 +- code/addons/backgrounds/package.json | 2 +- code/addons/controls/package.json | 2 +- code/addons/docs/package.json | 2 +- code/addons/essentials/package.json | 2 +- code/addons/gfm/package.json | 2 +- code/addons/highlight/package.json | 2 +- code/addons/interactions/package.json | 2 +- code/addons/jest/package.json | 2 +- code/addons/links/package.json | 2 +- code/addons/measure/package.json | 2 +- code/addons/onboarding/package.json | 2 +- code/addons/outline/package.json | 2 +- code/addons/storysource/package.json | 2 +- code/addons/test/package.json | 2 +- code/addons/themes/package.json | 2 +- code/addons/toolbars/package.json | 2 +- code/addons/viewport/package.json | 2 +- code/builders/builder-vite/package.json | 2 +- code/builders/builder-webpack5/package.json | 2 +- code/core/package.json | 2 +- code/core/src/common/versions.ts | 168 +++++++++--------- code/core/src/manager-api/version.ts | 2 +- code/deprecated/builder-manager/package.json | 2 +- code/deprecated/channels/package.json | 2 +- code/deprecated/client-logger/package.json | 2 +- code/deprecated/components/package.json | 2 +- code/deprecated/core-common/package.json | 2 +- code/deprecated/core-events/package.json | 2 +- code/deprecated/core-server/package.json | 2 +- code/deprecated/csf-tools/package.json | 2 +- code/deprecated/docs-tools/package.json | 2 +- code/deprecated/manager-api/package.json | 2 +- code/deprecated/manager/package.json | 2 +- code/deprecated/node-logger/package.json | 2 +- code/deprecated/preview-api/package.json | 2 +- code/deprecated/preview/package.json | 2 +- code/deprecated/router/package.json | 2 +- code/deprecated/telemetry/package.json | 2 +- code/deprecated/theming/package.json | 2 +- code/deprecated/types/package.json | 2 +- code/frameworks/angular/package.json | 2 +- code/frameworks/ember/package.json | 2 +- .../experimental-nextjs-vite/package.json | 2 +- code/frameworks/html-vite/package.json | 2 +- code/frameworks/html-webpack5/package.json | 2 +- code/frameworks/nextjs/package.json | 2 +- code/frameworks/preact-vite/package.json | 2 +- code/frameworks/preact-webpack5/package.json | 2 +- code/frameworks/react-vite/package.json | 2 +- code/frameworks/react-webpack5/package.json | 2 +- code/frameworks/server-webpack5/package.json | 2 +- code/frameworks/svelte-vite/package.json | 2 +- code/frameworks/svelte-webpack5/package.json | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/frameworks/vue3-vite/package.json | 2 +- code/frameworks/vue3-webpack5/package.json | 2 +- .../web-components-vite/package.json | 2 +- .../web-components-webpack5/package.json | 2 +- code/lib/blocks/package.json | 2 +- code/lib/cli-sb/package.json | 2 +- code/lib/cli-storybook/package.json | 2 +- code/lib/cli/package.json | 2 +- code/lib/codemod/package.json | 2 +- code/lib/core-webpack/package.json | 2 +- code/lib/create-storybook/package.json | 2 +- code/lib/csf-plugin/package.json | 2 +- code/lib/instrumenter/package.json | 2 +- code/lib/react-dom-shim/package.json | 2 +- code/lib/source-loader/package.json | 2 +- code/lib/test/package.json | 2 +- code/package.json | 5 +- code/presets/create-react-app/package.json | 2 +- code/presets/html-webpack/package.json | 2 +- code/presets/preact-webpack/package.json | 2 +- code/presets/react-webpack/package.json | 2 +- code/presets/server-webpack/package.json | 2 +- code/presets/svelte-webpack/package.json | 2 +- code/presets/vue3-webpack/package.json | 2 +- code/renderers/html/package.json | 2 +- code/renderers/preact/package.json | 2 +- code/renderers/react/package.json | 2 +- code/renderers/server/package.json | 2 +- code/renderers/svelte/package.json | 2 +- code/renderers/vue3/package.json | 2 +- code/renderers/web-components/package.json | 2 +- 87 files changed, 171 insertions(+), 172 deletions(-) diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index bdd3310cef25..9dfc740ce2bb 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index 179db8003635..f5425e0a9bd6 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index bbeacc4bdf68..774dc2a62f7e 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index 838005e155ff..5365104e2b99 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index 10d0f83aac81..6049b919629b 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index 210efeceb7ff..a30cee0476f8 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index 010b02f01462..6a7f16913d9a 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index dfd92f3d6554..18c0cb499d06 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index 53b233dfe1a0..a1d109352726 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index 7bc2e7209fd6..01efa6e44501 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "React storybook addon that show component jest report", "keywords": [ "addon", diff --git a/code/addons/links/package.json b/code/addons/links/package.json index 5d9eb11ae55f..6b1b8b5d3cd5 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json index 477cf4fdaf73..c3f172884333 100644 --- a/code/addons/measure/package.json +++ b/code/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json index 28d38d8e82b0..99ac961d75f3 100644 --- a/code/addons/onboarding/package.json +++ b/code/addons/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-onboarding", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Addon Onboarding - Introduces a new onboarding experience", "keywords": [ "storybook-addons", diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 16817816d17e..6d82a2898eb8 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index de3ce2cf2ad9..cbf4e5d68663 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", diff --git a/code/addons/test/package.json b/code/addons/test/package.json index 4346d6ea9b9c..c26ee6bd5262 100644 --- a/code/addons/test/package.json +++ b/code/addons/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-addon-test", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Integrate Vitest with Storybook", "keywords": [ "storybook-addons", diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json index 916775ac206b..6a676defa365 100644 --- a/code/addons/themes/package.json +++ b/code/addons/themes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-themes", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Switch between multiple themes for you components in Storybook", "keywords": [ "css", diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index 2c48c750d875..db58560ada55 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index 3932f2907666..aaf3f5d03769 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index 94a148570ac0..01f54edc95b4 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "A plugin to run and build Storybooks with Vite", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme", "bugs": { diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index d9d1fcd1a4e9..19454f9a6de5 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/package.json b/code/core/package.json index 0ca89f3ebd54..34ec9ab435dd 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/src/common/versions.ts b/code/core/src/common/versions.ts index 18a0e438366a..283bb6fc6628 100644 --- a/code/core/src/common/versions.ts +++ b/code/core/src/common/versions.ts @@ -1,87 +1,87 @@ // auto generated file, do not edit export default { - '@storybook/addon-a11y': '8.3.0-beta.5', - '@storybook/addon-actions': '8.3.0-beta.5', - '@storybook/addon-backgrounds': '8.3.0-beta.5', - '@storybook/addon-controls': '8.3.0-beta.5', - '@storybook/addon-docs': '8.3.0-beta.5', - '@storybook/addon-essentials': '8.3.0-beta.5', - '@storybook/addon-mdx-gfm': '8.3.0-beta.5', - '@storybook/addon-highlight': '8.3.0-beta.5', - '@storybook/addon-interactions': '8.3.0-beta.5', - '@storybook/addon-jest': '8.3.0-beta.5', - '@storybook/addon-links': '8.3.0-beta.5', - '@storybook/addon-measure': '8.3.0-beta.5', - '@storybook/addon-onboarding': '8.3.0-beta.5', - '@storybook/addon-outline': '8.3.0-beta.5', - '@storybook/addon-storysource': '8.3.0-beta.5', - '@storybook/experimental-addon-test': '8.3.0-beta.5', - '@storybook/addon-themes': '8.3.0-beta.5', - '@storybook/addon-toolbars': '8.3.0-beta.5', - '@storybook/addon-viewport': '8.3.0-beta.5', - '@storybook/builder-vite': '8.3.0-beta.5', - '@storybook/builder-webpack5': '8.3.0-beta.5', - '@storybook/core': '8.3.0-beta.5', - '@storybook/builder-manager': '8.3.0-beta.5', - '@storybook/channels': '8.3.0-beta.5', - '@storybook/client-logger': '8.3.0-beta.5', - '@storybook/components': '8.3.0-beta.5', - '@storybook/core-common': '8.3.0-beta.5', - '@storybook/core-events': '8.3.0-beta.5', - '@storybook/core-server': '8.3.0-beta.5', - '@storybook/csf-tools': '8.3.0-beta.5', - '@storybook/docs-tools': '8.3.0-beta.5', - '@storybook/manager': '8.3.0-beta.5', - '@storybook/manager-api': '8.3.0-beta.5', - '@storybook/node-logger': '8.3.0-beta.5', - '@storybook/preview': '8.3.0-beta.5', - '@storybook/preview-api': '8.3.0-beta.5', - '@storybook/router': '8.3.0-beta.5', - '@storybook/telemetry': '8.3.0-beta.5', - '@storybook/theming': '8.3.0-beta.5', - '@storybook/types': '8.3.0-beta.5', - '@storybook/angular': '8.3.0-beta.5', - '@storybook/ember': '8.3.0-beta.5', - '@storybook/experimental-nextjs-vite': '8.3.0-beta.5', - '@storybook/html-vite': '8.3.0-beta.5', - '@storybook/html-webpack5': '8.3.0-beta.5', - '@storybook/nextjs': '8.3.0-beta.5', - '@storybook/preact-vite': '8.3.0-beta.5', - '@storybook/preact-webpack5': '8.3.0-beta.5', - '@storybook/react-vite': '8.3.0-beta.5', - '@storybook/react-webpack5': '8.3.0-beta.5', - '@storybook/server-webpack5': '8.3.0-beta.5', - '@storybook/svelte-vite': '8.3.0-beta.5', - '@storybook/svelte-webpack5': '8.3.0-beta.5', - '@storybook/sveltekit': '8.3.0-beta.5', - '@storybook/vue3-vite': '8.3.0-beta.5', - '@storybook/vue3-webpack5': '8.3.0-beta.5', - '@storybook/web-components-vite': '8.3.0-beta.5', - '@storybook/web-components-webpack5': '8.3.0-beta.5', - '@storybook/blocks': '8.3.0-beta.5', - storybook: '8.3.0-beta.5', - sb: '8.3.0-beta.5', - '@storybook/cli': '8.3.0-beta.5', - '@storybook/codemod': '8.3.0-beta.5', - '@storybook/core-webpack': '8.3.0-beta.5', - 'create-storybook': '8.3.0-beta.5', - '@storybook/csf-plugin': '8.3.0-beta.5', - '@storybook/instrumenter': '8.3.0-beta.5', - '@storybook/react-dom-shim': '8.3.0-beta.5', - '@storybook/source-loader': '8.3.0-beta.5', - '@storybook/test': '8.3.0-beta.5', - '@storybook/preset-create-react-app': '8.3.0-beta.5', - '@storybook/preset-html-webpack': '8.3.0-beta.5', - '@storybook/preset-preact-webpack': '8.3.0-beta.5', - '@storybook/preset-react-webpack': '8.3.0-beta.5', - '@storybook/preset-server-webpack': '8.3.0-beta.5', - '@storybook/preset-svelte-webpack': '8.3.0-beta.5', - '@storybook/preset-vue3-webpack': '8.3.0-beta.5', - '@storybook/html': '8.3.0-beta.5', - '@storybook/preact': '8.3.0-beta.5', - '@storybook/react': '8.3.0-beta.5', - '@storybook/server': '8.3.0-beta.5', - '@storybook/svelte': '8.3.0-beta.5', - '@storybook/vue3': '8.3.0-beta.5', - '@storybook/web-components': '8.3.0-beta.5', + '@storybook/addon-a11y': '8.3.0', + '@storybook/addon-actions': '8.3.0', + '@storybook/addon-backgrounds': '8.3.0', + '@storybook/addon-controls': '8.3.0', + '@storybook/addon-docs': '8.3.0', + '@storybook/addon-essentials': '8.3.0', + '@storybook/addon-mdx-gfm': '8.3.0', + '@storybook/addon-highlight': '8.3.0', + '@storybook/addon-interactions': '8.3.0', + '@storybook/addon-jest': '8.3.0', + '@storybook/addon-links': '8.3.0', + '@storybook/addon-measure': '8.3.0', + '@storybook/addon-onboarding': '8.3.0', + '@storybook/addon-outline': '8.3.0', + '@storybook/addon-storysource': '8.3.0', + '@storybook/experimental-addon-test': '8.3.0', + '@storybook/addon-themes': '8.3.0', + '@storybook/addon-toolbars': '8.3.0', + '@storybook/addon-viewport': '8.3.0', + '@storybook/builder-vite': '8.3.0', + '@storybook/builder-webpack5': '8.3.0', + '@storybook/core': '8.3.0', + '@storybook/builder-manager': '8.3.0', + '@storybook/channels': '8.3.0', + '@storybook/client-logger': '8.3.0', + '@storybook/components': '8.3.0', + '@storybook/core-common': '8.3.0', + '@storybook/core-events': '8.3.0', + '@storybook/core-server': '8.3.0', + '@storybook/csf-tools': '8.3.0', + '@storybook/docs-tools': '8.3.0', + '@storybook/manager': '8.3.0', + '@storybook/manager-api': '8.3.0', + '@storybook/node-logger': '8.3.0', + '@storybook/preview': '8.3.0', + '@storybook/preview-api': '8.3.0', + '@storybook/router': '8.3.0', + '@storybook/telemetry': '8.3.0', + '@storybook/theming': '8.3.0', + '@storybook/types': '8.3.0', + '@storybook/angular': '8.3.0', + '@storybook/ember': '8.3.0', + '@storybook/experimental-nextjs-vite': '8.3.0', + '@storybook/html-vite': '8.3.0', + '@storybook/html-webpack5': '8.3.0', + '@storybook/nextjs': '8.3.0', + '@storybook/preact-vite': '8.3.0', + '@storybook/preact-webpack5': '8.3.0', + '@storybook/react-vite': '8.3.0', + '@storybook/react-webpack5': '8.3.0', + '@storybook/server-webpack5': '8.3.0', + '@storybook/svelte-vite': '8.3.0', + '@storybook/svelte-webpack5': '8.3.0', + '@storybook/sveltekit': '8.3.0', + '@storybook/vue3-vite': '8.3.0', + '@storybook/vue3-webpack5': '8.3.0', + '@storybook/web-components-vite': '8.3.0', + '@storybook/web-components-webpack5': '8.3.0', + '@storybook/blocks': '8.3.0', + storybook: '8.3.0', + sb: '8.3.0', + '@storybook/cli': '8.3.0', + '@storybook/codemod': '8.3.0', + '@storybook/core-webpack': '8.3.0', + 'create-storybook': '8.3.0', + '@storybook/csf-plugin': '8.3.0', + '@storybook/instrumenter': '8.3.0', + '@storybook/react-dom-shim': '8.3.0', + '@storybook/source-loader': '8.3.0', + '@storybook/test': '8.3.0', + '@storybook/preset-create-react-app': '8.3.0', + '@storybook/preset-html-webpack': '8.3.0', + '@storybook/preset-preact-webpack': '8.3.0', + '@storybook/preset-react-webpack': '8.3.0', + '@storybook/preset-server-webpack': '8.3.0', + '@storybook/preset-svelte-webpack': '8.3.0', + '@storybook/preset-vue3-webpack': '8.3.0', + '@storybook/html': '8.3.0', + '@storybook/preact': '8.3.0', + '@storybook/react': '8.3.0', + '@storybook/server': '8.3.0', + '@storybook/svelte': '8.3.0', + '@storybook/vue3': '8.3.0', + '@storybook/web-components': '8.3.0', }; diff --git a/code/core/src/manager-api/version.ts b/code/core/src/manager-api/version.ts index 78f7ab7e0bd1..e06e9b4aab4e 100644 --- a/code/core/src/manager-api/version.ts +++ b/code/core/src/manager-api/version.ts @@ -1 +1 @@ -export const version = '8.3.0-beta.5'; +export const version = '8.3.0'; diff --git a/code/deprecated/builder-manager/package.json b/code/deprecated/builder-manager/package.json index 19fa9372b410..82c05b8db848 100644 --- a/code/deprecated/builder-manager/package.json +++ b/code/deprecated/builder-manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-manager", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook manager builder", "keywords": [ "storybook" diff --git a/code/deprecated/channels/package.json b/code/deprecated/channels/package.json index ac793731b668..d66bed828560 100644 --- a/code/deprecated/channels/package.json +++ b/code/deprecated/channels/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channels", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/client-logger/package.json b/code/deprecated/client-logger/package.json index ba627661d64b..4292ce01d48b 100644 --- a/code/deprecated/client-logger/package.json +++ b/code/deprecated/client-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-logger", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/components/package.json b/code/deprecated/components/package.json index 409e692bd517..d85c1eab4af0 100644 --- a/code/deprecated/components/package.json +++ b/code/deprecated/components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/components", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/core-common/package.json b/code/deprecated/core-common/package.json index 204adea56eb7..8b554b0d3907 100644 --- a/code/deprecated/core-common/package.json +++ b/code/deprecated/core-common/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-common", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/core-events/package.json b/code/deprecated/core-events/package.json index eafd34bf6be5..e090f6b06f5f 100644 --- a/code/deprecated/core-events/package.json +++ b/code/deprecated/core-events/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-events", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Event names used in storybook core", "keywords": [ "storybook" diff --git a/code/deprecated/core-server/package.json b/code/deprecated/core-server/package.json index 7882b3aabbec..49343475f277 100644 --- a/code/deprecated/core-server/package.json +++ b/code/deprecated/core-server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-server", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/csf-tools/package.json b/code/deprecated/csf-tools/package.json index 4caa8fac5a08..1c66630f46be 100644 --- a/code/deprecated/csf-tools/package.json +++ b/code/deprecated/csf-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-tools", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Parse and manipulate CSF and Storybook config files", "keywords": [ "storybook" diff --git a/code/deprecated/docs-tools/package.json b/code/deprecated/docs-tools/package.json index 928f90cc0804..1ed87e2b0796 100644 --- a/code/deprecated/docs-tools/package.json +++ b/code/deprecated/docs-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/docs-tools", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Shared utility functions for frameworks to implement docs", "keywords": [ "storybook" diff --git a/code/deprecated/manager-api/package.json b/code/deprecated/manager-api/package.json index 038144dd976d..1a0f2b0ec1b7 100644 --- a/code/deprecated/manager-api/package.json +++ b/code/deprecated/manager-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager-api", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook Manager API & Context", "keywords": [ "storybook" diff --git a/code/deprecated/manager/package.json b/code/deprecated/manager/package.json index 3e0c991fb608..453aac036460 100644 --- a/code/deprecated/manager/package.json +++ b/code/deprecated/manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook UI", "keywords": [ "storybook" diff --git a/code/deprecated/node-logger/package.json b/code/deprecated/node-logger/package.json index 8901ed7f14cf..6bb3cb307fa8 100644 --- a/code/deprecated/node-logger/package.json +++ b/code/deprecated/node-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/node-logger", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview-api/package.json b/code/deprecated/preview-api/package.json index b254ebdd8768..7ad68a7b3790 100644 --- a/code/deprecated/preview-api/package.json +++ b/code/deprecated/preview-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview-api", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview/package.json b/code/deprecated/preview/package.json index 7f7a51d27974..ff95cea7f2b0 100644 --- a/code/deprecated/preview/package.json +++ b/code/deprecated/preview/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/router/package.json b/code/deprecated/router/package.json index ffc3f6ccc850..a24a935f798b 100644 --- a/code/deprecated/router/package.json +++ b/code/deprecated/router/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/router", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook Router", "keywords": [ "storybook" diff --git a/code/deprecated/telemetry/package.json b/code/deprecated/telemetry/package.json index c82b46411d3e..293fde0347b1 100644 --- a/code/deprecated/telemetry/package.json +++ b/code/deprecated/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/telemetry", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Telemetry logging for crash reports and usage statistics", "keywords": [ "storybook" diff --git a/code/deprecated/theming/package.json b/code/deprecated/theming/package.json index b7f850ccb2bd..c4c9cc826b25 100644 --- a/code/deprecated/theming/package.json +++ b/code/deprecated/theming/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/theming", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/types/package.json b/code/deprecated/types/package.json index 8bb2554675b5..14bc1083b18d 100644 --- a/code/deprecated/types/package.json +++ b/code/deprecated/types/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/types", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Core Storybook TS Types", "keywords": [ "storybook" diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 1badd71aee97..050f9cc6fe8d 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 7e7c31e4facc..7053b58da0a6 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index 60b2442513ae..e50db381249d 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-nextjs-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Next.js and Vite", "keywords": [ "storybook", diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 84d3bae80ef2..c86282fb62a4 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index f685e702ad3b..3e97efb323fe 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 57fe6ae80cf8..46bb1d5d4059 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/nextjs", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Next.js", "keywords": [ "storybook", diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 63dc9ed4a51f..fd7757db1e73 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index e6a420633dbd..2e69fb2db5be 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index a29a56f5dd79..4b422ccc0dff 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index be86692ae401..e51519feb77e 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index 79fe5e3e1b86..556f9cef257c 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index a767d1f6b6ba..a079474fd828 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index 1425a0e579b9..31fa95cd408e 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index c3800e1dad0c..546b6d37a08d 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/sveltekit", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for SvelteKit", "keywords": [ "storybook", diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 4061d79cda74..93ecb9cd18b9 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 9ea728ca905a..c7f0c78f12ad 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 22de31145d6d..5068bddabfa3 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-vite", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 95429756f449..196656fd8901 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-webpack5", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit", diff --git a/code/lib/blocks/package.json b/code/lib/blocks/package.json index be218625886b..af57aff4dec6 100644 --- a/code/lib/blocks/package.json +++ b/code/lib/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/blocks", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Doc Blocks", "keywords": [ "storybook" diff --git a/code/lib/cli-sb/package.json b/code/lib/cli-sb/package.json index 150628dabc1d..8efc08e58f07 100644 --- a/code/lib/cli-sb/package.json +++ b/code/lib/cli-sb/package.json @@ -1,6 +1,6 @@ { "name": "sb", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index 9e5be67e2b87..0270e1562734 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/cli", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index ec0ce5cbb3fc..b41226e44775 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook's CLI - install, dev, build, upgrade, and more", "keywords": [ "cli", diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index 6ec768d6cc68..fd669252c954 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/codemod", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "A collection of codemod scripts written with JSCodeshift", "keywords": [ "storybook" diff --git a/code/lib/core-webpack/package.json b/code/lib/core-webpack/package.json index 11c1058d64c3..7bfb1ebf3fa3 100644 --- a/code/lib/core-webpack/package.json +++ b/code/lib/core-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/create-storybook/package.json b/code/lib/create-storybook/package.json index 1515c472cf6a..96ba8afea720 100644 --- a/code/lib/create-storybook/package.json +++ b/code/lib/create-storybook/package.json @@ -1,6 +1,6 @@ { "name": "create-storybook", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Initialize Storybook into your project", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook", "bugs": { diff --git a/code/lib/csf-plugin/package.json b/code/lib/csf-plugin/package.json index f79d8ca09086..dba394117ca2 100644 --- a/code/lib/csf-plugin/package.json +++ b/code/lib/csf-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-plugin", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Enrich CSF files via static analysis", "keywords": [ "storybook" diff --git a/code/lib/instrumenter/package.json b/code/lib/instrumenter/package.json index 57ff514b7d09..af2c084dbb0c 100644 --- a/code/lib/instrumenter/package.json +++ b/code/lib/instrumenter/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/instrumenter", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/lib/react-dom-shim/package.json b/code/lib/react-dom-shim/package.json index 80364b6bebf0..5a800b9b8374 100644 --- a/code/lib/react-dom-shim/package.json +++ b/code/lib/react-dom-shim/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-dom-shim", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json index 308fab65ce8a..e8ad91adb8bb 100644 --- a/code/lib/source-loader/package.json +++ b/code/lib/source-loader/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/source-loader", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Source loader", "keywords": [ "lib", diff --git a/code/lib/test/package.json b/code/lib/test/package.json index 0aa37cd6d5ac..485cd8885166 100644 --- a/code/lib/test/package.json +++ b/code/lib/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/test", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "", "keywords": [ "storybook" diff --git a/code/package.json b/code/package.json index a6967711237b..5b65e068b4b2 100644 --- a/code/package.json +++ b/code/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/root", - "version": "8.3.0-beta.5", + "version": "8.3.0", "private": true, "description": "Storybook root", "homepage": "https://storybook.js.org/", @@ -295,6 +295,5 @@ "Dependency Upgrades" ] ] - }, - "deferredNextVersion": "8.3.0" + } } diff --git a/code/presets/create-react-app/package.json b/code/presets/create-react-app/package.json index 12fca76a6bec..462293b26994 100644 --- a/code/presets/create-react-app/package.json +++ b/code/presets/create-react-app/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-create-react-app", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Create React App preset", "keywords": [ "storybook" diff --git a/code/presets/html-webpack/package.json b/code/presets/html-webpack/package.json index 7a65af963106..13fc3f6ff203 100644 --- a/code/presets/html-webpack/package.json +++ b/code/presets/html-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-html-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json index d6db6935db42..1fdd3057ef48 100644 --- a/code/presets/preact-webpack/package.json +++ b/code/presets/preact-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-preact-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index 17476669f734..492e3ca9eebf 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-react-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading", "keywords": [ "storybook" diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json index a4a7d1213947..e53f4e90102b 100644 --- a/code/presets/server-webpack/package.json +++ b/code/presets/server-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-server-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json index b682ead94aee..706f2c1175d8 100644 --- a/code/presets/svelte-webpack/package.json +++ b/code/presets/svelte-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-svelte-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/vue3-webpack/package.json b/code/presets/vue3-webpack/package.json index 828c51524cbe..7c13257f982d 100644 --- a/code/presets/vue3-webpack/package.json +++ b/code/presets/vue3-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-vue3-webpack", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/renderers/html/package.json b/code/renderers/html/package.json index 573f32cae134..0a792ba8758a 100644 --- a/code/renderers/html/package.json +++ b/code/renderers/html/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook HTML renderer", "keywords": [ "storybook" diff --git a/code/renderers/preact/package.json b/code/renderers/preact/package.json index 21013f4ab4c0..3a0945c1e67c 100644 --- a/code/renderers/preact/package.json +++ b/code/renderers/preact/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Preact renderer", "keywords": [ "storybook" diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 36c00f774d0f..762e57f6e74f 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook React renderer", "keywords": [ "storybook" diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json index da88a2a5ef65..3d0e72c88993 100644 --- a/code/renderers/server/package.json +++ b/code/renderers/server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Server renderer", "keywords": [ "storybook" diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index ccb4b142aa8e..d4de65901941 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Svelte renderer", "keywords": [ "storybook" diff --git a/code/renderers/vue3/package.json b/code/renderers/vue3/package.json index 7c227869ca72..4c2cb30c6928 100644 --- a/code/renderers/vue3/package.json +++ b/code/renderers/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook Vue 3 renderer", "keywords": [ "storybook" diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json index 57edb9280a25..87ce191c45ff 100644 --- a/code/renderers/web-components/package.json +++ b/code/renderers/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "8.3.0-beta.5", + "version": "8.3.0", "description": "Storybook web-components renderer", "keywords": [ "lit", From 3389e2b99103e3ff994e0c612034834748d0e3c3 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:53:34 +0000 Subject: [PATCH 066/213] Write changelog for 8.4.0-alpha.0 [skip ci] --- CHANGELOG.prerelease.md | 3 +++ code/package.json | 3 ++- docs/versions/next.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 414ba2162d77..692c7edaf2e9 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,6 @@ +## 8.4.0-alpha.0 + + ## 8.3.0-beta.5 - Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic! diff --git a/code/package.json b/code/package.json index 5b65e068b4b2..b5763dc8eeac 100644 --- a/code/package.json +++ b/code/package.json @@ -295,5 +295,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.4.0-alpha.0" } diff --git a/docs/versions/next.json b/docs/versions/next.json index 33043c2d6fdd..9963ff265181 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.3.0-beta.5","info":{"plain":"- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic!\n- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic!\n- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert!"}} +{"version":"8.4.0-alpha.0","info":{"plain":""}} From 8b16feb67674d6ccfdf3a1c539ca35e56f3e1968 Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:56:33 +0000 Subject: [PATCH 067/213] Bump version from "8.3.0" to "8.4.0-alpha.0" [skip ci] --- code/addons/a11y/package.json | 2 +- code/addons/actions/package.json | 2 +- code/addons/backgrounds/package.json | 2 +- code/addons/controls/package.json | 2 +- code/addons/docs/package.json | 2 +- code/addons/essentials/package.json | 2 +- code/addons/gfm/package.json | 2 +- code/addons/highlight/package.json | 2 +- code/addons/interactions/package.json | 2 +- code/addons/jest/package.json | 2 +- code/addons/links/package.json | 2 +- code/addons/measure/package.json | 2 +- code/addons/onboarding/package.json | 2 +- code/addons/outline/package.json | 2 +- code/addons/storysource/package.json | 2 +- code/addons/test/package.json | 2 +- code/addons/themes/package.json | 2 +- code/addons/toolbars/package.json | 2 +- code/addons/viewport/package.json | 2 +- code/builders/builder-vite/package.json | 2 +- code/builders/builder-webpack5/package.json | 2 +- code/core/package.json | 2 +- code/core/src/common/versions.ts | 168 +++++++++--------- code/core/src/manager-api/version.ts | 2 +- code/deprecated/builder-manager/package.json | 2 +- code/deprecated/channels/package.json | 2 +- code/deprecated/client-logger/package.json | 2 +- code/deprecated/components/package.json | 2 +- code/deprecated/core-common/package.json | 2 +- code/deprecated/core-events/package.json | 2 +- code/deprecated/core-server/package.json | 2 +- code/deprecated/csf-tools/package.json | 2 +- code/deprecated/docs-tools/package.json | 2 +- code/deprecated/manager-api/package.json | 2 +- code/deprecated/manager/package.json | 2 +- code/deprecated/node-logger/package.json | 2 +- code/deprecated/preview-api/package.json | 2 +- code/deprecated/preview/package.json | 2 +- code/deprecated/router/package.json | 2 +- code/deprecated/telemetry/package.json | 2 +- code/deprecated/theming/package.json | 2 +- code/deprecated/types/package.json | 2 +- code/frameworks/angular/package.json | 2 +- code/frameworks/ember/package.json | 2 +- .../experimental-nextjs-vite/package.json | 2 +- code/frameworks/html-vite/package.json | 2 +- code/frameworks/html-webpack5/package.json | 2 +- code/frameworks/nextjs/package.json | 2 +- code/frameworks/preact-vite/package.json | 2 +- code/frameworks/preact-webpack5/package.json | 2 +- code/frameworks/react-vite/package.json | 2 +- code/frameworks/react-webpack5/package.json | 2 +- code/frameworks/server-webpack5/package.json | 2 +- code/frameworks/svelte-vite/package.json | 2 +- code/frameworks/svelte-webpack5/package.json | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/frameworks/vue3-vite/package.json | 2 +- code/frameworks/vue3-webpack5/package.json | 2 +- .../web-components-vite/package.json | 2 +- .../web-components-webpack5/package.json | 2 +- code/lib/blocks/package.json | 2 +- code/lib/cli-sb/package.json | 2 +- code/lib/cli-storybook/package.json | 2 +- code/lib/cli/package.json | 2 +- code/lib/codemod/package.json | 2 +- code/lib/core-webpack/package.json | 2 +- code/lib/create-storybook/package.json | 2 +- code/lib/csf-plugin/package.json | 2 +- code/lib/instrumenter/package.json | 2 +- code/lib/react-dom-shim/package.json | 2 +- code/lib/source-loader/package.json | 2 +- code/lib/test/package.json | 2 +- code/package.json | 5 +- code/presets/create-react-app/package.json | 2 +- code/presets/html-webpack/package.json | 2 +- code/presets/preact-webpack/package.json | 2 +- code/presets/react-webpack/package.json | 2 +- code/presets/server-webpack/package.json | 2 +- code/presets/svelte-webpack/package.json | 2 +- code/presets/vue3-webpack/package.json | 2 +- code/renderers/html/package.json | 2 +- code/renderers/preact/package.json | 2 +- code/renderers/react/package.json | 2 +- code/renderers/server/package.json | 2 +- code/renderers/svelte/package.json | 2 +- code/renderers/vue3/package.json | 2 +- code/renderers/web-components/package.json | 2 +- 87 files changed, 171 insertions(+), 172 deletions(-) diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index 9dfc740ce2bb..82f3c87c1375 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index f5425e0a9bd6..c646b66260db 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index 774dc2a62f7e..51cb0ada1bc4 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index 5365104e2b99..3dabde260726 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index 6049b919629b..d905b004df47 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index a30cee0476f8..6a1611d0a48e 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index 6a7f16913d9a..37a490a15e46 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index 18c0cb499d06..88bab3c462b3 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index a1d109352726..dd30fb2650d4 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index 01efa6e44501..8fb9fc0b47d7 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "React storybook addon that show component jest report", "keywords": [ "addon", diff --git a/code/addons/links/package.json b/code/addons/links/package.json index 6b1b8b5d3cd5..c11fa3e056b3 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json index c3f172884333..b09da705f4e1 100644 --- a/code/addons/measure/package.json +++ b/code/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json index 99ac961d75f3..c33ab5d84d22 100644 --- a/code/addons/onboarding/package.json +++ b/code/addons/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-onboarding", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Addon Onboarding - Introduces a new onboarding experience", "keywords": [ "storybook-addons", diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 6d82a2898eb8..918c00c7945f 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index cbf4e5d68663..e79924cda4db 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", diff --git a/code/addons/test/package.json b/code/addons/test/package.json index c26ee6bd5262..09f9235271f4 100644 --- a/code/addons/test/package.json +++ b/code/addons/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-addon-test", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Integrate Vitest with Storybook", "keywords": [ "storybook-addons", diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json index 6a676defa365..87c826276318 100644 --- a/code/addons/themes/package.json +++ b/code/addons/themes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-themes", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Switch between multiple themes for you components in Storybook", "keywords": [ "css", diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index db58560ada55..87d838129b7b 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index aaf3f5d03769..d1c6c85fe942 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index 01f54edc95b4..5c8bd9b47ea1 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "A plugin to run and build Storybooks with Vite", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme", "bugs": { diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index 19454f9a6de5..913991d99689 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/package.json b/code/core/package.json index 34ec9ab435dd..181b04312985 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/core/src/common/versions.ts b/code/core/src/common/versions.ts index 283bb6fc6628..11ac53790fcd 100644 --- a/code/core/src/common/versions.ts +++ b/code/core/src/common/versions.ts @@ -1,87 +1,87 @@ // auto generated file, do not edit export default { - '@storybook/addon-a11y': '8.3.0', - '@storybook/addon-actions': '8.3.0', - '@storybook/addon-backgrounds': '8.3.0', - '@storybook/addon-controls': '8.3.0', - '@storybook/addon-docs': '8.3.0', - '@storybook/addon-essentials': '8.3.0', - '@storybook/addon-mdx-gfm': '8.3.0', - '@storybook/addon-highlight': '8.3.0', - '@storybook/addon-interactions': '8.3.0', - '@storybook/addon-jest': '8.3.0', - '@storybook/addon-links': '8.3.0', - '@storybook/addon-measure': '8.3.0', - '@storybook/addon-onboarding': '8.3.0', - '@storybook/addon-outline': '8.3.0', - '@storybook/addon-storysource': '8.3.0', - '@storybook/experimental-addon-test': '8.3.0', - '@storybook/addon-themes': '8.3.0', - '@storybook/addon-toolbars': '8.3.0', - '@storybook/addon-viewport': '8.3.0', - '@storybook/builder-vite': '8.3.0', - '@storybook/builder-webpack5': '8.3.0', - '@storybook/core': '8.3.0', - '@storybook/builder-manager': '8.3.0', - '@storybook/channels': '8.3.0', - '@storybook/client-logger': '8.3.0', - '@storybook/components': '8.3.0', - '@storybook/core-common': '8.3.0', - '@storybook/core-events': '8.3.0', - '@storybook/core-server': '8.3.0', - '@storybook/csf-tools': '8.3.0', - '@storybook/docs-tools': '8.3.0', - '@storybook/manager': '8.3.0', - '@storybook/manager-api': '8.3.0', - '@storybook/node-logger': '8.3.0', - '@storybook/preview': '8.3.0', - '@storybook/preview-api': '8.3.0', - '@storybook/router': '8.3.0', - '@storybook/telemetry': '8.3.0', - '@storybook/theming': '8.3.0', - '@storybook/types': '8.3.0', - '@storybook/angular': '8.3.0', - '@storybook/ember': '8.3.0', - '@storybook/experimental-nextjs-vite': '8.3.0', - '@storybook/html-vite': '8.3.0', - '@storybook/html-webpack5': '8.3.0', - '@storybook/nextjs': '8.3.0', - '@storybook/preact-vite': '8.3.0', - '@storybook/preact-webpack5': '8.3.0', - '@storybook/react-vite': '8.3.0', - '@storybook/react-webpack5': '8.3.0', - '@storybook/server-webpack5': '8.3.0', - '@storybook/svelte-vite': '8.3.0', - '@storybook/svelte-webpack5': '8.3.0', - '@storybook/sveltekit': '8.3.0', - '@storybook/vue3-vite': '8.3.0', - '@storybook/vue3-webpack5': '8.3.0', - '@storybook/web-components-vite': '8.3.0', - '@storybook/web-components-webpack5': '8.3.0', - '@storybook/blocks': '8.3.0', - storybook: '8.3.0', - sb: '8.3.0', - '@storybook/cli': '8.3.0', - '@storybook/codemod': '8.3.0', - '@storybook/core-webpack': '8.3.0', - 'create-storybook': '8.3.0', - '@storybook/csf-plugin': '8.3.0', - '@storybook/instrumenter': '8.3.0', - '@storybook/react-dom-shim': '8.3.0', - '@storybook/source-loader': '8.3.0', - '@storybook/test': '8.3.0', - '@storybook/preset-create-react-app': '8.3.0', - '@storybook/preset-html-webpack': '8.3.0', - '@storybook/preset-preact-webpack': '8.3.0', - '@storybook/preset-react-webpack': '8.3.0', - '@storybook/preset-server-webpack': '8.3.0', - '@storybook/preset-svelte-webpack': '8.3.0', - '@storybook/preset-vue3-webpack': '8.3.0', - '@storybook/html': '8.3.0', - '@storybook/preact': '8.3.0', - '@storybook/react': '8.3.0', - '@storybook/server': '8.3.0', - '@storybook/svelte': '8.3.0', - '@storybook/vue3': '8.3.0', - '@storybook/web-components': '8.3.0', + '@storybook/addon-a11y': '8.4.0-alpha.0', + '@storybook/addon-actions': '8.4.0-alpha.0', + '@storybook/addon-backgrounds': '8.4.0-alpha.0', + '@storybook/addon-controls': '8.4.0-alpha.0', + '@storybook/addon-docs': '8.4.0-alpha.0', + '@storybook/addon-essentials': '8.4.0-alpha.0', + '@storybook/addon-mdx-gfm': '8.4.0-alpha.0', + '@storybook/addon-highlight': '8.4.0-alpha.0', + '@storybook/addon-interactions': '8.4.0-alpha.0', + '@storybook/addon-jest': '8.4.0-alpha.0', + '@storybook/addon-links': '8.4.0-alpha.0', + '@storybook/addon-measure': '8.4.0-alpha.0', + '@storybook/addon-onboarding': '8.4.0-alpha.0', + '@storybook/addon-outline': '8.4.0-alpha.0', + '@storybook/addon-storysource': '8.4.0-alpha.0', + '@storybook/experimental-addon-test': '8.4.0-alpha.0', + '@storybook/addon-themes': '8.4.0-alpha.0', + '@storybook/addon-toolbars': '8.4.0-alpha.0', + '@storybook/addon-viewport': '8.4.0-alpha.0', + '@storybook/builder-vite': '8.4.0-alpha.0', + '@storybook/builder-webpack5': '8.4.0-alpha.0', + '@storybook/core': '8.4.0-alpha.0', + '@storybook/builder-manager': '8.4.0-alpha.0', + '@storybook/channels': '8.4.0-alpha.0', + '@storybook/client-logger': '8.4.0-alpha.0', + '@storybook/components': '8.4.0-alpha.0', + '@storybook/core-common': '8.4.0-alpha.0', + '@storybook/core-events': '8.4.0-alpha.0', + '@storybook/core-server': '8.4.0-alpha.0', + '@storybook/csf-tools': '8.4.0-alpha.0', + '@storybook/docs-tools': '8.4.0-alpha.0', + '@storybook/manager': '8.4.0-alpha.0', + '@storybook/manager-api': '8.4.0-alpha.0', + '@storybook/node-logger': '8.4.0-alpha.0', + '@storybook/preview': '8.4.0-alpha.0', + '@storybook/preview-api': '8.4.0-alpha.0', + '@storybook/router': '8.4.0-alpha.0', + '@storybook/telemetry': '8.4.0-alpha.0', + '@storybook/theming': '8.4.0-alpha.0', + '@storybook/types': '8.4.0-alpha.0', + '@storybook/angular': '8.4.0-alpha.0', + '@storybook/ember': '8.4.0-alpha.0', + '@storybook/experimental-nextjs-vite': '8.4.0-alpha.0', + '@storybook/html-vite': '8.4.0-alpha.0', + '@storybook/html-webpack5': '8.4.0-alpha.0', + '@storybook/nextjs': '8.4.0-alpha.0', + '@storybook/preact-vite': '8.4.0-alpha.0', + '@storybook/preact-webpack5': '8.4.0-alpha.0', + '@storybook/react-vite': '8.4.0-alpha.0', + '@storybook/react-webpack5': '8.4.0-alpha.0', + '@storybook/server-webpack5': '8.4.0-alpha.0', + '@storybook/svelte-vite': '8.4.0-alpha.0', + '@storybook/svelte-webpack5': '8.4.0-alpha.0', + '@storybook/sveltekit': '8.4.0-alpha.0', + '@storybook/vue3-vite': '8.4.0-alpha.0', + '@storybook/vue3-webpack5': '8.4.0-alpha.0', + '@storybook/web-components-vite': '8.4.0-alpha.0', + '@storybook/web-components-webpack5': '8.4.0-alpha.0', + '@storybook/blocks': '8.4.0-alpha.0', + storybook: '8.4.0-alpha.0', + sb: '8.4.0-alpha.0', + '@storybook/cli': '8.4.0-alpha.0', + '@storybook/codemod': '8.4.0-alpha.0', + '@storybook/core-webpack': '8.4.0-alpha.0', + 'create-storybook': '8.4.0-alpha.0', + '@storybook/csf-plugin': '8.4.0-alpha.0', + '@storybook/instrumenter': '8.4.0-alpha.0', + '@storybook/react-dom-shim': '8.4.0-alpha.0', + '@storybook/source-loader': '8.4.0-alpha.0', + '@storybook/test': '8.4.0-alpha.0', + '@storybook/preset-create-react-app': '8.4.0-alpha.0', + '@storybook/preset-html-webpack': '8.4.0-alpha.0', + '@storybook/preset-preact-webpack': '8.4.0-alpha.0', + '@storybook/preset-react-webpack': '8.4.0-alpha.0', + '@storybook/preset-server-webpack': '8.4.0-alpha.0', + '@storybook/preset-svelte-webpack': '8.4.0-alpha.0', + '@storybook/preset-vue3-webpack': '8.4.0-alpha.0', + '@storybook/html': '8.4.0-alpha.0', + '@storybook/preact': '8.4.0-alpha.0', + '@storybook/react': '8.4.0-alpha.0', + '@storybook/server': '8.4.0-alpha.0', + '@storybook/svelte': '8.4.0-alpha.0', + '@storybook/vue3': '8.4.0-alpha.0', + '@storybook/web-components': '8.4.0-alpha.0', }; diff --git a/code/core/src/manager-api/version.ts b/code/core/src/manager-api/version.ts index e06e9b4aab4e..83c9913763e5 100644 --- a/code/core/src/manager-api/version.ts +++ b/code/core/src/manager-api/version.ts @@ -1 +1 @@ -export const version = '8.3.0'; +export const version = '8.4.0-alpha.0'; diff --git a/code/deprecated/builder-manager/package.json b/code/deprecated/builder-manager/package.json index 82c05b8db848..cd56ab5e48b0 100644 --- a/code/deprecated/builder-manager/package.json +++ b/code/deprecated/builder-manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-manager", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook manager builder", "keywords": [ "storybook" diff --git a/code/deprecated/channels/package.json b/code/deprecated/channels/package.json index d66bed828560..0c5d9207f286 100644 --- a/code/deprecated/channels/package.json +++ b/code/deprecated/channels/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channels", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/client-logger/package.json b/code/deprecated/client-logger/package.json index 4292ce01d48b..e925983b6e29 100644 --- a/code/deprecated/client-logger/package.json +++ b/code/deprecated/client-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-logger", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/components/package.json b/code/deprecated/components/package.json index d85c1eab4af0..f05ba78d1004 100644 --- a/code/deprecated/components/package.json +++ b/code/deprecated/components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/components", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/core-common/package.json b/code/deprecated/core-common/package.json index 8b554b0d3907..6f5d1305fac6 100644 --- a/code/deprecated/core-common/package.json +++ b/code/deprecated/core-common/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-common", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/core-events/package.json b/code/deprecated/core-events/package.json index e090f6b06f5f..b7f3d3b567a5 100644 --- a/code/deprecated/core-events/package.json +++ b/code/deprecated/core-events/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-events", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Event names used in storybook core", "keywords": [ "storybook" diff --git a/code/deprecated/core-server/package.json b/code/deprecated/core-server/package.json index 49343475f277..057ed66ca4a6 100644 --- a/code/deprecated/core-server/package.json +++ b/code/deprecated/core-server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-server", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/deprecated/csf-tools/package.json b/code/deprecated/csf-tools/package.json index 1c66630f46be..95a5ea0c608d 100644 --- a/code/deprecated/csf-tools/package.json +++ b/code/deprecated/csf-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-tools", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Parse and manipulate CSF and Storybook config files", "keywords": [ "storybook" diff --git a/code/deprecated/docs-tools/package.json b/code/deprecated/docs-tools/package.json index 1ed87e2b0796..c591880ff39b 100644 --- a/code/deprecated/docs-tools/package.json +++ b/code/deprecated/docs-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/docs-tools", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Shared utility functions for frameworks to implement docs", "keywords": [ "storybook" diff --git a/code/deprecated/manager-api/package.json b/code/deprecated/manager-api/package.json index 1a0f2b0ec1b7..f2a9d61f34fc 100644 --- a/code/deprecated/manager-api/package.json +++ b/code/deprecated/manager-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager-api", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook Manager API & Context", "keywords": [ "storybook" diff --git a/code/deprecated/manager/package.json b/code/deprecated/manager/package.json index 453aac036460..b1d991cdbb19 100644 --- a/code/deprecated/manager/package.json +++ b/code/deprecated/manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook UI", "keywords": [ "storybook" diff --git a/code/deprecated/node-logger/package.json b/code/deprecated/node-logger/package.json index 6bb3cb307fa8..2b5121aa0fc9 100644 --- a/code/deprecated/node-logger/package.json +++ b/code/deprecated/node-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/node-logger", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview-api/package.json b/code/deprecated/preview-api/package.json index 7ad68a7b3790..736cd04c8338 100644 --- a/code/deprecated/preview-api/package.json +++ b/code/deprecated/preview-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview-api", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/preview/package.json b/code/deprecated/preview/package.json index ff95cea7f2b0..e55184702d1b 100644 --- a/code/deprecated/preview/package.json +++ b/code/deprecated/preview/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/deprecated/router/package.json b/code/deprecated/router/package.json index a24a935f798b..66d026f73f2e 100644 --- a/code/deprecated/router/package.json +++ b/code/deprecated/router/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/router", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook Router", "keywords": [ "storybook" diff --git a/code/deprecated/telemetry/package.json b/code/deprecated/telemetry/package.json index 293fde0347b1..faffe3105862 100644 --- a/code/deprecated/telemetry/package.json +++ b/code/deprecated/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/telemetry", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Telemetry logging for crash reports and usage statistics", "keywords": [ "storybook" diff --git a/code/deprecated/theming/package.json b/code/deprecated/theming/package.json index c4c9cc826b25..90bd9362026f 100644 --- a/code/deprecated/theming/package.json +++ b/code/deprecated/theming/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/theming", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/deprecated/types/package.json b/code/deprecated/types/package.json index 14bc1083b18d..1adbdeea218f 100644 --- a/code/deprecated/types/package.json +++ b/code/deprecated/types/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/types", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Core Storybook TS Types", "keywords": [ "storybook" diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 050f9cc6fe8d..0dd1fa78ba0b 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 7053b58da0a6..d2c853d602b1 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index e50db381249d..a3b13a8430af 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/experimental-nextjs-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Next.js and Vite", "keywords": [ "storybook", diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index c86282fb62a4..fdf1b4aaca73 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index 3e97efb323fe..eb68bb0405bf 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 46bb1d5d4059..856982c811dd 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/nextjs", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Next.js", "keywords": [ "storybook", diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index fd7757db1e73..160fcae2c060 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index 2e69fb2db5be..95ecb773d3d8 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 4b422ccc0dff..ba7b57702d3f 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index e51519feb77e..1117894ced7e 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index 556f9cef257c..4ee3f6eca929 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index a079474fd828..7ee073acf0bf 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index 31fa95cd408e..4a6a2a541cb0 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index 546b6d37a08d..54e060c0191e 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/sveltekit", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for SvelteKit", "keywords": [ "storybook", diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 93ecb9cd18b9..92d6ab4d41fa 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index c7f0c78f12ad..554f5d92370d 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 5068bddabfa3..2f617925837b 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-vite", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 196656fd8901..b6ff71516042 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-webpack5", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit", diff --git a/code/lib/blocks/package.json b/code/lib/blocks/package.json index af57aff4dec6..ca92f5fffac7 100644 --- a/code/lib/blocks/package.json +++ b/code/lib/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/blocks", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Doc Blocks", "keywords": [ "storybook" diff --git a/code/lib/cli-sb/package.json b/code/lib/cli-sb/package.json index 8efc08e58f07..25a66aa344ed 100644 --- a/code/lib/cli-sb/package.json +++ b/code/lib/cli-sb/package.json @@ -1,6 +1,6 @@ { "name": "sb", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index 0270e1562734..5e13a89d5b30 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/cli", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index b41226e44775..8dead94de633 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook's CLI - install, dev, build, upgrade, and more", "keywords": [ "cli", diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index fd669252c954..28445891eb3c 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/codemod", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "A collection of codemod scripts written with JSCodeshift", "keywords": [ "storybook" diff --git a/code/lib/core-webpack/package.json b/code/lib/core-webpack/package.json index 7bfb1ebf3fa3..ca73db9d84de 100644 --- a/code/lib/core-webpack/package.json +++ b/code/lib/core-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/create-storybook/package.json b/code/lib/create-storybook/package.json index 96ba8afea720..2a08fc5deed2 100644 --- a/code/lib/create-storybook/package.json +++ b/code/lib/create-storybook/package.json @@ -1,6 +1,6 @@ { "name": "create-storybook", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Initialize Storybook into your project", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook", "bugs": { diff --git a/code/lib/csf-plugin/package.json b/code/lib/csf-plugin/package.json index dba394117ca2..709c14d03eda 100644 --- a/code/lib/csf-plugin/package.json +++ b/code/lib/csf-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-plugin", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Enrich CSF files via static analysis", "keywords": [ "storybook" diff --git a/code/lib/instrumenter/package.json b/code/lib/instrumenter/package.json index af2c084dbb0c..0393a36e1f8e 100644 --- a/code/lib/instrumenter/package.json +++ b/code/lib/instrumenter/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/instrumenter", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/lib/react-dom-shim/package.json b/code/lib/react-dom-shim/package.json index 5a800b9b8374..f9c6fdf7d3b5 100644 --- a/code/lib/react-dom-shim/package.json +++ b/code/lib/react-dom-shim/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-dom-shim", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json index e8ad91adb8bb..7372daad6416 100644 --- a/code/lib/source-loader/package.json +++ b/code/lib/source-loader/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/source-loader", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Source loader", "keywords": [ "lib", diff --git a/code/lib/test/package.json b/code/lib/test/package.json index 485cd8885166..f103259c54c5 100644 --- a/code/lib/test/package.json +++ b/code/lib/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/test", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "", "keywords": [ "storybook" diff --git a/code/package.json b/code/package.json index b5763dc8eeac..e348ef665900 100644 --- a/code/package.json +++ b/code/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/root", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "private": true, "description": "Storybook root", "homepage": "https://storybook.js.org/", @@ -295,6 +295,5 @@ "Dependency Upgrades" ] ] - }, - "deferredNextVersion": "8.4.0-alpha.0" + } } diff --git a/code/presets/create-react-app/package.json b/code/presets/create-react-app/package.json index 462293b26994..5dab09ec6c19 100644 --- a/code/presets/create-react-app/package.json +++ b/code/presets/create-react-app/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-create-react-app", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Create React App preset", "keywords": [ "storybook" diff --git a/code/presets/html-webpack/package.json b/code/presets/html-webpack/package.json index 13fc3f6ff203..7c9fd1d7cebb 100644 --- a/code/presets/html-webpack/package.json +++ b/code/presets/html-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-html-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json index 1fdd3057ef48..ee4f7b1d79ab 100644 --- a/code/presets/preact-webpack/package.json +++ b/code/presets/preact-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-preact-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index 492e3ca9eebf..d22f61a94932 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-react-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading", "keywords": [ "storybook" diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json index e53f4e90102b..48fc4ac5927c 100644 --- a/code/presets/server-webpack/package.json +++ b/code/presets/server-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-server-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json index 706f2c1175d8..d3f4f143e6c7 100644 --- a/code/presets/svelte-webpack/package.json +++ b/code/presets/svelte-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-svelte-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/vue3-webpack/package.json b/code/presets/vue3-webpack/package.json index 7c13257f982d..defa498c49be 100644 --- a/code/presets/vue3-webpack/package.json +++ b/code/presets/vue3-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-vue3-webpack", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/renderers/html/package.json b/code/renderers/html/package.json index 0a792ba8758a..610953c43199 100644 --- a/code/renderers/html/package.json +++ b/code/renderers/html/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook HTML renderer", "keywords": [ "storybook" diff --git a/code/renderers/preact/package.json b/code/renderers/preact/package.json index 3a0945c1e67c..fd75078890cf 100644 --- a/code/renderers/preact/package.json +++ b/code/renderers/preact/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Preact renderer", "keywords": [ "storybook" diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 762e57f6e74f..3a2e94742328 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook React renderer", "keywords": [ "storybook" diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json index 3d0e72c88993..8214690cb7de 100644 --- a/code/renderers/server/package.json +++ b/code/renderers/server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Server renderer", "keywords": [ "storybook" diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index d4de65901941..aa804d3d0ce6 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Svelte renderer", "keywords": [ "storybook" diff --git a/code/renderers/vue3/package.json b/code/renderers/vue3/package.json index 4c2cb30c6928..be6775754ba9 100644 --- a/code/renderers/vue3/package.json +++ b/code/renderers/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook Vue 3 renderer", "keywords": [ "storybook" diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json index 87ce191c45ff..37413d6a4fd7 100644 --- a/code/renderers/web-components/package.json +++ b/code/renderers/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "8.3.0", + "version": "8.4.0-alpha.0", "description": "Storybook web-components renderer", "keywords": [ "lit", From 651674adcd313940f9c3f7134f591bc942226ddc Mon Sep 17 00:00:00 2001 From: kazuyainoue0124 <88877589+kazuyainoue0124@users.noreply.github.com> Date: Thu, 12 Sep 2024 08:21:25 +0900 Subject: [PATCH 068/213] api.md typo --- code/addons/themes/docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/addons/themes/docs/api.md b/code/addons/themes/docs/api.md index 143178b00047..a45818ab724e 100644 --- a/code/addons/themes/docs/api.md +++ b/code/addons/themes/docs/api.md @@ -148,7 +148,7 @@ export const myCustomDecorator = ({ themes, defaultState, ...rest }) => { Let's use Vuetify as an example. Vuetify uses it's own global state to know which theme to render. To build a custom decorator to accommodate this method we'll need to do the following ```js -// .storybook/withVeutifyTheme.decorator.js +// .storybook/withVuetifyTheme.decorator.js import { DecoratorHelpers } from '@storybook/addon-themes'; import { useTheme } from 'vuetify'; From 4af51ac4c2d184fc4a4eba85a1bcd5c931dda23d Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Thu, 12 Sep 2024 15:13:51 +0200 Subject: [PATCH 069/213] Use ansi-to-html for colored test errors --- code/addons/interactions/package.json | 1 + .../interactions/src/components/Interaction.tsx | 5 +++-- .../src/components/InteractionsPanel.tsx | 12 ++++++++---- .../src/components/MatcherResult.tsx | 10 +++++++++- code/addons/interactions/src/utils.ts | 16 ++++++++++++++++ code/yarn.lock | 1 + 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index dd30fb2650d4..9deb3a01105f 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -62,6 +62,7 @@ "@devtools-ds/object-inspector": "^1.1.2", "@storybook/icons": "^1.2.5", "@types/node": "^22.0.0", + "ansi-to-html": "^0.7.2", "formik": "^2.2.9", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/code/addons/interactions/src/components/Interaction.tsx b/code/addons/interactions/src/components/Interaction.tsx index c9b557cddc68..610d0c1b032b 100644 --- a/code/addons/interactions/src/components/Interaction.tsx +++ b/code/addons/interactions/src/components/Interaction.tsx @@ -8,7 +8,7 @@ import { type Call, CallStates, type ControlStates } from '@storybook/instrument import { transparentize } from 'polished'; -import { isChaiError, isJestError } from '../utils'; +import { isChaiError, isJestError, useAnsiToHtmlFilter } from '../utils'; import type { Controls } from './InteractionsPanel'; import { MatcherResult } from './MatcherResult'; import { MethodCall } from './MethodCall'; @@ -116,6 +116,7 @@ const RowMessage = styled('div')(({ theme }) => ({ })); export const Exception = ({ exception }: { exception: Call['exception'] }) => { + const filter = useAnsiToHtmlFilter(); if (isJestError(exception)) { return ; } @@ -135,7 +136,7 @@ export const Exception = ({ exception }: { exception: Call['exception'] }) => { const more = paragraphs.length > 1; return ( -
{paragraphs[0]}
+

       {more && 

See the full stack trace in the browser console.

}
); diff --git a/code/addons/interactions/src/components/InteractionsPanel.tsx b/code/addons/interactions/src/components/InteractionsPanel.tsx index c86a1df8ffde..643732f250ca 100644 --- a/code/addons/interactions/src/components/InteractionsPanel.tsx +++ b/code/addons/interactions/src/components/InteractionsPanel.tsx @@ -6,7 +6,7 @@ import { type Call, CallStates, type ControlStates } from '@storybook/instrument import { transparentize } from 'polished'; -import { isTestAssertionError } from '../utils'; +import { isTestAssertionError, useAnsiToHtmlFilter } from '../utils'; import { Empty } from './EmptyState'; import { Interaction } from './Interaction'; import { Subnav } from './Subnav'; @@ -97,6 +97,7 @@ export const InteractionsPanel: React.FC = React.memo( onScrollToEnd, endRef, }) { + const filter = useAnsiToHtmlFilter(); return ( {(interactions.length > 0 || hasException) && ( @@ -131,9 +132,12 @@ export const InteractionsPanel: React.FC = React.memo( Caught exception in play function - - {printSerializedError(caughtException)} - + )} {unhandledErrors && ( diff --git a/code/addons/interactions/src/components/MatcherResult.tsx b/code/addons/interactions/src/components/MatcherResult.tsx index beae8b2146ff..46b5e540ad8d 100644 --- a/code/addons/interactions/src/components/MatcherResult.tsx +++ b/code/addons/interactions/src/components/MatcherResult.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { styled, typography } from 'storybook/internal/theming'; +import { useAnsiToHtmlFilter } from '../utils'; import { Node } from './MethodCall'; const getParams = (line: string, fromIndex = 0): string => { @@ -59,6 +60,7 @@ export const MatcherResult = ({ message: string; style?: React.CSSProperties; }) => { + const filter = useAnsiToHtmlFilter(); const lines = message.split('\n'); return (
{line}, 
]; + return [ + , +
, + ]; })}
); diff --git a/code/addons/interactions/src/utils.ts b/code/addons/interactions/src/utils.ts index 1b08eca12a24..d80d9f4cdbee 100644 --- a/code/addons/interactions/src/utils.ts +++ b/code/addons/interactions/src/utils.ts @@ -1,3 +1,7 @@ +import { type StorybookTheme, useTheme } from 'storybook/internal/theming'; + +import Filter from 'ansi-to-html'; + export function isTestAssertionError(error: unknown) { return isChaiError(error) || isJestError(error); } @@ -21,3 +25,15 @@ export function isJestError(error: unknown) { error.message.startsWith('expect(') ); } + +export function createAnsiToHtmlFilter(theme: StorybookTheme) { + return new Filter({ + fg: theme.color.defaultText, + bg: theme.background.content, + }); +} + +export function useAnsiToHtmlFilter() { + const theme = useTheme(); + return createAnsiToHtmlFilter(theme); +} diff --git a/code/yarn.lock b/code/yarn.lock index 52f251440bb3..1c9424cca89c 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5492,6 +5492,7 @@ __metadata: "@storybook/instrumenter": "workspace:*" "@storybook/test": "workspace:*" "@types/node": "npm:^22.0.0" + ansi-to-html: "npm:^0.7.2" formik: "npm:^2.2.9" polished: "npm:^4.2.2" react: "npm:^18.2.0" From c55b7b55fd378b45f12cea0fcd7b985a1064e3a8 Mon Sep 17 00:00:00 2001 From: Lars Kappert Date: Thu, 12 Sep 2024 20:10:23 +0200 Subject: [PATCH 070/213] Add Knip with initial custom config --- code/knip.ts | 93 +++++++++++++++++++++++++++ code/package.json | 1 + code/yarn.lock | 159 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 1 + 4 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 code/knip.ts diff --git a/code/knip.ts b/code/knip.ts new file mode 100644 index 000000000000..ee1a6bb99281 --- /dev/null +++ b/code/knip.ts @@ -0,0 +1,93 @@ +import { join, relative } from 'node:path'; + +import fg from 'fast-glob'; +import type { KnipConfig } from 'knip'; +import { isMatch } from 'picomatch'; + +// Files we want to exclude from analysis should be negated project patterns, not `ignores` +// docs: https://knip.dev/guides/configuring-project-files +const project = [ + 'src/**/*.{js,jsx,ts,tsx}', + '!**/__search-files-tests__/**', + '!**/__testfixtures__/**', + '!**/__mocks-ng-workspace__/**', + '!**/__mockdata__/**', +]; + +// Adding an explicit MDX "compiler", as the dependency knip looks for isn't listed (@mdx-js/mdx or astro) +// Alternatively, we could ignore a few false positives +// docs: https://knip.dev/features/compilers +const importMatcher = /import[^'"]+['"]([^'"]+)['"]/g; +const fencedCodeBlockMatcher = /```[\s\S]*?```/g; +const mdx = (text: string) => + [...text.replace(fencedCodeBlockMatcher, '').matchAll(importMatcher)].join('\n'); + +const baseConfig = { + ignoreWorkspaces: ['renderers/svelte'], // ignored: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in code/node_modules/@sveltejs/vite-plugin-svelte/package.json + + // storybook itself configured (only) in root + storybook: { entry: ['**/*.@(mdx|stories.@(mdx|js|jsx|mjs|ts|tsx))'] }, + + workspaces: { + '.': { + project, + }, + 'addons/*': { + project, + }, + 'builders/*': { + project, + }, + core: { + entry: ['src/index.ts', 'src/cli/bin/index.ts', 'src/*/{globals*,index,runtime}.ts'], + project, + }, + 'frameworks/*': { + entry: [ + // these extra entries we only need for frameworks/angular and frameworks/ember it seems + 'src/index.ts', + 'src/builders/{build,start}-storybook/index.ts', + 'src/**/docs/{index,config}.{js,ts}', + ], + project, + }, + 'lib/*': { + project, + }, + 'presets/*': { + project, + }, + 'renderers/*': { + project, + }, + }, + compilers: { + mdx, + }, +} satisfies KnipConfig; + +// Adds package.json#bundler.entries etc. to each workspace config `entry: []` +export const addBundlerEntries = async (config: KnipConfig) => { + const baseDir = process.cwd(); + const rootManifest = await import(join(baseDir, 'package.json')); + const workspaceDirs = await fg(rootManifest.workspaces.packages, { onlyDirectories: true }); + const workspaceDirectories = workspaceDirs.map((dir) => relative(baseDir, join(baseDir, dir))); + for (const wsDir of workspaceDirectories) { + for (const configKey of Object.keys(baseConfig.workspaces)) { + if (isMatch(wsDir, configKey)) { + const manifest = await import(join(baseDir, wsDir, 'package.json')); + const configEntries = config.workspaces[configKey].entry ?? []; + const bundler = manifest?.bundler; + for (const value of Object.values(bundler ?? {})) { + if (Array.isArray(value)) { + configEntries.push(...value); + } + } + config.workspaces[configKey].entry = Array.from(new Set(configEntries)); + } + } + } + return config; +}; + +export default addBundlerEntries(baseConfig); diff --git a/code/package.json b/code/package.json index e348ef665900..f713f32e45aa 100644 --- a/code/package.json +++ b/code/package.json @@ -200,6 +200,7 @@ "happy-dom": "^14.12.0", "http-server": "^14.1.1", "husky": "^4.3.7", + "knip": "^5.30.1", "lint-staged": "^13.2.2", "lodash": "^4.17.21", "mock-require": "^3.0.3", diff --git a/code/yarn.lock b/code/yarn.lock index 52f251440bb3..ce807183913c 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -4001,7 +4001,7 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:1.2.8, @nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -5329,6 +5329,19 @@ __metadata: languageName: node linkType: hard +"@snyk/github-codeowners@npm:1.1.0": + version: 1.1.0 + resolution: "@snyk/github-codeowners@npm:1.1.0" + dependencies: + commander: "npm:^4.1.1" + ignore: "npm:^5.1.8" + p-map: "npm:^4.0.0" + bin: + github-codeowners: dist/cli.js + checksum: 10c0/92d860a904a1e67f8563d4ac4d540cc613f71193f7968933b4a4b1526e80a97f536f52d27762c158e3e39d48c2f3db4906ec78846309351c741abb1a28653af9 + languageName: node + linkType: hard + "@storybook/addon-a11y@workspace:*, @storybook/addon-a11y@workspace:addons/a11y": version: 0.0.0-use.local resolution: "@storybook/addon-a11y@workspace:addons/a11y" @@ -6908,6 +6921,7 @@ __metadata: happy-dom: "npm:^14.12.0" http-server: "npm:^14.1.1" husky: "npm:^4.3.7" + knip: "npm:^5.30.1" lint-staged: "npm:^13.2.2" lodash: "npm:^4.17.21" mock-require: "npm:^3.0.3" @@ -12095,6 +12109,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^4.1.1": + version: 4.1.1 + resolution: "commander@npm:4.1.1" + checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab + languageName: node + linkType: hard + "commander@npm:^5.1.0": version: 5.1.0 resolution: "commander@npm:5.1.0" @@ -13519,6 +13540,19 @@ __metadata: languageName: node linkType: hard +"easy-table@npm:1.2.0": + version: 1.2.0 + resolution: "easy-table@npm:1.2.0" + dependencies: + ansi-regex: "npm:^5.0.1" + wcwidth: "npm:^1.0.1" + dependenciesMeta: + wcwidth: + optional: true + checksum: 10c0/2d37937cd608586ba02e1ec479f90ccec581d366b3b0d1bb26b99ee6005f8d724e32a07a873759893461ca45b99e2d08c30326529d967ce9eedc1e9b68d4aa63 + languageName: node + linkType: hard + "ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": version: 1.0.11 resolution: "ecdsa-sig-formatter@npm:1.0.11" @@ -13826,6 +13860,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.17.1": + version: 5.17.1 + resolution: "enhanced-resolve@npm:5.17.1" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370 + languageName: node + linkType: hard + "enquirer@npm:^2.3.5": version: 2.4.1 resolution: "enquirer@npm:2.4.1" @@ -17297,6 +17341,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.1.8": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + "image-size@npm:^1.0.0, image-size@npm:^1.1.1": version: 1.1.1 resolution: "image-size@npm:1.1.1" @@ -18365,6 +18416,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^1.21.6": + version: 1.21.6 + resolution: "jiti@npm:1.21.6" + bin: + jiti: bin/jiti.js + checksum: 10c0/05b9ed58cd30d0c3ccd3c98209339e74f50abd9a17e716f65db46b6a35812103f6bde6e134be7124d01745586bca8cc5dae1d0d952267c3ebe55171949c32e56 + languageName: node + linkType: hard + "jju@npm:^1.4.0": version: 1.4.0 resolution: "jju@npm:1.4.0" @@ -18847,6 +18907,36 @@ __metadata: languageName: node linkType: hard +"knip@npm:^5.30.1": + version: 5.30.1 + resolution: "knip@npm:5.30.1" + dependencies: + "@nodelib/fs.walk": "npm:1.2.8" + "@snyk/github-codeowners": "npm:1.1.0" + easy-table: "npm:1.2.0" + enhanced-resolve: "npm:^5.17.1" + fast-glob: "npm:^3.3.2" + jiti: "npm:^1.21.6" + js-yaml: "npm:^4.1.0" + minimist: "npm:^1.2.8" + picocolors: "npm:^1.0.0" + picomatch: "npm:^4.0.1" + pretty-ms: "npm:^9.0.0" + smol-toml: "npm:^1.1.4" + strip-json-comments: "npm:5.0.1" + summary: "npm:2.1.0" + zod: "npm:^3.22.4" + zod-validation-error: "npm:^3.0.3" + peerDependencies: + "@types/node": ">=18" + typescript: ">=5.0.4" + bin: + knip: bin/knip.js + knip-bun: bin/knip-bun.js + checksum: 10c0/1c470266d7967dad0f2fb1b1f6c8a797bc7bea6c1f0021c52dce40e067ae87217eb17ff11a4164e3a5244bf3d0672f9e8678e4c3898260c48b9c020132ebb29a + languageName: node + linkType: hard + "language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" @@ -22404,6 +22494,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16 + languageName: node + linkType: hard + "parse-node-version@npm:^1.0.1": version: 1.0.1 resolution: "parse-node-version@npm:1.0.1" @@ -22693,6 +22790,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.1": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc + languageName: node + linkType: hard + "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -23227,6 +23331,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.0.0": + version: 9.1.0 + resolution: "pretty-ms@npm:9.1.0" + dependencies: + parse-ms: "npm:^4.0.0" + checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9 + languageName: node + linkType: hard + "prettyjson@npm:^1.2.1": version: 1.2.5 resolution: "prettyjson@npm:1.2.5" @@ -25869,6 +25982,13 @@ __metadata: languageName: node linkType: hard +"smol-toml@npm:^1.1.4": + version: 1.3.0 + resolution: "smol-toml@npm:1.3.0" + checksum: 10c0/442b4d033236ff6dd05bf91d57695fd9070a8221af080a5b2782cb2d9fad8bc31f698c61de5308a351907c1200202ba3ee51d52c5704f5349149e7c374f5fe90 + languageName: node + linkType: hard + "snapdragon-node@npm:^2.0.1": version: 2.1.1 resolution: "snapdragon-node@npm:2.1.1" @@ -26546,6 +26666,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:5.0.1, strip-json-comments@npm:^5.0.1": + version: 5.0.1 + resolution: "strip-json-comments@npm:5.0.1" + checksum: 10c0/c9d9d55a0167c57aa688df3aa20628cf6f46f0344038f189eaa9d159978e80b2bfa6da541a40d83f7bde8a3554596259bf6b70578b2172356536a0e3fa5a0982 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -26553,13 +26680,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^5.0.1": - version: 5.0.1 - resolution: "strip-json-comments@npm:5.0.1" - checksum: 10c0/c9d9d55a0167c57aa688df3aa20628cf6f46f0344038f189eaa9d159978e80b2bfa6da541a40d83f7bde8a3554596259bf6b70578b2172356536a0e3fa5a0982 - languageName: node - linkType: hard - "strong-log-transformer@npm:^2.1.0": version: 2.1.0 resolution: "strong-log-transformer@npm:2.1.0" @@ -26646,6 +26766,13 @@ __metadata: languageName: node linkType: hard +"summary@npm:2.1.0": + version: 2.1.0 + resolution: "summary@npm:2.1.0" + checksum: 10c0/2743c1f940fb303c496ef1b085e654704a6c16872957b6b76648c34bd32c8f0b7a3c5ec4e0f8bfb71dcb8473e34d172fef31026b85562af589cf220aa901698d + languageName: node + linkType: hard + "supports-color@npm:^5.0.0, supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -29733,6 +29860,22 @@ __metadata: languageName: node linkType: hard +"zod-validation-error@npm:^3.0.3": + version: 3.3.1 + resolution: "zod-validation-error@npm:3.3.1" + peerDependencies: + zod: ^3.18.0 + checksum: 10c0/53869a8478f42cd38f51e159431fe7af9e0b456e8078c6d9d906adb212753788defa9c8bd7374e9ecd4a688b6736fcfa091aebac65054328b8cfdecce9395d8e + languageName: node + linkType: hard + +"zod@npm:^3.22.4": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 + languageName: node + linkType: hard + "zone.js@npm:^0.14.2": version: 0.14.2 resolution: "zone.js@npm:0.14.2" diff --git a/package.json b/package.json index d0eb7795735e..2104e1eb7f49 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "get-template": "cd scripts; yarn get-template", "i": "yarn --cwd scripts && yarn --cwd code", "lint": "cd code; yarn lint", + "knip": "cd code; yarn knip", "nx": "cd code; yarn nx", "pretty-docs": "cd scripts; yarn install >/dev/null; yarn docs:prettier:write", "start": "yarn task --task dev --template react-vite/default-ts --start-from=install", From 9f15da58fb3db05a5b95d2f3c21fb79cb42f77e4 Mon Sep 17 00:00:00 2001 From: Lars Kappert Date: Thu, 12 Sep 2024 20:53:12 +0200 Subject: [PATCH 071/213] Move script/config --- code/package.json | 2 +- code/yarn.lock | 159 ++----------------------- package.json | 2 +- code/knip.ts => scripts/knip.config.ts | 4 +- scripts/package.json | 1 + scripts/yarn.lock | 142 +++++++++++++++++++++- 6 files changed, 151 insertions(+), 159 deletions(-) rename code/knip.ts => scripts/knip.config.ts (97%) diff --git a/code/package.json b/code/package.json index f713f32e45aa..9cedc81b71ea 100644 --- a/code/package.json +++ b/code/package.json @@ -36,6 +36,7 @@ "generate-sandboxes": "yarn --cwd ../scripts generate-sandboxes", "github-release": "github-release-from-changelog", "i": "yarn --cwd .. i", + "knip": "VITE_CJS_IGNORE_WARNING=1 ../scripts/node_modules/.bin/knip --config ../scripts/knip.config.ts", "lint": "yarn lint:js && yarn lint:md", "lint:ejs": "ejslint **/*.ejs", "lint:js": "yarn lint:js:cmd . --quiet", @@ -200,7 +201,6 @@ "happy-dom": "^14.12.0", "http-server": "^14.1.1", "husky": "^4.3.7", - "knip": "^5.30.1", "lint-staged": "^13.2.2", "lodash": "^4.17.21", "mock-require": "^3.0.3", diff --git a/code/yarn.lock b/code/yarn.lock index ce807183913c..52f251440bb3 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -4001,7 +4001,7 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.walk@npm:1.2.8, @nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -5329,19 +5329,6 @@ __metadata: languageName: node linkType: hard -"@snyk/github-codeowners@npm:1.1.0": - version: 1.1.0 - resolution: "@snyk/github-codeowners@npm:1.1.0" - dependencies: - commander: "npm:^4.1.1" - ignore: "npm:^5.1.8" - p-map: "npm:^4.0.0" - bin: - github-codeowners: dist/cli.js - checksum: 10c0/92d860a904a1e67f8563d4ac4d540cc613f71193f7968933b4a4b1526e80a97f536f52d27762c158e3e39d48c2f3db4906ec78846309351c741abb1a28653af9 - languageName: node - linkType: hard - "@storybook/addon-a11y@workspace:*, @storybook/addon-a11y@workspace:addons/a11y": version: 0.0.0-use.local resolution: "@storybook/addon-a11y@workspace:addons/a11y" @@ -6921,7 +6908,6 @@ __metadata: happy-dom: "npm:^14.12.0" http-server: "npm:^14.1.1" husky: "npm:^4.3.7" - knip: "npm:^5.30.1" lint-staged: "npm:^13.2.2" lodash: "npm:^4.17.21" mock-require: "npm:^3.0.3" @@ -12109,13 +12095,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^4.1.1": - version: 4.1.1 - resolution: "commander@npm:4.1.1" - checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab - languageName: node - linkType: hard - "commander@npm:^5.1.0": version: 5.1.0 resolution: "commander@npm:5.1.0" @@ -13540,19 +13519,6 @@ __metadata: languageName: node linkType: hard -"easy-table@npm:1.2.0": - version: 1.2.0 - resolution: "easy-table@npm:1.2.0" - dependencies: - ansi-regex: "npm:^5.0.1" - wcwidth: "npm:^1.0.1" - dependenciesMeta: - wcwidth: - optional: true - checksum: 10c0/2d37937cd608586ba02e1ec479f90ccec581d366b3b0d1bb26b99ee6005f8d724e32a07a873759893461ca45b99e2d08c30326529d967ce9eedc1e9b68d4aa63 - languageName: node - linkType: hard - "ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": version: 1.0.11 resolution: "ecdsa-sig-formatter@npm:1.0.11" @@ -13860,16 +13826,6 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.17.1": - version: 5.17.1 - resolution: "enhanced-resolve@npm:5.17.1" - dependencies: - graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.2.0" - checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370 - languageName: node - linkType: hard - "enquirer@npm:^2.3.5": version: 2.4.1 resolution: "enquirer@npm:2.4.1" @@ -17341,13 +17297,6 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.1.8": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 - languageName: node - linkType: hard - "image-size@npm:^1.0.0, image-size@npm:^1.1.1": version: 1.1.1 resolution: "image-size@npm:1.1.1" @@ -18416,15 +18365,6 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.21.6": - version: 1.21.6 - resolution: "jiti@npm:1.21.6" - bin: - jiti: bin/jiti.js - checksum: 10c0/05b9ed58cd30d0c3ccd3c98209339e74f50abd9a17e716f65db46b6a35812103f6bde6e134be7124d01745586bca8cc5dae1d0d952267c3ebe55171949c32e56 - languageName: node - linkType: hard - "jju@npm:^1.4.0": version: 1.4.0 resolution: "jju@npm:1.4.0" @@ -18907,36 +18847,6 @@ __metadata: languageName: node linkType: hard -"knip@npm:^5.30.1": - version: 5.30.1 - resolution: "knip@npm:5.30.1" - dependencies: - "@nodelib/fs.walk": "npm:1.2.8" - "@snyk/github-codeowners": "npm:1.1.0" - easy-table: "npm:1.2.0" - enhanced-resolve: "npm:^5.17.1" - fast-glob: "npm:^3.3.2" - jiti: "npm:^1.21.6" - js-yaml: "npm:^4.1.0" - minimist: "npm:^1.2.8" - picocolors: "npm:^1.0.0" - picomatch: "npm:^4.0.1" - pretty-ms: "npm:^9.0.0" - smol-toml: "npm:^1.1.4" - strip-json-comments: "npm:5.0.1" - summary: "npm:2.1.0" - zod: "npm:^3.22.4" - zod-validation-error: "npm:^3.0.3" - peerDependencies: - "@types/node": ">=18" - typescript: ">=5.0.4" - bin: - knip: bin/knip.js - knip-bun: bin/knip-bun.js - checksum: 10c0/1c470266d7967dad0f2fb1b1f6c8a797bc7bea6c1f0021c52dce40e067ae87217eb17ff11a4164e3a5244bf3d0672f9e8678e4c3898260c48b9c020132ebb29a - languageName: node - linkType: hard - "language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" @@ -22494,13 +22404,6 @@ __metadata: languageName: node linkType: hard -"parse-ms@npm:^4.0.0": - version: 4.0.0 - resolution: "parse-ms@npm:4.0.0" - checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16 - languageName: node - linkType: hard - "parse-node-version@npm:^1.0.1": version: 1.0.1 resolution: "parse-node-version@npm:1.0.1" @@ -22790,13 +22693,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^4.0.1": - version: 4.0.2 - resolution: "picomatch@npm:4.0.2" - checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc - languageName: node - linkType: hard - "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -23331,15 +23227,6 @@ __metadata: languageName: node linkType: hard -"pretty-ms@npm:^9.0.0": - version: 9.1.0 - resolution: "pretty-ms@npm:9.1.0" - dependencies: - parse-ms: "npm:^4.0.0" - checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9 - languageName: node - linkType: hard - "prettyjson@npm:^1.2.1": version: 1.2.5 resolution: "prettyjson@npm:1.2.5" @@ -25982,13 +25869,6 @@ __metadata: languageName: node linkType: hard -"smol-toml@npm:^1.1.4": - version: 1.3.0 - resolution: "smol-toml@npm:1.3.0" - checksum: 10c0/442b4d033236ff6dd05bf91d57695fd9070a8221af080a5b2782cb2d9fad8bc31f698c61de5308a351907c1200202ba3ee51d52c5704f5349149e7c374f5fe90 - languageName: node - linkType: hard - "snapdragon-node@npm:^2.0.1": version: 2.1.1 resolution: "snapdragon-node@npm:2.1.1" @@ -26666,13 +26546,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:5.0.1, strip-json-comments@npm:^5.0.1": - version: 5.0.1 - resolution: "strip-json-comments@npm:5.0.1" - checksum: 10c0/c9d9d55a0167c57aa688df3aa20628cf6f46f0344038f189eaa9d159978e80b2bfa6da541a40d83f7bde8a3554596259bf6b70578b2172356536a0e3fa5a0982 - languageName: node - linkType: hard - "strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -26680,6 +26553,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:^5.0.1": + version: 5.0.1 + resolution: "strip-json-comments@npm:5.0.1" + checksum: 10c0/c9d9d55a0167c57aa688df3aa20628cf6f46f0344038f189eaa9d159978e80b2bfa6da541a40d83f7bde8a3554596259bf6b70578b2172356536a0e3fa5a0982 + languageName: node + linkType: hard + "strong-log-transformer@npm:^2.1.0": version: 2.1.0 resolution: "strong-log-transformer@npm:2.1.0" @@ -26766,13 +26646,6 @@ __metadata: languageName: node linkType: hard -"summary@npm:2.1.0": - version: 2.1.0 - resolution: "summary@npm:2.1.0" - checksum: 10c0/2743c1f940fb303c496ef1b085e654704a6c16872957b6b76648c34bd32c8f0b7a3c5ec4e0f8bfb71dcb8473e34d172fef31026b85562af589cf220aa901698d - languageName: node - linkType: hard - "supports-color@npm:^5.0.0, supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -29860,22 +29733,6 @@ __metadata: languageName: node linkType: hard -"zod-validation-error@npm:^3.0.3": - version: 3.3.1 - resolution: "zod-validation-error@npm:3.3.1" - peerDependencies: - zod: ^3.18.0 - checksum: 10c0/53869a8478f42cd38f51e159431fe7af9e0b456e8078c6d9d906adb212753788defa9c8bd7374e9ecd4a688b6736fcfa091aebac65054328b8cfdecce9395d8e - languageName: node - linkType: hard - -"zod@npm:^3.22.4": - version: 3.23.8 - resolution: "zod@npm:3.23.8" - checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 - languageName: node - linkType: hard - "zone.js@npm:^0.14.2": version: 0.14.2 resolution: "zone.js@npm:0.14.2" diff --git a/package.json b/package.json index 2104e1eb7f49..64a3e118ab67 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "get-report-message": "cd scripts; yarn get-report-message", "get-template": "cd scripts; yarn get-template", "i": "yarn --cwd scripts && yarn --cwd code", - "lint": "cd code; yarn lint", "knip": "cd code; yarn knip", + "lint": "cd code; yarn lint", "nx": "cd code; yarn nx", "pretty-docs": "cd scripts; yarn install >/dev/null; yarn docs:prettier:write", "start": "yarn task --task dev --template react-vite/default-ts --start-from=install", diff --git a/code/knip.ts b/scripts/knip.config.ts similarity index 97% rename from code/knip.ts rename to scripts/knip.config.ts index ee1a6bb99281..919d53259fd4 100644 --- a/code/knip.ts +++ b/scripts/knip.config.ts @@ -68,9 +68,9 @@ const baseConfig = { // Adds package.json#bundler.entries etc. to each workspace config `entry: []` export const addBundlerEntries = async (config: KnipConfig) => { - const baseDir = process.cwd(); + const baseDir = join(__dirname, '../code'); const rootManifest = await import(join(baseDir, 'package.json')); - const workspaceDirs = await fg(rootManifest.workspaces.packages, { onlyDirectories: true }); + const workspaceDirs = await fg(rootManifest.workspaces.packages, { cwd: baseDir, onlyDirectories: true }); const workspaceDirectories = workspaceDirs.map((dir) => relative(baseDir, join(baseDir, dir))); for (const wsDir of workspaceDirectories) { for (const configKey of Object.keys(baseConfig.workspaces)) { diff --git a/scripts/package.json b/scripts/package.json index 2cd8402ddcd8..47bb3cd000fa 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -135,6 +135,7 @@ "husky": "^4.3.7", "json5": "^2.2.3", "junit-xml": "^1.2.0", + "knip": "^5.30.1", "lint-staged": "^15.2.7", "lodash": "^4.17.21", "memoizerific": "^1.11.3", diff --git a/scripts/yarn.lock b/scripts/yarn.lock index 204801ac47ac..5689424235fa 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -768,7 +768,7 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:1.2.8, @nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -1459,6 +1459,19 @@ __metadata: languageName: node linkType: hard +"@snyk/github-codeowners@npm:1.1.0": + version: 1.1.0 + resolution: "@snyk/github-codeowners@npm:1.1.0" + dependencies: + commander: "npm:^4.1.1" + ignore: "npm:^5.1.8" + p-map: "npm:^4.0.0" + bin: + github-codeowners: dist/cli.js + checksum: 10c0/92d860a904a1e67f8563d4ac4d540cc613f71193f7968933b4a4b1526e80a97f536f52d27762c158e3e39d48c2f3db4906ec78846309351c741abb1a28653af9 + languageName: node + linkType: hard + "@storybook/csf@npm:^0.0.1": version: 0.0.1 resolution: "@storybook/csf@npm:0.0.1" @@ -1587,6 +1600,7 @@ __metadata: jiti: "npm:^1.21.6" json5: "npm:^2.2.3" junit-xml: "npm:^1.2.0" + knip: "npm:^5.30.1" lint-staged: "npm:^15.2.7" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" @@ -4164,7 +4178,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^4.0.0": +"commander@npm:^4.0.0, commander@npm:^4.1.1": version: 4.1.1 resolution: "commander@npm:4.1.1" checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab @@ -4952,6 +4966,19 @@ __metadata: languageName: node linkType: hard +"easy-table@npm:1.2.0": + version: 1.2.0 + resolution: "easy-table@npm:1.2.0" + dependencies: + ansi-regex: "npm:^5.0.1" + wcwidth: "npm:^1.0.1" + dependenciesMeta: + wcwidth: + optional: true + checksum: 10c0/2d37937cd608586ba02e1ec479f90ccec581d366b3b0d1bb26b99ee6005f8d724e32a07a873759893461ca45b99e2d08c30326529d967ce9eedc1e9b68d4aa63 + languageName: node + linkType: hard + "ecc-jsbn@npm:~0.1.1": version: 0.1.2 resolution: "ecc-jsbn@npm:0.1.2" @@ -5071,6 +5098,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.17.1": + version: 5.17.1 + resolution: "enhanced-resolve@npm:5.17.1" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370 + languageName: node + linkType: hard + "enquirer@npm:~2.3.6": version: 2.3.6 resolution: "enquirer@npm:2.3.6" @@ -6853,7 +6890,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -7306,6 +7343,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.1.8": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" @@ -8368,6 +8412,36 @@ __metadata: languageName: node linkType: hard +"knip@npm:^5.30.1": + version: 5.30.1 + resolution: "knip@npm:5.30.1" + dependencies: + "@nodelib/fs.walk": "npm:1.2.8" + "@snyk/github-codeowners": "npm:1.1.0" + easy-table: "npm:1.2.0" + enhanced-resolve: "npm:^5.17.1" + fast-glob: "npm:^3.3.2" + jiti: "npm:^1.21.6" + js-yaml: "npm:^4.1.0" + minimist: "npm:^1.2.8" + picocolors: "npm:^1.0.0" + picomatch: "npm:^4.0.1" + pretty-ms: "npm:^9.0.0" + smol-toml: "npm:^1.1.4" + strip-json-comments: "npm:5.0.1" + summary: "npm:2.1.0" + zod: "npm:^3.22.4" + zod-validation-error: "npm:^3.0.3" + peerDependencies: + "@types/node": ">=18" + typescript: ">=5.0.4" + bin: + knip: bin/knip.js + knip-bun: bin/knip-bun.js + checksum: 10c0/1c470266d7967dad0f2fb1b1f6c8a797bc7bea6c1f0021c52dce40e067ae87217eb17ff11a4164e3a5244bf3d0672f9e8678e4c3898260c48b9c020132ebb29a + languageName: node + linkType: hard + "language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" @@ -10544,6 +10618,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16 + languageName: node + linkType: hard + "parse-passwd@npm:^1.0.0": version: 1.0.0 resolution: "parse-passwd@npm:1.0.0" @@ -10686,6 +10767,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.1": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc + languageName: node + linkType: hard + "pidtree@npm:~0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -11069,6 +11157,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.0.0": + version: 9.1.0 + resolution: "pretty-ms@npm:9.1.0" + dependencies: + parse-ms: "npm:^4.0.0" + checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9 + languageName: node + linkType: hard + "prettyjson@npm:^1.2.1": version: 1.2.5 resolution: "prettyjson@npm:1.2.5" @@ -12486,6 +12583,13 @@ __metadata: languageName: node linkType: hard +"smol-toml@npm:^1.1.4": + version: 1.3.0 + resolution: "smol-toml@npm:1.3.0" + checksum: 10c0/442b4d033236ff6dd05bf91d57695fd9070a8221af080a5b2782cb2d9fad8bc31f698c61de5308a351907c1200202ba3ee51d52c5704f5349149e7c374f5fe90 + languageName: node + linkType: hard + "socks-proxy-agent@npm:^7.0.0": version: 7.0.0 resolution: "socks-proxy-agent@npm:7.0.0" @@ -12960,6 +13064,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:5.0.1": + version: 5.0.1 + resolution: "strip-json-comments@npm:5.0.1" + checksum: 10c0/c9d9d55a0167c57aa688df3aa20628cf6f46f0344038f189eaa9d159978e80b2bfa6da541a40d83f7bde8a3554596259bf6b70578b2172356536a0e3fa5a0982 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -13005,6 +13116,13 @@ __metadata: languageName: node linkType: hard +"summary@npm:2.1.0": + version: 2.1.0 + resolution: "summary@npm:2.1.0" + checksum: 10c0/2743c1f940fb303c496ef1b085e654704a6c16872957b6b76648c34bd32c8f0b7a3c5ec4e0f8bfb71dcb8473e34d172fef31026b85562af589cf220aa901698d + languageName: node + linkType: hard + "supports-color@npm:^5.0.0, supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -13066,6 +13184,13 @@ __metadata: languageName: node linkType: hard +"tapable@npm:^2.2.0": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 10c0/bc40e6efe1e554d075469cedaba69a30eeb373552aaf41caeaaa45bf56ffacc2674261b106245bd566b35d8f3329b52d838e851ee0a852120acae26e622925c9 + languageName: node + linkType: hard + "tar-stream@npm:^1.5.2": version: 1.6.2 resolution: "tar-stream@npm:1.6.2" @@ -14833,7 +14958,16 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.23.8": +"zod-validation-error@npm:^3.0.3": + version: 3.3.1 + resolution: "zod-validation-error@npm:3.3.1" + peerDependencies: + zod: ^3.18.0 + checksum: 10c0/53869a8478f42cd38f51e159431fe7af9e0b456e8078c6d9d906adb212753788defa9c8bd7374e9ecd4a688b6736fcfa091aebac65054328b8cfdecce9395d8e + languageName: node + linkType: hard + +"zod@npm:^3.22.4, zod@npm:^3.23.8": version: 3.23.8 resolution: "zod@npm:3.23.8" checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 From 2806b81d4619088ba07fa054e89f927276281c3f Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 13 Sep 2024 10:58:04 +0200 Subject: [PATCH 072/213] move metafiles --- code/core/scripts/prep.ts | 45 +++++++++++++++++++++++++++------------ code/nx.json | 6 +++++- scripts/prepare/bundle.ts | 33 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/code/core/scripts/prep.ts b/code/core/scripts/prep.ts index 49c2bd00cfa0..6d8fcef3a838 100644 --- a/code/core/scripts/prep.ts +++ b/code/core/scripts/prep.ts @@ -3,7 +3,7 @@ import { watch } from 'node:fs'; import { mkdir, rm, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; -import { ensureDir } from 'fs-extra'; +import { emptyDir, ensureDir } from 'fs-extra'; import { chalk, @@ -308,25 +308,42 @@ async function run() { console.log(`compiled ${chalk.cyan(filename)}`); }); } else { + // repo root/benchmarks/esbuild-metafiles/core + const metafilesDir = join( + __dirname, + '..', + '..', + '..', + 'benchmarks', + 'esbuild-metafiles', + 'core' + ); + await ensureDir(metafilesDir); + await emptyDir(metafilesDir); + await Promise.all( compile.map(async (context, index) => { const out = await context.rebuild(); await context.dispose(); - if (out.metafile) { - const { outputs } = out.metafile; - const keys = Object.keys(outputs); - const format = keys.every((key) => key.endsWith('.js')) ? 'esm' : 'cjs'; - const outName = - keys.length === 1 ? dirname(keys[0]).replace('dist/', '') : `meta-${format}-${index}`; - - await ensureDir('report'); - await writeFile(`report/${outName}.json`, JSON.stringify(out.metafile, null, 2)); - await writeFile( - `report/${outName}.txt`, - await esbuild.analyzeMetafile(out.metafile, { color: false, verbose: false }) - ); + if (!out.metafile) { + return; } + + const { outputs } = out.metafile; + const keys = Object.keys(outputs); + const format = keys.every((key) => key.endsWith('.js')) ? 'esm' : 'cjs'; + const outName = + keys.length === 1 ? dirname(keys[0]).replace('dist/', '') : `core.${format}-${index}`; + + await await writeFile( + join(metafilesDir, `${outName}.json`), + JSON.stringify(out.metafile, null, 2) + ); + await writeFile( + join(metafilesDir, `${outName}.txt`), + await esbuild.analyzeMetafile(out.metafile, { color: false, verbose: false }) + ); }) ); } diff --git a/code/nx.json b/code/nx.json index 12070cbb8d4e..80d456e5c63d 100644 --- a/code/nx.json +++ b/code/nx.json @@ -52,7 +52,11 @@ "{workspaceRoot}/../scripts/prepare/{bundle,addon-bundle,esm-bundle}.ts" ], "dependsOn": ["^build"], - "outputs": ["{projectRoot}/dist"], + "outputs": [ + "{projectRoot}/dist", + // "{projectRoot}/benchmarks/{projectName}.{cjs,esm}.json" + "{workspaceRoot}/benchmarks/esbuild-metafiles/{projectName}" + ], "cache": true }, "test": { diff --git a/scripts/prepare/bundle.ts b/scripts/prepare/bundle.ts index 81a7b301fe41..868e6722de74 100755 --- a/scripts/prepare/bundle.ts +++ b/scripts/prepare/bundle.ts @@ -95,6 +95,7 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { watch, outDir, sourcemap: false, + metafile: true, format: ['esm'], target: platform === 'node' ? ['node18'] : ['chrome100', 'safari15', 'firefox91'], clean: false, @@ -129,6 +130,7 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { watch, outDir, sourcemap: false, + metafile: true, format: ['cjs'], target: 'node18', ...(dtsBuild === 'cjs' ? dtsConfig : {}), @@ -150,6 +152,15 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { await Promise.all(tasks); + if (!watch) { + if (formats.includes('cjs')) { + await moveMetafile({ name, format: 'cjs', outDir }); + } + if (formats.includes('esm')) { + await moveMetafile({ name, format: 'esm', outDir }); + } + } + const dtsFiles = await glob(outDir + '/**/*.d.ts'); await Promise.all( dtsFiles.map(async (file) => { @@ -225,6 +236,28 @@ async function generateDTSMapperFile(file: string) { ); } +async function moveMetafile({ + name, + format, + outDir, +}: { + name: string; + format: 'esm' | 'cjs'; + outDir: string; +}) { + const metafilesDir = join(__dirname, '..', '..', 'code', 'benchmarks', 'esbuild-metafiles'); + await fs.ensureDir(metafilesDir); + const metafilePrefix = name.replace('@storybook/', ''); + + console.log('LOG: ', { dest: metafilesDir }); + + await fs.move( + join(outDir, `metafile-${format}.json`), + join(metafilesDir, `${metafilePrefix}/${format}.json`), + { overwrite: true } + ); +} + const hasFlag = (flags: string[], name: string) => !!flags.find((s) => s.startsWith(`--${name}`)); /* SELF EXECUTION */ From e693dcd92622651f51ae3e6e69a566cdf6dfe6fe Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Fri, 13 Sep 2024 11:11:18 +0200 Subject: [PATCH 073/213] Fix check --- code/renderers/react/src/__test__/portable-stories.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/renderers/react/src/__test__/portable-stories.test.tsx b/code/renderers/react/src/__test__/portable-stories.test.tsx index 94de89e093a5..85f33c9a714a 100644 --- a/code/renderers/react/src/__test__/portable-stories.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories.test.tsx @@ -8,7 +8,8 @@ import React from 'react'; import { addons } from 'storybook/internal/preview-api'; -import type { Meta } from '@storybook/react'; +import type { ProjectAnnotations } from '@storybook/csf'; +import type { Meta, ReactRenderer } from '@storybook/react'; import * as addonActionsPreview from '@storybook/addon-actions/preview'; @@ -124,7 +125,7 @@ describe('projectAnnotations', () => { const Story = composeStory( ButtonStories.WithActionArgType, ButtonStories.default, - addonActionsPreview + addonActionsPreview as ProjectAnnotations ); expect(Story.args.someActionArg).toHaveProperty('isAction', true); }); From 568d96d46148a25a740db550b28a0328367f7576 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 13 Sep 2024 11:36:56 +0200 Subject: [PATCH 074/213] use bench-dir for esbuild metafile, fix addon-test collision --- code/core/scripts/prep.ts | 12 ++---------- code/nx.json | 6 +----- scripts/prepare/bundle.ts | 10 ++++++---- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/code/core/scripts/prep.ts b/code/core/scripts/prep.ts index 6d8fcef3a838..355942e61156 100644 --- a/code/core/scripts/prep.ts +++ b/code/core/scripts/prep.ts @@ -308,16 +308,8 @@ async function run() { console.log(`compiled ${chalk.cyan(filename)}`); }); } else { - // repo root/benchmarks/esbuild-metafiles/core - const metafilesDir = join( - __dirname, - '..', - '..', - '..', - 'benchmarks', - 'esbuild-metafiles', - 'core' - ); + // repo root/bench/esbuild-metafiles/core + const metafilesDir = join(__dirname, '..', '..', '..', 'bench', 'esbuild-metafiles', 'core'); await ensureDir(metafilesDir); await emptyDir(metafilesDir); diff --git a/code/nx.json b/code/nx.json index 80d456e5c63d..a34b471c624e 100644 --- a/code/nx.json +++ b/code/nx.json @@ -52,11 +52,7 @@ "{workspaceRoot}/../scripts/prepare/{bundle,addon-bundle,esm-bundle}.ts" ], "dependsOn": ["^build"], - "outputs": [ - "{projectRoot}/dist", - // "{projectRoot}/benchmarks/{projectName}.{cjs,esm}.json" - "{workspaceRoot}/benchmarks/esbuild-metafiles/{projectName}" - ], + "outputs": ["{projectRoot}/dist", "{workspaceRoot}/../bench/esbuild-metafiles/{projectName}"], "cache": true }, "test": { diff --git a/scripts/prepare/bundle.ts b/scripts/prepare/bundle.ts index 868e6722de74..b271837135ec 100755 --- a/scripts/prepare/bundle.ts +++ b/scripts/prepare/bundle.ts @@ -245,15 +245,17 @@ async function moveMetafile({ format: 'esm' | 'cjs'; outDir: string; }) { - const metafilesDir = join(__dirname, '..', '..', 'code', 'benchmarks', 'esbuild-metafiles'); + const metafilesDir = join(__dirname, '..', '..', 'bench', 'esbuild-metafiles'); await fs.ensureDir(metafilesDir); - const metafilePrefix = name.replace('@storybook/', ''); + const packageDir = process.cwd().includes('addons/test') + ? 'addon-test' // special case, because @storybook/addon-test and @storybook/test have the same leaf dirname + : process.cwd().split(sep).at(-1); - console.log('LOG: ', { dest: metafilesDir }); + console.log('LOG: ', join(metafilesDir, packageDir, `${format}.json`)); await fs.move( join(outDir, `metafile-${format}.json`), - join(metafilesDir, `${metafilePrefix}/${format}.json`), + join(metafilesDir, packageDir, `${format}.json`), { overwrite: true } ); } From 1439a0d176b4a8171d1392b7830addb2d4af1833 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 13 Sep 2024 11:37:57 +0200 Subject: [PATCH 075/213] fix mixing nx project names --- code/lib/instrumenter/project.json | 1 + code/lib/test/project.json | 1 + 2 files changed, 2 insertions(+) diff --git a/code/lib/instrumenter/project.json b/code/lib/instrumenter/project.json index 3ecdad88a0dd..dd7cc79ecbe4 100644 --- a/code/lib/instrumenter/project.json +++ b/code/lib/instrumenter/project.json @@ -1,4 +1,5 @@ { + "name": "instrumenter", "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "library", "targets": { diff --git a/code/lib/test/project.json b/code/lib/test/project.json index 3ecdad88a0dd..1302a230f1e1 100644 --- a/code/lib/test/project.json +++ b/code/lib/test/project.json @@ -1,4 +1,5 @@ { + "name": "test", "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "library", "targets": { From bc838f212037175cec4050fa1d975a6a303274c7 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 13 Sep 2024 11:41:30 +0200 Subject: [PATCH 076/213] store esbuild metafiles in circleci artifacts --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e5c0b499cc6..685cd7291134 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -154,6 +154,8 @@ jobs: cd code yarn local-registry --publish - report-workflow-on-failure + - store_artifacts: + path: bench/esbuild-metafiles - save_cache: name: Save Yarn cache key: build-yarn-2-cache-v4--{{ checksum "code/yarn.lock" }}--{{ checksum "scripts/yarn.lock" }} From 3d4f7ec05c89fcb64bb34c7b1be49657c059c093 Mon Sep 17 00:00:00 2001 From: 3w36zj6 <52315048+3w36zj6@users.noreply.github.com> Date: Sat, 14 Sep 2024 00:56:03 +0900 Subject: [PATCH 077/213] Ensure `.gitignore` updated via CLI ends with a newline --- code/lib/create-storybook/src/initiate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/create-storybook/src/initiate.ts b/code/lib/create-storybook/src/initiate.ts index 787e16288cc2..bed1870fd2a9 100644 --- a/code/lib/create-storybook/src/initiate.ts +++ b/code/lib/create-storybook/src/initiate.ts @@ -375,7 +375,7 @@ export async function doInitiate(options: CommandOptions): Promise< if (foundGitIgnoreFile && foundGitIgnoreFile.includes(rootDirectory)) { const contents = await readFile(foundGitIgnoreFile, 'utf-8'); if (!contents.includes('*storybook.log')) { - await appendFile(foundGitIgnoreFile, '\n*storybook.log'); + await appendFile(foundGitIgnoreFile, '\n*storybook.log\n'); } } From 247efff2d76bb2cda236b3aa3d06a07e9b7bc263 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 00:14:30 +0200 Subject: [PATCH 078/213] Remove `fs-extra` from `presets/server` --- code/renderers/server/package.json | 2 -- code/renderers/server/src/preset.ts | 7 ++++--- code/yarn.lock | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json index 8214690cb7de..67d3343a72b3 100644 --- a/code/renderers/server/package.json +++ b/code/renderers/server/package.json @@ -51,8 +51,6 @@ "@storybook/manager-api": "workspace:^", "@storybook/preview-api": "workspace:^", "@storybook/theming": "workspace:^", - "@types/fs-extra": "^11.0.1", - "fs-extra": "^11.1.0", "ts-dedent": "^2.0.0", "yaml": "^2.3.1" }, diff --git a/code/renderers/server/src/preset.ts b/code/renderers/server/src/preset.ts index 018f50623eee..04937a0b8c14 100644 --- a/code/renderers/server/src/preset.ts +++ b/code/renderers/server/src/preset.ts @@ -1,8 +1,8 @@ +import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; import type { ComponentTitle, PresetProperty, StoryName, Tag } from 'storybook/internal/types'; -import fs from 'fs-extra'; import yaml from 'yaml'; type FileContent = { @@ -18,9 +18,10 @@ export const experimental_indexers: PresetProperty<'experimental_indexers'> = ( { test: /(stories|story)\.(json|ya?ml)$/, createIndex: async (fileName) => { + const rawFile = await readFile(fileName, { encoding: 'utf-8' }); const content: FileContent = fileName.endsWith('.json') - ? await fs.readJson(fileName, 'utf-8') - : yaml.parse((await fs.readFile(fileName, 'utf-8')).toString()); + ? JSON.parse(rawFile) + : yaml.parse(rawFile); return content.stories.map((story) => { const tags = Array.from(new Set([...(content.tags ?? []), ...(story.tags ?? [])])); diff --git a/code/yarn.lock b/code/yarn.lock index 52f251440bb3..57d65cf7988c 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6984,8 +6984,6 @@ __metadata: "@storybook/manager-api": "workspace:^" "@storybook/preview-api": "workspace:^" "@storybook/theming": "workspace:^" - "@types/fs-extra": "npm:^11.0.1" - fs-extra: "npm:^11.1.0" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" yaml: "npm:^2.3.1" From 2ac99b3addc2842434563686e6e4c1f0a6838ca4 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 00:17:40 +0200 Subject: [PATCH 079/213] Remove `fs-extra` from `presets/react-webpack` --- code/presets/react-webpack/package.json | 1 - code/yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index d22f61a94932..8f3e04e671b7 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -70,7 +70,6 @@ "@types/node": "^22.0.0", "@types/semver": "^7.3.4", "find-up": "^5.0.0", - "fs-extra": "^11.1.0", "magic-string": "^0.30.5", "react-docgen": "^7.0.0", "resolve": "^1.22.8", diff --git a/code/yarn.lock b/code/yarn.lock index 57d65cf7988c..9a9b1cedaa13 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6583,7 +6583,6 @@ __metadata: "@types/node": "npm:^22.0.0" "@types/semver": "npm:^7.3.4" find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" magic-string: "npm:^0.30.5" react-docgen: "npm:^7.0.0" resolve: "npm:^1.22.8" From ce73ddb77c3bf76f6f4c39d64a79ea2570693e4c Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 12:20:06 +0200 Subject: [PATCH 080/213] Remove `fs-extra` from `lib/create-storybook` --- code/lib/create-storybook/package.json | 1 - .../src/generators/baseGenerator.ts | 6 +++-- .../src/generators/configure.test.ts | 23 +++++++++++-------- .../src/generators/configure.ts | 16 +++++++++---- .../src/scaffold-new-project.ts | 6 +++-- code/yarn.lock | 1 - 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/code/lib/create-storybook/package.json b/code/lib/create-storybook/package.json index 2a08fc5deed2..612b559bcae2 100644 --- a/code/lib/create-storybook/package.json +++ b/code/lib/create-storybook/package.json @@ -61,7 +61,6 @@ "execa": "^5.0.0", "fd-package-json": "^1.2.0", "find-up": "^5.0.0", - "fs-extra": "^11.1.0", "ora": "^5.4.1", "prettier": "^3.1.1", "prompts": "^2.4.0", diff --git a/code/lib/create-storybook/src/generators/baseGenerator.ts b/code/lib/create-storybook/src/generators/baseGenerator.ts index 20318b78a68e..f5d0c6ed828c 100644 --- a/code/lib/create-storybook/src/generators/baseGenerator.ts +++ b/code/lib/create-storybook/src/generators/baseGenerator.ts @@ -1,3 +1,4 @@ +import { mkdir } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import type { NpmOptions } from 'storybook/internal/cli'; @@ -10,7 +11,6 @@ import type { JsPackageManager } from 'storybook/internal/common'; import { getPackageDetails, versions as packageVersions } from 'storybook/internal/common'; import type { SupportedFrameworks } from 'storybook/internal/types'; -import fse from 'fs-extra'; import ora from 'ora'; import invariant from 'tiny-invariant'; import { dedent } from 'ts-dedent'; @@ -328,7 +328,9 @@ export async function baseGenerator( addDependenciesSpinner.succeed(); } - await fse.ensureDir(`./${storybookConfigFolder}`); + // Passing `recursive: true` ensures that the method doesn't throw when + // the directory already exists. + await mkdir(`./${storybookConfigFolder}`, { recursive: true }); if (addMainFile) { const prefixes = shouldApplyRequireWrapperOnPackageNames diff --git a/code/lib/create-storybook/src/generators/configure.test.ts b/code/lib/create-storybook/src/generators/configure.test.ts index b1ce1005d230..db099baf5590 100644 --- a/code/lib/create-storybook/src/generators/configure.test.ts +++ b/code/lib/create-storybook/src/generators/configure.test.ts @@ -1,17 +1,20 @@ +import type { Stats } from 'node:fs'; +import * as fsp from 'node:fs/promises'; + import { beforeAll, describe, expect, it, vi } from 'vitest'; import { SupportedLanguage } from 'storybook/internal/cli'; -import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; import { configureMain, configurePreview } from './configure'; -vi.mock('fs-extra'); +vi.mock('node:fs/promises'); describe('configureMain', () => { beforeAll(() => { vi.clearAllMocks(); + vi.mocked(fsp.stat).mockRejectedValue({}); }); it('should generate main.js', async () => { @@ -25,7 +28,7 @@ describe('configureMain', () => { }, }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [mainConfigPath, mainConfigContent] = calls[0]; expect(mainConfigPath).toEqual('./.storybook/main.js'); @@ -54,7 +57,7 @@ describe('configureMain', () => { }, }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [mainConfigPath, mainConfigContent] = calls[0]; expect(mainConfigPath).toEqual('./.storybook/main.ts'); @@ -89,7 +92,7 @@ describe('configureMain', () => { }, }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [mainConfigPath, mainConfigContent] = calls[0]; expect(mainConfigPath).toEqual('./.storybook/main.js'); @@ -123,7 +126,7 @@ describe('configurePreview', () => { rendererId: 'react', }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [previewConfigPath, previewConfigContent] = calls[0]; expect(previewConfigPath).toEqual('./.storybook/preview.js'); @@ -152,7 +155,7 @@ describe('configurePreview', () => { rendererId: 'react', }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [previewConfigPath, previewConfigContent] = calls[0]; expect(previewConfigPath).toEqual('./.storybook/preview.ts'); @@ -176,13 +179,13 @@ describe('configurePreview', () => { }); it('should not do anything if the framework template already included a preview', async () => { - vi.mocked(fse.pathExists).mockImplementationOnce(() => Promise.resolve(true)); + vi.mocked(fsp.stat).mockResolvedValueOnce({} as Stats); await configurePreview({ language: SupportedLanguage.TYPESCRIPT_4_9, storybookConfigFolder: '.storybook', rendererId: 'react', }); - expect(fse.writeFile).not.toHaveBeenCalled(); + expect(fsp.writeFile).not.toHaveBeenCalled(); }); it('should add prefix if frameworkParts are passed', async () => { @@ -199,7 +202,7 @@ describe('configurePreview', () => { }, }); - const { calls } = vi.mocked(fse.writeFile).mock; + const { calls } = vi.mocked(fsp.writeFile).mock; const [previewConfigPath, previewConfigContent] = calls[0]; expect(previewConfigPath).toEqual('./.storybook/preview.ts'); diff --git a/code/lib/create-storybook/src/generators/configure.ts b/code/lib/create-storybook/src/generators/configure.ts index 94304f4c2d06..c7002c58c045 100644 --- a/code/lib/create-storybook/src/generators/configure.ts +++ b/code/lib/create-storybook/src/generators/configure.ts @@ -1,9 +1,9 @@ +import { stat, writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; import { SupportedLanguage, externalFrameworks } from 'storybook/internal/cli'; import { logger } from 'storybook/internal/node-logger'; -import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; interface ConfigureMainOptions { @@ -35,6 +35,12 @@ interface ConfigurePreviewOptions { rendererId: string; } +const pathExists = async (path: string) => { + return stat(path) + .then(() => true) + .catch(() => false); +}; + /** * We need to clean up the paths in case of pnp input: * `path.dirname(require.resolve(path.join('@storybook/react-webpack5', 'package.json')))` output: @@ -59,7 +65,7 @@ export async function configureMain({ ...custom }: ConfigureMainOptions) { const srcPath = resolve(storybookConfigFolder, '../src'); - const prefix = (await fse.pathExists(srcPath)) ? '../src' : '../stories'; + const prefix = (await pathExists(srcPath)) ? '../src' : '../stories'; const config = { stories: [`${prefix}/**/*.mdx`, `${prefix}/**/*.stories.@(${extensions.join('|')})`], addons, @@ -114,7 +120,7 @@ export async function configureMain({ logger.verbose(`Failed to prettify ${mainPath}`); } - await fse.writeFile(mainPath, mainJsContents, { encoding: 'utf8' }); + await writeFile(mainPath, mainJsContents, { encoding: 'utf8' }); } export async function configurePreview(options: ConfigurePreviewOptions) { @@ -134,7 +140,7 @@ export async function configurePreview(options: ConfigurePreviewOptions) { const previewPath = `./${options.storybookConfigFolder}/preview.${isTypescript ? 'ts' : 'js'}`; // If the framework template included a preview then we have nothing to do - if (await fse.pathExists(previewPath)) { + if (await pathExists(previewPath)) { return; } @@ -177,5 +183,5 @@ export async function configurePreview(options: ConfigurePreviewOptions) { logger.verbose(`Failed to prettify ${previewPath}`); } - await fse.writeFile(previewPath, preview, { encoding: 'utf8' }); + await writeFile(previewPath, preview, { encoding: 'utf8' }); } diff --git a/code/lib/create-storybook/src/scaffold-new-project.ts b/code/lib/create-storybook/src/scaffold-new-project.ts index f80ff2281f23..f2d64fa794bd 100644 --- a/code/lib/create-storybook/src/scaffold-new-project.ts +++ b/code/lib/create-storybook/src/scaffold-new-project.ts @@ -1,3 +1,6 @@ +import { readdirSync } from 'node:fs'; +import { rm } from 'node:fs/promises'; + import type { PackageManagerName } from 'storybook/internal/common'; import { logger } from 'storybook/internal/node-logger'; import { GenerateNewProjectOnInitError } from 'storybook/internal/server-errors'; @@ -6,7 +9,6 @@ import { telemetry } from 'storybook/internal/telemetry'; import boxen from 'boxen'; import chalk from 'chalk'; import execa from 'execa'; -import { readdirSync, remove } from 'fs-extra'; import prompts from 'prompts'; import { dedent } from 'ts-dedent'; @@ -173,7 +175,7 @@ export const scaffoldNewProject = async ( try { // If target directory has a .cache folder, remove it // so that it does not block the creation of the new project - await remove(`${targetDir}/.cache`); + await rm(`${targetDir}/.cache`, { recursive: true, force: true }); // Create new project in temp directory await execa.command(createScript, { diff --git a/code/yarn.lock b/code/yarn.lock index 9a9b1cedaa13..ce362b0e899b 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -12498,7 +12498,6 @@ __metadata: execa: "npm:^5.0.0" fd-package-json: "npm:^1.2.0" find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" ora: "npm:^5.4.1" prettier: "npm:^3.1.1" prompts: "npm:^2.4.0" From 5ed3ab439808616329a22e1959d9f8573d2ee0cf Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:31:23 +0200 Subject: [PATCH 081/213] Remove `fs-extra` from `lib/cli-storybook` --- code/__mocks__/fs/promises.ts | 34 +++++++++++++++++++ code/lib/cli-storybook/package.json | 1 - .../automigrate/fixes/eslint-plugin.test.ts | 6 ++-- .../automigrate/fixes/initial-globals.test.ts | 7 ++-- .../src/automigrate/fixes/initial-globals.ts | 3 +- .../src/automigrate/fixes/mdx-1-to-3.ts | 6 ++-- .../fixes/remove-global-client-apis.test.ts | 7 ++-- .../fixes/remove-global-client-apis.ts | 5 +-- .../cli-storybook/src/automigrate/index.ts | 7 ++-- code/lib/cli-storybook/src/doctor/index.ts | 7 ++-- code/lib/cli-storybook/src/link.ts | 12 ++++--- code/lib/cli-storybook/src/sandbox.ts | 3 +- code/yarn.lock | 1 - 13 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 code/__mocks__/fs/promises.ts diff --git a/code/__mocks__/fs/promises.ts b/code/__mocks__/fs/promises.ts new file mode 100644 index 000000000000..44a0bbd1a516 --- /dev/null +++ b/code/__mocks__/fs/promises.ts @@ -0,0 +1,34 @@ +import { vi } from 'vitest'; + +// This is a custom function that our tests can use during setup to specify +// what the files on the "mock" filesystem should look like when any of the +// `fs` APIs are used. +let mockFiles = Object.create(null); + +// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention +export function __setMockFiles(newMockFiles: Record) { + mockFiles = newMockFiles; +} + +// A custom version of `readdirSync` that reads from the special mocked out +// file list set via __setMockFiles +export const writeFile = vi.fn(async (filePath: string, content: string) => { + mockFiles[filePath] = content; +}); +export const readFile = vi.fn(async (filePath: string) => mockFiles[filePath]); +export const lstat = vi.fn(async (filePath: string) => ({ + isFile: () => !!mockFiles[filePath], +})); +export const readdir = vi.fn(); +export const readlink = vi.fn(); +export const realpath = vi.fn(); + +export default { + __setMockFiles, + writeFile, + readFile, + lstat, + readdir, + readlink, + realpath, +}; diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index 5e13a89d5b30..7623c68b2f4d 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -51,7 +51,6 @@ "envinfo": "^7.7.3", "fd-package-json": "^1.2.0", "find-up": "^5.0.0", - "fs-extra": "^11.1.0", "giget": "^1.0.0", "glob": "^10.0.0", "globby": "^14.0.1", diff --git a/code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.test.ts index 2120abd7098f..5c8bee41c2f0 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.test.ts @@ -1,17 +1,17 @@ /* eslint-disable no-underscore-dangle */ import * as fs from 'node:fs'; +import * as fsp from 'node:fs/promises'; import { describe, expect, it, vi } from 'vitest'; import type { PackageJson } from 'storybook/internal/common'; -import * as fsExtra from 'fs-extra'; import { dedent } from 'ts-dedent'; import { makePackageManager } from '../helpers/testing-helpers'; import { eslintPlugin } from './eslint-plugin'; -vi.mock('fs-extra', async () => import('../../../../../__mocks__/fs-extra')); +vi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises')); vi.mock('fs'); const checkEslint = async ({ @@ -23,7 +23,7 @@ const checkEslint = async ({ hasEslint?: boolean; eslintExtension?: string; }) => { - vi.mocked(fsExtra as any).__setMockFiles({ + vi.mocked(fsp as any).__setMockFiles({ [`.eslintrc.${eslintExtension}`]: !hasEslint ? null : dedent(` diff --git a/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.test.ts index e74d5ce810da..b78a80fe79b3 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.test.ts @@ -1,17 +1,16 @@ /* eslint-disable no-underscore-dangle */ +import * as fsp from 'node:fs/promises'; import { join } from 'node:path'; import { expect, it, vi } from 'vitest'; -import * as fsExtra from 'fs-extra'; - import { initialGlobals } from './initial-globals'; -vi.mock('fs-extra', async () => import('../../../../../__mocks__/fs-extra')); +vi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises')); const previewConfigPath = join('.storybook', 'preview.js'); const check = async (previewContents: string) => { - vi.mocked(fsExtra as any).__setMockFiles({ + vi.mocked(fsp as any).__setMockFiles({ [previewConfigPath]: previewContents, }); return initialGlobals.check({ diff --git a/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.ts b/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.ts index d4a96033a8c5..fe40749ffa16 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/initial-globals.ts @@ -1,9 +1,10 @@ +import { readFile, writeFile } from 'node:fs/promises'; + import type { ConfigFile } from 'storybook/internal/csf-tools'; import { formatConfig, loadConfig } from 'storybook/internal/csf-tools'; import type { Expression } from '@babel/types'; import chalk from 'chalk'; -import { readFile, writeFile } from 'fs-extra'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts b/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts index 221edd9298e0..d5277a5e8c92 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts @@ -1,7 +1,7 @@ +import { readFile, writeFile } from 'node:fs/promises'; import { basename } from 'node:path'; import chalk from 'chalk'; -import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; @@ -74,14 +74,14 @@ export const mdx1to3: Fix = { async run({ result: { storiesMdxFiles }, dryRun }) { await Promise.all([ ...storiesMdxFiles.map(async (fname) => { - const contents = await fse.readFile(fname, 'utf-8'); + const contents = await readFile(fname, { encoding: 'utf-8' }); const updated = fixMdxComments(fixMdxStyleTags(contents)); if (updated === contents) { logger.info(`🆗 Unmodified ${basename(fname)}`); } else { logger.info(`✅ Modified ${basename(fname)}`); if (!dryRun) { - await fse.writeFile(fname, updated); + await writeFile(fname, updated); } } }), diff --git a/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.test.ts index 6ae48ad95018..3e1af96c38f6 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.test.ts @@ -1,19 +1,18 @@ /* eslint-disable no-underscore-dangle */ +import * as fsp from 'node:fs/promises'; import { join } from 'node:path'; import { describe, expect, it, vi } from 'vitest'; import type { JsPackageManager } from 'storybook/internal/common'; -import * as fsExtra from 'fs-extra'; - import { RemovedAPIs, removedGlobalClientAPIs as migration } from './remove-global-client-apis'; -vi.mock('fs-extra', async () => import('../../../../../__mocks__/fs-extra')); +vi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises')); const check = async ({ contents, previewConfigPath }: any) => { if (contents) { - vi.mocked(fsExtra as any).__setMockFiles({ + vi.mocked(fsp as any).__setMockFiles({ [join('.storybook', 'preview.js')]: contents, }); } diff --git a/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.ts b/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.ts index 232ac4fea188..e7caf9027d4b 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/remove-global-client-apis.ts @@ -1,5 +1,6 @@ +import { readFile } from 'node:fs/promises'; + import chalk from 'chalk'; -import { readFile } from 'fs-extra'; import { dedent } from 'ts-dedent'; import type { Fix } from '../types'; @@ -26,7 +27,7 @@ export const removedGlobalClientAPIs: Fix = { async check({ previewConfigPath }) { if (previewConfigPath) { - const contents = await readFile(previewConfigPath, 'utf8'); + const contents = await readFile(previewConfigPath, { encoding: 'utf8' }); const usedAPIs = Object.values(RemovedAPIs).reduce((acc, item) => { if (contents.includes(item)) { diff --git a/code/lib/cli-storybook/src/automigrate/index.ts b/code/lib/cli-storybook/src/automigrate/index.ts index 690c3d1b15f7..ff727783dff3 100644 --- a/code/lib/cli-storybook/src/automigrate/index.ts +++ b/code/lib/cli-storybook/src/automigrate/index.ts @@ -1,3 +1,5 @@ +import { createWriteStream } from 'node:fs'; +import { rename, rm } from 'node:fs/promises'; import { join } from 'node:path'; import { @@ -10,7 +12,6 @@ import { import boxen from 'boxen'; import chalk from 'chalk'; -import { createWriteStream, move, remove } from 'fs-extra'; import prompts from 'prompts'; import semver from 'semver'; import invariant from 'tiny-invariant'; @@ -182,9 +183,9 @@ export const automigrate = async ({ // if migration failed, display a log file in the users cwd if (hasFailures) { - await move(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME), { overwrite: true }); + await rename(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME)); } else { - await remove(TEMP_LOG_FILE_PATH); + await rm(TEMP_LOG_FILE_PATH, { recursive: true, force: true }); } if (!hideMigrationSummary) { diff --git a/code/lib/cli-storybook/src/doctor/index.ts b/code/lib/cli-storybook/src/doctor/index.ts index 08e798288753..53439e244f00 100644 --- a/code/lib/cli-storybook/src/doctor/index.ts +++ b/code/lib/cli-storybook/src/doctor/index.ts @@ -1,3 +1,5 @@ +import { createWriteStream } from 'node:fs'; +import { rename, rm } from 'node:fs/promises'; import { join } from 'node:path'; import { JsPackageManagerFactory, temporaryFile } from 'storybook/internal/common'; @@ -5,7 +7,6 @@ import type { PackageManagerName } from 'storybook/internal/common'; import boxen from 'boxen'; import chalk from 'chalk'; -import { createWriteStream, move, remove } from 'fs-extra'; import { dedent } from 'ts-dedent'; import { cleanLog } from '../automigrate/helpers/cleanLog'; @@ -161,11 +162,11 @@ export const doctor = async ({ logger.info(`Full logs are available in ${chalk.cyan(LOG_FILE_PATH)}`); - await move(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME), { overwrite: true }); + await rename(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME)); } else { logger.info(`🥳 Your Storybook project looks good!`); logger.info(commandMessage); - await remove(TEMP_LOG_FILE_PATH); + await rm(TEMP_LOG_FILE_PATH, { recursive: true, force: true }); } logger.info(); diff --git a/code/lib/cli-storybook/src/link.ts b/code/lib/cli-storybook/src/link.ts index 369d668d2c2a..a858847e26b2 100644 --- a/code/lib/cli-storybook/src/link.ts +++ b/code/lib/cli-storybook/src/link.ts @@ -1,10 +1,10 @@ +import { mkdir, readFile } from 'node:fs/promises'; import { basename, extname, join } from 'node:path'; import { logger } from 'storybook/internal/node-logger'; import chalk from 'chalk'; import { spawn as spawnAsync, sync as spawnSync } from 'cross-spawn'; -import fse from 'fs-extra'; type ExecOptions = Parameters[2]; @@ -61,7 +61,7 @@ export const exec = async ( export const link = async ({ target, local, start }: LinkOptions) => { const storybookDir = process.cwd(); try { - const packageJson = await fse.readJSON('package.json'); + const packageJson = JSON.parse(await readFile('package.json', { encoding: 'utf-8' })); if (packageJson.name !== '@storybook/root') { throw new Error(); } @@ -75,7 +75,9 @@ export const link = async ({ target, local, start }: LinkOptions) => { if (!local) { const reprosDir = join(storybookDir, '../storybook-repros'); logger.info(`Ensuring directory ${reprosDir}`); - await fse.ensureDir(reprosDir); + // Passing `recursive: true` ensures that the method doesn't throw when + // the directory already exists. + await mkdir(reprosDir, { recursive: true }); logger.info(`Cloning ${target}`); await exec(`git clone ${target}`, { cwd: reprosDir }); @@ -84,7 +86,9 @@ export const link = async ({ target, local, start }: LinkOptions) => { reproDir = join(reprosDir, reproName); } - const reproPackageJson = await fse.readJSON(join(reproDir, 'package.json')); + const reproPackageJson = JSON.parse( + await readFile(join(reproDir, 'package.json'), { encoding: 'utf-8' }) + ); const version = spawnSync('yarn', ['--version'], { cwd: reproDir, diff --git a/code/lib/cli-storybook/src/sandbox.ts b/code/lib/cli-storybook/src/sandbox.ts index a6b4fe40f043..4bbe097d7d16 100644 --- a/code/lib/cli-storybook/src/sandbox.ts +++ b/code/lib/cli-storybook/src/sandbox.ts @@ -1,3 +1,5 @@ +import { existsSync } from 'node:fs'; +import { readdir } from 'node:fs/promises'; import { isAbsolute, join } from 'node:path'; import type { PackageManagerName } from 'storybook/internal/common'; @@ -7,7 +9,6 @@ import { versions } from 'storybook/internal/common'; import boxen from 'boxen'; import chalk from 'chalk'; import { initiate } from 'create-storybook'; -import { existsSync, readdir } from 'fs-extra'; import { downloadTemplate } from 'giget'; import prompts from 'prompts'; import { lt, prerelease } from 'semver'; diff --git a/code/yarn.lock b/code/yarn.lock index ce362b0e899b..997e639d2e70 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5896,7 +5896,6 @@ __metadata: envinfo: "npm:^7.7.3" fd-package-json: "npm:^1.2.0" find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" giget: "npm:^1.0.0" glob: "npm:^10.0.0" globby: "npm:^14.0.1" From 2e89262e63c10c41d5b24484dc1a0139efc1496f Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:32:21 +0200 Subject: [PATCH 082/213] Remove `fs-extra` from `frameworks/nextjs` --- code/frameworks/nextjs/package.json | 1 - code/yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 856982c811dd..6b28e51f8e7b 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -148,7 +148,6 @@ "babel-loader": "^9.1.3", "css-loader": "^6.7.3", "find-up": "^5.0.0", - "fs-extra": "^11.1.0", "image-size": "^1.0.0", "loader-utils": "^3.2.1", "node-polyfill-webpack-plugin": "^2.0.1", diff --git a/code/yarn.lock b/code/yarn.lock index 997e639d2e70..3115e30df1dd 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6433,7 +6433,6 @@ __metadata: babel-loader: "npm:^9.1.3" css-loader: "npm:^6.7.3" find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" image-size: "npm:^1.0.0" loader-utils: "npm:^3.2.1" next: "npm:^14.1.0" From b080e7153ac422cb9667dd6adacee405929e67e8 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:38:45 +0200 Subject: [PATCH 083/213] Remove `fs-extra` from `builders/builder-webpack5` --- code/builders/builder-webpack5/package.json | 1 - code/builders/builder-webpack5/src/index.ts | 6 ++++-- code/yarn.lock | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index 913991d99689..2d4c5330bd01 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -74,7 +74,6 @@ "es-module-lexer": "^1.5.0", "express": "^4.19.2", "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", "html-webpack-plugin": "^5.5.0", "magic-string": "^0.30.5", "path-browserify": "^1.0.1", diff --git a/code/builders/builder-webpack5/src/index.ts b/code/builders/builder-webpack5/src/index.ts index f9a83f8efaf2..7d12dabb4b6f 100644 --- a/code/builders/builder-webpack5/src/index.ts +++ b/code/builders/builder-webpack5/src/index.ts @@ -1,3 +1,4 @@ +import { cp } from 'node:fs/promises'; import { join, parse } from 'node:path'; import { PREVIEW_BUILDER_PROGRESS } from 'storybook/internal/core-events'; @@ -12,7 +13,6 @@ import type { Builder, Options } from 'storybook/internal/types'; import { checkWebpackVersion } from '@storybook/core-webpack'; import express from 'express'; -import fs from 'fs-extra'; import prettyTime from 'pretty-hrtime'; import { corePath } from 'storybook/core-path'; import type { Configuration, Stats, StatsOptions } from 'webpack'; @@ -292,7 +292,9 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, const previewDirOrigin = previewResolvedDir; const previewDirTarget = join(options.outputDir || '', `sb-preview`); - const previewFiles = fs.copy(previewDirOrigin, previewDirTarget, { + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. + const previewFiles = cp(previewDirOrigin, previewDirTarget, { filter: (src) => { const { ext } = parse(src); if (ext) { diff --git a/code/yarn.lock b/code/yarn.lock index 3115e30df1dd..66d1f39375f7 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5843,7 +5843,6 @@ __metadata: es-module-lexer: "npm:^1.5.0" express: "npm:^4.19.2" fork-ts-checker-webpack-plugin: "npm:^8.0.0" - fs-extra: "npm:^11.1.0" html-webpack-plugin: "npm:^5.5.0" magic-string: "npm:^0.30.5" path-browserify: "npm:^1.0.1" From b9c600ad157e6e949b0111336b90036d01dbb5ef Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:44:12 +0200 Subject: [PATCH 084/213] Remove `fs-extra` from `builders/builder-vite` --- code/builders/builder-vite/package.json | 1 - code/builders/builder-vite/src/index.ts | 13 +++++++------ .../src/plugins/external-globals-plugin.ts | 8 ++++++-- code/yarn.lock | 1 - 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index 5c8bd9b47ea1..94fde0bf8cfb 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -49,7 +49,6 @@ "es-module-lexer": "^1.5.0", "express": "^4.19.2", "find-cache-dir": "^3.0.0", - "fs-extra": "^11.1.0", "magic-string": "^0.30.0", "ts-dedent": "^2.0.0" }, diff --git a/code/builders/builder-vite/src/index.ts b/code/builders/builder-vite/src/index.ts index a8a775a13344..fb841b1c473d 100644 --- a/code/builders/builder-vite/src/index.ts +++ b/code/builders/builder-vite/src/index.ts @@ -1,4 +1,5 @@ // noinspection JSUnusedGlobalSymbols +import { cp, readFile } from 'node:fs/promises'; import { join, parse } from 'node:path'; import { NoStatsForViteDevError } from 'storybook/internal/server-errors'; @@ -6,7 +7,6 @@ import type { Options } from 'storybook/internal/types'; import type { RequestHandler } from 'express'; import express from 'express'; -import * as fs from 'fs-extra'; import { corePath } from 'storybook/core-path'; import type { ViteDevServer } from 'vite'; @@ -34,10 +34,9 @@ function iframeMiddleware(options: Options, server: ViteDevServer): RequestHandl return; } - const indexHtml = await fs.readFile( - require.resolve('@storybook/builder-vite/input/iframe.html'), - 'utf-8' - ); + const indexHtml = await readFile(require.resolve('@storybook/builder-vite/input/iframe.html'), { + encoding: 'utf-8', + }); const generated = await transformIframeHtml(indexHtml, options); const transformed = await server.transformIndexHtml('/iframe.html', generated); res.setHeader('Content-Type', 'text/html'); @@ -85,7 +84,9 @@ export const build: ViteBuilder['build'] = async ({ options }) => { const previewDirOrigin = previewResolvedDir; const previewDirTarget = join(options.outputDir || '', `sb-preview`); - const previewFiles = fs.copy(previewDirOrigin, previewDirTarget, { + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. + const previewFiles = cp(previewDirOrigin, previewDirTarget, { filter: (src) => { const { ext } = parse(src); if (ext) { diff --git a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts index a71f9f3b0fe8..f7798ccff136 100644 --- a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts +++ b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts @@ -1,8 +1,10 @@ +import { existsSync, openSync } from 'node:fs'; +import { writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { init, parse } from 'es-module-lexer'; import findCacheDirectory from 'find-cache-dir'; -import { ensureFile, writeFile } from 'fs-extra'; +import { ensureFile } from 'fs-extra'; import MagicString from 'magic-string'; import type { Alias, Plugin } from 'vite'; @@ -59,7 +61,9 @@ export async function externalGlobalsPlugin(externals: Record) { (Object.keys(externals) as Array).map(async (externalKey) => { const externalCachePath = join(cachePath, `${externalKey}.js`); newAlias.push({ find: new RegExp(`^${externalKey}$`), replacement: externalCachePath }); - await ensureFile(externalCachePath); + if (!existsSync(externalCachePath)) { + openSync(externalCachePath, 'w'); + } await writeFile(externalCachePath, `module.exports = ${externals[externalKey]};`); }) ); diff --git a/code/yarn.lock b/code/yarn.lock index 66d1f39375f7..99ad7d5bdb79 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5802,7 +5802,6 @@ __metadata: es-module-lexer: "npm:^1.5.0" express: "npm:^4.19.2" find-cache-dir: "npm:^3.0.0" - fs-extra: "npm:^11.1.0" glob: "npm:^10.0.0" magic-string: "npm:^0.30.0" slash: "npm:^5.0.0" From 67dbe11f02d5c4b8978769e586adb315069572b6 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:45:28 +0200 Subject: [PATCH 085/213] Remove `fs-extra` from `addons/docs` --- code/addons/docs/package.json | 1 - code/yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index d905b004df47..7e38a4d00383 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -103,7 +103,6 @@ "@storybook/global": "^5.0.0", "@storybook/react-dom-shim": "workspace:*", "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "fs-extra": "^11.1.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "rehype-external-links": "^3.0.0", diff --git a/code/yarn.lock b/code/yarn.lock index 99ad7d5bdb79..70a5397e0d27 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5437,7 +5437,6 @@ __metadata: "@storybook/global": "npm:^5.0.0" "@storybook/react-dom-shim": "workspace:*" "@types/react": "npm:^16.8.0 || ^17.0.0 || ^18.0.0" - fs-extra: "npm:^11.1.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" rehype-external-links: "npm:^3.0.0" From cf80eaa1889424ccf0db50a156ef69ac02c4bdde Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 13:46:23 +0200 Subject: [PATCH 086/213] Remove rogue import in `builders/builder-vite` --- .../builders/builder-vite/src/plugins/external-globals-plugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts index f7798ccff136..7813e1c50030 100644 --- a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts +++ b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts @@ -4,7 +4,6 @@ import { join } from 'node:path'; import { init, parse } from 'es-module-lexer'; import findCacheDirectory from 'find-cache-dir'; -import { ensureFile } from 'fs-extra'; import MagicString from 'magic-string'; import type { Alias, Plugin } from 'vite'; From 353dfb10a28b64902d0c163e5863d913504fd35b Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 14:05:40 +0200 Subject: [PATCH 087/213] Remove rogue comment --- code/__mocks__/fs/promises.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/__mocks__/fs/promises.ts b/code/__mocks__/fs/promises.ts index 44a0bbd1a516..d6673a26e648 100644 --- a/code/__mocks__/fs/promises.ts +++ b/code/__mocks__/fs/promises.ts @@ -10,8 +10,6 @@ export function __setMockFiles(newMockFiles: Record) { mockFiles = newMockFiles; } -// A custom version of `readdirSync` that reads from the special mocked out -// file list set via __setMockFiles export const writeFile = vi.fn(async (filePath: string, content: string) => { mockFiles[filePath] = content; }); From 08c6eef3ffeea4081e67acbec140919b3bbcdd9c Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 18:18:49 +0200 Subject: [PATCH 088/213] Remove `fs-extra` from `presets/server-webpack` --- code/presets/server-webpack/package.json | 1 - .../src/lib/compiler/json-to-csf-compiler.test.ts | 7 ++++--- code/yarn.lock | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json index 48fc4ac5927c..0dcf0288a02e 100644 --- a/code/presets/server-webpack/package.json +++ b/code/presets/server-webpack/package.json @@ -63,7 +63,6 @@ "yaml-loader": "^0.8.0" }, "devDependencies": { - "fs-extra": "^11.1.0", "typescript": "^5.3.2", "yaml": "^2.3.1" }, diff --git a/code/presets/server-webpack/src/lib/compiler/json-to-csf-compiler.test.ts b/code/presets/server-webpack/src/lib/compiler/json-to-csf-compiler.test.ts index 0c44665bdc25..f0d8237215cb 100644 --- a/code/presets/server-webpack/src/lib/compiler/json-to-csf-compiler.test.ts +++ b/code/presets/server-webpack/src/lib/compiler/json-to-csf-compiler.test.ts @@ -1,14 +1,15 @@ +import { readdirSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; -import fs from 'fs-extra'; import YAML from 'yaml'; import { compileCsfModule } from '.'; async function generate(filePath: string) { - const content = await fs.readFile(filePath, 'utf8'); + const content = await readFile(filePath, { encoding: 'utf8' }); const parsed = filePath.endsWith('.json') ? JSON.parse(content) : YAML.parse(content); return compileCsfModule(parsed); } @@ -18,7 +19,7 @@ async function generate(filePath: string) { describe(`${fileType}-to-csf-compiler`, () => { const transformFixturesDir = join(__dirname, '__testfixtures__'); - fs.readdirSync(transformFixturesDir) + readdirSync(transformFixturesDir) .filter((fileName: string) => inputRegExp.test(fileName)) .forEach((fixtureFile: string) => { it(`${fixtureFile}`, async () => { diff --git a/code/yarn.lock b/code/yarn.lock index f8bffd7aee76..2b753fe187ab 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6604,7 +6604,6 @@ __metadata: "@storybook/global": "npm:^5.0.0" "@storybook/server": "workspace:*" "@types/node": "npm:^22.0.0" - fs-extra: "npm:^11.1.0" safe-identifier: "npm:^0.4.1" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" From a09abbc1c8d25d12f36cd4333ba6c5adf57a471a Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 18:32:26 +0200 Subject: [PATCH 089/213] Remove `fs-extra` from `renderers/svelte` VS Code complains about not being able to find Node types, but building the package works. Need to investigate. --- code/renderers/svelte/package.json | 1 - code/renderers/svelte/scripts/copy-unbundled-to-dist.ts | 5 +++-- code/yarn.lock | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index aa804d3d0ce6..5972c0ef2ac8 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -68,7 +68,6 @@ "@sveltejs/vite-plugin-svelte": "^3.0.2", "@testing-library/svelte": "patch:@testing-library/svelte@npm%3A4.1.0#~/.yarn/patches/@testing-library-svelte-npm-4.1.0-34b7037bc0.patch", "expect-type": "^0.15.0", - "fs-extra": "^11.1.0", "svelte": "^5.0.0-next.65", "svelte-check": "^3.6.4", "typescript": "^5.3.2" diff --git a/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts b/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts index a82964679960..0444a5960183 100644 --- a/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts +++ b/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts @@ -1,4 +1,5 @@ -import { copy } from 'fs-extra'; +import { cp } from 'node:fs/promises'; + import { join } from 'path'; const src = join(__dirname, '..', 'src'); @@ -11,7 +12,7 @@ const run = async () => { console.log('Copying unbundled files to dist...'); await Promise.all( PATHS_TO_COPY.map((pathToCopy) => - copy(join(src, pathToCopy), join(dist, pathToCopy), { overwrite: true }) + cp(join(src, pathToCopy), join(dist, pathToCopy), { recursive: true, force: true }) ) ); console.log('Done!'); diff --git a/code/yarn.lock b/code/yarn.lock index 2b753fe187ab..a3672777a19b 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -7052,7 +7052,6 @@ __metadata: "@sveltejs/vite-plugin-svelte": "npm:^3.0.2" "@testing-library/svelte": "patch:@testing-library/svelte@npm%3A4.1.0#~/.yarn/patches/@testing-library-svelte-npm-4.1.0-34b7037bc0.patch" expect-type: "npm:^0.15.0" - fs-extra: "npm:^11.1.0" svelte: "npm:^5.0.0-next.65" svelte-check: "npm:^3.6.4" sveltedoc-parser: "npm:^4.2.1" From 93b866b4a1ee7c345421568f7ab13eb4b07213f2 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 18:37:15 +0200 Subject: [PATCH 090/213] Remove `fs-extra` from `addons/links` VS Code complains about not being able to find Node types, but building the package works. Need to investigate. --- code/addons/links/package.json | 1 - code/addons/links/scripts/fix-preview-api-reference.ts | 2 +- code/yarn.lock | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/code/addons/links/package.json b/code/addons/links/package.json index c11fa3e056b3..ca95baea88ac 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -71,7 +71,6 @@ "ts-dedent": "^2.0.0" }, "devDependencies": { - "fs-extra": "^11.1.0", "typescript": "^5.3.2" }, "peerDependencies": { diff --git a/code/addons/links/scripts/fix-preview-api-reference.ts b/code/addons/links/scripts/fix-preview-api-reference.ts index 71ca667999e2..90d54704768d 100644 --- a/code/addons/links/scripts/fix-preview-api-reference.ts +++ b/code/addons/links/scripts/fix-preview-api-reference.ts @@ -1,4 +1,4 @@ -import { readFile, writeFile } from 'fs-extra'; +import { readFile, writeFile } from 'node:fs/promises'; /* I wish this wasn't needed.. * There seems to be some bug in tsup / the unlaying lib that does DTS bundling diff --git a/code/yarn.lock b/code/yarn.lock index a3672777a19b..e477552d26d5 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5527,7 +5527,6 @@ __metadata: dependencies: "@storybook/csf": "npm:^0.1.11" "@storybook/global": "npm:^5.0.0" - fs-extra: "npm:^11.1.0" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" peerDependencies: From 7c14a13412fd5bed24074145b7ef79d372319b43 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 18:59:18 +0200 Subject: [PATCH 091/213] core: Remove `fs-extra` from `src/telemetry` --- code/__mocks__/fs.js | 29 ----------------- code/__mocks__/fs.ts | 32 +++++++++++++++++++ .../src/telemetry/get-monorepo-type.test.ts | 7 ++-- code/core/src/telemetry/get-monorepo-type.ts | 7 ++-- code/core/src/telemetry/package-json.ts | 5 ++- 5 files changed, 41 insertions(+), 39 deletions(-) delete mode 100644 code/__mocks__/fs.js create mode 100644 code/__mocks__/fs.ts diff --git a/code/__mocks__/fs.js b/code/__mocks__/fs.js deleted file mode 100644 index 9e608c3ff038..000000000000 --- a/code/__mocks__/fs.js +++ /dev/null @@ -1,29 +0,0 @@ -import { vi } from 'vitest'; - -const fs = vi.createMockFromModule('fs'); - -// This is a custom function that our tests can use during setup to specify -// what the files on the "mock" filesystem should look like when any of the -// `fs` APIs are used. -let mockFiles = Object.create(null); - -// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention -function __setMockFiles(newMockFiles) { - mockFiles = newMockFiles; -} - -// A custom version of `readdirSync` that reads from the special mocked out -// file list set via __setMockFiles -const readFileSync = (filePath = '') => mockFiles[filePath]; -const existsSync = (filePath) => !!mockFiles[filePath]; -const lstatSync = (filePath) => ({ - isFile: () => !!mockFiles[filePath], -}); - -// eslint-disable-next-line no-underscore-dangle -fs.__setMockFiles = __setMockFiles; -fs.readFileSync = readFileSync; -fs.existsSync = existsSync; -fs.lstatSync = lstatSync; - -module.exports = fs; diff --git a/code/__mocks__/fs.ts b/code/__mocks__/fs.ts new file mode 100644 index 000000000000..50e34e8e4ca1 --- /dev/null +++ b/code/__mocks__/fs.ts @@ -0,0 +1,32 @@ +import { vi } from 'vitest'; + +// This is a custom function that our tests can use during setup to specify +// what the files on the "mock" filesystem should look like when any of the +// `fs` APIs are used. +let mockFiles = Object.create(null); + +// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention +export function __setMockFiles(newMockFiles: Record) { + mockFiles = newMockFiles; +} + +export const readFileSync = (filePath = '') => mockFiles[filePath]; +export const existsSync = (filePath: string) => !!mockFiles[filePath]; +export const lstatSync = (filePath: string) => ({ + isFile: () => !!mockFiles[filePath], +}); +export const realpathSync = vi.fn(); +export const readdir = vi.fn(); +export const readdirSync = vi.fn(); +export const readlinkSync = vi.fn(); + +export default { + __setMockFiles, + readFileSync, + existsSync, + lstatSync, + realpathSync, + readdir, + readdirSync, + readlinkSync, +}; diff --git a/code/core/src/telemetry/get-monorepo-type.test.ts b/code/core/src/telemetry/get-monorepo-type.test.ts index 530da9f4abc9..3f8ecfca723a 100644 --- a/code/core/src/telemetry/get-monorepo-type.test.ts +++ b/code/core/src/telemetry/get-monorepo-type.test.ts @@ -1,13 +1,12 @@ /* eslint-disable no-underscore-dangle */ +import * as fs from 'node:fs'; import { join } from 'node:path'; import { describe, expect, it, vi } from 'vitest'; -import * as fsExtra from 'fs-extra'; - import { getMonorepoType, monorepoConfigs } from './get-monorepo-type'; -vi.mock('fs-extra', async () => import('../../../__mocks__/fs-extra')); +vi.mock('node:fs', async () => import('../../../__mocks__/fs')); vi.mock('@storybook/core/common', async (importOriginal) => { return { @@ -25,7 +24,7 @@ const checkMonorepoType = ({ monorepoConfigFile, isYarnWorkspace = false }: any) mockFiles[join('root', monorepoConfigFile)] = '{}'; } - vi.mocked(fsExtra as any).__setMockFiles(mockFiles); + vi.mocked(fs as any).__setMockFiles(mockFiles); return getMonorepoType(); }; diff --git a/code/core/src/telemetry/get-monorepo-type.ts b/code/core/src/telemetry/get-monorepo-type.ts index 41dcc0087044..e004365fcbb0 100644 --- a/code/core/src/telemetry/get-monorepo-type.ts +++ b/code/core/src/telemetry/get-monorepo-type.ts @@ -1,10 +1,9 @@ +import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; import { getProjectRoot } from '@storybook/core/common'; import type { PackageJson } from '@storybook/core/types'; -import { existsSync, readJsonSync } from 'fs-extra'; - export const monorepoConfigs = { Nx: 'nx.json', Turborepo: 'turbo.json', @@ -36,7 +35,9 @@ export const getMonorepoType = (): MonorepoType => { return undefined; } - const packageJson = readJsonSync(join(projectRootPath, 'package.json')) as PackageJson; + const packageJson = JSON.parse( + readFileSync(join(projectRootPath, 'package.json'), { encoding: 'utf-8' }) + ) as PackageJson; if (packageJson?.workspaces) { return 'Workspaces'; diff --git a/code/core/src/telemetry/package-json.ts b/code/core/src/telemetry/package-json.ts index b88ebc237ddc..3bf006115c4a 100644 --- a/code/core/src/telemetry/package-json.ts +++ b/code/core/src/telemetry/package-json.ts @@ -1,7 +1,6 @@ +import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { readJson } from 'fs-extra'; - import type { Dependency } from './types'; export const getActualPackageVersions = async (packages: Record>) => { @@ -25,6 +24,6 @@ export const getActualPackageJson = async (packageName: string) => { const resolvedPackageJson = require.resolve(join(packageName, 'package.json'), { paths: [process.cwd()], }); - const packageJson = await readJson(resolvedPackageJson); + const packageJson = JSON.parse(await readFile(resolvedPackageJson, { encoding: 'utf-8' })); return packageJson; }; From 7816541a57b21879837664261bc0deb3e0d33a44 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:12:08 +0200 Subject: [PATCH 092/213] core: Remove `fs-extra` from `src/common/utils` --- .../src/common/js-package-manager/PNPMProxy.ts | 3 +-- code/core/src/common/utils/cli.ts | 16 +++++++--------- code/core/src/common/utils/get-storybook-info.ts | 7 ++----- code/core/src/common/utils/get-storybook-refs.ts | 8 +++++--- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/code/core/src/common/js-package-manager/PNPMProxy.ts b/code/core/src/common/js-package-manager/PNPMProxy.ts index f8df230d0fe6..3f4073c6f35e 100644 --- a/code/core/src/common/js-package-manager/PNPMProxy.ts +++ b/code/core/src/common/js-package-manager/PNPMProxy.ts @@ -4,7 +4,6 @@ import { join } from 'node:path'; import { FindPackageVersionsError } from '@storybook/core/server-errors'; import { findUpSync } from 'find-up'; -import { pathExistsSync } from 'fs-extra'; import { dedent } from 'ts-dedent'; import { createLogStream } from '../utils/cli'; @@ -42,7 +41,7 @@ export class PNPMProxy extends JsPackageManager { const CWD = process.cwd(); const pnpmWorkspaceYaml = `${CWD}/pnpm-workspace.yaml`; - return pathExistsSync(pnpmWorkspaceYaml); + return existsSync(pnpmWorkspaceYaml); } async initPackageJson() { diff --git a/code/core/src/common/utils/cli.ts b/code/core/src/common/utils/cli.ts index 00b831133d2a..05f4704360ea 100644 --- a/code/core/src/common/utils/cli.ts +++ b/code/core/src/common/utils/cli.ts @@ -1,9 +1,9 @@ -import { realpath } from 'node:fs/promises'; +import type { WriteStream } from 'node:fs'; +import { createWriteStream, mkdirSync } from 'node:fs'; +import { readFile, realpath, rename, rm, writeFile } from 'node:fs/promises'; import os from 'node:os'; import { join } from 'node:path'; -import type { WriteStream } from 'fs-extra'; -import { createWriteStream, mkdirSync, move, readFile, remove, writeFile } from 'fs-extra'; import { type MergeExclusive } from 'type-fest'; import uniqueString from 'unique-string'; @@ -17,7 +17,7 @@ const getPath = async (prefix = '') => join(await tempDir(), prefix + uniqueStri export async function temporaryDirectory({ prefix = '' } = {}) { const directory = await getPath(prefix); - await mkdirSync(directory); + mkdirSync(directory); return directory; } @@ -146,12 +146,10 @@ export const createLogStream = async ( return new Promise((resolve, reject) => { logStream.once('open', () => { - const moveLogFile = async () => move(temporaryLogPath, finalLogPath, { overwrite: true }); + const moveLogFile = async () => rename(temporaryLogPath, finalLogPath); const clearLogFile = async () => writeFile(temporaryLogPath, ''); - const removeLogFile = async () => remove(temporaryLogPath); - const readLogFile = async () => { - return readFile(temporaryLogPath, 'utf8'); - }; + const removeLogFile = async () => rm(temporaryLogPath, { recursive: true, force: true }); + const readLogFile = async () => readFile(temporaryLogPath, { encoding: 'utf8' }); resolve({ logStream, moveLogFile, clearLogFile, removeLogFile, readLogFile }); }); logStream.once('error', reject); diff --git a/code/core/src/common/utils/get-storybook-info.ts b/code/core/src/common/utils/get-storybook-info.ts index af65546949eb..a7e887a87d63 100644 --- a/code/core/src/common/utils/get-storybook-info.ts +++ b/code/core/src/common/utils/get-storybook-info.ts @@ -1,10 +1,9 @@ +import { existsSync } from 'node:fs'; import { join } from 'node:path'; import type { SupportedFrameworks } from '@storybook/core/types'; import type { CoreCommon_StorybookInfo, PackageJson } from '@storybook/core/types'; -import { pathExistsSync } from 'fs-extra'; - import { getStorybookConfiguration } from './get-storybook-configuration'; export const rendererPackages: Record = { @@ -92,9 +91,7 @@ const validConfigExtensions = ['ts', 'js', 'tsx', 'jsx', 'mjs', 'cjs']; export const findConfigFile = (prefix: string, configDir: string) => { const filePrefix = join(configDir, prefix); - const extension = validConfigExtensions.find((ext: string) => - pathExistsSync(`${filePrefix}.${ext}`) - ); + const extension = validConfigExtensions.find((ext: string) => existsSync(`${filePrefix}.${ext}`)); return extension ? `${filePrefix}.${extension}` : null; }; diff --git a/code/core/src/common/utils/get-storybook-refs.ts b/code/core/src/common/utils/get-storybook-refs.ts index 053ae17abc93..c733febf6aea 100644 --- a/code/core/src/common/utils/get-storybook-refs.ts +++ b/code/core/src/common/utils/get-storybook-refs.ts @@ -1,3 +1,4 @@ +import { readFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import type { Options, Ref } from '@storybook/core/types'; @@ -5,7 +6,6 @@ import type { Options, Ref } from '@storybook/core/types'; import { logger } from '@storybook/core/node-logger'; import { findUp } from 'find-up'; -import { readJSON } from 'fs-extra'; import resolveFrom from 'resolve-from'; export const getAutoRefs = async (options: Options): Promise> => { @@ -15,7 +15,8 @@ export const getAutoRefs = async (options: Options): Promise } const directory = dirname(location); - const { dependencies = [], devDependencies = [] } = (await readJSON(location)) || {}; + const { dependencies = [], devDependencies = [] } = + JSON.parse(await readFile(location, { encoding: 'utf-8' })) || {}; const deps = Object.keys({ ...dependencies, ...devDependencies }); const list = await Promise.all( @@ -23,7 +24,8 @@ export const getAutoRefs = async (options: Options): Promise try { const l = resolveFrom(directory, join(d, 'package.json')); - const { storybook, name, version } = (await readJSON(l)) || {}; + const { storybook, name, version } = + JSON.parse(await readFile(l, { encoding: 'utf-8' })) || {}; if (storybook?.url) { return { id: name, ...storybook, version }; From fb2455bfbab954d570e165c50f6a79eb7e16dd37 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:31:03 +0200 Subject: [PATCH 093/213] core: Remove `fs-extra` from `src/core-server/utils` --- .../src/core-server/presets/common-preset.ts | 11 +++---- .../src/core-server/presets/favicon.test.ts | 30 ++++++++----------- .../core-server/utils/StoryIndexGenerator.ts | 11 +++---- .../utils/__tests__/server-statics.test.ts | 13 ++++---- .../utils/copy-all-static-files.ts | 10 +++++-- code/core/src/core-server/utils/metadata.ts | 5 ++-- .../src/core-server/utils/output-stats.ts | 4 +-- .../core/src/core-server/utils/server-init.ts | 9 +++--- .../src/core-server/utils/server-statics.ts | 4 +-- .../src/core-server/utils/stories-json.ts | 4 +-- .../utils/warnWhenUsingArgTypesRegex.ts | 7 +++-- code/core/src/core-server/utils/whats-new.ts | 5 ++-- 12 files changed, 58 insertions(+), 55 deletions(-) diff --git a/code/core/src/core-server/presets/common-preset.ts b/code/core/src/core-server/presets/common-preset.ts index bca9a1c9cfe6..9a32187c11f6 100644 --- a/code/core/src/core-server/presets/common-preset.ts +++ b/code/core/src/core-server/presets/common-preset.ts @@ -1,3 +1,5 @@ +import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; import { dirname, isAbsolute, join } from 'node:path'; import type { Channel } from '@storybook/core/channels'; @@ -21,7 +23,6 @@ import type { import { readCsf } from '@storybook/core/csf-tools'; import { logger } from '@storybook/core/node-logger'; -import { pathExists, readFile } from 'fs-extra'; import { dedent } from 'ts-dedent'; import { initCreateNewStoryChannel } from '../server-channel/create-new-story-channel'; @@ -75,14 +76,14 @@ export const favicon = async ( if (targetEndpoint === '/') { const url = 'favicon.svg'; const path = join(staticPath, url); - if (await pathExists(path)) { + if (existsSync(path)) { results.push(path); } } if (targetEndpoint === '/') { const url = 'favicon.ico'; const path = join(staticPath, url); - if (await pathExists(path)) { + if (existsSync(path)) { results.push(path); } } @@ -256,8 +257,8 @@ export const docs: PresetProperty<'docs'> = (docsOptions, { docs: docsMode }: CL export const managerHead = async (_: any, options: Options) => { const location = join(options.configDir, 'manager-head.html'); - if (await pathExists(location)) { - const contents = readFile(location, 'utf-8'); + if (existsSync(location)) { + const contents = readFile(location, { encoding: 'utf-8' }); const interpolations = options.presets.apply>('env'); return interpolate(await contents, await interpolations); diff --git a/code/core/src/core-server/presets/favicon.test.ts b/code/core/src/core-server/presets/favicon.test.ts index 7af2bfbfb34d..4e6c72cc0618 100644 --- a/code/core/src/core-server/presets/favicon.test.ts +++ b/code/core/src/core-server/presets/favicon.test.ts @@ -1,11 +1,10 @@ +import * as fs from 'node:fs'; import { dirname, join } from 'node:path'; import { expect, it, vi } from 'vitest'; import { logger } from '@storybook/core/node-logger'; -import * as fs from 'fs-extra'; - import * as m from './common-preset'; const defaultFavicon = join( @@ -30,17 +29,6 @@ const createOptions = (locations: string[]): Parameters[1] => }, }); -vi.mock('fs-extra', () => { - return { - pathExists: vi.fn((p: string) => { - return false; - }), - existsSync: vi.fn((p: string) => { - return false; - }), - }; -}); - vi.mock('@storybook/core/node-logger', () => { return { logger: { @@ -49,7 +37,13 @@ vi.mock('@storybook/core/node-logger', () => { }; }); -const pathExists = vi.mocked(fs.pathExists); +vi.mock('node:fs', async (importOriginal) => ({ + ...(await importOriginal()), + existsSync: vi.fn((p: string) => { + return false; + }), +})); +const existsSyncMock = vi.mocked(fs.existsSync); it('with no staticDirs favicon should return default', async () => { const options = createOptions([]); @@ -59,7 +53,7 @@ it('with no staticDirs favicon should return default', async () => { it('with staticDirs containing a single favicon.ico should return the found favicon', async () => { const location = 'static'; - pathExists.mockImplementation((p: string) => { + existsSyncMock.mockImplementation((p: string | Buffer | URL) => { if (p === createPath(location)) { return true; } @@ -75,7 +69,7 @@ it('with staticDirs containing a single favicon.ico should return the found favi it('with staticDirs containing a single favicon.svg should return the found favicon', async () => { const location = 'static'; - pathExists.mockImplementation((p: string) => { + existsSyncMock.mockImplementation((p: string | Buffer | URL) => { if (p === createPath(location)) { return true; } @@ -91,7 +85,7 @@ it('with staticDirs containing a single favicon.svg should return the found favi it('with staticDirs containing a multiple favicons should return the first favicon and warn', async () => { const location = 'static'; - pathExists.mockImplementation((p: string) => { + existsSyncMock.mockImplementation((p: string | Buffer | URL) => { if (p === createPath(location)) { return true; } @@ -113,7 +107,7 @@ it('with staticDirs containing a multiple favicons should return the first favic it('with multiple staticDirs containing a multiple favicons should return the first favicon and warn', async () => { const locationA = 'static-a'; const locationB = 'static-b'; - pathExists.mockImplementation((p: string) => { + existsSyncMock.mockImplementation((p: string | Buffer | URL) => { if (p === createPath(locationA)) { return true; } diff --git a/code/core/src/core-server/utils/StoryIndexGenerator.ts b/code/core/src/core-server/utils/StoryIndexGenerator.ts index 0c5338debf88..b3bc3239b983 100644 --- a/code/core/src/core-server/utils/StoryIndexGenerator.ts +++ b/code/core/src/core-server/utils/StoryIndexGenerator.ts @@ -1,4 +1,6 @@ /* eslint-disable no-underscore-dangle */ +import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; import { dirname, extname, join, normalize, relative, resolve, sep } from 'node:path'; import { commonGlobOptions, normalizeStoryPath } from '@storybook/core/common'; @@ -23,7 +25,6 @@ import { sortStoriesV7, userOrAutoTitleFromSpecifier } from '@storybook/core/pre import chalk from 'chalk'; import { findUp } from 'find-up'; -import fs from 'fs-extra'; import slash from 'slash'; import invariant from 'tiny-invariant'; import { dedent } from 'ts-dedent'; @@ -324,7 +325,7 @@ export class StoryIndexGenerator { const absoluteComponentPath = resolve(dirname(absolutePath), rawPath); const existing = ['', '.js', '.ts', '.jsx', '.tsx', '.mjs', '.mts'] .map((ext) => `${absoluteComponentPath}${ext}`) - .find((candidate) => fs.existsSync(candidate)); + .find((candidate) => existsSync(candidate)); if (existing) { const relativePath = relative(this.options.workingDir, existing); return slash(normalizeStoryPath(relativePath)); @@ -432,7 +433,7 @@ export class StoryIndexGenerator { const normalizedPath = normalizeStoryPath(relativePath); const importPath = slash(normalizedPath); - const content = await fs.readFile(absolutePath, 'utf8'); + const content = await readFile(absolutePath, { encoding: 'utf8' }); const { analyze } = await import('@storybook/docs-mdx'); const result = await analyze(content); @@ -753,9 +754,9 @@ export class StoryIndexGenerator { async getPreviewCode() { const previewFile = ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'mts'] .map((ext) => join(this.options.configDir, `preview.${ext}`)) - .find((fname) => fs.existsSync(fname)); + .find((fname) => existsSync(fname)); - return previewFile && (await fs.readFile(previewFile, 'utf-8')).toString(); + return previewFile && (await readFile(previewFile, { encoding: 'utf-8' })).toString(); } getProjectTags(previewCode?: string) { diff --git a/code/core/src/core-server/utils/__tests__/server-statics.test.ts b/code/core/src/core-server/utils/__tests__/server-statics.test.ts index ca532a8b04f9..0dfaea67f5df 100644 --- a/code/core/src/core-server/utils/__tests__/server-statics.test.ts +++ b/code/core/src/core-server/utils/__tests__/server-statics.test.ts @@ -1,19 +1,17 @@ +import fs from 'node:fs'; import { resolve } from 'node:path'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import fs from 'fs-extra'; - import { onlyWindows, skipWindows } from '../../../../../vitest.helpers'; import { parseStaticDir } from '../server-statics'; -vi.mock('fs-extra'); -const pathExistsMock = vi.mocked(fs.pathExists); +vi.mock('node:fs'); +const existsSyncMock = vi.mocked(fs.existsSync); describe('parseStaticDir', () => { beforeEach(() => { - // @ts-expect-error for some reason vitest does not match the return type with one of the overloads from pathExists - pathExistsMock.mockResolvedValue(true); + existsSyncMock.mockReturnValue(true); }); it('returns the static dir/path and default target', async () => { @@ -57,8 +55,7 @@ describe('parseStaticDir', () => { }); it('checks that the path exists', async () => { - // @ts-expect-error for some reason vitest does not match the return type with one of the overloads from pathExists - pathExistsMock.mockResolvedValue(false); + existsSyncMock.mockReturnValueOnce(false); await expect(parseStaticDir('nonexistent')).rejects.toThrow(resolve('nonexistent')); }); diff --git a/code/core/src/core-server/utils/copy-all-static-files.ts b/code/core/src/core-server/utils/copy-all-static-files.ts index bc9a515731ef..f0b3d331033d 100644 --- a/code/core/src/core-server/utils/copy-all-static-files.ts +++ b/code/core/src/core-server/utils/copy-all-static-files.ts @@ -1,3 +1,4 @@ +import { cp } from 'node:fs/promises'; import { join, relative } from 'node:path'; import { getDirectoryFromWorkingDir } from '@storybook/core/common'; @@ -5,7 +6,6 @@ import { getDirectoryFromWorkingDir } from '@storybook/core/common'; import { logger } from '@storybook/core/node-logger'; import chalk from 'chalk'; -import fs from 'fs-extra'; import { parseStaticDir } from './server-statics'; @@ -26,10 +26,13 @@ export async function copyAllStaticFiles(staticDirs: any[] | undefined, outputDi // Storybook's own files should not be overwritten, so we skip such files if we find them const skipPaths = ['index.html', 'iframe.html'].map((f) => join(targetPath, f)); - await fs.copy(staticPath, targetPath, { + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. + await cp(staticPath, targetPath, { dereference: true, preserveTimestamps: true, filter: (_, dest) => !skipPaths.includes(dest), + recursive: true, }); } catch (e) { if (e instanceof Error) { @@ -68,10 +71,11 @@ export async function copyAllStaticFilesRelativeToMain( `=> Copying static files: ${chalk.cyan(print(from))} at ${chalk.cyan(print(targetPath))}` ); } - await fs.copy(from, targetPath, { + await cp(from, targetPath, { dereference: true, preserveTimestamps: true, filter: (_, dest) => !skipPaths.includes(dest), + recursive: true, }); }, Promise.resolve()); } diff --git a/code/core/src/core-server/utils/metadata.ts b/code/core/src/core-server/utils/metadata.ts index cc047d841768..a617b3e1f52c 100644 --- a/code/core/src/core-server/utils/metadata.ts +++ b/code/core/src/core-server/utils/metadata.ts @@ -1,12 +1,13 @@ +import { writeFile } from 'node:fs/promises'; + import { getStorybookMetadata } from '@storybook/core/telemetry'; import type { Request, Response, Router } from 'express'; -import { writeJSON } from 'fs-extra'; export async function extractStorybookMetadata(outputFile: string, configDir: string) { const storybookMetadata = await getStorybookMetadata(configDir); - await writeJSON(outputFile, storybookMetadata); + await writeFile(outputFile, JSON.stringify(storybookMetadata)); } export function useStorybookMetadata(router: Router, configDir?: string) { diff --git a/code/core/src/core-server/utils/output-stats.ts b/code/core/src/core-server/utils/output-stats.ts index c3a5b9f8aad9..1d5047862247 100644 --- a/code/core/src/core-server/utils/output-stats.ts +++ b/code/core/src/core-server/utils/output-stats.ts @@ -1,3 +1,4 @@ +import { createWriteStream } from 'node:fs'; import { join } from 'node:path'; import type { Stats } from '@storybook/core/types'; @@ -6,7 +7,6 @@ import { logger } from '@storybook/core/node-logger'; import { stringifyStream } from '@discoveryjs/json-ext'; import chalk from 'chalk'; -import fs from 'fs-extra'; export async function outputStats(directory: string, previewStats?: any, managerStats?: any) { if (previewStats) { @@ -25,7 +25,7 @@ export const writeStats = async (directory: string, name: string, stats: Stats) await new Promise((resolve, reject) => { stringifyStream(data, null, 2) .on('error', reject) - .pipe(fs.createWriteStream(filePath)) + .pipe(createWriteStream(filePath)) .on('error', reject) .on('finish', resolve); }); diff --git a/code/core/src/core-server/utils/server-init.ts b/code/core/src/core-server/utils/server-init.ts index b63d663e6857..cdcd3c920543 100644 --- a/code/core/src/core-server/utils/server-init.ts +++ b/code/core/src/core-server/utils/server-init.ts @@ -1,7 +1,8 @@ +import { readFile } from 'node:fs/promises'; + import { logger } from '@storybook/core/node-logger'; import type { Express } from 'express'; -import { readFile } from 'fs-extra'; import http from 'http'; import https from 'https'; @@ -29,9 +30,9 @@ export async function getServer( } const sslOptions = { - ca: await Promise.all((options.sslCa || []).map((ca) => readFile(ca, 'utf-8'))), - cert: await readFile(options.sslCert, 'utf-8'), - key: await readFile(options.sslKey, 'utf-8'), + ca: await Promise.all((options.sslCa || []).map((ca) => readFile(ca, { encoding: 'utf-8' }))), + cert: await readFile(options.sslCert, { encoding: 'utf-8' }), + key: await readFile(options.sslKey, { encoding: 'utf-8' }), }; return https.createServer(sslOptions, app); diff --git a/code/core/src/core-server/utils/server-statics.ts b/code/core/src/core-server/utils/server-statics.ts index b10a573e7d90..edd1a4f45fb2 100644 --- a/code/core/src/core-server/utils/server-statics.ts +++ b/code/core/src/core-server/utils/server-statics.ts @@ -1,3 +1,4 @@ +import { existsSync } from 'node:fs'; import { basename, isAbsolute, posix, resolve, sep, win32 } from 'node:path'; import { getDirectoryFromWorkingDir } from '@storybook/core/common'; @@ -8,7 +9,6 @@ import { logger } from '@storybook/core/node-logger'; import chalk from 'chalk'; import type { Router } from 'express'; import express from 'express'; -import { pathExists } from 'fs-extra'; import { dedent } from 'ts-dedent'; export async function useStatics(router: Router, options: Options) { @@ -69,7 +69,7 @@ export const parseStaticDir = async (arg: string) => { const targetDir = target.replace(/^\/?/, './'); const targetEndpoint = targetDir.substring(1); - if (!(await pathExists(staticPath))) { + if (!existsSync(staticPath)) { throw new Error( dedent` Failed to load static files, no such directory: ${chalk.cyan(staticPath)} diff --git a/code/core/src/core-server/utils/stories-json.ts b/code/core/src/core-server/utils/stories-json.ts index 8956a4ed7ab1..d34ba9d72186 100644 --- a/code/core/src/core-server/utils/stories-json.ts +++ b/code/core/src/core-server/utils/stories-json.ts @@ -1,3 +1,4 @@ +import { writeFile } from 'node:fs/promises'; import { basename } from 'node:path'; import type { NormalizedStoriesSpecifier, StoryIndex } from '@storybook/core/types'; @@ -5,7 +6,6 @@ import type { NormalizedStoriesSpecifier, StoryIndex } from '@storybook/core/typ import { STORY_INDEX_INVALIDATED } from '@storybook/core/core-events'; import type { Request, Response, Router } from 'express'; -import { writeJSON } from 'fs-extra'; import debounce from 'lodash/debounce.js'; import type { StoryIndexGenerator } from './StoryIndexGenerator'; @@ -22,7 +22,7 @@ export async function extractStoriesJson( ) { const generator = await initializedStoryIndexGenerator; const storyIndex = await generator.getIndex(); - await writeJSON(outputFile, transform ? transform(storyIndex) : storyIndex); + await writeFile(outputFile, JSON.stringify(transform ? transform(storyIndex) : storyIndex)); } export function useStoriesJson({ diff --git a/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts b/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts index dd543bff54bc..d8fa4dcc521c 100644 --- a/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts +++ b/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts @@ -1,17 +1,20 @@ +import { readFile } from 'node:fs/promises'; + import { type BabelFile, core } from '@storybook/core/babel'; import type { StorybookConfig } from '@storybook/core/types'; import { babelParse } from '@storybook/core/csf-tools'; import chalk from 'chalk'; -import { readFile } from 'fs-extra'; import { dedent } from 'ts-dedent'; export async function warnWhenUsingArgTypesRegex( previewConfigPath: string | undefined, config: StorybookConfig ) { - const previewContent = previewConfigPath ? await readFile(previewConfigPath, 'utf8') : ''; + const previewContent = previewConfigPath + ? await readFile(previewConfigPath, { encoding: 'utf8' }) + : ''; const hasVisualTestAddon = config?.addons?.some((it) => diff --git a/code/core/src/core-server/utils/whats-new.ts b/code/core/src/core-server/utils/whats-new.ts index 1091d77ab74f..cb523f78318e 100644 --- a/code/core/src/core-server/utils/whats-new.ts +++ b/code/core/src/core-server/utils/whats-new.ts @@ -1,3 +1,5 @@ +import { writeFile } from 'node:fs/promises'; + import type { Channel } from '@storybook/core/channels'; import { findConfigFile } from '@storybook/core/common'; import { telemetry } from '@storybook/core/telemetry'; @@ -14,7 +16,6 @@ import { import { printConfig, readConfig } from '@storybook/core/csf-tools'; import { logger } from '@storybook/core/node-logger'; -import fs from 'fs-extra'; import invariant from 'tiny-invariant'; import { sendTelemetryError } from '../withTelemetry'; @@ -93,7 +94,7 @@ export function initializeWhatsNew( invariant(mainPath, `unable to find storybook main file in ${options.configDir}`); const main = await readConfig(mainPath); main.setFieldValue(['core', 'disableWhatsNewNotifications'], disableWhatsNewNotifications); - await fs.writeFile(mainPath, printConfig(main).code); + await writeFile(mainPath, printConfig(main).code); if (isTelemetryEnabled) { await telemetry('core-config', { disableWhatsNewNotifications }); } From 2dcc7b75e719487e6bb6c27cf844c8bb51b68d4c Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:38:58 +0200 Subject: [PATCH 094/213] Add `recursive: true` to `cp` calls --- code/builders/builder-vite/src/index.ts | 1 + code/builders/builder-webpack5/src/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/code/builders/builder-vite/src/index.ts b/code/builders/builder-vite/src/index.ts index fb841b1c473d..7a8771a5efe9 100644 --- a/code/builders/builder-vite/src/index.ts +++ b/code/builders/builder-vite/src/index.ts @@ -94,6 +94,7 @@ export const build: ViteBuilder['build'] = async ({ options }) => { } return true; }, + recursive: true, }); const [out] = await Promise.all([viteCompilation, previewFiles]); diff --git a/code/builders/builder-webpack5/src/index.ts b/code/builders/builder-webpack5/src/index.ts index 7d12dabb4b6f..bf87a0700131 100644 --- a/code/builders/builder-webpack5/src/index.ts +++ b/code/builders/builder-webpack5/src/index.ts @@ -302,6 +302,7 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, } return true; }, + recursive: true, }); const [webpackCompilationOutput] = await Promise.all([webpackCompilation, previewFiles]); From ca39982d8873141a36b8c56a2594af9d3027599d Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:39:31 +0200 Subject: [PATCH 095/213] core: Remove `fs-extra` from `src/core-server` --- code/core/src/core-server/build-dev.ts | 4 ++-- code/core/src/core-server/build-static.ts | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/code/core/src/core-server/build-dev.ts b/code/core/src/core-server/build-dev.ts index 5c87a7d9ccd8..2f1e08703a21 100644 --- a/code/core/src/core-server/build-dev.ts +++ b/code/core/src/core-server/build-dev.ts @@ -1,3 +1,4 @@ +import { readFile } from 'node:fs/promises'; import { join, relative, resolve } from 'node:path'; import { @@ -18,7 +19,6 @@ import { global } from '@storybook/global'; import { deprecate } from '@storybook/core/node-logger'; import { MissingBuilderError, NoStatsForViteDevError } from '@storybook/core/server-errors'; -import { readFile } from 'fs-extra'; import prompts from 'prompts'; import invariant from 'tiny-invariant'; import { dedent } from 'ts-dedent'; @@ -156,7 +156,7 @@ export async function buildDevStandalone( if (/\.c[jt]s$/.test(mainJsPath)) { deprecate(deprecationMessage); } - const mainJsContent = await readFile(mainJsPath, 'utf-8'); + const mainJsContent = await readFile(mainJsPath, { encoding: 'utf-8' }); // Regex that matches any CommonJS-specific syntax, stolen from Vite: https://github.com/vitejs/vite/blob/91a18c2f7da796ff8217417a4bf189ddda719895/packages/vite/src/node/ssr/ssrExternal.ts#L87 const CJS_CONTENT_REGEX = /\bmodule\.exports\b|\bexports[.[]|\brequire\s*\(|\bObject\.(?:defineProperty|defineProperties|assign)\s*\(\s*exports\b/; diff --git a/code/core/src/core-server/build-static.ts b/code/core/src/core-server/build-static.ts index 248b2746ea8c..d0835d0d8a67 100644 --- a/code/core/src/core-server/build-static.ts +++ b/code/core/src/core-server/build-static.ts @@ -1,3 +1,5 @@ +import { cp, mkdir, readdir } from 'node:fs/promises'; +import { rm } from 'node:fs/promises'; import { dirname, join, relative, resolve } from 'node:path'; import { @@ -14,7 +16,6 @@ import { global } from '@storybook/global'; import { logger } from '@storybook/core/node-logger'; import chalk from 'chalk'; -import { copy, emptyDir, ensureDir } from 'fs-extra'; import { StoryIndexGenerator } from './utils/StoryIndexGenerator'; import { buildOrThrow } from './utils/build-or-throw'; @@ -43,8 +44,12 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption if (options.outputDir === '/') { throw new Error("Won't remove directory '/'. Check your outputDir!"); } - await emptyDir(options.outputDir); - await ensureDir(options.outputDir); + + const outputDirFiles = await readdir(options.outputDir); + if (outputDirFiles.length > 0) { + await rm(options.outputDir, { recursive: true, force: true }); + await mkdir(options.outputDir, { recursive: true }); + } const config = await loadMainConfig(options); const { framework } = config; @@ -127,7 +132,9 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption dirname(require.resolve('@storybook/core/package.json')), 'assets/browser' ); - effects.push(copy(coreServerPublicDir, options.outputDir)); + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. + effects.push(cp(coreServerPublicDir, options.outputDir, { recursive: true })); let initializedStoryIndexGenerator: Promise = Promise.resolve(undefined); From a42ff7e9590c5747395c379c8c39c7fe0af980f1 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:53:13 +0200 Subject: [PATCH 096/213] Close the file descriptor --- .../builder-vite/src/plugins/external-globals-plugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts index 7813e1c50030..6477ade92b4a 100644 --- a/code/builders/builder-vite/src/plugins/external-globals-plugin.ts +++ b/code/builders/builder-vite/src/plugins/external-globals-plugin.ts @@ -1,4 +1,4 @@ -import { existsSync, openSync } from 'node:fs'; +import { closeSync, existsSync, openSync } from 'node:fs'; import { writeFile } from 'node:fs/promises'; import { join } from 'node:path'; @@ -61,7 +61,7 @@ export async function externalGlobalsPlugin(externals: Record) { const externalCachePath = join(cachePath, `${externalKey}.js`); newAlias.push({ find: new RegExp(`^${externalKey}$`), replacement: externalCachePath }); if (!existsSync(externalCachePath)) { - openSync(externalCachePath, 'w'); + closeSync(openSync(externalCachePath, 'w')); } await writeFile(externalCachePath, `module.exports = ${externals[externalKey]};`); }) From 174868afbaa4775e2fc9621665b0d651fbe93dee Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 19:57:46 +0200 Subject: [PATCH 097/213] core: Remove `fs-extra` from `src/builder-manager` --- code/core/src/builder-manager/index.ts | 15 +++--- code/core/src/builder-manager/utils/files.ts | 9 ++-- .../builder-manager/utils/managerEntries.ts | 9 ++-- .../src/builder-manager/utils/template.ts | 4 +- code/core/src/cli/detect.test.ts | 4 -- code/core/src/cli/eslintPlugin.ts | 10 ++-- code/core/src/cli/helpers.test.ts | 46 ++++++++----------- code/core/src/cli/helpers.ts | 30 ++++++------ 8 files changed, 64 insertions(+), 63 deletions(-) diff --git a/code/core/src/builder-manager/index.ts b/code/core/src/builder-manager/index.ts index 1e246b5d1cb1..a1589af27b23 100644 --- a/code/core/src/builder-manager/index.ts +++ b/code/core/src/builder-manager/index.ts @@ -1,3 +1,4 @@ +import { cp, rm, writeFile } from 'node:fs/promises'; import { dirname, join, parse } from 'node:path'; import { stringifyProcessEnvs } from '@storybook/core/common'; @@ -9,7 +10,6 @@ import { globalExternals } from '@fal-works/esbuild-plugin-global-externals'; import { pnpPlugin } from '@yarnpkg/esbuild-plugin-pnp'; import aliasPlugin from 'esbuild-plugin-alias'; import express from 'express'; -import fs from 'fs-extra'; import type { BuilderBuildResult, @@ -149,7 +149,7 @@ const starter: StarterFunction = async function* starterGeneratorFn({ // make sure we clear output directory of addons dir before starting // this could cause caching issues where addons are loaded when they shouldn't const addonsDir = config.outdir; - await fs.remove(addonsDir); + await rm(addonsDir, { recursive: true, force: true }); yield; @@ -256,7 +256,9 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, yield; - const managerFiles = fs.copy(coreDirOrigin, coreDirTarget, { + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. + const managerFiles = cp(coreDirOrigin, coreDirTarget, { filter: (src) => { const { ext } = parse(src); if (ext) { @@ -264,6 +266,7 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, } return true; }, + recursive: true, }); const { cssFiles, jsFiles } = await readOrderedFiles(addonsDir, compilation?.outputFiles); @@ -288,11 +291,7 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, globals ); - await Promise.all([ - // - fs.writeFile(join(options.outputDir, 'index.html'), html), - managerFiles, - ]); + await Promise.all([writeFile(join(options.outputDir, 'index.html'), html), managerFiles]); logger.trace({ message: '=> Manager built', time: process.hrtime(startTime) }); diff --git a/code/core/src/builder-manager/utils/files.ts b/code/core/src/builder-manager/utils/files.ts index 94ec31677c4a..b83cb2e7a13e 100644 --- a/code/core/src/builder-manager/utils/files.ts +++ b/code/core/src/builder-manager/utils/files.ts @@ -1,7 +1,8 @@ +import { closeSync, existsSync, openSync } from 'node:fs'; +import { writeFile } from 'node:fs/promises'; import { join, normalize } from 'node:path'; import type { OutputFile } from 'esbuild'; -import fs from 'fs-extra'; import slash from 'slash'; import type { Compilation } from '../types'; @@ -15,8 +16,10 @@ export async function readOrderedFiles( // convert deeply nested paths to a single level, also remove special characters const { location, url } = sanitizePath(file, addonsDir); - await fs.ensureFile(location); - await fs.writeFile(location, file.contents); + if (!existsSync(location)) { + closeSync(openSync(location, 'w')); + } + await writeFile(location, file.contents); return url; }) || [] ); diff --git a/code/core/src/builder-manager/utils/managerEntries.ts b/code/core/src/builder-manager/utils/managerEntries.ts index d808596f52e4..3cb2f1d3aea9 100644 --- a/code/core/src/builder-manager/utils/managerEntries.ts +++ b/code/core/src/builder-manager/utils/managerEntries.ts @@ -1,8 +1,9 @@ +import { closeSync, existsSync, openSync } from 'node:fs'; +import { writeFile } from 'node:fs/promises'; import { join, parse, relative, sep } from 'node:path'; import { resolvePathInStorybookCache } from '@storybook/core/common'; -import fs from 'fs-extra'; import slash from 'slash'; const sanitizeBase = (path: string) => { @@ -55,8 +56,10 @@ export async function wrapManagerEntries(entrypoints: string[], uniqueId?: strin sanitizeFinal(join(`${sanitizeBase(base)}-${i}`, `${sanitizeBase(name)}-bundle.js`)) ); - await fs.ensureFile(location); - await fs.writeFile(location, `import '${slash(entry)}';`); + if (!existsSync(location)) { + closeSync(openSync(location, 'w')); + } + await writeFile(location, `import '${slash(entry)}';`); return location; }) diff --git a/code/core/src/builder-manager/utils/template.ts b/code/core/src/builder-manager/utils/template.ts index b264a3d5e02e..1ca99e07e2e6 100644 --- a/code/core/src/builder-manager/utils/template.ts +++ b/code/core/src/builder-manager/utils/template.ts @@ -1,9 +1,9 @@ +import { readFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import type { DocsOptions, Options, Ref, TagsOptions } from '@storybook/core/types'; import { render } from 'ejs'; -import fs from 'fs-extra'; export const getTemplatePath = async (template: string) => { return join(dirname(require.resolve('@storybook/core/package.json')), 'assets/server', template); @@ -12,7 +12,7 @@ export const getTemplatePath = async (template: string) => { export const readTemplate = async (template: string) => { const path = await getTemplatePath(template); - return fs.readFile(path, 'utf8'); + return readFile(path, { encoding: 'utf8' }); }; export async function getManagerMainTemplate() { diff --git a/code/core/src/cli/detect.test.ts b/code/core/src/cli/detect.test.ts index f12ece4314fa..95c1b126dca3 100644 --- a/code/core/src/cli/detect.test.ts +++ b/code/core/src/cli/detect.test.ts @@ -26,10 +26,6 @@ vi.mock('fs', () => ({ default: vi.fn(), })); -vi.mock('fs-extra', () => ({ - pathExistsSync: vi.fn(() => true), -})); - vi.mock('@storybook/core/node-logger'); const MOCK_FRAMEWORK_FILES: { diff --git a/code/core/src/cli/eslintPlugin.ts b/code/core/src/cli/eslintPlugin.ts index 4b8d47b293a2..e6a37adfd64e 100644 --- a/code/core/src/cli/eslintPlugin.ts +++ b/code/core/src/cli/eslintPlugin.ts @@ -1,4 +1,5 @@ import { existsSync } from 'node:fs'; +import { readFile, writeFile } from 'node:fs/promises'; import type { JsPackageManager } from '@storybook/core/common'; import { paddedLog } from '@storybook/core/common'; @@ -7,7 +8,6 @@ import { readConfig, writeConfig } from '@storybook/core/csf-tools'; import chalk from 'chalk'; import detectIndent from 'detect-indent'; -import { readFile, readJson, writeJson } from 'fs-extra'; import prompts from 'prompts'; import { dedent } from 'ts-dedent'; @@ -72,13 +72,15 @@ export async function configureEslintPlugin( if (eslintFile) { paddedLog(`Configuring Storybook ESLint plugin at ${eslintFile}`); if (eslintFile.endsWith('json')) { - const eslintConfig = (await readJson(eslintFile)) as { extends?: string[] }; + const eslintConfig = JSON.parse(await readFile(eslintFile, { encoding: 'utf-8' })) as { + extends?: string[]; + }; const existingExtends = normalizeExtends(eslintConfig.extends).filter(Boolean); eslintConfig.extends = [...existingExtends, 'plugin:storybook/recommended'] as string[]; - const eslintFileContents = await readFile(eslintFile, 'utf8'); + const eslintFileContents = await readFile(eslintFile, { encoding: 'utf8' }); const spaces = detectIndent(eslintFileContents).amount || 2; - await writeJson(eslintFile, eslintConfig, { spaces }); + await writeFile(eslintFile, JSON.stringify(eslintConfig, undefined, spaces)); } else { const eslint = await readConfig(eslintFile); const existingExtends = normalizeExtends(eslint.getFieldValue(['extends'])).filter(Boolean); diff --git a/code/core/src/cli/helpers.test.ts b/code/core/src/cli/helpers.test.ts index cff797a8f505..4615f0cfdd84 100644 --- a/code/core/src/cli/helpers.test.ts +++ b/code/core/src/cli/helpers.test.ts @@ -1,8 +1,10 @@ +import fs from 'node:fs'; +import fsp from 'node:fs/promises'; + import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { JsPackageManager } from '@storybook/core/common'; -import fse from 'fs-extra'; import { sep } from 'path'; import { IS_WINDOWS } from '../../../vitest.helpers'; @@ -13,21 +15,18 @@ import { SupportedLanguage } from './project_types'; const normalizePath = (path: string) => (IS_WINDOWS ? path.replace(/\//g, sep) : path); const fsMocks = vi.hoisted(() => ({ + cpSync: vi.fn(() => ({})), existsSync: vi.fn(), })); -const fseMocks = vi.hoisted(() => ({ - copySync: vi.fn(() => ({})), - copy: vi.fn(() => ({})), - ensureDir: vi.fn(() => {}), - existsSync: vi.fn(), - pathExists: vi.fn(), +const fspMocks = vi.hoisted(() => ({ + cp: vi.fn(() => ({})), readFile: vi.fn(() => ''), writeFile: vi.fn(), })); -vi.mock('fs', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('node:fs', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, ...fsMocks, @@ -42,14 +41,14 @@ vi.mock('./dirs', () => ({ normalizePath(`@storybook/${renderer}`), })); -vi.mock('fs-extra', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('node:fs/promises', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, - ...fseMocks, + ...fspMocks, default: { ...actual, - ...fseMocks, + ...fspMocks, }, }; }); @@ -83,7 +82,7 @@ describe('Helpers', () => { helpers.copyTemplate(''); - expect(fse.copySync).toHaveBeenCalledWith( + expect(fs.cpSync).toHaveBeenCalledWith( expect.stringMatching(csfDirectory), expect.anything(), expect.anything() @@ -115,7 +114,7 @@ describe('Helpers', () => { const componentsDirectory = exists.map((folder: string) => normalizePath(`@storybook/react/template/cli/${folder}`) ); - fseMocks.pathExists.mockImplementation( + fsMocks.existsSync.mockImplementation( (filePath) => componentsDirectory.includes(filePath) || filePath === normalizePath('@storybook/react/template/cli') @@ -127,7 +126,7 @@ describe('Helpers', () => { commonAssetsDir: normalizePath('create-storybook/rendererAssets/common'), }); - expect(fse.copy).toHaveBeenNthCalledWith( + expect(fsp.cp).toHaveBeenNthCalledWith( 1, normalizePath('create-storybook/rendererAssets/common'), './stories', @@ -135,17 +134,12 @@ describe('Helpers', () => { ); const expectedDirectory = normalizePath(`@storybook/react/template/cli${expected}`); - expect(fse.copy).toHaveBeenNthCalledWith( - 2, - expectedDirectory, - './stories', - expect.anything() - ); + expect(fsp.cp).toHaveBeenNthCalledWith(2, expectedDirectory, './stories', expect.anything()); } ); it(`should copy to src folder when exists`, async () => { - vi.mocked(fse.pathExists).mockImplementation((filePath) => { + vi.mocked(fs.existsSync).mockImplementation((filePath) => { return filePath === normalizePath('@storybook/react/template/cli') || filePath === './src'; }); await helpers.copyTemplateFiles({ @@ -153,11 +147,11 @@ describe('Helpers', () => { language: SupportedLanguage.JAVASCRIPT, packageManager: packageManagerMock, }); - expect(fse.copy).toHaveBeenCalledWith(expect.anything(), './src/stories', expect.anything()); + expect(fsp.cp).toHaveBeenCalledWith(expect.anything(), './src/stories', expect.anything()); }); it(`should copy to root folder when src doesn't exist`, async () => { - vi.mocked(fse.pathExists).mockImplementation((filePath) => { + vi.mocked(fs.existsSync).mockImplementation((filePath) => { return filePath === normalizePath('@storybook/react/template/cli'); }); await helpers.copyTemplateFiles({ @@ -165,7 +159,7 @@ describe('Helpers', () => { language: SupportedLanguage.JAVASCRIPT, packageManager: packageManagerMock, }); - expect(fse.copy).toHaveBeenCalledWith(expect.anything(), './stories', expect.anything()); + expect(fsp.cp).toHaveBeenCalledWith(expect.anything(), './stories', expect.anything()); }); it(`should throw an error for unsupported renderer`, async () => { diff --git a/code/core/src/cli/helpers.ts b/code/core/src/cli/helpers.ts index 355e142cece1..1b1448e7b469 100644 --- a/code/core/src/cli/helpers.ts +++ b/code/core/src/cli/helpers.ts @@ -1,4 +1,5 @@ -import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { cpSync, existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { cp, readFile, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import { @@ -12,7 +13,6 @@ import type { SupportedFrameworks, SupportedRenderers } from '@storybook/core/ty import chalk from 'chalk'; import { findUpSync } from 'find-up'; -import { copy, copySync, pathExists, readFile, writeFile } from 'fs-extra'; import { coerce, satisfies } from 'semver'; import stripJsonComments from 'strip-json-comments'; import invariant from 'tiny-invariant'; @@ -130,7 +130,9 @@ export function copyTemplate(templateRoot: string, destination = '.') { throw new Error(`Couldn't find template dir`); } - copySync(templateDir, destination, { overwrite: true }); + // TODO: `fsPromises.cpSync` is marked as experimental in Node 16-21. Ask in the PR whether we + // should use it anyway or stick to `fs-extra` for now. + cpSync(templateDir, destination, { recursive: true }); } type CopyTemplateFilesOptions = { @@ -197,42 +199,44 @@ export async function copyTemplateFiles({ const assetsTS38 = join(assetsDir, languageFolderMapping[SupportedLanguage.TYPESCRIPT_3_8]); // Ideally use the assets that match the language & version. - if (await pathExists(assetsLanguage)) { + if (existsSync(assetsLanguage)) { return assetsLanguage; } // Use fallback typescript 3.8 assets if new ones aren't available - if (language === SupportedLanguage.TYPESCRIPT_4_9 && (await pathExists(assetsTS38))) { + if (language === SupportedLanguage.TYPESCRIPT_4_9 && existsSync(assetsTS38)) { return assetsTS38; } // Fallback further to TS (for backwards compatibility purposes) - if (await pathExists(assetsTS)) { + if (existsSync(assetsTS)) { return assetsTS; } // Fallback further to JS - if (await pathExists(assetsJS)) { + if (existsSync(assetsJS)) { return assetsJS; } // As a last resort, look for the root of the asset directory - if (await pathExists(assetsDir)) { + if (existsSync(assetsDir)) { return assetsDir; } throw new Error(`Unsupported renderer: ${renderer} (${baseDir})`); }; const targetPath = async () => { - if (await pathExists('./src')) { + if (existsSync('./src')) { return './src/stories'; } return './stories'; }; const destinationPath = destination ?? (await targetPath()); + // TODO: `fsPromises.cp` is marked as experimental in Node 16-21. Ask in the PR whether we should + // use it anyway or stick to `fs-extra` for now. if (commonAssetsDir) { - await copy(commonAssetsDir, destinationPath, { - overwrite: true, + await cp(commonAssetsDir, destinationPath, { + recursive: true, }); } - await copy(await templatePath(), destinationPath, { overwrite: true }); + await cp(await templatePath(), destinationPath, { recursive: true }); if (commonAssetsDir) { let rendererType = frameworkToRenderer[renderer] || 'react'; @@ -248,7 +252,7 @@ export async function copyTemplateFiles({ export async function adjustTemplate(templatePath: string, templateData: Record) { // for now, we're just doing a simple string replace // in the future we might replace this with a proper templating engine - let template = await readFile(templatePath, 'utf8'); + let template = await readFile(templatePath, { encoding: 'utf8' }); Object.keys(templateData).forEach((key) => { template = template.replaceAll(`{{${key}}}`, `${templateData[key]}`); From 643acbfc2a03faa240fa01693e11bd1c54a293e2 Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 20:01:00 +0200 Subject: [PATCH 098/213] core: Remove `fs-extra` from `scripts` --- code/core/package.json | 2 -- code/core/scripts/helpers/dependencies.ts | 7 ++++--- code/core/scripts/helpers/generatePackageJsonFile.ts | 5 ++--- code/core/scripts/helpers/generateTypesMapperFiles.ts | 7 ++++--- code/core/scripts/prep.ts | 8 ++++---- code/yarn.lock | 2 -- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/code/core/package.json b/code/core/package.json index 181b04312985..e9464c5339b6 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -320,7 +320,6 @@ "@types/diff": "^5.0.9", "@types/ejs": "^3.1.1", "@types/find-cache-dir": "^5.0.0", - "@types/fs-extra": "^11.0.1", "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.167", "@types/node": "^22.0.0", @@ -371,7 +370,6 @@ "find-cache-dir": "^5.0.0", "find-up": "^7.0.0", "flush-promises": "^1.0.2", - "fs-extra": "^11.1.0", "fuse.js": "^3.6.1", "get-npm-tarball-url": "^2.0.3", "glob": "^10.0.0", diff --git a/code/core/scripts/helpers/dependencies.ts b/code/core/scripts/helpers/dependencies.ts index 82b22a022ad4..e84e80931e75 100644 --- a/code/core/scripts/helpers/dependencies.ts +++ b/code/core/scripts/helpers/dependencies.ts @@ -1,7 +1,6 @@ +import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { readJson } from 'fs-extra'; - export async function flattenDependencies( list: string[], output: string[] = [], @@ -18,7 +17,9 @@ export async function flattenDependencies( console.log(dep + ' not found'); return; } - const { dependencies = {}, peerDependencies = {} } = await readJson(path); + const { dependencies = {}, peerDependencies = {} } = JSON.parse( + await readFile(path, { encoding: 'utf-8' }) + ); const all: string[] = [ ...new Set([...Object.keys(dependencies), ...Object.keys(peerDependencies)]), ] diff --git a/code/core/scripts/helpers/generatePackageJsonFile.ts b/code/core/scripts/helpers/generatePackageJsonFile.ts index 9ecf2f7679e5..1d14e141504a 100644 --- a/code/core/scripts/helpers/generatePackageJsonFile.ts +++ b/code/core/scripts/helpers/generatePackageJsonFile.ts @@ -1,7 +1,6 @@ -import { writeFile } from 'node:fs/promises'; +import { readFile, writeFile } from 'node:fs/promises'; import { join, relative } from 'node:path'; -import { readJSON } from 'fs-extra'; import slash from 'slash'; import { sortPackageJson } from '../../../../scripts/prepare/tools'; @@ -11,7 +10,7 @@ const cwd = process.cwd(); export async function generatePackageJsonFile(entries: ReturnType) { const location = join(cwd, 'package.json'); - const pkgJson = await readJSON(location); + const pkgJson = JSON.parse(await readFile(location, { encoding: 'utf-8' })); /** * Re-create the `exports` field in `code/core/package.json` This way we only need to update the diff --git a/code/core/scripts/helpers/generateTypesMapperFiles.ts b/code/core/scripts/helpers/generateTypesMapperFiles.ts index 2f79f80643d8..11845a5e3239 100644 --- a/code/core/scripts/helpers/generateTypesMapperFiles.ts +++ b/code/core/scripts/helpers/generateTypesMapperFiles.ts @@ -1,8 +1,7 @@ +import { closeSync, existsSync, openSync } from 'node:fs'; import { writeFile } from 'node:fs/promises'; import { join, relative } from 'node:path'; -import { ensureFile } from 'fs-extra'; - import { dedent } from '../../../../scripts/prepare/tools'; import type { getEntries } from '../entries'; @@ -34,7 +33,9 @@ export async function generateTypesMapperFiles(entries: ReturnType { const location = filePath.replace('src', 'dist').replace(/\.tsx?/, '.d.ts'); - await ensureFile(location); + if (!existsSync(location)) { + closeSync(openSync(location, 'w')); + } await writeFile(location, await generateTypesMapperContent(filePath)); }) ); diff --git a/code/core/scripts/prep.ts b/code/core/scripts/prep.ts index 49c2bd00cfa0..20c979ebd9aa 100644 --- a/code/core/scripts/prep.ts +++ b/code/core/scripts/prep.ts @@ -1,10 +1,8 @@ /* eslint-disable local-rules/no-uncategorized-errors */ -import { watch } from 'node:fs'; +import { existsSync, mkdirSync, watch } from 'node:fs'; import { mkdir, rm, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; -import { ensureDir } from 'fs-extra'; - import { chalk, dedent, @@ -320,7 +318,9 @@ async function run() { const outName = keys.length === 1 ? dirname(keys[0]).replace('dist/', '') : `meta-${format}-${index}`; - await ensureDir('report'); + if (!existsSync('report')) { + mkdirSync('report'); + } await writeFile(`report/${outName}.json`, JSON.stringify(out.metafile, null, 2)); await writeFile( `report/${outName}.txt`, diff --git a/code/yarn.lock b/code/yarn.lock index e477552d26d5..544c7fa773c5 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6034,7 +6034,6 @@ __metadata: "@types/ejs": "npm:^3.1.1" "@types/express": "npm:^4.17.21" "@types/find-cache-dir": "npm:^5.0.0" - "@types/fs-extra": "npm:^11.0.1" "@types/js-yaml": "npm:^4.0.5" "@types/lodash": "npm:^4.14.167" "@types/node": "npm:^22.0.0" @@ -6087,7 +6086,6 @@ __metadata: find-cache-dir: "npm:^5.0.0" find-up: "npm:^7.0.0" flush-promises: "npm:^1.0.2" - fs-extra: "npm:^11.1.0" fuse.js: "npm:^3.6.1" get-npm-tarball-url: "npm:^2.0.3" glob: "npm:^10.0.0" From 89cdff3bec640b6bd8d8831d578cf4b9cc9858af Mon Sep 17 00:00:00 2001 From: ziebam Date: Sat, 14 Sep 2024 20:04:38 +0200 Subject: [PATCH 099/213] Remove `fs-extra` from `code` --- code/package.json | 1 - code/yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/code/package.json b/code/package.json index e348ef665900..000f4d270a0b 100644 --- a/code/package.json +++ b/code/package.json @@ -194,7 +194,6 @@ "eslint-plugin-local-rules": "portal:../scripts/eslint-plugin-local-rules", "eslint-plugin-playwright": "^1.6.2", "eslint-plugin-storybook": "^0.8.0", - "fs-extra": "^11.1.0", "github-release-from-changelog": "^2.1.1", "glob": "^10.0.0", "happy-dom": "^14.12.0", diff --git a/code/yarn.lock b/code/yarn.lock index 544c7fa773c5..ae4ac70a6765 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6893,7 +6893,6 @@ __metadata: eslint-plugin-local-rules: "portal:../scripts/eslint-plugin-local-rules" eslint-plugin-playwright: "npm:^1.6.2" eslint-plugin-storybook: "npm:^0.8.0" - fs-extra: "npm:^11.1.0" github-release-from-changelog: "npm:^2.1.1" glob: "npm:^10.0.0" happy-dom: "npm:^14.12.0" From 0d10b9586305315994a2b2e8716d18492481fc0a Mon Sep 17 00:00:00 2001 From: ziebam Date: Sun, 15 Sep 2024 11:40:41 +0200 Subject: [PATCH 100/213] Replace 'utf-8' with 'utf8' for consistency with Node docs --- code/builders/builder-vite/src/index.ts | 2 +- code/core/scripts/helpers/dependencies.ts | 2 +- code/core/scripts/helpers/generatePackageJsonFile.ts | 2 +- code/core/src/cli/eslintPlugin.ts | 2 +- code/core/src/common/utils/get-storybook-refs.ts | 4 ++-- code/core/src/core-server/build-dev.ts | 2 +- code/core/src/core-server/presets/common-preset.ts | 2 +- code/core/src/core-server/utils/StoryIndexGenerator.ts | 2 +- code/core/src/core-server/utils/server-init.ts | 6 +++--- code/core/src/telemetry/get-monorepo-type.ts | 2 +- code/core/src/telemetry/package-json.ts | 2 +- code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts | 2 +- code/lib/cli-storybook/src/link.ts | 4 ++-- code/renderers/server/src/preset.ts | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/code/builders/builder-vite/src/index.ts b/code/builders/builder-vite/src/index.ts index 7a8771a5efe9..cdd4ed972eef 100644 --- a/code/builders/builder-vite/src/index.ts +++ b/code/builders/builder-vite/src/index.ts @@ -35,7 +35,7 @@ function iframeMiddleware(options: Options, server: ViteDevServer): RequestHandl } const indexHtml = await readFile(require.resolve('@storybook/builder-vite/input/iframe.html'), { - encoding: 'utf-8', + encoding: 'utf8', }); const generated = await transformIframeHtml(indexHtml, options); const transformed = await server.transformIndexHtml('/iframe.html', generated); diff --git a/code/core/scripts/helpers/dependencies.ts b/code/core/scripts/helpers/dependencies.ts index e84e80931e75..89e67fc554f3 100644 --- a/code/core/scripts/helpers/dependencies.ts +++ b/code/core/scripts/helpers/dependencies.ts @@ -18,7 +18,7 @@ export async function flattenDependencies( return; } const { dependencies = {}, peerDependencies = {} } = JSON.parse( - await readFile(path, { encoding: 'utf-8' }) + await readFile(path, { encoding: 'utf8' }) ); const all: string[] = [ ...new Set([...Object.keys(dependencies), ...Object.keys(peerDependencies)]), diff --git a/code/core/scripts/helpers/generatePackageJsonFile.ts b/code/core/scripts/helpers/generatePackageJsonFile.ts index 1d14e141504a..271f775cba23 100644 --- a/code/core/scripts/helpers/generatePackageJsonFile.ts +++ b/code/core/scripts/helpers/generatePackageJsonFile.ts @@ -10,7 +10,7 @@ const cwd = process.cwd(); export async function generatePackageJsonFile(entries: ReturnType) { const location = join(cwd, 'package.json'); - const pkgJson = JSON.parse(await readFile(location, { encoding: 'utf-8' })); + const pkgJson = JSON.parse(await readFile(location, { encoding: 'utf8' })); /** * Re-create the `exports` field in `code/core/package.json` This way we only need to update the diff --git a/code/core/src/cli/eslintPlugin.ts b/code/core/src/cli/eslintPlugin.ts index e6a37adfd64e..fafb91b2652a 100644 --- a/code/core/src/cli/eslintPlugin.ts +++ b/code/core/src/cli/eslintPlugin.ts @@ -72,7 +72,7 @@ export async function configureEslintPlugin( if (eslintFile) { paddedLog(`Configuring Storybook ESLint plugin at ${eslintFile}`); if (eslintFile.endsWith('json')) { - const eslintConfig = JSON.parse(await readFile(eslintFile, { encoding: 'utf-8' })) as { + const eslintConfig = JSON.parse(await readFile(eslintFile, { encoding: 'utf8' })) as { extends?: string[]; }; const existingExtends = normalizeExtends(eslintConfig.extends).filter(Boolean); diff --git a/code/core/src/common/utils/get-storybook-refs.ts b/code/core/src/common/utils/get-storybook-refs.ts index c733febf6aea..4108ba969412 100644 --- a/code/core/src/common/utils/get-storybook-refs.ts +++ b/code/core/src/common/utils/get-storybook-refs.ts @@ -16,7 +16,7 @@ export const getAutoRefs = async (options: Options): Promise const directory = dirname(location); const { dependencies = [], devDependencies = [] } = - JSON.parse(await readFile(location, { encoding: 'utf-8' })) || {}; + JSON.parse(await readFile(location, { encoding: 'utf8' })) || {}; const deps = Object.keys({ ...dependencies, ...devDependencies }); const list = await Promise.all( @@ -25,7 +25,7 @@ export const getAutoRefs = async (options: Options): Promise const l = resolveFrom(directory, join(d, 'package.json')); const { storybook, name, version } = - JSON.parse(await readFile(l, { encoding: 'utf-8' })) || {}; + JSON.parse(await readFile(l, { encoding: 'utf8' })) || {}; if (storybook?.url) { return { id: name, ...storybook, version }; diff --git a/code/core/src/core-server/build-dev.ts b/code/core/src/core-server/build-dev.ts index 2f1e08703a21..c8b336a22e09 100644 --- a/code/core/src/core-server/build-dev.ts +++ b/code/core/src/core-server/build-dev.ts @@ -156,7 +156,7 @@ export async function buildDevStandalone( if (/\.c[jt]s$/.test(mainJsPath)) { deprecate(deprecationMessage); } - const mainJsContent = await readFile(mainJsPath, { encoding: 'utf-8' }); + const mainJsContent = await readFile(mainJsPath, { encoding: 'utf8' }); // Regex that matches any CommonJS-specific syntax, stolen from Vite: https://github.com/vitejs/vite/blob/91a18c2f7da796ff8217417a4bf189ddda719895/packages/vite/src/node/ssr/ssrExternal.ts#L87 const CJS_CONTENT_REGEX = /\bmodule\.exports\b|\bexports[.[]|\brequire\s*\(|\bObject\.(?:defineProperty|defineProperties|assign)\s*\(\s*exports\b/; diff --git a/code/core/src/core-server/presets/common-preset.ts b/code/core/src/core-server/presets/common-preset.ts index 9a32187c11f6..10f8be05614f 100644 --- a/code/core/src/core-server/presets/common-preset.ts +++ b/code/core/src/core-server/presets/common-preset.ts @@ -258,7 +258,7 @@ export const docs: PresetProperty<'docs'> = (docsOptions, { docs: docsMode }: CL export const managerHead = async (_: any, options: Options) => { const location = join(options.configDir, 'manager-head.html'); if (existsSync(location)) { - const contents = readFile(location, { encoding: 'utf-8' }); + const contents = readFile(location, { encoding: 'utf8' }); const interpolations = options.presets.apply>('env'); return interpolate(await contents, await interpolations); diff --git a/code/core/src/core-server/utils/StoryIndexGenerator.ts b/code/core/src/core-server/utils/StoryIndexGenerator.ts index b3bc3239b983..fb2a0f4b887c 100644 --- a/code/core/src/core-server/utils/StoryIndexGenerator.ts +++ b/code/core/src/core-server/utils/StoryIndexGenerator.ts @@ -756,7 +756,7 @@ export class StoryIndexGenerator { .map((ext) => join(this.options.configDir, `preview.${ext}`)) .find((fname) => existsSync(fname)); - return previewFile && (await readFile(previewFile, { encoding: 'utf-8' })).toString(); + return previewFile && (await readFile(previewFile, { encoding: 'utf8' })).toString(); } getProjectTags(previewCode?: string) { diff --git a/code/core/src/core-server/utils/server-init.ts b/code/core/src/core-server/utils/server-init.ts index cdcd3c920543..60710cb19cfb 100644 --- a/code/core/src/core-server/utils/server-init.ts +++ b/code/core/src/core-server/utils/server-init.ts @@ -30,9 +30,9 @@ export async function getServer( } const sslOptions = { - ca: await Promise.all((options.sslCa || []).map((ca) => readFile(ca, { encoding: 'utf-8' }))), - cert: await readFile(options.sslCert, { encoding: 'utf-8' }), - key: await readFile(options.sslKey, { encoding: 'utf-8' }), + ca: await Promise.all((options.sslCa || []).map((ca) => readFile(ca, { encoding: 'utf8' }))), + cert: await readFile(options.sslCert, { encoding: 'utf8' }), + key: await readFile(options.sslKey, { encoding: 'utf8' }), }; return https.createServer(sslOptions, app); diff --git a/code/core/src/telemetry/get-monorepo-type.ts b/code/core/src/telemetry/get-monorepo-type.ts index e004365fcbb0..143241b0a214 100644 --- a/code/core/src/telemetry/get-monorepo-type.ts +++ b/code/core/src/telemetry/get-monorepo-type.ts @@ -36,7 +36,7 @@ export const getMonorepoType = (): MonorepoType => { } const packageJson = JSON.parse( - readFileSync(join(projectRootPath, 'package.json'), { encoding: 'utf-8' }) + readFileSync(join(projectRootPath, 'package.json'), { encoding: 'utf8' }) ) as PackageJson; if (packageJson?.workspaces) { diff --git a/code/core/src/telemetry/package-json.ts b/code/core/src/telemetry/package-json.ts index 3bf006115c4a..4104425fc2d0 100644 --- a/code/core/src/telemetry/package-json.ts +++ b/code/core/src/telemetry/package-json.ts @@ -24,6 +24,6 @@ export const getActualPackageJson = async (packageName: string) => { const resolvedPackageJson = require.resolve(join(packageName, 'package.json'), { paths: [process.cwd()], }); - const packageJson = JSON.parse(await readFile(resolvedPackageJson, { encoding: 'utf-8' })); + const packageJson = JSON.parse(await readFile(resolvedPackageJson, { encoding: 'utf8' })); return packageJson; }; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts b/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts index d5277a5e8c92..bf87b5fed74f 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/mdx-1-to-3.ts @@ -74,7 +74,7 @@ export const mdx1to3: Fix = { async run({ result: { storiesMdxFiles }, dryRun }) { await Promise.all([ ...storiesMdxFiles.map(async (fname) => { - const contents = await readFile(fname, { encoding: 'utf-8' }); + const contents = await readFile(fname, { encoding: 'utf8' }); const updated = fixMdxComments(fixMdxStyleTags(contents)); if (updated === contents) { logger.info(`🆗 Unmodified ${basename(fname)}`); diff --git a/code/lib/cli-storybook/src/link.ts b/code/lib/cli-storybook/src/link.ts index a858847e26b2..8f0b2ed6718c 100644 --- a/code/lib/cli-storybook/src/link.ts +++ b/code/lib/cli-storybook/src/link.ts @@ -61,7 +61,7 @@ export const exec = async ( export const link = async ({ target, local, start }: LinkOptions) => { const storybookDir = process.cwd(); try { - const packageJson = JSON.parse(await readFile('package.json', { encoding: 'utf-8' })); + const packageJson = JSON.parse(await readFile('package.json', { encoding: 'utf8' })); if (packageJson.name !== '@storybook/root') { throw new Error(); } @@ -87,7 +87,7 @@ export const link = async ({ target, local, start }: LinkOptions) => { } const reproPackageJson = JSON.parse( - await readFile(join(reproDir, 'package.json'), { encoding: 'utf-8' }) + await readFile(join(reproDir, 'package.json'), { encoding: 'utf8' }) ); const version = spawnSync('yarn', ['--version'], { diff --git a/code/renderers/server/src/preset.ts b/code/renderers/server/src/preset.ts index 04937a0b8c14..197a303bb15b 100644 --- a/code/renderers/server/src/preset.ts +++ b/code/renderers/server/src/preset.ts @@ -18,7 +18,7 @@ export const experimental_indexers: PresetProperty<'experimental_indexers'> = ( { test: /(stories|story)\.(json|ya?ml)$/, createIndex: async (fileName) => { - const rawFile = await readFile(fileName, { encoding: 'utf-8' }); + const rawFile = await readFile(fileName, { encoding: 'utf8' }); const content: FileContent = fileName.endsWith('.json') ? JSON.parse(rawFile) : yaml.parse(rawFile); From 0002066784477d9cfcb6228de5f8a2da4d7d4168 Mon Sep 17 00:00:00 2001 From: shreysinha25 Date: Sun, 15 Sep 2024 16:32:32 +0530 Subject: [PATCH 101/213] fix issue #29122 [Bug]: Brand image css class conflict causes image to resize on hot reloads --- code/core/src/manager/components/sidebar/Brand.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/src/manager/components/sidebar/Brand.tsx b/code/core/src/manager/components/sidebar/Brand.tsx index 995b924948ec..f4ca666e0579 100644 --- a/code/core/src/manager/components/sidebar/Brand.tsx +++ b/code/core/src/manager/components/sidebar/Brand.tsx @@ -12,7 +12,7 @@ export const StorybookLogoStyled = styled(StorybookLogo)(({ theme }) => ({ export const Img = styled.img({ display: 'block', - maxWidth: '150px', + maxWidth: '150px !important', maxHeight: '100px', }); From f5537b925a6649a3bae958626dfe965247a215de Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 16 Sep 2024 09:29:49 +0200 Subject: [PATCH 102/213] add analyzed metafiles to the output --- code/core/scripts/prep.ts | 10 +++--- scripts/prepare/bundle.ts | 65 +++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/code/core/scripts/prep.ts b/code/core/scripts/prep.ts index 355942e61156..308ff628c638 100644 --- a/code/core/scripts/prep.ts +++ b/code/core/scripts/prep.ts @@ -325,15 +325,15 @@ async function run() { const { outputs } = out.metafile; const keys = Object.keys(outputs); const format = keys.every((key) => key.endsWith('.js')) ? 'esm' : 'cjs'; - const outName = - keys.length === 1 ? dirname(keys[0]).replace('dist/', '') : `core.${format}-${index}`; + const basename = + keys.length === 1 ? dirname(keys[0]).replace('dist/', '') : `core-${format}-${index}`; - await await writeFile( - join(metafilesDir, `${outName}.json`), + await writeFile( + join(metafilesDir, `${basename}.json`), JSON.stringify(out.metafile, null, 2) ); await writeFile( - join(metafilesDir, `${outName}.txt`), + join(metafilesDir, `${basename}.txt`), await esbuild.analyzeMetafile(out.metafile, { color: false, verbose: false }) ); }) diff --git a/scripts/prepare/bundle.ts b/scripts/prepare/bundle.ts index b271837135ec..4cdd887094ce 100755 --- a/scripts/prepare/bundle.ts +++ b/scripts/prepare/bundle.ts @@ -1,3 +1,4 @@ +import { writeFile } from 'node:fs/promises'; import { dirname, join, parse, posix, relative, resolve, sep } from 'node:path'; import aliasPlugin from 'esbuild-plugin-alias'; @@ -10,6 +11,7 @@ import { build } from 'tsup'; import type { PackageJson } from 'type-fest'; import { exec } from '../utils/exec'; +import { esbuild } from './tools'; /* TYPES */ @@ -30,6 +32,16 @@ type DtsConfigSection = Pick; /* MAIN */ +const METAFILES_DIR = join( + __dirname, + '..', + '..', + 'bench', + 'esbuild-metafiles', + process.cwd().split(sep).at(-1) +); +const OUT_DIR = join(process.cwd(), 'dist'); + const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { const { name, @@ -53,14 +65,13 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { const reset = hasFlag(flags, 'reset'); const watch = hasFlag(flags, 'watch'); const optimized = hasFlag(flags, 'optimized'); - if (reset) { - await fs.emptyDir(join(process.cwd(), 'dist')); + await fs.emptyDir(OUT_DIR); + await fs.emptyDir(METAFILES_DIR); } const tasks: Promise[] = []; - const outDir = join(process.cwd(), 'dist'); const externals = [ name, ...extraExternals, @@ -93,7 +104,7 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { entry: nonPresetEntries, shims: false, watch, - outDir, + outDir: OUT_DIR, sourcemap: false, metafile: true, format: ['esm'], @@ -128,7 +139,7 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { silent: true, entry: allEntries, watch, - outDir, + outDir: OUT_DIR, sourcemap: false, metafile: true, format: ['cjs'], @@ -153,15 +164,10 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { await Promise.all(tasks); if (!watch) { - if (formats.includes('cjs')) { - await moveMetafile({ name, format: 'cjs', outDir }); - } - if (formats.includes('esm')) { - await moveMetafile({ name, format: 'esm', outDir }); - } + await saveMetafiles({ formats }); } - const dtsFiles = await glob(outDir + '/**/*.d.ts'); + const dtsFiles = await glob(OUT_DIR + '/**/*.d.ts'); await Promise.all( dtsFiles.map(async (file) => { const content = await fs.readFile(file, 'utf-8'); @@ -236,27 +242,20 @@ async function generateDTSMapperFile(file: string) { ); } -async function moveMetafile({ - name, - format, - outDir, -}: { - name: string; - format: 'esm' | 'cjs'; - outDir: string; -}) { - const metafilesDir = join(__dirname, '..', '..', 'bench', 'esbuild-metafiles'); - await fs.ensureDir(metafilesDir); - const packageDir = process.cwd().includes('addons/test') - ? 'addon-test' // special case, because @storybook/addon-test and @storybook/test have the same leaf dirname - : process.cwd().split(sep).at(-1); - - console.log('LOG: ', join(metafilesDir, packageDir, `${format}.json`)); - - await fs.move( - join(outDir, `metafile-${format}.json`), - join(metafilesDir, packageDir, `${format}.json`), - { overwrite: true } +async function saveMetafiles({ formats }: { formats: Formats[] }) { + await fs.ensureDir(METAFILES_DIR); + await Promise.all( + formats.map(async (format) => { + const basename = `metafile-${format}`; + const metafile = await fs.readJson(join(OUT_DIR, `${basename}.json`)); + await fs.move(join(OUT_DIR, `${basename}.json`), join(METAFILES_DIR, `${basename}.json`), { + overwrite: true, + }); + await writeFile( + join(METAFILES_DIR, `${basename}.txt`), + await esbuild.analyzeMetafile(metafile, { color: false, verbose: false }) + ); + }) ); } From c5c640f299444fb7ca94142606435adc1354100a Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 16 Sep 2024 09:32:55 +0200 Subject: [PATCH 103/213] save metafiles from addons --- scripts/prepare/addon-bundle.ts | 216 ++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 80 deletions(-) diff --git a/scripts/prepare/addon-bundle.ts b/scripts/prepare/addon-bundle.ts index 14c62791514e..6a1f4ba58f7c 100755 --- a/scripts/prepare/addon-bundle.ts +++ b/scripts/prepare/addon-bundle.ts @@ -1,3 +1,4 @@ +import { writeFile } from 'node:fs/promises'; import { builtinModules } from 'node:module'; import aliasPlugin from 'esbuild-plugin-alias'; @@ -13,6 +14,7 @@ import type { PackageJson } from 'type-fest'; import { globalPackages as globalManagerPackages } from '../../code/core/src/manager/globals/globals'; import { globalPackages as globalPreviewPackages } from '../../code/core/src/preview/globals/globals'; import { exec } from '../utils/exec'; +import { esbuild } from './tools'; /* TYPES */ @@ -34,6 +36,18 @@ type DtsConfigSection = Pick; /* MAIN */ +const METAFILES_DIR = join( + __dirname, + '..', + '..', + 'bench', + 'esbuild-metafiles', + process.cwd().includes('addons/test') + ? 'addon-test' // special case, because @storybook/addon-test and @storybook/test have the same leaf dirname + : process.cwd().split(sep).at(-1) +); +const OUT_DIR = join(process.cwd(), 'dist'); + export const nodeInternals = [ 'module', 'node:module', @@ -66,14 +80,15 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { const optimized = hasFlag(flags, 'optimized'); if (reset) { - await fs.emptyDir(join(process.cwd(), 'dist')); + await fs.emptyDir(OUT_DIR); + await fs.emptyDir(METAFILES_DIR); } - const tasks: Promise[] = []; + const tasks: (() => Promise)[] = []; - const outDir = join(process.cwd(), 'dist'); const commonOptions: Options = { - outDir, + outDir: OUT_DIR, + metafile: true, silent: true, treeshake: true, shims: false, @@ -117,37 +132,42 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { optimized, }); - tasks.push( - build({ - ...commonOptions, - ...(optimized ? dtsConfig : {}), - ...browserOptions, - entry: exportEntries, - external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages], - }), - build({ - ...commonOptions, - ...(optimized ? dtsConfig : {}), - entry: exportEntries, - format: ['cjs'], - target: browserOptions.target, - platform: 'neutral', - external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages], - esbuildOptions: (options) => { - options.platform = 'neutral'; - Object.assign(options, getESBuildOptions(optimized)); - }, - }) - ); + tasks.push(async () => { + await Promise.all([ + build({ + ...commonOptions, + ...(optimized ? dtsConfig : {}), + ...browserOptions, + entry: exportEntries, + external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages], + }), + build({ + ...commonOptions, + ...(optimized ? dtsConfig : {}), + entry: exportEntries, + format: ['cjs'], + target: browserOptions.target, + platform: 'neutral', + external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages], + esbuildOptions: (options) => { + options.platform = 'neutral'; + Object.assign(options, getESBuildOptions(optimized)); + }, + }), + ]); + if (!watch) { + await saveMetafiles({ name: 'exportEntries', formats: ['esm', 'cjs'] }); + } + }); if (tsConfigExists && !optimized) { - tasks.push(...exportEntries.map(generateDTSMapperFile)); + tasks.push(...exportEntries.map((entry) => () => generateDTSMapperFile(entry))); } } if (managerEntries.length > 0) { - tasks.push( - build({ + tasks.push(async () => { + await build({ ...commonOptions, ...browserOptions, entry: managerEntries.map((e: string) => slash(join(cwd, e))), @@ -155,8 +175,11 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { js: '.js', }), external: [...commonExternals, ...globalManagerPackages], - }) - ); + }); + if (!watch) { + await saveMetafiles({ name: 'managerEntries', formats: ['esm'] }); + } + }); } if (previewEntries.length > 0) { @@ -165,19 +188,22 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { entries: previewEntries, optimized, }); - tasks.push( - build({ + tasks.push(async () => { + await build({ ...commonOptions, ...(optimized ? dtsConfig : {}), ...browserOptions, format: ['esm', 'cjs'], entry: previewEntries.map((e: string) => slash(join(cwd, e))), external: [...commonExternals, ...globalPreviewPackages], - }) - ); + }); + if (!watch) { + await saveMetafiles({ name: 'previewEntries', formats: ['esm', 'cjs'] }); + } + }); if (tsConfigExists && !optimized) { - tasks.push(...previewEntries.map(generateDTSMapperFile)); + tasks.push(...previewEntries.map((entry) => () => generateDTSMapperFile(entry))); } } @@ -187,56 +213,61 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { entries: nodeEntries, optimized, }); - tasks.push( - build({ - ...commonOptions, - entry: nodeEntries.map((e: string) => slash(join(cwd, e))), - format: ['cjs'], - target: 'node18', - platform: 'node', - external: commonExternals, - esbuildOptions: (c) => { - c.platform = 'node'; - Object.assign(c, getESBuildOptions(optimized)); - }, - }) - ); - tasks.push( - build({ - ...commonOptions, - ...(optimized ? dtsConfig : {}), - entry: nodeEntries.map((e: string) => slash(join(cwd, e))), - format: ['esm'], - target: 'node18', - platform: 'neutral', - banner: { - js: dedent` - import ESM_COMPAT_Module from "node:module"; - import { fileURLToPath as ESM_COMPAT_fileURLToPath } from 'node:url'; - import { dirname as ESM_COMPAT_dirname } from 'node:path'; - const __filename = ESM_COMPAT_fileURLToPath(import.meta.url); - const __dirname = ESM_COMPAT_dirname(__filename); - const require = ESM_COMPAT_Module.createRequire(import.meta.url); - `, - }, - external: [...commonExternals, ...nodeInternals], - esbuildOptions: (c) => { - c.mainFields = ['main', 'module', 'node']; - c.conditions = ['node', 'module', 'import', 'require']; - c.platform = 'neutral'; - Object.assign(c, getESBuildOptions(optimized)); - }, - }) - ); + tasks.push(async () => { + await Promise.all([ + build({ + ...commonOptions, + entry: nodeEntries.map((e: string) => slash(join(cwd, e))), + format: ['cjs'], + target: 'node18', + platform: 'node', + external: commonExternals, + esbuildOptions: (c) => { + c.platform = 'node'; + Object.assign(c, getESBuildOptions(optimized)); + }, + }), + build({ + ...commonOptions, + ...(optimized ? dtsConfig : {}), + entry: nodeEntries.map((e: string) => slash(join(cwd, e))), + format: ['esm'], + target: 'node18', + platform: 'neutral', + banner: { + js: dedent` + import ESM_COMPAT_Module from "node:module"; + import { fileURLToPath as ESM_COMPAT_fileURLToPath } from 'node:url'; + import { dirname as ESM_COMPAT_dirname } from 'node:path'; + const __filename = ESM_COMPAT_fileURLToPath(import.meta.url); + const __dirname = ESM_COMPAT_dirname(__filename); + const require = ESM_COMPAT_Module.createRequire(import.meta.url); + `, + }, + external: [...commonExternals, ...nodeInternals], + esbuildOptions: (c) => { + c.mainFields = ['main', 'module', 'node']; + c.conditions = ['node', 'module', 'import', 'require']; + c.platform = 'neutral'; + Object.assign(c, getESBuildOptions(optimized)); + }, + }), + ]); + if (!watch) { + await saveMetafiles({ name: 'nodeEntries', formats: ['esm', 'cjs'] }); + } + }); if (tsConfigExists && !optimized) { - tasks.push(...nodeEntries.map(generateDTSMapperFile)); + tasks.push(...nodeEntries.map((entry) => () => generateDTSMapperFile(entry))); } } - await Promise.all(tasks); + for (const task of tasks) { + await task(); + } - const dtsFiles = await glob(outDir + '/**/*.d.ts'); + const dtsFiles = await glob(OUT_DIR + '/**/*.d.ts'); await Promise.all( dtsFiles.map(async (file) => { const content = await fs.readFile(file, 'utf-8'); @@ -311,6 +342,31 @@ async function generateDTSMapperFile(file: string) { ); } +async function saveMetafiles({ + name, + formats, +}: { + name: 'exportEntries' | 'managerEntries' | 'previewEntries' | 'nodeEntries'; + formats: Formats[]; +}) { + await fs.ensureDir(METAFILES_DIR); + await Promise.all( + formats.map(async (format) => { + const fromFilename = `metafile-${format}.json`; + const toBasename = `${name}-${format}`; + + const metafile = await fs.readJson(join(OUT_DIR, fromFilename)); + await fs.move(join(OUT_DIR, fromFilename), join(METAFILES_DIR, `${toBasename}.json`), { + overwrite: true, + }); + await writeFile( + join(METAFILES_DIR, `${toBasename}.txt`), + await esbuild.analyzeMetafile(metafile, { color: false, verbose: false }) + ); + }) + ); +} + const hasFlag = (flags: string[], name: string) => !!flags.find((s) => s.startsWith(`--${name}`)); /* SELF EXECUTION */ From 8c58016b55eaffa301118d0b68628b01c18f448e Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Mon, 16 Sep 2024 12:00:10 +0200 Subject: [PATCH 104/213] CLI: Fix skip-install for stable latest releases --- .../JsPackageManager.test.ts | 54 +++++++++++++++++++ .../js-package-manager/JsPackageManager.ts | 12 ++--- 2 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 code/core/src/common/js-package-manager/JsPackageManager.test.ts diff --git a/code/core/src/common/js-package-manager/JsPackageManager.test.ts b/code/core/src/common/js-package-manager/JsPackageManager.test.ts new file mode 100644 index 000000000000..153edd0be596 --- /dev/null +++ b/code/core/src/common/js-package-manager/JsPackageManager.test.ts @@ -0,0 +1,54 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { JsPackageManager } from './JsPackageManager'; + +vi.mock('../versions', () => ({ + default: { + '@storybook/react': '8.3.0', + }, +})); + +describe('JsPackageManager', () => { + let jsPackageManager: JsPackageManager; + let mockLatestVersion: ReturnType; + let mockStorybookPackagesVersions: Record; + + beforeEach(() => { + mockLatestVersion = vi.fn(); + mockStorybookPackagesVersions = { + '@storybook/react': '8.3.0', + }; + + // @ts-expect-error Ignore abstract class error + jsPackageManager = new JsPackageManager(); + jsPackageManager.latestVersion = mockLatestVersion; + + vi.clearAllMocks(); + }); + + describe('getVersionedPackages method', () => { + it('should return the latest stable release version when current version is the latest stable release', async () => { + mockLatestVersion.mockResolvedValue('8.3.0'); + + const result = await jsPackageManager.getVersionedPackages(['@storybook/react']); + + expect(result).toEqual(['@storybook/react@^8.3.0']); + }); + + it('should return the current version when it is not the latest stable release', async () => { + mockLatestVersion.mockResolvedValue('8.3.1'); + + const result = await jsPackageManager.getVersionedPackages(['@storybook/react']); + + expect(result).toEqual(['@storybook/react@8.3.0']); + }); + + it('should return the latest stable release version when there is no current version', async () => { + mockLatestVersion.mockResolvedValue('2.0.0'); + + const result = await jsPackageManager.getVersionedPackages(['@storybook/new-addon@^8.3.0']); + + expect(result).toEqual(['@storybook/new-addon@^2.0.0']); + }); + }); +}); diff --git a/code/core/src/common/js-package-manager/JsPackageManager.ts b/code/core/src/common/js-package-manager/JsPackageManager.ts index 4b3e00c2f5e7..305ba8d99ed2 100644 --- a/code/core/src/common/js-package-manager/JsPackageManager.ts +++ b/code/core/src/common/js-package-manager/JsPackageManager.ts @@ -337,13 +337,13 @@ export abstract class JsPackageManager { const k = packageName as keyof typeof storybookPackagesVersions; const currentVersion = storybookPackagesVersions[k]; - if (currentVersion === latestInRange) { - return `${packageName}`; - } - if (currentVersion) { - return `${packageName}@${currentVersion}`; + const isLatestStableRelease = currentVersion === latestInRange; + + if (isLatestStableRelease || !currentVersion) { + return `${packageName}@^${latestInRange}`; } - return `${packageName}@^${latestInRange}`; + + return `${packageName}@${currentVersion}`; }) ); } From a3d75f58037260703c9d6d5fd70735a81352fbfb Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Mon, 16 Sep 2024 12:23:52 +0200 Subject: [PATCH 105/213] Core: Do not prebundle jsdoc-type-pratt-parser --- code/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/package.json b/code/core/package.json index 181b04312985..cd21b877c41c 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -283,6 +283,7 @@ "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", "esbuild-register": "^3.5.0", "express": "^4.19.2", + "jsdoc-type-pratt-parser": "^4.0.0", "process": "^0.11.10", "recast": "^0.23.5", "semver": "^7.6.2", @@ -378,7 +379,6 @@ "globby": "^14.0.1", "handlebars": "^4.7.7", "js-yaml": "^4.1.0", - "jsdoc-type-pratt-parser": "^4.0.0", "lazy-universal-dotenv": "^4.0.0", "leven": "^4.0.0", "lodash": "^4.17.21", From b40b44fe6d3c506b5c658f510f83592bebb036f7 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Mon, 16 Sep 2024 14:17:05 +0200 Subject: [PATCH 106/213] Core: Do not prebundle better-opn --- code/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/package.json b/code/core/package.json index 181b04312985..1d0ea0942bed 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -279,6 +279,7 @@ "dependencies": { "@storybook/csf": "^0.1.11", "@types/express": "^4.17.21", + "better-opn": "^3.0.2", "browser-assert": "^1.2.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", "esbuild-register": "^3.5.0", @@ -340,7 +341,6 @@ "ansi-to-html": "^0.7.2", "assert": "^2.1.0", "babel-plugin-react-docgen": "4.2.1", - "better-opn": "^3.0.2", "boxen": "^7.1.1", "browser-dtector": "^3.4.0", "camelcase": "^8.0.0", From 1f25aafaa407e802d2fc841acba16706b7ae9942 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 16 Sep 2024 19:49:11 +0200 Subject: [PATCH 107/213] add bench story that visualizes metafiles --- code/.storybook/bench.stories.tsx | 120 ++++++++++++++++++++++++++++++ code/.storybook/main.ts | 1 + 2 files changed, 121 insertions(+) create mode 100644 code/.storybook/bench.stories.tsx diff --git a/code/.storybook/bench.stories.tsx b/code/.storybook/bench.stories.tsx new file mode 100644 index 000000000000..ce3221a7786f --- /dev/null +++ b/code/.storybook/bench.stories.tsx @@ -0,0 +1,120 @@ +import React from 'react'; + +import type { Meta } from '@storybook/react'; + +// @ts-expect-error - TS doesn't know about import.meta.glob from Vite +const allMetafiles = import.meta.glob( + [ + '../../bench/esbuild-metafiles/**/*.json', + // the following metafiles are too big to be loaded automatically in the iframe + '!**/core-cjs-0.json', + '!**/core-esm-2.json', + ], + { + // eagerly loading is not ideal because it imports all metafiles upfront, + // but it's the only way to create the argTypes from this list, + // as otherwise it would be an async operation + eager: true, + } +); +console.log('LOG: ', { allMetafiles }); +const METAFILES_DIR = '../../bench/esbuild-metafiles/'; +const METAFILE_DIR_PKG_NAME_MAP = { + cli: 'storybook', + 'cli-sb': 'sb', + 'cli-storybook': '@storybook/cli', + docs: '@storybook/addon-docs', + 'addon-test': '@storybook/experimental-addon-test', +} as const; +const TOO_BIG_METAFILES = ['@storybook/core core-cjs-0', '@storybook/core core-esm-2']; + +// allows the metafile path to be used in the URL hash +const safeMetafileArg = (path: string) => + path.replace(METAFILES_DIR, '').replaceAll('/', '_SLASH_').replaceAll('.', '_DOT_'); + +export default { + title: 'Bench', + parameters: { + layout: 'fullscreen', + chromatic: { disableSnapshot: true }, + }, + argTypes: { + metafile: { + options: Object.keys(allMetafiles).map(safeMetafileArg).concat(TOO_BIG_METAFILES), + mapping: Object.fromEntries( + Object.keys(allMetafiles).map((path) => [safeMetafileArg(path), path]) + ), + control: { + type: 'select', + labels: Object.fromEntries( + Object.keys(allMetafiles) + .concat(TOO_BIG_METAFILES) + .map((path) => { + if (TOO_BIG_METAFILES.includes(path)) { + return [path, `${path} - TOO BIG PLEASE UPLOAD MANUALLY`]; + } + // example path: ../../bench/esbuild-metafiles/actions/previewEntries-esm.json + + const pkgDir = path.split('/').at(-2)!; // 'actions' + const basename = path.split('/').at(-1)!.split('.').at(0)!; // 'previewEntries-esm' + const entriesMatch = path.match(/\w+Entries/); // ['previewEntries'] + + let pkgName; + if (pkgDir in METAFILE_DIR_PKG_NAME_MAP) { + pkgName = METAFILE_DIR_PKG_NAME_MAP[pkgDir]; + } else if (entriesMatch) { + // only addons have specific xEntries files + pkgName = `@storybook/addon-${pkgDir}`; + } else { + pkgName = `@storybook/${pkgDir}`; + } + + let extraInfo = ''; + + if (pkgDir === 'core') { + extraInfo = `- ${basename} `; + } else if (entriesMatch) { + extraInfo = `- ${entriesMatch[0]} `; + } + const moduleType = path.includes('cjs') ? 'CJS' : 'ESM'; + + return [safeMetafileArg(path), `${pkgName} ${extraInfo}- ${moduleType}`]; + }) + ), + }, + }, + }, + render: (args) => { + if (!args.metafile) { + return ( +
+ + Select a metafile in the metafile Control + +
+ ); + } + const metafile = allMetafiles[args.metafile]; + const encodedMetafile = btoa(JSON.stringify(metafile)); + + return ( +