storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.73k stars 9.33k forks source link

[Bug]: Storybook canvas doesn't persist arg from URL #29436

Open penx opened 1 month ago

penx commented 1 month ago

Describe the bug

Storybook canvas doesn't persist an arg from the URL arg when @storybook/addon-essentials (docs add-on) is installed and an arg can accept React.ReactNode (or other complex type).

For example, say I have a Button component with a label prop that accepts a string (label: string), I can:

  1. Preview the button in storybook
  2. Change the label to 'Test'
  3. Click "Open canvas in new tab"
  4. See the Button with the "Test" label (expected)

If I change the TypeScript type for the Button's label prop from label: string to label: React.ReactNode or label: string | React.ReactNode, then

  1. Preview the button in storybook
  2. Change the label to 'Test'
  3. Click "Open canvas in new tab"
  4. The Button has the default label, not the new "Test" label (unexpected)

If I disable the @storybook/addon-essentials add-on, reload storybook and refresh the canvas, then this resolves the issue.

If I keep the @storybook/addon-essentials add-on enabled, but specifically disable docs, this also resolves the issue:

  {
      name: "@storybook/addon-essentials",
      options: {
        docs: false,
      },
    },

(note that in the sample repository, when disabling docs, you also need to remove .mdx files from the stories entries so that you don't get an error)

  stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],

Also note that if you disable the docs addon, the Storybook canvas live updates when you type in the Controls field for the Button label - without this you need to tab away.

Reproduction link

https://github.com/penx/storybook-controls-frame-issue

Reproduction steps

1.

npx storybook@next sandbox
npx storybook@latest init

2.

Open src/stories/Button.tsx and change

  label: string;

to

  label: string | React.ReactNode;

Follow steps above

System

Storybook Environment Info:

System: OS: macOS 15.0 CPU: (12) arm64 Apple M2 Max Shell: 5.9 - /bin/zsh Binaries: Node: 22.9.0 - ~/.nvm/versions/node/v22.9.0/bin/node Yarn: 1.22.22 - ~/.nvm/versions/node/v22.9.0/bin/yarn npm: 10.8.3 - ~/.nvm/versions/node/v22.9.0/bin/npm <----- active pnpm: 9.12.1 - ~/.nvm/versions/node/v22.9.0/bin/pnpm Browsers: Safari: 18.0 npmPackages: @storybook/addon-essentials: ^8.3.6 => 8.3.6 @storybook/addon-interactions: ^8.3.6 => 8.3.6 @storybook/addon-links: ^8.3.6 => 8.3.6 @storybook/addon-onboarding: ^8.3.6 => 8.3.6 @storybook/blocks: ^8.3.6 => 8.3.6 @storybook/react: ^8.3.6 => 8.3.6 @storybook/react-vite: ^8.3.6 => 8.3.6 @storybook/test: ^8.3.6 => 8.3.6 eslint-plugin-storybook: ^0.10.1 => 0.10.1 storybook: ^8.3.6 => 8.3.6

Additional context

We need to be able to produce links to a canvas in this way so that, during testing, we can create and send a preconfigured canvas URL to a mobile device and then open the URL directly on the device.

shilman commented 3 weeks ago

Storybook has logic that only serializes an arg to the URL if it validates:

https://github.com/storybookjs/storybook/blob/next/code/core/src/router/utils.ts#L193-L203

I suspect that the value somehow changes from a string to a ReactNode when docs is enabled.

penx commented 3 weeks ago

@shilman I had a look at the docs addon source last week but couldn’t figure out which bits of it may be affecting this.

From what I can tell, when checking out the storybook monorepo and building the docs addon in watch mode, I need to restart the sandbox storybook whenever I make a change?

Was making it a little difficult to figure out as I don’t have much familiarity here. So any pointers as to which code in the storybook addon could be doing this would be appreciated.

https://github.com/storybookjs/storybook/tree/next/code/addons/docs

penx commented 3 weeks ago

Running my reproduction and editing the label prop in the controls to "Example", I can see that the linked lines are run, it does not filter out the label prop and the argsString that is returned contains the string value of the label that I entered ("label:Butsffsddfton"). This renders correctly.

If I then click "Open canvas in new tab", I am taken to the following URL:

http://localhost:6006/iframe.html?args=label%3AExample&globals=&id=example-button--primary&viewMode=story

I see that the value I set ("Example"). is present in the URL, but (as per the bug above), the canvas does not show it.

@shilman The lines you linked to do not seem to run inside this frame, unless I've missed something.