Skip to content

Conversation

@Sidnioulz
Copy link
Member

@Sidnioulz Sidnioulz commented Aug 13, 2025

Closes #25918
Closes #32235
Closes #26674

New components

AriaToolbar

We needed a bar that has the proper toolbar role and implements the toolbar navigation.

  • Has built-in kb navigation
  • Bundled inside a Bar component

AbstractAriaToolbar

  • Has an absolutely awful name
  • Not bundled inside a Bar component, made for custom layout use cases

AriaTabs

We needed the proper tablist-tabpanel implementation with

  • Keyboard navigation (left-right in the list, tab/shift+tab to switch between list and panel)

  • The list and panel directly adjacent in tabbing order

  • Integrates all below components and hooks into a preconfigured tabpanel

  • Forces a layout where the tablist and tabpanel are huddled together, with the tablist in a Bar and optional tools on the side

  • Provides access to AriaTabPanel props to limit need to detach

  • Allows passing a style object and bg color to the Bar, also to limit need to detach

  • Has empty state support like old Tabs

  • Can receive tools like old Tabs (but places them before the ariatabs in the tabbing order for WCAG compliance)

AriaTabList

  • Consumes the shared state object
  • Shows the list of buttons that control the panel
  • Has built-in kb navigation
  • Tab items can be disabled, selected (current tab), pressed (being pressed/activated), focused
  • Tab items have a title (can be string or ReactNode)

AriaTabPanel

  • Consumes the shared state object
  • Shows only the current tab by default
  • Has option to render other tabs in the background with a forced hidden attr, for React context preservation in existing addon panels
  • Has built-in ScrollArea that can be disabled for advanced layouts

useAriaTabListState

  • Generates a shared state from a declarative list of tabs
  • The shared state helps tablist and tabpanel share DOM ids, aria attributes, etc.
  • Each tab has an id, a title (string|ReactNode), children (string|ReactNode) and aria-label

Changes to existing UI

Bar (@storybook/components)

Changes made

  • Removed ScrollArea in favour of the CSS scrollbar that was effectively in use everywhere
  • Added an inner div to the Bar to preserve height when it scrolls without having to hardcode Bar implementation details in callee code
  • Added an innerStyle prop to help handling recurring layout customisation needs (padding, gap, flex direction) without having to fork Bar or rely on internal DOM structure

Changes not made

  • Did not fix the logical coupling between border and backgroundColor as it was not relevant to what I was fixing, though I'd be happy to smooth that out too to group up component API changes in a single major

Rationale

Bar's primary issues are:

  • ScrollArea would have side effects in how flex positioning is applied to Bar, because it div layers between the Bar and its callee; this is an issue I ran into during this PR
  • Likely erroneous of default values for the scrollable prop resulting in three variants: true uses ScrollArea, undefined uses CSS scrollbars, false is non-scrollable; knowing that no code inside Storybook uses true
  • Bar's handling of height forces callees who want a scrollable Bar to have an extra div layer between the Bar and its children that hardcodes the Bar height, to preserve content height when the scrollbar is drawn

FlexBar (@storybook/components)

Changes made

  • Added a deprecate notice

Rationale

FlexBar is a layout specialisation of Bar, but it turned out that we had places in the code where we needed exactly that layout, but still used Bar. That's because FlexBar made it harder to apply paddings and gaps between items. The component likely was written for a specific use case and existing use cases likely didn't get refactored in time.

Given that the bulk of FlexBar's value can be achieved with a few CSS properties, and that using FlexBar requires writing as much CSS to override its opinionated padding, I prefer removing it entirely.

Tabs (@storybook/components)

Changes made

  • Added a deprecate notice
  • Removed unused useResizeDetector dependency
  • Moved TabButton subcomponent from the bar folder to the tabs/ folder because it belongs to Tabs

Rationale

Tabs suffers a few issues:

  • A11y: it hardcodes IDs which results in duplicate-ID WCAG violations
  • A11y: it doesn't provide a tabpanel role for the active panel
  • A11y: it doesn't implement the required keyboard navigation panel (<- ->)
  • A11y: it doesn't attempt to ensure the tablist and tabpanel immediately follow each other in keyboard tab order
  • A11y: it doesn't mark the currently selected item in the tablist with aria-selected
  • A11y: its focus state is not distinguishable from its selected state
  • Quality: the existing API has a fair share of presentational props (border, background colour, absolute positioning) that feel like they should be grouped and presented via Emotion CSS objects if relevant, or simply left to callees to handle via Emotion
  • Quality: it contains a fair share of addon panel specific code, violating separation of concerns
  • Perf: it forces us to render every child instead of just the selected one, even when unnecessary

Fixing those issues requires a near total rewrite of the component's logic, especially because we have patterns where we need the tablist and tabpanel to be rendered separately, and their shared state to be maintained upstream. It also requires adding props for an opaque state object that can contain all the relevant shared state without forcing callees to be aware of implementation details.

It was significantly easier to create a new component than to ensure that both new and existing components are API-compatible.

AddonPanel (@storybook/components)

  • Forced a height of 100% by default, as this is almost always necessary in the addon panel; it helps with vertical centering and scrollbar behaviour
  • Added a hasScrollbar prop to pre-integrate the scrollbar for addons that don't need a more advanced layout; can be disabled easily enough

Rationale

This component is used internally for many of our 'simpler' addon layouts, but also exposed to addon authors. Therefore, it makes sense for the component to provide the best defaults out of the box for addon panel positioning (aka. take all the space and have a scrollbar).

Toolbar (@storybook/addon-docs/blocks)

  • Switched from FlexBar to AriaToolbar, because this is a toolbar and it did not need the FlexBar layout specialisation
  • Replaced wrapper div with CSS properties to simplify DOM and code

SubNav -> Toolbar (component-testing module)

  • Renamed component because it is not a nav, and that had caused confusion in the past when refactoring nav ARIA attributes
  • Made component use AriaToolbar instead of Bar, as this is a toolbar :)
  • Improved aria-label to explain the types of tools found instead of repeating "toolbar" (SRs will already announce that this is a toolbar)
  • Simplified layout, favouring padding and gap instead of side margins on children where possible

Addon panel

  • Ported to use AriaTabList and AriaTabPanel
  • Moved ErrorBoundary code specific to this panel back from the shared Bars component into the panel source
  • Added heading and DOM/ARIA markup for the toolbar to become a landmark

Addon-controls panel

  • Save Story: Adjusted positioning and dimensions of the bar as it was cropped a little
  • Adjusted layout to handle changes to AddonPanel container

Toolbar

  • Temporarily migrated the canvas/docs/addon tabs to AriaTabs, without wrapping the preview in a tabpanel, just to fix kb nav behaviour and avoid regressions
  • Made minor change to display logic for the canvas wrapper: ensured that if the tabId is set to canvas, it also shows (and not just when undefined, for compat with components setting tabId)
  • Added mention of goal to remove tabs for SB 11, as per RFC: [RFC] Remove addon "tab" type #32273
  • Ported the actual toolbar section to use AbstractAriaToolbar (to avoid compat issues with the tabs section, can be made to use a real AriaToolbar in SB 11)
  • Added heading and DOM/ARIA markup for the toolbar to become a landmark

Settings page

  • Switched to new AriaTabs for kb nav
  • Simplified code a bit to limit Location context consumers

TO DO

Solve the overflow menu dilemma

With this PR, we lose the overflow menu that shows when scrollbars with a TabList have too little space. We're considering options:

  • sacrifice usability and unmake some of this PR's changes to preserve the overflow button temporarily

  • make the entire tablist become a vertical tablist on a menu button as soon as there's an overflow

  • permanently replace the tablist with a menu, and add a title for the current addon

  • accept the scrollbar and the loss of the overflow menu for now

  • @MichaelArestad to try out options in Figma and make a recommendation

  • Implementation of the recommended solution

Implement CSS changes

  • @MichaelArestad to review CSS states from the written stories and provide mockups
  • Implement provided mockups

Finalise naming and deprecation decisions

Please provide async comments on your preferences. Now that I know SB 10 is here, my recommendation is to entirely remove Tabs and to remove Aria prefixes from the new components' names.

  • We want to minimize breaking changes, so we want to keep existing names and deprecate rather than remove Tabs / Bar / FlexBar

  • Double check source code in Tabs and Bar to make sure what's deprecated is marked as such and to delete what we choose to remove in SB 10

  • Ensure deprecation / removal notices are well written

  • TabList: mention that the new AriaTabList does not support mixed link/tab content (tabs only)

Finish integration of new components

  • Use new AriaTabs in TabbedArgsTable (forgotten use case)

Doc changes

  • Write behaviour changes to MIGRATION.md
  • Add deprecation notices to MIGRATION.md

Fix E2E tests

  • Fix broken locators in Playwright E2E tests

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Run SB
  2. Check out the new keyboard behaviour on all affected components: now using Left+Right to navigate as expected

Documentation

