Open unional opened 4 months ago
Disclaimer This information might be inaccurate, due to it being generated automatically
To fix the issue with the theme not updating in autodocs in Storybook 8.2, modify the ExternalDocsContainer
component to use the useDarkMode
hook and apply the theme dynamically. Here's the updated code:
import React from 'react';
import { ThemeProvider, themes, ensure } from 'storybook/internal/theming';
import { DocsContext } from '../DocsContext';
import { ExternalPreview } from './ExternalPreview';
import { useDarkMode } from 'storybook-dark-mode';
let preview: ExternalPreview<Renderer>;
export const ExternalDocsContainer: React.FC<
React.PropsWithChildren<{ projectAnnotations: any }>
> = ({ projectAnnotations, children }) => {
if (!preview) preview = new ExternalPreview(projectAnnotations);
const dark = useDarkMode();
const theme = dark ? themes.dark : themes.light;
return (
<DocsContext.Provider value={preview.docsContext()}>
<ThemeProvider theme={ensure(theme)}>{children}</ThemeProvider>
</DocsContext.Provider>
);
};
This change ensures that the theme in the autodocs updates automatically based on the dark mode setting.
/.github/DISCUSSION_TEMPLATE/help.yml /docs/_snippets/storybook-preview-auto-docs-override-mdx-container.md /.github/DISCUSSION_TEMPLATE/ideas.yml /docs/_snippets/storybook-preview-docs-dark-theme.md /docs/_snippets/configure-mock-provider-with-story-parameter.md /code/lib/blocks/src/blocks/external/ExternalDocsContainer.tsx /code/lib/blocks/src/blocks/external /docs/_snippets/storybook-preview-with-angular-polyfills.md /test-storybooks/external-docs/.storybook /.github/DISCUSSION_TEMPLATE/rfc.yml /code/addons/docs/template/stories/docspage /code/core/src/manager/components/sidebar/Brand.tsx /code/core/scripts/helpers/modifyThemeTypes.ts /code/lib/cli/src/automigrate/fixes/autodocs-tags.test.ts /code/addons/docs/angular /code/addons/docs/ember /code/frameworks/ember/src/client/preview/docs /code/addons/docs/template/stories/docspage/override.stories.ts /code/.storybook/preview.tsx /docs/_snippets/mock-provider-in-preview.md /code/core/src/core-server/utils/mockdata/errors/MetaOfClashingDefaultName.mdx /code/addons/docs/react /docs/_snippets/storybook-preview-empty-sort-object.md /code/core/src/preview-api/modules/preview-web/docs-context /docs/_snippets/storybook-preview-optout-inline.md
FYI I also tried to make it work with @storybook/addon-themes
and here is the ThemedContainer
that works:
import { DocsContainer, type DocsContextProps } from '@storybook/blocks'
import { themes } from '@storybook/theming'
import { type PropsWithChildren } from 'react'
export function ThemedContainer(props: PropsWithChildren<{ context: DocsContextProps }>) {
return (
<DocsContainer
context={props.context}
theme={(props.context as any).store.globals.globals.theme === 'dark' ? themes.dark : themes.light}
>
{props.children}
</DocsContainer>
)
}
You can see I dive in to the internals to get the theme value which is probably not a good idea.
And alternative is parsing the globals
query params.
We have the same issue for themes, and consequentially found the same solution as @unional, but yes it seems very hacky.
Allowing addon hooks to be used in DocsContainer would be really handy.
Same issue here, and workaround doesn't seem to work for us on version 8.2.7
Same issue for me as well, here's the code that breaks:
import React from 'react'
import { DocsContainer as SBDocsContainer } from '@storybook/blocks'
import { useDarkMode } from 'storybook-dark-mode'
import { darkTheme, lightTheme } from '../themes'
const DocsContainer = ({ children, context }) => (
<SBDocsContainer
context={context}
theme={useDarkMode() ? darkTheme : lightTheme}
>
{children}
</SBDocsContainer>
)
export default DocsContainer
For me store.globals.globals.theme
is undefined
.
I am experiencing a variant of this with any of my stories that use useState
in the story function -- updating the state triggers the error described here. Seems new with v8.3; worked fine in v8.1. Any ideas?
I ran into this issue after upgrading from 8.2.9 to 8.3.1
@unional @mohitkyadav @mellm0 FYI we were previously manually accessing store.globals.globals.theme
but had to adjust to store.userGlobals.globals.theme
after upgrading to 8.3
I got the error "Storybook preview hooks can only be called inside decorators and story functions" that is mentioned in the title when I navigated to docs pages that had inline story blocks with the dark mode addon.
I found out that the useDarkMode
hook is the culprit. I was using it in a custom docs container. I changed my docs container to not use this, this fixed the issue.
DarkModeAwareDocsContainer.jsx:
import React, { useEffect, useState } from 'react'
import { DocsContainer } from '@storybook/blocks'
import { themes } from '@storybook/theming'
import { addons } from '@storybook/preview-api'
const DARK_MODE_EVENT_NAME = 'DARK_MODE'
export default ({ children, ...props }) => {
const [isDark, setIsDark] = useState(document.body.classList.contains('dark'))
useEffect(() => {
const chan = addons.getChannel()
chan.on(DARK_MODE_EVENT_NAME, setIsDark)
return () => chan.off(DARK_MODE_EVENT_NAME, setIsDark)
}, [])
return (
<DocsContainer
{...props}
theme={isDark ? themes.dark : themes.light}
>
{children}
</DocsContainer>
)
}
I noticed with the above that the classList was empty on initial load, which meant that the code above failed to detect dark mode.
I modified it to this:
import React, { useEffect, useState } from 'react'
import { DocsContainer } from '@storybook/blocks'
import { themes } from '@storybook/theming'
import { addons } from '@storybook/preview-api'
const DARK_MODE_EVENT_NAME = 'DARK_MODE'
function useDocumentClassListObserver(
callback: (classList: DOMTokenList) => void
) {
useEffect(() => {
// Define a MutationObserver that listens to changes in classList
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.attributeName === 'class') {
callback(document.documentElement.classList)
}
}
})
// Start observing the documentElement for attribute changes
observer.observe(document.documentElement, { attributes: true })
// Clean up on component unmount
return () => observer.disconnect()
}, [callback])
}
export default ({ children, ...props }) => {
const [isDark, setIsDark] = useState(document.documentElement.classList.contains('dark'))
useDocumentClassListObserver((classList) => {
setIsDark(classList.contains('dark'))
})
useEffect(() => {
const chan = addons.getChannel()
chan.on(DARK_MODE_EVENT_NAME, setIsDark)
return () => chan.off(DARK_MODE_EVENT_NAME, setIsDark)
}, [])
return (
<DocsContainer
{...props}
theme={isDark ? themes.dark : themes.light}
>
{children}
</DocsContainer>
)
}
n.b my class is applied to documentElement
instead
Let's see if this might be fixed by: #26243 React: Fix RSC compatibility with addon-themes
Describe the bug
I'm using
storybook-dark-mode
to toggle my stories between light and dark mode.It works in stories, but the theme in the autodocs are not updated automatically.
To address that, I use a custom doc container:
This is working is storybook 8.1, but broken in 8.2.
Reproduction link
https://stackblitz.com/edit/github-2sfagn?file=.storybook%2Fpreview.tsx
Reproduction steps
open the repro
System
Additional context
No response