Skip to content

Conversation

@ndelangen
Copy link
Member

@ndelangen ndelangen commented Sep 4, 2025

What I did

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

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

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>

Greptile Summary

Updated On: 2025-09-04 09:52:15 UTC

This PR upgrades React from v18.2.0 to v19.1.1 across Storybook's manager UI and addon ecosystem. The changes are applied systematically to multiple packages including the root package.json, core Storybook package, and various addons (a11y, docs, jest, onboarding, pseudo-states, themes, vitest, create-storybook). The upgrade affects both direct dependencies and devDependencies, with yarn resolutions ensuring consistent versions across the monorepo workspace.

The upgrade encompasses the entire React ecosystem within Storybook, including React DOM and related packages like react-helmet-async, react-inspector, react-syntax-highlighter, and react-textarea-autosize. The changes maintain backward compatibility for end users by keeping flexible peer dependency ranges in addon packages (e.g., ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0) while using React v19 for development and build processes.

This modernization effort positions Storybook to leverage React 19's improvements including enhanced concurrent features, automatic batching optimizations, and new APIs. The coordinated approach ensures consistency across the entire addon ecosystem and manager UI components.

Confidence score: 2/5

  • This PR requires careful review due to React 19's breaking changes and dependency compatibility issues
  • Score lowered due to critical compatibility problems with deprecated APIs and outdated dependencies
  • Pay close attention to code/addons/onboarding/package.json and code/addons/jest/package.json for breaking changes

Summary by CodeRabbit

  • New Features

    • Broad React 19 compatibility across the app and addons.
  • Improvements

    • Safer, more predictable UI: improved handling of refs, timeouts, resizing, and sidebar interactions.
    • Component inspector now opens collapsed by default for clearer object inspection.
    • Tooltip and preview behaviors strengthened for greater stability.
  • Bug Fixes

    • Reduced crashes by guarding null refs, timeouts, and animation-frame cleanup.
  • Chores

    • Updated React, React DOM, related dependencies and 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.

10 files reviewed, no comments

Edit Code Review Bot Settings | Greptile

@ndelangen ndelangen marked this pull request as draft September 4, 2025 09:52
@nx-cloud
Copy link

nx-cloud bot commented Sep 4, 2025

View your CI Pipeline Execution ↗ for commit 6fb36b1

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

☁️ Nx Cloud last updated this comment at 2025-09-29 10:54:40 UTC

@storybook-app-bot
Copy link

storybook-app-bot bot commented Sep 4, 2025

Package Benchmarks

Commit: 6fb36b1, ran on 29 September 2025 at 10:45:14 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 508 KB 697 KB 🚨 +189 KB 🚨
Dependency size 2.80 MB 2.80 MB 0 B
Bundle Size Analyzer Link Link

@storybook/addon-jest

Before After Difference
Dependency count 2 2 0
Self size 47 KB 236 KB 🚨 +189 KB 🚨
Dependency size 53 KB 53 KB 0 B
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 43 43 0
Self size 30.16 MB 30.47 MB 🚨 +315 KB 🚨
Dependency size 17.30 MB 17.30 MB 0 B
Bundle Size Analyzer Link Link

@storybook/nextjs-vite

Before After Difference
Dependency count 124 124 0
Self size 4.10 MB 1.54 MB 🎉 -2.56 MB 🎉
Dependency size 21.62 MB 21.62 MB 🎉 -53 B 🎉
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 187 187 0
Self size 905 KB 905 KB 🚨 +611 B 🚨
Dependency size 79.76 MB 80.07 MB 🚨 +315 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 169 169 0
Self size 35 KB 35 KB 0 B
Dependency size 76.19 MB 76.50 MB 🚨 +315 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 44 44 0
Self size 1.55 MB 1.55 MB 0 B
Dependency size 47.46 MB 47.77 MB 🚨 +315 KB 🚨
Bundle Size Analyzer node node

….9 respectively in package.json and yarn.lock
- Changed TypeScript target and lib versions in tsconfig.json to support ES2024 features.
- Updated useRef hooks in multiple components to explicitly allow null values for better type safety.
- Enhanced type checks in getStoryId and copyToClipboard functions to ensure proper handling of props.
- Updated tsconfig.json to target ESNext and use the latest lib definitions.
- Replaced deprecated ReactDOM.render with createRoot for improved rendering in onboarding manager.
- Added explicit JSX type imports in various components for better type safety.
- Converted ts-ignore comments to ts-expect-error for better TypeScript error handling in prop types.
- Updated prop types in Tabs and Tooltip components to allow for additional types.
- Refined useRef hooks in FileSearchList and TestingModule to explicitly handle null values.
- Removed unnecessary ts-expect-error comments and added type checks for better error handling.
- Improved type definitions in useExpanded hook for clearer state management.
- Changed module from ESNext to Preserve for compatibility.
- Updated target from esnext to es2020 to align with project requirements.
@ndelangen ndelangen changed the title Manager: Upgrade to react v19 for manager UI & Addons Manager: Upgrade to react v19 for manager UI & Addons (SPIKE) Sep 16, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Important

Review skipped

Draft detected.

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.

Walkthrough

This PR upgrades React and related type packages to 19.x across the repo, bumps many devDependencies, and updates gitHead metadata. It tightens TypeScript typings and null-safety for refs and timeouts, converts several ts-ignore to ts-expect-error, and adjusts a few public types (Addon_BaseType.render now returns ReactNode; WithTooltip tooltip prop type changed; ZoomIFrame iFrameRef nullable). Onboarding rendering switched to createRoot from react-dom/client. Miscellaneous formatting and tooling changes include prettier formatting for generated files.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Manager as Onboarding manager
  participant DOM as DOM container
  participant ReactClient as react-dom/client

  Note over Manager,ReactClient: adopt React 18+ client API (createRoot)
  Manager->>DOM: querySelector('#root')
  Manager->>ReactClient: createRoot(DOM)
  ReactClient-->>Manager: root instance
  Manager->>ReactClient: root.render(<Suspense><Onboarding/></Suspense>)
  User-->>Manager: interact with onboarding UI
Loading
sequenceDiagram
  autonumber
  participant TestingModule as TestingModule
  participant RO as ResizeObserver
  participant RAF as requestAnimationFrame
  participant Timer as setTimeout

  Note over TestingModule: null-safe timeout + rAF-based measurement
  TestingModule->>Timer: setTimeout(reset isUpdated, 1000)
  TestingModule->>RO: observe(container)
  RO-->>TestingModule: onResize
  TestingModule->>RAF: requestAnimationFrame(measureHeight)
  RAF-->>TestingModule: apply height
  TestingModule->>Timer: clearTimeout(if exists) [cleanup]
  TestingModule->>RAF: cancelAnimationFrame(if pending) [cleanup]
  TestingModule->>RO: disconnect() [cleanup]
Loading
sequenceDiagram
  autonumber
  actor User
  participant Sidebar as TagsFilterPanel
  participant Hooks as React hooks (useRef/useMemo)

  Note over Sidebar,Hooks: safer refs and guarded navigation
  User->>Sidebar: toggle tag / change selection
  Sidebar->>Hooks: useMemo(compute groups)
  Sidebar-->>User: render updated tag groups
  User->>Sidebar: keyboard navigation
  Sidebar->>Hooks: guarded DOM access and highlight/expand updates
Loading

Possibly related PRs

Suggested labels

ui

Suggested reviewers

  • kasperpeulen
  • JReinhold
  • vanessayuenn

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly summarizes the primary change—upgrading React to version 19 for the manager UI and addons—while remaining concise and focused without unnecessary noise.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

…ttings updates by moving setTimeout logic outside of the conditional block.
addButtonElement &&
cloneElement(addButtonElement, {
onClick: this.onSubmit,
});
Copy link
Member

Choose a reason for hiding this comment

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

Maybe not do that?

Copy link
Member Author

Choose a reason for hiding this comment

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

The API usage/types is incorrect.

No overload matches this call.
  The last overload gave the following error.
    Object literal may only specify known properties, and 'onClick' does not exist in type 'Partial<unknown> & Attributes'.ts(2769)
index.d.ts(524, 14): The last overload is declared here.

according to types :

  addButtonElement?: ReactElement;
  cancelButtonElement?: ReactElement;

But cloneElement does not accept ReactElement, accepts a DetailedReactHTMLElement.
Those interfaces are not aligned.

In this PR I didn't want to make any possible behavior changes.

@ndelangen
Copy link
Member Author

@shilman has requested that I test this with a bunch of community addons.

It's on my todo list.

@ndelangen ndelangen marked this pull request as ready for review September 24, 2025 08:39
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: 8

Caution

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

⚠️ Outside diff range comments (1)
code/core/src/component-testing/components/MethodCall.tsx (1)

216-221: Avoid JSON.stringify in React keys; can throw on circular refs and hurts perf.

Using JSON.stringify(v) in the key may crash rendering for circular structures and is expensive; index is sufficient here (bounded slice, non-reordering).

Apply this diff:

-  const nodes = value
-    .slice(0, 3)
-    .map((v, index) => (
-      <Node key={`${index}--${JSON.stringify(v)}`} value={v} nested callsById={callsById} />
-    ));
+  const nodes = value
+    .slice(0, 3)
+    .map((v, index) => (
+      <Node key={index} value={v} nested callsById={callsById} />
+    ));
🧹 Nitpick comments (31)
code/addons/vitest/src/use-test-provider-state.ts (3)

74-76: Guarded clearTimeout: also null out the ref (nit)

Prevents stale IDs and helps type narrowing.

-        if (settingsUpdatedTimeoutRef.current) {
-          clearTimeout(settingsUpdatedTimeoutRef.current);
-        }
+        if (settingsUpdatedTimeoutRef.current) {
+          clearTimeout(settingsUpdatedTimeoutRef.current);
+          settingsUpdatedTimeoutRef.current = null;
+        }

84-86: Cleanup: also null the ref after clearing

Avoids retaining a stale handle post-unmount.

-      if (settingsUpdatedTimeoutRef.current) {
-        clearTimeout(settingsUpdatedTimeoutRef.current);
-      }
+      if (settingsUpdatedTimeoutRef.current) {
+        clearTimeout(settingsUpdatedTimeoutRef.current);
+        settingsUpdatedTimeoutRef.current = null;
+      }

90-94: Address TODO: recompute storyIds on index changes

If api is stable across index updates, this memo won’t recalc. Consider adding a store signal to the deps (broad but safe: storeState).

Example:

const storyIds = useMemo(
  () => (entryId ? api.findAllLeafStoryIds(entryId) : undefined),
  [entryId, api, storeState] // or a narrower key if you have one (e.g., storeState.index)
);