N/A, only MIGRATION.md changes AFAIK

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

  • New Features

    • Added accessible AriaTabs and AriaToolbar components and a new component-testing Toolbar (status, navigation, rerun).
  • Improvements

    • Improved keyboard/ARIA support; panels and controls get configurable, consistent scrolling and layout tweaks.
  • Deprecations / Removals

    • Removed legacy Tabs, TabsState, FlexBar and related helpers; Bar API updated.
  • Documentation

    • Migration guide updated with API/component notes and a minor typo fix.
  • Chores

    • Added react-aria/react-stately and updated package metadata.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 files reviewed, 4 comments

Edit Code Review Bot Settings | Greptile

@nx-cloud
Copy link

nx-cloud bot commented Aug 13, 2025

View your CI Pipeline Execution ↗ for commit 85a2462

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 51s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-22 18:13:09 UTC

@storybook-app-bot
Copy link

storybook-app-bot bot commented Aug 13, 2025

Package Benchmarks

Commit: a83d1fb, ran on 22 September 2025 at 16:23:45 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-a11y

Before After Difference
Dependency count 2 2 0
Self size 507 KB 486 KB 🎉 -21 KB 🎉
Dependency size 2.80 MB 2.80 MB 0 B
Bundle Size Analyzer Link Link

@storybook/addon-onboarding

Before After Difference
Dependency count 0 0 0
Self size 368 KB 333 KB 🎉 -35 KB 🎉
Dependency size 667 B 667 B 0 B
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 43 44 🚨 +1 🚨
Self size 31.96 MB 35.35 MB 🚨 +3.39 MB 🚨
Dependency size 17.30 MB 17.33 MB 🚨 +29 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 529 528 🎉 -1 🎉
Self size 939 KB 939 KB 0 B
Dependency size 58.25 MB 58.22 MB 🎉 -32 KB 🎉
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 187 188 🚨 +1 🚨
Self size 886 KB 886 KB 🎉 -120 B 🎉
Dependency size 81.55 MB 84.97 MB 🚨 +3.42 MB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 169 170 🚨 +1 🚨
Self size 35 KB 35 KB 0 B
Dependency size 77.98 MB 81.40 MB 🚨 +3.42 MB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 44 45 🚨 +1 🚨
Self size 1.55 MB 1.55 MB 0 B
Dependency size 49.26 MB 52.68 MB 🚨 +3.42 MB 🚨
Bundle Size Analyzer node node

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch 3 times, most recently from fdb96ac to d85f513 Compare August 13, 2025 18:24
emptyState,
showToolsWhenEmpty,
}) => {
deprecate('The `Tabs` component is deprecated. Use `AriaTabs` instead.');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be revisited based on target removal date/version for Tabs and on final name for AriaTabs.

}

