fontaine 1.0.1 → 1.0.2
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/README.md +19 -8
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{metrics-DjL28VHB.cjs → metrics-CioeRv3e.cjs} +32 -9
- package/dist/{metrics-R5FQ6W30.mjs → metrics-Dru3RLLL.mjs} +32 -9
- package/dist/postcss.cjs +1 -1
- package/dist/postcss.mjs +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -183,9 +183,9 @@ const options = {
|
|
|
183
183
|
|
|
184
184
|
### Default Category Fallbacks
|
|
185
185
|
|
|
186
|
-
- **sans-serif**: `Segoe UI`, `Helvetica Neue`, `Arial`, `Noto Sans`
|
|
187
|
-
- **serif**: `Times New Roman`, `Georgia`, `Noto Serif`
|
|
188
|
-
- **monospace**: `Courier New`, `Roboto Mono`, `Noto Sans Mono`
|
|
186
|
+
- **sans-serif**: `Segoe UI`, `Helvetica Neue`, `Arial`, `Noto Sans`, `Liberation Sans`
|
|
187
|
+
- **serif**: `Times New Roman`, `Georgia`, `Noto Serif`, `Liberation Serif`
|
|
188
|
+
- **monospace**: `Courier New`, `Roboto Mono`, `Noto Sans Mono`, `Liberation Mono`
|
|
189
189
|
- **display** & **handwriting**: Same as sans-serif
|
|
190
190
|
|
|
191
191
|
> **Note:** These presets are available programmatically via `DEFAULT_CATEGORY_FALLBACKS` and can be used with the `resolveCategoryFallbacks` helper function for advanced use cases. Both are exported from the `fontaine` package and shared across related packages (e.g., `fontless`) to ensure consistent fallback behavior.
|
|
@@ -226,15 +226,26 @@ Example:
|
|
|
226
226
|
format('woff');
|
|
227
227
|
font-weight: 700;
|
|
228
228
|
}
|
|
229
|
-
/*
|
|
229
|
+
/* One additional font-face declaration per fallback font will be added to your CSS. */
|
|
230
230
|
@font-face {
|
|
231
231
|
font-family: 'Roboto fallback';
|
|
232
|
-
src: local('Segoe UI'), local('
|
|
233
|
-
local('
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
src: local('Segoe UI'), local('Segoe UI Regular'), local('SegoeUI-Regular'),
|
|
233
|
+
local('SegoeUI');
|
|
234
|
+
size-adjust: 100.3304%;
|
|
235
|
+
ascent-override: 92.4679%;
|
|
236
|
+
descent-override: 24.3337%;
|
|
236
237
|
line-gap-override: 0%;
|
|
237
238
|
}
|
|
239
|
+
@font-face {
|
|
240
|
+
font-family: 'Roboto fallback';
|
|
241
|
+
src: local('Arial'), local('Arial Regular'), local('Arial-Regular'),
|
|
242
|
+
local('ArialMT');
|
|
243
|
+
size-adjust: 99.7809%;
|
|
244
|
+
ascent-override: 92.9771%;
|
|
245
|
+
descent-override: 24.4677%;
|
|
246
|
+
line-gap-override: 0%;
|
|
247
|
+
}
|
|
248
|
+
/* ... */
|
|
238
249
|
```
|
|
239
250
|
|
|
240
251
|
Then, whenever you use `font-family: 'Roboto'`, `fontaine` will add the fallback to the font-family:
|
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
|
-
const require_metrics = require("./metrics-
|
|
24
|
+
const require_metrics = require("./metrics-CioeRv3e.cjs");
|
|
25
25
|
let css_tree = require("css-tree");
|
|
26
26
|
let node_path = require("node:path");
|
|
27
27
|
let node_url = require("node:url");
|
package/dist/index.d.cts
CHANGED
|
@@ -28,7 +28,7 @@ interface FallbackOptions {
|
|
|
28
28
|
*/
|
|
29
29
|
[key: string]: any;
|
|
30
30
|
}
|
|
31
|
-
type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm" | "xWidthAvg"> & {
|
|
31
|
+
type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm" | "xWidthAvg"> & Partial<Pick<Font, "fullName" | "postscriptName">> & {
|
|
32
32
|
category?: string;
|
|
33
33
|
};
|
|
34
34
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -28,7 +28,7 @@ interface FallbackOptions {
|
|
|
28
28
|
*/
|
|
29
29
|
[key: string]: any;
|
|
30
30
|
}
|
|
31
|
-
type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm" | "xWidthAvg"> & {
|
|
31
|
+
type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm" | "xWidthAvg"> & Partial<Pick<Font, "fullName" | "postscriptName">> & {
|
|
32
32
|
category?: string;
|
|
33
33
|
};
|
|
34
34
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, i as DEFAULT_CATEGORY_FALLBACKS, l as genericCSSFamilies, n as readMetrics, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-
|
|
1
|
+
import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, i as DEFAULT_CATEGORY_FALLBACKS, l as genericCSSFamilies, n as readMetrics, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-Dru3RLLL.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { parse, walk } from "css-tree";
|
|
4
4
|
import { isAbsolute } from "node:path";
|
|
@@ -188,7 +188,7 @@ function generateFontFace(metrics, fallback) {
|
|
|
188
188
|
const lineGapOverride = metrics.lineGap / adjustedEmSquare;
|
|
189
189
|
return `@font-face {\n${toCSS({
|
|
190
190
|
"font-family": JSON.stringify(fallbackName),
|
|
191
|
-
"src": renderLocalSrc(fallbackFontName),
|
|
191
|
+
"src": renderLocalSrc(fallbackFontName, fallbackMetrics),
|
|
192
192
|
"size-adjust": toPercentage(sizeAdjust),
|
|
193
193
|
"ascent-override": toPercentage(ascentOverride),
|
|
194
194
|
"descent-override": toPercentage(descentOverride),
|
|
@@ -196,8 +196,16 @@ function generateFontFace(metrics, fallback) {
|
|
|
196
196
|
...properties
|
|
197
197
|
})}\n}\n`;
|
|
198
198
|
}
|
|
199
|
-
function renderLocalSrc(font) {
|
|
200
|
-
|
|
199
|
+
function renderLocalSrc(font, metrics) {
|
|
200
|
+
const family = withoutQuotes(font);
|
|
201
|
+
const families = genericFamilyLocals[family.toLowerCase()] || [family];
|
|
202
|
+
const names = new Set(families.flatMap((family) => [
|
|
203
|
+
family,
|
|
204
|
+
`${family} Regular`,
|
|
205
|
+
`${family.replace(/\s+/g, "")}-Regular`
|
|
206
|
+
]));
|
|
207
|
+
for (const name of [metrics?.fullName, metrics?.postscriptName]) if (name) names.add(name);
|
|
208
|
+
return [...names].map((local) => `local(${JSON.stringify(local)})`).join(", ");
|
|
201
209
|
}
|
|
202
210
|
//#endregion
|
|
203
211
|
//#region src/fallbacks.ts
|
|
@@ -210,29 +218,34 @@ const DEFAULT_CATEGORY_FALLBACKS = {
|
|
|
210
218
|
"Segoe UI",
|
|
211
219
|
"Helvetica Neue",
|
|
212
220
|
"Arial",
|
|
213
|
-
"Noto Sans"
|
|
221
|
+
"Noto Sans",
|
|
222
|
+
"Liberation Sans"
|
|
214
223
|
],
|
|
215
224
|
"serif": [
|
|
216
225
|
"Times New Roman",
|
|
217
226
|
"Georgia",
|
|
218
|
-
"Noto Serif"
|
|
227
|
+
"Noto Serif",
|
|
228
|
+
"Liberation Serif"
|
|
219
229
|
],
|
|
220
230
|
"monospace": [
|
|
221
231
|
"Courier New",
|
|
222
232
|
"Roboto Mono",
|
|
223
|
-
"Noto Sans Mono"
|
|
233
|
+
"Noto Sans Mono",
|
|
234
|
+
"Liberation Mono"
|
|
224
235
|
],
|
|
225
236
|
"display": [
|
|
226
237
|
"Segoe UI",
|
|
227
238
|
"Helvetica Neue",
|
|
228
239
|
"Arial",
|
|
229
|
-
"Noto Sans"
|
|
240
|
+
"Noto Sans",
|
|
241
|
+
"Liberation Sans"
|
|
230
242
|
],
|
|
231
243
|
"handwriting": [
|
|
232
244
|
"Segoe UI",
|
|
233
245
|
"Helvetica Neue",
|
|
234
246
|
"Arial",
|
|
235
|
-
"Noto Sans"
|
|
247
|
+
"Noto Sans",
|
|
248
|
+
"Liberation Sans"
|
|
236
249
|
]
|
|
237
250
|
};
|
|
238
251
|
/**
|
|
@@ -267,6 +280,11 @@ function resolveCategoryFallbacks(options) {
|
|
|
267
280
|
//#endregion
|
|
268
281
|
//#region src/metrics.ts
|
|
269
282
|
const metricCache = {};
|
|
283
|
+
const metricAliases = {
|
|
284
|
+
"liberation sans": "Arimo",
|
|
285
|
+
"liberation serif": "Tinos",
|
|
286
|
+
"liberation mono": "Cousine"
|
|
287
|
+
};
|
|
270
288
|
function filterRequiredMetrics(font) {
|
|
271
289
|
return {
|
|
272
290
|
ascent: font.ascent,
|
|
@@ -287,7 +305,8 @@ async function getMetricsForFamily(family) {
|
|
|
287
305
|
family = withoutQuotes(family);
|
|
288
306
|
if (family in metricCache) return metricCache[family] ?? null;
|
|
289
307
|
try {
|
|
290
|
-
const
|
|
308
|
+
const alias = metricAliases[family.toLowerCase()];
|
|
309
|
+
const name = fontFamilyToCamelCase(alias ?? family);
|
|
291
310
|
const { entireMetricsCollection } = await import("#capsize-font-metrics");
|
|
292
311
|
const metrics = entireMetricsCollection[name];
|
|
293
312
|
/* v8 ignore next 4 */
|
|
@@ -296,6 +315,10 @@ async function getMetricsForFamily(family) {
|
|
|
296
315
|
return null;
|
|
297
316
|
}
|
|
298
317
|
const filteredMetrics = filterRequiredMetrics(metrics);
|
|
318
|
+
if (!alias) {
|
|
319
|
+
filteredMetrics.fullName = metrics.fullName;
|
|
320
|
+
filteredMetrics.postscriptName = metrics.postscriptName;
|
|
321
|
+
}
|
|
299
322
|
metricCache[family] = filteredMetrics;
|
|
300
323
|
return filteredMetrics;
|
|
301
324
|
} catch {
|
|
@@ -188,7 +188,7 @@ function generateFontFace(metrics, fallback) {
|
|
|
188
188
|
const lineGapOverride = metrics.lineGap / adjustedEmSquare;
|
|
189
189
|
return `@font-face {\n${toCSS({
|
|
190
190
|
"font-family": JSON.stringify(fallbackName),
|
|
191
|
-
"src": renderLocalSrc(fallbackFontName),
|
|
191
|
+
"src": renderLocalSrc(fallbackFontName, fallbackMetrics),
|
|
192
192
|
"size-adjust": toPercentage(sizeAdjust),
|
|
193
193
|
"ascent-override": toPercentage(ascentOverride),
|
|
194
194
|
"descent-override": toPercentage(descentOverride),
|
|
@@ -196,8 +196,16 @@ function generateFontFace(metrics, fallback) {
|
|
|
196
196
|
...properties
|
|
197
197
|
})}\n}\n`;
|
|
198
198
|
}
|
|
199
|
-
function renderLocalSrc(font) {
|
|
200
|
-
|
|
199
|
+
function renderLocalSrc(font, metrics) {
|
|
200
|
+
const family = withoutQuotes(font);
|
|
201
|
+
const families = genericFamilyLocals[family.toLowerCase()] || [family];
|
|
202
|
+
const names = new Set(families.flatMap((family) => [
|
|
203
|
+
family,
|
|
204
|
+
`${family} Regular`,
|
|
205
|
+
`${family.replace(/\s+/g, "")}-Regular`
|
|
206
|
+
]));
|
|
207
|
+
for (const name of [metrics?.fullName, metrics?.postscriptName]) if (name) names.add(name);
|
|
208
|
+
return [...names].map((local) => `local(${JSON.stringify(local)})`).join(", ");
|
|
201
209
|
}
|
|
202
210
|
//#endregion
|
|
203
211
|
//#region src/fallbacks.ts
|
|
@@ -210,29 +218,34 @@ const DEFAULT_CATEGORY_FALLBACKS = {
|
|
|
210
218
|
"Segoe UI",
|
|
211
219
|
"Helvetica Neue",
|
|
212
220
|
"Arial",
|
|
213
|
-
"Noto Sans"
|
|
221
|
+
"Noto Sans",
|
|
222
|
+
"Liberation Sans"
|
|
214
223
|
],
|
|
215
224
|
"serif": [
|
|
216
225
|
"Times New Roman",
|
|
217
226
|
"Georgia",
|
|
218
|
-
"Noto Serif"
|
|
227
|
+
"Noto Serif",
|
|
228
|
+
"Liberation Serif"
|
|
219
229
|
],
|
|
220
230
|
"monospace": [
|
|
221
231
|
"Courier New",
|
|
222
232
|
"Roboto Mono",
|
|
223
|
-
"Noto Sans Mono"
|
|
233
|
+
"Noto Sans Mono",
|
|
234
|
+
"Liberation Mono"
|
|
224
235
|
],
|
|
225
236
|
"display": [
|
|
226
237
|
"Segoe UI",
|
|
227
238
|
"Helvetica Neue",
|
|
228
239
|
"Arial",
|
|
229
|
-
"Noto Sans"
|
|
240
|
+
"Noto Sans",
|
|
241
|
+
"Liberation Sans"
|
|
230
242
|
],
|
|
231
243
|
"handwriting": [
|
|
232
244
|
"Segoe UI",
|
|
233
245
|
"Helvetica Neue",
|
|
234
246
|
"Arial",
|
|
235
|
-
"Noto Sans"
|
|
247
|
+
"Noto Sans",
|
|
248
|
+
"Liberation Sans"
|
|
236
249
|
]
|
|
237
250
|
};
|
|
238
251
|
/**
|
|
@@ -267,6 +280,11 @@ function resolveCategoryFallbacks(options) {
|
|
|
267
280
|
//#endregion
|
|
268
281
|
//#region src/metrics.ts
|
|
269
282
|
const metricCache = {};
|
|
283
|
+
const metricAliases = {
|
|
284
|
+
"liberation sans": "Arimo",
|
|
285
|
+
"liberation serif": "Tinos",
|
|
286
|
+
"liberation mono": "Cousine"
|
|
287
|
+
};
|
|
270
288
|
function filterRequiredMetrics(font) {
|
|
271
289
|
return {
|
|
272
290
|
ascent: font.ascent,
|
|
@@ -287,7 +305,8 @@ async function getMetricsForFamily(family) {
|
|
|
287
305
|
family = withoutQuotes(family);
|
|
288
306
|
if (family in metricCache) return metricCache[family] ?? null;
|
|
289
307
|
try {
|
|
290
|
-
const
|
|
308
|
+
const alias = metricAliases[family.toLowerCase()];
|
|
309
|
+
const name = fontFamilyToCamelCase(alias ?? family);
|
|
291
310
|
const { entireMetricsCollection } = await import("#capsize-font-metrics");
|
|
292
311
|
const metrics = entireMetricsCollection[name];
|
|
293
312
|
/* v8 ignore next 4 */
|
|
@@ -296,6 +315,10 @@ async function getMetricsForFamily(family) {
|
|
|
296
315
|
return null;
|
|
297
316
|
}
|
|
298
317
|
const filteredMetrics = filterRequiredMetrics(metrics);
|
|
318
|
+
if (!alias) {
|
|
319
|
+
filteredMetrics.fullName = metrics.fullName;
|
|
320
|
+
filteredMetrics.postscriptName = metrics.postscriptName;
|
|
321
|
+
}
|
|
299
322
|
metricCache[family] = filteredMetrics;
|
|
300
323
|
return filteredMetrics;
|
|
301
324
|
} catch {
|
package/dist/postcss.cjs
CHANGED
package/dist/postcss.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, l as genericCSSFamilies, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-
|
|
1
|
+
import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, l as genericCSSFamilies, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-Dru3RLLL.mjs";
|
|
2
2
|
import { parse } from "css-tree";
|
|
3
3
|
//#region src/postcss.ts
|
|
4
4
|
const supportedExtensions = [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fontaine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"description": "Automatic font fallback based on font metrics",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Daniel Roe",
|
|
@@ -68,16 +68,16 @@
|
|
|
68
68
|
"@types/css-tree": "3.2.0",
|
|
69
69
|
"@types/node": "24.19.1",
|
|
70
70
|
"@types/serve-handler": "6.1.4",
|
|
71
|
-
"@vitest/coverage-v8": "5.0.
|
|
72
|
-
"eslint": "10.
|
|
71
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
72
|
+
"eslint": "10.13.0",
|
|
73
73
|
"get-port-please": "3.2.0",
|
|
74
74
|
"magic-regexp": "0.11.2",
|
|
75
75
|
"postcss": "8.5.29",
|
|
76
76
|
"serve-handler": "6.1.7",
|
|
77
77
|
"tsdown": "0.23.0",
|
|
78
78
|
"typescript": "6.0.3",
|
|
79
|
-
"vite": "8.3.
|
|
80
|
-
"vitest": "5.0.
|
|
79
|
+
"vite": "8.3.4",
|
|
80
|
+
"vitest": "5.0.5"
|
|
81
81
|
},
|
|
82
82
|
"scripts": {
|
|
83
83
|
"build": "tsdown",
|