From 9226671f49b507ce6f71e6e2c3621014f05f74e9 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 23 Mar 2022 22:05:30 +0100 Subject: refactor: load prism plugins without babel --- src/utils/helpers/prism.ts | 21 +++-- src/utils/providers/prism-theme.tsx | 165 ++++++++++++++++++++++++++++++++++++ src/utils/providers/prism.tsx | 161 ----------------------------------- 3 files changed, 175 insertions(+), 172 deletions(-) create mode 100644 src/utils/providers/prism-theme.tsx delete mode 100644 src/utils/providers/prism.tsx (limited to 'src/utils') diff --git a/src/utils/helpers/prism.ts b/src/utils/helpers/prism.ts index bc84c91..a5f5787 100644 --- a/src/utils/helpers/prism.ts +++ b/src/utils/helpers/prism.ts @@ -17,19 +17,18 @@ export const addPrismClasses = () => { const preTags = document.getElementsByTagName('pre'); Array.from(preTags).forEach((preTag) => { - if ( - isLanguageBlock(preTag.classList) && - !preTag.classList.contains('command-line') && - !preTag.classList.contains('language-diff') - ) { - preTag.classList.add('line-numbers', 'match-braces'); - } + if (!isLanguageBlock(preTag.classList)) return; + + preTag.classList.add('match-braces'); - if ( - preTag.classList.contains('command-line') && - preTag.classList.contains('filter-output') - ) { + if (preTag.classList.contains('filter-output')) { preTag.setAttribute('data-filter-output', '#output#'); } + + if (preTag.classList.contains('language-bash')) { + preTag.classList.add('command-line'); + } else if (!preTag.classList.contains('language-diff')) { + preTag.classList.add('line-numbers'); + } }); }; diff --git a/src/utils/providers/prism-theme.tsx b/src/utils/providers/prism-theme.tsx new file mode 100644 index 0000000..2ed8454 --- /dev/null +++ b/src/utils/providers/prism-theme.tsx @@ -0,0 +1,165 @@ +import { LocalStorage } from '@services/local-storage'; +import { + createContext, + FC, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; + +export type PrismTheme = 'dark' | 'light' | 'system'; +export type ResolvedPrismTheme = 'dark' | 'light'; + +export type UsePrismThemeProps = { + themes: PrismTheme[]; + theme?: PrismTheme; + setTheme: (theme: PrismTheme) => void; + resolvedTheme?: ResolvedPrismTheme; + codeBlocks?: NodeListOf; + setCodeBlocks: (codeBlocks: NodeListOf) => void; +}; + +export type PrismThemeProviderProps = { + attribute?: string; + storageKey?: string; + themes?: PrismTheme[]; +}; + +export const PrismThemeContext = createContext({ + themes: ['dark', 'light', 'system'], + setTheme: (_) => { + // This is intentional. + }, + setCodeBlocks: (_) => { + // This is intentional. + }, +}); + +export const usePrismTheme = () => useContext(PrismThemeContext); + +const prefersDarkScheme = () => { + if (typeof window === 'undefined') return; + + return ( + window.matchMedia && + window.matchMedia('(prefers-color-scheme: dark)').matches + ); +}; + +const isValidTheme = (theme: string): boolean => { + return theme === 'dark' || theme === 'light' || theme === 'system'; +}; + +const getTheme = (key: string): PrismTheme | undefined => { + if (typeof window === 'undefined') return undefined; + const storageValue = LocalStorage.get(key); + + return storageValue && isValidTheme(storageValue) + ? (storageValue as PrismTheme) + : undefined; +}; + +export const PrismThemeProvider: FC = ({ + attribute = 'data-prismjs-color-scheme-current', + storageKey = 'prismjs-color-scheme', + themes = ['dark', 'light', 'system'], + children, +}) => { + const getThemeFromSystem = useCallback(() => { + return prefersDarkScheme() ? 'dark' : 'light'; + }, []); + + const [prismTheme, setPrismTheme] = useState( + getTheme(storageKey) || 'system' + ); + + const updateTheme = (theme: PrismTheme) => { + setPrismTheme(theme); + }; + + useEffect(() => { + LocalStorage.set(storageKey, prismTheme); + }, [prismTheme, storageKey]); + + const [resolvedTheme, setResolvedTheme] = useState(); + + useEffect(() => { + if (prismTheme === 'dark' || prismTheme === 'light') { + setResolvedTheme(prismTheme); + } else { + setResolvedTheme(getThemeFromSystem()); + } + }, [prismTheme, getThemeFromSystem]); + + const updateResolvedTheme = useCallback(() => { + setResolvedTheme(getThemeFromSystem()); + }, [getThemeFromSystem]); + + useEffect(() => { + window + .matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', updateResolvedTheme); + + return () => + window + .matchMedia('(prefers-color-scheme: dark)') + .removeEventListener('change', updateResolvedTheme); + }, [updateResolvedTheme]); + + const [preTags, setPreTags] = useState>(); + + const updatePreTags = useCallback((tags: NodeListOf) => { + setPreTags(tags); + }, []); + + const updatePreTagsAttribute = useCallback(() => { + preTags?.forEach((pre) => { + pre.setAttribute(attribute, prismTheme); + }); + }, [attribute, preTags, prismTheme]); + + useEffect(() => { + updatePreTagsAttribute(); + }, [updatePreTagsAttribute, prismTheme]); + + const listenAttributeChange = useCallback( + (pre: HTMLPreElement) => { + var observer = new MutationObserver(function (mutations) { + mutations.forEach((record) => { + var mutatedPre = record.target as HTMLPreElement; + var newTheme = mutatedPre.getAttribute(attribute) as PrismTheme; + setPrismTheme(newTheme); + }); + }); + observer.observe(pre, { + attributes: true, + attributeFilter: [attribute], + }); + }, + [attribute] + ); + + useEffect(() => { + if (!preTags) return; + + preTags.forEach((pre) => { + listenAttributeChange(pre); + }); + }, [preTags, listenAttributeChange]); + + return ( + + {children} + + ); +}; diff --git a/src/utils/providers/prism.tsx b/src/utils/providers/prism.tsx deleted file mode 100644 index 7a4221d..0000000 --- a/src/utils/providers/prism.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { LocalStorage } from '@services/local-storage'; -import { - createContext, - FC, - useCallback, - useContext, - useEffect, - useState, -} from 'react'; - -export type PrismTheme = 'dark' | 'light' | 'system'; -export type ResolvedPrismTheme = 'dark' | 'light'; - -export type UsePrismThemeProps = { - themes: PrismTheme[]; - theme?: PrismTheme; - setTheme: (theme: PrismTheme) => void; - resolvedTheme?: ResolvedPrismTheme; - codeBlocks?: NodeListOf; - setCodeBlocks: (codeBlocks: NodeListOf) => void; -}; - -export type PrismThemeProviderProps = { - attribute?: string; - storageKey?: string; - themes?: PrismTheme[]; -}; - -export const PrismThemeContext = createContext({ - themes: ['dark', 'light', 'system'], - setTheme: (_) => {}, - setCodeBlocks: (_) => {}, -}); - -export const usePrismTheme = () => useContext(PrismThemeContext); - -const prefersDarkScheme = () => { - if (typeof window === 'undefined') return; - - return ( - window.matchMedia && - window.matchMedia('(prefers-color-scheme: dark)').matches - ); -}; - -const isValidTheme = (theme: string): boolean => { - return theme === 'dark' || theme === 'light' || theme === 'system'; -}; - -const getTheme = (key: string): PrismTheme | undefined => { - if (typeof window === 'undefined') return undefined; - const storageValue = LocalStorage.get(key); - - return storageValue && isValidTheme(storageValue) - ? (storageValue as PrismTheme) - : undefined; -}; - -export const PrismThemeProvider: FC = ({ - attribute = 'data-prismjs-color-scheme-current', - storageKey = 'prismjs-color-scheme', - themes = ['dark', 'light', 'system'], - children, -}) => { - const getThemeFromSystem = useCallback(() => { - return prefersDarkScheme() ? 'dark' : 'light'; - }, []); - - const [prismTheme, setPrismTheme] = useState( - getTheme(storageKey) || 'system' - ); - - const updateTheme = (theme: PrismTheme) => { - setPrismTheme(theme); - }; - - useEffect(() => { - LocalStorage.set(storageKey, prismTheme); - }, [prismTheme, storageKey]); - - const [resolvedTheme, setResolvedTheme] = useState(); - - useEffect(() => { - if (prismTheme === 'dark' || prismTheme === 'light') { - setResolvedTheme(prismTheme); - } else { - setResolvedTheme(getThemeFromSystem()); - } - }, [prismTheme, getThemeFromSystem]); - - const updateResolvedTheme = useCallback(() => { - setResolvedTheme(getThemeFromSystem()); - }, [getThemeFromSystem]); - - useEffect(() => { - window - .matchMedia('(prefers-color-scheme: dark)') - .addEventListener('change', updateResolvedTheme); - - return () => - window - .matchMedia('(prefers-color-scheme: dark)') - .removeEventListener('change', updateResolvedTheme); - }, [updateResolvedTheme]); - - const [preTags, setPreTags] = useState>(); - - const updatePreTags = useCallback((tags: NodeListOf) => { - setPreTags(tags); - }, []); - - const updatePreTagsAttribute = useCallback(() => { - preTags?.forEach((pre) => { - pre.setAttribute(attribute, prismTheme); - }); - }, [attribute, preTags, prismTheme]); - - useEffect(() => { - updatePreTagsAttribute(); - }, [updatePreTagsAttribute, prismTheme]); - - const listenAttributeChange = useCallback( - (pre: HTMLPreElement) => { - var observer = new MutationObserver(function (mutations) { - mutations.forEach((record) => { - var mutatedPre = record.target as HTMLPreElement; - var newTheme = mutatedPre.getAttribute(attribute) as PrismTheme; - setPrismTheme(newTheme); - }); - }); - observer.observe(pre, { - attributes: true, - attributeFilter: [attribute], - }); - }, - [attribute] - ); - - useEffect(() => { - if (!preTags) return; - - preTags.forEach((pre) => { - listenAttributeChange(pre); - }); - }, [preTags, listenAttributeChange]); - - return ( - - {children} - - ); -}; -- cgit v1.2.3