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

Allow for simple switching between light and dark modes #283

Closed
schne324 opened this issue Jul 9, 2021 · 1 comment · Fixed by #292 or #294
Closed

Allow for simple switching between light and dark modes #283

schne324 opened this issue Jul 9, 2021 · 1 comment · Fixed by #292 or #294
Assignees

Comments

@schne324
Copy link
Member

schne324 commented Jul 9, 2021

completely open to feedback but here are our initial thoughts...

Create a generic <CauldronProvider /> which accepts a theme prop ("light" or "dark"). Under-the-hood this will actually instantiate a <ThemeProvider /> and pass the theme prop through. This leaves us open to future enhancements that could benefit from a provider-like state. Consumers can still directly use <ThemeProvider /> if they want.

Prior art

@scurker
Copy link
Member

scurker commented Jul 12, 2021

We still need to decide how we want components to utilize the theme.

The way we currently do this in extension is components use cascading based on a theme-dark class on the body. We probably don't want something so generic as that could conflict with consumer things so we may want a more specific name along with allowing it to be customized.

Some example code as follows:

const ThemeProvider = function({
  children,
  context = document.body,
  initialTheme = 'light',
  themeClasses = {
    light: 'cauldron--theme-light',
    dark: 'cauldron--theme-dark'
  }
}) {
  const [theme, setTheme] = useState(initialTheme)
  const getThemeFromContext = () => 
    context.classList.contains(classes.dark) 
      ? 'dark'
      : 'light' 
  const toggleTheme = () => 
    setTheme(
      getThemeFromContext() === 'dark' ? 'light' : 'dark'
    )

  useEffect(() => {
    context.classList.toggle(classes.light, theme === 'light')
    context.classList.toggle(classes.dark, theme === 'dark')
  }, [context, theme])

  // Use a MutationObserver to track changes to the classes outside of the context of React
  const handleMutation = mutationList => {
    for (const mutation of mutationList) {
      if (
        mutation.type === 'attributes' &&
        mutation.attributeName === 'class'
      ) {
        setTheme(getThemeFromContext())
      }
    }
  }

  useEffect(() => {
    const observer = new MutationObserver(handleMutation)
    observer.observe(context, {
      childList: false,
      subtree: false,
      attributes: true
    })

    setTheme(getThemeFromContext())

    return () => observer.disconnect()
  }, [context])

  return (
    <ThemeContext.Provider
      value={{
        theme,
        toggleTheme
      }}
    >
      {children}
    </ThemeContext.Provider>
  )
}

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

Successfully merging a pull request may close this issue.

2 participants