/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import React from 'react'; import clsx from 'clsx'; import useIsBrowser from '@docusaurus/useIsBrowser'; import {useColorMode} from '../../contexts/colorMode'; import styles from './styles.module.css'; const AllThemes = ['light', 'dark'] as const; type Theme = (typeof AllThemes)[number]; type RenderFn = ({ theme, className, }: { theme: Theme; className: string; }) => React.ReactNode; type Props = { children: RenderFn; className?: string; }; /** * Generic component to render anything themed in light/dark * Note: it's preferable to use CSS for theming because this component * will need to render all the variants during SSR to avoid a theme flash. * * Use this only when CSS customizations are not convenient or impossible. * For example, rendering themed images or SVGs... * * @param className applied to all the variants * @param children function to render a theme variant * @constructor */ export default function ThemedComponent({ className, children, }: Props): JSX.Element { const isBrowser = useIsBrowser(); const {colorMode} = useColorMode(); function getThemesToRender(): Theme[] { if (isBrowser) { return colorMode === 'dark' ? ['dark'] : ['light']; } // We need to render both components on the server / hydration to avoid: // - a flash of wrong theme before hydration // - React hydration mismatches // See https://github.com/facebook/docusaurus/pull/3730 return ['light', 'dark']; } return ( <> {getThemesToRender().map((theme) => { const themedElement = children({ theme, className: clsx( className, styles.themedComponent, styles[`themedComponent--${theme}`], ), }); return {themedElement}; })} ); }