Skip to content
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

Addon-Docs: Changing the theme via api doesn't persist in Docs #10523

Open
angelolucas opened this issue Apr 22, 2020 · 24 comments
Open

Addon-Docs: Changing the theme via api doesn't persist in Docs #10523

angelolucas opened this issue Apr 22, 2020 · 24 comments

Comments

@angelolucas
Copy link

Describe the bug
I have an addon tool that handles the storybook theme through the api:

// inside my addon

api.setOptions ({
  theme: themes[base],
});

The Storybook matches, but Docs don't change.
Docs works with the dark theme just by adding through addParametes:

// config.js

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

addParameters({
  options: {
    theme: themes.dark,
},

Expected behavior
That when changing the theme through the storybook API, it trigger the Docs theme

Screenshots
issue

System:
Environment Info:

System:
OS: macOS 10.15.4
CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Binaries:
Node: 10.16.0 - /usr/local/bin/node
Yarn: 1.9.4 - /usr/local/bin/yarn
npm: 6.13.7 - /usr/local/bin/npm
Browsers:
Chrome: 81.0.4044.122
Firefox: 74.0
Safari: 13.1
npmPackages:
@storybook/addon-a11y: ^5.3.18 => 5.3.18
@storybook/addon-actions: ^5.3.18 => 5.3.18
@storybook/addon-docs: ^5.3.18 => 5.3.18
@storybook/addon-knobs: ^5.3.18 => 5.3.18
@storybook/addon-storysource: ^5.3.18 => 5.3.18
@storybook/addon-viewport: ^5.3.18 => 5.3.18
@storybook/addons: ^5.3.18 => 5.3.18
@storybook/react: ^5.3.18 => 5.3.18
@storybook/storybook-deployer: ^2.8.3 => 2.8.5

@shilman
Copy link
Member

shilman commented Apr 22, 2020

In 6.0 we've moved to a parallel theming structure for docs:

https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/theming.md#storybook-theming

@angelolucas
Copy link
Author

@shilman this instruction set the theme in the initial state. Is there a way to change at run time?

I want to change the theme of the Storybook, Docs and Design System at once:

Screen Shot 2020-04-23 at 15 59 09

@shilman
Copy link
Member

shilman commented Apr 23, 2020

I believe docs is dynamically themable but Storybook UI is not cc @ndelangen

@hipstersmoothie
Copy link
Contributor

hipstersmoothie commented Apr 30, 2020

I'm looking for this same thing too for https://github.com/hipstersmoothie/storybook-dark-mode/. I need a way to dynamically set the theme for the addon-docs tab.

@shilman
Copy link
Member

shilman commented Apr 30, 2020

@hipstersmoothie OK I misunderstood the issue. In master, docs is themed by the options.theme parameter per this issue. In next, docs is themed via the docs.theme parameter per #10114. How did your addon work before api.setOptions existed?

@tmeasday is it possible to update parameters dynamically, or perhaps we should consider moving to globalArgs instead?

@ndelangen
Copy link
Member

setting the theme is possible at runtime for the manager:

setOptions: (options: any) => {
const { layout, ui, selectedPanel, theme } = store.getState();
if (options) {
const updatedLayout = {
...layout,
...pick(options, Object.keys(layout)),
};
const updatedUi = {
...ui,
...pick(options, Object.keys(ui)),
};
const updatedTheme = {
...theme,
...options.theme,
};
const modification: PartialSubState = {};
if (!deepEqual(ui, updatedUi)) {
modification.ui = updatedUi;
}
if (!deepEqual(layout, updatedLayout)) {
modification.layout = updatedLayout;
}
if (options.selectedPanel && !deepEqual(selectedPanel, options.selectedPanel)) {
modification.selectedPanel = options.selectedPanel;
}
if (Object.keys(modification).length) {
store.setState(modification, { persistence: 'permanent' });
}
if (!deepEqual(theme, updatedTheme)) {
store.setState({ theme: updatedTheme });
}
}
},
};

@hipstersmoothie
Copy link
Contributor

@shilman This is how I have always set the theme for storybook https://github.com/hipstersmoothie/storybook-dark-mode/blob/master/src/Tool.tsx#L90 I'm not sure that theming ever worked with the docs tab (hipstersmoothie/storybook-dark-mode#70) for this addon.

is it possible to update parameters dynamically

This is exactly what I need. I saw the globalArg function but it seems like it was for the new args feature

@tmeasday
Copy link
Member

tmeasday commented May 1, 2020

is it possible to update parameters dynamically

No? I haven't really been following the discussion above but the obvious answer to that question is of course not. That's exactly why we made global args.

@hipstersmoothie
Copy link
Contributor

So the question remains: How can I dynamically theme addon-docs? If it's through global args that's cool. I just read through the doc and it doesn't mention parameters very much.

@shilman
Copy link
Member

shilman commented May 1, 2020

@tmeasday in that case either #10114 was wrong and we should switch to globalArgs (which is possible because we haven't released 6.0 yet), or we should forego dynamic theming in docs. thoughts?

@ndelangen
Copy link
Member

I think it should use global args then?

@tmeasday
Copy link
Member

tmeasday commented May 2, 2020

Yeah, I guess?

I think we’ll likely keep running into challenges deciding if things should be configured via parameters vs global args. Perhaps we should make a pattern where certain things are can be configured both ways.

What do you think folks?

@ndelangen
Copy link
Member

Yeah that seems very very likely to me too tom..

@stale stale bot added the inactive label May 25, 2020
@stale stale bot removed the inactive label May 25, 2020
@shilman shilman added this to the 6.0 docs milestone May 25, 2020
@csardinha
Copy link

hey @shilman, are you planning to include this soon? it would be great! 🙏

@storybookjs storybookjs deleted a comment from stale bot Jun 2, 2020
@shilman shilman modified the milestones: 6.0 docs, 6.0, 6.1 docs Jul 30, 2020
@shilman shilman modified the milestones: 6.1 docs, 6.2 docs Oct 13, 2020
@igloude
Copy link

igloude commented Nov 3, 2020

Bump on this one - would love to see dynamic theming for docs!

@jesse23
Copy link

jesse23 commented Mar 12, 2021

Temp workround - just refresh the iframe:
https://gist.github.com/nfarina/fb708f66858d2d3317877ab8adf8d926

@shilman shilman removed this from the 6.2 docs milestone Jun 8, 2021
@dartess
Copy link
Contributor

dartess commented Nov 29, 2021

@shilman @tmeasday @ndelangen I apologize for mentioning, but have you come to any solution?

Prior to version 6.4 there was a workaround with dynamically installing the theme through the substitution of DocsContainer
props : hipstersmoothie/storybook-dark-mode#127 (comment) . But it doesn't work anymore.

@martijnhalekor
Copy link

Any update on this?

@quantizor
Copy link

@shilman could this be looked at prior to v7 final release? I think there's some machinery missing to get docs to update in tandem with the set storybook theme. Not all the same initialization code seems to be run when loading a docs page vs a component story when it comes to addons?

@shilman
Copy link
Member

shilman commented Mar 29, 2023

@probablyup we'll take a look at things this week. i don't think we'll block the release for it, but depending on how broken it is it's possibly something that we could address in a patch release during stabilization.

@quantizor
Copy link

Thanks @shilman. I think I was able to narrow down the issue to the useParameter() hook from api. It seems to never get the initialized parameters for doc stories, at least until you’ve switched to a component story and then back.

@tmeasday
Copy link
Member

tmeasday commented Apr 3, 2023

#21798 (comment)

@ernestostifano
Copy link

ernestostifano commented Jul 24, 2023

Hello everyone. Having this exact issue. We have managed to integrate all of Storybook's theming with our own theming system ("natively"), but not the docs page (workaround below).

We actually have a custom docs container component, but it gets wrapped with some SB stuff including a background. While you guys are at this, please consider removing any wrapping when a custom docs container is being used.

Our workaround have been to manually override the background as follows:

const useStyles = createUseStyles(({palette}) => ({
    '@global': {
        '.sbdocs-wrapper': {
            // TODO: https://github.com/storybookjs/storybook/issues/10523
            backgroundColor: 'transparent!important'
        },
        html: {
            backgroundColor: palette.background.normal
        },
        body: {
            backgroundColor: palette.background.normal
        }
    }
}));

const Background: FC = () => {
    useStyles();
    return null;
};

const DocsContainer: FC<DocsContainerProps> = (props) => {
    const themeRef = useRef(DEFAULT_THEME_PACK.themes[DEFAULT_THEME_TYPE]);

    const {context} = props;

    const stories = context.componentStories();

    const {globals} = context.getStoryContext(stories[0]);

    const theme = useMemo(() => {
        if (
            (globals as IGlobals).themePackKey &&
            (globals as IGlobals).themeType
        ) {
            themeRef.current = getThemeFromGlobals(globals as IGlobals);
        }

        return themeRef.current;
    }, [globals]);

    return (
        <Unstyled>
            <UDSProvider>
                <ThemeStore theme={theme}>
                    <NotificationsServiceStore>
                        <PromptsServiceStore>
                            <Background />
                            <DocsContainerInternal {...props} />
                            <NotificationsServiceManager />
                            <PromptsServiceManager />
                        </PromptsServiceStore>
                    </NotificationsServiceStore>
                </ThemeStore>
            </UDSProvider>
        </Unstyled>
    );
};

In another related topic, we do something similar in stories decorators (to change the background of the stories automatically based on theme).

We want everything to adjust automatically based on selected theme in toolbar and we have managed to do so, using the latest version of Storybook.

The only remaining issue so far is that (for stories and docs) since the injection of the styles take place "locally", there is always a quick flash when loading stories and docs (from default/initial background).

Your suggested solution should fix this for docs, since the correct value will be used from the beginning, during first render. But stories will continue to have the issue unless you map stories backgrounds to the theme too.

We are currently using the same pattern your background add-on uses.

@r1m
Copy link

r1m commented Jan 18, 2024

My solution for those in Storybook 7.6.
I use the localstorage as a way to pass the current theme to preview with custom DocsContainer.

First create a themed docs container
theme-docs-container.tsx

import { DocsContainer } from '@storybook/blocks'; // !! Not from @storybook/addon-doc
import React, { useEffect, useState } from 'react';
import { getUserPreferedColorTheme } from '../theme';

export const ThemedDocsContainer = ({ children, context, ...rest }) => {
 // getUserPreferedColorTheme : Use localstorage and prefer dark media query to guess the user theme
	const [theme, setTheme] = useState(getUserPreferedColorTheme());
	const handler = () => {
		setTheme(getUserPreferedColorTheme());
	};

	useEffect(() => {
		window.addEventListener('storage', handler);
		return function cleanup() {
			window.removeEventListener('storage', handler);
		};
	});

	return (
		<DocsContainer context={context} {...rest} theme={theme}>
			{children}
		</DocsContainer>
	);
};

Register a new addon that will listen to globals changes.
In manager.tsx

import { addons } from '@storybook/manager-api';
import { GLOBALS_UPDATED } from '@storybook/core-events';
addons.setConfig({
	theme: getUserPreferedColorTheme(),
});
addons.register('auto-theme-switcher', (api) => {
	let currTheme = undefined;
	function updateTheme() {
		const theme = getUserPreferedColorTheme();
		if (theme && currTheme !== theme) {
			currTheme = theme;
			api.setOptions({ theme }); // change theme of manager
			// addons.getChannel().emit(FORCE_RE_RENDER);
		}
	}

	api.on(GLOBALS_UPDATED, ({ globals }) => {
		if (globals.theme) {
			setUserPreferedColorTheme(globals.theme); // Store the value in localstorage
			updateTheme();
		}
	});

	queryWindowMatchMedia().addEventListener('change', () => {
		updateTheme();
	});
});

In preview.tsx add the theme global and change the docs container.

const preview: Preview = {
	globalTypes: {
		theme: {
			description: 'Global theme',
			defaultValue: getUserPreferedColorTheme().name, // My ThemeVars have a `name` property
			toolbar: {
				title: 'Theme',
				items: [
					{ value: 'my-light', right: 'my-light', title: 'Light', icon: 'sun' },
					{ value: 'my-dark', right: 'my-dark', title: 'Dark', icon: 'moon' },
				],
				dynamicTitle: true, // Change title based on selected value
			},
		},
	},
	parameters: {
		docs: {
			container: ThemedDocsContainer, // our custom container
		}
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests