Skip to content

Conversation

@alexey-kozlenkov
Copy link
Contributor

@alexey-kozlenkov alexey-kozlenkov commented Jul 2, 2025

Closes #31735

What I did

Modified mapping in mapArgsToTypes utility to allow primitive values (string, number, boolean) to pass through for ReactNode control.
I chose simple yet limited approach to validate for primitive type and return it as is. Another option could be to simply convert to string whatever arg holds, let me know if this suits better.

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

Unfortunately, I didn't figure out how to modify smth in sandbox (e.g. code/frameworks/react-vite/template/cli/ts/Button.tsx) and see the change when I run storybook, so I rely on units.

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

Modified mapArgsToTypes utility in Storybook core to handle primitive values for ReactNode control types, fixing URL parameter handling in CSF3 iframe mode.

  • Updated code/core/src/preview-api/modules/store/args.ts to allow primitive values (string, number, boolean) to pass through for ReactNode control type
  • Added test coverage in code/core/src/preview-api/modules/store/args.test.ts for primitive value handling
  • Implemented simple validation approach to return primitive values as-is for ReactNode controls
  • Addresses issue where URL parameters weren't properly mapping for ReactNode argTypes

Summary by CodeRabbit

  • New Features
    • Improved handling of ReactNode-type arguments: primitive values (string, number, boolean) are now accepted and passed through; non-primitive values are treated as incompatible.
  • Tests
    • Added test coverage validating ReactNode argument handling across various primitive and non-primitive inputs to ensure correct mapping behavior.

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.

2 files reviewed, 1 comment
Edit PR Review Bot Settings | Greptile

@alexey-kozlenkov alexey-kozlenkov changed the title fix: allow primitive URL arg value for ReactNode argType Core: (fix) allow primitive URL arg value for ReactNode argType Jul 2, 2025
@nx-cloud
Copy link

nx-cloud bot commented Jul 2, 2025

View your CI Pipeline Execution ↗ for commit f863ac3

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

☁️ Nx Cloud last updated this comment at 2025-09-23 13:17:34 UTC

@storybook-app-bot
Copy link

storybook-app-bot bot commented Jul 7, 2025

Package Benchmarks

Commit: f863ac3, ran on 23 September 2025 at 12:46:56 UTC

No significant changes detected, all good. 👏

@alexey-kozlenkov
Copy link
Contributor Author

@valentinpalkovic @ghengeveld 👋 hey! Not sure what are appropriate channels to do so, yet could you help me getting a review for this?
Thanks!

@ghengeveld
Copy link
Member

@alexey-kozlenkov Thanks for doing this. I've assigned @ndelangen for the review and merge. I've taken a quick look and see no immediate issues. Perhaps a code comment would be helpful to explain why only primitive values are supported for ReactNode props, just to discourage others from wanting to extend it to cover other (unsafe) types in the future.

@alexey-kozlenkov
Copy link
Contributor Author

alexey-kozlenkov commented Aug 28, 2025

@ghengeveld thank you!
I've updated the comment in newly added other case stating that it only cares for ReactNode argType case and it only allows primitives to pass as they are already included in ReactNode.

UPD: also added non-primitive test cases

Let me know please if any other changes needed.

@alexey-kozlenkov
Copy link
Contributor Author

@ndelangen hey!
Could you please have a look at this PR? I'd much appreciate!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Note

Other AI code review bot(s) detected

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

Walkthrough

Adds support in arg mapping for ArgTypes with name: 'other' and value: 'ReactNode': primitive arguments (string, number, boolean) are mapped through; non-primitives are treated as incompatible. A unit test exercising this behavior was added.

Changes

Cohort / File(s) Summary
Arg mapping logic
code/core/src/preview-api/modules/store/args.ts
Adds handling for argType.name === 'other' with argType.value === 'ReactNode'; uses isPrimitiveArg to allow primitives through and returns INCOMPATIBLE for non-primitives. Other mapping cases unchanged.
Tests for ReactNode handling
code/core/src/preview-api/modules/store/args.test.ts
Adds reactNodeType: SBType = { name: 'other', value: 'ReactNode' } and a test "passes only primitives for ReactNode type" asserting primitives map through and non-primitives do not produce mapped keys.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant URLArgs as URL / Controls
  participant Mapper as mapArgsToTypes
  participant Renderer

  User->>URLArgs: supply arg value (e.g., label=...)
  URLArgs->>Mapper: mapArgsToTypes(arg, argType)
  alt argType.name == "other" and argType.value == "ReactNode"
    alt arg is primitive (string|number|boolean)
      Mapper-->>Renderer: mapped primitive value
    else non-primitive
      Mapper-->>Renderer: INCOMPATIBLE (no mapping)
    end
  else other argType cases
    Mapper-->>Renderer: existing mapping logic
  end
  Renderer-->>User: render with mapped args
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibbled through the arg-filled night,
Let strings and numbers hop in light.
Booleans bounded, objects stayed out,
Symbols pondered what it's about.
Tests clap softly — a rabbit's delight 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Controls: Allow primitive values of ReactNode argType" is concise, focused, and accurately describes the primary change in the PR: allowing primitive values for ReactNode argTypes in Controls/mapArgsToTypes so URL-provided args are accepted. It avoids vague wording and directly reflects the implemented behavior and tests.
Linked Issues Check ✅ Passed The code change adds handling in mapArgsToTypes for argType 'other' with value 'ReactNode' to return primitive values (string, number, boolean) unchanged and adds unit tests including non-primitive cases; this directly implements the linked issue #31735's requirement that URL-provided primitive args be applied for ReactNode-typed props. The modifications are limited to argument mapping logic and tests, and the behavior described in the issue is addressed by the new mapping and tests.
Out of Scope Changes Check ✅ Passed The changes touch only code/core/src/preview-api/modules/store/args.ts and its test file and implement the narrowly scoped behavior for ReactNode argTypes; there are no unrelated file modifications or public API signature changes, so no out-of-scope changes are detected.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c2e33f and f863ac3.

