diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-10-26 19:07:31 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-11 18:15:27 +0100 |
| commit | 795b92cc1a168c48c7710ca6e0e1ef5974013d95 (patch) | |
| tree | 8f57204b0ffe7c8acb3203a24292f375377b6369 /src/utils/providers | |
| parent | 9aeb82269d7c74c4566b7ca254782a4dfbd69a6e (diff) | |
refactor(hooks): rewrite useLocalStorage hook
* return a tuple instead of an object
* add a validator function as parameter (if the stored value
is manually changed, it is not safe to cast its type)
* add tests
Diffstat (limited to 'src/utils/providers')
| -rw-r--r-- | src/utils/providers/prism-theme.tsx | 61 |
1 files changed, 35 insertions, 26 deletions
diff --git a/src/utils/providers/prism-theme.tsx b/src/utils/providers/prism-theme.tsx index c063bd5..603e8a7 100644 --- a/src/utils/providers/prism-theme.tsx +++ b/src/utils/providers/prism-theme.tsx @@ -1,11 +1,13 @@ +/* eslint-disable max-statements */ import { createContext, - FC, - ReactNode, + type FC, + type ReactNode, useCallback, useContext, useEffect, useState, + useMemo, } from 'react'; import { useAttributes, useLocalStorage, useQuerySelectorAll } from '../hooks'; @@ -42,12 +44,9 @@ export const usePrismTheme = () => useContext(PrismThemeContext); * @returns {boolean|undefined} True if `prefers-color-scheme` is set to `dark`. */ const prefersDarkScheme = (): boolean | undefined => { - if (typeof window === 'undefined') return; + if (typeof window === 'undefined') return undefined; - return ( - window.matchMedia && - window.matchMedia('(prefers-color-scheme: dark)').matches - ); + return window.matchMedia('(prefers-color-scheme: dark)').matches; }; /** @@ -56,25 +55,33 @@ const prefersDarkScheme = (): boolean | undefined => { * @param {string} theme - A string. * @returns {boolean} True if the given string match a Prism theme name. */ -const isValidTheme = (theme: string): boolean => { - return theme === 'dark' || theme === 'light' || theme === 'system'; -}; +const isValidTheme = (theme: string): boolean => + theme === 'dark' || theme === 'light' || theme === 'system'; + +const defaultThemes = ['dark', 'light', 'system'] satisfies PrismTheme[]; + +const validator = (value: unknown): value is PrismTheme => + typeof value === 'string' && (defaultThemes as string[]).includes(value); export const PrismThemeProvider: FC<PrismThemeProviderProps> = ({ attribute = 'data-prismjs-color-scheme-current', storageKey = 'prismjs-color-scheme', - themes = ['dark', 'light', 'system'], + themes = defaultThemes, children, }) => { /** * Retrieve the theme to use depending on `prefers-color-scheme`. */ const getThemeFromSystem = useCallback(() => { - return prefersDarkScheme() ? 'dark' : 'light'; + if (prefersDarkScheme()) return 'dark'; + return 'light'; }, []); - const { value: prismTheme, setValue: setPrismTheme } = - useLocalStorage<PrismTheme>(storageKey, 'system'); + const [prismTheme, setPrismTheme] = useLocalStorage<PrismTheme>( + storageKey, + 'system', + validator + ); useEffect(() => { if (!isValidTheme(prismTheme)) setPrismTheme('system'); @@ -113,10 +120,10 @@ export const PrismThemeProvider: FC<PrismThemeProviderProps> = ({ */ const listenAttributeChange = useCallback( (pre: HTMLPreElement) => { - var observer = new MutationObserver(function (mutations) { + const observer = new MutationObserver((mutations) => { mutations.forEach((record) => { - var mutatedPre = record.target as HTMLPreElement; - var newTheme = mutatedPre.getAttribute(attribute) as PrismTheme; + const mutatedPre = record.target as HTMLPreElement; + const newTheme = mutatedPre.getAttribute(attribute) as PrismTheme; setPrismTheme(newTheme); }); }); @@ -133,16 +140,18 @@ export const PrismThemeProvider: FC<PrismThemeProviderProps> = ({ preTags.forEach(listenAttributeChange); }, [preTags, listenAttributeChange]); + const value = useMemo(() => { + return { + themes, + theme: prismTheme, + setTheme: setPrismTheme, + codeBlocks: preTags, + resolvedTheme, + }; + }, [preTags, prismTheme, resolvedTheme, setPrismTheme, themes]); + return ( - <PrismThemeContext.Provider - value={{ - themes, - theme: prismTheme, - setTheme: setPrismTheme, - codeBlocks: preTags, - resolvedTheme, - }} - > + <PrismThemeContext.Provider value={value}> {children} </PrismThemeContext.Provider> ); |
