@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.
Files changed (62) hide show
  1. package/README.md +437 -437
  2. package/dist/UploadModal-6LIX7XOK.js +6 -0
  3. package/dist/UploadModal-NME2W53V.mjs +6 -0
  4. package/dist/chunk-646WCBRR.mjs +7276 -0
  5. package/dist/chunk-FH4QKHOH.js +7276 -0
  6. package/dist/index.js +747 -1675
  7. package/dist/index.mjs +400 -1237
  8. package/package.json +85 -85
  9. package/src/components/BatchUploadFonts.jsx +653 -639
  10. package/src/components/BulkActions.jsx +99 -0
  11. package/src/components/ExistingDocumentResolver.jsx +152 -0
  12. package/src/components/FontReviewCard.jsx +415 -0
  13. package/src/components/FontScriptUploaderComponent.jsx +463 -463
  14. package/src/components/GenerateCollectionsPairsComponent.jsx +259 -259
  15. package/src/components/KeyValueInput.jsx +95 -95
  16. package/src/components/KeyValueReferenceInput.jsx +254 -254
  17. package/src/components/NestedObjectArraySelector.jsx +146 -146
  18. package/src/components/PriceInput.jsx +26 -26
  19. package/src/components/PrimaryCollectionGeneratorTypeface.jsx +116 -116
  20. package/src/components/RegenerateSubfamiliesComponent.jsx +185 -185
  21. package/src/components/SetOTF.jsx +87 -87
  22. package/src/components/SingleUploaderTool.jsx +672 -673
  23. package/src/components/StatusDisplay.jsx +26 -26
  24. package/src/components/StyleCountInput.jsx +16 -16
  25. package/src/components/UpdateScriptsComponent.jsx +76 -76
  26. package/src/components/UploadButton.jsx +43 -43
  27. package/src/components/UploadModal.jsx +268 -0
  28. package/src/components/UploadScriptsComponent.jsx +539 -537
  29. package/src/components/UploadStep1Settings.jsx +272 -0
  30. package/src/components/UploadStep2Review.jsx +472 -0
  31. package/src/components/UploadStep3Execute.jsx +234 -0
  32. package/src/components/UploadSummary.jsx +196 -0
  33. package/src/components/VariableInstanceReferencesInput.jsx +190 -190
  34. package/src/hooks/useNestedObjects.js +92 -92
  35. package/src/hooks/useSanityClient.js +9 -9
  36. package/src/index.js +115 -70
  37. package/src/schema/openTypeField.js +1945 -1945
  38. package/src/schema/styleCountField.js +12 -12
  39. package/src/schema/stylesField.js +268 -268
  40. package/src/schema/stylisticSetField.js +301 -301
  41. package/src/utils/buildUploadPlan.js +325 -0
  42. package/src/utils/executeUploadPlan.js +437 -0
  43. package/src/utils/executionReducer.js +56 -0
  44. package/src/utils/fontHelpers.js +267 -0
  45. package/src/utils/generateCssFile.js +207 -205
  46. package/src/utils/generateFontData.js +98 -145
  47. package/src/utils/generateFontFile.js +38 -38
  48. package/src/utils/generateKeywords.js +185 -185
  49. package/src/utils/generateSubset.js +45 -45
  50. package/src/utils/getEmptyFontKit.js +101 -99
  51. package/src/utils/parseFont.js +55 -0
  52. package/src/utils/parseVariableFontInstances.js +211 -211
  53. package/src/utils/planReducer.js +517 -0
  54. package/src/utils/planTypes.js +183 -0
  55. package/src/utils/processFontFiles.js +529 -477
  56. package/src/utils/regenerateFontData.js +146 -146
  57. package/src/utils/resolveExistingFont.js +87 -0
  58. package/src/utils/sanitizeForSanityId.js +65 -65
  59. package/src/utils/updateFontPrices.js +94 -94
  60. package/src/utils/updateTypefaceDocument.js +149 -160
  61. package/src/utils/uploadFontFiles.js +405 -316
  62. package/src/utils/utils.js +24 -24
@@ -1,99 +1,101 @@
1
- // Returns a zeroed-out fontkit-shaped placeholder object used when no font binary is available
2
- import * as fontkit from 'fontkit';
3
- import slugify from 'slugify';
4
-
5
- /** Reads font files and returns name/subfamily metadata without writing to Sanity */
6
- export async function getEmptyFontKit({ title, files, weightKeywordList, italicKeywordList }) {
7
-
8
- let fontNames = {};
9
- let subfamilies = {};
10
-
11
- for (var i = 0; i < files.length; i++) {
12
-
13
- const file = files[i];
14
- const fontBuffer = await readFontFile(file);
15
- const font = fontkit.create(fontBuffer);
16
-
17
- let weightName = font?.name?.records?.preferredSubfamily ? font?.name?.records?.preferredSubfamily : font?.name?.records?.fontSubfamily;
18
- weightName = weightName?.en ? weightName.en : weightName.constructor == Object ? weightName[Object.keys(weightName)[0]] : weightName;
19
-
20
- let variableFont = font?.variationAxes && Object.keys(font.variationAxes).length > 0 ? true : false;
21
- let subfamilyName = font.familyName.toLowerCase().trim().replace(title.toLowerCase().trim(), '').trim();
22
- let fontTitle = font?.fullName.toLowerCase().trim();
23
-
24
- weightKeywordList.forEach(keyword => {
25
- const kw = keyword.toLowerCase().trim();
26
-
27
- if (fontTitle.includes(kw)) {
28
- fontTitle = fontTitle.replace(kw, '');
29
- }
30
- if (subfamilyName.includes(kw)) {
31
- subfamilyName = subfamilyName.replace(kw, '');
32
- }
33
- });
34
-
35
- italicKeywordList.forEach(keyword => {
36
- const kw = keyword.toLowerCase().trim();
37
-
38
- if (subfamilyName.includes(kw)) {
39
- subfamilyName = subfamilyName.replace(kw, '');
40
- }
41
- if (fontTitle.includes(kw)) {
42
- fontTitle = fontTitle.replace(kw, '');
43
- }
44
- });
45
-
46
- fontTitle = fontTitle.trim().split(' ').map(word => word[0].toUpperCase() + word.slice(1)).join(' ');
47
-
48
- subfamilyName = subfamilyName.trim();
49
- subfamilyName = (subfamilyName == '') ? 'Regular' : subfamilyName.split(' ').map(word => word[0].toUpperCase() + word.slice(1)).join(' ');
50
-
51
-
52
- let id = slugify(fontTitle.toLowerCase().trim());
53
- if (variableFont && !id.endsWith('-vf')) {
54
- id = id + '-vf';
55
- fontTitle = fontTitle + ' VF';
56
- }
57
-
58
- // add subfamily to list
59
- if (!subfamilies[id]) {
60
- subfamilies[id] = [subfamilyName];
61
- } else if (subfamilies[id].indexOf(subfamilyName) == -1) {
62
- subfamilies[id] = [...subfamilies[id], subfamilyName];
63
- }
64
-
65
- if (!fontNames[id]) {
66
- fontNames[id] = [{
67
- file: file.name,
68
- fullName: font.fullName,
69
- familyName: font.familyName,
70
- subFamily: subfamilyName,
71
- }];
72
- } else if (fontNames[id].indexOf(file.name) == -1) {
73
- fontNames[id].push({
74
- file: file.name,
75
- fullName: font.fullName,
76
- familyName: font.familyName,
77
- subFamily: subfamilyName,
78
- })
79
- }
80
-
81
-
82
- }
83
-
84
- console.log('font names : ', fontNames);
85
- }
86
-
87
- /** Reads a font file and returns its content as a Uint8Array */
88
- const readFontFile = (file) => {
89
- return new Promise((resolve, reject) => {
90
- const reader = new FileReader();
91
-
92
- reader.onload = (event) => {
93
- resolve(new Uint8Array(event.target.result));
94
- };
95
-
96
- reader.onerror = (error) => { reject(error); };
97
- reader.readAsArrayBuffer(file);
98
- });
99
- };
1
+ // Parses font files and returns name/subfamily metadata groupings without writing to Sanity
2
+
3
+ import { parseFont } from './parseFont';
4
+ import { getNameString, getVariationAxes } from './fontHelpers';
5
+ import slugify from 'slugify';
6
+
7
+ /** Reads font files and returns name/subfamily metadata without writing to Sanity */
8
+ export async function getEmptyFontKit({ title, files, weightKeywordList, italicKeywordList }) {
9
+
10
+ let fontNames = {};
11
+ let subfamilies = {};
12
+
13
+ for (var i = 0; i < files.length; i++) {
14
+
15
+ const file = files[i];
16
+ const fontBuffer = await readFontFile(file);
17
+ const font = await parseFont(fontBuffer, file.name);
18
+
19
+ let weightName = getNameString(font, 17) || getNameString(font, 2) || '';
20
+
21
+ const axes = getVariationAxes(font);
22
+ let variableFont = axes !== null;
23
+ const familyName = getNameString(font, 1);
24
+ const fullName = getNameString(font, 4);
25
+ let subfamilyName = familyName.toLowerCase().trim().replace(title.toLowerCase().trim(), '').trim();
26
+ let fontTitle = fullName.toLowerCase().trim();
27
+
28
+ weightKeywordList.forEach(keyword => {
29
+ const kw = keyword.toLowerCase().trim();
30
+
31
+ if (fontTitle.includes(kw)) {
32
+ fontTitle = fontTitle.replace(kw, '');
33
+ }
34
+ if (subfamilyName.includes(kw)) {
35
+ subfamilyName = subfamilyName.replace(kw, '');
36
+ }
37
+ });
38
+
39
+ italicKeywordList.forEach(keyword => {
40
+ const kw = keyword.toLowerCase().trim();
41
+
42
+ if (subfamilyName.includes(kw)) {
43
+ subfamilyName = subfamilyName.replace(kw, '');
44
+ }
45
+ if (fontTitle.includes(kw)) {
46
+ fontTitle = fontTitle.replace(kw, '');
47
+ }
48
+ });
49
+
50
+ fontTitle = fontTitle.trim().split(' ').map(word => word[0].toUpperCase() + word.slice(1)).join(' ');
51
+
52
+ subfamilyName = subfamilyName.trim();
53
+ subfamilyName = (subfamilyName == '') ? 'Regular' : subfamilyName.split(' ').map(word => word[0].toUpperCase() + word.slice(1)).join(' ');
54
+
55
+
56
+ let id = slugify(fontTitle.toLowerCase().trim());
57
+ if (variableFont && !id.endsWith('-vf')) {
58
+ id = id + '-vf';
59
+ fontTitle = fontTitle + ' VF';
60
+ }
61
+
62
+ // add subfamily to list
63
+ if (!subfamilies[id]) {
64
+ subfamilies[id] = [subfamilyName];
65
+ } else if (subfamilies[id].indexOf(subfamilyName) == -1) {
66
+ subfamilies[id] = [...subfamilies[id], subfamilyName];
67
+ }
68
+
69
+ if (!fontNames[id]) {
70
+ fontNames[id] = [{
71
+ file: file.name,
72
+ fullName: fullName,
73
+ familyName: familyName,
74
+ subFamily: subfamilyName,
75
+ }];
76
+ } else if (fontNames[id].indexOf(file.name) == -1) {
77
+ fontNames[id].push({
78
+ file: file.name,
79
+ fullName: fullName,
80
+ familyName: familyName,
81
+ subFamily: subfamilyName,
82
+ })
83
+ }
84
+ }
85
+
86
+ console.log('Font names:', fontNames);
87
+ }
88
+
89
+ /** Reads a font file and returns its content as an ArrayBuffer */
90
+ const readFontFile = (file) => {
91
+ return new Promise((resolve, reject) => {
92
+ const reader = new FileReader();
93
+
94
+ reader.onload = (event) => {
95
+ resolve(event.target.result);
96
+ };
97
+
98
+ reader.onerror = (error) => { reject(error); };
99
+ reader.readAsArrayBuffer(file);
100
+ });
101
+ };
@@ -0,0 +1,55 @@
1
+ // Async font parser — wraps lib-font event model in a Promise with decompressor bootstrap
2
+
3
+ import pako from 'pako';
4
+
5
+ // Set decompressor globals BEFORE lib-font is imported.
6
+ // lib-font reads globalThis.pako and globalThis.unbrotli at module evaluation time
7
+ // (top of woff.js / woff2.js), not at parse time. These must be set before lib-font
8
+ // is first evaluated, so we use dynamic import() below to guarantee ordering.
9
+ globalThis.pako = pako;
10
+
11
+ // unbrotli is a UMD that sets globalThis.unbrotli as a side effect on evaluation.
12
+ // We vendor it from lib-font/lib/unbrotli.js because the subpath is not in
13
+ // lib-font's exports map (ERR_PACKAGE_PATH_NOT_EXPORTED).
14
+ import '../vendor/unbrotli.js';
15
+
16
+ // Lazy-loaded lib-font Font constructor — resolved on first parseFont() call.
17
+ // Using dynamic import() guarantees globalThis.pako and globalThis.unbrotli are
18
+ // set before lib-font evaluates, which static imports cannot guarantee in ESM.
19
+ let _Font = null;
20
+
21
+ /** Returns the lib-font Font constructor, loading it on first call */
22
+ async function getFont() {
23
+ if (!_Font) {
24
+ const mod = await import('lib-font');
25
+ _Font = mod.Font;
26
+ }
27
+ return _Font;
28
+ }
29
+
30
+ /** Maximum font file size accepted for parsing (50 MB) */
31
+ const MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
32
+
33
+ /**
34
+ * Parse a font file from an ArrayBuffer.
35
+ * Returns a lib-font Font object with all tables accessible via font.opentype.tables.*.
36
+ *
37
+ * @param {ArrayBuffer} buffer - Raw font file bytes
38
+ * @param {string} filename - Original filename (used for format detection by lib-font)
39
+ * @returns {Promise<import('lib-font').Font>} Parsed lib-font Font object
40
+ * @throws {Error} If the file exceeds MAX_FONT_FILE_SIZE or parsing fails
41
+ */
42
+ export async function parseFont(buffer, filename) {
43
+ if (buffer.byteLength > MAX_FONT_FILE_SIZE) {
44
+ throw new Error(`Font file exceeds ${MAX_FONT_FILE_SIZE / 1024 / 1024}MB limit: ${filename} (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB)`);
45
+ }
46
+
47
+ const Font = await getFont();
48
+
49
+ return new Promise((resolve, reject) => {
50
+ const font = new Font('font', { skipStyleSheet: true });
51
+ font.onload = (evt) => resolve(evt.detail.font);
52
+ font.onerror = (evt) => reject(new Error(evt.detail?.message || `Failed to parse ${filename}`));
53
+ font.fromDataBuffer(buffer, filename);
54
+ });
55
+ }