返回 presentation-ai
fontChecker.ts
根目录 / src / components / ui / font-picker / utils / fontChecker.ts
1 export type FontStyle = "italic" | "normal";
2 export type FontWeight =
3 | 100
4 | 200
5 | 300
6 | 400
7 | 500
8 | 600
9 | 700
10 | 800
11 | 900
12 | 1000;
13
14 export interface CheckLoadedOptions {
15 fontFamily: string;
16 fontStyle?: FontStyle;
17 fontWeight?: FontWeight;
18 timeout?: number;
19 }
20
21 // Check whether a font family is loaded using the browser fonts api.
22 // Returns (true) if font family is loaded. Throws error if not loaded within timeout.
23 export async function checkLoaded({
24 fontFamily,
25 fontStyle,
26 fontWeight,
27 timeout = 500,
28 }: CheckLoadedOptions): Promise<boolean> {
29 const start = Date.now();
30 // ref: https://stackoverflow.com/a/56239226
31 let timeoutId: ReturnType<typeof setTimeout>;
32
33 return new Promise((resolve, reject) => {
34 if (document?.fonts) {
35 const checker = new Promise<boolean>((resolve, reject) => {
36 const check = () => {
37 const now = Date.now();
38 if (now - start >= timeout) {
39 reject(new Error(`Font not loaded within ${timeout} ms`));
40 } else {
41 // ref: https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/check
42 const loaded = document.fonts.check(
43 `${fontStyle ?? ""} ${fontWeight ?? ""} 0 ${fontFamily}`,
44 );
45 if (loaded) {
46 resolve(true);
47 } else {
48 setTimeout(check, 25);
49 }
50 }
51 };
52 check();
53 });
54 const timer = new Promise<boolean>((_resolve, reject) => {
55 timeoutId = setTimeout(
56 () => reject(new Error(`Font not loaded within ${timeout} ms`)),
57 timeout,
58 );
59 });
60 Promise.race<boolean>([timer, checker]).then((value) => {
61 clearTimeout(timeoutId);
62 resolve(value);
63 }, reject);
64 } else {
65 reject(new Error("Fonts API not supported by client"));
66 }
67 });
68 }
69
69 lines TYPESCRIPT