@flighthq/font 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fontFormat.d.ts +2 -1
- package/dist/fontFormat.d.ts.map +1 -1
- package/dist/fontFormat.js +25 -1
- package/dist/fontFormat.js.map +1 -1
- package/dist/fontFrom.d.ts.map +1 -1
- package/dist/fontFrom.js +4 -3
- package/dist/fontFrom.js.map +1 -1
- package/dist/fontResourceFrom.d.ts.map +1 -1
- package/dist/fontResourceFrom.js +4 -3
- package/dist/fontResourceFrom.js.map +1 -1
- package/dist/fontShorthand.d.ts +2 -0
- package/dist/fontShorthand.d.ts.map +1 -0
- package/dist/fontShorthand.js +7 -0
- package/dist/fontShorthand.js.map +1 -0
- package/dist/fontStatus.d.ts +3 -0
- package/dist/fontStatus.d.ts.map +1 -0
- package/dist/fontStatus.js +8 -0
- package/dist/fontStatus.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
- package/src/fontFormat.test.ts +64 -12
- package/src/fontFrom.test.ts +93 -1
- package/src/fontShorthand.test.ts +23 -0
- package/src/fontStatus.test.ts +49 -0
package/dist/fontFormat.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function detectFontFormat(bytes: ArrayBuffer | Uint8Array): string | null;
|
|
2
|
+
export declare function inferFontFormatFromUrl(url: string): string | null;
|
|
2
3
|
//# sourceMappingURL=fontFormat.d.ts.map
|
package/dist/fontFormat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontFormat.d.ts","sourceRoot":"","sources":["../src/fontFormat.ts"],"names":[],"mappings":"AAAA,wBAAgB,
|
|
1
|
+
{"version":3,"file":"fontFormat.d.ts","sourceRoot":"","sources":["../src/fontFormat.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CAuB/E;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBjE"}
|
package/dist/fontFormat.js
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function detectFontFormat(bytes) {
|
|
2
|
+
const b = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
3
|
+
if (b.byteLength < 4)
|
|
4
|
+
return null;
|
|
5
|
+
// sfnt version 0x00010000 → TrueType outlines
|
|
6
|
+
if (b[0] === 0x00 && b[1] === 0x01 && b[2] === 0x00 && b[3] === 0x00)
|
|
7
|
+
return 'truetype';
|
|
8
|
+
// 'OTTO' → CFF/OpenType outlines
|
|
9
|
+
if (b[0] === 0x4f && b[1] === 0x54 && b[2] === 0x54 && b[3] === 0x4f)
|
|
10
|
+
return 'opentype';
|
|
11
|
+
// 'wOFF' → WOFF
|
|
12
|
+
if (b[0] === 0x77 && b[1] === 0x4f && b[2] === 0x46 && b[3] === 0x46)
|
|
13
|
+
return 'woff';
|
|
14
|
+
// 'wOF2' → WOFF2
|
|
15
|
+
if (b[0] === 0x77 && b[1] === 0x4f && b[2] === 0x46 && b[3] === 0x32)
|
|
16
|
+
return 'woff2';
|
|
17
|
+
// 'ttcf' → TrueType/OpenType Collection
|
|
18
|
+
if (b[0] === 0x74 && b[1] === 0x74 && b[2] === 0x63 && b[3] === 0x66)
|
|
19
|
+
return 'collection';
|
|
20
|
+
// 'true' → legacy Apple TrueType
|
|
21
|
+
if (b[0] === 0x74 && b[1] === 0x72 && b[2] === 0x75 && b[3] === 0x65)
|
|
22
|
+
return 'truetype';
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
export function inferFontFormatFromUrl(url) {
|
|
2
26
|
const ext = url.split('?')[0].split('.').pop()?.toLowerCase();
|
|
3
27
|
switch (ext) {
|
|
4
28
|
case 'woff':
|
package/dist/fontFormat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontFormat.js","sourceRoot":"","sources":["../src/fontFormat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"fontFormat.js","sourceRoot":"","sources":["../src/fontFormat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,KAA+B;IAC9D,MAAM,CAAC,GAAG,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACtE,IAAI,CAAC,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,8CAA8C;IAC9C,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAExF,iCAAiC;IACjC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAExF,gBAAgB;IAChB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAEpF,iBAAiB;IACjB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IAErF,wCAAwC;IACxC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC;IAE1F,iCAAiC;IACjC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAExF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;IAC9D,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,KAAK;YACR,OAAO,UAAU,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,UAAU,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,mBAAmB,CAAC;QAC7B,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/dist/fontFrom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontFrom.d.ts","sourceRoot":"","sources":["../src/fontFrom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"fontFrom.d.ts","sourceRoot":"","sources":["../src/fontFrom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAMrD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhF;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxF"}
|
package/dist/fontFrom.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createFont } from './font';
|
|
2
|
-
import {
|
|
2
|
+
import { inferFontFormatFromUrl } from './fontFormat';
|
|
3
|
+
import { getFontShorthand } from './fontShorthand';
|
|
3
4
|
export async function loadFontFromBytes(bytes, family) {
|
|
4
5
|
const face = new FontFace(family, bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
|
|
5
6
|
await face.load();
|
|
@@ -7,7 +8,7 @@ export async function loadFontFromBytes(bytes, family) {
|
|
|
7
8
|
return createFont(family);
|
|
8
9
|
}
|
|
9
10
|
export async function loadFontFromName(name) {
|
|
10
|
-
await document.fonts.load(
|
|
11
|
+
await document.fonts.load(getFontShorthand(name));
|
|
11
12
|
return createFont(name);
|
|
12
13
|
}
|
|
13
14
|
export async function loadFontFromUrl(url, family) {
|
|
@@ -19,7 +20,7 @@ export async function loadFontFromUrl(url, family) {
|
|
|
19
20
|
export async function loadFontFromUrls(sources, family) {
|
|
20
21
|
const src = sources
|
|
21
22
|
.map(({ url, format }) => {
|
|
22
|
-
const fmt = format ??
|
|
23
|
+
const fmt = format ?? inferFontFormatFromUrl(url);
|
|
23
24
|
return fmt !== null ? `url(${url}) format('${fmt}')` : `url(${url})`;
|
|
24
25
|
})
|
|
25
26
|
.join(', ');
|
package/dist/fontFrom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontFrom.js","sourceRoot":"","sources":["../src/fontFrom.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fontFrom.js","sourceRoot":"","sources":["../src/fontFrom.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAiB,EAAE,MAAc;IACvE,MAAM,IAAI,GAAG,IAAI,QAAQ,CACvB,MAAM,EACL,KAAK,CAAC,MAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CAC3F,CAAC;IACF,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,MAAc;IAC/D,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAkB,EAAE,MAAc;IACvE,MAAM,GAAG,GAAG,OAAO;SAChB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,MAAM,IAAI,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;IACvE,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontResourceFrom.d.ts","sourceRoot":"","sources":["../src/fontResourceFrom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"fontResourceFrom.d.ts","sourceRoot":"","sources":["../src/fontResourceFrom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK7D,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAS3G;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAIvF;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAMnG;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAY3G"}
|
package/dist/fontResourceFrom.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { inferFontFormatFromUrl } from './fontFormat';
|
|
2
|
+
import { getFontShorthand } from './fontShorthand';
|
|
2
3
|
export async function loadFontResourceFromBytes(out, bytes) {
|
|
3
4
|
const face = new FontFace(out.family, bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
|
|
4
5
|
await face.load();
|
|
@@ -7,7 +8,7 @@ export async function loadFontResourceFromBytes(out, bytes) {
|
|
|
7
8
|
return out;
|
|
8
9
|
}
|
|
9
10
|
export async function loadFontResourceFromName(out) {
|
|
10
|
-
const faces = await document.fonts.load(
|
|
11
|
+
const faces = await document.fonts.load(getFontShorthand(out.family));
|
|
11
12
|
if (faces.length > 0)
|
|
12
13
|
out.face = faces[0];
|
|
13
14
|
return out;
|
|
@@ -22,7 +23,7 @@ export async function loadFontResourceFromUrl(out, url) {
|
|
|
22
23
|
export async function loadFontResourceFromUrls(out, sources) {
|
|
23
24
|
const src = sources
|
|
24
25
|
.map(({ url, format }) => {
|
|
25
|
-
const fmt = format ??
|
|
26
|
+
const fmt = format ?? inferFontFormatFromUrl(url);
|
|
26
27
|
return fmt !== null ? `url(${url}) format('${fmt}')` : `url(${url})`;
|
|
27
28
|
})
|
|
28
29
|
.join(', ');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontResourceFrom.js","sourceRoot":"","sources":["../src/fontResourceFrom.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fontResourceFrom.js","sourceRoot":"","sources":["../src/fontResourceFrom.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,GAAiB,EAAE,KAAiB;IAClF,MAAM,IAAI,GAAG,IAAI,QAAQ,CACvB,GAAG,CAAC,MAAM,EACT,KAAK,CAAC,MAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CAC3F,CAAC;IACF,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,GAAiB;IAC9D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,GAAiB,EAAE,GAAW;IAC1E,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC;IACrD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,GAAiB,EAAE,OAAkB;IAClF,MAAM,GAAG,GAAG,OAAO;SAChB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,MAAM,IAAI,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;IACvE,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontShorthand.d.ts","sourceRoot":"","sources":["../src/fontShorthand.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvE"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function getFontShorthand(family, style) {
|
|
2
|
+
// Backslash-escape backslashes and single quotes so a family name containing either
|
|
3
|
+
// cannot break out of the quoted CSS string in the `font` shorthand.
|
|
4
|
+
const quoted = `'${family.replace(/[\\']/g, '\\$&')}'`;
|
|
5
|
+
return style !== undefined && style !== '' ? `${style} 1em ${quoted}` : `1em ${quoted}`;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=fontShorthand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontShorthand.js","sourceRoot":"","sources":["../src/fontShorthand.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,KAAc;IAC7D,oFAAoF;IACpF,qEAAqE;IACrE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IACvD,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontStatus.d.ts","sourceRoot":"","sources":["../src/fontStatus.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpE;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getFontShorthand } from './fontShorthand';
|
|
2
|
+
export function isFontLoaded(family, style) {
|
|
3
|
+
return document.fonts.check(getFontShorthand(family, style));
|
|
4
|
+
}
|
|
5
|
+
export async function whenFontsReady() {
|
|
6
|
+
await document.fonts.ready;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=fontStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontStatus.js","sourceRoot":"","sources":["../src/fontStatus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,KAAc;IACzD,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7B,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/font",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/flighthq/flight.git",
|
|
7
|
+
"directory": "packages/font"
|
|
8
|
+
},
|
|
4
9
|
"type": "module",
|
|
5
10
|
"main": "dist/index.js",
|
|
6
11
|
"types": "dist/index.d.ts",
|
|
@@ -27,8 +32,8 @@
|
|
|
27
32
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
28
33
|
},
|
|
29
34
|
"dependencies": {
|
|
30
|
-
"@flighthq/entity": "0.
|
|
31
|
-
"@flighthq/types": "0.
|
|
35
|
+
"@flighthq/entity": "0.2.0",
|
|
36
|
+
"@flighthq/types": "0.2.0"
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|
|
34
39
|
"typescript": "^5.3.0"
|
package/src/fontFormat.test.ts
CHANGED
|
@@ -1,43 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { detectFontFormat, inferFontFormatFromUrl } from './fontFormat';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function bytesOf(...values: number[]): Uint8Array {
|
|
4
|
+
return new Uint8Array(values);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function asciiBytes(text: string): Uint8Array {
|
|
8
|
+
const b = new Uint8Array(text.length);
|
|
9
|
+
for (let i = 0; i < text.length; i++) b[i] = text.charCodeAt(i);
|
|
10
|
+
return b;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('detectFontFormat', () => {
|
|
14
|
+
it('returns "truetype" for the 0x00010000 sfnt signature', () => {
|
|
15
|
+
expect(detectFontFormat(bytesOf(0x00, 0x01, 0x00, 0x00))).toBe('truetype');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns "opentype" for the "OTTO" signature', () => {
|
|
19
|
+
expect(detectFontFormat(asciiBytes('OTTO'))).toBe('opentype');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns "woff" for the "wOFF" signature', () => {
|
|
23
|
+
expect(detectFontFormat(asciiBytes('wOFF'))).toBe('woff');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns "woff2" for the "wOF2" signature', () => {
|
|
27
|
+
expect(detectFontFormat(asciiBytes('wOF2'))).toBe('woff2');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns "collection" for the "ttcf" signature', () => {
|
|
31
|
+
expect(detectFontFormat(asciiBytes('ttcf'))).toBe('collection');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns "truetype" for the legacy "true" signature', () => {
|
|
35
|
+
expect(detectFontFormat(asciiBytes('true'))).toBe('truetype');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('accepts an ArrayBuffer as well as a Uint8Array', () => {
|
|
39
|
+
expect(detectFontFormat(asciiBytes('wOFF').buffer as ArrayBuffer)).toBe('woff');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('ignores trailing bytes past the 4-byte signature', () => {
|
|
43
|
+
expect(detectFontFormat(asciiBytes('OTTO with more data'))).toBe('opentype');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns null for an unrecognized signature', () => {
|
|
47
|
+
expect(detectFontFormat(asciiBytes('%PDF'))).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns null when there are fewer than 4 bytes', () => {
|
|
51
|
+
expect(detectFontFormat(bytesOf(0x00, 0x01, 0x00))).toBeNull();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('inferFontFormatFromUrl', () => {
|
|
4
56
|
it('returns "woff" for .woff files', () => {
|
|
5
|
-
expect(
|
|
57
|
+
expect(inferFontFormatFromUrl('font.woff')).toBe('woff');
|
|
6
58
|
});
|
|
7
59
|
|
|
8
60
|
it('returns "woff2" for .woff2 files', () => {
|
|
9
|
-
expect(
|
|
61
|
+
expect(inferFontFormatFromUrl('font.woff2')).toBe('woff2');
|
|
10
62
|
});
|
|
11
63
|
|
|
12
64
|
it('returns "truetype" for .ttf files', () => {
|
|
13
|
-
expect(
|
|
65
|
+
expect(inferFontFormatFromUrl('font.ttf')).toBe('truetype');
|
|
14
66
|
});
|
|
15
67
|
|
|
16
68
|
it('returns "opentype" for .otf files', () => {
|
|
17
|
-
expect(
|
|
69
|
+
expect(inferFontFormatFromUrl('font.otf')).toBe('opentype');
|
|
18
70
|
});
|
|
19
71
|
|
|
20
72
|
it('returns "embedded-opentype" for .eot files', () => {
|
|
21
|
-
expect(
|
|
73
|
+
expect(inferFontFormatFromUrl('font.eot')).toBe('embedded-opentype');
|
|
22
74
|
});
|
|
23
75
|
|
|
24
76
|
it('returns "svg" for .svg files', () => {
|
|
25
|
-
expect(
|
|
77
|
+
expect(inferFontFormatFromUrl('font.svg')).toBe('svg');
|
|
26
78
|
});
|
|
27
79
|
|
|
28
80
|
it('returns null for unrecognized extensions', () => {
|
|
29
|
-
expect(
|
|
81
|
+
expect(inferFontFormatFromUrl('font.bin')).toBeNull();
|
|
30
82
|
});
|
|
31
83
|
|
|
32
84
|
it('strips query parameters before matching', () => {
|
|
33
|
-
expect(
|
|
85
|
+
expect(inferFontFormatFromUrl('font.woff2?v=123')).toBe('woff2');
|
|
34
86
|
});
|
|
35
87
|
|
|
36
88
|
it('is case-insensitive', () => {
|
|
37
|
-
expect(
|
|
89
|
+
expect(inferFontFormatFromUrl('font.WOFF2')).toBe('woff2');
|
|
38
90
|
});
|
|
39
91
|
|
|
40
92
|
it('returns null for a URL with no extension', () => {
|
|
41
|
-
expect(
|
|
93
|
+
expect(inferFontFormatFromUrl('font')).toBeNull();
|
|
42
94
|
});
|
|
43
95
|
});
|
package/src/fontFrom.test.ts
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
import { loadFontFromBytes, loadFontFromName, loadFontFromUrl, loadFontFromUrls } from './fontFrom';
|
|
2
2
|
|
|
3
|
+
interface FontFaceConstruction {
|
|
4
|
+
family: string;
|
|
5
|
+
source: string | ArrayBuffer;
|
|
6
|
+
instance: MockFontFace;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let constructions: FontFaceConstruction[];
|
|
10
|
+
let addMock: ReturnType<typeof vi.fn>;
|
|
11
|
+
let loadMock: ReturnType<typeof vi.fn>;
|
|
12
|
+
|
|
3
13
|
class MockFontFace {
|
|
4
14
|
load = vi.fn().mockResolvedValue(undefined);
|
|
15
|
+
constructor(family: string, source: string | ArrayBuffer) {
|
|
16
|
+
const construction = { family, source, instance: this };
|
|
17
|
+
constructions.push(construction);
|
|
18
|
+
}
|
|
5
19
|
}
|
|
6
20
|
|
|
7
21
|
// Re-applied per test (not once) and torn down, so under a shared (isolate:false) worker with
|
|
8
22
|
// unstubGlobals the FontFace stub survives every test and the document.fonts patch never leaks out.
|
|
9
23
|
let originalFonts: PropertyDescriptor | undefined;
|
|
10
24
|
beforeEach(() => {
|
|
25
|
+
constructions = [];
|
|
26
|
+
addMock = vi.fn();
|
|
27
|
+
loadMock = vi.fn().mockResolvedValue([]);
|
|
11
28
|
vi.stubGlobal('FontFace', MockFontFace);
|
|
12
29
|
originalFonts = Object.getOwnPropertyDescriptor(document, 'fonts');
|
|
13
30
|
Object.defineProperty(document, 'fonts', {
|
|
14
|
-
value: { add:
|
|
31
|
+
value: { add: addMock, load: loadMock },
|
|
15
32
|
configurable: true,
|
|
16
33
|
});
|
|
17
34
|
});
|
|
@@ -29,6 +46,35 @@ describe('loadFontFromBytes', () => {
|
|
|
29
46
|
const font = await loadFontFromBytes(new Uint8Array(0), 'TestFont');
|
|
30
47
|
expect(font.name).toBe('TestFont');
|
|
31
48
|
});
|
|
49
|
+
|
|
50
|
+
it('loads the face and registers it with document.fonts', async () => {
|
|
51
|
+
await loadFontFromBytes(new Uint8Array(8), 'TestFont');
|
|
52
|
+
expect(constructions).toHaveLength(1);
|
|
53
|
+
expect(constructions[0].family).toBe('TestFont');
|
|
54
|
+
expect(constructions[0].instance.load).toHaveBeenCalledOnce();
|
|
55
|
+
expect(addMock).toHaveBeenCalledWith(constructions[0].instance);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('slices only the view bytes out of a larger backing buffer', async () => {
|
|
59
|
+
const backing = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
60
|
+
const view = backing.subarray(2, 6);
|
|
61
|
+
await loadFontFromBytes(view, 'TestFont');
|
|
62
|
+
const source = constructions[0].source as ArrayBuffer;
|
|
63
|
+
expect(new Uint8Array(source)).toEqual(new Uint8Array([3, 4, 5, 6]));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('propagates a load failure and does not register the face', async () => {
|
|
67
|
+
const failing = new MockFontFace('', new ArrayBuffer(0));
|
|
68
|
+
failing.load.mockRejectedValue(new Error('bad font'));
|
|
69
|
+
vi.stubGlobal(
|
|
70
|
+
'FontFace',
|
|
71
|
+
vi.fn(function () {
|
|
72
|
+
return failing;
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
await expect(loadFontFromBytes(new Uint8Array(4), 'TestFont')).rejects.toThrow('bad font');
|
|
76
|
+
expect(addMock).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
32
78
|
});
|
|
33
79
|
|
|
34
80
|
describe('loadFontFromName', () => {
|
|
@@ -36,6 +82,21 @@ describe('loadFontFromName', () => {
|
|
|
36
82
|
const font = await loadFontFromName('MyFont');
|
|
37
83
|
expect(font.name).toBe('MyFont');
|
|
38
84
|
});
|
|
85
|
+
|
|
86
|
+
it('loads the family via the escaped font shorthand', async () => {
|
|
87
|
+
await loadFontFromName('MyFont');
|
|
88
|
+
expect(loadMock).toHaveBeenCalledWith("1em 'MyFont'");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('escapes a single quote in the family name so the shorthand stays valid', async () => {
|
|
92
|
+
await loadFontFromName("Josh's Font");
|
|
93
|
+
expect(loadMock).toHaveBeenCalledWith("1em 'Josh\\'s Font'");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('propagates a load failure', async () => {
|
|
97
|
+
loadMock.mockRejectedValue(new Error('no such font'));
|
|
98
|
+
await expect(loadFontFromName('MyFont')).rejects.toThrow('no such font');
|
|
99
|
+
});
|
|
39
100
|
});
|
|
40
101
|
|
|
41
102
|
describe('loadFontFromUrl', () => {
|
|
@@ -43,6 +104,13 @@ describe('loadFontFromUrl', () => {
|
|
|
43
104
|
const font = await loadFontFromUrl('font.woff2', 'MyFont');
|
|
44
105
|
expect(font.name).toBe('MyFont');
|
|
45
106
|
});
|
|
107
|
+
|
|
108
|
+
it('builds a url() source and registers the face', async () => {
|
|
109
|
+
await loadFontFromUrl('font.woff2', 'MyFont');
|
|
110
|
+
expect(constructions[0].family).toBe('MyFont');
|
|
111
|
+
expect(constructions[0].source).toBe('url(font.woff2)');
|
|
112
|
+
expect(addMock).toHaveBeenCalledWith(constructions[0].instance);
|
|
113
|
+
});
|
|
46
114
|
});
|
|
47
115
|
|
|
48
116
|
describe('loadFontFromUrls', () => {
|
|
@@ -50,4 +118,28 @@ describe('loadFontFromUrls', () => {
|
|
|
50
118
|
const font = await loadFontFromUrls([{ url: 'font.woff2', format: 'woff2' }], 'MyFont');
|
|
51
119
|
expect(font.name).toBe('MyFont');
|
|
52
120
|
});
|
|
121
|
+
|
|
122
|
+
it('composes a comma-joined src with explicit and inferred format() hints', async () => {
|
|
123
|
+
await loadFontFromUrls([{ url: 'font.woff2', format: 'woff2' }, { url: 'font.ttf' }], 'MyFont');
|
|
124
|
+
expect(constructions[0].source).toBe("url(font.woff2) format('woff2'), url(font.ttf) format('truetype')");
|
|
125
|
+
expect(addMock).toHaveBeenCalledWith(constructions[0].instance);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('omits the format() hint when it cannot be inferred and none is given', async () => {
|
|
129
|
+
await loadFontFromUrls([{ url: 'font.bin' }], 'MyFont');
|
|
130
|
+
expect(constructions[0].source).toBe('url(font.bin)');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('propagates a load failure and does not register the face', async () => {
|
|
134
|
+
const failing = new MockFontFace('', '');
|
|
135
|
+
failing.load.mockRejectedValue(new Error('bad url'));
|
|
136
|
+
vi.stubGlobal(
|
|
137
|
+
'FontFace',
|
|
138
|
+
vi.fn(function () {
|
|
139
|
+
return failing;
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
await expect(loadFontFromUrls([{ url: 'font.woff2' }], 'MyFont')).rejects.toThrow('bad url');
|
|
143
|
+
expect(addMock).not.toHaveBeenCalled();
|
|
144
|
+
});
|
|
53
145
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getFontShorthand } from './fontShorthand';
|
|
2
|
+
|
|
3
|
+
describe('getFontShorthand', () => {
|
|
4
|
+
it('quotes a plain family name at 1em', () => {
|
|
5
|
+
expect(getFontShorthand('MyFont')).toBe("1em 'MyFont'");
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('backslash-escapes single quotes in the family name', () => {
|
|
9
|
+
expect(getFontShorthand("Josh's Font")).toBe("1em 'Josh\\'s Font'");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('backslash-escapes backslashes in the family name', () => {
|
|
13
|
+
expect(getFontShorthand('Back\\slash')).toBe("1em 'Back\\\\slash'");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('prefixes a style when provided', () => {
|
|
17
|
+
expect(getFontShorthand('MyFont', 'italic')).toBe("italic 1em 'MyFont'");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('omits the style prefix for an empty style string', () => {
|
|
21
|
+
expect(getFontShorthand('MyFont', '')).toBe("1em 'MyFont'");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isFontLoaded, whenFontsReady } from './fontStatus';
|
|
2
|
+
|
|
3
|
+
let originalFonts: PropertyDescriptor | undefined;
|
|
4
|
+
let checkMock: ReturnType<typeof vi.fn>;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
checkMock = vi.fn().mockReturnValue(true);
|
|
8
|
+
originalFonts = Object.getOwnPropertyDescriptor(document, 'fonts');
|
|
9
|
+
Object.defineProperty(document, 'fonts', {
|
|
10
|
+
value: { check: checkMock, ready: Promise.resolve() },
|
|
11
|
+
configurable: true,
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
if (originalFonts) {
|
|
17
|
+
Object.defineProperty(document, 'fonts', originalFonts);
|
|
18
|
+
} else {
|
|
19
|
+
delete (document as unknown as { fonts?: unknown }).fonts;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('isFontLoaded', () => {
|
|
24
|
+
it('queries document.fonts.check with the family shorthand', () => {
|
|
25
|
+
expect(isFontLoaded('MyFont')).toBe(true);
|
|
26
|
+
expect(checkMock).toHaveBeenCalledWith("1em 'MyFont'");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('includes the style in the shorthand when provided', () => {
|
|
30
|
+
isFontLoaded('MyFont', 'italic');
|
|
31
|
+
expect(checkMock).toHaveBeenCalledWith("italic 1em 'MyFont'");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('escapes single quotes in the family name', () => {
|
|
35
|
+
isFontLoaded("Josh's Font");
|
|
36
|
+
expect(checkMock).toHaveBeenCalledWith("1em 'Josh\\'s Font'");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('returns false when the font is not available', () => {
|
|
40
|
+
checkMock.mockReturnValue(false);
|
|
41
|
+
expect(isFontLoaded('Absent')).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('whenFontsReady', () => {
|
|
46
|
+
it('resolves once document.fonts.ready resolves', async () => {
|
|
47
|
+
await expect(whenFontsReady()).resolves.toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|