diff --git a/apps/website/src/docs/components/mdx-components/codeblock/frame-provider.tsx b/apps/website/src/docs/components/mdx-components/codeblock/frame-provider.tsx index cd68ac99c..cd8dda733 100644 --- a/apps/website/src/docs/components/mdx-components/codeblock/frame-provider.tsx +++ b/apps/website/src/docs/components/mdx-components/codeblock/frame-provider.tsx @@ -5,7 +5,7 @@ import weakMemoize from '@emotion/weak-memoize' import { FrameContextConsumer, useFrame } from 'react-frame-component' import { SaasProvider } from '@saas-ui/react' import theme from '../../../../styles/theme' -import { GlobalStyle, useColorMode } from '@chakra-ui/system' +import { ColorMode, GlobalStyle, useColorMode } from '@chakra-ui/system' let memoizedCreateCacheWithContainer = weakMemoize((container: Node) => { let newCache = createCache({ key: 'frame', container }) @@ -26,7 +26,7 @@ export const FrameProvider = (props) => { - + {props.children} ) @@ -35,37 +35,100 @@ export const FrameProvider = (props) => { ) } -const ColorModeScript = () => { - const { document, window } = useFrame() +const ColorModeScript = ({ colorMode }) => { + const { getSystemTheme, setClassName, setDataset } = useColorModeUtils() + + const setColorMode = React.useCallback( + (value: ColorMode | 'system') => { + // + const resolved = value === 'system' ? getSystemTheme() : value + + setClassName(resolved === 'dark') + setDataset(resolved) + }, + [getSystemTheme, setClassName, setDataset] + ) React.useEffect(() => { - try { - if (!document || !window) return - var a = function (c) { - var v = '(prefers-color-scheme: dark)', - h = window.matchMedia(v).matches ? 'dark' : 'light', - r = c === 'system' ? h : c, - o = document.documentElement, - s = document.body, - l = 'chakra-ui-light', - d = 'chakra-ui-dark', - i = r === 'dark' - return ( - s.classList.add(i ? d : l), - s.classList.remove(i ? l : d), - (o.style.colorScheme = r), - (o.dataset.theme = r), - r - ) - }, - n = a, - m = 'dark', - e = 'chakra-ui-color-mode', - t = localStorage.getItem(e) - t ? a(t) : localStorage.setItem(e, a(m)) - } catch (a) { - console.log(a) - } - }, []) + setColorMode(colorMode) + }, [colorMode, setColorMode]) + return null } + +const classNames = { + light: 'chakra-ui-light', + dark: 'chakra-ui-dark', +} + +type UtilOptions = { + preventTransition?: boolean + document?: Document +} + +function useColorModeUtils(options: UtilOptions = {}) { + const { preventTransition = true } = options + + const frame = useFrame() + + const doc = frame?.document ?? document + const win = frame?.window ?? window + + const utils = { + setDataset: (value: ColorMode) => { + const cleanup = preventTransition ? utils.preventTransition() : undefined + doc.documentElement.dataset.theme = value + doc.documentElement.style.colorScheme = value + cleanup?.() + }, + setClassName(dark: boolean) { + doc.body.classList.add(dark ? classNames.dark : classNames.light) + doc.body.classList.remove(dark ? classNames.light : classNames.dark) + }, + query() { + return win.matchMedia('(prefers-color-scheme: dark)') + }, + getSystemTheme(fallback?: ColorMode) { + const dark = utils.query().matches ?? fallback === 'dark' + return dark ? 'dark' : 'light' + }, + addListener(fn: (cm: ColorMode) => unknown) { + const mql = utils.query() + const listener = (e: MediaQueryListEvent) => { + fn(e.matches ? 'dark' : 'light') + } + + if (typeof mql.addListener === 'function') mql.addListener(listener) + else mql.addEventListener('change', listener) + + return () => { + if (typeof mql.removeListener === 'function') + mql.removeListener(listener) + else mql.removeEventListener('change', listener) + } + }, + preventTransition() { + const css = document.createElement('style') + css.appendChild( + document.createTextNode( + `*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}` + ) + ) + doc.head.appendChild(css) + + return () => { + // force a reflow + ;(() => win.getComputedStyle(doc.body))() + + // wait for next tick + requestAnimationFrame(() => { + requestAnimationFrame(() => { + doc.head.removeChild(css) + }) + }) + } + }, + } + + return utils +} diff --git a/apps/website/src/docs/components/mdx-components/codeblock/react-live-block.tsx b/apps/website/src/docs/components/mdx-components/codeblock/react-live-block.tsx index 9d95f0a29..00c34b4bf 100644 --- a/apps/website/src/docs/components/mdx-components/codeblock/react-live-block.tsx +++ b/apps/website/src/docs/components/mdx-components/codeblock/react-live-block.tsx @@ -162,7 +162,7 @@ function ReactLiveBlock({ }, [frameRef, inline]) const frame = inline ? ( - + ) : ( setFrameRef(ref)} width="100%" height="100%"> @@ -200,11 +200,15 @@ function ReactLiveBlock({ width="4px" bg="muted" mx="2" - height="100px" + height="80px" rounded="full" _hover={{ bg: 'primary.500', }} + _focus={{ + outline: 'none', + bg: 'primary.500', + }} /> diff --git a/apps/website/src/pages/docs/components/authentication/auth/usage.mdx b/apps/website/src/pages/docs/components/authentication/auth/usage.mdx index d4515e9d3..6b284d68a 100644 --- a/apps/website/src/pages/docs/components/authentication/auth/usage.mdx +++ b/apps/website/src/pages/docs/components/authentication/auth/usage.mdx @@ -49,14 +49,15 @@ If you need more flexiblity it's possible to use these components directly. The default authentication strategy is `magiclink`. ```jsx center=true height=550px +import { SaasUILogo } from '@saas-ui/assets' import { Card, CardHeader, CardBody } from '@chakra-ui/react' import { Auth } from '@saas-ui/auth' export default function AuthPage() { return ( - - + + @@ -71,14 +72,15 @@ export default function AuthPage() { Using the `type` prop you can switch to password login. ```jsx center=true height=550px +import { SaasUILogo } from '@saas-ui/assets' import { Card, CardHeader, CardBody } from '@chakra-ui/react' import { Auth } from '@saas-ui/auth' export default function AuthPage() { return ( - - + + @@ -93,14 +95,15 @@ export default function AuthPage() { Using the `providers` prop you can add social login buttons. ```jsx center=true height=550px +import { SaasUILogo } from '@saas-ui/assets' import { Card, CardHeader, CardBody } from '@chakra-ui/react' import { Auth } from '@saas-ui/auth' export default function AuthPage() { return ( - - + + - - + + - - + + @@ -173,6 +178,7 @@ export default function AuthPage() { Use the `redirectTo` prop to redirect the user after login. ```jsx center=true height=550px +import { SaasUILogo } from '@saas-ui/assets' import { Card, CardHeader, CardBody } from '@chakra-ui/react' import { useSnackbar } from '@saas-ui/react' import { Auth } from '@saas-ui/auth' @@ -187,8 +193,8 @@ const getAbsoluteUrl = (path: string) => { export default function AuthPage() { return ( - - + + { export default function AuthPage() { return ( - - + + { export default function AuthPage() { return ( - - + + { `useHotkeysShortcut` returns the command value and can be used to show the key combinations to your users. -```jsx inline=true live=false +```jsx center=true inline=true live=false import { Kbd } from '@chakra-ui/react' import { useHotkeysShortcut } from '@saas-ui/react' @@ -246,7 +246,7 @@ The `HotkeysList` component can be used to list all available hotkeys in your ap Press `?` to open the modal. -```jsx inline=true +```jsx center=true inline=true import { Box, Text,