export const FlexBar = ({ children, backgroundColor, className, ...rest }: FlexBarProps) => {
deprecate('FlexBar is deprecated. Use Bar with justifyContent: "space-between" instead.');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: clarify date/version of removal.

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch 2 times, most recently from cb54314 to 1e92287 Compare August 21, 2025 09:21
@Sidnioulz Sidnioulz changed the title UI: Make preview Toolbar and core Bar implement the toolbar role [WIP] UI: Make preview Toolbar and core Bar implement the toolbar role Aug 29, 2025
@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch from 1e92287 to 62c4a8a Compare September 5, 2025 06:29
@ghengeveld
Copy link
Member

I added ci: do not merge because we want to wrap up our supercycle (2 weeks remaining) before merging this PR, due to it being potentially disruptive. The label may be removed after September 15.

@github-actions
Copy link
Contributor

github-actions bot commented Sep 5, 2025

Fails
🚫 PR is marked with "ci: do not merge" label.

Generated by 🚫 dangerJS against 3c5bba9

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch 2 times, most recently from 81ed808 to 61f9908 Compare September 5, 2025 09:30
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces legacy Tabs/TabBar/FlexBar UI with new ARIA-first components (AriaTabs, AriaTabList, AriaTabPanel, AriaToolbar), refactors multiple manager/addon/component-testing surfaces to use them, removes old tabs modules/stories, adds react-aria/react-stately and related runtime externals, and updates e2e tests to role-based selectors.

Changes

Cohort / File(s) Summary
New ARIA tabs components & stories
code/core/src/components/components/AriaTabs/*
Added AriaTabs, AriaTabList, AriaTabPanel, useAriaTabListState, TabProps, Container/FlexTabPanel and multiple stories; exposes new ARIA tab API and state hook.
New ARIA toolbar components & stories
code/core/src/components/components/AriaToolbar/*
Added AbstractAriaToolbar and AriaToolbar using @react-aria/toolbar plus stories.
Bar refactor & button removals
code/core/src/components/components/bar/bar.tsx, code/core/src/components/components/bar/button.tsx
Rewrote Bar as forwardRef with new BarProps (scrollable, innerStyle), deprecated FlexBar; removed button.tsx (TabButton/IconButton/ButtonOrLink) and associated exports.
Removed legacy Tabs implementation
code/core/src/components/components/tabs/*, code/core/src/components/index.ts
Deleted old Tabs, TabsState, helpers, hooks, stories; updated exports to remove old tab APIs and add ARIA components.
Addon panel → AriaTabs
code/core/src/manager/components/panel/Panel.tsx, code/core/src/components/components/addon-panel/addon-panel.tsx
Switched addon panels to AriaTabs, added per-panel TabErrorBoundary, added hasScrollbar prop, removed absolute prop.
Preview toolbar & manager refactor
code/core/src/manager/components/preview/Preview.tsx, .../Toolbar.tsx, .../utils/components.ts, .../globals/exports.ts
Manager/preview now build tab state via useAriaTabListState, pass tabState to toolbar, use AriaTabList/AbstractAriaToolbar; FrameWrap element changed to section; new internal exports added.
Settings UI → AriaTabs
code/core/src/manager/settings/index.tsx
Replaced TabBar/TabButton with AriaTabs, route-driven tab composition, tools integrated into tabs.
Component testing: Subnav → Toolbar
code/core/src/component-testing/components/*
Deleted Subnav, added Toolbar (new component and stories), updated InteractionsPanel and related stories to use Toolbar.
Addons adopt AriaTabs
code/addons/a11y/src/components/Tabs.tsx, code/addons/docs/.../TabbedArgsTable.tsx, code/addons/jest/src/components/Panel.tsx
Migrated addon tab UIs to AriaTabs/AriaTabPanel; reworked data flow, tools area, and badges; jest exports AssertionResult type.
Controls panel & SaveStory layout changes
code/core/src/controls/components/ControlsPanel.tsx, .../SaveStory.tsx, .../manager.tsx
Wrapped ArgsTable in ScrollArea, conditional save footer layout, moved modal out of Bar and used Bar.innerStyle; AddonPanel usage sets hasScrollbar={false}.
Dependencies & build updates
code/package.json, code/core/package.json, scripts/build/utils/entry-utils.ts
Added react-aria, react-stately, use-sync-external-store (and dev dep @react-aria/toolbar), included runtimeExternal for use-sync-external-store.
Migration docs & minor docs fixes
MIGRATION.md
Added API/component migration notes (Bar, FlexBar removal, Tabs removal and replacement with AriaTabs), adjusted ToC anchors, fixed a typo.
E2E tests & utilities updated
code/e2e-tests/*, code/e2e-tests/util.ts
Switched selectors to ARIA role-based locators (tab/tabpanel/toolbar), updated expectations (aria-selected), added SbPage.panelContent() helper and adjusted log assertions.
Wide metadata updates
.../package.json across many packages
Updated gitHead fields in many package.json files (metadata-only changes).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as AriaTabs (Tab Bar)
  participant State as useAriaTabListState
  participant Manager as Manager / Actions
  participant Panel as Panel Content (TabPanel)

  User->>UI: Click or keyboard-select tab
  UI->>State: onSelectionChange(key)
  State-->>UI: selectedKey
  UI->>Manager: onSelectionChange(key) (e.g., actions.onSelect)
  Manager->>Panel: render selected panel (wrapped in TabErrorBoundary)
  Panel-->>User: display active panel content
  Note right of UI: Keyboard navigation & ARIA semantics handled by react-aria/react-stately
Loading
sequenceDiagram
  autonumber
  actor User
  participant PreviewToolbar as Preview Toolbar (AriaTabList)
  participant TabState as useAriaTabListState
  participant Router as Manager (query params)
  participant Preview as Canvas / Tab Panels

  User->>PreviewToolbar: Select tab
  PreviewToolbar->>TabState: update selection
  TabState->>Router: update selected tabId (query param)
  Router->>Preview: compute visibility (canvas vs selected tab)
  Preview-->>User: show canvas or selected addon panel
  Note over Router,Preview: deprecation warning emitted when >1 addon tab
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

core

Suggested reviewers

  • ghengeveld
  • kylegach
  • jonniebigodes

Poem

I thump my paw on tabs anew,
ARIA hums and headers true.
Toolbars tidy, panels glide —
A rabbit hops from side to side.
Happy hops for accessible pride. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title is concise and accurately describes the PR's primary change: adding toolbar semantics to the preview Toolbar and the core Bar. The raw summary and PR objectives show the introduction of AriaToolbar/AbstractAriaToolbar and Bar updates to implement the toolbar role and ARIA labeling, so the title reflects the main purpose. It is specific, readable, and not generic.
Linked Issues Check ✅ Passed The changes directly address the linked issues: the PR adds AriaToolbar/AbstractAriaToolbar and the AriaTabs suite, integrates useToolbar/useTabList state, adds aria-labelledby headings and tabpanel landmarks, and updates consumers and tests to use aria-selected and role-based locators, which together satisfy the coding objectives in #25918 and #32235. These edits implement toolbar semantics, labeled sections/headings, aria-selected reporting, and ARIA keyboard behavior for tabs. The implementation does not literally wrap toolbar items in a ul/li in every place, but the useToolbar hook and labeled section/heading provide equivalent accessible semantics. Overall the primary coding requirements from both linked issues are met by the patch.
Out of Scope Changes Check ✅ Passed The bulk of edits are aligned with the ARIA/tabbar migration—Bar refactor, AriaTabs/AriaToolbar additions, manager/preview and AddonPanel updates, and corresponding test adjustments—so they are in-scope for the accessibility objectives. Incidental changes (many package.json gitHead bumps and added react-aria/react-stately and use-sync-external-store deps) appear required to support the new components and are not feature creep. The PR does remove several legacy public exports (Tabs, TabsState, TabButton, Subnav) which, while related to the migration, are broad public-surface changes and must be clearly documented as breaking. I recommend ensuring MIGRATION.md and release notes explicitly list these removed/renamed exports and consumption migration steps before merge.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/addons/jest/src/components/Panel.tsx (1)

285-291: Update Jest addon docs link

Replace the GitHub href in code/addons/jest/src/components/Panel.tsx (lines 285–291) with Storybook’s current Jest addon docs URL: https://storybook.js.org/addons/%40junk-temporary-prototypes/addon-jest

♻️ Duplicate comments (9)
code/addons/themes/package.json (1)

75-75: gitHead metadata update looks fine.

No functional changes here; see preact-vite comment for the repo-wide consistency check.

code/builders/builder-vite/package.json (1)

73-73: gitHead updated — no runtime impact.

Nothing else changed; refer to the first comment for the validation script.

code/addons/docs/package.json (1)

121-121: gitHead change acknowledged.

Metadata-only; align with repo-wide check from the first comment.

code/renderers/web-components/package.json (1)

74-74: gitHead bump LGTM.

No additional concerns; see earlier note for consistency verification.

code/addons/links/package.json (1)

74-74: gitHead update only.

Looks good; rely on the shared script to confirm SHA alignment.

code/addons/a11y/package.json (1)

82-82: gitHead updated; OK to proceed.

No behavior change; cross-check with the repo-wide validation script.

code/builders/builder-webpack5/package.json (1)

92-92: gitHead metadata change confirmed.

All good; refer to the initial comment for the consistency check.

code/core/src/components/components/AriaTabs/AriaTabList.stories.tsx (1)

32-44: Stories structure LGTM; parameters-based data resolves earlier TS issue.

code/core/src/manager/components/preview/Toolbar.tsx (1)

112-114: Heading level in toolbar label

Using an h2 may disrupt heading hierarchy; confirm this level is appropriate or consider aria-label without an actual heading.

🧹 Nitpick comments (54)
code/e2e-tests/component-tests.spec.ts (2)

34-36: Role-based locator switch LGTM; consider scoping to reduce ambiguity.

Using getByRole aligns with the new ARIA Tabs. To avoid potential duplicate-name collisions, scope the locator to the addon panel tablist if available.

Example:

const interactionsTab = page.getByRole('tablist', { name: /Addon Panel/i }).getByRole('tab', { name: 'Interactions' });

67-69: Consistent locator; refresh adjacent skip text and typo.

  • Keep this role-based locator.
  • Line 22 skip reason still mentions “className locators” — update to reflect role-based locators or remove if obsolete.
  • Line 55: fix “FIreFox” → “Firefox”.
scripts/build/utils/entry-utils.ts (1)

58-61: Also externalize the shim entry for use-sync-external-store.
If any packages import use-sync-external-store/shim (common for React < 18), it won’t be externalized by listing only the base package. Add the shim path to avoid bundling it accidentally.

Apply this diff:

   const runtimeExternalInclude: string[] = [
     'react',
-    'use-sync-external-store',
+    'use-sync-external-store',
+    'use-sync-external-store/shim',
     'react-dom',
     'react-dom/client',
     '@storybook/icons',
code/e2e-tests/preview-api.spec.ts (1)

30-31: Prefer asserting selection state over visibility for tabs

Since tabs now follow ARIA patterns, assert aria-selected to reduce flake after click.

-    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });
-    await expect(interactionsTab).toBeVisible();
+    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });
+    await expect(interactionsTab).toHaveAttribute('aria-selected', 'true');
code/e2e-tests/addon-a11y.spec.ts (1)

69-72: Align check with ARIA semantics — good; consider updating remaining tab checks

Using aria-selected is the right assertion for tabs. For consistency, consider changing the later tab assertion (Line 78-79) to aria-selected as well to avoid relying on data-state.

-    const element = page.getByRole('tab', { name: '1. <body' });
-    await expect(element).toHaveAttribute('data-state', 'active');
+    const element = page.getByRole('tab', { name: '1. <body' });
+    await expect(element).toHaveAttribute('aria-selected', 'true');
code/e2e-tests/addon-actions.spec.ts (2)

31-33: Make the text assertion slightly more robust.
Allow optional colon to reduce brittle coupling to punctuation.

-const logItem = sbPage.panelContent().locator('span', {
-  hasText: 'onClick:',
-});
+const logItem = sbPage.panelContent().locator('span', {
+  hasText: /onClick:?/,
+});

55-57: Same here: loosen the match a bit.

-const logItem = sbPage.panelContent().locator('span', {
-  hasText: 'console.log:',
-});
+const logItem = sbPage.panelContent().locator('span', {
+  hasText: /console\.log:?/,
+});
code/e2e-tests/module-mocking.spec.ts (2)

45-49: Prefer Locator.nth() over CSS nth syntax

Use the Playwright API directly; it's clearer and less error‑prone.

-      actualTexts.push(await panel.locator(`li >> nth=${i}`).innerText());
+      actualTexts.push(await panel.locator('li').nth(i).innerText());

53-54: Remove noisy console logging (or guard behind a flag)

Unnecessary logs slow CI and clutter output.

-    console.log(actualTexts);
+    if (process.env.DEBUG_E2E) console.log(actualTexts);
code/e2e-tests/manager.spec.ts (1)

42-51: Rename helper: it checks “hidden”, not “non‑existence”

Name should reflect behavior to avoid confusion in future edits.

-      const expectToolbarToNotExist = async () => {
+      const expectToolbarToBeHidden = async () => {
         const toolbar = page.getByTestId('sb-preview-toolbar').getByRole('toolbar');
         await expect(toolbar).toBeHidden();
-      };
+      };

Also update call sites:

-      await expectToolbarToNotExist();
+      await expectToolbarToBeHidden();
code/addons/jest/src/components/Panel.tsx (2)

139-154: Remove unnecessary optional chaining

tests is already an array; optional chaining hides real bugs.

-    {tests.length ? (
-      tests?.map((res: AssertionResult) => (
+    {tests.length ? (
+      tests.map((res: AssertionResult) => (

244-248: Optional: Select first non‑empty tab by default

Better UX: open the most relevant tab if “Failing” is empty.

-      <AriaTabs
-        defaultSelected="failing-tests"
+      {/*
+        Prefer the first non-empty category; fall back to "todo-tests"
+      */}
+      <AriaTabs
+        defaultSelected={
+          (testsByType.get(StatusTypes.FAILED_TYPE)?.length ?? 0) > 0 ? 'failing-tests' :
+          (testsByType.get(StatusTypes.PASSED_TYPE)?.length ?? 0) > 0 ? 'passing-tests' :
+          (testsByType.get(StatusTypes.PENDING_TYPE)?.length ?? 0) > 0 ? 'pending-tests' :
+          'todo-tests'
+        }
         backgroundColor={convert(themes.light).background.hoverable}
         tabs={tabs}
       />
code/core/src/components/components/bar/bar.tsx (2)

122-134: Avoid "undefined" in className

Guard concatenation when className is falsy.

-    <Bar backgroundColor={backgroundColor} className={`sb-bar ${className}`} {...rest}>
+    <Bar
+      backgroundColor={backgroundColor}
+      className={['sb-bar', className].filter(Boolean).join(' ')}
+      {...rest}
+    >

