tonai / storybook-addon-themes

MIT License
83 stars 30 forks source link

onChange doesn't trigger #56

Closed nekitk closed 2 years ago

nekitk commented 3 years ago

I'm trying to change html's data attribute on theme change. Looking at docs it seems like I should be able to do it inside onChange function. So I wrote config like this:

export const parameters = {
  themes: {
    default: 'light',
    list: [
      { name: 'light', color: '#FFFFFF' },
      { name: 'dark', color: '#2C2D31' },
    ],
    onChange: (theme) => {
      console.log('THEME:', theme)
      // todo change html's data attr here
    },
  },
}

But when I change theme I don't see any logs and no changes in html's data attributes. Am I not using onChange correctly?

Versions:

@storybook/react@^6.2.7
storybook-addon-themes@6.1.0
tjmusser commented 3 years ago

I'm also having this issue in 6.1.0

Ryuno-Ki commented 3 years ago

Same with storybook-addon-themes@6.1.0 and @storybook/html@6.3.2.

Ryuno-Ki commented 3 years ago

Scratch that. Confused the icons. Thanks https://github.com/tonai/storybook-addon-themes/issues/51#issuecomment-815980623 !

darekkay commented 2 years ago

I'm using Storybook 6.1.0 with addParameters and the onChange event is working fine for me: https://github.com/darekkay/dashboard/commit/c8b68314bb3391da7a154543bf1f479e2bb0e956

addParameters({
  themes: {
    default: "Default",
    list: [
      { name: "Default", color: "#f5f7fb", class: "theme-default" },
      { name: "Dark", color: "#1c1c1c", class: "theme-dark" },
    ],
    onChange: (theme) => {
      const storybookIframe = document.getElementById("storybook-preview-iframe");
      const storybookIframeDocument = storybookIframe.contentDocument || storybookIframe.contentWindow.document;
      storybookIframeDocument.body.dataset.theme = theme?.class.substring(6) || "default";
    },
  },
});
yannickoo commented 2 years ago

@darekkay thank you very much for your addParameters approach. I can confirm that this works 💪

I was adding the themes key inside the exported parameters object but that doesn't seem to work anymore.

wmarques commented 2 years ago

I'm having the same issue and the addParameters approach doesn't work, onChange is still not called... I'm using Angular, does it still work for you @yannickoo @darekkay ?

Thanks !

jeremyzilar commented 2 years ago

Thanks @darekkay!

I am modified my onChange to swap out the value of data-theme in the HTML Element that is the child of the iFrame

export const parameters = {
  themes: {
    default: BonsaiTheme.Old,
    list: [
      { name: BonsaiTheme.Old, class: BonsaiTheme.Old, color: "#009900" },
      { name: BonsaiTheme.Light, class: BonsaiTheme.Light, color: "#000099" },
      { name: BonsaiTheme.Dark, class: BonsaiTheme.Dark, color: "#000000" },
    ],
    onChange: (theme) => {
      const storybookIframe = document.getElementById("storybook-preview-iframe")
      const storybookIframeDocument = storybookIframe.contentDocument || storybookIframe.contentWindow.document
      const storybookHtml = storybookIframeDocument.querySelector("html")
      storybookHtml.setAttribute("data-theme", theme.name)
    },
  },

@wmarques I was able to pass in the parameter for a given story or file via my decorator in preview.js with context.parameters.pageTheme. This lets that story load with a particular default.

export const decorators = [
  (Story, context) => {
    const pageTheme = context.parameters.pageTheme

Next step: Explore how to get Chromatic to snapshot each story under each theme!

wmarques commented 2 years ago

@jeremyzilar thanks for your input. However in my case I need to update some CSS Variables when the theme change and those variables are stored in a JS file.

But the onChange doesn't seem called so I don't know how to do that :(

jasosims commented 1 year ago

Not working for me either. Using addParameters instead of exporting via parameters makes no difference. Either way, the themes are registered, but the onChange callback is never called.

Storybook 6.5.13, React 17.

Instead, I'm using the PostMessage event that gets triggered on the preview frame (this is in preview.js):

window.addEventListener('message', (event) => {
  const data = JSON.parse(event.data)
  if (data.event.type === 'storybook-addon-themes/change') {
    const theme = data.event.args[0]
    // do something here
  }
})

This works okay, but I'm running into an issue where hot reloading causes the Themes addon to reset to the default theme, and when that happens, the above event handler doesn't get called, so it can get out of sync if you use it to manage state.