返回 marp
useFontFace.tsx
根目录 / website / utils / hooks / useFontFace.tsx
1 import { createContext, useContext, useEffect, useMemo, useState } from 'react'
2
3 interface FontFaceContextInterface {
4 styles: readonly string[]
5 setStyles: (styles: string[] | ((styles: string[]) => string[])) => void
6 }
7
8 const FontFaceContext = createContext<FontFaceContextInterface>({
9 styles: [],
10 setStyles: () => {
11 throw new Error('Required wrapping by <FontFaceProvider>.')
12 },
13 })
14
15 export const useFontFace = (fonts: string | string[]) => {
16 const fnts = useMemo(() => ([] as string[]).concat(fonts), [fonts])
17 const { setStyles } = useContext(FontFaceContext)
18
19 useEffect(() => {
20 setStyles((styles) => [...styles, ...fnts])
21
22 return () => {
23 const _fnts = [...fnts]
24
25 setStyles((styles) =>
26 styles.filter((existingStyle) => {
27 const fntIdx = _fnts.indexOf(existingStyle)
28 if (fntIdx >= 0) _fnts.splice(fntIdx, 1)
29
30 return fntIdx !== -1
31 })
32 )
33 }
34 }, [fnts, setStyles])
35 }
36
37 // eslint-disable-next-line @typescript-eslint/ban-types
38 export const FontFaceProvider: React.FC<React.PropsWithChildren<{}>> = ({
39 children,
40 }) => {
41 const [styles, setStyles] = useState<string[]>([])
42
43 return (
44 <FontFaceContext.Provider value={{ styles, setStyles }}>
45 {children}
46 </FontFaceContext.Provider>
47 )
48 }
49
50 export const FontFaceRenderer = () => {
51 const { styles } = useContext(FontFaceContext)
52
53 return (
54 <>
55 {[...new Set(styles)]
56 .filter((style) => !!style)
57 .map((style) => (
58 <style data-type="marp-font-face" key={style}>
59 {style}
60 </style>
61 ))}
62 </>
63 )
64 }
65
65 lines Plain Text