117-120: Drop duplicated props in FlexBarProps

border/backgroundColor are already in BarProps. Keep a single source of truth.

-export interface FlexBarProps extends BarProps {
-  border?: boolean;
-  backgroundColor?: string;
-}
+export interface FlexBarProps extends BarProps {}
code/core/src/controls/components/SaveStory.tsx (2)

44-48: Move responsive layout rules to Bar.innerStyle

With the new Bar, layout is driven by innerStyle on the inner wrapper; these @container rules on the outer wrapper won’t affect child ordering.

-  '@container (max-width: 799px)': {
-    flexDirection: 'row',
-    justifyContent: 'flex-end',
-  },

149-155: Apply responsive rules via innerStyle (effective target)

Ensure small‑viewport overrides hit the HeightPreserver wrapper.

-      <Bar
-        innerStyle={{
-          flexDirection: 'row-reverse',
-          justifyContent: 'space-between',
-          flexWrap: 'wrap',
-        }}
-      >
+      <Bar
+        innerStyle={{
+          flexDirection: 'row-reverse',
+          justifyContent: 'space-between',
+          flexWrap: 'wrap',
+          '@container (max-width: 799px)': {
+            flexDirection: 'row',
+            justifyContent: 'flex-end',
+          },
+        }}
+      >
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)

8-13: Broaden props to accept standard DOM attributes (id, data-*, etc.).

Expose div attributes on the public API to avoid type friction and enable test hooks.

-export interface AbstractAriaToolbarProps {
-  className?: string;
-  children?: React.ReactNode;
-  'aria-label'?: string;
-  'aria-labelledby'?: string;
-}
+export interface AbstractAriaToolbarProps extends React.ComponentPropsWithoutRef<'div'> {
+  'aria-label'?: string;
+  'aria-labelledby'?: string;
+}
code/addons/docs/src/blocks/components/Toolbar.tsx (1)

55-64: Add button aria-labels and avoid unnecessary preventDefault().

Icons alone aren’t accessible; use explicit labels. preventDefault on a button click is redundant here.

-        <IconButton
-          key="zoomin"
-          onClick={(e: SyntheticEvent) => {
-            e.preventDefault();
-            zoom(0.8);
-          }}
-          title="Zoom in"
-        >
+        <IconButton
+          key="zoomin"
+          aria-label="Zoom in"
+          onClick={() => zoom(0.8)}
+          title="Zoom in"
+        >
           <ZoomIcon />
         </IconButton>
@@
-        <IconButton
-          key="zoomout"
-          onClick={(e: SyntheticEvent) => {
-            e.preventDefault();
-            zoom(1.25);
-          }}
-          title="Zoom out"
-        >
+        <IconButton
+          key="zoomout"
+          aria-label="Zoom out"
+          onClick={() => zoom(1.25)}
+          title="Zoom out"
+        >
           <ZoomOutIcon />
         </IconButton>
@@
-        <IconButton
-          key="zoomreset"
-          onClick={(e: SyntheticEvent) => {
-            e.preventDefault();
-            resetZoom();
-          }}
-          title="Reset zoom"
-        >
+        <IconButton
+          key="zoomreset"
+          aria-label="Reset zoom"
+          onClick={() => resetZoom()}
+          title="Reset zoom"
+        >
           <ZoomResetIcon />
         </IconButton>

Also applies to: 65-74, 75-84

code/core/src/components/components/AriaToolbar/AbstractAriaToolbar.stories.tsx (1)

19-25: Provide an accessible name in the story.

Demonstrate best practice by labeling the toolbar.

   args: {
     children: <Children />,
+    'aria-label': 'Example toolbar',
   },
code/core/src/component-testing/components/Toolbar.stories.tsx (1)

28-31: Optional: make “Scroll to end” interactive in stories.

Provide onScrollToEnd so the button isn’t disabled in examples.

   args: {
@@
     storyFileName: 'Toolbar.stories.tsx',
+    onScrollToEnd: action('scrollToEnd'),
     hasNext: true,
     hasPrevious: true,
   },
code/core/src/components/components/addon-panel/addon-panel.tsx (1)

8-17: Nit: type the refs for clarity.

useRef<any>() (or a generic) improves readability over implicit any.

