Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
09a3fdb
fix(core): add showSelectedLabel prop to Select to control selected l…
ia319 Dec 5, 2025
a3bc089
fix(core): disable Select selected-label override in ToolbarMenuSelect
ia319 Dec 5, 2025
6e1cae0
fix lint error
ia319 Dec 5, 2025
a0befe0
refactor (ToolbarMenuSelect): remove manual title calculation, remove…
ia319 Dec 6, 2025
b6ac5b3
Merge branch 'next' into bug/33281-dynamic-title-select
ia319 Dec 6, 2025
75c9403
refactor: rename legacy Select prop and clean up ToolbarMenuSelect ti…
ia319 Dec 11, 2025
1134d29
chore: update globaltypes snippet and remove unused getSelectedTitle
ia319 Dec 11, 2025
303fccc
test(core): add four stories validating Select label behavior
ia319 Dec 11, 2025
fae8f79
Merge branch 'bug/33281-dynamic-title-select' of https://github.com/i…
ia319 Dec 11, 2025
eec0b3d
Merge branch 'next' into bug/33281-dynamic-title-select
ia319 Dec 11, 2025
6c43d09
Merge branch 'next' into bug/33281-dynamic-title-select
Sidnioulz Dec 19, 2025
304eb5a
CLI: Support addon-vitest setup when --skip-install is passed
valentinpalkovic Jan 30, 2026
906df16
Refactor addon-vitest templates and postinstall logic to use .txt ext…
valentinpalkovic Jan 30, 2026
7a5f4d7
Fix tests
valentinpalkovic Jan 30, 2026
5184bfa
Add support for cross-file story imports in story-to-csf transformation
yatishgoel Jan 31, 2026
b6464e0
Hardcode list of templates
valentinpalkovic Feb 2, 2026
c5e9676
Add manual configuration instructions for failed addon installations …
valentinpalkovic Feb 2, 2026
73addfb
Fix template naming
valentinpalkovic Feb 2, 2026
388db38
Simplify template naming handling
valentinpalkovic Feb 2, 2026
1bee851
Add raw plugin
valentinpalkovic Feb 2, 2026
1efe45f
Add support for importing raw content in TypeScript typings and remov…
valentinpalkovic Feb 2, 2026
6755af1
Ensure postinstall script executions take place even when skipInstall…
valentinpalkovic Feb 2, 2026
5308634
Small refactoring
valentinpalkovic Feb 3, 2026
5f277da
Add documentation comment to clarify template import handling in getT…
valentinpalkovic Feb 4, 2026
6d0104a
Merge pull request #33718 from storybookjs/valentin/bundle-addon-vite…
valentinpalkovic Feb 4, 2026
95ff0df
Merge branch 'next-release' into next
storybook-bot Feb 4, 2026
089bd3f
Update CHANGELOG.md for v10.2.6 [skip ci]
storybook-bot Feb 4, 2026
c7f0f7a
Merge branch 'next' into bug/33281-dynamic-title-select
ia319 Feb 4, 2026
9eaacdb
Merge branch 'next' into bug/33281-dynamic-title-select
ia319 Feb 4, 2026
d355c8b
Merge pull request #33284 from ia319/bug/33281-dynamic-title-select
valentinpalkovic Feb 4, 2026
3463795
fix(core): apply --loglevel to npmlog
Feb 5, 2026
8ef9070
Merge pull request #33723 from yatishgoel/fix/csf-factories-cross-fil…
valentinpalkovic Feb 5, 2026
fecb2ef
Build: Fix test
valentinpalkovic Feb 5, 2026
01fc452
Merge pull request #33780 from storybookjs/valentin/fix-unit-test
valentinpalkovic Feb 5, 2026
02fdf2a
Merge pull request #33776 from LouisLau-art/fix/loglevel-flag-works
valentinpalkovic Feb 5, 2026
fc65414
ignore empty story files when indexing
JReinhold Feb 5, 2026
6af360f
Merge pull request #33782 from storybookjs/jeppe/ignore-empty-story-f…
JReinhold Feb 5, 2026
48dee50
Write changelog for 10.3.0-alpha.5 [skip ci]
storybook-bot Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 10.2.6

