@liiift-studio/sanity-font-manager 2.7.0 → 2.7.1

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/LICENSE +21 -0
  2. package/README.md +695 -437
  3. package/dist/index.js +1634 -17839
  4. package/dist/index.mjs +1551 -17745
  5. package/package.json +83 -83
  6. package/src/components/BatchUploadFonts.jsx +655 -655
  7. package/src/components/BulkActions.jsx +99 -99
  8. package/src/components/ExistingDocumentResolver.jsx +152 -152
  9. package/src/components/FontReviewCard.jsx +455 -455
  10. package/src/components/FontScriptUploaderComponent.jsx +463 -463
  11. package/src/components/GenerateCollectionsPairsComponent.jsx +259 -259
  12. package/src/components/KeyValueInput.jsx +95 -95
  13. package/src/components/KeyValueReferenceInput.jsx +267 -267
  14. package/src/components/NestedObjectArraySelector.jsx +146 -146
  15. package/src/components/PriceInput.jsx +26 -26
  16. package/src/components/PrimaryCollectionGeneratorTypeface.jsx +116 -116
  17. package/src/components/RegenerateSubfamiliesComponent.jsx +185 -185
  18. package/src/components/SetOTF.jsx +87 -87
  19. package/src/components/SingleUploaderTool.jsx +674 -674
  20. package/src/components/StatusDisplay.jsx +26 -26
  21. package/src/components/StyleCountInput.jsx +16 -16
  22. package/src/components/UpdateScriptsComponent.jsx +76 -76
  23. package/src/components/UploadButton.jsx +43 -43
  24. package/src/components/UploadModal.jsx +309 -309
  25. package/src/components/UploadScriptsComponent.jsx +539 -539
  26. package/src/components/UploadStep1Settings.jsx +272 -272
  27. package/src/components/UploadStep2Review.jsx +478 -478
  28. package/src/components/UploadStep3Execute.jsx +234 -234
  29. package/src/components/UploadStep3bInstances.jsx +396 -396
  30. package/src/components/UploadSummary.jsx +196 -196
  31. package/src/components/VariableInstanceReferencesInput.jsx +190 -190
  32. package/src/hooks/useNestedObjects.js +92 -92
  33. package/src/hooks/useSanityClient.js +9 -9
  34. package/src/index.js +120 -120
  35. package/src/schema/openTypeField.js +1995 -1995
  36. package/src/schema/styleCountField.js +12 -12
  37. package/src/schema/stylesField.js +302 -302
  38. package/src/schema/stylisticSetField.js +301 -301
  39. package/src/utils/buildUploadPlan.js +326 -326
  40. package/src/utils/executeUploadPlan.js +430 -430
  41. package/src/utils/executionReducer.js +56 -56
  42. package/src/utils/fontHelpers.js +281 -281
  43. package/src/utils/generateCssFile.js +207 -207
  44. package/src/utils/generateFontData.js +98 -98
  45. package/src/utils/generateFontFile.js +38 -38
  46. package/src/utils/generateKeywords.js +185 -185
  47. package/src/utils/generateSubset.js +45 -45
  48. package/src/utils/getEmptyFontKit.js +101 -101
  49. package/src/utils/parseFont.js +56 -56
  50. package/src/utils/parseVariableFontInstances.js +301 -301
  51. package/src/utils/planReducer.js +531 -531
  52. package/src/utils/planTypes.js +183 -183
  53. package/src/utils/processFontFiles.js +530 -530
  54. package/src/utils/regenerateFontData.js +146 -146
  55. package/src/utils/resolveExistingFont.js +87 -87
  56. package/src/utils/retitleFontEntries.js +154 -154
  57. package/src/utils/sanitizeForSanityId.js +65 -65
  58. package/src/utils/setupDecompressors.js +27 -27
  59. package/src/utils/updateFontPrices.js +94 -94
  60. package/src/utils/updateTypefaceDocument.js +162 -162
  61. package/src/utils/uploadFontFiles.js +405 -405
  62. package/src/utils/utils.js +24 -24