-const usePrevious = (value: any) => {
-  const ref = useRef();
+const usePrevious = <T,>(value: T) => {
+  const ref = useRef<T | undefined>(undefined);
@@
-const useUpdate = (update: boolean, value: any) => {
-  const previousValue = usePrevious(value);
+const useUpdate = <T,>(update: boolean, value: T) => {
+  const previousValue = usePrevious<T>(value);
code/core/src/component-testing/components/Interaction.stories.tsx (2)

8-8: Decouple from another story’s meta; use shared fixtures instead.

Importing args from Toolbar.stories creates cross‑story coupling and brittle dependencies. Prefer a small fixtures module.

Apply this diff:

-import ToolbarStories from './Toolbar.stories';
+import { controlsFixture, controlStatesFixture } from './Toolbar.fixtures';
-    controls: ToolbarStories.args.controls,
-    controlStates: ToolbarStories.args.controlStates,
+    controls: controlsFixture,
+    controlStates: controlStatesFixture,

And add a tiny fixture (new file) to support both stories:

// code/core/src/component-testing/components/Toolbar.fixtures.ts
import type { Controls } from './InteractionsPanel';

export const controlsFixture: Controls = {
  start: () => {},
  back: () => {},
  goto: () => {},
  next: () => {},
  end: () => {},
  rerun: () => {},
};

export const controlStatesFixture = {
  start: true,
  back: true,
  goto: true,
  next: true,
  end: true,
  detached: false,
};

Also applies to: 17-19


65-65: goto has no visible effect in Toolbar; disable a control the Toolbar actually renders.

The new Toolbar doesn’t expose a “goto” button, so goto: false won’t show a disabled UI. Use end/next/back instead.

Apply this diff:

-  args: { ...Done.args, controlStates: { ...ToolbarStories.args.controlStates, goto: false } },
+  args: { ...Done.args, controlStates: { ...controlStatesFixture, end: false } },
MIGRATION.md (3)

591-593: Duplicate paragraph and spelling error ("superceded").

The "Removed x-only builtin tags" paragraph is duplicated and one instance misspells "superseded" as "superceded". Please dedupe and fix the spelling.

Apply this diff:

- During development of Storybook [Tags](https://storybook.js.org/docs/writing-stories/tags), we created `dev-only`, `docs-only`, and `test-only` built-in tags. These tags were never documented and superceded by the currently-documented `dev`, `autodocs`, and `test` tags which provide more precise control. The outdated `x-only` tags are removed in 10.0.
+ During development of Storybook [Tags](https://storybook.js.org/docs/writing-stories/tags), we created `dev-only`, `docs-only`, and `test-only` built-in tags. These tags were never documented and superseded by the currently-documented `dev`, `autodocs`, and `test` tags which provide more precise control. The outdated `x-only` tags are removed in 10.0.

609-611: Replace checkbox/TODO with a definitive statement and fix list style (MD004).

Use a dash list and remove the question mark.

Apply this diff:

-* [ ] Tabs no longer accepts link components?
+- Tabs no longer accepts link components.

11-15: Fix duplicated TOC anchors for "API and Component Changes"

MIGRATION.md has two identical headings (lines 594 and 899) producing anchors #api-and-component-changes and #api-and-component-changes-1; TOC entries at lines 11 and 34 point to them. Rename one heading or update the TOC links (e.g., add a version suffix) so each anchor uniquely targets its intended section.

code/core/src/manager/components/preview/Preview.tsx (2)

66-77: Eagerly invoking tab render functions may be costly. Consider lazy panel rendering.

children: () => tab.render({ active: true }) is executed during state construction (see useAriaTabListState), which can mount heavy content for all tabs. Prefer deferring panel rendering to the TabPanel layer and render only the selected tab.

One approach: pass a lightweight placeholder in children and move the actual tab.render invocation into the TabPanel renderer conditioned on selection. If that’s not feasible now, document the trade‑off and gate behind a feature flag for large addons.


79-81: Deprecation message: include removal version and actionable guidance.

Message is good; consider adding a short pointer (e.g., “Use tool-type addons or AriaTabs-based panels”) to help users migrate.

code/core/src/components/components/AriaTabs/AriaTabList.stories.tsx (2)

15-18: Don’t pass unknown tabs prop to AriaTabList.

It ends up as a non-standard DOM attribute on the container. Drop it from args.

Apply:

-  args: {
-    tabs: DEFAULT_TABS,
-    state: undefined,
-  },
+  args: {},

25-29: Strip tabs from forwarded story args.

Avoid leaking it to the component.

-    (Story, { args, parameters }) => {
-      const state = useAriaTabListState({ tabs: parameters.data.tabs });
-      return <Story args={{ ...args, state }} />;
-    },
+    (Story, { args, parameters }) => {
+      const { tabs: _tabs, ...rest } = args as any;
+      const state = useAriaTabListState({ tabs: parameters.data.tabs });
+      return <Story args={{ ...rest, state }} />;
+    },
code/core/src/manager/settings/index.tsx (4)

21-29: Remove unused Header.

Dead code; safe to delete.

-const Header = styled.div(({ theme }) => ({
-  display: 'flex',
-  justifyContent: 'space-between',
-  alignItems: 'center',
-  height: 40,
-  boxShadow: `${theme.appBorderColor}  0 -1px 0 0 inset`,
-  background: theme.barBg,
-  paddingRight: 8,
-}));

43-49: Drop unused enableWhatsNew prop wiring.

The tab is always present now; remove prop and its usage.

-const Pages: FC<{
-  onClose: () => void;
-  enableShortcuts?: boolean;
-  changeTab: (tab: string) => void;
-  enableWhatsNew: boolean;
-}> = ({ changeTab, onClose, enableShortcuts = true, enableWhatsNew }) => {
+const Pages: FC<{
+  onClose: () => void;
+  enableShortcuts?: boolean;
+  changeTab: (tab: string) => void;
+}> = ({ changeTab, onClose, enableShortcuts = true }) => {
   return (
     <Pages
-      enableWhatsNew={state.whatsNewData?.status === 'SUCCESS'}
       enableShortcuts={state.ui.enableShortcuts}
       changeTab={changeTab}
       onClose={api.closeSettings}
     />
   );

Also applies to: 128-134


96-116: Provide a deterministic default selection.

Avoid controlled/uncontrolled ambiguity when the URL is /settings/.

-        const selected = tabs.find((tab) => path.includes(`settings/${tab.id}`))?.id;
+        const selected = tabs.find((tab) => path.includes(`settings/${tab.id}`))?.id ?? 'about';

105-111: preventDefault() is unnecessary on a button.

Can be removed.

-                onClick={(e: SyntheticEvent) => {
-                  e.preventDefault();
-                  return onClose();
-                }}
+                onClick={() => onClose()}
code/core/src/component-testing/components/Toolbar.tsx (1)

165-169: Hook up the rerun spin animation to status.

Tiny UX improvement; no behavior change.

-            <RerunButton aria-label="Rerun" onClick={controls.rerun}>
+            <RerunButton
+              aria-label="Rerun"
+              onClick={controls.rerun}
+              animating={status === 'playing' || status === 'rendering'}
+            >
code/core/src/components/components/AriaTabs/AriaTabList.tsx (3)

8-11: Unify AriaTabListProps into a single declaration.

Duplicate interface declarations are confusing; prefer one extends HTMLAttributes<HTMLDivElement>.

-export interface AriaTabListProps {
-  state: TabListState<object>;
-}
+export interface AriaTabListProps extends HTMLAttributes<HTMLDivElement> {
+  state: TabListState<object>;
+}
 
-export interface AriaTabListProps extends HTMLAttributes<HTMLDivElement> {
-  state: TabListState<object>;
-}
+// (second declaration removed)

Also applies to: 96-98


90-93: Type the tab ref to the actual element.

Minor typing hygiene.

-  const tabRef = React.useRef(null);
+  const tabRef = React.useRef<HTMLButtonElement>(null);

53-66: Add a disabled visual state.

Improve affordance when tabs are disabled.

   ({ isSelected, textColor, theme }) =>
     isSelected
       ? {
         color: textColor || theme.barSelectedColor,
         borderBottomColor: theme.barSelectedColor,
       }
       : {
         color: textColor || theme.barTextColor,
         borderBottomColor: 'transparent',
         '&:hover': {
           color: theme.barHoverColor,
         },
       }
+  ,
+  ({ isDisabled }) =>
+    isDisabled
+      ? {
+          opacity: 0.5,
+          cursor: 'not-allowed',
+          pointerEvents: 'none',
+        }
+      : {}
code/core/src/components/components/AriaToolbar/AriaToolbar.stories.tsx (2)

24-27: Add an accessible name to the toolbar in stories

Demonstrate best practice by labeling the toolbar so ATs announce it.

Apply this diff:

 const meta = preview.meta({
   title: 'AriaToolbar',
   component: AriaToolbar,
   args: {
+    'aria-label': 'Example toolbar',
     children: <Children />,
   },
 });

35-36: Remove redundant JSX braces in render

Minor cleanup; no behavior change.

-  render: (args) => <div style={{ width: 400 }}>{<AriaToolbar {...args} />}</div>,
+  render: (args) => <div style={{ width: 400 }}><AriaToolbar {...args} /></div>,

Also applies to: 42-43

code/addons/a11y/src/components/Tabs.tsx (1)

92-96: Ensure toggle button announces pressed state

If IconButton’s active does not map to aria-pressed, add it explicitly.

Apply this diff if needed:

-              <ToggleButton onClick={toggleHighlight} active={highlighted}>
+              <ToggleButton onClick={toggleHighlight} active={highlighted} aria-pressed={highlighted}>

Please confirm whether IconButton sets aria-pressed when active is true. If it already does, skip this change.

code/core/src/components/components/AriaTabs/AriaTabPanel.stories.tsx (1)

104-113: Reduce DOM-coupling in assertions

The .parentNode?.parentNode?... chain is brittle. Prefer closest('[hidden]') or querying the panel container directly.

code/core/src/components/components/AriaTabs/AriaTabPanel.tsx (2)

38-40: Type the ref target

Tiny improvement to aid editor tooling and prevent accidental misuse.

-  const ref = useRef(null);
+  const ref = useRef<HTMLDivElement>(null);

27-30: Verify overflow behavior when hasScrollbar is false

With overflowY: 'hidden' on Panel, disabling the internal ScrollArea might clip content. Confirm the “WithoutScrollbar” story scrolls as intended via an ancestor container; if not, set Panel’s overflowY to 'auto' when hasScrollbar is false.

Also applies to: 56-61

code/core/src/manager/components/preview/Toolbar.tsx (2)

105-127: Don’t render an empty toolbar

Arrays are truthy; current check always renders when isShown is true. Gate on lengths.

-  return isShown && (tabs || tools || toolsExtra) ? (
+  return isShown && (tabs.length > 0 || tools.length > 0 || toolsExtra.length > 0) ? (

195-204: Optional: Group tool clusters for semantics

Consider role="group" with aria-label on each ToolGroup to help AT users understand left vs. right clusters.

Also applies to: 131-137

code/core/src/components/components/AriaTabs/AriaTabs.stories.tsx (1)

74-97: Controlled story doesn’t resync when args.selected changes.

If the Controls panel updates selected, local state won’t follow. Sync it to avoid desync.

- import { useState } from 'react';
+ import { useEffect, useState } from 'react';
@@
   render: (args) => {
     const [selected, setSelected] = useState(args.selected);
+    useEffect(() => {
+      setSelected(args.selected);
+    }, [args.selected]);
     return (

Also applies to: 1-1

code/core/src/manager/components/panel/Panel.tsx (4)

96-99: Add rel="noopener noreferrer" to external link opened in a new tab.

Prevents opener hijacking and improves perf.

-        <Link href={'https://storybook.js.org/addons?ref=ui'} target="_blank" withArrow>
+        <Link
+          href={'https://storybook.js.org/addons?ref=ui'}
+          target="_blank"
+          rel="noopener noreferrer"
+          withArrow
+        >

103-128: IconButtons rely on title only; add aria-labels for consistent SR names.

Title isn’t reliably announced across AT. Mirror the title in aria-label.

-          <IconButton
+          <IconButton
             key="position"
             onClick={actions.togglePosition}
             title={`Change addon orientation [${shortcutToHumanString(shortcuts.panelPosition)}]`}
+            aria-label="Change addon orientation"
           >
@@
-          <IconButton
+          <IconButton
             key="visibility"
             onClick={actions.toggleVisibility}
             title={`Hide addons [${shortcutToHumanString(shortcuts.togglePanel)}]`}
+            aria-label="Hide addons"
           >

15-19: Remove unused SafeTabProps.

Dead type; not referenced after the refactor.

-export interface SafeTabProps {
-  title: Addon_BaseType['title'];
-  id: string;
-  children: Addon_BaseType['render'];
-}

69-70: Drop obsolete absolute prop from the public type.

It’s unused; leaving it can confuse integrators.

   panelPosition?: 'bottom' | 'right';
-  absolute?: boolean;
code/core/src/components/components/AriaTabs/AriaTabs.tsx (3)

10-16: Type nit: title already covered by ReactNode; string is redundant.

Simplify the union.

-export interface TabProps {
+export interface TabProps {
   id: string;
   'aria-label'?: string;
-  title: FC | ReactNode | string;
+  title: FC | ReactNode;
   children?: FC | ReactNode;
   isDisabled?: boolean;
 }

110-113: Empty-state early return drops wrapper props (id/className) and layout. Wrap it.

Returning the node directly can break callers relying on Container’s semantics.

-  if (!showToolsWhenEmpty && tabs.length === 0) {
-    return EmptyContent;
-  }
+  if (!showToolsWhenEmpty && tabs.length === 0) {
+    return <Container {...props}>{EmptyContent}</Container>;
+  }

93-105: Heads-up: panelProps.id cannot override the tabpanel id.

AriaTabPanel spreads tabPanelProps after rest, so react-aria’s id wins by design. Document this or reject id in panelProps to avoid surprises.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3b728d and ee627a6.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (87)
  • MIGRATION.md (5 hunks)
  • code/addons/a11y/package.json (1 hunks)
  • code/addons/a11y/src/components/Tabs.tsx (3 hunks)
  • code/addons/docs/package.json (1 hunks)
  • code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.tsx (2 hunks)
  • code/addons/docs/src/blocks/components/Toolbar.tsx (3 hunks)
  • code/addons/jest/package.json (1 hunks)
  • code/addons/jest/src/components/Panel.tsx (7 hunks)
  • code/addons/jest/src/hoc/provideJestResult.tsx (1 hunks)
  • code/addons/links/package.json (1 hunks)
  • code/addons/themes/package.json (1 hunks)
  • code/builders/builder-vite/package.json (1 hunks)
  • code/builders/builder-webpack5/package.json (1 hunks)
  • code/core/package.json (3 hunks)
  • code/core/src/component-testing/components/Interaction.stories.tsx (3 hunks)
  • code/core/src/component-testing/components/InteractionsPanel.stories.tsx (2 hunks)
  • code/core/src/component-testing/components/InteractionsPanel.tsx (2 hunks)
  • code/core/src/component-testing/components/Subnav.tsx (0 hunks)
  • code/core/src/component-testing/components/Toolbar.stories.tsx (2 hunks)
  • code/core/src/component-testing/components/Toolbar.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabList.stories.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabList.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabPanel.stories.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabPanel.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabs.stories.tsx (1 hunks)
  • code/core/src/components/components/AriaTabs/AriaTabs.tsx (1 hunks)
  • code/core/src/components/components/AriaToolbar/AbstractAriaToolbar.stories.tsx (1 hunks)
  • code/core/src/components/components/AriaToolbar/AriaToolbar.stories.tsx (1 hunks)
  • code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1 hunks)
  • code/core/src/components/components/addon-panel/addon-panel.tsx (2 hunks)
  • code/core/src/components/components/bar/bar.tsx (2 hunks)
  • code/core/src/components/components/bar/button.tsx (0 hunks)
  • code/core/src/components/components/tabs/tabs.helpers.tsx (0 hunks)
  • code/core/src/components/components/tabs/tabs.hooks.tsx (0 hunks)
  • code/core/src/components/components/tabs/tabs.stories.tsx (0 hunks)
  • code/core/src/components/components/tabs/tabs.tsx (0 hunks)
  • code/core/src/components/index.ts (1 hunks)
  • code/core/src/controls/components/ControlsPanel.tsx (3 hunks)
  • code/core/src/controls/components/SaveStory.tsx (3 hunks)
  • code/core/src/controls/manager.tsx (1 hunks)
  • code/core/src/manager/components/panel/Panel.tsx (2 hunks)
  • code/core/src/manager/components/preview/Preview.tsx (3 hunks)
  • code/core/src/manager/components/preview/Toolbar.tsx (3 hunks)
  • code/core/src/manager/components/preview/utils/components.ts (1 hunks)
  • code/core/src/manager/globals/exports.ts (1 hunks)
  • code/core/src/manager/settings/index.tsx (3 hunks)
  • code/e2e-tests/addon-a11y.spec.ts (1 hunks)
  • code/e2e-tests/addon-actions.spec.ts (2 hunks)
  • code/e2e-tests/component-tests.spec.ts (2 hunks)
  • code/e2e-tests/manager.spec.ts (2 hunks)
  • code/e2e-tests/module-mocking.spec.ts (4 hunks)
  • code/e2e-tests/preview-api.spec.ts (1 hunks)
  • code/e2e-tests/util.ts (1 hunks)
  • code/frameworks/angular/package.json (1 hunks)
  • code/frameworks/ember/package.json (1 hunks)
  • code/frameworks/html-vite/package.json (1 hunks)
  • code/frameworks/nextjs-vite/package.json (1 hunks)
  • code/frameworks/nextjs/package.json (1 hunks)
  • code/frameworks/preact-vite/package.json (1 hunks)
  • code/frameworks/react-native-web-vite/package.json (1 hunks)
  • code/frameworks/react-vite/package.json (1 hunks)
  • code/frameworks/react-webpack5/package.json (1 hunks)
  • code/frameworks/server-webpack5/package.json (1 hunks)
  • code/frameworks/svelte-vite/package.json (1 hunks)
  • code/frameworks/sveltekit/package.json (1 hunks)
  • code/frameworks/vue3-vite/package.json (1 hunks)
  • code/frameworks/web-components-vite/package.json (1 hunks)
  • code/lib/cli-sb/package.json (1 hunks)
  • code/lib/cli-storybook/package.json (1 hunks)
  • code/lib/codemod/package.json (1 hunks)
  • code/lib/core-webpack/package.json (1 hunks)
  • code/lib/create-storybook/package.json (1 hunks)
  • code/lib/csf-plugin/package.json (1 hunks)
  • code/lib/eslint-plugin/package.json (1 hunks)
  • code/lib/react-dom-shim/package.json (1 hunks)
  • code/package.json (1 hunks)
  • code/presets/create-react-app/package.json (1 hunks)
  • code/presets/react-webpack/package.json (1 hunks)
  • code/presets/server-webpack/package.json (1 hunks)
  • code/renderers/html/package.json (1 hunks)
  • code/renderers/preact/package.json (1 hunks)
  • code/renderers/react/package.json (1 hunks)
  • code/renderers/server/package.json (1 hunks)
  • code/renderers/svelte/package.json (1 hunks)
  • code/renderers/vue3/package.json (1 hunks)
  • code/renderers/web-components/package.json (1 hunks)
  • scripts/build/utils/entry-utils.ts (2 hunks)
💤 Files with no reviewable changes (6)
  • code/core/src/components/components/tabs/tabs.helpers.tsx
  • code/core/src/components/components/tabs/tabs.hooks.tsx
  • code/core/src/components/components/bar/button.tsx
  • code/core/src/component-testing/components/Subnav.tsx
  • code/core/src/components/components/tabs/tabs.stories.tsx
  • code/core/src/components/components/tabs/tabs.tsx
🧰 Additional context used
📓 Path-based instructions (1)
code/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Files:

  • code/e2e-tests/preview-api.spec.ts
  • code/e2e-tests/addon-actions.spec.ts
  • code/e2e-tests/addon-a11y.spec.ts
  • code/e2e-tests/manager.spec.ts
  • code/e2e-tests/module-mocking.spec.ts
  • code/e2e-tests/component-tests.spec.ts
🧠 Learnings (1)
📚 Learning: 2025-09-17T08:11:47.184Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.184Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors

Applied to files:

  • code/e2e-tests/module-mocking.spec.ts
  • code/core/src/components/components/AriaTabs/AriaTabPanel.stories.tsx
🧬 Code graph analysis (25)
code/core/src/components/components/AriaToolbar/AbstractAriaToolbar.stories.tsx (3)
code/core/src/components/index.ts (2)
  • Button (53-53)
  • AbstractAriaToolbar (75-75)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)
  • AbstractAriaToolbar (15-32)
code/core/src/components/components/AriaToolbar/AriaToolbar.stories.tsx (1)
  • Basic (29-29)
code/core/src/component-testing/components/Toolbar.stories.tsx (1)
code/core/src/component-testing/components/Toolbar.tsx (1)
  • Toolbar (99-175)
code/e2e-tests/addon-a11y.spec.ts (2)
code/core/src/test/expect.ts (1)
  • expect (148-148)
code/e2e-tests/util.ts (1)
  • SbPage (8-203)
code/core/src/components/components/addon-panel/addon-panel.tsx (2)
code/core/src/components/index.ts (2)
  • Div (10-10)
  • ScrollArea (47-47)
code/core/src/manager/components/panel/Panel.tsx (1)
  • AddonPanel (63-151)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (3)
code/core/src/components/components/AriaTabs/AriaTabPanel.tsx (1)
  • AriaTabPanel (32-64)
code/core/src/components/components/bar/bar.tsx (1)
  • Bar (50-68)
code/core/src/components/components/AriaTabs/AriaTabList.tsx (1)
  • AriaTabList (100-111)
code/core/src/controls/components/ControlsPanel.tsx (3)
code/core/src/components/index.ts (1)
  • ScrollArea (47-47)
code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx (1)
  • ArgsTable (318-474)
code/core/src/controls/components/SaveStory.tsx (1)
  • SaveStory (96-232)
code/addons/a11y/src/components/Tabs.tsx (2)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (2)
  • Container (44-48)
  • AriaTabs (93-140)
code/core/src/components/index.ts (4)
  • AriaTabs (74-74)
  • WithTooltip (58-58)
  • TooltipNote (60-60)
  • IconButton (54-54)
code/core/src/components/components/AriaToolbar/AriaToolbar.stories.tsx (2)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)
  • AriaToolbar (36-53)
code/core/src/components/components/AriaToolbar/AbstractAriaToolbar.stories.tsx (1)
  • Basic (27-27)
code/core/src/controls/manager.tsx (2)
code/core/src/manager/components/panel/Panel.tsx (1)
  • AddonPanel (63-151)
code/core/src/components/components/addon-panel/addon-panel.tsx (1)
  • AddonPanel (35-46)
code/core/src/component-testing/components/Toolbar.tsx (6)
code/core/src/component-testing/components/InteractionsPanel.tsx (1)
  • Controls (16-23)
code/core/src/instrumenter/types.ts (1)
  • ControlStates (51-58)
code/core/src/component-testing/components/StatusBadge.tsx (2)
  • PlayStatus (5-5)
  • StatusBadge (45-52)
code/core/src/components/index.ts (7)
  • Button (53-53)
  • TooltipNote (60-60)
  • IconButton (54-54)
  • P (22-22)
  • AriaToolbar (75-75)
  • Separator (69-69)
  • WithTooltip (58-58)
code/core/src/component-testing/components/Interaction.tsx (1)
  • StyledIconButton (102-105)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)
  • AriaToolbar (36-53)
code/core/src/component-testing/components/InteractionsPanel.tsx (1)
code/core/src/component-testing/components/Toolbar.tsx (1)
  • Toolbar (99-175)
code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.tsx (1)
code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx (1)
  • ArgsTable (318-474)
code/core/src/components/components/AriaTabs/AriaTabPanel.tsx (1)
code/core/src/components/index.ts (2)
  • AriaTabPanel (73-73)
  • ScrollArea (47-47)
code/core/src/components/components/AriaTabs/AriaTabList.stories.tsx (2)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (2)
  • TabProps (10-16)
  • useAriaTabListState (25-42)
code/core/src/components/components/AriaTabs/AriaTabList.tsx (1)
  • AriaTabList (100-111)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (2)
code/core/src/components/index.ts (4)
  • AbstractAriaToolbar (75-75)
  • BarProps (70-70)
  • AriaToolbar (75-75)
  • Bar (70-70)
code/core/src/components/components/bar/bar.tsx (2)
  • BarProps (7-14)
  • Bar (50-68)
code/core/src/components/components/AriaTabs/AriaTabList.tsx (1)
code/core/src/components/index.ts (1)
  • AriaTabList (72-72)
code/addons/docs/src/blocks/components/Toolbar.tsx (2)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)
  • AriaToolbar (36-53)
code/core/src/component-testing/components/Toolbar.tsx (1)
  • Toolbar (99-175)
code/core/src/components/components/AriaTabs/AriaTabs.stories.tsx (1)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (1)
  • AriaTabs (93-140)
code/core/src/controls/components/SaveStory.tsx (1)
code/core/src/components/components/Modal/Modal.tsx (1)
  • Modal (58-58)
code/core/src/manager/components/panel/Panel.tsx (3)
code/core/src/components/components/addon-panel/addon-panel.tsx (1)
  • AddonPanel (35-46)
code/core/src/manager/components/layout/LayoutProvider.tsx (1)
  • useLayout (61-61)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (1)
  • AriaTabs (93-140)
code/core/src/manager/components/preview/Toolbar.tsx (2)
code/core/src/components/components/AriaTabs/AriaTabList.tsx (1)
  • AriaTabList (100-111)
code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)
  • AbstractAriaToolbar (15-32)
code/addons/jest/src/components/Panel.tsx (1)
code/addons/jest/src/hoc/provideJestResult.tsx (2)
  • Test (18-26)
  • AssertionResult (11-16)
code/core/src/components/components/bar/bar.tsx (1)
code/core/src/node-logger/index.ts (1)
  • deprecate (94-94)
code/core/src/components/components/AriaTabs/AriaTabPanel.stories.tsx (4)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (2)
  • TabProps (10-16)
  • useAriaTabListState (25-42)
code/core/src/components/components/AriaTabs/AriaTabPanel.tsx (1)
  • AriaTabPanel (32-64)
code/core/src/components/components/AriaTabs/AriaTabList.tsx (1)
  • AriaTabList (100-111)
code/core/src/test/testing-library.ts (1)
  • userEvent (119-122)
code/core/src/manager/components/preview/Preview.tsx (2)
code/core/src/components/components/AriaTabs/AriaTabs.tsx (1)
  • useAriaTabListState (25-42)
code/core/src/node-logger/index.ts (1)
  • deprecate (94-94)
🪛 Biome (2.1.2)
code/core/src/components/components/addon-panel/addon-panel.tsx

[error] 40-40: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 42-42: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

code/addons/jest/src/components/Panel.tsx

[error] 163-163: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 167-167: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🪛 markdownlint-cli2 (0.17.2)
MIGRATION.md

609-609: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: normal
🔇 Additional comments (55)
code/frameworks/server-webpack5/package.json (1)

65-65: LGTM: metadata-only gitHead bump

No functional or runtime impact from this change.

If your release/publish pipeline keys off package.json changes, confirm metadata-only edits like gitHead don’t trigger a publish.

code/renderers/svelte/package.json (1)

78-78: gitHead updated; no runtime/API change here.

code/addons/jest/package.json (1)

69-69: gitHead bump only; addon behavior unchanged.

code/frameworks/react-vite/package.json (1)

80-80: gitHead bump only; framework package unaffected functionally.

code/lib/cli-storybook/package.json (1)

75-75: gitHead bump; CLI package semantics unchanged.

code/renderers/html/package.json (1)

62-62: gitHead bump only; no export or dependency changes.

code/lib/core-webpack/package.json (1)

56-56: gitHead metadata updated; no functional delta.

code/lib/eslint-plugin/package.json (1)

71-71: gitHead bump; ESLint plugin contents unchanged.

code/lib/csf-plugin/package.json (1)

73-73: Metadata-only gitHead bump — verified consistent, LGTM.
All package.json files (40) contain the same gitHead: a8e7fd8a655c69780bc20b9749d2699e45beae17.

code/frameworks/nextjs/package.json (1)

146-146: Metadata-only gitHead bump — OK.

No action needed.

code/frameworks/svelte-vite/package.json (1)

79-79: Metadata-only gitHead bump — OK.

No action needed.

code/presets/react-webpack/package.json (1)

73-73: Metadata-only gitHead bump — OK.

No action needed.

code/frameworks/ember/package.json (1)

74-74: Metadata-only gitHead bump — OK.

No action needed.

code/core/package.json (3)

239-243: use-sync-external-store addition — OK.

Reasonable choice for subscription-based state; no further action.


384-384: Metadata-only gitHead bump — OK.

No action needed.


239-243: Add runtime deps here if core imports ARIA libs.

If core’s AriaTabs/AriaToolbar import react-aria/react-stately, declare them as dependencies (or peers) in this package to satisfy consumers.

Apply if applicable:

@@ "dependencies": {
   "semver": "^7.6.2",
+  "react-aria": "^3.42.0",
+  "react-stately": "^3.40.0",
   "use-sync-external-store": "^1.5.0",
   "ws": "^8.18.0"
 }
⛔ Skipped due to learnings
Learnt from: ndelangen
PR: storybookjs/storybook#32484
File: code/core/package.json:326-326
Timestamp: 2025-09-17T07:31:04.408Z
Learning: In Storybook's core package, dependencies like `open` are bundled into the final distribution during the build process, so they should remain in devDependencies rather than being moved to dependencies. End users don't need these packages as separate runtime dependencies since they're included in the bundled code.
code/frameworks/nextjs-vite/package.json (1)

108-108: Metadata-only gitHead bump — OK.

No action needed.

code/lib/create-storybook/package.json (1)

66-66: Metadata-only gitHead bump — LGTM.
No runtime or API impact.

code/lib/react-dom-shim/package.json (1)

55-55: gitHead updated — looks fine.
No behavioral change.

code/frameworks/react-webpack5/package.json (1)

74-74: gitHead bump only — OK to proceed.

code/lib/cli-sb/package.json (1)

34-34: gitHead bump only — LGTM.

code/renderers/react/package.json (1)

94-94: gitHead metadata update — approved.

code/presets/server-webpack/package.json (1)

59-59: gitHead metadata update — approved.

code/frameworks/angular/package.json (1)

126-126: gitHead update only — LGTM.

scripts/build/utils/entry-utils.ts (2)

3-3: Import reordering — fine.
No semantic change.


58-75: Verify packages importing use-sync-external-store declare it (prevent missing external at runtime).
rg in the sandbox returned "No files were searched" so importer scan is inconclusive; only package.json found that declares it is code/core/package.json -> ^1.5.0. Ensure any package that imports "use-sync-external-store" or "use-sync-external-store/shim" lists it in dependencies or peerDependencies, or add it to runtimeExternalInclude.

code/frameworks/react-native-web-vite/package.json (1)

77-77: Metadata-only gitHead bump — OK to merge

No functional/package surface changes in this file.

code/frameworks/html-vite/package.json (1)

66-66: Metadata-only gitHead bump — OK

No runtime impact.

code/frameworks/sveltekit/package.json (1)

77-77: gitHead update only

Looks good.

code/renderers/preact/package.json (1)

64-64: gitHead updated — no code changes

All good.

code/renderers/vue3/package.json (1)

72-72: gitHead metadata update

No issues.

code/presets/create-react-app/package.json (1)

56-56: gitHead bump only

Safe.

code/e2e-tests/addon-a11y.spec.ts (1)

62-64: Good fix: remove await for sync assertion

String containment via expect(...) is synchronous; this change is correct.

code/renderers/server/package.json (1)

61-61: Metadata-only gitHead bump — OK.
No functional changes; safe to land.

code/frameworks/vue3-vite/package.json (1)

75-75: gitHead update looks good.
Repository metadata sync only.

code/frameworks/web-components-vite/package.json (1)

68-68: gitHead update acknowledged.
No runtime impact.

code/e2e-tests/util.ts (1)

160-161: Role-based locator is preferable — nice.
More robust than CSS + :not([hidden]).

code/core/src/manager/components/preview/utils/components.ts (1)

13-19: Ensure the

has an accessible name (heading or aria-label/aria-labelledby).
Automated search produced no matches for under code/core/src/manager — confirm the component defined at code/core/src/manager/components/preview/utils/components.ts (lines 13–19) includes a visible heading or an aria-label/aria-labelledby so the
is a labeled landmark.

code/addons/jest/src/hoc/provideJestResult.tsx (1)

11-16: Use Jest’s official AssertionResult type; add @jest/test-result if missing.

Replace the local interface with the upstream type to keep status literals and fields in sync.

-// TODO: import type from @types/jest
-export interface AssertionResult {
-  status: string;
-  fullName: string;
-  title: string;
-  failureMessages: string[];
-}
+// Align with Jest's upstream types to prevent divergence
+import type { AssertionResult as JestAssertionResult } from '@jest/test-result';
+export type AssertionResult = Pick<
+  JestAssertionResult,
+  'status' | 'fullName' | 'title' | 'failureMessages'
+>;

Verification: AssertionResult is defined at code/addons/jest/src/hoc/provideJestResult.tsx and referenced in code/addons/jest/src/components/Panel.tsx; no "@jest/test-result" entry was found in package.json — add it as a devDependency (e.g., yarn add -D @jest/test-result or npm i -D @jest/test-result) before applying the change.

code/e2e-tests/module-mocking.spec.ts (1)

22-29: Nice: deterministic panel state before assertions

Clearing and remounting ensures stable expectations in Actions panel.

code/e2e-tests/manager.spec.ts (1)

240-254: Good switch to role-based selectors on mobile

Using getByRole('tab', { name: 'Controls' }) aligns with the ARIA migration and reduces ID brittleness.

code/core/src/components/components/bar/bar.tsx (1)

16-38: LGTM: Scrollable Bar with inner wrapper

The HeightPreserver pattern preserves height while enabling native horizontal scrolling. Matches the ARIA toolbar/tab needs.

code/core/src/controls/components/SaveStory.tsx (1)

200-229: LGTM: Modal split from Bar

Extracting the modal sibling avoids layout coupling and is cleaner for focus management.

code/core/src/components/components/AriaToolbar/AriaToolbar.tsx (1)

24-28: Orientation is hardcoded. Verify this is intentional across all toolbars.

If vertical toolbars are planned, consider an orientation?: 'horizontal' | 'vertical' prop (default horizontal).

Also applies to: 45-49

code/core/src/controls/manager.tsx (1)

125-127: LGTM: avoid double scrollbars in active panel.

Passing hasScrollbar={false} aligns with the new AriaTabs panel container.

code/core/src/component-testing/components/InteractionsPanel.stories.tsx (1)

13-14: LGTM: stories now reference Toolbar controls.

Import swap and args linkage look correct.

Also applies to: 52-54

code/core/src/controls/components/ControlsPanel.tsx (1)

3-3: LGTM: scroll behavior and save‑UI gating.

Wrapping ArgsTable in ScrollArea and using showSaveFromUI simplifies layout and avoids double scrollbars.

Also applies to: 33-39, 91-114

code/addons/docs/src/blocks/components/Toolbar.tsx (1)

49-50: Prevent leaking non-DOM props (storyId, baseUrl) to the DOM. Destructure and drop storyId/baseUrl (or use shouldForwardProp); the diff already renames them to _storyId/_baseUrl.
Location: code/addons/docs/src/blocks/components/Toolbar.tsx (around lines 49–50).
Repo-wide verification failed due to a script error — search for JSX spreads that forward {...rest} and for tokens "storyId" / "baseUrl" to confirm no other components leak these props.

code/core/src/component-testing/components/InteractionsPanel.tsx (2)

14-14: LGTM: Toolbar migration import is correct.


117-123: LGTM — props forwarded correctly to AriaToolbar. Re-run E2E role-based locators.

AriaToolbar is used in code/core/src/component-testing/components/Toolbar.tsx (aria-label="Component test playback controls"); AbstractAriaToolbar (code/core/src/components/components/AriaToolbar/AriaToolbar.tsx) accepts 'aria-label'/'aria-labelledby' via useToolbar — controls/controlStates/status/storyFileName/onScrollToEnd are forwarded.

code/core/src/manager/globals/exports.ts (1)

477-483: Exports verified in components barrel

code/core/src/components/index.ts re-exports the symbols — lines 72–75 export AriaTabList, AriaTabPanel, AriaTabs, useAriaTabListState, AriaToolbar, AbstractAriaToolbar.

code/core/src/manager/components/preview/Preview.tsx (1)

2-2: Import hygiene after heading-id fix.

Once the useId change above is applied, this import becomes used; otherwise, drop it to avoid lint noise.

code/core/src/components/index.ts (1)

70-75: Verify TypeScript ≥ 4.5 and downstream imports

  • BarProps is re-exported as a type in code/core/src/components/index.ts (export { Bar, type BarProps }) — ensure the repository/build uses TypeScript ≥ 4.5.
  • Confirm no consumers import Tabs, TabBar, TabsState, TabWrapper, TabButton, or FlexBar from the public components entry; found one local usage only: code/addons/a11y/src/components/A11YPanel.tsx imports ./Tabs (local), so that file isn't affected.
code/addons/a11y/src/components/Tabs.tsx (1)

85-91: Tooltips should also appear on keyboard focus

Confirm WithTooltip trigger="hover" also shows on focus for keyboard users; otherwise include focus.

If WithTooltip supports multiple triggers, prefer adding focus without removing hover (e.g., trigger="hover focus" or equivalent API).

Also applies to: 97-103, 111-117

code/core/src/manager/components/panel/Panel.tsx (1)

137-143: Don't remove panelProps.id here — update callers/tests first

AriaTabPanel applies its own id (so this prop is ignored), but the literal "panel-tab-content" is referenced across the repo; removing the prop will break tests/stories unless those references are updated.

  • code/core/src/component-testing/components/InteractionsPanel.stories.tsx (StyledWrapper id="panel-tab-content")
  • code/core/src/component-testing/components/Panel.tsx (IntersectionObserver root: document.querySelector('#panel-tab-content'))
  • code/e2e-tests/framework-svelte.spec.ts (multiple locators using '#storybook-panel-root #panel-tab-content')
  • code/e2e-tests/framework-nextjs.spec.ts (locators using '#storybook-panel-root #panel-tab-content')
  • code/addons/a11y/src/components/A11YPanel.stories.tsx (StyledWrapper id="panel-tab-content")
  • code/addons/a11y/src/components/Report/Report.stories.tsx (StyledWrapper id="panel-tab-content")

Either remove this prop and update all these references to use AriaTabPanel's generated id or another stable selector, or keep the prop for test compatibility and add a comment explaining it's overridden.

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch from ee627a6 to 3c5bba9 Compare September 18, 2025 22:58
@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-25918-toolbar branch from a83d1fb to 85a2462 Compare September 22, 2025 17:46
@Sidnioulz Sidnioulz merged commit ebe087d into a11y-consolidation Sep 22, 2025
6 of 10 checks passed
@Sidnioulz Sidnioulz deleted the sidnioulz/issue-25918-toolbar branch September 22, 2025 17:48
@coderabbitai coderabbitai bot mentioned this pull request Nov 14, 2025
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[A11y]: Addon panel tabbar is not accessible [Bug]: Top toolbar lacking semantics

7 participants