diff --git a/CHANGELOG.md b/CHANGELOG.md index d94e871aa45c..0fdbefeb9821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 8.1.1 + +- Docgen: Only add react-docgen info when a component is defined in the file - [#26967](https://github.com/storybookjs/storybook/pull/26967), thanks @glenjamin! +- Docs: Fix MDX Stories block tag-filtering behavior - [#27144](https://github.com/storybookjs/storybook/pull/27144), thanks @shilman! +- Docs: Fix Subtitle block when no `of` prop passed - [#27147](https://github.com/storybookjs/storybook/pull/27147), thanks @JReinhold! +- Next.js: Add typing for NextImage to main framework options type - [#27105](https://github.com/storybookjs/storybook/pull/27105), thanks @valentinpalkovic! +- Next.js: Avoid conflicts with the raw loader - [#27093](https://github.com/storybookjs/storybook/pull/27093), thanks @seanparmelee! +- Types: Fix typing for main.framework/builder fields - [#27088](https://github.com/storybookjs/storybook/pull/27088), thanks @valentinpalkovic! + ## 8.1.0 Storybook 8.1 is here with a tone of new features and bug fixes: diff --git a/code/addons/docs/src/preview.ts b/code/addons/docs/src/preview.ts index 7a352b15b0a6..991a7811b472 100644 --- a/code/addons/docs/src/preview.ts +++ b/code/addons/docs/src/preview.ts @@ -22,9 +22,7 @@ export const parameters: any = { filter: (story: PreparedStory) => { const tags = story.tags || []; return ( - tags.includes('autodocs') && - tags.filter((tag) => excludeTags[tag]).length === 0 && - !story.parameters.docs?.disable + tags.filter((tag) => excludeTags[tag]).length === 0 && !story.parameters.docs?.disable ); }, }, diff --git a/code/frameworks/angular/src/types.ts b/code/frameworks/angular/src/types.ts index 926213e222b6..a965368eaf94 100644 --- a/code/frameworks/angular/src/types.ts +++ b/code/frameworks/angular/src/types.ts @@ -7,9 +7,10 @@ import { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/angular'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/angular'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = AngularOptions & { builder?: BuilderOptions; diff --git a/code/frameworks/ember/src/types.ts b/code/frameworks/ember/src/types.ts index 2c2605f286af..6106e1391199 100644 --- a/code/frameworks/ember/src/types.ts +++ b/code/frameworks/ember/src/types.ts @@ -7,9 +7,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/ember-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/ember-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 8df2e9e34343..c97c234d1f4f 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -51,6 +51,7 @@ "@storybook/core-server": "workspace:*", "@storybook/html": "workspace:*", "@storybook/node-logger": "workspace:*", + "@storybook/types": "workspace:*", "magic-string": "^0.30.0" }, "devDependencies": { diff --git a/code/frameworks/html-vite/src/types.ts b/code/frameworks/html-vite/src/types.ts index db508a143b53..d25f61997d14 100644 --- a/code/frameworks/html-vite/src/types.ts +++ b/code/frameworks/html-vite/src/types.ts @@ -1,8 +1,8 @@ -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { StorybookConfig as StorybookConfigBase, CompatibleString } from '@storybook/types'; import type { StorybookConfigVite, BuilderOptions } from '@storybook/builder-vite'; -type FrameworkName = '@storybook/html-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/html-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index d5347e065b05..094110519fad 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -52,6 +52,7 @@ "@storybook/global": "^5.0.0", "@storybook/html": "workspace:*", "@storybook/preset-html-webpack": "workspace:*", + "@storybook/types": "workspace:*", "@types/node": "^18.0.0" }, "devDependencies": { diff --git a/code/frameworks/html-webpack5/src/types.ts b/code/frameworks/html-webpack5/src/types.ts index 2360ef4ac9e6..eb0fa25b9ebd 100644 --- a/code/frameworks/html-webpack5/src/types.ts +++ b/code/frameworks/html-webpack5/src/types.ts @@ -7,9 +7,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/html-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/html-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/nextjs/src/swc/loader.ts b/code/frameworks/nextjs/src/swc/loader.ts index d1b5c6e7ab98..c9ca896d533b 100644 --- a/code/frameworks/nextjs/src/swc/loader.ts +++ b/code/frameworks/nextjs/src/swc/loader.ts @@ -4,9 +4,10 @@ import type { Options } from '@storybook/types'; import type { NextConfig } from 'next'; import path from 'path'; import loadJsConfig from 'next/dist/build/load-jsconfig'; +import type { Configuration as WebpackConfig } from 'webpack'; export const configureSWCLoader = async ( - baseConfig: any, + baseConfig: WebpackConfig, options: Options, nextConfig: NextConfig ) => { @@ -18,33 +19,38 @@ export const configureSWCLoader = async ( const { jsConfig } = await loadJsConfig(dir, nextConfig as any); - baseConfig.module.rules = [ - ...baseConfig.module.rules, - { - test: /\.((c|m)?(j|t)sx?)$/, - include: [getProjectRoot()], - exclude: [/(node_modules)/, ...Object.keys(virtualModules)], - enforce: 'post', - use: { - // we use our own patch because we need to remove tracing from the original code - // which is not possible otherwise - loader: require.resolve('./swc/next-swc-loader-patch.js'), - options: { - isServer: false, - rootDir: dir, - pagesDir: `${dir}/pages`, - appDir: `${dir}/apps`, - hasReactRefresh: isDevelopment, - jsConfig, - nextConfig, - supportedBrowsers: require('next/dist/build/utils').getSupportedBrowsers( - dir, - isDevelopment - ), - swcCacheDir: path.join(dir, nextConfig?.distDir ?? '.next', 'cache', 'swc'), - bundleTarget: 'default', - }, + const rawRule = baseConfig.module?.rules?.find( + (rule) => typeof rule === 'object' && rule?.resourceQuery?.toString() === '/raw/' + ); + + if (rawRule && typeof rawRule === 'object') { + rawRule.test = /^(?!__barrel_optimize__)/; + } + + baseConfig.module?.rules?.push({ + test: /\.((c|m)?(j|t)sx?)$/, + include: [getProjectRoot()], + exclude: [/(node_modules)/, ...Object.keys(virtualModules)], + enforce: 'post', + use: { + // we use our own patch because we need to remove tracing from the original code + // which is not possible otherwise + loader: require.resolve('./swc/next-swc-loader-patch.js'), + options: { + isServer: false, + rootDir: dir, + pagesDir: `${dir}/pages`, + appDir: `${dir}/apps`, + hasReactRefresh: isDevelopment, + jsConfig, + nextConfig, + supportedBrowsers: require('next/dist/build/utils').getSupportedBrowsers( + dir, + isDevelopment + ), + swcCacheDir: path.join(dir, nextConfig?.distDir ?? '.next', 'cache', 'swc'), + bundleTarget: 'default', }, }, - ]; + }); }; diff --git a/code/frameworks/nextjs/src/types.ts b/code/frameworks/nextjs/src/types.ts index 4707d03d27e8..9c7fcd9efd7d 100644 --- a/code/frameworks/nextjs/src/types.ts +++ b/code/frameworks/nextjs/src/types.ts @@ -8,13 +8,15 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; +import type * as NextImage from 'next/image'; -type FrameworkName = '@storybook/nextjs'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/nextjs'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = ReactOptions & { nextConfigPath?: string; - + image?: Partial; builder?: BuilderOptions; }; diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 3104055633b8..3aef9cf9676a 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -48,7 +48,8 @@ }, "dependencies": { "@storybook/builder-vite": "workspace:*", - "@storybook/preact": "workspace:*" + "@storybook/preact": "workspace:*", + "@storybook/types": "workspace:*" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/code/frameworks/preact-vite/src/types.ts b/code/frameworks/preact-vite/src/types.ts index d654f5e13bbc..36481753d4e5 100644 --- a/code/frameworks/preact-vite/src/types.ts +++ b/code/frameworks/preact-vite/src/types.ts @@ -1,8 +1,8 @@ -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { CompatibleString, StorybookConfig as StorybookConfigBase } from '@storybook/types'; import type { StorybookConfigVite, BuilderOptions } from '@storybook/builder-vite'; -type FrameworkName = '@storybook/preact-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/preact-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index b79e36dc3ede..6dd1b7968057 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -51,6 +51,7 @@ "@storybook/core-common": "workspace:*", "@storybook/preact": "workspace:*", "@storybook/preset-preact-webpack": "workspace:*", + "@storybook/types": "workspace:*", "@types/node": "^18.0.0" }, "devDependencies": { diff --git a/code/frameworks/preact-webpack5/src/types.ts b/code/frameworks/preact-webpack5/src/types.ts index 2d66b8576166..cad7d38ac6c2 100644 --- a/code/frameworks/preact-webpack5/src/types.ts +++ b/code/frameworks/preact-webpack5/src/types.ts @@ -7,9 +7,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/preact-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/preact-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 4ea1f39b270d..45fd47702865 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -52,6 +52,7 @@ "@storybook/builder-vite": "workspace:*", "@storybook/node-logger": "workspace:*", "@storybook/react": "workspace:*", + "@storybook/types": "workspace:*", "find-up": "^5.0.0", "magic-string": "^0.30.0", "react-docgen": "^7.0.0", diff --git a/code/frameworks/react-vite/src/plugins/docgen-handlers/actualNameHandler.ts b/code/frameworks/react-vite/src/plugins/docgen-handlers/actualNameHandler.ts index 01889ddf9dcf..7fe133be6bb9 100644 --- a/code/frameworks/react-vite/src/plugins/docgen-handlers/actualNameHandler.ts +++ b/code/frameworks/react-vite/src/plugins/docgen-handlers/actualNameHandler.ts @@ -15,6 +15,8 @@ import { utils } from 'react-docgen'; const { getNameOrValue, isReactForwardRefCall } = utils; const actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) { + documentation.set('definedInFile', componentDefinition.hub.file.opts.filename); + if ( (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) && componentDefinition.has('id') diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index c59861e4ff43..f41191dc0024 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -20,7 +20,7 @@ import { } from './docgen-resolver'; import { logger } from '@storybook/node-logger'; -type DocObj = Documentation & { actualName: string }; +type DocObj = Documentation & { actualName: string; definedInFile: string }; // TODO: None of these are able to be overridden, so `default` is aspirational here. const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler); @@ -71,8 +71,8 @@ export async function reactDocgen({ const s = new MagicString(src); docgenResults.forEach((info) => { - const { actualName, ...docgenInfo } = info; - if (actualName) { + const { actualName, definedInFile, ...docgenInfo } = info; + if (actualName && definedInFile == id) { const docNode = JSON.stringify(docgenInfo); s.append(`;${actualName}.__docgenInfo=${docNode}`); } diff --git a/code/frameworks/react-vite/src/types.ts b/code/frameworks/react-vite/src/types.ts index 2499ae4bf93a..79c704f1e914 100644 --- a/code/frameworks/react-vite/src/types.ts +++ b/code/frameworks/react-vite/src/types.ts @@ -1,12 +1,13 @@ import type { + CompatibleString, StorybookConfig as StorybookConfigBase, TypescriptOptions as TypescriptOptionsBase, } from '@storybook/types'; import type { StorybookConfigVite, BuilderOptions } from '@storybook/builder-vite'; import type docgenTypescript from '@joshwooding/vite-plugin-react-docgen-typescript'; -type FrameworkName = '@storybook/react-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/react-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index 166a5b829640..4c285fa09680 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -50,6 +50,7 @@ "@storybook/builder-webpack5": "workspace:*", "@storybook/preset-react-webpack": "workspace:*", "@storybook/react": "workspace:*", + "@storybook/types": "workspace:*", "@types/node": "^18.0.0" }, "peerDependencies": { diff --git a/code/frameworks/react-webpack5/src/types.ts b/code/frameworks/react-webpack5/src/types.ts index 7e50ef23aba4..fa5a70f8f444 100644 --- a/code/frameworks/react-webpack5/src/types.ts +++ b/code/frameworks/react-webpack5/src/types.ts @@ -8,9 +8,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/react-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/react-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = ReactOptions & { builder?: BuilderOptions; diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index e35f10860bfb..d47c4b72b346 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -51,6 +51,7 @@ "@storybook/core-common": "workspace:*", "@storybook/preset-server-webpack": "workspace:*", "@storybook/server": "workspace:*", + "@storybook/types": "workspace:*", "@types/node": "^18.0.0" }, "devDependencies": { diff --git a/code/frameworks/server-webpack5/src/types.ts b/code/frameworks/server-webpack5/src/types.ts index 63ecb28ab897..1374b9788c61 100644 --- a/code/frameworks/server-webpack5/src/types.ts +++ b/code/frameworks/server-webpack5/src/types.ts @@ -7,9 +7,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/server-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/server-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index b891341be96a..26862d99323a 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -50,6 +50,7 @@ "@storybook/builder-vite": "workspace:*", "@storybook/node-logger": "workspace:*", "@storybook/svelte": "workspace:*", + "@storybook/types": "workspace:*", "magic-string": "^0.30.0", "svelte-preprocess": "^5.1.1", "sveltedoc-parser": "^4.2.1", diff --git a/code/frameworks/svelte-vite/src/types.ts b/code/frameworks/svelte-vite/src/types.ts index 8d4ccb8cc9cb..6fe0c01de2c3 100644 --- a/code/frameworks/svelte-vite/src/types.ts +++ b/code/frameworks/svelte-vite/src/types.ts @@ -1,8 +1,8 @@ -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { CompatibleString, StorybookConfig as StorybookConfigBase } from '@storybook/types'; import type { StorybookConfigVite, BuilderOptions } from '@storybook/builder-vite'; -type FrameworkName = '@storybook/svelte-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/svelte-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index d0f55a33f3c2..79eab4f01839 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -50,7 +50,8 @@ "@storybook/builder-webpack5": "workspace:*", "@storybook/core-common": "workspace:*", "@storybook/preset-svelte-webpack": "workspace:*", - "@storybook/svelte": "workspace:*" + "@storybook/svelte": "workspace:*", + "@storybook/types": "workspace:*" }, "devDependencies": { "svelte": "^4.0.0", diff --git a/code/frameworks/svelte-webpack5/src/types.ts b/code/frameworks/svelte-webpack5/src/types.ts index d5c0578faa32..6c285d94caa9 100644 --- a/code/frameworks/svelte-webpack5/src/types.ts +++ b/code/frameworks/svelte-webpack5/src/types.ts @@ -8,9 +8,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/svelte-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/svelte-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = SvelteOptions & { builder?: BuilderOptions; diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index cf426bf079eb..1ed5a492c365 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -56,7 +56,8 @@ "@storybook/addon-actions": "workspace:*", "@storybook/builder-vite": "workspace:*", "@storybook/svelte": "workspace:*", - "@storybook/svelte-vite": "workspace:*" + "@storybook/svelte-vite": "workspace:*", + "@storybook/types": "workspace:*" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/code/frameworks/sveltekit/src/types.ts b/code/frameworks/sveltekit/src/types.ts index c3f04a22bc82..a41c333ccc5f 100644 --- a/code/frameworks/sveltekit/src/types.ts +++ b/code/frameworks/sveltekit/src/types.ts @@ -1,10 +1,10 @@ import type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite'; -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { CompatibleString, StorybookConfig as StorybookConfigBase } from '@storybook/types'; import type { enhance } from './mocks/app/forms'; import type { goto, invalidate, invalidateAll } from './mocks/app/navigation'; -type FrameworkName = '@storybook/sveltekit'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/sveltekit'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 962e8eb5443f..3c828ff79b9c 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -49,6 +49,7 @@ "dependencies": { "@storybook/builder-vite": "workspace:*", "@storybook/core-server": "workspace:*", + "@storybook/types": "workspace:*", "@storybook/vue3": "workspace:*", "find-package-json": "^1.2.0", "magic-string": "^0.30.0", diff --git a/code/frameworks/vue3-vite/src/types.ts b/code/frameworks/vue3-vite/src/types.ts index c75fee101de8..09806828a421 100644 --- a/code/frameworks/vue3-vite/src/types.ts +++ b/code/frameworks/vue3-vite/src/types.ts @@ -1,10 +1,10 @@ import type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite'; -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { CompatibleString, StorybookConfig as StorybookConfigBase } from '@storybook/types'; import type { ComponentMeta } from 'vue-component-meta'; import type { ComponentDoc } from 'vue-docgen-api'; -type FrameworkName = '@storybook/vue3-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/vue3-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; /** * Available docgen plugins for vue. diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 97e14e2efda7..baf3a1b5e7a4 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -50,6 +50,7 @@ "@storybook/builder-webpack5": "workspace:*", "@storybook/core-common": "workspace:*", "@storybook/preset-vue3-webpack": "workspace:*", + "@storybook/types": "workspace:*", "@storybook/vue3": "workspace:*", "@types/node": "^18.0.0" }, diff --git a/code/frameworks/vue3-webpack5/src/types.ts b/code/frameworks/vue3-webpack5/src/types.ts index bdae08526600..9c9352eabfda 100644 --- a/code/frameworks/vue3-webpack5/src/types.ts +++ b/code/frameworks/vue3-webpack5/src/types.ts @@ -7,9 +7,10 @@ import type { BuilderOptions, TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; +import type { CompatibleString } from '@storybook/types'; -type FrameworkName = '@storybook/vue3-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/vue3-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 6d0035f0c463..92542f0534c5 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -50,6 +50,7 @@ "@storybook/builder-vite": "workspace:*", "@storybook/core-server": "workspace:*", "@storybook/node-logger": "workspace:*", + "@storybook/types": "workspace:*", "@storybook/web-components": "workspace:*", "magic-string": "^0.30.0" }, diff --git a/code/frameworks/web-components-vite/src/types.ts b/code/frameworks/web-components-vite/src/types.ts index 25fd697cb4b3..a43eaabd3161 100644 --- a/code/frameworks/web-components-vite/src/types.ts +++ b/code/frameworks/web-components-vite/src/types.ts @@ -1,8 +1,8 @@ -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { CompatibleString, StorybookConfig as StorybookConfigBase } from '@storybook/types'; import type { StorybookConfigVite, BuilderOptions } from '@storybook/builder-vite'; -type FrameworkName = '@storybook/web-components-vite'; -type BuilderName = '@storybook/builder-vite'; +type FrameworkName = CompatibleString<'@storybook/web-components-vite'>; +type BuilderName = CompatibleString<'@storybook/builder-vite'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 293a0ec7ae7e..5441a60a9124 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -52,6 +52,7 @@ "dependencies": { "@storybook/builder-webpack5": "workspace:*", "@storybook/core-common": "workspace:*", + "@storybook/types": "workspace:*", "@storybook/web-components": "workspace:*", "@types/node": "^18.0.0" }, diff --git a/code/frameworks/web-components-webpack5/src/types.ts b/code/frameworks/web-components-webpack5/src/types.ts index 01442d08f08a..265b605772c8 100644 --- a/code/frameworks/web-components-webpack5/src/types.ts +++ b/code/frameworks/web-components-webpack5/src/types.ts @@ -1,4 +1,5 @@ import type { + CompatibleString, StorybookConfig as StorybookConfigBase, TypescriptOptions as TypescriptOptionsWebComponents, } from '@storybook/types'; @@ -8,8 +9,8 @@ import type { TypescriptOptions as TypescriptOptionsBuilder, } from '@storybook/builder-webpack5'; -type FrameworkName = '@storybook/web-components-webpack5'; -type BuilderName = '@storybook/builder-webpack5'; +type FrameworkName = CompatibleString<'@storybook/web-components-webpack5'>; +type BuilderName = CompatibleString<'@storybook/builder-webpack5'>; export type FrameworkOptions = { builder?: BuilderOptions; diff --git a/code/lib/types/src/modules/core-common.ts b/code/lib/types/src/modules/core-common.ts index 9a3106931053..f16ef638cbf4 100644 --- a/code/lib/types/src/modules/core-common.ts +++ b/code/lib/types/src/modules/core-common.ts @@ -571,3 +571,15 @@ export interface CoreCommon_StorybookInfo { previewConfig?: string; managerConfig?: string; } + +/** + * Given a generic string type, returns that type but ensures that a string in general is compatible with it. + * We use this construct to ensure that IDEs can provide better autocompletion for string types. + * This is, for example, needed for main config fields, where we want to ensure that the user can provide + * a custom string, but also a string that is compatible with the type. + * @example + * type Framework = CompatibleString<'@storybook/nextjs'> + * const framework: Framework = '@storybook/nextjs'; // valid and will be autocompleted + * const framework: Framework = path.dirname(require.resolve(path.join("@storybook/nextjs", "package.json"))) // valid + */ +export type CompatibleString = T | (string & Record); diff --git a/code/package.json b/code/package.json index d233b81a5de3..776df02ef696 100644 --- a/code/package.json +++ b/code/package.json @@ -299,5 +299,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.1.1" } diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index ac83e37982de..ba3dd1805999 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -22,6 +22,7 @@ import { const { getNameOrValue, isReactForwardRefCall } = utils; const actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) { + documentation.set('definedInFile', componentDefinition.hub.file.opts.filename); if ( (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) && componentDefinition.has('id') @@ -58,7 +59,7 @@ const actualNameHandler: Handler = function actualNameHandler(documentation, com } }; -type DocObj = Documentation & { actualName: string }; +type DocObj = Documentation & { actualName: string; definedInFile: string }; const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler); const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver(); @@ -107,8 +108,8 @@ export default async function reactDocgenLoader( const magicString = new MagicString(source); docgenResults.forEach((info) => { - const { actualName, ...docgenInfo } = info; - if (actualName) { + const { actualName, definedInFile, ...docgenInfo } = info; + if (actualName && definedInFile == this.resourcePath) { const docNode = JSON.stringify(docgenInfo); magicString.append(`;${actualName}.__docgenInfo=${docNode}`); } diff --git a/code/renderers/react/src/docs/extractArgTypes.test.ts b/code/renderers/react/src/docs/extractArgTypes.test.ts index 96b750f26525..a51b7aa54382 100644 --- a/code/renderers/react/src/docs/extractArgTypes.test.ts +++ b/code/renderers/react/src/docs/extractArgTypes.test.ts @@ -50,6 +50,7 @@ const annotateWithDocgen = (inputPath: string) => { const skippedTests = [ 'js-class-component', 'js-function-component', + 'js-re-exported-component', 'js-function-component-inline-defaults', 'js-function-component-inline-defaults-no-propTypes', 'ts-function-component', diff --git a/code/renderers/react/template/stories/docgen-components/js-re-exported-component/docgen.snapshot b/code/renderers/react/template/stories/docgen-components/js-re-exported-component/docgen.snapshot new file mode 100644 index 000000000000..c3ad6f276316 --- /dev/null +++ b/code/renderers/react/template/stories/docgen-components/js-re-exported-component/docgen.snapshot @@ -0,0 +1 @@ +export { component } from '../js-function-component/input.jsx'; \ No newline at end of file diff --git a/code/renderers/react/template/stories/docgen-components/js-re-exported-component/input.jsx b/code/renderers/react/template/stories/docgen-components/js-re-exported-component/input.jsx new file mode 100644 index 000000000000..7b7ce9d3c8e9 --- /dev/null +++ b/code/renderers/react/template/stories/docgen-components/js-re-exported-component/input.jsx @@ -0,0 +1,3 @@ +import { component } from '../js-function-component/input.jsx'; + +export { component }; diff --git a/code/renderers/react/template/stories/js-argtypes.stories.jsx b/code/renderers/react/template/stories/js-argtypes.stories.jsx index a72d6771dbeb..2101e61979f3 100644 --- a/code/renderers/react/template/stories/js-argtypes.stories.jsx +++ b/code/renderers/react/template/stories/js-argtypes.stories.jsx @@ -7,6 +7,7 @@ import { ThemeProvider, themes, convert } from '@storybook/theming'; import { component as JsClassComponentComponent } from './docgen-components/js-class-component/input.jsx'; import { component as JsFunctionComponentComponent } from './docgen-components/js-function-component/input.jsx'; +import { component as JsRexportedComponentComponent } from './docgen-components/js-re-exported-component/input.jsx'; import { component as JsFunctionComponentInlineDefaultsComponent } from './docgen-components/js-function-component-inline-defaults/input.jsx'; import { component as JsFunctionComponentInlineDefaultsNoPropTypesComponent } from './docgen-components/js-function-component-inline-defaults-no-propTypes/input.jsx'; import { component as JsProptypesShapeComponent } from './docgen-components/9399-js-proptypes-shape/input.jsx'; @@ -60,6 +61,10 @@ export const JsClassComponent = { parameters: { component: JsClassComponentCompo export const JsFunctionComponent = { parameters: { component: JsFunctionComponentComponent } }; +export const JsRexportedComponent = { + parameters: { component: JsRexportedComponentComponent }, +}; + export const JsFunctionComponentInlineDefaults = { parameters: { component: JsFunctionComponentInlineDefaultsComponent }, }; diff --git a/code/ui/blocks/src/blocks/Stories.stories.tsx b/code/ui/blocks/src/blocks/Stories.stories.tsx index 9462f5f2a2dd..0c91aec638e6 100644 --- a/code/ui/blocks/src/blocks/Stories.stories.tsx +++ b/code/ui/blocks/src/blocks/Stories.stories.tsx @@ -26,3 +26,13 @@ export const DifferentToolbars: Story = { relativeCsfPaths: ['../examples/StoriesParameters.stories'], }, }; +export const NoAutodocs: Story = { + parameters: { + relativeCsfPaths: ['../examples/ButtonNoAutodocs.stories'], + }, +}; +export const SomeAutodocs: Story = { + parameters: { + relativeCsfPaths: ['../examples/ButtonSomeAutodocs.stories'], + }, +}; diff --git a/code/ui/blocks/src/blocks/Stories.tsx b/code/ui/blocks/src/blocks/Stories.tsx index 8681e4151c4d..c2b5c53dc729 100644 --- a/code/ui/blocks/src/blocks/Stories.tsx +++ b/code/ui/blocks/src/blocks/Stories.tsx @@ -34,6 +34,17 @@ export const Stories: FC = ({ title = 'Stories', includePrimary = if (filter) { stories = stories.filter((story) => filter(story, getStoryContext(story))); } + // NOTE: this should be part of the default filter function. However, there is currently + // no way to distinguish a Stories block in an autodocs page from Stories in an MDX file + // making https://github.com/storybookjs/storybook/pull/26634 an unintentional breaking change. + // + // The new behavior here is that if NONE of the stories in the autodocs page are tagged + // with 'autodocs', we show all stories. If ANY of the stories have autodocs then we use + // the new behavior. + const hasAutodocsTaggedStory = stories.some((story) => story.tags?.includes('autodocs')); + if (hasAutodocsTaggedStory) { + stories = stories.filter((story) => story.tags?.includes('autodocs')); + } if (!includePrimary) stories = stories.slice(1); diff --git a/code/ui/blocks/src/blocks/Subtitle.stories.tsx b/code/ui/blocks/src/blocks/Subtitle.stories.tsx index 4fe4a2ef6a19..6ee1e865baba 100644 --- a/code/ui/blocks/src/blocks/Subtitle.stories.tsx +++ b/code/ui/blocks/src/blocks/Subtitle.stories.tsx @@ -99,6 +99,6 @@ export const OfStringMetaAttached: Story = { parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true }, }; export const Children: Story = { - parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true }, + parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: false }, render: () => This subtitle is a string passed as a children, }; diff --git a/code/ui/blocks/src/blocks/Subtitle.tsx b/code/ui/blocks/src/blocks/Subtitle.tsx index 9b7556e9c7c6..055ed047cc12 100644 --- a/code/ui/blocks/src/blocks/Subtitle.tsx +++ b/code/ui/blocks/src/blocks/Subtitle.tsx @@ -25,8 +25,17 @@ export const Subtitle: FunctionComponent = (props) => { throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?'); } - const { preparedMeta } = useOf(of || 'meta', ['meta']); - const { componentSubtitle, docs } = preparedMeta.parameters || {}; + let preparedMeta; + try { + preparedMeta = useOf(of || 'meta', ['meta']).preparedMeta; + } catch (error) { + if (children && !error.message.includes('did you forget to use ?')) { + // ignore error about unattached CSF since we can still render children + throw error; + } + } + + const { componentSubtitle, docs } = preparedMeta?.parameters || {}; if (componentSubtitle) { deprecate( diff --git a/code/ui/blocks/src/blocks/Title.tsx b/code/ui/blocks/src/blocks/Title.tsx index 55b85ebad717..28ac06136ef1 100644 --- a/code/ui/blocks/src/blocks/Title.tsx +++ b/code/ui/blocks/src/blocks/Title.tsx @@ -42,7 +42,7 @@ export const Title: FunctionComponent = (props) => { } } - const content = children || extractTitle(preparedMeta.title); + const content = children || extractTitle(preparedMeta?.title); return content ? {content} : null; }; diff --git a/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx b/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx new file mode 100644 index 000000000000..c934e70753f2 --- /dev/null +++ b/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from './Button'; + +const meta = { + title: 'examples/ButtonNoAutodocs', + component: Button, + argTypes: { + backgroundColor: { control: 'color' }, + }, + parameters: { + chromatic: { disable: true }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + label: 'Button', + }, +}; diff --git a/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx b/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx new file mode 100644 index 000000000000..dd5f7d227f49 --- /dev/null +++ b/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx @@ -0,0 +1,30 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from './Button'; + +const meta = { + title: 'examples/ButtonSomeAutodocs', + component: Button, + argTypes: { + backgroundColor: { control: 'color' }, + }, + parameters: { + chromatic: { disable: true }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + tags: ['autodocs'], + args: { + label: 'Button', + }, +}; diff --git a/code/yarn.lock b/code/yarn.lock index 2168bf13fdaa..33f0944c6efd 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6152,6 +6152,7 @@ __metadata: "@storybook/core-server": "workspace:*" "@storybook/html": "workspace:*" "@storybook/node-logger": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" magic-string: "npm:^0.30.0" typescript: "npm:^5.3.2" @@ -6167,6 +6168,7 @@ __metadata: "@storybook/global": "npm:^5.0.0" "@storybook/html": "workspace:*" "@storybook/preset-html-webpack": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" typescript: "npm:^5.3.2" languageName: unknown @@ -6406,6 +6408,7 @@ __metadata: dependencies: "@storybook/builder-vite": "workspace:*" "@storybook/preact": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" typescript: "npm:^5.3.2" vite: "npm:^4.0.0" @@ -6423,6 +6426,7 @@ __metadata: "@storybook/core-common": "workspace:*" "@storybook/preact": "workspace:*" "@storybook/preset-preact-webpack": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" preact: "npm:^10.5.13" typescript: "npm:^5.3.2" @@ -6651,6 +6655,7 @@ __metadata: "@storybook/builder-vite": "workspace:*" "@storybook/node-logger": "workspace:*" "@storybook/react": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" find-up: "npm:^5.0.0" magic-string: "npm:^0.30.0" @@ -6673,6 +6678,7 @@ __metadata: "@storybook/builder-webpack5": "workspace:*" "@storybook/preset-react-webpack": "workspace:*" "@storybook/react": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -6913,6 +6919,7 @@ __metadata: "@storybook/core-common": "workspace:*" "@storybook/preset-server-webpack": "workspace:*" "@storybook/server": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" typescript: "npm:^5.3.2" languageName: unknown @@ -6955,6 +6962,7 @@ __metadata: "@storybook/builder-vite": "workspace:*" "@storybook/node-logger": "workspace:*" "@storybook/svelte": "workspace:*" + "@storybook/types": "workspace:*" "@sveltejs/vite-plugin-svelte": "npm:^3.0.1" "@types/node": "npm:^18.0.0" magic-string: "npm:^0.30.0" @@ -6979,6 +6987,7 @@ __metadata: "@storybook/core-common": "workspace:*" "@storybook/preset-svelte-webpack": "workspace:*" "@storybook/svelte": "workspace:*" + "@storybook/types": "workspace:*" svelte: "npm:^4.0.0" svelte-loader: "npm:^3.1.9" typescript: "npm:^5.3.2" @@ -7023,6 +7032,7 @@ __metadata: "@storybook/builder-vite": "workspace:*" "@storybook/svelte": "workspace:*" "@storybook/svelte-vite": "workspace:*" + "@storybook/types": "workspace:*" "@types/node": "npm:^18.0.0" typescript: "npm:^5.3.2" vite: "npm:^4.0.0" @@ -7133,6 +7143,7 @@ __metadata: dependencies: "@storybook/builder-vite": "workspace:*" "@storybook/core-server": "workspace:*" + "@storybook/types": "workspace:*" "@storybook/vue3": "workspace:*" "@types/find-package-json": "npm:^1.2.6" "@types/node": "npm:^18.0.0" @@ -7154,6 +7165,7 @@ __metadata: "@storybook/builder-webpack5": "workspace:*" "@storybook/core-common": "workspace:*" "@storybook/preset-vue3-webpack": "workspace:*" + "@storybook/types": "workspace:*" "@storybook/vue3": "workspace:*" "@types/node": "npm:^18.0.0" "@vue/compiler-sfc": "npm:3.0.0" @@ -7197,6 +7209,7 @@ __metadata: "@storybook/builder-vite": "workspace:*" "@storybook/core-server": "workspace:*" "@storybook/node-logger": "workspace:*" + "@storybook/types": "workspace:*" "@storybook/web-components": "workspace:*" "@types/node": "npm:^18.0.0" magic-string: "npm:^0.30.0" @@ -7210,6 +7223,7 @@ __metadata: dependencies: "@storybook/builder-webpack5": "workspace:*" "@storybook/core-common": "workspace:*" + "@storybook/types": "workspace:*" "@storybook/web-components": "workspace:*" "@types/node": "npm:^18.0.0" lit: "npm:2.3.1" diff --git a/docs/snippets/common/test-runner-image-snapshot-testing.js.mdx b/docs/snippets/common/test-runner-image-snapshot-testing.js.mdx index d3fd40334eb1..4056d2a3cded 100644 --- a/docs/snippets/common/test-runner-image-snapshot-testing.js.mdx +++ b/docs/snippets/common/test-runner-image-snapshot-testing.js.mdx @@ -16,7 +16,7 @@ module.exports = { // Waits for the page to be ready before taking a screenshot to ensure consistent results await waitForPageReady(page); - // To capture a screenshot for for different browsers, add page.context().browser().browserType().name() to get the browser name to prefix the file name + // To capture a screenshot for different browsers, add page.context().browser().browserType().name() to get the browser name to prefix the file name const image = await page.screenshot(); expect(image).toMatchImageSnapshot({ customSnapshotsDir, diff --git a/docs/versions/latest.json b/docs/versions/latest.json index f2b7dba133dd..eef9cd9b7aa8 100644 --- a/docs/versions/latest.json +++ b/docs/versions/latest.json @@ -1 +1 @@ -{"version":"8.1.0","info":{"plain":"- Automigration: Improve react-docgen automigration prompt - [#27106](https://github.com/storybookjs/storybook/pull/27106), thanks @valentinpalkovic!\n- Typescript: Add types for `experimental-playwright` entries without `type:bundler` - [#27107](https://github.com/storybookjs/storybook/pull/27107), thanks @ndelangen!"}} +{"version":"8.1.1","info":{"plain":"- Docgen: Only add react-docgen info when a component is defined in the file - [#26967](https://github.com/storybookjs/storybook/pull/26967), thanks @glenjamin!\n- Docs: Fix MDX Stories block tag-filtering behavior - [#27144](https://github.com/storybookjs/storybook/pull/27144), thanks @shilman!\n- Docs: Fix Subtitle block when no `of` prop passed - [#27147](https://github.com/storybookjs/storybook/pull/27147), thanks @JReinhold!\n- Next.js: Add typing for NextImage to main framework options type - [#27105](https://github.com/storybookjs/storybook/pull/27105), thanks @valentinpalkovic!\n- Next.js: Avoid conflicts with the raw loader - [#27093](https://github.com/storybookjs/storybook/pull/27093), thanks @seanparmelee!\n- Types: Fix typing for main.framework/builder fields - [#27088](https://github.com/storybookjs/storybook/pull/27088), thanks @valentinpalkovic!"}} diff --git a/docs/versions/next.json b/docs/versions/next.json index 7f0c72f527a4..3062aa7a1fea 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.1.0-beta.1","info":{"plain":"- API: Add API access to sidebar renderLabel - [#27099](https://github.com/storybookjs/storybook/pull/27099), thanks @shilman!\n- CLI: Add main.js `docs.autodocs` automigration - [#27089](https://github.com/storybookjs/storybook/pull/27089), thanks @shilman!\n- CLI: Fix eslint configuration for string `extends` - [#27097](https://github.com/storybookjs/storybook/pull/27097), thanks @shilman!\n- Indexer: Escape special characters in storyImport regex - [#22545](https://github.com/storybookjs/storybook/pull/22545), thanks @VojGin!\n- Next.js: Fix Compatibility with