@@ -1,101 +1,101 @@
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
- };
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
+ };
@@ -1,56 +1,56 @@
1
- // Async font parser — decompressor globals must be set before lib-font is imported
2
-
3
- import './setupDecompressors.js';
4
- import { Font } from 'lib-font';
5
-
6
- /** Maximum font file size accepted for parsing (50 MB) */
7
- const MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
8
-
9
- /** Parse timeout — prevents hanging if lib-font silently fails (30 seconds) */
10
- const PARSE_TIMEOUT_MS = 30000;
11
-
12
- /**
13
- * Parse a font file from an ArrayBuffer.
14
- * Returns a lib-font Font object with all tables accessible via font.opentype.tables.*.
15
- *
16
- * @param {ArrayBuffer} buffer - Raw font file bytes
17
- * @param {string} filename - Original filename (used for format detection by lib-font)
18
- * @returns {Promise<import('lib-font').Font>} Parsed lib-font Font object
19
- * @throws {Error} If the file exceeds MAX_FONT_FILE_SIZE, parsing fails, or times out
20
- */
21
- export async function parseFont(buffer, filename) {
22
- if (buffer.byteLength > MAX_FONT_FILE_SIZE) {
23
- throw new Error(`Font file exceeds ${MAX_FONT_FILE_SIZE / 1024 / 1024}MB limit: ${filename} (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB)`);
24
- }
25
-
26
- return new Promise((resolve, reject) => {
27
- let settled = false;
28
-
29
- const settle = (fn) => (...args) => {
30
- if (!settled) {
31
- settled = true;
32
- clearTimeout(timer);
33
- fn(...args);
34
- }
35
- };
36
-
37
- // Timeout guard — prevents infinite hang if lib-font fails silently
38
- const timer = setTimeout(() => {
39
- settle(reject)(new Error(`Parsing timed out for ${filename} (${PARSE_TIMEOUT_MS / 1000}s). The file may be corrupted or in an unsupported format.`));
40
- }, PARSE_TIMEOUT_MS);
41
-
42
- const font = new Font('font', { skipStyleSheet: true });
43
- font.onload = settle((evt) => resolve(evt.detail.font));
44
- font.onerror = settle((evt) => {
45
- const msg = evt.detail?.message || `Failed to parse ${filename}`;
46
- reject(new Error(msg));
47
- });
48
-
49
- try {
50
- font.fromDataBuffer(buffer, filename);
51
- } catch (err) {
52
- // Catches synchronous throws from WOFF2 constructor when brotli is missing
53
- settle(reject)(new Error(`${filename}: ${err.message}`));
54
- }
55
- });
56
- }
1
+ // Async font parser — decompressor globals must be set before lib-font is imported
2
+
3
+ import './setupDecompressors.js';
4
+ import { Font } from 'lib-font';
5
+
6
+ /** Maximum font file size accepted for parsing (50 MB) */
7
+ const MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
8
+
9
+ /** Parse timeout — prevents hanging if lib-font silently fails (30 seconds) */
10
+ const PARSE_TIMEOUT_MS = 30000;
11
+
12
+ /**
13
+ * Parse a font file from an ArrayBuffer.
14
+ * Returns a lib-font Font object with all tables accessible via font.opentype.tables.*.
15
+ *
16
+ * @param {ArrayBuffer} buffer - Raw font file bytes
17
+ * @param {string} filename - Original filename (used for format detection by lib-font)
18
+ * @returns {Promise<import('lib-font').Font>} Parsed lib-font Font object
19
+ * @throws {Error} If the file exceeds MAX_FONT_FILE_SIZE, parsing fails, or times out
20
+ */
21
+ export async function parseFont(buffer, filename) {
22
+ if (buffer.byteLength > MAX_FONT_FILE_SIZE) {
23
+ throw new Error(`Font file exceeds ${MAX_FONT_FILE_SIZE / 1024 / 1024}MB limit: ${filename} (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB)`);
24
+ }
25
+
26
+ return new Promise((resolve, reject) => {
27
+ let settled = false;
28
+
29
+ const settle = (fn) => (...args) => {
30
+ if (!settled) {
31
+ settled = true;
32
+ clearTimeout(timer);
33
+ fn(...args);
34
+ }
35
+ };
36
+
37
+ // Timeout guard — prevents infinite hang if lib-font fails silently
38
+ const timer = setTimeout(() => {
39
+ settle(reject)(new Error(`Parsing timed out for ${filename} (${PARSE_TIMEOUT_MS / 1000}s). The file may be corrupted or in an unsupported format.`));
40
+ }, PARSE_TIMEOUT_MS);
41
+
42
+ const font = new Font('font', { skipStyleSheet: true });
43
+ font.onload = settle((evt) => resolve(evt.detail.font));
44
+ font.onerror = settle((evt) => {
45
+ const msg = evt.detail?.message || `Failed to parse ${filename}`;
46
+ reject(new Error(msg));
47
+ });
48
+
49
+ try {
50
+ font.fromDataBuffer(buffer, filename);
51
+ } catch (err) {
52
+ // Catches synchronous throws from WOFF2 constructor when brotli is missing
53
+ settle(reject)(new Error(`${filename}: ${err.message}`));
54
+ }
55
+ });
56
+ }