Release: Prerelease beta 10.5.0-beta.3#35407
Open
github-actions[bot] wants to merge 81 commits into
Open
Conversation
…ng to do The check only evaluated the "already migrated" skip conditions when both .storybook/vitest.setup.* and .storybook/preview.* existed. Projects without a vitest.setup file (the norm since the vitest plugin auto-provisions preview annotations in 10.3+) were always prompted, even when preview already had parameters.a11y.test configured — and running the migration was a no-op. The skip flags are now computed independently per file: a missing setup file counts as nothing-to-transform on the setup side, and the preview file is checked on its own. This also fixes re-transforming an already-migrated setup file (duplicate a11yAddonAnnotations import) when no preview file existed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…emas, widen preview transform match The angular-to-angular-vite automigration never re-added zone.js after moving projects off the webpack builder's implicit polyfill loading, breaking zone-based Angular apps (e.g. Bitwarden clients) after migrating to @storybook/angular-vite. Detection reads the flag-only signal (storybook builder target options.experimentalZoneless) across every angular.json/Nx project.json storybook target, injects import 'zone.js' into the preview when needed, and renames any leftover experimentalZoneless key to zoneless. Also fixes two adjacent bugs so the zoneless story lands coherently: - angular-vite's published start-schema.json/build-schema.json still declared the stale experimentalZoneless option instead of zoneless, so the correct zoneless: false setting failed schema validation while the stale key passed silently. - preset.ts's transform hook only matched a literal preview.ts, so .tsx (and other) preview files never received the runtime zone.js injection. It now resolves the preview path once via findConfigFile (core's own resolution list), cached in the plugin's config() hook.
Dropping the standalone schema-consistency test file per request; schema correctness for zoneless/experimentalZoneless is still exercised indirectly through the migration test suite and manual verification.
Initial screen: - Use a ToggleButton (role=switch) for the new-stories filter so its state is exposed - Render the "Summary:" label and each collection title as <h2> headings - Give each collection a role=group labelled by its title - Expose list semantics on the collection grid (role=list / role=listitem) - Add an accessible label to the per-collection story count - Use the formatted story title (not the raw story id) in the story aria-label and iframe title - Stop the story focus indicator from being cropped by an ancestor overflow Story screen: - Rename "Open story list" to "Select story" so the action is predictable - Disable the previous/next story buttons (aria-disabled) when there is no adjacent story
- Make the ArrowLeft/ArrowRight shortcuts boundary-aware so they no longer wrap past the first/last story, matching the disabled prev/next buttons - Extract a NavButton helper to deduplicate the previous/next controls - Deduplicate the story-count pluralization in the summary screen Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaBs21ubN8uuz1wx1EtVZJ
Fixes composed-ref Controls showing "No controls" on a direct deep-link. A ref's runtime story enrichment (args, argTypes, parameters, prepared) arrives via STORY_PREPARED but is not part of the ref's static story index, so `setRef` rebuilding the index wiped it — and on a deep-link the enrichment can arrive before the index is composed, so `updateStory` dropped it entirely. Cache the enrichment per ref (`ref.storyUpdates`) and re-apply it whenever the ref index is (re)built, making it order-independent. Co-authored-by: Cursor <cursoragent@cursor.com>
…-vitest
The migration's TS config loader broke whenever `skipCache`'s cache-busting
query string was appended to a `.ts` main config URL: the loader matched
files via `url.endsWith('.ts')`, which silently failed on `main.ts?<ts>`
and fell back to Node's native type-stripping, which (unlike the esbuild
transform it bypassed) doesn't elide type-only named imports. That caused
a hard crash for any project importing `StorybookConfig` without `type`,
and separately let stale, pre-migration framework/builder data leak into
the addon-vitest compatibility check, producing a false
"Non-Vite builder is not supported" failure right after a successful
migration to `@storybook/angular-vite`.
Also fixes an inverted `--yes` default on the webpackFinal continuation
prompt, which cancelled the whole migration in non-interactive mode, and
threads `skipCache` through `getStorybookData` so `automigrate`/`add`
read the freshly-rewritten main config instead of a cached evaluation.
… fixes Covers the loader.ts esbuild transform still applying to a `.ts?<query>` URL, the webpackFinal prompt proceeding automatically under `--yes`, and the migration marking a plain StorybookConfig import as `import type`.
…port rewrite The loader.ts fix already makes esbuild's transform apply to every .ts main config load regardless of skipCache's query string, and esbuild elides a type-only StorybookConfig import whether or not it's marked `type` — so the type-import rewrite in this fixer was redundant. Cancelling the migration under --yes when a webpackFinal hook is present is intentional: silently dropping a hook that won't carry over to Vite in unattended mode is worse than requiring an explicit rerun after porting it.
A direct edit on the PR branch introduced a duplicated eslint-disable comment and mis-indented the globby dynamic import, tripping CI's format-check and eslint jobs. Restores the original correctly formatted line.
Core: Fix potential race condition in SET_CONFIG hook
Cli: Allow -p shorthand to --port for ai command
Addon register callbacks run in the ManagerProvider constructor (before the component mounts) so manager-side listeners (e.g. open-service) are ready before the preview iframe emits. React's this.setState is a no-op before mount, which silently dropped register-time store writes such as experimental_setFilter. As a result the initial story index was rendered unfiltered, and the filter only took effect after a later navigation re-applied it. Write store patches directly to this.state while the component is not yet mounted, then delegate to React's setState once mounted. This keeps addon registration in the constructor (preserving open-service ordering) while ensuring register-time filters land in the first render. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the cell's overflow clipping and inset the focus outline so the indicator stays fully visible, per review feedback.
…apper Raise the SummaryHeading override specificity so the h2 keeps the inline bold appearance instead of inheriting the document wrapper's larger, bordered h2 style.
pnpm-only repos with devEngines fail when Storybook upgrade or setup instructions invoke npm via npx. Route remote CLI packages through the detected package manager and emit matching commands in AI setup prompts.
…llback from poisoning it The shared channel slot introduced in the channel-management refactor made `addons.getChannel()`'s mock fallback global: a single early read would mirror a throwaway mock into `__STORYBOOK_ADDONS_CHANNEL__` and permanently resolve `ready()` to it, so the real channel installed later never took over. - Install the manager channel at module load (before the deferred render) so `getChannel()` returns the real channel instead of a fallback. - Make the mock fallback in both the manager-api and preview-api AddonStores non-poisoning: return a throwaway mock without caching it, mirroring it to the shared slot, or resolving `ready()`. Co-authored-by: Cursor <cursoragent@cursor.com>
When detectAgent() (std-env) reports an AI agent environment (Claude Code, Codex, Cursor, explicit AI_AGENT, ...), resolve open: false for storybook dev so the system browser is not opened next to the agent's own preview. Claude-preview launch behavior, including PORT precedence, is unchanged. Part 1 of #35411
The Storybook Vitest runtime (browser mode) has no builder preamble to install a channel, and preview open-services register at import time. This previously worked only by accident: the mock-fallback in getChannel() installed one. Now that the fallback no longer poisons the shared slot, install a channel explicitly at the setup entry point, before preview.tsx evaluates. Co-authored-by: Cursor <cursoragent@cursor.com>
Both independent reviews flagged that detectAgent() silently bypassed the injected env seam of resolveDevCommandOptions. Expose it as an overridable 'agent' option (defaulting to ambient detection) so tests opt out with agent: null instead of scrubbing a hand-maintained agent env-var list.
Align with AddonStore.setChannel's parameter type (Channel from storybook/internal/channels) to fix a TS2345 nominal mismatch against the source-module Channel. Co-authored-by: Cursor <cursoragent@cursor.com>
…ntinfo A contentinfo landmark should stay top-level, but the summary footer is nested inside the main landmark; expose it as a named region instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaBs21ubN8uuz1wx1EtVZJ
…d collect Template selection in the addon-vitest postinstall used coerce() while collectDependencies() used validRange()/minVersion(); the two could disagree on the vitest major (e.g. an installed `4.0.0-beta.1` -> coerce says v4 but minVersion keeps the prerelease and fails `>=4.0.0`, so it read as v3). Extract a shared AddonVitestService.getComparableVersion() helper used by both, which takes a range's lower bound and coerces away the prerelease tag so both paths agree. Also document why the pnpm catalog helpers edit pnpm-workspace.yaml directly rather than through `pnpm config` like the minimumReleaseAge settings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review feedback: the catalog complexity (detecting `catalog:`, reading `getCatalogVersion`, emitting `@catalog:` specifiers, syncing the workspace file) lived in AddonVitestService and ran regardless of package manager, so a stray `catalog:` on npm/yarn would emit broken specifiers. Introduce two package-manager methods and move all catalog logic behind them: - getDeclaredVersionSpecifier(pkg): installed version, else declared range; PNPMProxy additionally resolves a `catalog:` reference. - applyVersionToRelatedPackages(packages, version, anchor): pins each directly; PNPMProxy registers them in the anchor's catalog and returns `catalog:` refs. The catalog read/write helpers (getCatalogVersion/syncWorkspaceCatalog and the yaml document plumbing) are now private to PNPMProxy. AddonVitestService no longer references catalogs at all, and non-pnpm managers never produce catalog specifiers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…talog failures - Follow the workspace's existing default-catalog form (top-level catalog vs catalogs.default) instead of always writing a top-level catalog key, which pnpm rejects when catalogs.default already exists. - When the workspace file is missing, malformed, or unwritable, fall back to direct version pins instead of returning unresolvable catalog: refs. - Reuse the anchor's own catalog entry format (e.g. ^3.2.0) for new entries rather than the resolved exact installed version. - Rewrite catalog tests on memfs per repo testing guidelines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the `WebSocket` global stub out of module scope into `beforeEach` and add `vi.unstubAllGlobals()` to `afterEach`, so the suite no longer leaves an ambient global behind for other test files in the same worker. CodeRabbit's proposed fix (only adding `vi.unstubAllGlobals()` while keeping the stub at module scope) would break the suite: after the first test's cleanup the stub is gone and subsequent tests construct a real WebSocket, so `socketRef` is never populated. Re-stubbing per test keeps all 7 tests passing while complying with the repo's global-stubbing guideline. Co-authored-by: Cursor <cursoragent@cursor.com>
…artbeat-reset-on-any-message
Cli: Handle nested array schema for AI help
CLI: Skip a11y addon automigration prompting when not applicable
…at-reset-on-any-message Core: Reset WebsocketTransport heartbeat on every message, not just ping
Init: Support pnpm catalogs when adding addon-vitest dependencies
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 72 | 73 | 🚨 +1 🚨 |
| Self size | 21.94 MB | 22.16 MB | 🚨 +217 KB 🚨 |
| Dependency size | 36.44 MB | 36.65 MB | 🚨 +213 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/angular-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 32 | 33 | 🚨 +1 🚨 |
| Self size | 22.38 MB | 22.48 MB | 🚨 +94 KB 🚨 |
| Dependency size | 20.07 MB | 20.07 MB | 🚨 +455 B 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/cli
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 204 | 205 | 🚨 +1 🚨 |
| Self size | 821 KB | 827 KB | 🚨 +6 KB 🚨 |
| Dependency size | 91.93 MB | 92.36 MB | 🚨 +430 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/codemod
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 197 | 198 | 🚨 +1 🚨 |
| Self size | 32 KB | 32 KB | 0 B |
| Dependency size | 90.41 MB | 90.84 MB | 🚨 +429 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
create-storybook
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 73 | 74 | 🚨 +1 🚨 |
| Self size | 1.09 MB | 1.09 MB | 🚨 +1 KB 🚨 |
| Dependency size | 58.38 MB | 58.81 MB | 🚨 +430 KB 🚨 |
| Bundle Size Analyzer | node | node |
Review: Fix accessibility/UX issues in the review UI
After the dedupe step, the upgrade command configures addons that automigrations deferred (e.g. addon-vitest/addon-a11y from angular-to-angular-vite). The a11y postinstall spawned the nested "storybook automigrate addon-a11y-addon-test" command with open stdio pipes. When that nested run failed (e.g. an npm ERESOLVE peer conflict), the process tree blocked forever with zero output - the upgrade appeared to hang right after the dedupe prompt. It now uses stdio: 'ignore' like the addon-vitest postinstall already does, so a failure surfaces instead of hanging. The upgrade also logs a visible "Configuring addons: ..." step and warns when that phase fails, so it can no longer fail invisibly.
Only stdin needs to be closed to prevent the npm exec layers from blocking on a never-ending pipe; stdout/stderr can stay piped so that a failed nested run still reports the underlying error (e.g. the npm ERESOLVE details) instead of just an exit code.
…ailures Previously the postinstall hook of a deferred addon was resolved relative to the CLI bundle (import.meta.resolve first, and a createRequire anchored to a bare directory, which resolves from the parent). When the CLI runs from a different tree than the project (npx, monorepo), resolution failed and the addon was silently skipped and left unconfigured. The hook is now resolved from the user's project first. Because the upgrade command installs the addon mid-run, Node's module resolution has already cached the earlier negative lookup, so a short-lived child process (clean resolution cache) is used as a fallback before giving up. The subsequent load goes through a direct file URL, which is not affected by the cached exports lookup. Resolution and load failures now warn with the underlying error and a manual setup hint instead of silently returning.
…ug--upgrade--CLI CLI: Fix silent hang in deferred addon configuration during upgrade
e8cd0b4 to
9bfa1e1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is an automated pull request that bumps the version from `10.5.0-beta.2` to `10.5.0-beta.3`.
Once this pull request is merged, it will trigger a new release of version `10.5.0-beta.3`.
If you're not a core maintainer with permissions to release you can ignore this pull request.
To do
Before merging the PR, there are a few QA steps to go through:
And for each change below:
This is a list of all the PRs merged and commits pushed directly to `next`, that will be part of this release:
If you've made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with this workflow and wait for it to finish. It will wipe your progress in this to do, which is expected.
Feel free to manually commit any changes necessary to this branch after you've done the last re-generation, following the Make Manual Changes section in the docs, especially if you're making changes to the changelog.
When everything above is done:
Generated changelog
10.5.0-beta.3