- Addon-Vitest: Skip postinstall setup when configured - [#33712](https://github.com/storybookjs/storybook/pull/33712), thanks @valentinpalkovic!
- Addon-Vitest: Support vite/vitest config with deferred export - [#33755](https://github.com/storybookjs/storybook/pull/33755), thanks @valentinpalkovic!
- CLI: Support addon-vitest setup when --skip-install is passed - [#33718](https://github.com/storybookjs/storybook/pull/33718), thanks @valentinpalkovic!
- Manager: Update logic to use base path instead of full pathname - [#33686](https://github.com/storybookjs/storybook/pull/33686), thanks @JSMike!

## 10.2.5

- Angular: fix --loglevel options in docs and descriptions - [#33726](https://github.com/storybookjs/storybook/pull/33726), thanks @theRuslan!
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 10.3.0-alpha.5

- CLI: Support addon-vitest setup when --skip-install is passed - [#33718](https://github.com/storybookjs/storybook/pull/33718), thanks @valentinpalkovic!
- CSF: Fix cross-file story imports in csf-factories codemod - [#33723](https://github.com/storybookjs/storybook/pull/33723), thanks @yatishgoel!
- Core: Ignore empty files when indexing - [#33782](https://github.com/storybookjs/storybook/pull/33782), thanks @JReinhold!
- Globals: Repair dynamicTitle: false for user-defined tools - [#33284](https://github.com/storybookjs/storybook/pull/33284), thanks @ia319!
- Logger: Honor --loglevel for npmlog output - [#33776](https://github.com/storybookjs/storybook/pull/33776), thanks @LouisLau-art!

## 10.3.0-alpha.4

- Addon-Vitest: Support vite/vitest config with deferred export - [#33755](https://github.com/storybookjs/storybook/pull/33755), thanks @valentinpalkovic!
Expand Down
1 change: 1 addition & 0 deletions code/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ ember-output
!.storybook
core/assets
core/src/core-server/utils/__search-files-tests__
core/src/core-server/utils/__mockdata__/src/Empty.stories.ts
core/report
10 changes: 7 additions & 3 deletions code/addons/a11y/src/postinstall.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { JsPackageManagerFactory } from 'storybook/internal/common';
import { JsPackageManagerFactory, versions } from 'storybook/internal/common';

import type { PostinstallOptions } from '../../../lib/cli-storybook/src/add';

export default async function postinstall(options: PostinstallOptions) {
const args = ['storybook', 'automigrate', 'addon-a11y-addon-test'];
const args = [
options.skipInstall ? `storybook@${versions.storybook}` : `storybook`,
'automigrate',
'addon-a11y-addon-test',
];

args.push('--loglevel', 'silent');
args.push('--skip-doctor');
Expand All @@ -25,5 +29,5 @@ export default async function postinstall(options: PostinstallOptions) {
configDir: options.configDir,
});

await jsPackageManager.runPackageCommand({ args });
await jsPackageManager.runPackageCommand({ args, useRemotePkg: !!options.skipInstall });
}
19 changes: 13 additions & 6 deletions code/addons/vitest/src/postinstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
formatFileContent,
getProjectRoot,
getStorybookInfo,
versions,
} from 'storybook/internal/common';
import { CLI_COLORS } from 'storybook/internal/node-logger';
import type { StorybookError } from 'storybook/internal/server-errors';
Expand Down Expand Up @@ -161,6 +162,7 @@ export default async function postInstall(options: PostinstallOptions) {
if (!options.skipInstall) {
await addonVitestService.installPlaywright({
yes: options.yes,
useRemotePkg: !!options.skipInstall,
});
} else {
logger.warn(dedent`
Expand Down Expand Up @@ -229,11 +231,11 @@ export default async function postInstall(options: PostinstallOptions) {

const getTemplateName = () => {
if (isVitest4OrNewer) {
return 'vitest.config.4.template.ts';
return 'vitest.config.4.template';
} else if (isVitest3_2To4) {
return 'vitest.config.3.2.template.ts';
return 'vitest.config.3.2.template';
}
return 'vitest.config.template.ts';
return 'vitest.config.template';
};

// If there's an existing workspace file, we update that file to include the Storybook Addon Vitest plugin.
Expand All @@ -249,7 +251,7 @@ export default async function postInstall(options: PostinstallOptions) {
return;
}

const workspaceTemplate = await loadTemplate('vitest.workspace.template.ts', {
const workspaceTemplate = await loadTemplate('vitest.workspace.template', {
EXTENDS_WORKSPACE: viteConfigFile
? relative(dirname(vitestWorkspaceFile), viteConfigFile)
: '',
Expand Down Expand Up @@ -358,7 +360,7 @@ export default async function postInstall(options: PostinstallOptions) {
if (a11yAddon) {
try {
const command = [
'storybook',
options.skipInstall ? `storybook@${versions.storybook}` : `storybook`,
'automigrate',
'addon-a11y-addon-test',
'--loglevel',
Expand All @@ -381,7 +383,12 @@ export default async function postInstall(options: PostinstallOptions) {

await prompt.executeTask(
// TODO: Remove stdio: 'ignore' once we have a way to log the output of the command properly
() => packageManager.runPackageCommand({ args: command, stdio: 'ignore' }),
() =>
packageManager.runPackageCommand({
args: command,
stdio: 'ignore',
useRemotePkg: !!options.skipInstall,
}),
{
intro: 'Setting up a11y addon for @storybook/addon-vitest',
error: 'Failed to setup a11y addon for @storybook/addon-vitest',
Expand Down
5 changes: 5 additions & 0 deletions code/addons/vitest/src/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ interface ImportMetaEnv {
interface ImportMeta {
readonly env: ImportMetaEnv;
}

declare module '*?raw' {
const content: string;
export default content;
}
38 changes: 19 additions & 19 deletions code/addons/vitest/src/updateVitestFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ vi.mock('../../../core/src/shared/utils/module', () => ({
describe('updateConfigFile', () => {
it('updates vite config file', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -102,7 +102,7 @@ describe('updateConfigFile', () => {

it('supports object notation without defineConfig', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -182,7 +182,7 @@ describe('updateConfigFile', () => {

it('does not support function notation', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -214,7 +214,7 @@ describe('updateConfigFile', () => {

it('adds projects property to test config', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -293,7 +293,7 @@ describe('updateConfigFile', () => {

it('updates config which is not exported immediately', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -378,7 +378,7 @@ describe('updateConfigFile', () => {

it('edits projects property of test config', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -458,7 +458,7 @@ describe('updateConfigFile', () => {

it('adds workspace property to test config', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -537,7 +537,7 @@ describe('updateConfigFile', () => {

it('adds test property to vite config', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -612,7 +612,7 @@ describe('updateConfigFile', () => {

it('supports mergeConfig with multiple defineConfig calls, finding the one with test', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -698,7 +698,7 @@ describe('updateConfigFile', () => {
});
it('supports mergeConfig without defineConfig calls', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -781,7 +781,7 @@ describe('updateConfigFile', () => {

it('supports mergeConfig without config containing test property', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -857,7 +857,7 @@ describe('updateConfigFile', () => {

it('supports mergeConfig with defineConfig pattern using projects (Vitest 3.2+)', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -941,7 +941,7 @@ describe('updateConfigFile', () => {

it('appends storybook project to existing test.projects array (no double nesting)', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -1030,7 +1030,7 @@ describe('updateConfigFile', () => {

it('extracts coverage config and keeps it at top level when using workspace', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
await loadTemplate('vitest.config.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -1129,7 +1129,7 @@ describe('updateConfigFile', () => {

it('extracts coverage config and keeps it at top level when using projects', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
await loadTemplate('vitest.config.3.2.template', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
Expand Down Expand Up @@ -1230,7 +1230,7 @@ describe('updateConfigFile', () => {
describe('updateWorkspaceFile', () => {
it('updates vitest workspace file using array syntax', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.workspace.template.ts', {
await loadTemplate('vitest.workspace.template', {
EXTENDS_WORKSPACE: '',
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
Expand Down Expand Up @@ -1286,7 +1286,7 @@ describe('updateWorkspaceFile', () => {

it('updates vitest workspace file using defineWorkspace syntax', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.workspace.template.ts', {
await loadTemplate('vitest.workspace.template', {
EXTENDS_WORKSPACE: '',
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
Expand Down Expand Up @@ -1349,7 +1349,7 @@ describe('loadTemplate', () => {
// Windows-style path with backslashes (need to escape them in JS strings)
const windowsPath = '.\\apps\\frontend-storybook\\.storybook';

const result = await loadTemplate('vitest.config.template.ts', {
const result = await loadTemplate('vitest.config.template', {
CONFIG_DIR: windowsPath,
SETUP_FILE: '.\\apps\\frontend-storybook\\.storybook\\vitest.setup.ts',
});
Expand All @@ -1363,7 +1363,7 @@ describe('loadTemplate', () => {
// Unix-style path with forward slashes
const unixPath = './apps/frontend-storybook/.storybook';

const result = await loadTemplate('vitest.config.template.ts', {
const result = await loadTemplate('vitest.config.template', {
CONFIG_DIR: unixPath,
SETUP_FILE: './apps/frontend-storybook/.storybook/vitest.setup.ts',
});
Expand Down
30 changes: 22 additions & 8 deletions code/addons/vitest/src/updateVitestFile.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import * as fs from 'node:fs/promises';

import type { BabelFile, types as t } from 'storybook/internal/babel';

import { join, normalize } from 'pathe';
import { normalize } from 'pathe';

import { resolvePackageDir } from '../../../core/src/shared/utils/module';
/**
* Each template is imported separately to allow the build system to process the template as raw
* text. A mix of globs and the "?raw" string query is not supported in esbuild
*/
async function getTemplatePath(name: string) {
switch (name) {
case 'vitest.config.template':
return import('../templates/vitest.config.template?raw');
case 'vitest.config.4.template':
return import('../templates/vitest.config.4.template?raw');
case 'vitest.config.3.2.template':
return import('../templates/vitest.config.3.2.template?raw');
case 'vitest.workspace.template':
return import('../templates/vitest.workspace.template?raw');
default:
throw new Error(`Unknown template: ${name}`);
}
}

export const loadTemplate = async (name: string, replacements: Record<string, string>) => {
let template = await fs.readFile(
join(resolvePackageDir('@storybook/addon-vitest'), 'templates', name),
'utf8'
);
// Dynamically import the template file as plain text
const templateModule = await getTemplatePath(name);
let template = templateModule.default;
// Normalize Windows paths (backslashes) to forward slashes for JavaScript string compatibility
Object.entries(replacements).forEach(
([key, value]) => (template = template.replace(key, normalize(value)))
Expand Down
13 changes: 8 additions & 5 deletions code/core/src/bin/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getEnvConfig, optionalEnvToBoolean, parseList } from 'storybook/interna
import { logTracker, logger } from 'storybook/internal/node-logger';
import { addToGlobalContext } from 'storybook/internal/telemetry';

import { program } from 'commander';
import { Option, program } from 'commander';
import leven from 'leven';
import picocolors from 'picocolors';

Expand Down Expand Up @@ -45,17 +45,20 @@ const command = (name: string) =>
)
.option('--debug', 'Get more logs in debug mode', false)
.option('--enable-crash-reports', 'Enable sending crash reports to telemetry data')
.option('--loglevel <trace | debug | info | warn | error | silent>', 'Define log level', 'info')
.addOption(
new Option('--loglevel <level>', 'Define log level')
.choices(['trace', 'debug', 'info', 'warn', 'error', 'silent'])
.default('info')
)
.option(
'--logfile [path]',
'Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided'
)
.hook('preAction', async (self) => {
try {
const options = self.opts();
if (options.loglevel) {
logger.setLogLevel(options.loglevel);
}
const loglevel = options.debug ? 'debug' : options.loglevel;
logger.setLogLevel(loglevel);

if (options.logfile) {
logTracker.enableLogWriting();
Expand Down
7 changes: 6 additions & 1 deletion code/core/src/cli/AddonVitestService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ export class AddonVitestService {
* @returns Array of error messages if installation fails
*/
async installPlaywright(
options: { yes?: boolean } = {}
options: {
yes?: boolean;
/** Is set to true if Storybook didn't install the dependencies yet */
useRemotePkg?: boolean;
} = {}
): Promise<{ errors: string[]; result: 'installed' | 'skipped' | 'aborted' | 'failed' }> {
const errors: string[] = [];

Expand Down Expand Up @@ -148,6 +152,7 @@ export class AddonVitestService {
(signal) =>
this.packageManager.runPackageCommand({
args: playwrightCommand,
useRemotePkg: options.useRemotePkg,
stdio: ['inherit', 'pipe', 'pipe'],
signal,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ export abstract class JsPackageManager {
stdio?: 'inherit' | 'pipe' | 'ignore'
): ResultPromise;
public abstract runPackageCommand(
options: Omit<ExecuteCommandOptions, 'command'> & { args: string[] }
options: Omit<ExecuteCommandOptions, 'command'> & { args: string[]; useRemotePkg?: boolean }
): ResultPromise;
public abstract findInstallations(pattern?: string[]): Promise<InstallationMetadata | undefined>;
public abstract findInstallations(
Expand Down
Loading