Can you confirm whether api identity changes when the story index updates? If not, adding a specific store key here would ensure correctness with minimal recomputation.

code/lib/react-dom-shim/src/react-18.tsx (1)

23-25: Remove ts-expect-error by initializing the ref to null.

Avoid suppressing the type error; initialize the ref with a nullable type. Behavior remains identical and is compatible with React 18/19 typings.

-  // @ts-expect-error - React18 allowed this
-  const once = React.useRef<() => void>();
+  const once = React.useRef<(() => void) | null>(null);
code/core/src/highlight/StoryContent.tsx (1)

23-24: Make popover id instance-unique and set button type; confirm manual popover intent

Replace the hard-coded id with a stable instance-unique id and set button type to avoid accidental form submission; verify that popover="manual" is intentional (if you expect click-to-open, use popover="auto" or wire an explicit onClick to toggle). Only occurrence found: code/core/src/highlight/StoryContent.tsx.

-          <button popoverTarget="my-popover">Open Popover 1</button>
-          <div popover="manual" id="my-popover" style={{ padding: 20 }}>
+          <button type="button" popoverTarget={popoverId}>Open Popover 1</button>
+          <div popover="manual" id={popoverId} style={{ padding: 20 }}>

Add near the top (before return):

const popoverId = React.useId();
code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (2)

68-68: Consider memoizing the docs URL.

The docsUrl is computed on every render but depends only on the api instance, which should be stable. Consider memoizing it to be consistent with other memoization patterns in this component.

-  const docsUrl = api.getDocsUrl({ subpath: 'writing-stories/tags#filtering-by-custom-tags' });
+  const docsUrl = useMemo(
+    () => api.getDocsUrl({ subpath: 'writing-stories/tags#filtering-by-custom-tags' }),
+    [api]
+  );

133-142: Review dependency array for unnecessary dependencies.

The dependency array includes several values that might cause unnecessary re-renders:

  • toggleTag (function, likely recreated each render)
  • docsUrl (computed value, could be memoized)
  • noTags (already memoized, stable reference)

Consider whether all these dependencies are necessary or if some can be optimized.

If toggleTag is not memoized in the parent, consider this optimization:

  }, [
    allTags.size,
    userEntries,
    builtInEntries,
    selectedTags,
-   toggleTag,
    isDevelopment,
-   docsUrl,
-   noTags,
  ]);

And handle toggleTag via useCallback in the parent component or accept that this dependency is necessary for correctness.

code/addons/onboarding/src/manager.tsx (1)

40-46: Prevent duplicate mounts in dev/HMR by guarding existing container.

Avoids calling createRoot twice on the same node in rare re-registration/HMR cases.

Apply:

-    // Add a new DOM element to document.body, where we will bootstrap our React app
-    const domNode = document.createElement('div');
+    // Prevent duplicate mounts (e.g., HMR or re-registration)
+    if (document.getElementById('storybook-addon-onboarding')) {
+      return;
+    }
+
+    // Add a new DOM element to document.body, where we will bootstrap our React app
+    const domNode = document.createElement('div');
code/core/src/component-testing/components/MethodCall.tsx (2)

84-90: stringify should handle Symbols/unsupported types without rendering empty text.

JSON.stringify(value) can return undefined (e.g., Symbol), yielding an empty . Fallback to String(value) when JSON.stringify returns undefined.

Apply this diff:

-const stringify = (value: any) => {
-  try {
-    return JSON.stringify(value, null, 1);
-  } catch (e) {
-    return String(value);
-  }
-};
+const stringify = (value: any) => {
+  try {
+    const json = JSON.stringify(value, null, 1);
+    return typeof json === 'string' ? json : String(value);
+  } catch {
+    return String(value);
+  }
+};

349-351: Minor: prefer getTime() for invalid Date check.

Number(parsed) works, but parsed.getTime() is clearer intent.

