@webstudio-is/fonts 0.90.0 → 0.92.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/lib/constants.js CHANGED
@@ -1,20 +1,16 @@
1
- const SYSTEM_FONTS = /* @__PURE__ */ new Map([
1
+ "use strict";
2
+ export const SYSTEM_FONTS = /* @__PURE__ */ new Map([
2
3
  ["Arial", ["Roboto", "sans-serif"]],
3
4
  ["Times New Roman", ["sans"]],
4
5
  ["Courier New", ["monospace"]],
5
6
  ["system-ui", []]
6
7
  ]);
7
- const DEFAULT_FONT_FALLBACK = "sans-serif";
8
- const FONT_FORMATS = /* @__PURE__ */ new Map([
8
+ export const DEFAULT_FONT_FALLBACK = "sans-serif";
9
+ export const FONT_FORMATS = /* @__PURE__ */ new Map([
9
10
  ["woff", "woff"],
10
11
  ["woff2", "woff2"],
11
12
  ["ttf", "truetype"],
12
13
  ["otf", "opentype"]
13
14
  ]);
14
- const FONT_MIME_TYPES = Array.from(FONT_FORMATS.keys()).map((format) => `.${format}`).join(", ");
15
- export {
16
- DEFAULT_FONT_FALLBACK,
17
- FONT_FORMATS,
18
- FONT_MIME_TYPES,
19
- SYSTEM_FONTS
20
- };
15
+ export const FONT_MIME_TYPES = Array.from(FONT_FORMATS.keys()).map((format) => `.${format}`).join(", ");
16
+ export const FONT_STYLES = ["normal", "italic", "oblique"];
@@ -1,4 +1,5 @@
1
- const fontWeights = {
1
+ "use strict";
2
+ export const fontWeights = {
2
3
  "100": {
3
4
  label: "Thin",
4
5
  names: ["thin", "hairline"]
@@ -36,6 +37,3 @@ const fontWeights = {
36
37
  names: ["black", "heavy"]
37
38
  }
38
39
  };
39
- export {
40
- fontWeights
41
- };
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  import { FONT_FORMATS } from "./constants";
2
3
  const formatFace = (asset, format, url) => {
3
4
  if ("variationAxes" in asset.meta) {
@@ -25,7 +26,7 @@ const getKey = (asset) => {
25
26
  }
26
27
  return asset.meta.family + asset.meta.style + asset.meta.weight;
27
28
  };
28
- const getFontFaces = (assets, options) => {
29
+ export const getFontFaces = (assets, options) => {
29
30
  const { assetBaseUrl } = options;
30
31
  const faces = /* @__PURE__ */ new Map();
31
32
  for (const asset of assets) {
@@ -45,6 +46,3 @@ const getFontFaces = (assets, options) => {
45
46
  }
46
47
  return Array.from(faces.values());
47
48
  };
48
- export {
49
- getFontFaces
50
- };
@@ -1,87 +1,84 @@
1
+ "use strict";
1
2
  import { describe, test, expect } from "@jest/globals";
2
- import { getFontFaces, type PartialFontAsset } from "./get-font-faces";
3
-
3
+ import { getFontFaces } from "./get-font-faces";
4
4
  describe("getFontFaces()", () => {
5
5
  test("different formats", () => {
6
- const assets: Array<PartialFontAsset> = [
6
+ const assets = [
7
7
  {
8
8
  format: "woff",
9
9
  meta: {
10
10
  family: "Roboto",
11
11
  style: "normal",
12
- weight: 400,
12
+ weight: 400
13
13
  },
14
- name: "roboto.woff",
14
+ name: "roboto.woff"
15
15
  },
16
16
  {
17
17
  format: "ttf",
18
18
  meta: {
19
19
  family: "Roboto",
20
20
  style: "normal",
21
- weight: 400,
21
+ weight: 400
22
22
  },
23
- name: "roboto.ttf",
24
- },
23
+ name: "roboto.ttf"
24
+ }
25
25
  ];
26
26
  expect(getFontFaces(assets, { assetBaseUrl: "/fonts/" })).toMatchSnapshot();
27
27
  });
28
-
29
28
  test("different style", () => {
30
- const assets: Array<PartialFontAsset> = [
29
+ const assets = [
31
30
  {
32
31
  format: "ttf",
33
32
  meta: {
34
33
  family: "Roboto",
35
34
  style: "normal",
36
- weight: 400,
35
+ weight: 400
37
36
  },
38
- name: "roboto.ttf",
37
+ name: "roboto.ttf"
39
38
  },
40
39
  {
41
40
  format: "ttf",
42
41
  meta: {
43
42
  family: "Roboto",
44
43
  style: "italic",
45
- weight: 400,
44
+ weight: 400
46
45
  },
47
- name: "roboto-italic.ttf",
48
- },
46
+ name: "roboto-italic.ttf"
47
+ }
49
48
  ];
50
49
  expect(getFontFaces(assets, { assetBaseUrl: "/fonts/" })).toMatchSnapshot();
51
50
  });
52
-
53
51
  test("different weight", () => {
54
- const assets: Array<PartialFontAsset> = [
52
+ const assets = [
55
53
  {
56
54
  format: "ttf",
57
55
  meta: {
58
56
  family: "Roboto",
59
57
  style: "normal",
60
- weight: 400,
58
+ weight: 400
61
59
  },
62
- name: "roboto.ttf",
60
+ name: "roboto.ttf"
63
61
  },
64
62
  {
65
63
  format: "ttf",
66
64
  meta: {
67
65
  family: "Roboto",
68
66
  style: "normal",
69
- weight: 500,
67
+ weight: 500
70
68
  },
71
- name: "roboto-bold.ttf",
72
- },
69
+ name: "roboto-bold.ttf"
70
+ }
73
71
  ];
74
72
  expect(getFontFaces(assets, { assetBaseUrl: "/fonts/" })).toMatchSnapshot();
75
73
  });
76
-
77
74
  test("variable font", () => {
78
- const assets: Array<PartialFontAsset> = [
75
+ const assets = [
79
76
  {
80
77
  format: "ttf",
81
78
  meta: {
82
79
  family: "Inter",
83
80
  variationAxes: {
84
- wght: { name: "wght", min: 100, default: 400, max: 1000 },
81
+ wght: { name: "wght", min: 100, default: 400, max: 1e3 },
85
82
  wdth: { name: "wdth", min: 25, default: 100, max: 151 },
86
83
  opsz: { name: "opsz", min: 8, default: 14, max: 144 },
87
84
  GRAD: { name: "GRAD", min: -200, default: 0, max: 150 },
@@ -93,11 +90,11 @@ describe("getFontFaces()", () => {
93
90
  YTUC: { name: "YTUC", min: 528, default: 712, max: 760 },
94
91
  YTAS: { name: "YTAS", min: 649, default: 750, max: 854 },
95
92
  YTDE: { name: "YTDE", min: -305, default: -203, max: -98 },
96
- YTFI: { name: "YTFI", min: 560, default: 738, max: 788 },
97
- },
93
+ YTFI: { name: "YTFI", min: 560, default: 738, max: 788 }
94
+ }
98
95
  },
99
- name: "inter.ttf",
100
- },
96
+ name: "inter.ttf"
97
+ }
101
98
  ];
102
99
  expect(getFontFaces(assets, { assetBaseUrl: "/fonts/" })).toMatchSnapshot();
103
100
  });
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  export * from "./constants";
2
3
  export * from "./get-font-faces";
3
4
  export * from "./schema";
package/lib/schema.js CHANGED
@@ -1,6 +1,7 @@
1
+ "use strict";
1
2
  import { z } from "zod";
2
- import { styles } from "./font-data";
3
- const FontFormat = z.union([
3
+ import { FONT_STYLES } from "./constants";
4
+ export const FontFormat = z.union([
4
5
  z.literal("ttf"),
5
6
  z.literal("woff"),
6
7
  z.literal("woff2"),
@@ -31,18 +32,13 @@ const VariationAxes = z.record(
31
32
  max: z.number()
32
33
  })
33
34
  );
34
- const FontMetaStatic = z.object({
35
+ export const FontMetaStatic = z.object({
35
36
  family: z.string(),
36
- style: z.enum(styles),
37
+ style: z.enum(FONT_STYLES),
37
38
  weight: z.number()
38
39
  });
39
40
  const FontMetaVariable = z.object({
40
41
  family: z.string(),
41
42
  variationAxes: VariationAxes
42
43
  });
43
- const FontMeta = z.union([FontMetaStatic, FontMetaVariable]);
44
- export {
45
- FontFormat,
46
- FontMeta,
47
- FontMetaStatic
48
- };
44
+ export const FontMeta = z.union([FontMetaStatic, FontMetaVariable]);
@@ -3,3 +3,5 @@ export declare const SYSTEM_FONTS: Map<string, string[]>;
3
3
  export declare const DEFAULT_FONT_FALLBACK = "sans-serif";
4
4
  export declare const FONT_FORMATS: Map<FontFormat, string>;
5
5
  export declare const FONT_MIME_TYPES: string;
6
+ export declare const FONT_STYLES: readonly ["normal", "italic", "oblique"];
7
+ export type FontStyle = (typeof FONT_STYLES)[number];
@@ -23,13 +23,13 @@ export declare const FontMetaStatic: z.ZodObject<{
23
23
  style: z.ZodEnum<["normal", "italic", "oblique"]>;
24
24
  weight: z.ZodNumber;
25
25
  }, "strip", z.ZodTypeAny, {
26
+ family: string;
26
27
  style: "normal" | "italic" | "oblique";
27
28
  weight: number;
28
- family: string;
29
29
  }, {
30
+ family: string;
30
31
  style: "normal" | "italic" | "oblique";
31
32
  weight: number;
32
- family: string;
33
33
  }>;
34
34
  export type FontMetaStatic = z.infer<typeof FontMetaStatic>;
35
35
  export declare const FontMeta: z.ZodUnion<[z.ZodObject<{
@@ -37,13 +37,13 @@ export declare const FontMeta: z.ZodUnion<[z.ZodObject<{
37
37
  style: z.ZodEnum<["normal", "italic", "oblique"]>;
38
38
  weight: z.ZodNumber;
39
39
  }, "strip", z.ZodTypeAny, {
40
+ family: string;
40
41
  style: "normal" | "italic" | "oblique";
41
42
  weight: number;
42
- family: string;
43
43
  }, {
44
+ family: string;
44
45
  style: "normal" | "italic" | "oblique";
45
46
  weight: number;
46
- family: string;
47
47
  }>, z.ZodObject<{
48
48
  family: z.ZodString;
49
49
  variationAxes: z.ZodRecord<z.ZodEnum<["wght", "wdth", "slnt", "opsz", "ital", "GRAD", "XTRA", "XOPQ", "YOPQ", "YTLC", "YTUC", "YTAS", "YTDE", "YTFI"]>, z.ZodObject<{
@@ -63,21 +63,21 @@ export declare const FontMeta: z.ZodUnion<[z.ZodObject<{
63
63
  max: number;
64
64
  }>>;
65
65
  }, "strip", z.ZodTypeAny, {
66
+ family: string;
66
67
  variationAxes: Partial<Record<"wght" | "wdth" | "slnt" | "opsz" | "ital" | "GRAD" | "XTRA" | "XOPQ" | "YOPQ" | "YTLC" | "YTUC" | "YTAS" | "YTDE" | "YTFI", {
67
68
  name: string;
68
69
  min: number;
69
70
  default: number;
70
71
  max: number;
71
72
  }>>;
72
- family: string;
73
73
  }, {
74
+ family: string;
74
75
  variationAxes: Partial<Record<"wght" | "wdth" | "slnt" | "opsz" | "ital" | "GRAD" | "XTRA" | "XOPQ" | "YOPQ" | "YTLC" | "YTUC" | "YTAS" | "YTDE" | "YTFI", {
75
76
  name: string;
76
77
  min: number;
77
78
  default: number;
78
79
  max: number;
79
80
  }>>;
80
- family: string;
81
81
  }>]>;
82
82
  export type FontMeta = z.infer<typeof FontMeta>;
83
83
  export {};
package/package.json CHANGED
@@ -1,44 +1,29 @@
1
1
  {
2
2
  "name": "@webstudio-is/fonts",
3
- "version": "0.90.0",
3
+ "version": "0.92.0",
4
4
  "description": "Fonts utils",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
7
7
  "type": "module",
8
- "dependencies": {
9
- "fontkit": "^2.0.2"
10
- },
11
8
  "devDependencies": {
12
- "@jest/globals": "^29.6.2",
13
- "@types/fontkit": "^2.0.1",
14
- "jest": "^29.6.2",
15
- "typescript": "5.1.6",
9
+ "@jest/globals": "^29.6.4",
10
+ "jest": "^29.6.4",
11
+ "typescript": "5.2.2",
16
12
  "zod": "^3.21.4",
17
- "@webstudio-is/design-system": "^0.90.0",
18
13
  "@webstudio-is/jest-config": "^1.0.7",
19
- "@webstudio-is/scripts": "^0.0.0",
20
14
  "@webstudio-is/tsconfig": "^1.0.7"
21
15
  },
22
16
  "peerDependencies": {
23
17
  "zod": "^3.19.1"
24
18
  },
25
19
  "exports": {
26
- ".": {
27
- "source": "./src/index.ts",
28
- "types": "./lib/types/index.d.ts",
29
- "import": "./lib/index.js",
30
- "require": "./lib/cjs/index.js"
31
- },
32
- "./index.server": {
33
- "source": "./src/index.server.ts",
34
- "types": "./lib/types/index.server.d.ts",
35
- "import": "./lib/index.server.js"
36
- }
20
+ "source": "./src/index.ts",
21
+ "types": "./lib/types/index.d.ts",
22
+ "import": "./lib/index.js"
37
23
  },
38
24
  "files": [
39
25
  "lib/*",
40
- "src/*",
41
- "!*.test.*"
26
+ "!*.{test,stories}.*"
42
27
  ],
43
28
  "license": "AGPL-3.0-or-later",
44
29
  "private": false,
@@ -47,8 +32,8 @@
47
32
  "typecheck": "tsc",
48
33
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
49
34
  "checks": "pnpm typecheck && pnpm test",
50
- "dev": "build-package --watch",
51
- "build": "build-package",
35
+ "dev": "pnpm build --watch",
36
+ "build": "rm -rf lib && esbuild 'src/**/*.ts' 'src/**/*.tsx' --outdir=lib",
52
37
  "dts": "tsc --project tsconfig.dts.json"
53
38
  }
54
39
  }
@@ -1,40 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var constants_exports = {};
20
- __export(constants_exports, {
21
- DEFAULT_FONT_FALLBACK: () => DEFAULT_FONT_FALLBACK,
22
- FONT_FORMATS: () => FONT_FORMATS,
23
- FONT_MIME_TYPES: () => FONT_MIME_TYPES,
24
- SYSTEM_FONTS: () => SYSTEM_FONTS
25
- });
26
- module.exports = __toCommonJS(constants_exports);
27
- const SYSTEM_FONTS = /* @__PURE__ */ new Map([
28
- ["Arial", ["Roboto", "sans-serif"]],
29
- ["Times New Roman", ["sans"]],
30
- ["Courier New", ["monospace"]],
31
- ["system-ui", []]
32
- ]);
33
- const DEFAULT_FONT_FALLBACK = "sans-serif";
34
- const FONT_FORMATS = /* @__PURE__ */ new Map([
35
- ["woff", "woff"],
36
- ["woff2", "woff2"],
37
- ["ttf", "truetype"],
38
- ["otf", "opentype"]
39
- ]);
40
- const FONT_MIME_TYPES = Array.from(FONT_FORMATS.keys()).map((format) => `.${format}`).join(", ");
@@ -1,76 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var font_data_exports = {};
20
- __export(font_data_exports, {
21
- getFontData: () => getFontData,
22
- normalizeFamily: () => normalizeFamily,
23
- parseSubfamily: () => parseSubfamily,
24
- styles: () => styles
25
- });
26
- module.exports = __toCommonJS(font_data_exports);
27
- var import_fontkit = require("fontkit");
28
- var import_font_weights = require("./font-weights");
29
- const styles = ["normal", "italic", "oblique"];
30
- const parseSubfamily = (subfamily) => {
31
- const subfamilyLow = subfamily.toLowerCase();
32
- let style = "normal";
33
- for (const possibleStyle of styles) {
34
- if (subfamilyLow.includes(possibleStyle)) {
35
- style = possibleStyle;
36
- break;
37
- }
38
- }
39
- let weight = "400";
40
- for (weight in import_font_weights.fontWeights) {
41
- const { names } = import_font_weights.fontWeights[weight];
42
- if (names.some((name) => subfamilyLow.includes(name))) {
43
- break;
44
- }
45
- }
46
- return { style, weight: Number(weight) };
47
- };
48
- const splitAndTrim = (string) => string.split(" ").map((part) => part.trim()).filter(Boolean);
49
- const normalizeFamily = (family, subfamily) => {
50
- const familyParts = splitAndTrim(family);
51
- const subfamilyParts = splitAndTrim(subfamily.toLowerCase());
52
- const familyPartsNormalized = familyParts.filter(
53
- (familyPart) => subfamilyParts.includes(familyPart.toLowerCase()) === false
54
- );
55
- return familyPartsNormalized.join(" ");
56
- };
57
- const getFontData = (data) => {
58
- const font = (0, import_fontkit.create)(data);
59
- const format = font.type.toLowerCase();
60
- const originalFamily = font.getName("fontFamily");
61
- const subfamily = font.getName("preferredSubfamily") ?? font.getName("fontSubfamily");
62
- const family = normalizeFamily(originalFamily, subfamily);
63
- const isVariable = Object.keys(font.variationAxes).length !== 0;
64
- if (isVariable) {
65
- return {
66
- format,
67
- family,
68
- variationAxes: font.variationAxes
69
- };
70
- }
71
- return {
72
- format,
73
- family,
74
- ...parseSubfamily(subfamily)
75
- };
76
- };
@@ -1,61 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var font_weights_exports = {};
20
- __export(font_weights_exports, {
21
- fontWeights: () => fontWeights
22
- });
23
- module.exports = __toCommonJS(font_weights_exports);
24
- const fontWeights = {
25
- "100": {
26
- label: "Thin",
27
- names: ["thin", "hairline"]
28
- },
29
- "200": {
30
- label: "Extra Light",
31
- names: ["extra light", "extralight", "ultra light", "ultralight"]
32
- },
33
- "300": {
34
- label: "Light",
35
- names: ["light"]
36
- },
37
- "400": {
38
- label: "Normal",
39
- names: ["normal", "regular"]
40
- },
41
- "500": {
42
- label: "Medium",
43
- names: ["medium"]
44
- },
45
- "600": {
46
- label: "Semi Bold",
47
- names: ["semi bold", "semibold", "demi bold", "demibold"]
48
- },
49
- "700": {
50
- label: "Bold",
51
- names: ["bold", "bold"]
52
- },
53
- "800": {
54
- label: "Extra Bold",
55
- names: ["extra bold", "extrabold", "ultra bold", "ultrabold"]
56
- },
57
- "900": {
58
- label: "Black",
59
- names: ["black", "heavy"]
60
- }
61
- };
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var get_font_faces_exports = {};
20
- __export(get_font_faces_exports, {
21
- getFontFaces: () => getFontFaces
22
- });
23
- module.exports = __toCommonJS(get_font_faces_exports);
24
- var import_constants = require("./constants");
25
- const formatFace = (asset, format, url) => {
26
- if ("variationAxes" in asset.meta) {
27
- const { wght, wdth } = asset.meta?.variationAxes ?? {};
28
- return {
29
- fontFamily: asset.meta.family,
30
- fontStyle: "normal",
31
- fontDisplay: "swap",
32
- src: `url('${url}') format('${format}')`,
33
- fontStretch: wdth ? `${wdth.min}% ${wdth.max}%` : void 0,
34
- fontWeight: wght ? `${wght.min} ${wght.max}` : void 0
35
- };
36
- }
37
- return {
38
- fontFamily: asset.meta.family,
39
- fontStyle: asset.meta.style,
40
- fontWeight: asset.meta.weight,
41
- fontDisplay: "swap",
42
- src: `url('${url}') format('${format}')`
43
- };
44
- };
45
- const getKey = (asset) => {
46
- if ("variationAxes" in asset.meta) {
47
- return asset.meta.family + Object.values(asset.meta.variationAxes).join("");
48
- }
49
- return asset.meta.family + asset.meta.style + asset.meta.weight;
50
- };
51
- const getFontFaces = (assets, options) => {
52
- const { assetBaseUrl } = options;
53
- const faces = /* @__PURE__ */ new Map();
54
- for (const asset of assets) {
55
- const url = `${assetBaseUrl}${asset.name}`;
56
- const assetKey = getKey(asset);
57
- const face = faces.get(assetKey);
58
- const format = import_constants.FONT_FORMATS.get(asset.format);
59
- if (format === void 0) {
60
- continue;
61
- }
62
- if (face === void 0) {
63
- const face2 = formatFace(asset, format, url);
64
- faces.set(assetKey, face2);
65
- continue;
66
- }
67
- face.src += `, url('${url}') format('${format}')`;
68
- }
69
- return Array.from(faces.values());
70
- };
package/lib/cjs/index.js DELETED
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
- var src_exports = {};
17
- module.exports = __toCommonJS(src_exports);
18
- __reExport(src_exports, require("./constants"), module.exports);
19
- __reExport(src_exports, require("./get-font-faces"), module.exports);
20
- __reExport(src_exports, require("./schema"), module.exports);
21
- __reExport(src_exports, require("./font-weights"), module.exports);
@@ -1,24 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var index_server_exports = {};
20
- __export(index_server_exports, {
21
- getFontData: () => import_font_data.getFontData
22
- });
23
- module.exports = __toCommonJS(index_server_exports);
24
- var import_font_data = require("./font-data");
@@ -1 +0,0 @@
1
- {"type":"commonjs"}
package/lib/cjs/schema.js DELETED
@@ -1,68 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var schema_exports = {};
20
- __export(schema_exports, {
21
- FontFormat: () => FontFormat,
22
- FontMeta: () => FontMeta,
23
- FontMetaStatic: () => FontMetaStatic
24
- });
25
- module.exports = __toCommonJS(schema_exports);
26
- var import_zod = require("zod");
27
- var import_font_data = require("./font-data");
28
- const FontFormat = import_zod.z.union([
29
- import_zod.z.literal("ttf"),
30
- import_zod.z.literal("woff"),
31
- import_zod.z.literal("woff2"),
32
- import_zod.z.literal("otf")
33
- ]);
34
- const AxisName = import_zod.z.enum([
35
- "wght",
36
- "wdth",
37
- "slnt",
38
- "opsz",
39
- "ital",
40
- "GRAD",
41
- "XTRA",
42
- "XOPQ",
43
- "YOPQ",
44
- "YTLC",
45
- "YTUC",
46
- "YTAS",
47
- "YTDE",
48
- "YTFI"
49
- ]);
50
- const VariationAxes = import_zod.z.record(
51
- AxisName,
52
- import_zod.z.object({
53
- name: import_zod.z.string(),
54
- min: import_zod.z.number(),
55
- default: import_zod.z.number(),
56
- max: import_zod.z.number()
57
- })
58
- );
59
- const FontMetaStatic = import_zod.z.object({
60
- family: import_zod.z.string(),
61
- style: import_zod.z.enum(import_font_data.styles),
62
- weight: import_zod.z.number()
63
- });
64
- const FontMetaVariable = import_zod.z.object({
65
- family: import_zod.z.string(),
66
- variationAxes: VariationAxes
67
- });
68
- const FontMeta = import_zod.z.union([FontMetaStatic, FontMetaVariable]);
package/lib/font-data.js DELETED
@@ -1,56 +0,0 @@
1
- import { create as createFontKit } from "fontkit";
2
- import { fontWeights } from "./font-weights";
3
- const styles = ["normal", "italic", "oblique"];
4
- const parseSubfamily = (subfamily) => {
5
- const subfamilyLow = subfamily.toLowerCase();
6
- let style = "normal";
7
- for (const possibleStyle of styles) {
8
- if (subfamilyLow.includes(possibleStyle)) {
9
- style = possibleStyle;
10
- break;
11
- }
12
- }
13
- let weight = "400";
14
- for (weight in fontWeights) {
15
- const { names } = fontWeights[weight];
16
- if (names.some((name) => subfamilyLow.includes(name))) {
17
- break;
18
- }
19
- }
20
- return { style, weight: Number(weight) };
21
- };
22
- const splitAndTrim = (string) => string.split(" ").map((part) => part.trim()).filter(Boolean);
23
- const normalizeFamily = (family, subfamily) => {
24
- const familyParts = splitAndTrim(family);
25
- const subfamilyParts = splitAndTrim(subfamily.toLowerCase());
26
- const familyPartsNormalized = familyParts.filter(
27
- (familyPart) => subfamilyParts.includes(familyPart.toLowerCase()) === false
28
- );
29
- return familyPartsNormalized.join(" ");
30
- };
31
- const getFontData = (data) => {
32
- const font = createFontKit(data);
33
- const format = font.type.toLowerCase();
34
- const originalFamily = font.getName("fontFamily");
35
- const subfamily = font.getName("preferredSubfamily") ?? font.getName("fontSubfamily");
36
- const family = normalizeFamily(originalFamily, subfamily);
37
- const isVariable = Object.keys(font.variationAxes).length !== 0;
38
- if (isVariable) {
39
- return {
40
- format,
41
- family,
42
- variationAxes: font.variationAxes
43
- };
44
- }
45
- return {
46
- format,
47
- family,
48
- ...parseSubfamily(subfamily)
49
- };
50
- };
51
- export {
52
- getFontData,
53
- normalizeFamily,
54
- parseSubfamily,
55
- styles
56
- };
@@ -1,4 +0,0 @@
1
- import { getFontData } from "./font-data";
2
- export {
3
- getFontData
4
- };
@@ -1,29 +0,0 @@
1
- import type { FontFormat, VariationAxes } from "./schema";
2
- declare module "fontkit" {
3
- interface Font {
4
- type: string;
5
- getName: (name: string) => string;
6
- variationAxes: VariationAxes;
7
- }
8
- }
9
- export declare const styles: readonly ["normal", "italic", "oblique"];
10
- type Style = (typeof styles)[number];
11
- export declare const parseSubfamily: (subfamily: string) => {
12
- style: "normal" | "italic" | "oblique";
13
- weight: number;
14
- };
15
- export declare const normalizeFamily: (family: string, subfamily: string) => string;
16
- type FontDataStatic = {
17
- format: FontFormat;
18
- family: string;
19
- style: Style;
20
- weight: number;
21
- };
22
- type FontDataVariable = {
23
- format: FontFormat;
24
- family: string;
25
- variationAxes: VariationAxes;
26
- };
27
- type FontData = FontDataStatic | FontDataVariable;
28
- export declare const getFontData: (data: Uint8Array) => FontData;
29
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export { getFontData } from "./font-data";
@@ -1,64 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`getFontFaces() different formats 1`] = `
4
- [
5
- {
6
- "fontDisplay": "swap",
7
- "fontFamily": "Roboto",
8
- "fontStyle": "normal",
9
- "fontWeight": 400,
10
- "src": "url('/fonts/roboto.woff') format('woff'), url('/fonts/roboto.ttf') format('truetype')",
11
- },
12
- ]
13
- `;
14
-
15
- exports[`getFontFaces() different style 1`] = `
16
- [
17
- {
18
- "fontDisplay": "swap",
19
- "fontFamily": "Roboto",
20
- "fontStyle": "normal",
21
- "fontWeight": 400,
22
- "src": "url('/fonts/roboto.ttf') format('truetype')",
23
- },
24
- {
25
- "fontDisplay": "swap",
26
- "fontFamily": "Roboto",
27
- "fontStyle": "italic",
28
- "fontWeight": 400,
29
- "src": "url('/fonts/roboto-italic.ttf') format('truetype')",
30
- },
31
- ]
32
- `;
33
-
34
- exports[`getFontFaces() different weight 1`] = `
35
- [
36
- {
37
- "fontDisplay": "swap",
38
- "fontFamily": "Roboto",
39
- "fontStyle": "normal",
40
- "fontWeight": 400,
41
- "src": "url('/fonts/roboto.ttf') format('truetype')",
42
- },
43
- {
44
- "fontDisplay": "swap",
45
- "fontFamily": "Roboto",
46
- "fontStyle": "normal",
47
- "fontWeight": 500,
48
- "src": "url('/fonts/roboto-bold.ttf') format('truetype')",
49
- },
50
- ]
51
- `;
52
-
53
- exports[`getFontFaces() variable font 1`] = `
54
- [
55
- {
56
- "fontDisplay": "swap",
57
- "fontFamily": "Inter",
58
- "fontStretch": "25% 151%",
59
- "fontStyle": "normal",
60
- "fontWeight": "100 1000",
61
- "src": "url('/fonts/inter.ttf') format('truetype')",
62
- },
63
- ]
64
- `;
package/src/constants.ts DELETED
@@ -1,21 +0,0 @@
1
- import type { FontFormat } from "./schema";
2
-
3
- export const SYSTEM_FONTS = new Map([
4
- ["Arial", ["Roboto", "sans-serif"]],
5
- ["Times New Roman", ["sans"]],
6
- ["Courier New", ["monospace"]],
7
- ["system-ui", []],
8
- ]);
9
-
10
- export const DEFAULT_FONT_FALLBACK = "sans-serif";
11
-
12
- export const FONT_FORMATS: Map<FontFormat, string> = new Map([
13
- ["woff", "woff"],
14
- ["woff2", "woff2"],
15
- ["ttf", "truetype"],
16
- ["otf", "opentype"],
17
- ]);
18
-
19
- export const FONT_MIME_TYPES = Array.from(FONT_FORMATS.keys())
20
- .map((format) => `.${format}`)
21
- .join(", ");
@@ -1,70 +0,0 @@
1
- import { describe, test, expect } from "@jest/globals";
2
- import { parseSubfamily, normalizeFamily } from "./font-data";
3
-
4
- describe("font-data", () => {
5
- describe("parseSubfamily()", () => {
6
- test("Black Italic", () => {
7
- expect(parseSubfamily("Black Italic")).toEqual({
8
- style: "italic",
9
- weight: 900,
10
- });
11
- });
12
- test("Bold", () => {
13
- expect(parseSubfamily("Bold")).toEqual({
14
- style: "normal",
15
- weight: 700,
16
- });
17
- });
18
- test("Demi Bold Italic", () => {
19
- expect(parseSubfamily("Demi Bold Italic")).toEqual({
20
- style: "italic",
21
- weight: 600,
22
- });
23
- });
24
- test("Light", () => {
25
- expect(parseSubfamily("Light")).toEqual({
26
- style: "normal",
27
- weight: 300,
28
- });
29
- });
30
- test("Extra Light", () => {
31
- expect(parseSubfamily("Extra Light")).toEqual({
32
- style: "normal",
33
- weight: 200,
34
- });
35
- });
36
- test("Extra Light Italic", () => {
37
- expect(parseSubfamily("Extra Light Italic")).toEqual({
38
- style: "italic",
39
- weight: 200,
40
- });
41
- });
42
- test("Heavy Italic", () => {
43
- expect(parseSubfamily("Heavy Italic")).toEqual({
44
- style: "italic",
45
- weight: 900,
46
- });
47
- });
48
- test("Medium Italic", () => {
49
- expect(parseSubfamily("Medium Italic")).toEqual({
50
- style: "italic",
51
- weight: 500,
52
- });
53
- });
54
- });
55
-
56
- describe("normalizeFamily()", () => {
57
- test("basic", () => {
58
- expect(normalizeFamily("Roboto Black", "Black")).toBe("Roboto");
59
- expect(normalizeFamily("Roboto Light", "Light Italic")).toBe("Roboto");
60
- expect(normalizeFamily("Robolder Bold", "Bold")).toBe("Robolder");
61
- expect(normalizeFamily(" Roboto X Bold ", "Bold")).toBe("Roboto X");
62
- expect(normalizeFamily(" 'Roboto X' Bold ", "Bold")).toBe("'Roboto X'");
63
- expect(normalizeFamily(` "Roboto X" Bold `, "Bold")).toBe(`"Roboto X"`);
64
- expect(normalizeFamily(`"Roboto Bold"`, "Bold")).toBe(`"Roboto Bold"`);
65
- expect(normalizeFamily(`"Roboto Bold" Bold`, "Bold")).toBe(
66
- `"Roboto Bold"`
67
- );
68
- });
69
- });
70
- });
package/src/font-data.ts DELETED
@@ -1,88 +0,0 @@
1
- import type { FontFormat, VariationAxes } from "./schema";
2
- import { create as createFontKit } from "fontkit";
3
- import { type FontWeight, fontWeights } from "./font-weights";
4
-
5
- // @todo sumbit this to definitely typed, they are not up to date
6
- declare module "fontkit" {
7
- export interface Font {
8
- type: string;
9
- getName: (name: string) => string;
10
- variationAxes: VariationAxes;
11
- }
12
- }
13
-
14
- export const styles = ["normal", "italic", "oblique"] as const;
15
- type Style = (typeof styles)[number];
16
-
17
- export const parseSubfamily = (subfamily: string) => {
18
- const subfamilyLow = subfamily.toLowerCase();
19
- let style: Style = "normal";
20
- for (const possibleStyle of styles) {
21
- if (subfamilyLow.includes(possibleStyle)) {
22
- style = possibleStyle;
23
- break;
24
- }
25
- }
26
- let weight: FontWeight = "400";
27
- for (weight in fontWeights) {
28
- const { names } = fontWeights[weight];
29
- if (names.some((name) => subfamilyLow.includes(name))) {
30
- break;
31
- }
32
- }
33
- return { style, weight: Number(weight) };
34
- };
35
-
36
- const splitAndTrim = (string: string) =>
37
- string
38
- .split(" ")
39
- .map((part) => part.trim())
40
- .filter(Boolean);
41
-
42
- // Family name can contain additional information like "Roboto Black" or "Roboto Bold", though we need pure family name "Roboto", because the rest is already encoded in weight and style.
43
- // We need a name we can reference in CSS font-family property, while CSS matches it with the right font-face considering the weight and style.
44
- export const normalizeFamily = (family: string, subfamily: string) => {
45
- const familyParts = splitAndTrim(family);
46
- const subfamilyParts = splitAndTrim(subfamily.toLowerCase());
47
- const familyPartsNormalized = familyParts.filter(
48
- (familyPart) => subfamilyParts.includes(familyPart.toLowerCase()) === false
49
- );
50
- return familyPartsNormalized.join(" ");
51
- };
52
-
53
- type FontDataStatic = {
54
- format: FontFormat;
55
- family: string;
56
- style: Style;
57
- weight: number;
58
- };
59
- type FontDataVariable = {
60
- format: FontFormat;
61
- family: string;
62
- variationAxes: VariationAxes;
63
- };
64
- type FontData = FontDataStatic | FontDataVariable;
65
-
66
- export const getFontData = (data: Uint8Array): FontData => {
67
- const font = createFontKit(data as Buffer);
68
- const format = font.type.toLowerCase() as FontData["format"];
69
- const originalFamily = font.getName("fontFamily");
70
- const subfamily =
71
- font.getName("preferredSubfamily") ?? font.getName("fontSubfamily");
72
- const family = normalizeFamily(originalFamily, subfamily);
73
- const isVariable = Object.keys(font.variationAxes).length !== 0;
74
-
75
- if (isVariable) {
76
- return {
77
- format,
78
- family,
79
- variationAxes: font.variationAxes,
80
- };
81
- }
82
-
83
- return {
84
- format,
85
- family,
86
- ...parseSubfamily(subfamily),
87
- };
88
- };
@@ -1,40 +0,0 @@
1
- export const fontWeights = {
2
- "100": {
3
- label: "Thin",
4
- names: ["thin", "hairline"],
5
- },
6
- "200": {
7
- label: "Extra Light",
8
- names: ["extra light", "extralight", "ultra light", "ultralight"],
9
- },
10
- "300": {
11
- label: "Light",
12
- names: ["light"],
13
- },
14
- "400": {
15
- label: "Normal",
16
- names: ["normal", "regular"],
17
- },
18
- "500": {
19
- label: "Medium",
20
- names: ["medium"],
21
- },
22
- "600": {
23
- label: "Semi Bold",
24
- names: ["semi bold", "semibold", "demi bold", "demibold"],
25
- },
26
- "700": {
27
- label: "Bold",
28
- names: ["bold", "bold"],
29
- },
30
- "800": {
31
- label: "Extra Bold",
32
- names: ["extra bold", "extrabold", "ultra bold", "ultrabold"],
33
- },
34
- "900": {
35
- label: "Black",
36
- names: ["black", "heavy"],
37
- },
38
- } as const;
39
-
40
- export type FontWeight = keyof typeof fontWeights;
@@ -1,79 +0,0 @@
1
- import { FONT_FORMATS } from "./constants";
2
- import type { FontMeta, FontFormat, FontMetaStatic } from "./schema";
3
-
4
- export type PartialFontAsset = {
5
- format: FontFormat;
6
- meta: FontMeta;
7
- name: string;
8
- };
9
-
10
- export type FontFace = {
11
- fontFamily: string;
12
- fontDisplay: "swap" | "auto" | "block" | "fallback" | "optional";
13
- src: string;
14
- fontStyle?: FontMetaStatic["style"];
15
- fontWeight?: number | string;
16
- fontStretch?: string;
17
- };
18
-
19
- const formatFace = (
20
- asset: PartialFontAsset,
21
- format: string,
22
- url: string
23
- ): FontFace => {
24
- if ("variationAxes" in asset.meta) {
25
- const { wght, wdth } = asset.meta?.variationAxes ?? {};
26
- return {
27
- fontFamily: asset.meta.family,
28
- fontStyle: "normal",
29
- fontDisplay: "swap",
30
- src: `url('${url}') format('${format}')`,
31
- fontStretch: wdth ? `${wdth.min}% ${wdth.max}%` : undefined,
32
- fontWeight: wght ? `${wght.min} ${wght.max}` : undefined,
33
- };
34
- }
35
- return {
36
- fontFamily: asset.meta.family,
37
- fontStyle: asset.meta.style,
38
- fontWeight: asset.meta.weight,
39
- fontDisplay: "swap",
40
- src: `url('${url}') format('${format}')`,
41
- };
42
- };
43
-
44
- const getKey = (asset: PartialFontAsset) => {
45
- if ("variationAxes" in asset.meta) {
46
- return asset.meta.family + Object.values(asset.meta.variationAxes).join("");
47
- }
48
- return asset.meta.family + asset.meta.style + asset.meta.weight;
49
- };
50
-
51
- export const getFontFaces = (
52
- assets: Array<PartialFontAsset>,
53
- options: {
54
- assetBaseUrl: string;
55
- }
56
- ): Array<FontFace> => {
57
- const { assetBaseUrl } = options;
58
- const faces = new Map();
59
- for (const asset of assets) {
60
- const url = `${assetBaseUrl}${asset.name}`;
61
- const assetKey = getKey(asset);
62
- const face = faces.get(assetKey);
63
- const format = FONT_FORMATS.get(asset.format);
64
- if (format === undefined) {
65
- // Should never happen since we allow only uploading formats we support
66
- continue;
67
- }
68
-
69
- if (face === undefined) {
70
- const face = formatFace(asset, format, url);
71
- faces.set(assetKey, face);
72
- continue;
73
- }
74
-
75
- // We already have that font face, so we need to add the new src
76
- face.src += `, url('${url}') format('${format}')`;
77
- }
78
- return Array.from(faces.values());
79
- };
@@ -1 +0,0 @@
1
- export { getFontData } from "./font-data";
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./constants";
2
- export * from "./get-font-faces";
3
- export * from "./schema";
4
- export * from "./font-weights";
package/src/schema.ts DELETED
@@ -1,56 +0,0 @@
1
- import { z } from "zod";
2
- import { styles } from "./font-data";
3
-
4
- export const FontFormat = z.union([
5
- z.literal("ttf"),
6
- z.literal("woff"),
7
- z.literal("woff2"),
8
- z.literal("otf"),
9
- ]);
10
- export type FontFormat = z.infer<typeof FontFormat>;
11
-
12
- const AxisName = z.enum([
13
- "wght",
14
- "wdth",
15
- "slnt",
16
- "opsz",
17
- "ital",
18
- "GRAD",
19
- "XTRA",
20
- "XOPQ",
21
- "YOPQ",
22
- "YTLC",
23
- "YTUC",
24
- "YTAS",
25
- "YTDE",
26
- "YTFI",
27
- ]);
28
-
29
- const VariationAxes = z.record(
30
- AxisName,
31
- z.object({
32
- name: z.string(),
33
- min: z.number(),
34
- default: z.number(),
35
- max: z.number(),
36
- })
37
- );
38
-
39
- export type VariationAxes = z.infer<typeof VariationAxes>;
40
-
41
- export const FontMetaStatic = z.object({
42
- family: z.string(),
43
- style: z.enum(styles),
44
- weight: z.number(),
45
- });
46
-
47
- export type FontMetaStatic = z.infer<typeof FontMetaStatic>;
48
-
49
- const FontMetaVariable = z.object({
50
- family: z.string(),
51
- variationAxes: VariationAxes,
52
- });
53
-
54
- export const FontMeta = z.union([FontMetaStatic, FontMetaVariable]);
55
-
56
- export type FontMeta = z.infer<typeof FontMeta>;