📒 Files selected for processing (1)
  • code/core/src/preview-api/modules/store/args.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/core/src/preview-api/modules/store/args.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: normal

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
code/core/src/preview-api/modules/store/args.ts (1)

61-63: Nit: tighten the comment and reference the correct identifier

Use “type.value” (not “argType.value”) and state the intent crisply. Also note we intentionally exclude symbol/bigint/objects.

Apply this diff (if you prefer to keep the variable outside the block above, adjust line numbers accordingly):

-      // Only proceed if `argType.value` appeared to be a `ReactNode`.
-      // Only permit primitives as they are included in `ReactNode` type, hence easily applicable.
+      // Only handle when type.value is 'ReactNode'.
+      // Allow primitives only (string | number | boolean); exclude symbol/bigint/objects for safety.
code/core/src/preview-api/modules/store/args.test.ts (1)

127-136: Add null/undefined coverage for ReactNode primitives

Null and undefined are accepted early (lines 18–20 in args.ts) and are valid ReactNode values; add assertions to lock this in.

   it('passes only primitives for ReactNode type', () => {
     expect(mapArgsToTypes({ a: 'foo bar' }, { a: { type: reactNodeType } })).toStrictEqual({
       a: 'foo bar',
     });
     expect(mapArgsToTypes({ a: 1.2 }, { a: { type: reactNodeType } })).toStrictEqual({ a: 1.2 });
     expect(mapArgsToTypes({ a: true }, { a: { type: reactNodeType } })).toStrictEqual({ a: true });
+    expect(mapArgsToTypes({ a: null }, { a: { type: reactNodeType } })).toStrictEqual({ a: null });
+    expect(
+      mapArgsToTypes({ a: undefined }, { a: { type: reactNodeType } })
+    ).toStrictEqual({ a: undefined });
     expect(mapArgsToTypes({ a: new Date() }, { a: { type: reactNodeType } })).toStrictEqual({});
     expect(mapArgsToTypes({ a: { foo: 'bar' } }, { a: { type: reactNodeType } })).toStrictEqual({});
     expect(mapArgsToTypes({ a: Symbol('foo') }, { a: { type: reactNodeType } })).toStrictEqual({});
   });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63bb329 and 7ad81bd.

📒 Files selected for processing (2)
  • code/core/src/preview-api/modules/store/args.test.ts (2 hunks)
  • code/core/src/preview-api/modules/store/args.ts (1 hunks)
🧰 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/core/src/preview-api/modules/store/args.test.ts
**/*.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/core/src/preview-api/modules/store/args.test.ts
🧬 Code graph analysis (2)
code/core/src/preview-api/modules/store/args.ts (1)
code/core/src/csf/story.ts (2)
  • StoryContextUpdate (223-229)
  • StrictArgs (156-158)
code/core/src/preview-api/modules/store/args.test.ts (1)
code/core/src/preview-api/modules/store/args.ts (1)
  • mapArgsToTypes (73-81)
🪛 Biome (2.1.2)
code/core/src/preview-api/modules/store/args.ts

[error] 58-59: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: normal
🔇 Additional comments (1)
code/core/src/preview-api/modules/store/args.test.ts (1)

21-21: LGTM: clear SBType for ReactNode

The test constant is precise and readable.

@ndelangen ndelangen changed the title Core: (fix) allow primitive URL arg value for ReactNode argType Controls: Allow primitive values of ReactNode argType Sep 23, 2025
@ndelangen ndelangen merged commit ff83d3d into storybookjs:next Sep 23, 2025
53 of 54 checks passed
@github-actions github-actions bot mentioned this pull request Sep 23, 2025
18 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: CSF3 breaks passing primitive value to an arg of a wider type (e.g. ReactNode)

4 participants