question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature Request: Support for storybook

See original GitHub issue

Thanks for the library! It’s very well rounded and more polished than what I was doing on my own.

I’m looking to integrate this library with storybook for my application. When I was using my own theme provider example repo here which is heavily based on this blog post which provides the same solution this repo seeks to encapsulate in a library (i.e. inject script into head to run theme logic before first paint), I was able to easily integrate this with storybook globals. I went a step further to allow for stories to declare they want to be rendered with a certain theme by default with the following preview.js:

import React, { useLayoutEffect } from 'react'
import { usePrevious } from 'react-use'
import { addons } from '@storybook/addons'
import { UPDATE_GLOBALS } from '@storybook/core-events'
import { ThemeContext, updateTheme } from 'components/Theme'

export const globalTypes = {
  theme: {
    name: 'Theme',
    description: 'Color theme',
    defaultValue: 'light',
    toolbar: {
      icon: 'paintbrush',
      items: [
        { value: 'light', title: 'Light' },
        { value: 'dark', title: 'Dark' }
      ]
    }
  }
}

const updateThemeGlobal = theme =>
  addons.getChannel().emit(UPDATE_GLOBALS, {
    globals: { theme }
  })

export const decorators = [
  (Story, { globals, parameters }) => {
    const previousParametersTheme = usePrevious(parameters.theme)

    useLayoutEffect(() => {
      if (
        previousParametersTheme !== parameters.theme &&
        globals.theme !== parameters.theme
      ) {
        updateThemeGlobal(parameters.theme)
      } else {
        updateTheme(globals.theme)
      }
    }, [globals.theme, parameters.theme])

    return (
      <ThemeContext.Provider
        value={{
          theme: globals.theme,
          setTheme: updateThemeGlobal
        }}
      >
        <Story />
      </ThemeContext.Provider>
    )
  }
]

export const parameters = {
  theme: 'light'
}

I would like to accomplish something similar with this repo. i.e. allow outside code to force the theme and allow a custom version of the set theme function so we can keep the globals in sync.

The context object isn’t exported from this repo which would allow me to do all of this (alas, I would have to reimplement the logic to “set” the theme onto the dom unless that logic was also exported).

I tried to get a partial solution by using the forceTheme prop on the provider as follows, but that didn’t work either. It stayed on light mode even though the global was being reset causing a rerender.

  (Story, { globals }) => {
    return (
      <ThemeProvider
        forcedTheme={globals.theme}
        attribute="class"
        storageKey="themePreference"
      >
        <Story />
      </ThemeProvider>
    )
  }

Is exporting the context object and dom update logic the best solution or is there a better way to achieve what I’m doing?

Thanks for the help and your time; it’s greatly appreciated.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:5
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
natasha08ncommented, Sep 2, 2022

I managed to make theme changeable in toolbar in storybook

in preview.js

export const globalTypes = {
  theme: {
    name: 'Theme',
    description: 'Global theme for components',
    defaultValue: 'light',
    toolbar: {
      items: ['light', 'dark'],
      showName: true,
      dynamicTitle: true,
    },
  },
};

and also I added decorator in the same file

export const decorators = [withStyle];

And here is withStyle.tsx file

import { FC } from 'react';
import { ColorThemeProvider } from 'modules/styleSystem';

export function withStyle(Story: FC, context: any) {
  return (
    <ColorThemeProvider forcedTheme={context.globals.theme}>
        <Story />
    </ColorThemeProvider>
  );
}

And this is my ColorThemeProvider

import { PropsWithChildren } from 'react';
import { ThemeProvider as NextThemeProvider } from 'next-themes';

export const ColorThemeProvider = ({
  forcedTheme,
  ...props
}: PropsWithChildren<{ forcedTheme?: 'light' | 'dark' }>) => {
  return (
    <NextThemeProvider themes={['light', 'dark']} {...(forcedTheme ? { forcedTheme } : {})}>
      {props.children}
    </NextThemeProvider>
  );
};

Please let me know if it works for you guys

https://user-images.githubusercontent.com/14089769/188206877-67ca94c3-0e30-4384-945b-c638d3d320bc.mov

0reactions
olajcommented, Oct 6, 2022

I used a combination of the above.

// ThemeChanger.tsx
import React from "react";
import { useTheme } from "next-themes";
import { useEffect } from "react";

const ThemeChanger = ({ theme }: { theme: "modern" | "dark" | "classic" }) => {
  const { setTheme } = useTheme();

  useEffect(() => {
    console.log(theme, "theme");
    setTheme(theme);
  }, [setTheme, theme]);

  return null;
};

export default React.memo(ThemeChanger);
//preview.js
import "../public/static/global-styles.scss";
import { ThemeProvider } from "next-themes";
import ThemeChanger from "./ThemeChanger";

export const globalTypes = {
  theme: {
    name: "Theme",
    description: "Global theme for components",
    defaultValue: "modern",
    toolbar: {
      items: ["modern", "dark", "classic"],
      showName: true,
      dynamicTitle: true,
    },
  },
};

export const decorators = [
  (Story, { globals }) => (
    <ThemeProvider>
      <ThemeChanger theme={globals.theme ? globals.theme : "modern"} />
      <Story />
    </ThemeProvider>
  ),
];

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

The example from @fede-rodes didn’t include a “toolbar switcher” and i grabbed that from @natasha08n example and made some minor changes. Works for me!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Feature support for frameworks - Storybook
If you'd like a certain feature supported in your framework, we welcome pull requests. Core frameworks. Core frameworks have dedicated maintainers or ...
Read more >
Issue #20077 · storybookjs/storybook - Feature Request - GitHub
I want the storybook to be able to work from outside the project or from a subfolder. Like a separate project. And i...
Read more >
Feature request - zeroheight forum
Feature request · Tables Improvement: Drag to Reorder · More Granular Control of Storybook URL Params · Add custom CSS · Can Item...
Read more >
Workday Canvas Kit
Feature Requests. If you have an idea, we would love to hear about it. The best way to suggest a feature is to...
Read more >
Contribute - React Spectrum Libraries - Adobe
If you have a feature request, you can use our Feature Request issue template. ... There are many places to dive into react-spectrum...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found