-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Storybook 6 docs theming #127
Comments
It could. The last time I looked that wasn't configurable. Would happily accept a PR for this :D |
I had a go at this but I can't see how to make it work. |
I would love to see this be possible somehow as well. I'm running into this issue as well. I may have a look. |
In // preview.js
export const parameters = {
docs: {
container: DocsContainerTheme,
},
} Then through some styling solution manipulate the theme. As a proof of concept, the following worked to switch the background and color, but would be better to use a theme parameter rather than reconstruct the whole css here: // DocContainerTheme
import React from 'react'
import { DocsContainer } from '@storybook/addon-docs/blocks'
import { useDarkMode } from 'storybook-dark-mode'
import { makeStyles } from '../../src'
const useStyles = makeStyles({
override: {
'& .sbdocs': {
background: ({ dark }) => (dark ? 'black' : 'white'),
color: ({ dark }) => (dark ? 'white' : 'black'),
},
},
})
export const DocsContainerTheme = ({ children, context }) => {
const dark = useDarkMode()
const classes = useStyles({ dark })
return (
<div className={classes.override}>
<DocsContainer context={context}>{children}</DocsContainer>
</div>
)
} |
I think official support for this is still waiting on storybookjs/storybook#10523 Without a way to dynamically set params for the docs theme, this plugin can't do much. The approach above seems nice though in the interim |
Thanks for the sharing @stuarthendren! I found a better workaround that will fully respect the used theming without hacking the css by overriding the context using spread operators. First, create a doc container as the above example: // .storybook/components/DocContainer.tsx
import React from 'react'
import { DocsContainer as BaseContainer } from '@storybook/addon-docs/blocks'
import { useDarkMode } from 'storybook-dark-mode'
import { themes } from '@storybook/theming';
export const DocsContainer = ({ children, context }) => {
const dark = useDarkMode()
return (
<BaseContainer
context={{
...context,
parameters: {
...context.parameters,
docs: {
// This is where the magic happens.
theme: dark ? themes.dark : themes.light
},
},
}}
>
{children}
</BaseContainer>
);
} Then on your // .storybook/preview.js
import { DocsContainer } from './components/DocContainer';
export const parameters = {
docs: {
container: DocsContainer,
},
// Rest of your configuration
}; And voilà! 🎉 UPDATE: Not working since Storybook 6.4. See #127 (comment) or #127 (comment) for 6.4 compatible solution. |
This is life affirming. Surprised it's not in the docs as I don't consider it to be working properly if everything is dark and Docs are still blindingly white 😅 |
I'm not using React (but Vue3) and didn't see anything on creating containers in Vue (I'm not even sure it's possible). So I went with a very simple (but not reactive) solution, adding this in my export const parameters = {
/* ... */
docs: {
get theme() {
let isDarkMode = parent.document.body.classList.contains("dark");
return isDarkMode ? themes.dark : themes.light;
}
},
/* ... */
}; It's not reactive, so you must reload the page. The check is kinda dirty/hacky. But it works for my case, so I thought I might share. |
the above solution is working for me for the theme but it stopped showing props table. any ideas? Error: |
Yeah, same for me: @soullivaneuh @gsingh1370 @dominictobias have you managed to make the props work? |
@gazpachu use this. Added docs from context import React from 'react' export const DocsContainer = ({ children, context }) => { return ( |
Thanks, at the end, with lodash/set, the props work fine:
|
@gsingh1370 @gazpachu Not tested because I don't use props for my case, but as an alternative as the lodash example, you may use an additional spread operator: diff --git a/.storybook/components/DocContainer.tsx b/.storybook/components/DocContainer.tsx
index a0fd4b7..d1d775d 100644
--- a/.storybook/components/DocContainer.tsx
+++ b/.storybook/components/DocContainer.tsx
@@ -18,6 +18,7 @@ export const DocsContainer: FC<DocsContainerProps> = ({ children, context }) =>
parameters: {
...parameters,
docs: {
+ ...parameters.docs,
theme: dark ? themes.dark : themes.light,
},
}, This is surely why you don't have any prop, the |
Hmm I just upgraded from Does anyone got the same issue? Do you know if a workaround is possible? |
Storybook has released I haven't found a new way to set the theme dynamically. My very, very dirty hack with page refresh looks like this: import React, { useEffect } from 'react';
import { addParameters } from '@storybook/react';
import { DocsContainer as BaseContainer } from '@storybook/addon-docs';
import { themes } from '@storybook/theming';
import { useDarkMode } from 'storybook-dark-mode';
const isInitialDark = JSON.parse(localStorage.getItem('sb-addon-themes-3') ?? '{}')?.current === 'dark';
addParameters({
docs: {
theme: isInitialDark ? themes.dark : themes.light,
},
});
export const DocsContainer: typeof BaseContainer = (props) => {
const isDark = useDarkMode();
useEffect(
() => {
if (isInitialDark !== isDark) {
window.location.reload();
}
},
[isDark],
)
return <BaseContainer {...props} />;
}; I think this could potentially lead to endless page reloads. Use at your own risk. |
@dartess , @soullivaneuh after digging through the updates to DocsContainer in 6.4 , was able to get it working this way: <BaseContainer
context={{
...context,
storyById: (id) => {
const storyContext = context.storyById(id);
return {
...storyContext,
parameters: {
...storyContext?.parameters,
docs: {
theme: dark ? themes.dark : themes.light,
},
},
}
},
}}
> Not sure if this is the intended way, but it's working for me 😄 |
I was able to get both the args table to work correctly with subcomponents and the controls section to show up in dark mode with this:
|
tell me where you used it |
For anyone reading this in 2022. This is full fix description:
import React from "react";
import { DocsContainer as BaseContainer } from "@storybook/addon-docs/blocks";
import { useDarkMode } from "storybook-dark-mode";
import { themes } from "@storybook/theming";
export const DocsContainer = ({ children, context }) => {
const dark = useDarkMode();
return (
<BaseContainer
context={{
...context,
storyById: (id) => {
const storyContext = context.storyById(id);
return {
...storyContext,
parameters: {
...storyContext?.parameters,
docs: {
...storyContext?.parameters?.docs,
theme: dark ? themes.dark : themes.light,
},
},
};
},
}}
>
{children}
</BaseContainer>
);
};
import React from "react";
import { useDarkMode } from "storybook-dark-mode";
import { themes } from "@storybook/theming";
import { darkTheme } from "@retrolove-games/ui-themes";
import { DocsContainer } from './DocsContainer';
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
viewMode: "docs",
docs: {
// theme: themes.dark,
container: DocsContainer,
},
};
export const decorators = [
(Story) => (
<div className={useDarkMode() ? darkTheme.className : "light"}>
<Story />
</div>
),
]; Also published in my gist. |
Same problem here, docs are not updating when changing theme. Would love a similar option for styling docs, just like For now I'm sticking with the hack by @hugoattal because I'm also using Vue for my UI library. I tried the custom DocsContainer solution, but I can't install React as a devDependency in Storybook 6.4.20, because npm is complaining about dependency conflicts... Let's hope this Storybook issue gets solved.
|
Here is how I used @fedek6 DocsContainer with MUI5 theme: import { createTheme, CssBaseline, ThemeProvider } from "@mui/material";
import { getDesignTokens } from "theme/theme";
import { useDarkMode } from "storybook-dark-mode";
import { themes } from "@storybook/theming";
import { DocsContainer } from "./DocsContainer";
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
darkMode: {
dark: { ...themes.dark },
light: { ...themes.normal },
},
docs: {
container: DocsContainer,
},
};
function ThemeWrapper(props) {
const mode = useDarkMode() ? "dark" : "light";
const theme = createTheme(getDesignTokens(mode));
return (
<ThemeProvider theme={theme}>
<CssBaseline /> {props.children}
</ThemeProvider>
);
}
export const decorators = [
(Story) => (
<ThemeWrapper>
<Story />
</ThemeWrapper>
),
]; |
Hey! It's time to smoothly change the name to "Storybook 7 docs theming" In But The result of my research is this: diff --git a/.storybook/components/DocContainer.tsx b/.storybook/components/DocContainer.tsx
index 2e0d9fb8b..e1be68bf2 100644
--- a/.storybook/components/DocContainer.tsx
+++ b/.storybook/components/DocContainer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import { DocsContainer as BaseContainer } from '@storybook/addon-docs';
import { useDarkMode } from 'storybook-dark-mode';
@@ -15,24 +15,16 @@ so a workaround is used.
export const DocsContainer: typeof BaseContainer = ({ children, context }) => {
const dark = useDarkMode();
+ useEffect(() => {
+ // @ts-ignore
+ const { darkClass, lightClass } = context.store.projectAnnotations.parameters.darkMode;
+ const [addClass, removeClass] = dark ? [darkClass, lightClass] : [lightClass, darkClass]
+ document.body.classList.remove(removeClass);
+ document.body.classList.add(addClass);
+ }, [dark])
+
return (
- <BaseContainer
- context={{
- ...context,
- storyById: id => {
- const storyContext = context.storyById(id);
- return {
- ...storyContext,
- parameters: {
- ...storyContext?.parameters,
- docs: {
- theme: dark ? themes.dark : themes.light,
- },
- },
- };
- },
- }}
- >
+ <BaseContainer context={context} theme={dark ? themes.dark : themes.light}>
{children}
</BaseContainer>
); Tested on version |
I'm not really sure what the solution is here but if there are any that could be landed in the package feel free to make a PR! |
After upgrading to SB7+Next+Webpack my addons channel is no longer working (so no So for me, the quick solution is to use as wrapper: import { DocsContainer as BaseContainer } from '@storybook/addon-docs';
import { themes } from '@storybook/theming';
import React, { useEffect, useState } from 'react';
function isDarkInStorage(): boolean {
const themeString = localStorage.getItem('sb-addon-themes-3');
if (themeString) {
const theme = JSON.parse(themeString);
return theme['current'] !== 'light';
}
return false;
}
export const ThemedDocsContainer = ({ children, context }) => {
const [isDark, setIsDark] = useState(isDarkInStorage());
const handler = () => {
setIsDark(isDarkInStorage());
};
useEffect(() => {
window.addEventListener('storage', handler);
return function cleanup() {
window.removeEventListener('storage', handler);
};
});
return (
<BaseContainer context={context} theme={isDark ? themes.dark : themes.light}>
{children}
</BaseContainer>
);
}; (big sorry for this dirty workaround) |
thank you |
Thanks @fedek6 - This solution also worked for me, but now my source code block is only showing raw code — equivalent to setting the docs source parameter as |
@dartess I did nearly the similar but without having to hack with the diff --git a/.storybook/components/DocContainer.tsx b/.storybook/components/DocContainer.tsx
index 84bf99b..abd2e6d 100644
--- a/.storybook/components/DocContainer.tsx
+++ b/.storybook/components/DocContainer.tsx
@@ -13,27 +13,13 @@ import {
} from '@storybook/theming';
// @see https://github.com/hipstersmoothie/storybook-dark-mode/issues/127#issuecomment-1070524402
-export const DocsContainer: FC<DocsContainerProps> = ({ children, context }) => {
+export const DocsContainer: FC<DocsContainerProps> = ({ children, ...rest }) => {
const dark = useDarkMode();
return (
<BaseContainer
- context={{
- ...context,
- storyById: (id) => {
- const storyContext = context.storyById(id);
- return {
- ...storyContext,
- parameters: {
- ...storyContext?.parameters,
- docs: {
- ...storyContext?.parameters?.docs,
- theme: dark ? themes.dark : themes.light,
- },
- },
- };
- },
- }}
+ {...rest}
+ theme={dark ? themes.dark : themes.light}
>
{children}
</BaseContainer> The only thing I have to do is to fill the Why do you need to play with the DOM body here? 🤔 |
@soullivaneuh it was necessary for Now I have the same version as you. |
This is useful for me. Thanks |
@soullivaneuh's solution works well except for a few style regressions. Swapping out
Has anyone found a workaround that doesn't require reloading the docs iframe? |
😂 Still dirty: <!-- preview-head.html -->
<style>
/* Fix dynamic dark mode */
#storybook-docs h1>a:first-child,
#storybook-docs h2>a:first-child,
#storybook-docs h3>a:first-child,
#storybook-docs h4>a:first-child,
#storybook-docs h5>a:first-child,
#storybook-docs h6>a:first-child {
float: left;
line-height: inherit;
padding-right: 10px;
margin-left: -24px;
color: inherit;
}
</style> |
Finally got this working for me on react-vite 😅 Not sure if it is a vite specific issue, react 18 issue, or something, but overriding the context property seems to cause an error relating to useEffect being null weirdly. This was my least painful complete solution for theme to be controlled by the global parameters: import React from "react";
import type { Preview } from "@storybook/react";
import { DocsContainer, DocsContainerProps } from "@storybook/blocks";
import { themes } from "@storybook/theming";
const preview: Preview = {
globalTypes: {
theme: {
description: "Global theme for components",
defaultValue: "Dark",
toolbar: {
// The label to show for this toolbar item
title: "Theme",
icon: "circlehollow",
// Array of plain string values or MenuItem shape (see below)
items: ["Light", "Dark"],
// Change title based on selected value
dynamicTitle: true,
},
},
},
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
docs: {
container: (props: DocsContainerProps) => {
const { globals } = (props.context as any).store.globals;
return (
<DocsContainer
{...props}
context={props.context}
theme={
// Complains about missing properties, but it works
(globals.theme === "Dark" ? themes.dark : themes.light) as any
}
/>
);
},
},
},
};
export default preview; |
My project uses preview.tsx: import { DocsContainer, type DocsContainerProps } from '@storybook/blocks'
import type { Preview } from '@storybook/react'
import { themes } from '@storybook/theming'
import React, { type FC } from 'react'
import { useDarkMode } from 'storybook-dark-mode'
const { dark, light } = themes
const container: FC<DocsContainerProps> = ({ ...rest }) => (
<DocsContainer {...rest} theme={useDarkMode() ? dark : light} />
)
export const parameters = {
darkMode: { stylePreview: true },
docs: { container },
}
const preview: Preview = { parameters }
export default preview |
On storybook v8 I get |
My project uses Storybook@^7.6.7 with webpack, it worked fine! doc-container.tsx: import { DocsContainer as BaseContainer } from "@storybook/addon-docs";
import { useDarkMode } from "storybook-dark-mode";
import { themes } from "@storybook/theming";
export const DocsContainer = ({ children, context, ...rest }) => {
const { dark, light } = themes
return (
<BaseContainer
context={context}
{...rest}
theme={useDarkMode() ? dark : light}
>
{children}
</BaseContainer>
);
}; prevew.tsx: const parameters: Preview['parameters'] = {
...
docs: {
container: ({children, context}) => {
return (
<DocsContainer
context={context}
>
{children}
</DocsContainer>
)
},
},
} |
Can this be made to also configure the storybook docs theme which is supplied separately in v6.0?
The text was updated successfully, but these errors were encountered: