@liiift-studio/sanity-font-manager 2.3.19 → 2.5.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/README.md +437 -437
- package/dist/UploadModal-6LIX7XOK.js +6 -0
- package/dist/UploadModal-NME2W53V.mjs +6 -0
- package/dist/chunk-646WCBRR.mjs +7276 -0
- package/dist/chunk-FH4QKHOH.js +7276 -0
- package/dist/index.js +747 -1675
- package/dist/index.mjs +400 -1237
- package/package.json +85 -85
- package/src/components/BatchUploadFonts.jsx +653 -639
- package/src/components/BulkActions.jsx +99 -0
- package/src/components/ExistingDocumentResolver.jsx +152 -0
- package/src/components/FontReviewCard.jsx +415 -0
- package/src/components/FontScriptUploaderComponent.jsx +463 -463
- package/src/components/GenerateCollectionsPairsComponent.jsx +259 -259
- package/src/components/KeyValueInput.jsx +95 -95
- package/src/components/KeyValueReferenceInput.jsx +254 -254
- package/src/components/NestedObjectArraySelector.jsx +146 -146
- package/src/components/PriceInput.jsx +26 -26
- package/src/components/PrimaryCollectionGeneratorTypeface.jsx +116 -116
- package/src/components/RegenerateSubfamiliesComponent.jsx +185 -185
- package/src/components/SetOTF.jsx +87 -87
- package/src/components/SingleUploaderTool.jsx +672 -673
- package/src/components/StatusDisplay.jsx +26 -26
- package/src/components/StyleCountInput.jsx +16 -16
- package/src/components/UpdateScriptsComponent.jsx +76 -76
- package/src/components/UploadButton.jsx +43 -43
- package/src/components/UploadModal.jsx +268 -0
- package/src/components/UploadScriptsComponent.jsx +539 -537
- package/src/components/UploadStep1Settings.jsx +272 -0
- package/src/components/UploadStep2Review.jsx +472 -0
- package/src/components/UploadStep3Execute.jsx +234 -0
- package/src/components/UploadSummary.jsx +196 -0
- package/src/components/VariableInstanceReferencesInput.jsx +190 -190
- package/src/hooks/useNestedObjects.js +92 -92
- package/src/hooks/useSanityClient.js +9 -9
- package/src/index.js +115 -70
- package/src/schema/openTypeField.js +1945 -1945
- package/src/schema/styleCountField.js +12 -12
- package/src/schema/stylesField.js +268 -268
- package/src/schema/stylisticSetField.js +301 -301
- package/src/utils/buildUploadPlan.js +325 -0
- package/src/utils/executeUploadPlan.js +437 -0
- package/src/utils/executionReducer.js +56 -0
- package/src/utils/fontHelpers.js +267 -0
- package/src/utils/generateCssFile.js +207 -205
- package/src/utils/generateFontData.js +98 -145
- package/src/utils/generateFontFile.js +38 -38
- package/src/utils/generateKeywords.js +185 -185
- package/src/utils/generateSubset.js +45 -45
- package/src/utils/getEmptyFontKit.js +101 -99
- package/src/utils/parseFont.js +55 -0
- package/src/utils/parseVariableFontInstances.js +211 -211
- package/src/utils/planReducer.js +517 -0
- package/src/utils/planTypes.js +183 -0
- package/src/utils/processFontFiles.js +529 -477
- package/src/utils/regenerateFontData.js +146 -146
- package/src/utils/resolveExistingFont.js +87 -0
- package/src/utils/sanitizeForSanityId.js +65 -65
- package/src/utils/updateFontPrices.js +94 -94
- package/src/utils/updateTypefaceDocument.js +149 -160
- package/src/utils/uploadFontFiles.js +405 -316
- package/src/utils/utils.js +24 -24
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// Shared helpers for extracting data from lib-font parsed fonts — the ONLY code that touches font.opentype.tables.*
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Name record lookup cache — avoids repeated linear scans of nameRecords.
|
|
5
|
+
* Keyed by font instance (WeakMap), values are { [nameID]: string } maps.
|
|
6
|
+
* @type {WeakMap<object, Object.<number, string>>}
|
|
7
|
+
*/
|
|
8
|
+
const nameCache = new WeakMap();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get a name table string by numeric name ID.
|
|
12
|
+
* Prefers Windows/Unicode/English (platform 3, language 0x0409),
|
|
13
|
+
* falls back to Mac/Roman/English (platform 1, language 0),
|
|
14
|
+
* then first available record.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} font - lib-font Font instance
|
|
17
|
+
* @param {number} nameID - OpenType name ID (0=copyright, 1=family, 2=subfamily, 4=fullName, 6=postscript, 16=prefFamily, 17=prefSubfamily)
|
|
18
|
+
* @returns {string} Decoded name string, or empty string if not found
|
|
19
|
+
*/
|
|
20
|
+
export function getNameString(font, nameID) {
|
|
21
|
+
if (!nameCache.has(font)) nameCache.set(font, {});
|
|
22
|
+
const cache = nameCache.get(font);
|
|
23
|
+
if (nameID in cache) return cache[nameID];
|
|
24
|
+
|
|
25
|
+
const records = font.opentype?.tables?.name?.nameRecords || [];
|
|
26
|
+
|
|
27
|
+
// Priority 1: Windows Unicode English
|
|
28
|
+
const win = records.find(r => r.nameID === nameID && r.platformID === 3 && r.languageID === 0x0409);
|
|
29
|
+
if (win?.string) { cache[nameID] = win.string; return win.string; }
|
|
30
|
+
|
|
31
|
+
// Priority 2: Mac Roman English
|
|
32
|
+
const mac = records.find(r => r.nameID === nameID && r.platformID === 1 && r.languageID === 0);
|
|
33
|
+
if (mac?.string) { cache[nameID] = mac.string; return mac.string; }
|
|
34
|
+
|
|
35
|
+
// Priority 3: First record with this nameID
|
|
36
|
+
const any = records.find(r => r.nameID === nameID);
|
|
37
|
+
const result = any?.string || '';
|
|
38
|
+
cache[nameID] = result;
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get all OpenType feature tags from GSUB and GPOS tables.
|
|
44
|
+
* Traverses scripts → langsys → features, deduplicates, and caches.
|
|
45
|
+
* Equivalent to fontkit's font.availableFeatures.
|
|
46
|
+
*
|
|
47
|
+
* @param {object} font - lib-font Font instance
|
|
48
|
+
* @returns {string[]} Array of unique 4-character feature tag strings (e.g. ['kern', 'liga', 'smcp'])
|
|
49
|
+
*/
|
|
50
|
+
export function getAllFeatureTags(font) {
|
|
51
|
+
const tags = new Set();
|
|
52
|
+
const tables = font.opentype?.tables;
|
|
53
|
+
for (const layoutTable of [tables?.GSUB, tables?.GPOS]) {
|
|
54
|
+
if (!layoutTable) continue;
|
|
55
|
+
try {
|
|
56
|
+
for (const scriptTag of layoutTable.getSupportedScripts()) {
|
|
57
|
+
const script = layoutTable.getScriptTable(scriptTag);
|
|
58
|
+
for (const langTag of layoutTable.getSupportedLangSys(script)) {
|
|
59
|
+
const langsys = layoutTable.getLangSysTable(script, langTag);
|
|
60
|
+
for (const feature of layoutTable.getFeatures(langsys)) {
|
|
61
|
+
tags.add(feature.featureTag.trim());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.warn(`Error reading ${layoutTable === tables.GSUB ? 'GSUB' : 'GPOS'} features:`, err.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return [...tags];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get character set as array of code points from the cmap table.
|
|
74
|
+
* Uses Windows/Unicode BMP subtable (platform 3, encoding 1).
|
|
75
|
+
*
|
|
76
|
+
* @param {object} font - lib-font Font instance
|
|
77
|
+
* @returns {number[]} Array of supported Unicode code points
|
|
78
|
+
*/
|
|
79
|
+
export function getCharacterSet(font) {
|
|
80
|
+
const cmap = font.opentype?.tables?.cmap;
|
|
81
|
+
if (!cmap) return [];
|
|
82
|
+
try {
|
|
83
|
+
return cmap.getSupportedCharCodes(3, 1);
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build a variation axis map from fvar table.
|
|
91
|
+
* Filters out degenerate axes (min === max). Returns null if not a variable font.
|
|
92
|
+
*
|
|
93
|
+
* @param {object} font - lib-font Font instance
|
|
94
|
+
* @returns {{ [tag: string]: { min: number, max: number, default: number, name: string } } | null}
|
|
95
|
+
*/
|
|
96
|
+
export function getVariationAxes(font) {
|
|
97
|
+
const fvar = font.opentype?.tables?.fvar;
|
|
98
|
+
if (!fvar?.axes) return null;
|
|
99
|
+
|
|
100
|
+
const axes = {};
|
|
101
|
+
for (const axis of fvar.axes) {
|
|
102
|
+
if (axis.minValue === axis.maxValue) continue;
|
|
103
|
+
axes[axis.tag] = {
|
|
104
|
+
min: axis.minValue,
|
|
105
|
+
max: axis.maxValue,
|
|
106
|
+
default: axis.defaultValue,
|
|
107
|
+
name: getNameString(font, axis.axisNameID) || axis.tag,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return Object.keys(axes).length > 0 ? axes : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get named instances from fvar table.
|
|
115
|
+
* Resolves subfamilyNameID and postScriptNameID via the name table.
|
|
116
|
+
*
|
|
117
|
+
* @param {object} font - lib-font Font instance
|
|
118
|
+
* @returns {Array<{ name: string, coordinates: number[], postScriptName: string }>}
|
|
119
|
+
*/
|
|
120
|
+
export function getNamedInstances(font) {
|
|
121
|
+
const fvar = font.opentype?.tables?.fvar;
|
|
122
|
+
if (!fvar?.instances) return [];
|
|
123
|
+
return fvar.instances.map(inst => ({
|
|
124
|
+
name: getNameString(font, inst.subfamilyNameID),
|
|
125
|
+
coordinates: inst.coordinates,
|
|
126
|
+
postScriptName: getNameString(font, inst.postScriptNameID || 0),
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Build font metrics object matching the Sanity document shape.
|
|
132
|
+
* Uses OS/2 typo metrics when USE_TYPO_METRICS bit is set, otherwise hhea.
|
|
133
|
+
*
|
|
134
|
+
* @param {object} font - lib-font Font instance
|
|
135
|
+
* @returns {{ unitsPerEm: number, ascender: number, descender: number, lineGap: number, underlinePosition: number, underlineThickness: number, italicAngle: number, capHeight: number, xHeight: number, boundingBox: { xMin: number, yMin: number, xMax: number, yMax: number } }}
|
|
136
|
+
*/
|
|
137
|
+
export function getFontMetrics(font) {
|
|
138
|
+
const tables = font.opentype?.tables;
|
|
139
|
+
const os2 = tables?.['OS/2'];
|
|
140
|
+
const head = tables?.head;
|
|
141
|
+
const post = tables?.post;
|
|
142
|
+
const hhea = tables?.hhea;
|
|
143
|
+
|
|
144
|
+
// USE_TYPO_METRICS flag (fsSelection bit 7) — when set, use OS/2 typo metrics
|
|
145
|
+
const useTypo = os2 ? (os2.fsSelection & 0x80) !== 0 : false;
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
unitsPerEm: head?.unitsPerEm || 1000,
|
|
149
|
+
ascender: useTypo ? (os2?.sTypoAscender || 0) : (hhea?.ascender ?? os2?.sTypoAscender ?? 0),
|
|
150
|
+
descender: useTypo ? (os2?.sTypoDescender || 0) : (hhea?.descender ?? os2?.sTypoDescender ?? 0),
|
|
151
|
+
lineGap: useTypo ? (os2?.sTypoLineGap || 0) : (hhea?.lineGap ?? os2?.sTypoLineGap ?? 0),
|
|
152
|
+
underlinePosition: post?.underlinePosition || 0,
|
|
153
|
+
underlineThickness: post?.underlineThickness || 0,
|
|
154
|
+
italicAngle: post?.italicAngle || 0,
|
|
155
|
+
capHeight: (os2?.version >= 2) ? (os2?.sCapHeight || 0) : 0,
|
|
156
|
+
xHeight: (os2?.version >= 2) ? (os2?.sxHeight || 0) : 0,
|
|
157
|
+
boundingBox: {
|
|
158
|
+
xMin: head?.xMin || 0,
|
|
159
|
+
yMin: head?.yMin || 0,
|
|
160
|
+
xMax: head?.xMax || 0,
|
|
161
|
+
yMax: head?.yMax || 0,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Build font metadata object matching the Sanity document shape.
|
|
168
|
+
*
|
|
169
|
+
* @param {object} font - lib-font Font instance
|
|
170
|
+
* @returns {{ postscriptName: string, fullName: string, familyName: string, subfamilyName: string, copyright: string, version: string, genDate: string }}
|
|
171
|
+
*/
|
|
172
|
+
export function getFontMetadata(font) {
|
|
173
|
+
return {
|
|
174
|
+
postscriptName: getNameString(font, 6),
|
|
175
|
+
fullName: getNameString(font, 4),
|
|
176
|
+
familyName: getNameString(font, 1),
|
|
177
|
+
subfamilyName: getNameString(font, 2),
|
|
178
|
+
copyright: getNameString(font, 0),
|
|
179
|
+
version: getNameString(font, 5),
|
|
180
|
+
genDate: new Date().toISOString(),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get the OS/2 usWeightClass value.
|
|
186
|
+
*
|
|
187
|
+
* @param {object} font - lib-font Font instance
|
|
188
|
+
* @returns {number|null} Weight class (1-1000) or null if OS/2 table is missing
|
|
189
|
+
*/
|
|
190
|
+
export function getWeightClass(font) {
|
|
191
|
+
return font.opentype?.tables?.['OS/2']?.usWeightClass || null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get the OS/2 fsSelection flags as a raw uint16.
|
|
196
|
+
*
|
|
197
|
+
* @param {object} font - lib-font Font instance
|
|
198
|
+
* @returns {number} fsSelection bitmask (0 if OS/2 table is missing)
|
|
199
|
+
*/
|
|
200
|
+
export function getFsSelection(font) {
|
|
201
|
+
return font.opentype?.tables?.['OS/2']?.fsSelection || 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get the head macStyle flags as a uint16 bitmask.
|
|
206
|
+
* lib-font returns macStyle as a bit array (big-endian order: index 15 = bit 0).
|
|
207
|
+
* This helper converts it back to a standard uint16 for bitwise testing.
|
|
208
|
+
*
|
|
209
|
+
* @param {object} font - lib-font Font instance
|
|
210
|
+
* @returns {number} macStyle bitmask (0 if head table is missing)
|
|
211
|
+
*/
|
|
212
|
+
export function getMacStyle(font) {
|
|
213
|
+
const macStyle = font.opentype?.tables?.head?.macStyle;
|
|
214
|
+
if (!macStyle) return 0;
|
|
215
|
+
// lib-font returns a bit array or a number depending on version
|
|
216
|
+
if (typeof macStyle === 'number') return macStyle;
|
|
217
|
+
// Convert bit array (big-endian) to uint16: index 15 = bit 0, index 14 = bit 1, etc.
|
|
218
|
+
if (typeof macStyle === 'object') {
|
|
219
|
+
let value = 0;
|
|
220
|
+
for (let i = 0; i < 16; i++) {
|
|
221
|
+
if (macStyle[i]) value |= (1 << (15 - i));
|
|
222
|
+
}
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
return 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get the post table italic angle.
|
|
230
|
+
*
|
|
231
|
+
* @param {object} font - lib-font Font instance
|
|
232
|
+
* @returns {number} Italic angle in degrees (0 for upright fonts)
|
|
233
|
+
*/
|
|
234
|
+
export function getItalicAngle(font) {
|
|
235
|
+
return font.opentype?.tables?.post?.italicAngle || 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get glyph count from maxp table.
|
|
240
|
+
*
|
|
241
|
+
* @param {object} font - lib-font Font instance
|
|
242
|
+
* @returns {number} Number of glyphs
|
|
243
|
+
*/
|
|
244
|
+
export function getGlyphCount(font) {
|
|
245
|
+
return font.opentype?.tables?.maxp?.numGlyphs || 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the OS/2 sFamilyClass value for font category detection.
|
|
250
|
+
*
|
|
251
|
+
* @param {object} font - lib-font Font instance
|
|
252
|
+
* @returns {number} sFamilyClass value (0 if missing)
|
|
253
|
+
*/
|
|
254
|
+
export function getFamilyClass(font) {
|
|
255
|
+
return font.opentype?.tables?.['OS/2']?.sFamilyClass || 0;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Escape a font name for safe interpolation into CSS font-family declarations.
|
|
260
|
+
* Prevents CSS injection via crafted name table strings.
|
|
261
|
+
*
|
|
262
|
+
* @param {string} name - Raw font name from the name table
|
|
263
|
+
* @returns {string} Escaped name safe for CSS string context
|
|
264
|
+
*/
|
|
265
|
+
export function escapeCssFontName(name) {
|
|
266
|
+
return name.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/;/g, '');
|
|
267
|
+
}
|