Skip to content

Instantly share code, notes, and snippets.

@magicspon
Last active March 9, 2022 21:29
Show Gist options
  • Save magicspon/7e9c7283240b9d8a093ff0ae29c07a25 to your computer and use it in GitHub Desktop.
Save magicspon/7e9c7283240b9d8a093ff0ae29c07a25 to your computer and use it in GitHub Desktop.
useFontPicker
/* based on https://github.com/samuelmeuli/font-picker-react */
import * as React from 'react'
import {
Font,
FontList,
FontManager,
Options,
OPTIONS_DEFAULTS,
} from '@lib/font-manager'
type LoadingStatus = 'loading' | 'finished' | 'error'
function getFontId(fontFamily: string): string {
return fontFamily.replace(/\s+/g, '-').toLowerCase()
}
interface Props {
activeFontFamily?: string
onChange?: (font: Font) => void
}
const defaults: Options = {
pickerId: OPTIONS_DEFAULTS.pickerId,
families: OPTIONS_DEFAULTS.families,
categories: OPTIONS_DEFAULTS.categories,
scripts: OPTIONS_DEFAULTS.scripts,
variants: ['300'],
filter: OPTIONS_DEFAULTS.filter,
limit: OPTIONS_DEFAULTS.limit,
sort: OPTIONS_DEFAULTS.sort,
}
function useFontManager(
{ activeFontFamily, onChange }: Props,
options: Options,
) {
const [fontManager, setFontManager] = React.useState<FontManager>()
React.useEffect(() => {
if (typeof window !== 'undefined') {
setFontManager(
new FontManager(
process.env.NEXT_PUBLIC_GOOGLE_FONT_API_KEY!,
activeFontFamily,
options,
onChange,
),
)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return fontManager
}
function parseFonts(fonts: FontList, selectorSuffix: string) {
return Array.from(fonts.values())
.sort((font1, font2) => font1.family.localeCompare(font2.family))
.map((font) => ({
...font,
fontId: `font-button-${getFontId(font.family)}${selectorSuffix}`,
}))
}
const defaultFont = {
family: 'Open Sans',
id: 'open-sans',
}
function useFontPicker(options: Options = defaults) {
const [activeFont, setFontFamily] = React.useState<Partial<Font>>(defaultFont)
const pickFont = React.useCallback((font) => {
setFontFamily(font)
}, [])
const fontManager = useFontManager(
{ activeFontFamily: activeFont.family, onChange: pickFont },
options,
)
const [status, setLoading] = React.useState<LoadingStatus>('loading')
React.useEffect(() => {
if (fontManager && status !== 'finished') {
fontManager
.init()
.then(() => {
setLoading('finished')
})
.catch((e) => {
setLoading('error')
console.log(e)
})
}
}, [fontManager, status])
React.useEffect(() => {
if (fontManager && activeFont) {
fontManager.setActiveFont(activeFont.family!)
}
}, [fontManager, activeFont])
const fonts = React.useMemo(() => {
if (fontManager && status === 'finished') {
return parseFonts(fontManager.getFonts(), fontManager.selectorSuffix)
} else {
return []
}
}, [fontManager, status])
return {
fonts,
pickFont,
status,
activeFont,
}
}
export default useFontPicker
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment