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

Ability to force a color mode for a specific component subtree #316

Open
quantizor opened this issue Oct 8, 2021 · 5 comments
Open

Ability to force a color mode for a specific component subtree #316

quantizor opened this issue Oct 8, 2021 · 5 comments

Comments

@quantizor
Copy link
Collaborator

The ColorModeProvider component currently enables color shifting in general, but as far as I can tell there is no way to explicitly force a particular color mode for a given subtree. The use case I'm working on is there are particular screens where the insides are meant to use a dark style, but the outer UI is normal 🤷🏼

@sctgraham
Copy link

sctgraham commented Feb 3, 2022

This would be great, I could really use this too. +1
Did you happen to find a work around to achieve something similar ?

@quantizor
Copy link
Collaborator Author

quantizor commented Feb 4, 2022

@sctgraham this is what I came up with:

const XSTYLED_CLASS_PREFIX = 'xstyled-color-mode-';
const ColorModeContext = React.createContext<DSIColorModes>('light');

/**
 * Composes the typical `<ThemeProvider>` with some goodies. This wrapper should be placed at the root of your application.
 */
export function DSStyleProvider({
  children,
  colorMode = 'light',
  theme,
}: React.PropsWithChildren<{
  /**
   * Forces a particular color mode.
   */
  colorMode?: 'light' | 'dark';
  theme: DSITheme;
}>) {
  const Wrapper = (() => {
    switch (colorMode) {
      case 'dark':
        return DSDarkModeProvider;
      default:
        return DSLightModeProvider;
    }
  })();

  return (
    <ThemeProvider
      // @ts-expect-error need to make ThemeProvider less restrictive
      theme={theme}
    >
      <ColorModeProvider targetSelector={`[class*="${XSTYLED_CLASS_PREFIX}"]`}>
        <Wrapper>
          {children}
        </Wrapper>
      </ColorModeProvider>
    </ThemeProvider>
  );
}

/**
 * This wrapper forces on dark mode for a particular component subtree. Note that color mode shifting is not enabled by default
 * in DSP (controlled by the `useColorSchemeMediaQuery` theme variable) for UX reasons; dark mode is currently reserved for specific
 * interfaces like CAD view.
 */
 export function DSDarkModeProvider({ children }: React.PropsWithChildren<{}>) {
  return (
    <ColorModeContext.Provider value="dark">
      <x.div className={`${XSTYLED_CLASS_PREFIX}dark`} display="contents">
        {children}
      </x.div>
    </ColorModeContext.Provider>
  );
}

/**
 * This wrapper forces on light mode for a particular component subtree. Note that color mode shifting is not enabled by default
 * in DSP (controlled by the `useColorSchemeMediaQuery` theme variable) for UX reasons.
 *
 * You should pretty much never need to use this component, but it is included with the library for completeness.
 */
export function DSLightModeProvider({ children }: React.PropsWithChildren<{}>) {
  return (
    <ColorModeContext.Provider value="light">
      <x.div className={`${XSTYLED_CLASS_PREFIX}light`} display="contents">
        {children}
      </x.div>
    </ColorModeContext.Provider>
  );
}

/**
 * Replacement for xstyled's `useColorMode` that pays attention to component
 * subtrees.
 */
export function useColorMode() {
  return React.useContext(ColorModeContext);
}

@quantizor
Copy link
Collaborator Author

@gregberge you might want to steal this impl, it's been working great in our design system

@sctgraham
Copy link

Sweet ! Thanks for taking the time. I'll dig into this and see how it goes. Great use of display:contents btw.

@quantizor
Copy link
Collaborator Author

@sctgraham just a heads up I updated my example with a revised targetSelector

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

No branches or pull requests

2 participants