@webstudio-is/fonts 0.0.0-588fe22 → 0.0.0-7a19155

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/index.js CHANGED
@@ -246,78 +246,98 @@ var FONT_STYLES = ["normal", "italic", "oblique"];
246
246
 
247
247
  // src/get-font-faces.ts
248
248
  var sanitizeCssUrl = (str) => JSON.stringify(str);
249
- var formatFace = (asset, format, url) => {
249
+ var fontFormatOrder = Array.from(FONT_FORMATS.values());
250
+ var getFontFormat = (asset) => {
251
+ const extension = asset.name.slice(asset.name.lastIndexOf(".") + 1);
252
+ return FONT_FORMATS.has(extension) ? FONT_FORMATS.get(extension) ?? asset.format : FONT_FORMATS.get(asset.format) ?? asset.format;
253
+ };
254
+ var formatFace = ({ asset, format, style, url }) => {
255
+ const face = {
256
+ fontFamily: asset.meta.family,
257
+ fontStyle: style,
258
+ fontDisplay: "swap",
259
+ src: `url(${sanitizeCssUrl(url)}) format("${format}")`
260
+ };
250
261
  if ("variationAxes" in asset.meta) {
251
- const { wght, wdth } = asset.meta?.variationAxes ?? {};
262
+ const { wght, wdth } = asset.meta.variationAxes;
252
263
  return {
253
- fontFamily: asset.meta.family,
254
- fontStyle: "normal",
255
- fontDisplay: "swap",
256
- src: `url(${sanitizeCssUrl(url)}) format("${format}")`,
264
+ ...face,
257
265
  fontStretch: wdth ? `${wdth.min}% ${wdth.max}%` : void 0,
258
266
  fontWeight: wght ? `${wght.min} ${wght.max}` : void 0
259
267
  };
260
268
  }
261
269
  return {
262
- fontFamily: asset.meta.family,
263
- fontStyle: asset.meta.style,
264
- fontWeight: asset.meta.weight,
265
- fontDisplay: "swap",
266
- src: `url(${sanitizeCssUrl(url)}) format("${format}")`
270
+ ...face,
271
+ fontWeight: asset.meta.weight
267
272
  };
268
273
  };
269
- var getKey = (asset) => {
274
+ var getKey = (asset, style) => {
270
275
  if ("variationAxes" in asset.meta) {
271
- return asset.meta.family + Object.values(asset.meta.variationAxes).join("");
276
+ const { wght, wdth } = asset.meta.variationAxes;
277
+ return JSON.stringify([asset.meta.family, style, wght, wdth]);
278
+ }
279
+ return JSON.stringify([asset.meta.family, style, asset.meta.weight]);
280
+ };
281
+ var getStyles = (meta) => {
282
+ const styles = /* @__PURE__ */ new Set([meta.style]);
283
+ if ("variationAxes" in meta) {
284
+ const { ital, slnt } = meta.variationAxes;
285
+ if (ital !== void 0 && ital.min <= 0 && ital.max >= 1) {
286
+ styles.add("normal");
287
+ styles.add("italic");
288
+ }
289
+ if (slnt !== void 0 && slnt.min < slnt.max && slnt.min <= 0 && slnt.max >= 0) {
290
+ styles.add("normal");
291
+ styles.add("oblique");
292
+ }
272
293
  }
273
- return asset.meta.family + asset.meta.style + asset.meta.weight;
294
+ return Array.from(styles);
274
295
  };
275
296
  var getFontFaces = (assets, options) => {
276
297
  const { assetBaseUrl } = options;
277
298
  const faces = /* @__PURE__ */ new Map();
299
+ const seenSources = /* @__PURE__ */ new Set();
278
300
  for (const asset of assets) {
279
301
  const url = `${assetBaseUrl}${asset.name}`;
280
- const assetKey = getKey(asset);
281
- const face = faces.get(assetKey);
282
- const format = FONT_FORMATS.get(asset.format);
283
- if (format === void 0) {
284
- continue;
302
+ for (const style of getStyles(asset.meta)) {
303
+ const sourceKey = JSON.stringify([url, style]);
304
+ if (seenSources.has(sourceKey)) {
305
+ continue;
306
+ }
307
+ seenSources.add(sourceKey);
308
+ const assetKey = getKey(asset, style);
309
+ const format = getFontFormat(asset);
310
+ const sources = faces.get(assetKey) ?? /* @__PURE__ */ new Map();
311
+ const existing = sources.get(format);
312
+ if (existing === void 0 || url < existing.url) {
313
+ sources.set(format, { asset, format, style, url });
314
+ }
315
+ faces.set(assetKey, sources);
285
316
  }
286
- if (face === void 0) {
287
- const face2 = formatFace(asset, format, url);
288
- faces.set(assetKey, face2);
289
- continue;
290
- }
291
- face.src += `, url(${sanitizeCssUrl(url)}) format("${format}")`;
292
317
  }
293
- return Array.from(faces.values());
318
+ return Array.from(faces.values(), (sources) => {
319
+ const [source, ...fallbacks] = Array.from(sources.values()).sort(
320
+ (left, right) => fontFormatOrder.indexOf(left.format) - fontFormatOrder.indexOf(right.format)
321
+ );
322
+ const face = formatFace(source);
323
+ face.src += fallbacks.map(
324
+ ({ format: fallbackFormat, url: fallbackUrl }) => `, url(${sanitizeCssUrl(fallbackUrl)}) format("${fallbackFormat}")`
325
+ ).join("");
326
+ return face;
327
+ });
294
328
  };
295
329
 
296
330
  // src/schema.ts
297
331
  import { z } from "zod";
298
- var FontFormat = z.union([
332
+ var fontStyle = z.enum(FONT_STYLES);
333
+ var fontFormat = z.union([
299
334
  z.literal("ttf"),
300
335
  z.literal("woff"),
301
336
  z.literal("woff2")
302
337
  ]);
303
- var AxisName = z.enum([
304
- "wght",
305
- "wdth",
306
- "slnt",
307
- "opsz",
308
- "ital",
309
- "GRAD",
310
- "XTRA",
311
- "XOPQ",
312
- "YOPQ",
313
- "YTLC",
314
- "YTUC",
315
- "YTAS",
316
- "YTDE",
317
- "YTFI"
318
- ]);
319
- var VariationAxes = z.record(
320
- AxisName,
338
+ var axisName = z.string().regex(/^[A-Za-z][A-Za-z0-9]* *$/).length(4);
339
+ var variationAxes = z.partialRecord(
340
+ axisName,
321
341
  z.object({
322
342
  name: z.string(),
323
343
  min: z.number(),
@@ -325,16 +345,48 @@ var VariationAxes = z.record(
325
345
  max: z.number()
326
346
  })
327
347
  );
328
- var FontMetaStatic = z.object({
348
+ var fontMetaStatic = z.object({
329
349
  family: z.string(),
330
- style: z.enum(FONT_STYLES),
350
+ style: fontStyle,
331
351
  weight: z.number()
332
352
  });
333
- var FontMetaVariable = z.object({
353
+ var fontMetaVariable = z.object({
334
354
  family: z.string(),
335
- variationAxes: VariationAxes
355
+ style: fontStyle.default("normal"),
356
+ variationAxes
336
357
  });
337
- var FontMeta = z.union([FontMetaStatic, FontMetaVariable]);
358
+ var fontMeta = z.union([fontMetaStatic, fontMetaVariable]);
359
+ var fontMetaUpdate = z.union([
360
+ fontMetaStatic.partial().strict(),
361
+ z.object({
362
+ family: fontMetaVariable.shape.family.optional(),
363
+ style: fontStyle.optional(),
364
+ variationAxes: fontMetaVariable.shape.variationAxes.optional()
365
+ }).strict()
366
+ ]);
367
+ var mergeFontMeta = (current, override) => {
368
+ const result = fontMetaUpdate.safeParse(override);
369
+ if (result.success === false) {
370
+ return;
371
+ }
372
+ const { family, style } = result.data;
373
+ if ("variationAxes" in current) {
374
+ const variationAxes2 = "variationAxes" in result.data ? result.data.variationAxes : void 0;
375
+ return {
376
+ ...current,
377
+ ...family === void 0 ? {} : { family },
378
+ ...style === void 0 ? {} : { style },
379
+ ...variationAxes2 === void 0 ? {} : { variationAxes: variationAxes2 }
380
+ };
381
+ }
382
+ const weight = "weight" in result.data ? result.data.weight : void 0;
383
+ return {
384
+ ...current,
385
+ ...family === void 0 ? {} : { family },
386
+ ...style === void 0 ? {} : { style },
387
+ ...weight === void 0 ? {} : { weight }
388
+ };
389
+ };
338
390
 
339
391
  // src/font-weights.ts
340
392
  var fontWeights = {
@@ -364,7 +416,7 @@ var fontWeights = {
364
416
  },
365
417
  "700": {
366
418
  label: "Bold",
367
- names: ["bold", "bold"]
419
+ names: ["bold"]
368
420
  },
369
421
  "800": {
370
422
  label: "Extra Bold",
@@ -386,11 +438,14 @@ export {
386
438
  FONT_FORMATS,
387
439
  FONT_MIME_TYPES,
388
440
  FONT_STYLES,
389
- FontFormat,
390
- FontMeta,
391
- FontMetaStatic,
392
441
  SYSTEM_FONTS,
442
+ fontFormat,
443
+ fontMeta,
444
+ fontMetaStatic,
445
+ fontMetaUpdate,
446
+ fontMetaVariable,
393
447
  fontWeightNames,
394
448
  fontWeights,
395
- getFontFaces
449
+ getFontFaces,
450
+ mergeFontMeta
396
451
  };
@@ -25,7 +25,7 @@ export declare const fontWeights: {
25
25
  };
26
26
  readonly "700": {
27
27
  readonly label: "Bold";
28
- readonly names: readonly ["bold", "bold"];
28
+ readonly names: readonly ["bold"];
29
29
  };
30
30
  readonly "800": {
31
31
  readonly label: "Extra Bold";
@@ -1,4 +1,5 @@
1
- import type { FontMeta, FontFormat, FontMetaStatic } from "./schema";
1
+ import { type FontStyle } from "./constants";
2
+ import type { FontMeta, FontFormat } from "./schema";
2
3
  export type PartialFontAsset = {
3
4
  format: FontFormat;
4
5
  meta: FontMeta;
@@ -8,7 +9,7 @@ export type FontFace = {
8
9
  fontFamily: string;
9
10
  fontDisplay: "swap" | "auto" | "block" | "fallback" | "optional";
10
11
  src: string;
11
- fontStyle?: FontMetaStatic["style"];
12
+ fontStyle?: FontStyle;
12
13
  fontWeight?: number | string;
13
14
  fontStretch?: string;
14
15
  };
@@ -1,83 +1,81 @@
1
1
  import { z } from "zod";
2
- export declare const FontFormat: z.ZodUnion<[z.ZodLiteral<"ttf">, z.ZodLiteral<"woff">, z.ZodLiteral<"woff2">]>;
3
- export type FontFormat = z.infer<typeof FontFormat>;
4
- declare const VariationAxes: z.ZodRecord<z.ZodEnum<["wght", "wdth", "slnt", "opsz", "ital", "GRAD", "XTRA", "XOPQ", "YOPQ", "YTLC", "YTUC", "YTAS", "YTDE", "YTFI"]>, z.ZodObject<{
2
+ export declare const fontFormat: z.ZodUnion<readonly [z.ZodLiteral<"ttf">, z.ZodLiteral<"woff">, z.ZodLiteral<"woff2">]>;
3
+ export type FontFormat = z.infer<typeof fontFormat>;
4
+ declare const variationAxes: z.ZodRecord<z.ZodString & z.core.$partial, z.ZodObject<{
5
5
  name: z.ZodString;
6
6
  min: z.ZodNumber;
7
7
  default: z.ZodNumber;
8
8
  max: z.ZodNumber;
9
- }, "strip", z.ZodTypeAny, {
10
- name: string;
11
- min: number;
12
- default: number;
13
- max: number;
14
- }, {
15
- name: string;
16
- min: number;
17
- default: number;
18
- max: number;
19
- }>>;
20
- export type VariationAxes = z.infer<typeof VariationAxes>;
21
- export declare const FontMetaStatic: z.ZodObject<{
9
+ }, z.core.$strip>>;
10
+ export type VariationAxes = z.infer<typeof variationAxes>;
11
+ export declare const fontMetaStatic: z.ZodObject<{
22
12
  family: z.ZodString;
23
- style: z.ZodEnum<["normal", "italic", "oblique"]>;
13
+ style: z.ZodEnum<{
14
+ italic: "italic";
15
+ normal: "normal";
16
+ oblique: "oblique";
17
+ }>;
24
18
  weight: z.ZodNumber;
25
- }, "strip", z.ZodTypeAny, {
26
- family: string;
27
- style: "normal" | "italic" | "oblique";
28
- weight: number;
29
- }, {
30
- family: string;
31
- style: "normal" | "italic" | "oblique";
32
- weight: number;
33
- }>;
34
- export type FontMetaStatic = z.infer<typeof FontMetaStatic>;
35
- export declare const FontMeta: z.ZodUnion<[z.ZodObject<{
19
+ }, z.core.$strip>;
20
+ export type FontMetaStatic = z.infer<typeof fontMetaStatic>;
21
+ export declare const fontMetaVariable: z.ZodObject<{
36
22
  family: z.ZodString;
37
- style: z.ZodEnum<["normal", "italic", "oblique"]>;
23
+ style: z.ZodDefault<z.ZodEnum<{
24
+ italic: "italic";
25
+ normal: "normal";
26
+ oblique: "oblique";
27
+ }>>;
28
+ variationAxes: z.ZodRecord<z.ZodString & z.core.$partial, z.ZodObject<{
29
+ name: z.ZodString;
30
+ min: z.ZodNumber;
31
+ default: z.ZodNumber;
32
+ max: z.ZodNumber;
33
+ }, z.core.$strip>>;
34
+ }, z.core.$strip>;
35
+ export declare const fontMeta: z.ZodUnion<readonly [z.ZodObject<{
36
+ family: z.ZodString;
37
+ style: z.ZodEnum<{
38
+ italic: "italic";
39
+ normal: "normal";
40
+ oblique: "oblique";
41
+ }>;
38
42
  weight: z.ZodNumber;
39
- }, "strip", z.ZodTypeAny, {
40
- family: string;
41
- style: "normal" | "italic" | "oblique";
42
- weight: number;
43
- }, {
44
- family: string;
45
- style: "normal" | "italic" | "oblique";
46
- weight: number;
47
- }>, z.ZodObject<{
43
+ }, z.core.$strip>, z.ZodObject<{
48
44
  family: z.ZodString;
49
- variationAxes: z.ZodRecord<z.ZodEnum<["wght", "wdth", "slnt", "opsz", "ital", "GRAD", "XTRA", "XOPQ", "YOPQ", "YTLC", "YTUC", "YTAS", "YTDE", "YTFI"]>, z.ZodObject<{
45
+ style: z.ZodDefault<z.ZodEnum<{
46
+ italic: "italic";
47
+ normal: "normal";
48
+ oblique: "oblique";
49
+ }>>;
50
+ variationAxes: z.ZodRecord<z.ZodString & z.core.$partial, z.ZodObject<{
50
51
  name: z.ZodString;
51
52
  min: z.ZodNumber;
52
53
  default: z.ZodNumber;
53
54
  max: z.ZodNumber;
54
- }, "strip", z.ZodTypeAny, {
55
- name: string;
56
- min: number;
57
- default: number;
58
- max: number;
59
- }, {
60
- name: string;
61
- min: number;
62
- default: number;
63
- max: number;
64
- }>>;
65
- }, "strip", z.ZodTypeAny, {
66
- family: string;
67
- variationAxes: Partial<Record<"wght" | "wdth" | "slnt" | "opsz" | "ital" | "GRAD" | "XTRA" | "XOPQ" | "YOPQ" | "YTLC" | "YTUC" | "YTAS" | "YTDE" | "YTFI", {
68
- name: string;
69
- min: number;
70
- default: number;
71
- max: number;
55
+ }, z.core.$strip>>;
56
+ }, z.core.$strip>]>;
57
+ export declare const fontMetaUpdate: z.ZodUnion<readonly [z.ZodObject<{
58
+ family: z.ZodOptional<z.ZodString>;
59
+ style: z.ZodOptional<z.ZodEnum<{
60
+ italic: "italic";
61
+ normal: "normal";
62
+ oblique: "oblique";
72
63
  }>>;
73
- }, {
74
- family: string;
75
- variationAxes: Partial<Record<"wght" | "wdth" | "slnt" | "opsz" | "ital" | "GRAD" | "XTRA" | "XOPQ" | "YOPQ" | "YTLC" | "YTUC" | "YTAS" | "YTDE" | "YTFI", {
76
- name: string;
77
- min: number;
78
- default: number;
79
- max: number;
64
+ weight: z.ZodOptional<z.ZodNumber>;
65
+ }, z.core.$strict>, z.ZodObject<{
66
+ family: z.ZodOptional<z.ZodString>;
67
+ style: z.ZodOptional<z.ZodEnum<{
68
+ italic: "italic";
69
+ normal: "normal";
70
+ oblique: "oblique";
80
71
  }>>;
81
- }>]>;
82
- export type FontMeta = z.infer<typeof FontMeta>;
72
+ variationAxes: z.ZodOptional<z.ZodRecord<z.ZodString & z.core.$partial, z.ZodObject<{
73
+ name: z.ZodString;
74
+ min: z.ZodNumber;
75
+ default: z.ZodNumber;
76
+ max: z.ZodNumber;
77
+ }, z.core.$strip>>>;
78
+ }, z.core.$strict>]>;
79
+ export type FontMeta = z.infer<typeof fontMeta>;
80
+ export declare const mergeFontMeta: (current: FontMeta, override: unknown) => FontMeta | undefined;
83
81
  export {};
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@webstudio-is/fonts",
3
- "version": "0.0.0-588fe22",
3
+ "version": "0.0.0-7a19155",
4
4
  "description": "Fonts utils",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
7
7
  "type": "module",
8
8
  "devDependencies": {
9
- "vitest": "^3.0.2",
10
- "zod": "^3.22.4",
9
+ "vitest": "^3.1.2",
10
+ "zod": "^4.4.3",
11
11
  "@webstudio-is/tsconfig": "1.0.7"
12
12
  },
13
13
  "peerDependencies": {
14
- "zod": "^3.19.1"
14
+ "zod": "^4.4.3"
15
15
  },
16
16
  "exports": {
17
17
  "webstudio": "./src/index.ts",
@@ -26,7 +26,7 @@
26
26
  "private": false,
27
27
  "sideEffects": false,
28
28
  "scripts": {
29
- "typecheck": "tsc",
29
+ "typecheck": "tsc --noEmit",
30
30
  "test": "vitest run",
31
31
  "build": "rm -rf lib && esbuild src/index.ts --outdir=lib --bundle --format=esm --packages=external",
32
32
  "dts": "tsc --project tsconfig.dts.json"
@@ -1 +0,0 @@
1
- export {};