-  if (isNaN(Number(parsed))) {
+  if (Number.isNaN(parsed.getTime())) {
code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.tsx (1)

1-3: Optional: drop runtime React import; use type-only imports.

No runtime usage of React; you can remove the default import and rely on types to reduce bundle surface.

Apply:

-import type { FC, JSX } from 'react';
-import React from 'react';
+import type { FC, JSX, ElementType, ReactNode } from 'react';

-        const Component = 'div' as unknown as React.ElementType<
-          Omit<JSX.IntrinsicElements['div'], 'children'> & {
-            children: ({ active }: { active: boolean }) => React.ReactNode;
-          }
-        >;
+        const Component = 'div' as unknown as ElementType<
+          Omit<JSX.IntrinsicElements['div'], 'children'> & {
+            children: ({ active }: { active: boolean }) => ReactNode;
+          }
+        >;

Also applies to: 27-31

code/renderers/react/src/docs/jsxDecorator.test.tsx (4)

8-9: Replace ts-expect-error with types for PropTypes (optional)

Prefer adding @types/prop-types (devDependency) to avoid suppressing TS errors at import.

If you want to avoid the suppression, add the types in the renderer package’s devDependencies:

+  "devDependencies": {
+    "@types/prop-types": "^15.7.12",
+    ...
+  }

15-23: Align Vitest mocking with repo guidelines (spy + beforeEach implementations)

  • Use vi.mock with { spy: true }.
  • Move mock implementations (useEffect/useRef) into beforeEach.

Apply this diff to the mock (keeps real impls spied, overrides only what you need):

-vi.mock('storybook/preview-api', () => ({
-  addons: {
-    getChannel: vi.fn(),
-  },
-  useEffect: vi.fn((fn) => fn()),
-  useRef: vi.fn(() => ({ current: undefined })),
-  useState: vi.fn(),
-  emitTransformCode: vi.fn(),
-}));
+vi.mock(
+  'storybook/preview-api',
+  async () => {
+    const actual = await vi.importActual<typeof import('storybook/preview-api')>(
+      'storybook/preview-api'
+    );
+    return {
+      ...actual,
+      addons: { getChannel: vi.fn() },
+      useEffect: vi.fn(),
+      useRef: vi.fn(),
+      useState: vi.fn(),
+      emitTransformCode: vi.fn(),
+    };
+  },
+  { spy: true }
+);

And initialize behaviors in beforeEach:

 beforeEach(() => {
   vi.clearAllMocks();
   mockedGetChannel.mockReturnValue(channel as any);
   vi.mocked(useState).mockReturnValue([undefined, mockSetSource]);
+  vi.mocked(useEffect).mockImplementation((fn: any) => fn());
+  vi.mocked(useRef).mockReturnValue({ current: undefined } as any);

Outside-range import tweak required:

// add alongside existing imports from 'storybook/preview-api'
import { useEffect, useRef } from 'storybook/preview-api';

Also applies to: 321-328


141-147: Fix forwardRef generics (type-only cleanup)

Use a concrete ref type instead of FC for the ref generic.

-const MyExoticComponentRef = React.forwardRef<FC, PropsWithChildren>(
+const MyExoticComponentRef = React.forwardRef<HTMLDivElement, PropsWithChildren>(
   function MyExoticComponent(props, _ref) {
     return <div>{props.children}</div>;
   }
);

Apply similarly to the other two forwardRef declarations in this file.

Also applies to: 156-160, 173-181


76-81: Avoid ts-expect-error by typing the accumulator

Use a typed initial value for the reduce accumulator.

-const obj = Array.from({ length: 20 }).reduce((acc, _, i) => {
-  // @ts-expect-error (Converted from ts-ignore)
-  acc[`key_${i}`] = `val_${i}`;
-  return acc;
-}, {});
+const obj = Array.from({ length: 20 }).reduce<Record<string, string>>((acc, _, i) => {
+  acc[`key_${i}`] = `val_${i}`;
+  return acc;
+}, {});
code/core/src/components/components/addon-panel/addon-panel.tsx (2)

4-6: Annotate hook return type to stabilize inference

Explicitly declare the return type to avoid implicit widening and keep typings stable across TS upgrades.

-const usePrevious = (value: ReactElement) => {
+const usePrevious = (value: ReactElement): ReactElement | undefined => {
   const ref = useRef<ReactElement | undefined>(undefined);

15-19: Annotate return type for useUpdate

Prevents accidental widening; matches the possible undefined from usePrevious on initial render.

-const useUpdate = (update: boolean, value: ReactElement) => {
+const useUpdate = (update: boolean, value: ReactElement): ReactElement | undefined => {
   const previousValue = usePrevious(value);
code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/input.tsx (1)

21-24: Confirm intent to use defaultProps on FC; consider inline defaults if not required by the fixture

If this file is specifically testing docgen defaultProps behavior, keep as-is. Otherwise prefer parameter defaults over defaultProps for function components:

Example:

const iconButton: FC<IProps> = ({ color = 'primary' }) => { ... }
code/addons/docs/src/blocks/components/Story.tsx (1)

41-41: Tighten ref typing; avoid casts

With a typed ref, you can drop both casts:

  • Use the ref directly on the div.
  • Treat current as HTMLDivElement.

Example:

const storyRef = useRef<HTMLDivElement>(null);
// ...
const element = storyRef.current!;
...
<div ref={storyRef} id={`${storyBlockIdFromId(props)}-inner`} data-name={story.name} />
code/addons/docs/src/blocks/controls/Date.tsx (1)

72-73: Nullable refs alignment looks good; simplify usage and remove casts

  • You can simplify checks: if (dateRef.current) { ... } (same for timeRef).
  • You can pass refs directly without casting to RefObject:
    • ref={dateRef}
    • ref={timeRef}

This reduces type noise and avoids unnecessary assertions.

code/addons/docs/src/blocks/blocks/external/ExternalDocs.tsx (1)

18-18: Stable ref is fine; consider re-instantiating when annotations change

If projectAnnotationsList can change, the current ref guard prevents rebuilding the preview. Consider:

  • Using useMemo:
const preview = useMemo(() => new ExternalPreview<TRenderer>(projectAnnotations), [projectAnnotations]);
  • Or track the last annotations and recreate when they differ.

If annotations are truly static here, ignore.

code/core/src/components/components/tabs/tabs.helpers.tsx (1)

24-26: Widen children/title types to ReactNode to match usage

children is later treated as ReactNode; title also supports primitives/elements. Suggest aligning types:

-      children: FC<Addon_RenderOptions & PropsWithChildren> | ReactElement | null;
-      title: ReactElement | FC | string | number | null | boolean | undefined;
+      children: FC<Addon_RenderOptions & PropsWithChildren> | ReactNode;
+      title: ReactNode | FC;

This reduces friction for primitive children and removes the need to special-case types.

code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/input.tsx (1)

21-22: Prefer parameter defaults over defaultProps on function components (React 19).

defaultProps on function components is discouraged and not supported by React 19 type defs. If this is intentional for docgen coverage, consider adding a brief comment to state that. Otherwise, prefer ({ size = 'md' }) and drop the ts-expect-error.

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

256-256: Avoid as string cast; pass undefined when no id to prevent runtime null.

as string only coerces types; it won’t stop null at runtime. Prefer undefined when absent.

-          storyId={getStoryId(children) as string}
+          storyId={getStoryId(children) ?? undefined}
code/core/src/components/components/tabs/tabs.hooks.tsx (1)

127-127: Remove ts-expect-error by typing title as ReactNode.

The suppression hints a type mismatch. If ChildrenListComplete’s title isn’t ReactNode, update it so this render doesn’t need an override.

Example:

// tabs.helpers.ts (or wherever defined)
export type ChildrenListComplete = Array<{
  id: string;
  title: React.ReactNode; // ensure this
  color?: string;
  active?: boolean;
}>;

Additionally, consider replacing the useResizeObserver ts-expect-error by using its returned ref or a callback ref instead of passing tabBarRef directly.

code/core/src/manager/components/sidebar/useExpanded.ts (5)

56-59: Simplify initializeExpanded reducer (less cloning, clearer intent).

Avoid Object.assign in the loop; set keys directly and use nullish coalescing.

-  return [...rootIds, ...highlightedAncestors].reduce<ExpandedState>(
-    (acc: ExpandedState, id: string) =>
-      Object.assign(acc, {
-        [id]: id in (initialExpanded || {}) ? (initialExpanded || {})[id] : true,
-      }),
-    {}
-  );
+  return [...rootIds, ...highlightedAncestors].reduce<ExpandedState>((acc, id) => {
+    acc[id] = initialExpanded?.[id] ?? true;
+    return acc;
+  }, {});

82-86: Make reducer immutable without Object.assign in a loop.

Slightly faster and easier to read.

-  const [expanded, setExpanded] = useReducer(
-    (state: ExpandedState, { ids, value }: ExpandAction) =>
-      ids.reduce((acc: ExpandedState, id: string) => Object.assign(acc, { [id]: value }), {
-        ...state,
-      }),
+  const [expanded, setExpanded] = useReducer(
+    (state: ExpandedState, { ids, value }: ExpandAction) => {
+      const next: ExpandedState = { ...state };
+      for (const id of ids) next[id] = value;
+      return next;
+    },

107-121: Escape item id in selector to avoid invalid CSS attribute selectors.

If ids can contain special characters, escaping prevents querySelector errors.

-        const element = containerRef.current?.querySelector(
-          `[data-item-id="${ids[0]}"][data-ref-id="${refId}"]`
-        );
+        const escapedId = CSS?.escape?.(ids[0]) ?? ids[0];
+        const element = containerRef.current?.querySelector(
+          `[data-item-id="${escapedId}"][data-ref-id="${refId}"]`
+        );

Additionally, consider mirroring this in getElementByDataItemId:

const getElementByDataItemId = useCallback(
  (id: string) =>
    containerRef.current?.querySelector(
      `[data-item-id="${CSS?.escape?.(id) ?? id}"]`
    ),
  [containerRef]
);

187-188: Containment check is correct; optional simplification.

Equivalent using Node.contains: if (!menuElement.contains(target) && !target.contains(menuElement)) return; Your current approach is fine.


25-27: Align ref typing with React 19 (allow null in DOM refs).

Your code already uses optional chaining on current; widen the type accordingly.

-  containerRef: MutableRefObject<HTMLElement>;
+  containerRef: MutableRefObject<HTMLElement | null>;
code/package.json (1)

102-106: Add resolutions for react-dom and @types/react-dom to prevent version skew.

Ensures react and react-dom stay in lockstep across workspaces/subdeps.

     "playwright-core": "1.52.0",
-    "react": "^19.1.1",
+    "react": "^19.1.1",
+    "react-dom": "^19.1.1",
     "serialize-javascript": "^3.1.0",
     "type-fest": "~2.19",
     "typescript": "^5.8.3"

Optionally add types as well (helps with mixed constraints in subpackages):

-    "@types/react": "^19.0.0",
+    "@types/react": "^19.0.0",
+    "@types/react-dom": "^19.1.9",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68fc759 and d1f8b43.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (90)
  • code/addons/a11y/package.json (2 hunks)
  • code/addons/docs/package.json (2 hunks)
  • code/addons/docs/src/blocks/blocks/external/ExternalDocs.tsx (1 hunks)
  • code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.tsx (1 hunks)
  • code/addons/docs/src/blocks/components/Preview.tsx (3 hunks)
  • code/addons/docs/src/blocks/components/Story.tsx (1 hunks)
  • code/addons/docs/src/blocks/controls/Date.tsx (1 hunks)
  • code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx (7 hunks)
  • code/addons/jest/package.json (2 hunks)
  • code/addons/links/package.json (1 hunks)
  • code/addons/onboarding/package.json (1 hunks)
  • code/addons/onboarding/src/components/HighlightElement/HighlightElement.tsx (1 hunks)
  • code/addons/onboarding/src/manager.tsx (2 hunks)
  • code/addons/pseudo-states/package.json (1 hunks)
  • code/addons/themes/package.json (2 hunks)
  • code/addons/vitest/package.json (1 hunks)
  • code/addons/vitest/src/use-test-provider-state.ts (1 hunks)
  • code/builders/builder-vite/package.json (1 hunks)
  • code/builders/builder-webpack5/package.json (1 hunks)
  • code/core/package.json (5 hunks)
  • code/core/src/actions/components/ActionLogger/index.tsx (2 hunks)
  • code/core/src/component-testing/components/MethodCall.tsx (1 hunks)
  • code/core/src/component-testing/components/Panel.tsx (1 hunks)
  • code/core/src/components/components/Zoom/ZoomElement.tsx (1 hunks)
  • code/core/src/components/components/Zoom/ZoomIFrame.tsx (2 hunks)
  • code/core/src/components/components/addon-panel/addon-panel.tsx (2 hunks)
  • code/core/src/components/components/tabs/tabs.helpers.tsx (2 hunks)
  • code/core/src/components/components/tabs/tabs.hooks.tsx (2 hunks)
  • code/core/src/components/components/tabs/tabs.tsx (0 hunks)
  • code/core/src/components/components/tooltip/WithTooltip.tsx (2 hunks)
  • code/core/src/highlight/StoryContent.tsx (1 hunks)
  • code/core/src/manager/components/sidebar/FileSearchList.tsx (2 hunks)
  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (2 hunks)
  • code/core/src/manager/components/sidebar/TestingModule.tsx (2 hunks)
  • code/core/src/manager/components/sidebar/useExpanded.ts (7 hunks)
  • code/core/src/manager/globals/exports.ts (3 hunks)
  • code/core/src/types/modules/addons.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-vite/src/head-manager/head-manager-provider.tsx (1 hunks)
  • code/frameworks/nextjs/package.json (1 hunks)
  • code/frameworks/nextjs/src/head-manager/head-manager-provider.tsx (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/eslint-plugin/scripts/generate-rule.ts (2 hunks)
  • code/lib/react-dom-shim/package.json (1 hunks)
  • code/lib/react-dom-shim/src/react-16.tsx (1 hunks)
  • code/lib/react-dom-shim/src/react-18.tsx (2 hunks)
  • code/package.json (3 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/preact/src/render.tsx (0 hunks)
  • code/renderers/react/package.json (1 hunks)
  • code/renderers/react/src/csf-factories.test.tsx (1 hunks)
  • code/renderers/react/src/docs/jsxDecorator.test.tsx (1 hunks)
  • code/renderers/react/src/docs/jsxDecorator.tsx (2 hunks)
  • code/renderers/react/src/docs/propTypes/handleProp.test.tsx (1 hunks)
  • code/renderers/react/src/public-types.test.tsx (1 hunks)
  • code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/input.tsx (1 hunks)
  • code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/docgen.snapshot (1 hunks)
  • code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/input.tsx (1 hunks)
  • code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/docgen.snapshot (2 hunks)
  • code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/input.tsx (2 hunks)
  • code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx (1 hunks)
  • code/renderers/react/template/stories/docgen-components/ts-types/docgen.snapshot (1 hunks)
  • code/renderers/react/template/stories/docgen-components/ts-types/input.tsx (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)
  • code/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (2)
  • code/renderers/preact/src/render.tsx
  • code/core/src/components/components/tabs/tabs.tsx
🧰 Additional context used
📓 Path-based instructions (2)
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/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/public-types.test.tsx
  • code/renderers/react/src/docs/propTypes/handleProp.test.tsx
  • code/renderers/react/src/csf-factories.test.tsx
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together

Files:

  • code/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/public-types.test.tsx
  • code/renderers/react/src/docs/propTypes/handleProp.test.tsx
  • code/renderers/react/src/csf-factories.test.tsx
🧠 Learnings (5)
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases

Applied to files:

  • code/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/docs/propTypes/handleProp.test.tsx
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies

Applied to files:

  • code/renderers/react/src/docs/jsxDecorator.test.tsx
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors

Applied to files:

  • code/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/public-types.test.tsx
  • code/renderers/react/src/csf-factories.test.tsx
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock implementations should match the expected return type of the original function

Applied to files:

  • code/renderers/react/src/docs/propTypes/handleProp.test.tsx
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in beforeEach blocks

Applied to files:

  • code/renderers/react/src/csf-factories.test.tsx
🧬 Code graph analysis (3)
code/addons/onboarding/src/manager.tsx (1)
code/addons/onboarding/src/Onboarding.tsx (1)
  • Onboarding (70-296)
code/core/src/manager/components/sidebar/useExpanded.ts (1)
code/core/src/manager/utils/tree.ts (2)
  • getAncestorIds (34-36)
  • isAncestor (121-130)
code/core/src/components/components/tabs/tabs.helpers.tsx (1)
code/core/src/types/modules/addons.ts (1)
  • Addon_RenderOptions (318-320)
🔇 Additional comments (99)
code/frameworks/ember/package.json (1)

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

No functional impact. Peer ranges already include React 19, so this aligns with the repo-wide upgrade.

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

73-73: LGTM: metadata-only gitHead update

No functional impact; consistent with repo-wide metadata bumps.

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

72-72: LGTM: metadata-only gitHead bump

No functional or dependency changes in this package; safe to proceed.

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

77-77: LGTM: metadata-only change

gitHead update only; no functional impact for consumers.

code/renderers/react/template/stories/docgen-components/ts-types/docgen.snapshot (1)

24-26: Good swap to ts-expect-error; confirm intent to assert the error stays.

Using ts-expect-error over ts-ignore is preferable. Note this will fail if the TypeScript/@types-react error around function component defaultProps disappears in the future—which may be desirable for this snapshot. If that’s not intended, revert to ts-ignore here. Also ensure lint rules allow ts-expect-error in snapshot templates.

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

59-59: Metadata-only gitHead bump — LGTM.
No functional/package surface changes; verified no react-related deps/peers in code/presets/server-webpack/package.json (rg: "No react-related deps/peers found").

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

55-55: LGTM — metadata-only gitHead bump; exports unchanged

Verified code/lib/react-dom-shim/package.json still exports React 18 as the default ("types": "./dist/react-18.d.ts", "default": "./dist/react-18.js") and includes "./react-16"; build-config.ts and src/preset.ts reference react-18/react-16 — no React 19 changes detected. Confirm gitHead was auto-generated by your release tooling and isn’t a partial publish.

code/lib/eslint-plugin/scripts/generate-rule.ts (3)

5-5: Good addition of Prettier formatting to the generation pipeline.

Importing Prettier's format and resolveConfig functions ensures that generated files follow the project's formatting standards automatically.


158-201: LGTM! Proper Prettier integration for test file generation.

The implementation correctly:

  • Uses await format() to format the generated TypeScript test content
  • Applies the TypeScript parser for appropriate formatting
  • Resolves the project's Prettier configuration from the current directory
  • Maintains all the original template content while ensuring consistent formatting

206-246: LGTM! Proper Prettier integration for documentation generation.

The implementation correctly:

  • Uses await format() to format the generated Markdown documentation
  • Applies the Markdown parser for appropriate formatting
  • Resolves the project's Prettier configuration consistently
  • Preserves all template content while ensuring formatting standards
code/renderers/svelte/package.json (1)

78-78: Approve: Svelte renderer gitHead bump is non-functional; no React deps found

Checked code/renderers/svelte/package.json — gitHead = a8e7fd8a655c69780bc20b9749d2699e45beae18 (valid 40‑char hex) and no react/react-dom deps; searched renderer sources and found no React imports/usages.

code/addons/vitest/src/use-test-provider-state.ts (1)

68-68: Typed timeout ref with nullability is correct

Using ReturnType | null avoids NodeJS.Timeout vs number mismatches and aligns with the guards below.

code/lib/react-dom-shim/src/react-18.tsx (1)

36-47: Verify TS lib/types for Promise.withResolvers (ES2024) or add local types.

Repo scan: code/lib/react-dom-shim/package.json uses typescript ^5.8.3 and root code/tsconfig.json sets "lib": ["dom","dom.iterable","esnext"]; the shim and its only call site are in code/lib/react-dom-shim/src/react-18.tsx. Some subprojects/tsconfigs target older libs (e.g., ES2020), so consumers compiling with older TS/lib may get type errors for Promise.withResolvers / PromiseWithResolvers.

Options:

  • Keep as-is if all builds use TS >=5.8 + ESNext/ES2024 lib.
  • Add a minimal local augmentation (declare PromiseWithResolvers / PromiseConstructor.withResolvers).
  • Or change the shim’s annotations to local types: resolve: (value: T | PromiseLike) => void; reject: (reason?: unknown) => void.
code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/docgen.snapshot (3)

2-2: No-op whitespace change.


14-14: No-op whitespace change.


15-18: Appropriate @ts-expect-error for React 19 defaultProps on function components.

This guards the known type error (“defaultProps” no longer supported on function components) and will surface if/when the error disappears.

code/core/src/actions/components/ActionLogger/index.tsx (3)

45-45: LGTM! Proper React 19 ref typing.

The update from ElementRef<typeof Wrapper> to React.ComponentRef<typeof Wrapper> | null correctly aligns with React 19's typing conventions and explicitly includes null in the union type for better type safety.


53-55: LGTM! Improved null safety with guard condition.

The addition of the wrapperRef.current null check before accessing scroll properties prevents potential runtime errors and is consistent with the nullable ref typing. This defensive programming approach aligns well with the React 19 upgrade's emphasis on stricter type safety.


1-1: Verify consistency of React 19 ref typing across the codebase

Sandbox ripgrep couldn't search repo files; run these locally and update any remaining ElementRef / React.ComponentRef / useRef | null usages to match the React 19 typing pattern introduced here:
rg -nF 'ElementRef<' --hidden -g '!node_modules/' -C2
rg -nF 'React.ComponentRef<' --hidden -g '!node_modules/
' -C2
rg -nP 'useRef<[^>]|\snull' --hidden -g '!node_modules/**' -C2

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

14-15: Internal secrets identifier updated to match React 19 standards.

React 19 has renamed internal secret identifiers to discourage usage and prevent upgrade blocking. The change from __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_W_BE_FIRED to the new __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE and __COMPILER_RUNTIME aligns with React 19's internal API changes.


17-18: New React 19 APIs properly exposed.

The addition of new React 19 APIs like cache, captureOwnerStack, unstable_useCacheRefresh, use, useActionState, and useOptimistic aligns with React 19's introduction of the new use API for reading resources in render and other new hooks. These exports ensure the manager UI can access the latest React 19 features.

Also applies to: 28-30, 41-41


50-50: React DOM internals identifier updated correctly.

The replacement of __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_W_BE_FIRED with __DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE matches the React 19 internal API changes for DOM-specific internals.


53-59: React DOM APIs updated for React 19.

The addition of new React DOM APIs like preconnect, prefetchDNS, preinit, preinitModule, preload, preloadModule, requestFormReset, useFormState, and useFormStatus reflects React 19's expanded DOM capabilities and form handling improvements. React 19 introduces new hooks like useActionState and useFormStatus that simplify async actions.

Also applies to: 61-62


65-65: React DOM client exports correctly configured.

The consolidation of React DOM client exports to createRoot, hydrateRoot, and version is appropriate as React 19 removes createFactory and other legacy APIs in favor of modern approaches.


1-4: Verify the export list matches the React 19 API surface. code/core/src/manager/globals/exports.ts contains the react/react-dom export lists, but I couldn't find a React 19 dependency in package.jsons nor the generator (sourcefiles.ts) in the repo — compare this file against React 19's public API or regenerate it from the sourcefiles.ts generator to ensure no missing/renamed exports.

code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (5)

1-1: LGTM! Added useMemo import for memoization.

The addition of useMemo to the React import is appropriate for the performance optimization being implemented in this component.


70-77: Good memoization of static descriptor.

The noTags object is correctly memoized with an empty dependency array since it represents static content that never changes.


79-89: Excellent performance optimization with tag grouping memoization.

The memoization of tag grouping logic will prevent unnecessary recomputation when allTags hasn't changed. The reduce operation correctly separates built-in tags from user tags, and the dependency array is appropriate.


120-130: Smart conditional documentation link addition.

The logic to conditionally add a documentation link when there are no user entries in development mode is well-implemented and user-friendly.


91-142: toggleTag is memoized — no change needed.

toggleTag is created with useCallback in code/core/src/manager/components/sidebar/TagsFilter.tsx (lines 76–85), so including it in the useMemo deps for groups is acceptable.

code/addons/onboarding/src/components/HighlightElement/HighlightElement.tsx (1)

1-1: Type-only JSX import is correct for React 19 typings.

No runtime impact; aligns with updated React 19 type surface.

code/addons/onboarding/src/manager.tsx (1)

48-53: React 18/19 rendering API migration looks correct.

createRoot + root.render with Suspense is the right pattern.

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

250-251: ObjectInspector props verified — compatible with installed package

code/core/package.json lists @devtools-ds/object-inspector ^1.1.2; upstream README confirms expandLevel (number, default 0) and sortKeys (boolean, default false). expandLevel={0} and sortKeys={false} are correct.

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

92-92: Metadata-only gitHead bump — LGTM; gitHead consistent where present

All package.json files that include gitHead use a8e7fd8a655c69780bc20b9749d2699e45beae18. The following package.json files are missing gitHead and may need updating:

  • code/addons/onboarding/package.json
  • code/addons/pseudo-states/package.json
  • code/addons/vitest/package.json
  • code/core/src/common/js-package-manager/fixtures/multiple-lockfiles/package.json
  • code/core/src/common/js-package-manager/fixtures/multiple-lockfiles-pnpm-closer/inner/package.json
  • code/core/src/common/js-package-manager/fixtures/pnpm-workspace/package/package.json
  • code/core/src/common/js-package-manager/fixtures/pnpm-workspace/package.json
  • code/package.json
  • package.json
  • scripts/eslint-plugin-local-rules/package.json
  • scripts/package.json
  • test-storybooks/ember-cli/package.json
  • test-storybooks/external-docs/package.json
  • test-storybooks/portable-stories-kitchen-sink/nextjs/package.json
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
  • test-storybooks/portable-stories-kitchen-sink/svelte/package.json
  • test-storybooks/portable-stories-kitchen-sink/vue3/package.json
  • test-storybooks/server-kitchen-sink/package.json
  • test-storybooks/standalone-preview/package.json
  • test-storybooks/yarn-pnp/package.json
code/builders/builder-vite/package.json (1)

72-72: Metadata-only gitHead bump — LGTM; gitHead consistent where present (matches a8e7fd8a655c69780bc20b9749d2699e45beae18).
Verified: all package.json that include gitHead use that same value; several package.json (root, scripts, some addons, fixtures/test-storybooks) are missing gitHead — confirm whether you intended to update those as well.

code/addons/pseudo-states/package.json (1)

59-60: Upgrade to React 19 in devDependencies looks correct.

Aligns with the repo-wide upgrade and keeps peerDeps framework-agnostic. No issues.

code/renderers/react/src/csf-factories.test.tsx (1)

6-6: JSX type import aligns with React 19 typings.

Type-only import is appropriate; no runtime impact. Good change.

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

64-64: Metadata-only gitHead update.

No functional changes. OK to merge.

code/frameworks/nextjs/src/head-manager/head-manager-provider.tsx (1)

1-1: Adding JSX to type imports is appropriate.

Matches usage of JSX.Element in the file and React 19 typings.

code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/input.tsx (1)

2-2: Use of type JSX and explicit JSX.Element returns is consistent with TS/React 19.

No runtime changes; improves type clarity.

code/tsconfig.json (1)

21-21: Lowercased target is valid and equivalent.

No behavioral change; safe edit.

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

69-69: gitHead bump only.

No runtime/API impact.

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

74-74: gitHead bump only.

No code changes; React peer range already includes 19 and remains optional. Looks good.

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

82-82: LGTM: metadata bump.

gitHead update only.

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

73-73: LGTM: metadata bump only.

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

27-31: Typed render-prop cast looks good.

The IntrinsicElements + ElementType cast is a reasonable approach for TabsState’s function-children pattern.

Please re-check that TabsState still expects function children with the { active } signature on React 19.

code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx (1)

40-54: Good: ts-ignore → ts-expect-error.

This makes the intentional error explicit for docgen/defaultProps.

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

74-74: LGTM: metadata bump only.

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

95-96: LGTM: devDeps aligned to React 19.

No peer surface change here; safe for local tests.

code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx (1)

107-108: Replace as any on cloneElement with stronger prop typing for “menu/button” elements.

The casts work but hide type drift (onClick/className/style/aria-label). Prefer tightening prop types for supplied elements so cloneElement remains typed.

Introduce a shared prop type and use it on all relevant element props:

// near imports
import type { CSSProperties, MouseEventHandler, ReactElement } from 'react';

type MenuElProps = {
  onClick?: MouseEventHandler<any>;
  className?: string;
  style?: CSSProperties;
  'aria-label'?: string;
};

Then update interfaces (examples shown; apply similarly where used):

// JsonAddValueProps
addButtonElement?: ReactElement<MenuElProps>;
cancelButtonElement?: ReactElement<MenuElProps>;

// JsonArrayProps / JsonObjectProps / JsonValueProps / JsonFunctionValueProps
minusMenuElement?: ReactElement<MenuElProps>;
plusMenuElement?: ReactElement<MenuElProps>;

After this, the cloneElement calls won’t need as any.

Also applies to: 112-113, 339-340, 383-384, 391-392, 676-677, 1226-1227, 1272-1273, 1280-1281, 1546-1547

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

77-77: LGTM: metadata bump only.

code/core/src/components/components/Zoom/ZoomElement.tsx (1)

42-42: Type cast is correctly applied to align with stricter React 19 typing.

The cast to React.RefObject<HTMLDivElement> properly resolves the TypeScript compatibility issue with useResizeObserver under React 19's more stringent ref typing requirements. The runtime behavior remains unchanged.

code/renderers/react/src/docs/propTypes/handleProp.test.tsx (1)

12-13: Verify PropTypes compatibility with React 19.

The @ts-expect-error directive suggests PropTypes may have typing issues in React 19. This needs verification to ensure the suppression is appropriate and doesn't mask actual runtime problems.

Based on the web search results, PropTypes are removed from React 19 and usage will be silently ignored. The React team recommends migrating to TypeScript or another type-checking solution. The @ts-expect-error directive is appropriate here since PropTypes imports will trigger TypeScript errors in React 19 environments while still being necessary for the test functionality.

This suppression is correctly applied to maintain test compatibility during the React 19 transition period.

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

94-94: LGTM: Metadata update aligned with React 19 upgrade.

The gitHead update reflects the new commit state after React 19 changes. The peer dependencies already include React 19 support (^19.0.0), indicating this package is properly configured for the upgrade.

code/renderers/react/template/stories/docgen-components/ts-types/input.tsx (1)

96-97: Appropriate TypeScript error suppression for React 19 defaultProps.

The @ts-expect-error directive correctly handles the TypeScript compatibility issue with defaultProps in React 19. React 19 removes defaultProps from function components in favor of ES6 default parameters, making this assignment a type error while preserving runtime functionality during the transition.

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

56-56: LGTM: Metadata update consistent with repository-wide changes.

The gitHead update aligns with the broader React 19 upgrade across the monorepo. No functional changes impact this webpack core package.

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

62-62: LGTM: Metadata update maintains consistency.

The gitHead update reflects the current commit state. This HTML renderer package is unaffected by React-specific changes in this PR.

code/frameworks/nextjs-vite/src/head-manager/head-manager-provider.tsx (1)

1-1: Appropriate JSX type import addition for React 19 compatibility.

Adding the JSX type import ensures compatibility with React 19's stricter type requirements. The existing JSX.Element usage in the HeadManagerValue type (line 8) benefits from this explicit import without changing runtime behavior.

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

108-108: LGTM: Metadata update maintains consistency.

The gitHead update aligns with repository-wide changes. The peer dependencies already support React 19 (^19.0.0), so this package is properly configured for the upgrade.

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

65-65: Metadata-only change (gitHead) — LGTM

No functional impact.

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

67-67: Metadata-only change (gitHead) — LGTM

No functional impact.


59-59: React devDependency bump to ^19.1.1 — confirm necessity

I couldn't locate code/lib/create-storybook/package.json in the repo search output you ran, so I can't confirm placement or packaging. If React is only used for templates/types/local dev, keep it under devDependencies; if not, remove it from dependencies and ensure it isn't bundled in the published package.

Quick checks to run locally:

  • Locate the package.json: rg -nP '"name"\s*:\s*"create-storybook"' -S
  • Check dependency fields: jq -r '.dependencies.react // empty, .devDependencies.react // empty' path/to/package.json
  • Verify packed artifact doesn't include React: (cd path/to && npm pack && tar -tf *.tgz | rg 'node_modules/react')
code/frameworks/react-vite/package.json (1)

80-80: Metadata-only change (gitHead) — LGTM

No functional impact.

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

125-125: Metadata-only change (gitHead) — LGTM

No functional impact.

code/lib/codemod/package.json (1)

65-65: Metadata-only change (gitHead) — LGTM

No functional impact.

code/lib/react-dom-shim/src/react-16.tsx (2)

13-15: ts-expect-error on unmountComponentAtNode — same verification applies

Looks fine; confirm this code path is excluded when using React 19 runtime.

Same script as above applies.


7-9: ts-expect-error on ReactDOM.render is acceptable — ensure the react-16 shim is never used in React 19 builds

package.json exports default -> ./dist/react-18.js and exposes "./react-16" -> ./dist/react-16.js; react-16 shim (code/lib/react-dom-shim/src/react-16.tsx) uses deprecated ReactDOM APIs with ts-expect-error — verify no code imports '@storybook/react-dom-shim/react-16' and that the manager build for React 19 only resolves the default export. Locations: code/lib/react-dom-shim/package.json, code/lib/react-dom-shim/src/react-16.tsx

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

79-79: Metadata-only change (gitHead) — LGTM

No functional impact.

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

71-71: Metadata-only change (gitHead) — LGTM

No functional impact.

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

75-75: Metadata-only gitHead bump — OK

No functional impact. Safe to merge.

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

34-34: Metadata-only gitHead bump — OK

No runtime or dependency changes here.

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

73-73: Metadata-only gitHead bump — OK

Peer ranges already include React 19. No action needed.

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

56-56: Metadata-only gitHead bump — OK

No behavioral changes.

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

74-74: Metadata-only gitHead bump — OK

No functional changes in this package.

code/renderers/react/src/public-types.test.tsx (1)

5-5: JSX type import for React 19 — OK

This aligns with React 19 typings. No further changes needed.

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

61-61: Metadata-only gitHead bump — OK

All good here.

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

68-68: Metadata-only gitHead bump — OK

No functional impact here.

code/core/src/types/modules/addons.ts (1)

377-377: Widening render return to ReactNode — good compatibility move; verify call sites

This improves flexibility vs FC return types. Please ensure manager/consumer code paths treat the result as ReactNode and don’t assume ReactElement.

code/renderers/react/src/docs/jsxDecorator.tsx (1)

57-63: Type-safety in simplifyNodeForStringify — looks good

Casting props to a dictionary for safe iteration is appropriate here.

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

234-248: Nice ref nullability and guard

Initializing the ref with null and guarding observation is the right shape for strict refs.

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

105-105: React 19 devDeps bump — OK; ensure workspace resolution consistency

Looks good. Double-check your workspace resolutions lock React/DOM to 19.x across packages and that CI caches are invalidated.

Also applies to: 107-107, 121-121

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

146-146: Metadata-only change — LGTM

gitHead bump only; no functional impact.

code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/input.tsx (1)

4-5: Good migration to ts-expect-error

Replacing ts-ignore with ts-expect-error is safer and will fail if the suppression becomes unnecessary.

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

66-66: Metadata-only change — LGTM

gitHead bump only; no functional impact.

code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/docgen.snapshot (1)

15-18: Snapshot update aligns with added defaultProps — LGTM

Matches the companion fixture; no runtime impact.

code/core/src/manager/components/sidebar/FileSearchList.tsx (2)

87-87: LGTM: null-safe ref typing.

Switching to useRef<HTMLDivElement | null>(null) aligns with React 19 typings and avoids TDZ/undefined pitfalls.


1-1: Import casing matches file — no action needed. The import './FIleSearchList.utils' in code/core/src/manager/components/sidebar/FileSearchList.tsx matches the existing file FIleSearchList.utils.tsx in the same directory, so there is no case-sensitivity mismatch.

Likely an incorrect or invalid review comment.

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

65-67: LGTM: dev deps bumped to React 19.

Keeps end-user compatibility via peerDeps on storybook; no runtime impact here.

code/addons/docs/src/blocks/components/Preview.tsx (2)

157-159: LGTM: safer id guard in getStoryId.

The added prop shape check prevents accidental access on non-element children.


225-225: LGTM: safe extraction of source code text.

Explicit props cast with fallback avoids undefined issues in copy flow.

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

58-61: LGTM: React 19 dev deps.

Matches the monorepo’s upgrade; no user-facing peer changes.

code/core/src/components/components/tabs/tabs.hooks.tsx (1)

42-44: LGTM: nullable refs improve safety.

Using HTMLDivElement | null and HTMLButtonElement | null prevents TDZ/undefined access during mount/unmount.

code/core/src/manager/components/sidebar/TestingModule.tsx (2)

225-251: LGTM: rAF + ResizeObserver coordination to avoid layout thrash.

Deferring measurement and cancelling pending frames improves perf and correctness on expand/collapse.


446-447: LGTM: use boolean inert prop.

Passing { inert: true } is the correct boolean attribute usage with React 19.

code/core/package.json (1)

340-348: React 19 upgrade — peer ranges OK; fix a few non‑peer deps & validate runtime libs.

  • peerDependencies that declare "react" already include 19 (no peer ranges missing 19 found).
  • code/core/package.json uses react@^19.1.1, react-dom@^19.1.1 and the bumped libs: react-inspector@^9.0.0, react-textarea-autosize@^8.5.9, react-syntax-highlighter@^15.6.6, and @radix-ui/* entries.
  • Non-peer deps/devDeps still pinned <19 (update or confirm):
    • scripts/package.json — dependencies.react@^18.3.1, dependencies.react-dom@^18.3.1
    • test-storybooks/external-docs/package.json — dependencies.react 16.14.0, dependencies.react-dom ^18.2.0
    • test-storybooks/portable-stories-kitchen-sink/nextjs/package.json — dependencies.react ^18.2.0, react-dom ^18.2.0
    • test-storybooks/portable-stories-kitchen-sink/react/package.json — dependencies.react ^18.0.0, react-dom ^18.0.0
    • test-storybooks/standalone-preview/package.json — devDependencies.react 16.14.0, devDependencies.react-dom ^18.2.0
  • Runtime surface: createRoot/react-dom/client is used (e.g. code/core/src/manager/index.tsx, code/addons/onboarding/src/manager.tsx, test-storybooks/yarn-pnp/src/main.tsx); ReactDOM.render appears only in the legacy shim (code/lib/react-dom-shim/src/react-16.tsx) and comments.
  • Action: either update those non-peer deps to align with React 19 or document/isolated them as test fixtures, then run manager/preview integration tests with the bumped libs to confirm no runtime regressions.
code/core/src/manager/components/sidebar/useExpanded.ts (3)

98-101: Good guard before setting highlight.

Only updating when data-item-id exists prevents undefined highlights. LGTM.


125-127: Nice: only expand ancestry when a selection exists.

Prevents unnecessary state updates on null selection.


198-200: Good defensive check.

Guarding missing data-nodetype avoids invalid branches.

code/package.json (1)

96-106: Root resolutions bumped to React 19: LGTM.

This should help dedupe across the workspace.

Comment on lines +70 to 73
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-resize-detector": "^12.3.0",
"typescript": "^5.8.3",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

React 19 devDeps: verify ecosystem compatibility (esp. Testing Library).

Looks fine, but please confirm:

  • @testing-library/react version used here (still ^14.0.0 in repo elsewhere) doesn’t warn on React 19 peers.
  • react-resize-detector ^12.3.0 explicitly supports React 19.

🌐 Web query:

Does @testing-library/react v14 support React 19 (peerDependencies and compatibility)?

💡 Result:

Short answer: No — v14 does not officially support React 19. v14's peerDependencies target React 18 (so installing with React 19 will produce a peer-dep conflict). [1][2]

Recommendation: upgrade @testing-library/react to a version that adds React 19 support (projects migrating to React 19 report using later RTL releases, e.g. v16.x in practice). [3]

Sources:

  • Issue showing v14 peerDependencies require React 18. [1]
  • @testing-library/react package docs noting v13+ require React 18. [2]
  • Example migration noting use of @testing-library/react v16.x with React 19. [3]

🌐 Web query:

Is react-resize-detector v12 compatible with React 19?

💡 Result:

Yes — react-resize-detector v12 declares React ^18.0.0 || ^19.0.0 as a peer dependency (e.g. v12.0.2 package.json). [1]

Sources

  • package.json for [email protected] (peerDependencies: "react": "^18.0.0 || ^19.0.0"). [1]

Action: bump @testing-library/react to a React‑19‑compatible release; react-resize-detector v12 is OK.

  • @testing-library/react v14 targets React 18 (peerDeps) and will produce a peer-dep conflict with React 19 — upgrade to a v16.x (or later) release that declares React 19 support and update the lockfile/CI.
  • react-resize-detector v12 declares "react": "^18.0.0 || ^19.0.0" — no change required.
  • Location(s): repo uses React ^19.1.1 in code/addons/a11y/package.json; search the repo for any package.json entries with @testing-library/react ^14.0.0 and bump them.
🤖 Prompt for AI Agents
In code/addons/a11y/package.json around lines 70-73 the project depends on React
^19.1.1 but @testing-library/react v14 targets React 18 and will cause a
peer-dep conflict; bump any @testing-library/react entries (starting in this
file and across the repo) to a React‑19‑compatible release (e.g., ^16.x or later
that declares React 19 support), leave react-resize-detector v12 as-is, update
the lockfile (npm/yarn/pnpm) and CI artifacts, and run install/tests to verify
no remaining peer-dep warnings.

Comment on lines +56 to +57
"react": "^19.1.1",
"react-dom": "^19.1.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

React 19 bump LGTM; please verify deduped versions across the workspace.

Ensure all packages resolve to a single React/React DOM (19.x) to avoid multiple React copies at runtime.

Run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "All declared react/react-dom versions:"
rg -nP --glob 'package.json' '"react(?:-dom)?":\s*"[^"]+"'

echo
echo "Any non-19 or non-workspace declarations (should be empty):"
rg -nP --glob 'package.json' '"react(?:-dom)?":\s*"(?!\^?19|workspace:)[^"]+"' || true

Length of output: 4380


React 19 bump — fix remaining non-19 package.json entries

These files still declare React/React‑DOM outside 19.x; update them to ^19.1.1 (or use workspace:) so the workspace resolves a single React/React‑DOM:

  • test-storybooks/standalone-preview/package.json: "react": "16.14.0", "react-dom": "^18.2.0"
  • test-storybooks/external-docs/package.json: "react": "16.14.0", "react-dom": "^18.2.0"
  • test-storybooks/portable-stories-kitchen-sink/react/package.json: "react": "^18.0.0", "react-dom": "^18.0.0"
  • test-storybooks/portable-stories-kitchen-sink/nextjs/package.json: "react": "^18.2.0", "react-dom": "^18.2.0"
  • scripts/package.json: "react": "^18.3.1", "react-dom": "^18.3.1"
  • test-storybooks/yarn-pnp/package.json: "react": "^19.1.0", "react-dom": "^19.1.0" (consider matching ^19.1.1)
🤖 Prompt for AI Agents
In code/addons/onboarding/package.json around lines 56-57 and in the other
project package.json files listed
(test-storybooks/standalone-preview/package.json,
test-storybooks/external-docs/package.json,
test-storybooks/portable-stories-kitchen-sink/react/package.json,
test-storybooks/portable-stories-kitchen-sink/nextjs/package.json,
scripts/package.json, test-storybooks/yarn-pnp/package.json), update the react
and react-dom entries to match ^19.1.1 (or replace with "workspace:*"/workspace:
convention used by the monorepo) so the workspace resolves a single
React/React-DOM; change any exact older versions (e.g., 16.14.0, ^18.x) to
^19.1.1 (or workspace:), run npm/yarn install to refresh lockfiles, and verify
Storybook/test projects build with the unified React version.

withArrows?: boolean;
hasChrome?: boolean;
tooltip: ReactNode | ((p: WithHideFn) => ReactNode);
tooltip: ReactElement | ComponentType<WithHideFn>;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Tooltip prop was narrowed; restore ReactNode to avoid breaking existing consumers

Many callers pass string/primitive tooltips. Narrowing to ReactElement | ComponentType is a breaking typing change. Recommend accepting ReactNode (still supports elements) plus ComponentType for the render path.

-  tooltip: ReactElement | ComponentType<WithHideFn>;
+  tooltip: ReactNode | ComponentType<WithHideFn>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tooltip: ReactElement | ComponentType<WithHideFn>;
tooltip: ReactNode | ComponentType<WithHideFn>;
🤖 Prompt for AI Agents
In code/core/src/components/components/tooltip/WithTooltip.tsx around line 38,
the tooltip prop type was narrowed to ReactElement | ComponentType<WithHideFn>,
which breaks callers that pass strings/primitives; change the prop type to
ReactNode | ComponentType<WithHideFn> so it accepts primitives, elements and
components; update the import to include ReactNode from 'react' if missing and
run typecheck to ensure consumers still compile.

Comment on lines +7 to 8
iFrameRef: RefObject<HTMLIFrameElement | null>;
active?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Null-safety for iframe ref to avoid potential runtime errors

You allow null in iFrameRef, but unconditionally assign/call on this.iframe later. Guard the assignment and subsequent usage to avoid crashes if the ref isn’t set yet.

-  iFrameRef: RefObject<HTMLIFrameElement | null>;
+  iFrameRef: RefObject<HTMLIFrameElement | null>;
@@
-    this.iframe = iFrameRef.current as HTMLIFrameElement;
+    if (iFrameRef.current) this.iframe = iFrameRef.current;

Additionally (outside the changed lines), consider:

  • Typing the field as nullable and guarding usages:
// change field declaration
iframe: HTMLIFrameElement | null = null;

// guards
if (active !== nextProps.active) {
  this.iframe?.setAttribute('data-is-storybook', nextProps.active ? 'true' : 'false');
}

setIframeInnerZoom(scale: number) {
  if (!this.iframe) return;
  Object.assign(this.iframe.contentDocument!.body.style, { /* ... */ });
}

setIframeZoom(scale: number) {
  if (!this.iframe) return;
  Object.assign(this.iframe.style, { /* ... */ });
}

Also applies to: 17-18

Comment on lines +204 to 205
const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Type bug: useRef<ReturnType<typeof setTimeout>>(null) is invalid; include null in the type.

This won’t type-check; also inconsistent with timeoutRef above.

-  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);
+  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);

Scan for similar patterns:


🏁 Script executed:

#!/bin/bash
rg -nP -g '!**/node_modules/**' 'useRef<\s*ReturnType<\s*typeof\s+setTimeout\s*>\s*>\s*\(\s*null\s*\)'

Length of output: 148


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "rg version:"
rg --version || true
echo

echo "Search for settingsUpdatedTimeoutRef..."
rg -n -uu -S -g '!**/node_modules/**' 'settingsUpdatedTimeoutRef' || true
echo

echo "Search for ReturnType<typeof setTimeout ..."
rg -n -uu -S -g '!**/node_modules/**' 'ReturnType<typeof setTimeout' || true
echo

echo "Search for useRef<ReturnType ..."
rg -n -uu -S -g '!**/node_modules/**' 'useRef<ReturnType' || true
echo

echo "List files under code/core/src (if present)..."
ls -la code/core/src || true
echo

file="code/core/src/manager/components/sidebar/TestingModule.tsx"
if [ -f "$file" ]; then
  echo "File found: $file — printing lines 180-210:"
  nl -ba "$file" | sed -n '180,210p'
else
  echo "File not found at: $file"
fi

Length of output: 3513


🏁 Script executed:

#!/bin/bash
set -euo pipefail
file="code/core/src/manager/components/sidebar/TestingModule.tsx"

echo "File exists: $( [ -f "$file" ] && echo yes || echo no )"
echo
echo "Printing lines 160-220 from $file:"
sed -n '160,220p' "$file" || true
echo

echo "rg search (no-ignore) for specific symbols:"
rg -n --hidden --no-ignore -S 'settingsUpdatedTimeoutRef' || true
rg -n --hidden --no-ignore -S 'useRef<ReturnType' || true
rg -n --hidden --no-ignore -S 'ReturnType<typeof setTimeout' || true
echo

echo "grep fallback across . for .ts/.tsx files:"
grep -nR --exclude-dir=node_modules --include='*.ts*' -E 'settingsUpdatedTimeoutRef|useRef<[^>]*ReturnType<[^>]*typeof setTimeout' . || true

Length of output: 6656


Type bug — include null in the timeout useRef

useRef<ReturnType>(null) is invalid; change the type to include null to match the other refs and avoid a TypeScript error.

File: code/core/src/manager/components/sidebar/TestingModule.tsx:204

-  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);
+  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);
const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
🤖 Prompt for AI Agents
In code/core/src/manager/components/sidebar/TestingModule.tsx around line 204,
the useRef initialization is typed as useRef<ReturnType<typeof
setTimeout>>(null) which is invalid because null is assigned; change the ref
type to include null (e.g., useRef<ReturnType<typeof setTimeout> | null>(null))
so the initializer matches the type and is consistent with the other refs in the
file.

Comment on lines +155 to 157
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.9",
"@typescript-eslint/eslint-plugin": "^8.8.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Verify no lingering React 18 in workspace deps/devDeps.

Peer ranges may remain broad; focus on dependencies/devDependencies only. Script below lists offenders (if any).

Also applies to: 204-205


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Scan all package.json under code/ for deps/devDeps on react/react-dom not starting with ^19
fd -t f package.json code | while read -r f; do
  jq -r --argfile file <(echo "\"$f\"") '
    def checkDeps($obj):
      ($obj.react // empty) as $r
      | ($obj."react-dom" // empty) as $rd
      | if ($r != null and ($r|test("^\\^?19")|not)) then
          "react\t\($r)\t\($ENV_file)"
        else empty end,
        if ($rd != null and ($rd|test("^\\^?19")|not)) then
          "react-dom\t\($rd)\t\($ENV_file)"
        else empty end;

    . as $pkg
    | [
        {k:"dependencies", v:($pkg.dependencies // {})},
        {k:"devDependencies", v:($pkg.devDependencies // {})}
      ]
    | .[]
    | checkDeps(.v)
  ' "$f" | sed "s|\$ENV_file|$f|g"
done | awk 'NF' || echo "No non-^19 react/react-dom found in deps/devDeps."

Length of output: 4753


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find package.json files under code/ (fd if available, fallback to find)
if command -v fd >/dev/null 2>&1; then
  mapfile -t files < <(fd -t f package.json code || true)
else
  mapfile -t files < <(find code -name package.json -type f 2>/dev/null || true)
fi

if [ ${#files[@]} -eq 0 ]; then
  echo "No package.json files found under code/."
  exit 0
fi

found=0
for f in "${files[@]}"; do
  # Check dependencies + devDependencies for react/react-dom not starting with ^19 (allow optional leading ^)
  matches=$(jq -r --arg file "$f" '
    (.dependencies? // {} + .devDependencies? // {})
    | to_entries[]
    | select((.key == "react" or .key == "react-dom") and ((.value|tostring) | test("^\\^?19") | not))
    | "\(.key)\t\(.value)\t\($file)"
  ' "$f" 2>/dev/null || true)

  if [ -n "$matches" ]; then
    echo "$matches"
    found=1
  fi
done

if [ $found -eq 0 ]; then
  echo "No non-^19 react/react-dom found in deps/devDeps."
fi

Length of output: 56


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT

# Iterate package.json files under code/ without using process substitution
find code -type f -name package.json -print0 2>/dev/null | while IFS= read -r -d '' f; do
  matches=$(jq -r --arg file "$f" '
    (.dependencies? // {} + .devDependencies? // {})
    | to_entries[]
    | select((.key == "react" or .key == "react-dom") and ((.value|tostring) | test("^\\^?19") | not))
    | "\(.key)\t\(.value)\t\($file)"
  ' "$f" 2>/dev/null || true)

  if [ -n "$matches" ]; then
    printf '%s\n' "$matches" >> "$tmp"
  fi
done

if [ -s "$tmp" ]; then
  sort -u "$tmp"
else
  echo "No non-^19 react/react-dom found in deps/devDeps."
fi

Length of output: 157


Remove React 18 from workspace deps/devDeps.
code/addons/docs/package.json declares react and react-dom as "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" — restrict the peer/dependency range to "^19" (remove ^18 and older).

🤖 Prompt for AI Agents
In code/package.json around lines 155-157 and in code/addons/docs/package.json,
remove support for React 18 by updating any react/react-dom peerDependencies and
dependencies to only allow "^19" (remove the "^18.0.0" and any older ranges),
and update any @types/react and @types/react-dom devDependencies to the ^19.x
versions; ensure workspace-level deps/devDeps no longer list or accept React 18
and run a quick install to verify the lockfile updates.

Comment on lines +110 to 122
const props = renderedJSX.props as Record<string, any>;

if (typeof props.children === 'undefined') {
logger.warn('Not enough children to skip elements.');

if (typeof renderedJSX.type === 'function' && renderedJSX.type.name === '') {
renderedJSX = <Type {...renderedJSX.props} />;
renderedJSX = <Type {...props} />;
}
} else if (typeof renderedJSX.props.children === 'function') {
renderedJSX = renderedJSX.props.children();
} else if (typeof props.children === 'function') {
renderedJSX = props.children();
} else {
renderedJSX = renderedJSX.props.children;
renderedJSX = props.children;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Guard against non-elements and avoid stale type capture in skip loop

Two issues:

  • Accessing props when renderedJSX is not a valid element can throw.
  • Using the hoisted Type can drift after iterations; prefer using the current type.

Apply both fixes:

-    const props = renderedJSX.props as Record<string, any>;
+    const props = (isValidElement(renderedJSX)
+      ? (renderedJSX.props as Record<string, any>)
+      : ({} as Record<string, any>)) as Record<string, any>;
 
-    if (typeof props.children === 'undefined') {
+    if (typeof props.children === 'undefined') {
       logger.warn('Not enough children to skip elements.');
 
       if (typeof renderedJSX.type === 'function' && renderedJSX.type.name === '') {
-        renderedJSX = <Type {...props} />;
+        renderedJSX = createElement(renderedJSX.type as any, props);
       }
-    } else if (typeof props.children === 'function') {
+    } else if (typeof props.children === 'function') {
       renderedJSX = props.children();
     } else {
       renderedJSX = props.children;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const props = renderedJSX.props as Record<string, any>;
if (typeof props.children === 'undefined') {
logger.warn('Not enough children to skip elements.');
if (typeof renderedJSX.type === 'function' && renderedJSX.type.name === '') {
renderedJSX = <Type {...renderedJSX.props} />;
renderedJSX = <Type {...props} />;
}
} else if (typeof renderedJSX.props.children === 'function') {
renderedJSX = renderedJSX.props.children();
} else if (typeof props.children === 'function') {
renderedJSX = props.children();
} else {
renderedJSX = renderedJSX.props.children;
renderedJSX = props.children;
}
const props = (isValidElement(renderedJSX)
? (renderedJSX.props as Record<string, any>)
: ({} as Record<string, any>)) as Record<string, any>;
if (typeof props.children === 'undefined') {
logger.warn('Not enough children to skip elements.');
if (typeof renderedJSX.type === 'function' && renderedJSX.type.name === '') {
renderedJSX = createElement(renderedJSX.type as any, props);
}
} else if (typeof props.children === 'function') {
renderedJSX = props.children();
} else {
renderedJSX = props.children;
}
🤖 Prompt for AI Agents
In code/renderers/react/src/docs/jsxDecorator.tsx around lines 110 to 122, guard
against treating renderedJSX as an element before accessing props and stop using
the hoisted Type variable which can become stale during the skip loop; first
check React.isValidElement(renderedJSX) (or equivalent) and only read
renderedJSX.props after that check, and when rebinding the element use the
current renderedJSX.type instead of the outer Type so each iteration uses the
latest type; adjust branching to handle non-elements safely and to reconstruct
elements from the current type when needed.

Comment on lines +3 to 4
// @ts-expect-error (Converted from ts-ignore)
import PropTypes from 'prop-types';
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Good swap to @ts-expect-error; verify this reflects generator intent.

Replacing ts-ignore with ts-expect-error is safer. If this snapshot mirrors generated output, ensure the generator consistently emits @ts-expect-error (not @ts-ignore) across fixtures.

Run to find lingering ts-ignore in docgen component templates/snapshots:


🏁 Script executed:

#!/bin/bash
rg -n -C2 -g 'code/renderers/react/template/**' -P '@ts-ignore|ts-ignore'

Length of output: 7222


Good swap to @ts-expect-error; fix remaining @ts-ignore/@ts-ignore-error occurrences.
rg shows converted // @ts-expect-error (Converted from ts-ignore) but also leftover comments — update the generator/fixtures to consistently emit // @ts-expect-error.
Remaining occurrences: code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx (lines 4, 7), code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/input.tsx (line 4).

🤖 Prompt for AI Agents
In
code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/docgen.snapshot
around lines 3-4 and in the listed remaining files
(code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx
lines 4 and 7, and
code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/input.tsx
line 4), replace any leftover "// @ts-ignore" or "// @ts-ignore-error" comments
with "// @ts-expect-error" so the fixtures consistently emit the converted
comment; update the generator/fixture templates that produce these files to
output "// @ts-expect-error" everywhere instead of the older variants and run
the fixtures/regeneration step to update the snapshots.

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: 1

Caution

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

⚠️ Outside diff range comments (1)
code/core/package.json (1)

234-237: Core workspace also needs the React‑19‑ready RTL

Same issue as the a11y addon: @testing-library/react is still declared as ^14.0.0, whose peers exclude React 19. This makes yarn install fail under strict peers now that React ^19.1.1 is resolved for this package. Please upgrade RTL here as well (aligning on ^16.2.0 works with the root resolution) and refresh the lockfile.

-    "@testing-library/react": "^14.0.0",
+    "@testing-library/react": "^16.2.0",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1f8b43 and 9900a33.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (50)
  • code/addons/a11y/package.json (2 hunks)
  • code/addons/docs/package.json (2 hunks)
  • code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx (7 hunks)
  • code/addons/jest/package.json (2 hunks)
  • code/addons/links/package.json (1 hunks)
  • code/addons/onboarding/package.json (1 hunks)
  • code/addons/pseudo-states/package.json (1 hunks)
  • code/addons/themes/package.json (2 hunks)
  • code/addons/vitest/package.json (1 hunks)
  • code/builders/builder-vite/package.json (1 hunks)
  • code/builders/builder-webpack5/package.json (1 hunks)
  • code/core/package.json (5 hunks)
  • code/core/src/component-testing/components/Panel.tsx (1 hunks)
  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (1 hunks)
  • code/core/src/manager/components/sidebar/useExpanded.ts (6 hunks)
  • code/core/src/types/modules/addons.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/sveltekit/tsconfig.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 (3 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)
✅ Files skipped from review due to trivial changes (9)
  • code/lib/cli-storybook/package.json
  • code/frameworks/angular/package.json
  • code/lib/codemod/package.json
  • code/presets/react-webpack/package.json
  • code/renderers/server/package.json
  • code/renderers/html/package.json
  • code/renderers/svelte/package.json
  • code/frameworks/sveltekit/tsconfig.json
  • code/frameworks/react-webpack5/package.json
🚧 Files skipped from review as they are similar to previous changes (24)
  • code/frameworks/preact-vite/package.json
  • code/lib/cli-sb/package.json
  • code/frameworks/html-vite/package.json
  • code/builders/builder-webpack5/package.json
  • code/addons/links/package.json
  • code/renderers/vue3/package.json
  • code/renderers/react/package.json
  • code/frameworks/ember/package.json
  • code/addons/onboarding/package.json
  • code/builders/builder-vite/package.json
  • code/addons/docs/package.json
  • code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx
  • code/frameworks/server-webpack5/package.json
  • code/frameworks/sveltekit/package.json
  • code/addons/jest/package.json
  • code/lib/create-storybook/package.json
  • code/renderers/web-components/package.json
  • code/presets/server-webpack/package.json
  • code/frameworks/vue3-vite/package.json
  • code/frameworks/react-vite/package.json
  • code/addons/vitest/package.json
  • code/frameworks/web-components-vite/package.json
  • code/frameworks/nextjs/package.json
  • code/frameworks/nextjs-vite/package.json
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx
  • code/core/src/types/modules/addons.ts
  • code/core/src/manager/components/sidebar/useExpanded.ts
  • code/core/src/component-testing/components/Panel.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx
  • code/core/src/types/modules/addons.ts
  • code/core/src/manager/components/sidebar/useExpanded.ts
  • code/core/src/component-testing/components/Panel.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • code/package.json
🧬 Code graph analysis (1)
code/core/src/manager/components/sidebar/useExpanded.ts (1)
code/core/src/manager/utils/tree.ts (2)
  • getAncestorIds (34-36)
  • isAncestor (121-130)
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (16)
code/renderers/preact/package.json (1)

64-64: Metadata update looks good.

The gitHead bump aligns with the package publishing metadata.

code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (1)

119-119: Ref typing aligns with null initialization

Typing the ref as HTMLDivElement | null matches its initial null value and avoids strict-mode complaints when upgrading to React 19. All downstream uses remain valid.

code/core/src/types/modules/addons.ts (1)

377-377: Broader render return type aligns with React 19 expectations

Allowing addons to return any ReactNode (not just ReactElements) matches what React renderers accept and unblocks addons that return fragments or strings under the React 19 upgrade. Looks good.

code/addons/pseudo-states/package.json (1)

59-61: React 19 devDependency bump matches manager upgrade

The addon’s build-time React/React DOM targets align with the workspace-wide 19.1.1 upgrade, so no issues here.

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

71-71: gitHead metadata refresh looks correct

The updated gitHead simply tracks the new publish commit; nothing else changes.

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

79-79: gitHead metadata refresh looks correct

Only the gitHead pointer changed, which is expected bookkeeping for this publish bump.

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

77-77: gitHead metadata refresh looks correct

The gitHead update mirrors the repo-wide metadata sync; no functional impact.

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

56-56: gitHead metadata refresh looks correct

Nothing beyond the gitHead pointer moved, so this change is fine.

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

73-73: gitHead metadata refresh looks correct

This keeps the package metadata in sync with the new publish commit; no concerns.

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

56-56: gitHead metadata refresh looks correct

Only the commit pointer advanced; behavior remains unchanged.

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

65-76: React 19 devDependency bump and metadata sync look good

The addon now targets React/React DOM 19.1.1 for development, matching the manager upgrade, and the gitHead metadata tracks the new commit.

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

234-245: Nullable ref initialization keeps the observer safe

Typing endRef as HTMLDivElement | null and guarding the observe call removes the latent undefined access the compiler was complaining about while preserving runtime behavior. Looks good.

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

68-72: @testing-library/react v14 blocks React 19 installs

With React/ReactDOM now pinned to ^19.1.1 in this workspace, keeping @testing-library/react on ^14.0.0 causes a hard peer-dependency conflict (react peer is >=18.0.0 <19.0.0). Yarn Berry treats this as an install failure unless you relax peers globally. Please bump RTL here to the same React‑19–compatible line used at the root (e.g. ^16.2.0) and update the lockfile.

-    "@testing-library/react": "^14.0.0",
+    "@testing-library/react": "^16.2.0",
code/lib/react-dom-shim/package.json (1)

55-55: Metadata bump looks good.

gitHead update only—no functional impact, and it aligns this package with the upgraded commit.

code/package.json (2)

97-106: Resolution alignment LGTM.

Setting the Yarn resolutions for React and the new 19.x type packages keeps the workspace consistently on React 19 during the spike. No concerns here.


155-205: Root deps upgraded cleanly.

The root dependencies now reference React/ReactDOM 19.1.1 with matching type packages, so the manager tooling will consume the new runtime without version skew. Looks good.

Comment on lines 55 to 59
return [...rootIds, ...highlightedAncestors].reduce<ExpandedState>(
// @ts-expect-error (non strict)
(acc, id) => Object.assign(acc, { [id]: id in initialExpanded ? initialExpanded[id] : true }),
(acc: ExpandedState, id: string) =>
Object.assign(acc, {
[id]: id in (initialExpanded || {}) ? (initialExpanded || {})[id] : true,
}),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Preserve previously expanded nodes when initializing state.

The new initializer only keeps entries for rootIds and the highlighted ancestry. Any other initialExpanded entries—typically the nodes a user had expanded previously—are discarded, so those branches now start collapsed on load. We need to seed the reducer with the full initialExpanded snapshot before forcing roots/ancestors open.

-  return [...rootIds, ...highlightedAncestors].reduce<ExpandedState>(
-    (acc: ExpandedState, id: string) =>
-      Object.assign(acc, {
-        [id]: id in (initialExpanded || {}) ? (initialExpanded || {})[id] : true,
-      }),
-    {}
-  );
+  return [...rootIds, ...highlightedAncestors].reduce<ExpandedState>(
+    (acc: ExpandedState, id: string) => {
+      acc[id] = initialExpanded?.[id] ?? true;
+      return acc;
+    },
+    { ...(initialExpanded ?? {}) }
+  );
🤖 Prompt for AI Agents
In code/core/src/manager/components/sidebar/useExpanded.ts around lines 55 to
59, the reducer initializer is overwriting the full initialExpanded snapshot and
only keeps rootIds and highlightedAncestors, discarding previously expanded
nodes; preserve the user's initialExpanded by seeding the accumulator with the
full initialExpanded object (or an empty object when undefined) and then
override only the rootIds and highlightedAncestors entries to true so
roots/ancestors are forced open while all other initialExpanded entries are
retained.

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: 0

Caution

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

⚠️ Outside diff range comments (3)
code/addons/docs/src/blocks/components/Preview.tsx (3)

213-216: Copy flow is broken: text is ignored; nothing gets copied.

copyToClipboard imports the factory but never uses the returned function or the text argument, so the subsequent UI shows “Copied” without actually copying. Fix by invoking the returned copier and returning its result.

-  const copyToClipboard = useCallback(async (text: string) => {
-    const { createCopyToClipboardFunction } = await import('storybook/internal/components');
-    createCopyToClipboardFunction();
-  }, []);
+  const copyToClipboard = useCallback(async (text: string) => {
+    const { createCopyToClipboardFunction } = await import('storybook/internal/components');
+    const copy = createCopyToClipboardFunction();
+    return copy(text);
+  }, []);

218-246: Tighten event typing, guard window, and avoid stale state in async callbacks.

  • The handler attaches to a div, not an input; use ClipboardEvent<HTMLDivElement>.
  • Guard window reads for SSR/tests.
  • Use functional state updates to avoid stale closures in .then and setTimeout.
-  const onCopyCapture = (e: ClipboardEvent<HTMLInputElement>) => {
+  const onCopyCapture = (e: ClipboardEvent<HTMLDivElement>) => {
@@
-    const selection: Selection | null = globalWindow.getSelection();
+    const selection: Selection | null = globalWindow?.getSelection?.() ?? null;
@@
-    if (additionalActionItems.filter((item) => item.title === 'Copied').length === 0) {
+    if (additionalActionItems.filter((item) => item.title === 'Copied').length === 0) {
       copyToClipboard((source?.props as { code?: string })?.code ?? '').then(() => {
-        setAdditionalActionItems([
-          ...additionalActionItems,
-          {
-            title: 'Copied',
-            onClick: () => {},
-          },
-        ]);
-        globalWindow.setTimeout(
-          () =>
-            setAdditionalActionItems(
-              additionalActionItems.filter((item) => item.title !== 'Copied')
-            ),
-          1500
-        );
+        setAdditionalActionItems((prev) => [
+          ...prev,
+          { title: 'Copied', onClick: () => {} },
+        ]);
+        globalWindow?.setTimeout?.(
+          () =>
+            setAdditionalActionItems((prev) =>
+              prev.filter((item) => item.title !== 'Copied')
+            ),
+          1500
+        );
       });
     }

267-267: Don’t pass a boolean to an event prop.

onCopyCapture={withSource && onCopyCapture} can pass false and violates the event prop type (stricter React 19 + TS). Use undefined when disabled.

-        <Relative className="docs-story" onCopyCapture={withSource && onCopyCapture}>
+        <Relative className="docs-story" onCopyCapture={withSource ? onCopyCapture : undefined}>
🧹 Nitpick comments (1)
code/addons/docs/src/blocks/components/Preview.tsx (1)

229-229: Avoid ad-hoc casts by typing source precisely (or read from withSource).

Casting source.props to { code?: string } works but is brittle. Prefer typing SourceItem.source as ReactElement<{ code?: string }> (or ReactElement<SourceProps> if code lives there) so line 229 needs no cast.

-interface SourceItem {
-  source?: ReactElement | null;
+interface SourceItem {
+  source?: ReactElement<{ code?: string }> | null;
   actionItem: ActionItem;
 }

Then simplify line 229:

-      copyToClipboard((source?.props as { code?: string })?.code ?? '').then(() => {
+      copyToClipboard(source?.props.code ?? '').then(() => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9900a33 and 8218553.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • code/addons/docs/src/blocks/components/Preview.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/addons/docs/src/blocks/components/Preview.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/addons/docs/src/blocks/components/Preview.tsx
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest

@ndelangen ndelangen marked this pull request as draft September 29, 2025 08:58
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.

4 participants