Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Created April 16, 2024 08:13
Show Gist options
  • Save steveruizok/d1bf4f05321fc127fec8a2015c4207d8 to your computer and use it in GitHub Desktop.
Save steveruizok/d1bf4f05321fc127fec8a2015c4207d8 to your computer and use it in GitHub Desktop.
tldraw preload fonts
import { useEffect, useState } from 'react'
export type TLTypeFace = {
url: string
display?: any // FontDisplay
featureSettings?: string
stretch?: string
style?: string
unicodeRange?: string
variant?: string
weight?: string
format?: string
}
export async function preloadFont(id: string, font: TLTypeFace) {
const {
url,
style = 'normal',
weight = '500',
display,
featureSettings,
stretch,
unicodeRange,
variant,
format,
} = font
const descriptors: FontFaceDescriptors = {
style,
weight,
display,
featureSettings,
stretch,
unicodeRange,
// @ts-expect-error why is this here
variant,
}
const fontInstance = new FontFace(id, `url(${url})`, descriptors)
await fontInstance.load()
document.fonts.add(fontInstance)
// @ts-expect-error
fontInstance.$$_url = url
// @ts-expect-error
fontInstance.$$_fontface = `
@font-face {
font-family: ${fontInstance.family};
font-stretch: ${fontInstance.stretch};
font-weight: ${fontInstance.weight};
font-style: ${fontInstance.style};
src: url("${url}") format("${format}")
}`
return fontInstance
}
enum PreloadStatus {
SUCCESS,
FAILED,
WAITING,
}
const usePreloadFont = (id: string, font: TLTypeFace): PreloadStatus => {
const [state, setState] = useState<PreloadStatus>(PreloadStatus.WAITING)
useEffect(() => {
let cancelled = false
setState(PreloadStatus.WAITING)
preloadFont(id, font)
.then(() => {
if (cancelled) return
setState(PreloadStatus.SUCCESS)
})
.catch((err: any) => {
if (cancelled) return
console.error(err)
setState(PreloadStatus.FAILED)
})
return () => {
cancelled = true
}
}, [id, font])
return state
}
const TYPEFACES = {
draw: {
url: `https://www.yourhost.com/Shantell_Sans-Tldrawish.woff2`,
format: 'woff2',
},
serif: {
url: `https://www.yourhost.com/IBMPlexSerif-Medium.woff2`,
format: 'woff2',
},
sansSerif: {
url: `https://www.yourhost.com/IBMPlexSans-Medium.woff2`,
format: 'woff2',
},
monospace: {
url: `https://www.yourhost.com/IBMPlexMono-Medium.woff2`,
format: 'woff2',
},
}
export function usePreloadAssets() {
const results = [
usePreloadFont('tldraw_draw', TYPEFACES.draw),
usePreloadFont('tldraw_serif', TYPEFACES.serif),
usePreloadFont('tldraw_sans', TYPEFACES.sansSerif),
usePreloadFont('tldraw_mono', TYPEFACES.monospace),
]
return {
// If any of the results have errored, then preloading has failed
error: results.some((result) => result === PreloadStatus.FAILED),
// If any of the results are waiting, then we're not done yet
done: !results.some((result) => result === PreloadStatus.WAITING),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment