diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 871971bac231..90f09cc9f0d3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -19,18 +19,19 @@ body: attributes: label: To Reproduce description: >- - We prioritize bug reports that have a reproduction. You can create a reproduction using [storybook.new](https://storybook.new), or by running `npx sb@next sandbox` and - following the instructions. Read our - [documentation](https://storybook.js.org/docs/react/contribute/how-to-reproduce) - to learn more about creating reproductions. + Due to the high volume of reports we receive, we can only prioritize bug reports that include a clear reproduction of the problem. Please use [storybook.new](https://storybook.new) to create one, and consult our [documentation](https://storybook.js.org/docs/react/contribute/how-to-reproduce) for guidance. Thank you for your understanding! placeholder: >- - Paste a link to your reproduction here. We prioritize issues with reproductions over those without. + Please provide a link to your reproduction here. If creating a reproduction really isn't feasible, let us know and be sure to include as much detail as you can to help us understand the issue. + validations: + required: true - type: textarea id: system attributes: label: System description: Please paste the results of `npx storybook@latest info` here. render: bash + validations: + required: true - type: textarea id: context attributes: diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index cae0fb533129..3474586b1d3f 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,13 @@ +## 8.1.0-alpha.2 + +- CLI: Automigrate improve upgrade storybook related packages - [#26497](https://github.com/storybookjs/storybook/pull/26497), thanks @ndelangen! +- CLI: Improve `vite-config-file.ts` - [#26375](https://github.com/storybookjs/storybook/pull/26375), thanks @joevaugh4n! +- Controls: Fix number controls do not reset - [#26372](https://github.com/storybookjs/storybook/pull/26372), thanks @jiyiru! +- Core: Optimize clearNotification - [#26415](https://github.com/storybookjs/storybook/pull/26415), thanks @ndelangen! +- Portable stories: Make setProjectAnnotations accept multiple types of imports - [#26316](https://github.com/storybookjs/storybook/pull/26316), thanks @yannbf! +- UI: Add key property to list children in Highlight component - [#26471](https://github.com/storybookjs/storybook/pull/26471), thanks @valentinpalkovic! +- UI: Fix search result color contrast - [#26287](https://github.com/storybookjs/storybook/pull/26287), thanks @winchesHe! + ## 8.1.0-alpha.1 - Maintenance: Fix performance regressions - [#26411](https://github.com/storybookjs/storybook/pull/26411), thanks @kasperpeulen! diff --git a/code/addons/actions/src/runtime/action.ts b/code/addons/actions/src/runtime/action.ts index a647a8eb0d1b..fab9e8aae1d4 100644 --- a/code/addons/actions/src/runtime/action.ts +++ b/code/addons/actions/src/runtime/action.ts @@ -21,10 +21,9 @@ const isReactSyntheticEvent = (e: unknown): e is SyntheticEvent => findProto(e, (proto) => /^Synthetic(?:Base)?Event$/.test(proto.constructor.name)) && typeof (e as SyntheticEvent).persist === 'function' ); -const serializeArg = (a: T) => { +const serializeArg = (a: T) => { if (isReactSyntheticEvent(a)) { const e: SyntheticEvent = Object.create( - // @ts-expect-error (Converted from ts-ignore) a.constructor.prototype, Object.getOwnPropertyDescriptors(a) ); diff --git a/code/addons/interactions/src/components/InteractionsPanel.stories.tsx b/code/addons/interactions/src/components/InteractionsPanel.stories.tsx index 89f7ef115b59..5f8dd331935b 100644 --- a/code/addons/interactions/src/components/InteractionsPanel.stories.tsx +++ b/code/addons/interactions/src/components/InteractionsPanel.stories.tsx @@ -3,7 +3,7 @@ import type { StoryObj, Meta } from '@storybook/react'; import { CallStates } from '@storybook/instrumenter'; import { styled } from '@storybook/theming'; import { userEvent, within, waitFor, expect } from '@storybook/test'; -import isChromatic from 'chromatic/isChromatic'; +import { isChromatic } from '../../../../ui/.storybook/isChromatic'; import { getCalls, getInteractions } from '../mocks'; import { InteractionsPanel } from './InteractionsPanel'; diff --git a/code/addons/links/src/utils.ts b/code/addons/links/src/utils.ts index 51d8c09c5fc4..651183a9df66 100644 --- a/code/addons/links/src/utils.ts +++ b/code/addons/links/src/utils.ts @@ -37,9 +37,7 @@ export const hrefTo = (title: ComponentTitle, name: StoryName): Promise return new Promise((resolve) => { const { location } = document; const query = parseQuery(location.search); - // @ts-expect-error (Converted from ts-ignore) - const existingId = [].concat(query.id)[0]; - // @ts-expect-error (Converted from ts-ignore) + const existingId = query.id; const titleToLink = title || existingId.split('--', 2)[0]; const id = toId(titleToLink, name); const path = `/story/${id}`; diff --git a/code/chromatic.config.json b/code/chromatic.config.json index 01493ceba46a..77130b818b6d 100644 --- a/code/chromatic.config.json +++ b/code/chromatic.config.json @@ -3,6 +3,7 @@ "projectToken": "80b312430ec4", "buildScriptName": "storybook:ui:build", "onlyChanged": true, - "storybookConfigDir": "./ui/.storybook", - "storybookBaseDir": "./code" + "storybookConfigDir": "ui/.storybook", + "storybookBaseDir": "./code", + "zip": true } diff --git a/code/frameworks/react-vite/README.md b/code/frameworks/react-vite/README.md index 272f8f50d55f..847119afd03d 100644 --- a/code/frameworks/react-vite/README.md +++ b/code/frameworks/react-vite/README.md @@ -1,3 +1,3 @@ # Storybook for React & Vite -See [documentation](https://storybook.js.org/docs/8.0/get-started/react-vite?renderer=react) for installation instructions, usage examples, APIs, and more. \ No newline at end of file +See [documentation](https://storybook.js.org/docs/8.0/get-started/react-vite?renderer=react) for installation instructions, usage examples, APIs, and more. diff --git a/code/frameworks/react-webpack5/README.md b/code/frameworks/react-webpack5/README.md index 53e3de782715..d691444758e2 100644 --- a/code/frameworks/react-webpack5/README.md +++ b/code/frameworks/react-webpack5/README.md @@ -1,3 +1,3 @@ # Storybook for React & Webpack -See [documentation](https://storybook.js.org/docs/8.0/get-started/react-webpack5?renderer=react) for installation instructions, usage examples, APIs, and more. \ No newline at end of file +See [documentation](https://storybook.js.org/docs/8.0/get-started/react-webpack5?renderer=react) for installation instructions, usage examples, APIs, and more. diff --git a/code/frameworks/vue3-webpack5/README.md b/code/frameworks/vue3-webpack5/README.md index a4e696468d58..79644c76e821 100644 --- a/code/frameworks/vue3-webpack5/README.md +++ b/code/frameworks/vue3-webpack5/README.md @@ -1,3 +1,3 @@ # Storybook for Vue 3 and Webpack -See [documentation](https://storybook.js.org/docs/8.0/get-started/vue3-webpack5?renderer=vue) for installation instructions, usage examples, APIs, and more. \ No newline at end of file +See [documentation](https://storybook.js.org/docs/8.0/get-started/vue3-webpack5?renderer=vue) for installation instructions, usage examples, APIs, and more. diff --git a/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.test.ts b/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.test.ts index 0c16309647bd..7a8beeba0f76 100644 --- a/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.test.ts +++ b/code/lib/cli/src/automigrate/fixes/upgrade-storybook-related-dependencies.test.ts @@ -52,7 +52,7 @@ describe('upgrade-storybook-related-dependencies fix', () => { { packageName: 'storybook', packageVersion: '8.0.0', - availableUpgrade: undefined, + availableUpgrade: '8.0.0', hasIncompatibleDependencies: true, }, ]; @@ -60,14 +60,18 @@ describe('upgrade-storybook-related-dependencies fix', () => { await expect( check({ packageManager: { - getAllDependencies: async () => ({ - '@chromatic-com/storybook': '1.2.9', - '@storybook/jest': '0.2.3', - '@storybook/preset-create-react-app': '3.2.0', - storybook: '8.0.0', - }), + getAllDependencies: async () => + analyzedPackages.reduce( + (acc, { packageName, packageVersion }) => { + acc[packageName] = packageVersion; + return acc; + }, + {} as Record + ), latestVersion: async (pkgName) => analyzedPackages.find((pkg) => pkg.packageName === pkgName)?.availableUpgrade || '', + getInstalledVersion: async (pkgName) => + analyzedPackages.find((pkg) => pkg.packageName === pkgName)?.packageVersion || null, }, }) ).resolves.toMatchInlineSnapshot(` 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 5614b7e35ad0..c5a9d4218bb5 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,6 +1,6 @@ import { dedent } from 'ts-dedent'; import { cyan, yellow } from 'chalk'; -import { valid, coerce } from 'semver'; +import { gt } from 'semver'; import type { JsPackageManager } from '@storybook/core-common'; import { isCorePackage } from '@storybook/core-common'; import type { Fix } from '../types'; @@ -21,24 +21,14 @@ async function getLatestVersions( packages: [string, string][] ): Promise { return Promise.all( - packages.map(async ([packageName, beforeVersion]) => ({ + packages.map(async ([packageName]) => ({ packageName, - beforeVersion: coerce(beforeVersion)?.toString() || null, + beforeVersion: await packageManager.getInstalledVersion(packageName).catch(() => null), afterVersion: await packageManager.latestVersion(packageName).catch(() => null), })) ); } -function isPackageUpgradable( - afterVersion: string, - packageName: string, - allDependencies: Record -) { - const installedVersion = coerce(allDependencies[packageName])?.toString(); - - return valid(afterVersion) && afterVersion !== installedVersion; -} - /** * Is the user upgrading to the `latest` version of Storybook? * Let's try to pull along some of the storybook related dependencies to `latest` as well! @@ -75,15 +65,13 @@ export const upgradeStorybookRelatedDependencies = { const packageVersions = await getLatestVersions(packageManager, uniquePackages); - const upgradablePackages = packageVersions.filter( - ({ packageName, afterVersion, beforeVersion }) => { - if (beforeVersion === null || afterVersion === null) { - return false; - } - - return isPackageUpgradable(afterVersion, packageName, allDependencies); + const upgradablePackages = packageVersions.filter(({ afterVersion, beforeVersion }) => { + if (beforeVersion === null || afterVersion === null) { + return false; } - ); + + return gt(afterVersion, beforeVersion); + }); return upgradablePackages.length > 0 ? { upgradable: upgradablePackages } : null; }, diff --git a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts index 9203b45f225f..e81637dc6cb2 100644 --- a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts +++ b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts @@ -97,12 +97,12 @@ export const viteConfigFile = { prompt({ existed, plugins }) { if (existed) { return dedent` - Since version 8.0.0, Storybook no longer ships with a Vite config build-in. + Since version 8.0.0, Storybook no longer ships with an in-built Vite config. We've detected you do have a Vite config, but you may be missing the following plugins in it. ${plugins.map((plugin) => ` - ${plugin}`).join('\n')} - If you do already have these plugins, you can ignore this message. + If you already have these plugins, you can ignore this message. You can find more information on how to do this here: https://storybook.js.org/docs/8.0/migration-guide/#missing-viteconfigjs-file @@ -111,7 +111,7 @@ export const viteConfigFile = { `; } return dedent` - Since version 8.0.0, Storybook no longer ships with a Vite config build-in. + Since version 8.0.0, Storybook no longer ships with an in-built Vite config. Please add a vite.config.js file to your project root. You can find more information on how to do this here: diff --git a/code/lib/cli/src/generate.ts b/code/lib/cli/src/generate.ts index 53c6259dc35b..6830aea3d1c2 100644 --- a/code/lib/cli/src/generate.ts +++ b/code/lib/cli/src/generate.ts @@ -59,7 +59,7 @@ command('init') .option('-b --builder ', 'Builder library') .option('-l --linkable', 'Prepare installation for link (contributor helper)') .action((options: CommandOptions) => { - initiate(options, pkg).catch(() => process.exit(1)); + initiate(options).catch(() => process.exit(1)); }); command('add ') @@ -155,7 +155,7 @@ command('sandbox [filterValue]') .option('-o --output ', 'Define an output directory') .option('--no-init', 'Whether to download a template without an initialized Storybook', false) .action((filterValue, options) => - sandbox({ filterValue, ...options }, pkg).catch((e) => { + sandbox({ filterValue, ...options }).catch((e) => { logger.error(e); process.exit(1); }) diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index b5504f2f751e..730e4ce8dead 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -1,5 +1,4 @@ import { appendFile, readFile } from 'fs/promises'; -import type { PackageJson } from 'read-pkg-up'; import findUp from 'find-up'; import chalk from 'chalk'; import prompts from 'prompts'; @@ -228,10 +227,7 @@ const projectTypeInquirer = async ( process.exit(0); }; -export async function doInitiate( - options: CommandOptions, - pkg: PackageJson -): Promise< +export async function doInitiate(options: CommandOptions): Promise< | { shouldRunDev: true; projectType: ProjectType; @@ -409,14 +405,14 @@ export async function doInitiate( }; } -export async function initiate(options: CommandOptions, pkg: PackageJson): Promise { +export async function initiate(options: CommandOptions): Promise { const initiateResult = await withTelemetry( 'init', { cliOptions: options, printError: (err) => !err.handled && logger.error(err), }, - () => doInitiate(options, pkg) + () => doInitiate(options) ); if (initiateResult?.shouldRunDev) { diff --git a/code/lib/cli/src/sandbox.ts b/code/lib/cli/src/sandbox.ts index d7d5892abd5b..d06c633c1a4d 100644 --- a/code/lib/cli/src/sandbox.ts +++ b/code/lib/cli/src/sandbox.ts @@ -10,7 +10,7 @@ import invariant from 'tiny-invariant'; import { lt, prerelease } from 'semver'; import type { Template, TemplateKey } from './sandbox-templates'; import { allTemplates as TEMPLATES } from './sandbox-templates'; -import type { PackageJson, PackageManagerName } from '@storybook/core-common'; +import type { PackageManagerName } from '@storybook/core-common'; import { JsPackageManagerFactory } from '@storybook/core-common'; import { versions } from '@storybook/core-common'; import { doInitiate } from './initiate'; @@ -28,10 +28,12 @@ type Choice = keyof typeof TEMPLATES; const toChoices = (c: Choice): prompts.Choice => ({ title: TEMPLATES[c].name, value: c }); -export const sandbox = async ( - { output: outputDirectory, filterValue, init, ...options }: SandboxOptions, - pkg: PackageJson -) => { +export const sandbox = async ({ + output: outputDirectory, + filterValue, + init, + ...options +}: SandboxOptions) => { // Either get a direct match when users pass a template id, or filter through all templates let selectedConfig: Template | undefined = TEMPLATES[filterValue as TemplateKey]; let templateId: Choice | null = selectedConfig ? (filterValue as TemplateKey) : null; @@ -222,12 +224,9 @@ export const sandbox = async ( const before = process.cwd(); process.chdir(templateDestination); // we run doInitiate, instead of initiate, to avoid sending this init event to telemetry, because it's not a real world project - await doInitiate( - { - ...options, - }, - pkg - ); + await doInitiate({ + ...options, + }); process.chdir(before); } } catch (err) { 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 8523d7224eda..8f306850b032 100644 --- a/code/lib/core-common/src/js-package-manager/JsPackageManager.ts +++ b/code/lib/core-common/src/js-package-manager/JsPackageManager.ts @@ -17,6 +17,8 @@ const logger = console; export type PackageManagerName = 'npm' | 'yarn1' | 'yarn2' | 'pnpm'; +type StorybookPackage = keyof typeof storybookPackagesVersions; + /** * Extract package name and version from input * @@ -381,9 +383,8 @@ export abstract class JsPackageManager { public async getVersion(packageName: string, constraint?: string): Promise { let current: string | undefined; - if (/(@storybook|^sb$|^storybook$)/.test(packageName)) { - // @ts-expect-error (Converted from ts-ignore) - current = storybookPackagesVersions[packageName]; + if (packageName in storybookPackagesVersions) { + current = storybookPackagesVersions[packageName as StorybookPackage]; } let latest; @@ -535,6 +536,18 @@ export abstract class JsPackageManager { } } + /** + * Returns the installed (within node_modules or pnp zip) version of a specified package + */ + public async getInstalledVersion(packageName: string): Promise { + const installations = await this.findInstallations([packageName]); + if (!installations) { + return null; + } + + return Object.entries(installations.dependencies)[0]?.[1]?.[0].version || null; + } + public async executeCommand({ command, args = [], diff --git a/code/lib/manager-api/src/modules/notifications.ts b/code/lib/manager-api/src/modules/notifications.ts index 83e95d3928ca..3358dd67a241 100644 --- a/code/lib/manager-api/src/modules/notifications.ts +++ b/code/lib/manager-api/src/modules/notifications.ts @@ -37,11 +37,13 @@ export const init: ModuleFn = ({ store }) => { clearNotification: (id) => { const { notifications } = store.getState(); - store.setState({ notifications: notifications.filter((n) => n.id !== id) }); - const notification = notifications.find((n) => n.id === id); - if (notification && notification.onClear) { - notification.onClear({ dismissed: false }); + + if (notification) { + store.setState({ notifications: notifications.filter((n) => n.id !== id) }); + if (notification.onClear) { + notification.onClear({ dismissed: false }); + } } }, }; diff --git a/code/lib/preview-api/src/modules/preview-web/Preview.tsx b/code/lib/preview-api/src/modules/preview-web/Preview.tsx index af851edfc304..29ea71045949 100644 --- a/code/lib/preview-api/src/modules/preview-web/Preview.tsx +++ b/code/lib/preview-api/src/modules/preview-web/Preview.tsx @@ -100,9 +100,7 @@ export class Preview { get: (_, method) => { if (this.storyStoreValue) { deprecate('Accessing the Story Store is deprecated and will be removed in 9.0'); - - // @ts-expect-error I'm not sure if there's a way to keep TS happy here - return this.storyStoreValue[method]; + return this.storyStoreValue[method as keyof StoryStore]; } throw new StoryStoreAccessedBeforeInitializationError(); diff --git a/code/lib/preview-api/src/modules/store/csf/__mocks__/defaultExportAnnotations.mockfile.ts b/code/lib/preview-api/src/modules/store/csf/__mocks__/defaultExportAnnotations.mockfile.ts new file mode 100644 index 000000000000..6288e13ad9ce --- /dev/null +++ b/code/lib/preview-api/src/modules/store/csf/__mocks__/defaultExportAnnotations.mockfile.ts @@ -0,0 +1,7 @@ +export default { + parameters: { + fromAnnotations: { + asDefaultImport: true, + }, + }, +}; diff --git a/code/lib/preview-api/src/modules/store/csf/__mocks__/namedExportAnnotations.mockfile.ts b/code/lib/preview-api/src/modules/store/csf/__mocks__/namedExportAnnotations.mockfile.ts new file mode 100644 index 000000000000..53b427aceff5 --- /dev/null +++ b/code/lib/preview-api/src/modules/store/csf/__mocks__/namedExportAnnotations.mockfile.ts @@ -0,0 +1,5 @@ +export const parameters = { + fromAnnotations: { + asObjectImport: true, + }, +}; diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index dbca4640b05b..a3aa544c4827 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -7,6 +7,8 @@ import type { } from '@storybook/types'; import { composeStory, composeStories, setProjectAnnotations } from './portable-stories'; +import * as defaultExportAnnotations from './__mocks__/defaultExportAnnotations.mockfile'; +import * as namedExportAnnotations from './__mocks__/namedExportAnnotations.mockfile'; type StoriesModule = Store_CSFExports & Record; @@ -23,6 +25,18 @@ describe('composeStory', () => { }, }; + it('should compose project annotations in all module formats', () => { + setProjectAnnotations([defaultExportAnnotations, namedExportAnnotations]); + + const Story: Story = { + render: () => {}, + }; + + const composedStory = composeStory(Story, meta); + expect(composedStory.parameters.fromAnnotations.asObjectImport).toEqual(true); + expect(composedStory.parameters.fromAnnotations.asDefaultImport).toEqual(true); + }); + it('should return story with composed annotations from story, meta and project', () => { const decoratorFromProjectAnnotations = vi.fn((StoryFn) => StoryFn()); const decoratorFromStoryAnnotations = vi.fn((StoryFn) => StoryFn()); diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index bee091bfda4b..47465eacc8e5 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -5,7 +5,7 @@ import type { Args, ComponentAnnotations, LegacyStoryAnnotationsOrFn, - ProjectAnnotations, + NamedOrDefaultProjectAnnotations, ComposedStoryPlayFn, ComposeStoryFn, Store_CSFExports, @@ -14,6 +14,7 @@ import type { ComposedStoryFn, StrictArgTypes, PlayFunctionContext, + ProjectAnnotations, } from '@storybook/types'; import { HooksContext } from '../../../addons'; @@ -26,11 +27,22 @@ import { normalizeProjectAnnotations } from './normalizeProjectAnnotations'; let globalProjectAnnotations: ProjectAnnotations = {}; +function extractAnnotation( + annotation: NamedOrDefaultProjectAnnotations +) { + // support imports such as + // import * as annotations from '.storybook/preview' + // in both cases: 1 - the file has a default export; 2 - named exports only + return 'default' in annotation ? annotation.default : annotation; +} + export function setProjectAnnotations( - projectAnnotations: ProjectAnnotations | ProjectAnnotations[] + projectAnnotations: + | NamedOrDefaultProjectAnnotations + | NamedOrDefaultProjectAnnotations[] ) { const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations]; - globalProjectAnnotations = composeConfigs(annotations); + globalProjectAnnotations = composeConfigs(annotations.map(extractAnnotation)); } export function composeStory( diff --git a/code/lib/test/src/index.ts b/code/lib/test/src/index.ts index 600c68f1d3b4..7bd72666f341 100644 --- a/code/lib/test/src/index.ts +++ b/code/lib/test/src/index.ts @@ -36,6 +36,6 @@ const resetAllMocksLoader: LoaderFunction = ({ parameters }) => { } }; -// @ts-expect-error We are using this as a default Storybook loader, when the test package is used. This avoids the need for optional peer dependency workarounds. +// We are using this as a default Storybook loader, when the test package is used. This avoids the need for optional peer dependency workarounds. // eslint-disable-next-line no-underscore-dangle -global.__STORYBOOK_TEST_LOADERS__ = [resetAllMocksLoader]; +(global as any).__STORYBOOK_TEST_LOADERS__ = [resetAllMocksLoader]; diff --git a/code/lib/types/src/modules/composedStory.ts b/code/lib/types/src/modules/composedStory.ts index b0a7bff6c374..f670b1ef12a0 100644 --- a/code/lib/types/src/modules/composedStory.ts +++ b/code/lib/types/src/modules/composedStory.ts @@ -1,6 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import type { PlayFunction, Renderer, StoryId, StrictArgTypes } from '@storybook/csf'; +import type { + PlayFunction, + ProjectAnnotations, + Renderer, + StoryId, + StrictArgTypes, +} from '@storybook/csf'; import type { AnnotatedStoryFn, @@ -11,8 +17,6 @@ import type { StoryAnnotationsOrFn, } from './csf'; -import type { ProjectAnnotations } from './story'; - // TODO -- I think the name "CSFExports" overlaps here a bit with the types in csfFile.ts // we might want to reconcile @yannbf export type Store_CSFExports = { diff --git a/code/lib/types/src/modules/story.ts b/code/lib/types/src/modules/story.ts index cd4e9f1c9d16..f22d18ad7a3d 100644 --- a/code/lib/types/src/modules/story.ts +++ b/code/lib/types/src/modules/story.ts @@ -47,6 +47,11 @@ export type ProjectAnnotations = CsfProjectAnnotatio renderToDOM?: RenderToCanvas; }; +type NamedExportsOrDefault = TExport | { default: TExport }; + +export type NamedOrDefaultProjectAnnotations = + NamedExportsOrDefault>; + export type NormalizedProjectAnnotations = Omit< ProjectAnnotations, 'decorators' | 'loaders' diff --git a/code/package.json b/code/package.json index 205aacdf8b5e..07e40731b153 100644 --- a/code/package.json +++ b/code/package.json @@ -47,8 +47,8 @@ "storybook:blocks:build": "STORYBOOK_BLOCKS_ONLY=true yarn storybook:ui:build", "storybook:blocks:chromatic": "STORYBOOK_BLOCKS_ONLY=true yarn storybook:ui:chromatic --project-token=${CHROMATIC_TOKEN_STORYBOOK_BLOCKS:-MISSING_PROJECT_TOKEN}", "storybook:ui": "NODE_OPTIONS=\"--preserve-symlinks --preserve-symlinks-main\" ./lib/cli/bin/index.js dev --port 6006 --config-dir ./ui/.storybook", - "storybook:ui:build": "NODE_OPTIONS=\"--preserve-symlinks --preserve-symlinks-main\" ./lib/cli/bin/index.js build --config-dir ./ui/.storybook", - "storybook:ui:chromatic": "yarn chromatic --build-script-name storybook:ui:build --storybook-config-dir ./ui/.storybook --storybook-base-dir ./code --project-token=${CHROMATIC_TOKEN_STORYBOOK_UI:-MISSING_PROJECT_TOKEN} --only-changed --exit-zero-on-changes --exit-once-uploaded", + "storybook:ui:build": "NODE_OPTIONS=\"--preserve-symlinks --preserve-symlinks-main\" ./lib/cli/bin/index.js build --config-dir ./ui/.storybook --webpack-stats-json", + "storybook:ui:chromatic": "../scripts/node_modules/.bin/chromatic --build-script-name storybook:ui:build --storybook-base-dir ./ --project-token=${CHROMATIC_TOKEN_STORYBOOK_UI:-MISSING_PROJECT_TOKEN} --only-changed --exit-zero-on-changes --exit-once-uploaded", "task": "yarn --cwd ../scripts task", "test": "NODE_OPTIONS=--max_old_space_size=4096 vitest run", "test:watch": "NODE_OPTIONS=--max_old_space_size=4096 vitest watch" @@ -88,6 +88,7 @@ "type-fest": "~2.19" }, "dependencies": { + "@chromatic-com/storybook": "^1.2.18", "@nx/workspace": "17.0.2", "@playwright/test": "1.36.0", "@storybook/addon-a11y": "workspace:*", @@ -187,7 +188,6 @@ "@typescript-eslint/parser": "^6.18.1", "@vitejs/plugin-react": "^3.0.1", "@vitest/coverage-v8": "^1.2.2", - "chromatic": "7.1.0", "concurrently": "^5.3.0", "cross-env": "^7.0.3", "danger": "^11.2.6", @@ -222,13 +222,9 @@ "typescript": "^5.3.2", "util": "^0.12.4", "vite": "^4.0.0", - "vite-plugin-turbosnap": "^1.0.1", "vitest": "^1.2.2", "wait-on": "^7.0.1" }, - "devDependencies": { - "@chromaui/addon-visual-tests": "^0.0.124" - }, "dependenciesMeta": { "ejs": { "built": false @@ -295,5 +291,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.1.0-alpha.2" } diff --git a/code/renderers/react/src/portable-stories.ts b/code/renderers/react/src/portable-stories.ts index 5994dbc1e408..652e319b0998 100644 --- a/code/renderers/react/src/portable-stories.ts +++ b/code/renderers/react/src/portable-stories.ts @@ -5,10 +5,11 @@ import { } from '@storybook/preview-api'; import type { Args, - ProjectAnnotations, + NamedOrDefaultProjectAnnotations, StoryAnnotationsOrFn, Store_CSFExports, StoriesWithPartialProps, + ProjectAnnotations, } from '@storybook/types'; import * as defaultProjectAnnotations from './entry-preview'; @@ -28,17 +29,19 @@ import type { ReactRenderer } from './types'; * setProjectAnnotations(projectAnnotations); *``` * - * @param projectAnnotations - e.g. (import projectAnnotations from '../.storybook/preview') + * @param projectAnnotations - e.g. (import * as projectAnnotations from '../.storybook/preview') */ export function setProjectAnnotations( - projectAnnotations: ProjectAnnotations | ProjectAnnotations[] + projectAnnotations: + | NamedOrDefaultProjectAnnotations + | NamedOrDefaultProjectAnnotations[] ) { originalSetProjectAnnotations(projectAnnotations); } /** * Function that will receive a story along with meta (e.g. a default export from a .stories file) - * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) + * and optionally projectAnnotations e.g. (import * as projectAnnotations from '../.storybook/preview) * and will return a composed component that has all args/parameters/decorators/etc combined and applied to it. * * @@ -80,7 +83,7 @@ export function composeStory( /** * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`) - * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) + * and optionally projectAnnotations (e.g. `import * as projectAnnotations from '../.storybook/preview`) * and will return an object containing all the stories passed, but now as a composed component that has all args/parameters/decorators/etc combined and applied to it. * * diff --git a/code/renderers/vue3/src/portable-stories.ts b/code/renderers/vue3/src/portable-stories.ts index dca738d205bf..043f15ff46b3 100644 --- a/code/renderers/vue3/src/portable-stories.ts +++ b/code/renderers/vue3/src/portable-stories.ts @@ -5,6 +5,7 @@ import { } from '@storybook/preview-api'; import type { Args, + NamedOrDefaultProjectAnnotations, ProjectAnnotations, StoryAnnotationsOrFn, Store_CSFExports, @@ -32,7 +33,9 @@ import type { VueRenderer } from './types'; * @param projectAnnotations - e.g. (import projectAnnotations from '../.storybook/preview') */ export function setProjectAnnotations( - projectAnnotations: ProjectAnnotations | ProjectAnnotations[] + projectAnnotations: + | NamedOrDefaultProjectAnnotations + | NamedOrDefaultProjectAnnotations[] ) { originalSetProjectAnnotations(projectAnnotations); } diff --git a/code/ui/.storybook/isChromatic.ts b/code/ui/.storybook/isChromatic.ts new file mode 100644 index 000000000000..244058b2fabf --- /dev/null +++ b/code/ui/.storybook/isChromatic.ts @@ -0,0 +1,8 @@ +export function isChromatic(windowArg?: any) { + const windowToCheck = windowArg || (typeof window !== 'undefined' && window); + return !!( + windowToCheck && + (windowToCheck.navigator.userAgent.match(/Chromatic/) || + windowToCheck.location.href.match(/chromatic=true/)) + ); +} diff --git a/code/ui/.storybook/main.ts b/code/ui/.storybook/main.ts index 3defc0046331..dd01824a38e8 100644 --- a/code/ui/.storybook/main.ts +++ b/code/ui/.storybook/main.ts @@ -1,5 +1,4 @@ import path from 'path'; -import pluginTurbosnap from 'vite-plugin-turbosnap'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { mergeConfig } from 'vite'; import type { StorybookConfig } from '../../frameworks/react-vite'; @@ -53,7 +52,7 @@ const config: StorybookConfig = { '@storybook/addon-interactions', '@storybook/addon-storysource', '@storybook/addon-designs', - '@chromaui/addon-visual-tests', + '@chromatic-com/storybook', ], build: { test: { @@ -79,11 +78,6 @@ const config: StorybookConfig = { : {}), }, }, - plugins: [ - configType === 'PRODUCTION' - ? pluginTurbosnap({ rootDir: path.resolve(__dirname, '../..') }) - : [], - ], optimizeDeps: { force: true }, build: { // disable sourcemaps in CI to not run out of memory diff --git a/code/ui/.storybook/preview.tsx b/code/ui/.storybook/preview.tsx index 34d955269f75..5a5ed1a7ad75 100644 --- a/code/ui/.storybook/preview.tsx +++ b/code/ui/.storybook/preview.tsx @@ -1,6 +1,6 @@ import { global } from '@storybook/global'; import React, { Fragment, useEffect } from 'react'; -import isChromatic from 'chromatic/isChromatic'; +import { isChromatic } from './isChromatic'; import { Global, ThemeProvider, diff --git a/code/ui/blocks/src/controls/Number.tsx b/code/ui/blocks/src/controls/Number.tsx index 946563ea0c7d..2362f2fa48e3 100644 --- a/code/ui/blocks/src/controls/Number.tsx +++ b/code/ui/blocks/src/controls/Number.tsx @@ -66,7 +66,7 @@ export const NumberControl: FC = ({ } }, [value]); - if (!forceVisible && value === undefined) { + if (value === undefined) { return (