storybookjs / storybook

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

[Bug]: themes.normal not working for docs pages #28664

Open jackocnr opened 1 month ago

jackocnr commented 1 month ago

Describe the bug

I have a hosted storybook site which only shows docs pages, and I want the whole site (sidebar, preview etc) to all respect the user's system settings for light/dark mode.

On the Storybook Theming page, there is a video which states that you can use themes.normal (from @storybook/theming package) in your custom theme to respect the user's system setting for light/dark mode. This works fine in my custom theme (in manager.js), but not for my docs pages content.

From that same Theming page: it says you can theme docs pages by putting the following in preview.js:

parameters: {
    docs: {
        theme: themes.dark,
    },
},

This works fine, but I want to respect the user's system settings, so I try using themes.normal again, this time it doesn't work - it just always shows the light theme. You can see this in action here: https://intl-tel-input.com/storybook

Is there a way to get the docs preview panel to respect the user's system settings?

I found two relevant addons: https://storybook.js.org/addons/storybook-dark-mode https://storybook.js.org/addons/@storybook/addon-themes

But they both seem to be concerned with giving the user the ability to manually toggle the theme, which is not what I want - I just want it to automatically respect the user's system settings.

// manager.js
import { addons } from '@storybook/manager-api';
import { themes, create } from '@storybook/theming';

const customTheme = create({
  base: themes.normal,
  brandTitle: 'IntlTelInput Storybook',
  brandUrl: 'https://intl-tel-input.com',
  brandImage: 'https://intl-tel-input.com/img/logo.png',
  brandTarget: '_self',
});

addons.setConfig({
  showToolbar: false,
  showPanel: false,
  theme: customTheme,
});
// preview.js
import { themes } from '@storybook/theming';

/** @type { import('@storybook/react').Preview } */
const preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      theme: themes.default,
    },
  },
};

export default preview;

Reproduction link

https://stackblitz.com/edit/github-ctbu1e?file=.storybook%2Fpreview.js

Reproduction steps

Put the following in your preview.js:

parameters: {
    docs: {
        theme: themes.normal,
    },
},

I expected this to respect the user's system setting for light/dark mode, but it just always used light mode.

System

Storybook Environment Info:

  System:
    OS: macOS 13.6.7
    CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm <----- active
  Browsers:
    Chrome: 126.0.6478.183
    Safari: 17.5
  npmPackages:
    @storybook/addon-essentials: ^8.2.5 => 8.2.5 
    @storybook/addon-interactions: ^8.2.5 => 8.2.5 
    @storybook/addon-links: ^8.2.5 => 8.2.5 
    @storybook/addon-mdx-gfm: ^8.2.5 => 8.2.5 
    @storybook/blocks: ^8.2.5 => 8.2.5 
    @storybook/manager-api: ^8.2.5 => 8.2.5 
    @storybook/react: ^8.2.5 => 8.2.5 
    @storybook/react-vite: ^8.2.5 => 8.2.5 
    @storybook/test: ^8.2.5 => 8.2.5 
    @storybook/theming: ^8.2.5 => 8.2.5 
    eslint-plugin-storybook: ^0.8.0 => 0.8.0 
    storybook: ^8.2.5 => 8.2.5 
    storybook-addon-deep-controls: ^0.6.2 => 0.6.2

Additional context

No response

greptile-apps[bot] commented 1 month ago

Disclaimer This information might be inaccurate, due to it being generated automatically To resolve the issue with themes.normal not working for docs pages, update your .storybook/preview.js to use the ensure function from @storybook/theming to ensure the theme respects the user's system settings. Here is the updated code:

import { themes, ensure } from '@storybook/theming';

/** @type { import('@storybook/react').Preview } */
const preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      theme: ensure(themes.normal),
    },
  },
};

export default preview;

References

/docs/_snippets/storybook-preview-docs-dark-theme.md /docs/_snippets/configure-mock-provider-with-story-parameter.md /code/.storybook/preview.tsx /.github/DISCUSSION_TEMPLATE/help.yml /docs/_snippets/storybook-preview-auto-docs-override-theme.md /code/deprecated/theming/package.json /code/addons/themes/package.json /code/core/src/manager/components/sidebar/Brand.tsx /test-storybooks/external-docs/.storybook /code/addons/themes/README.md /code/core/scripts/helpers/modifyThemeTypes.ts /code/renderers/server/template/cli/button.stories.json /.github/DISCUSSION_TEMPLATE/ideas.yml /docs/_snippets/mock-provider-in-preview.md /code/presets/server-webpack/src/lib/compiler/testfixtures/backgrounds.json /code/addons/themes /docs/configure/user-interface/theming.mdx /docs/_snippets/storybook-preview-with-angular-polyfills.md /code/addons/themes/docs/getting-started /code/addons/docs/template/stories/docspage /code/presets/server-webpack/src/lib/compiler/testfixtures/kitchen_sink.snapshot /code/addons/docs/ember /code/core/src/theming/README.md /docs/_snippets/your-theme.md /code/frameworks/ember/src/client/preview/docs

#### About Greptile This response provides a starting point for your research, not a precise solution. Help us improve! Please leave a ๐Ÿ‘ if this is helpful and ๐Ÿ‘Ž if it is irrelevant. [Ask Greptile](https://app.greptile.com/chat/github/storybookjs/storybook/next) ยท [Edit Issue Bot Settings](https://app.greptile.com/apps/github)
jackocnr commented 1 month ago

Hello bot. I tried what you suggested and it just caused the following error when viewing the page: "Passed an incorrect argument to a color function, please pass a string representation of a color."

elisezhg commented 1 month ago

Hi @jackocnr !

From what I see in the code, themes.normal is equivalent to themes.light ๐Ÿค” (see core/src/theming/create.ts#L11). We get the user preference a few lines below so it shouldn't be too hard to make themes.normal adapt to the dark or light theme based on that preference. I'll try to find some time to fix this next week.

In the meantime, here's a workaround you can use:

// Copied from https://github.com/storybookjs/storybook/blob/v8.2.5/code/core/src/theming/utils.ts
const { window: globalWindow } = global;
export const getPreferredColorScheme = () => {
  if (!globalWindow || !globalWindow.matchMedia) return 'light';

  const isDarkThemePreferred = globalWindow.matchMedia('(prefers-color-scheme: dark)').matches;
  if (isDarkThemePreferred) return 'dark';

  return 'light';
};

// In your preview.js
const preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      theme: themes[getPreferredColorScheme()],
    },
  },
};
jackocnr commented 1 month ago

That worked a charm, thanks so much for the quick reply @elisezhg ๐Ÿ’

shilman commented 1 month ago

@kylegach This is a documentation issue in Chan's video. AFAIK themes.normal hasn't existed for awhile.

AmirTugi commented 1 month ago

@kylegach This is a documentation issue in Chan's video. AFAIK themes.normal hasn't existed for awhile.

Was just about to mention that Chan's video is explictly mentioning the normal as using the browser's theme preference.

@shilman I think that as long as the developers get access to the getPreferredColorScheme tool we don't need normal or anything, and we can make the configuration ourselves.

Another problem that this would solve is to create a custom theme that responses to the browser's theme pref (e.g different logo according to the browser pref).