@liiift-studio/sanity-font-manager 2.6.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.
- package/LICENSE +21 -0
- package/README.md +695 -437
- package/dist/index.js +1628 -17701
- package/dist/index.mjs +1537 -17599
- package/package.json +83 -83
- package/src/components/BatchUploadFonts.jsx +655 -653
- package/src/components/BulkActions.jsx +99 -99
- package/src/components/ExistingDocumentResolver.jsx +152 -152
- package/src/components/FontReviewCard.jsx +455 -455
- 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 +267 -267
- 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 +674 -674
- 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 +309 -304
- package/src/components/UploadScriptsComponent.jsx +539 -539
- package/src/components/UploadStep1Settings.jsx +272 -272
- package/src/components/UploadStep2Review.jsx +478 -474
- package/src/components/UploadStep3Execute.jsx +234 -234
- package/src/components/UploadStep3bInstances.jsx +396 -396
- package/src/components/UploadSummary.jsx +196 -196
- 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 +120 -120
- package/src/schema/openTypeField.js +1995 -1995
- package/src/schema/styleCountField.js +12 -12
- package/src/schema/stylesField.js +302 -302
- package/src/schema/stylisticSetField.js +301 -301
- package/src/utils/buildUploadPlan.js +326 -326
- package/src/utils/executeUploadPlan.js +430 -430
- package/src/utils/executionReducer.js +56 -56
- package/src/utils/fontHelpers.js +281 -267
- package/src/utils/generateCssFile.js +207 -207
- package/src/utils/generateFontData.js +98 -98
- 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 -101
- package/src/utils/parseFont.js +56 -56
- package/src/utils/parseVariableFontInstances.js +301 -301
- package/src/utils/planReducer.js +531 -517
- package/src/utils/planTypes.js +183 -183
- package/src/utils/processFontFiles.js +530 -530
- package/src/utils/regenerateFontData.js +146 -146
- package/src/utils/resolveExistingFont.js +87 -87
- package/src/utils/retitleFontEntries.js +154 -0
- package/src/utils/sanitizeForSanityId.js +65 -65
- package/src/utils/setupDecompressors.js +27 -27
- package/src/utils/updateFontPrices.js +94 -94
- package/src/utils/updateTypefaceDocument.js +162 -162
- package/src/utils/uploadFontFiles.js +405 -405
- package/src/utils/utils.js +24 -24
package/src/utils/planTypes.js
CHANGED
|
@@ -1,183 +1,183 @@
|
|
|
1
|
-
// Type constants and enums for the two-phase upload plan — single source of truth
|
|
2
|
-
|
|
3
|
-
/** @enum {string} — Font processing status within the plan */
|
|
4
|
-
export const FONT_STATUS = {
|
|
5
|
-
PENDING: 'pending',
|
|
6
|
-
PROCESSING: 'processing',
|
|
7
|
-
PROCESSED: 'processed',
|
|
8
|
-
ERROR: 'error',
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/** @enum {string} — Modal phase state machine */
|
|
12
|
-
export const PLAN_PHASE = {
|
|
13
|
-
IDLE: 'idle',
|
|
14
|
-
PROCESSING: 'processing',
|
|
15
|
-
REVIEWING: 'reviewing',
|
|
16
|
-
READY: 'ready',
|
|
17
|
-
EXECUTING: 'executing',
|
|
18
|
-
COMPLETE: 'complete',
|
|
19
|
-
ERROR: 'error',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/** @enum {string} — Document resolution recommendation from resolveExistingFont */
|
|
23
|
-
export const RECOMMENDATION = {
|
|
24
|
-
USE_EXACT: 'use-exact',
|
|
25
|
-
USE_CANDIDATE: 'use-candidate',
|
|
26
|
-
AMBIGUOUS: 'ambiguous',
|
|
27
|
-
CREATE: 'create',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** @enum {string} — Per-font execution progress status */
|
|
31
|
-
export const EXECUTION_STATUS = {
|
|
32
|
-
QUEUED: 'queued',
|
|
33
|
-
UPLOADING_ASSETS: 'uploading-assets',
|
|
34
|
-
GENERATING_CSS: 'generating-css',
|
|
35
|
-
GENERATING_METADATA: 'generating-metadata',
|
|
36
|
-
CREATING_DOCUMENT: 'creating-document',
|
|
37
|
-
PATCHING_TYPEFACE: 'patching-typeface',
|
|
38
|
-
COMPLETE: 'complete',
|
|
39
|
-
ERROR: 'error',
|
|
40
|
-
SKIPPED: 'skipped',
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/** Processing-owned fields — only written by ADD_PROCESSED_FONT, never by user edit actions */
|
|
44
|
-
export const PROCESSING_OWNED_FIELDS = ['parsedMetadata', 'glyphCount', 'opentypeFeatures', 'variationAxes', 'status'];
|
|
45
|
-
|
|
46
|
-
/** User-owned fields — only written by user edit actions via decisions.*.userOverride */
|
|
47
|
-
export const USER_OWNED_FIELDS = ['title', 'documentId', 'weight', 'weightName', 'style', 'subfamily'];
|
|
48
|
-
|
|
49
|
-
/** Current plan schema version — increment on breaking shape changes */
|
|
50
|
-
export const PLAN_VERSION = 1;
|
|
51
|
-
|
|
52
|
-
/** Maximum concurrent asset uploads */
|
|
53
|
-
export const CONCURRENCY_LIMIT = 3;
|
|
54
|
-
|
|
55
|
-
/** Maximum retry attempts for 429 rate-limited requests */
|
|
56
|
-
export const MAX_RETRIES = 3;
|
|
57
|
-
|
|
58
|
-
/** Base backoff delay in ms for exponential retry */
|
|
59
|
-
export const BASE_BACKOFF_MS = 1000;
|
|
60
|
-
|
|
61
|
-
/** Jitter factor for exponential backoff (±25%) */
|
|
62
|
-
export const JITTER_FACTOR = 0.25;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Calculate backoff delay with jitter for retry logic.
|
|
66
|
-
* @param {number} attempt - Zero-based attempt number
|
|
67
|
-
* @returns {number} Delay in milliseconds
|
|
68
|
-
*/
|
|
69
|
-
export function backoffWithJitter(attempt) {
|
|
70
|
-
const base = BASE_BACKOFF_MS * Math.pow(2, attempt);
|
|
71
|
-
const jitter = base * JITTER_FACTOR * (Math.random() * 2 - 1);
|
|
72
|
-
return Math.round(base + jitter);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Creates an empty FontDecisions object with default sources.
|
|
77
|
-
* @param {object} params
|
|
78
|
-
* @param {string} params.titleSource
|
|
79
|
-
* @param {string} params.title
|
|
80
|
-
* @param {string} params.titleOriginal
|
|
81
|
-
* @param {string} params.documentId
|
|
82
|
-
* @param {number} params.weight
|
|
83
|
-
* @param {string} params.weightSource
|
|
84
|
-
* @param {string|null} params.matchedKeyword
|
|
85
|
-
* @param {string} params.weightName
|
|
86
|
-
* @param {string} params.weightNameSource
|
|
87
|
-
* @param {string} params.style
|
|
88
|
-
* @param {string} params.styleSource
|
|
89
|
-
* @param {string} params.styleReason
|
|
90
|
-
* @param {string} params.subfamily
|
|
91
|
-
* @param {string} params.subfamilySource
|
|
92
|
-
* @param {Array} params.titleAlternatives
|
|
93
|
-
* @returns {object}
|
|
94
|
-
*/
|
|
95
|
-
export function createFontDecisions({
|
|
96
|
-
titleSource = 'fontkit-fullName',
|
|
97
|
-
title = '',
|
|
98
|
-
titleOriginal = '',
|
|
99
|
-
documentId = '',
|
|
100
|
-
weight = 400,
|
|
101
|
-
weightSource = 'default-400',
|
|
102
|
-
matchedKeyword = null,
|
|
103
|
-
weightName = '',
|
|
104
|
-
weightNameSource = 'nameId17-preferredSubfamily',
|
|
105
|
-
style = 'Regular',
|
|
106
|
-
styleSource = 'default-regular',
|
|
107
|
-
styleReason = '',
|
|
108
|
-
subfamily = '',
|
|
109
|
-
subfamilySource = 'default-empty',
|
|
110
|
-
titleAlternatives = [],
|
|
111
|
-
}) {
|
|
112
|
-
return {
|
|
113
|
-
title: {
|
|
114
|
-
source: titleSource,
|
|
115
|
-
original: titleOriginal,
|
|
116
|
-
processed: title,
|
|
117
|
-
alternatives: titleAlternatives,
|
|
118
|
-
userOverride: null,
|
|
119
|
-
},
|
|
120
|
-
documentId: {
|
|
121
|
-
source: 'derived-from-title',
|
|
122
|
-
generated: documentId,
|
|
123
|
-
userOverride: null,
|
|
124
|
-
},
|
|
125
|
-
weight: {
|
|
126
|
-
source: weightSource,
|
|
127
|
-
detected: weight,
|
|
128
|
-
matchedKeyword,
|
|
129
|
-
rawWeightName: weightName,
|
|
130
|
-
userOverride: null,
|
|
131
|
-
},
|
|
132
|
-
weightName: {
|
|
133
|
-
source: weightNameSource,
|
|
134
|
-
detected: weightName,
|
|
135
|
-
userOverride: null,
|
|
136
|
-
},
|
|
137
|
-
style: {
|
|
138
|
-
source: styleSource,
|
|
139
|
-
detected: style,
|
|
140
|
-
reason: styleReason,
|
|
141
|
-
userOverride: null,
|
|
142
|
-
},
|
|
143
|
-
subfamily: {
|
|
144
|
-
source: subfamilySource,
|
|
145
|
-
detected: subfamily,
|
|
146
|
-
userOverride: null,
|
|
147
|
-
},
|
|
148
|
-
existingDocument: {
|
|
149
|
-
recommendation: RECOMMENDATION.CREATE,
|
|
150
|
-
exact: null,
|
|
151
|
-
candidates: [],
|
|
152
|
-
userChoice: null,
|
|
153
|
-
selectedCandidate: null,
|
|
154
|
-
lookupFailed: false,
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Creates an initial empty UploadPlan.
|
|
161
|
-
* @param {object} settings
|
|
162
|
-
* @returns {object}
|
|
163
|
-
*/
|
|
164
|
-
export function createEmptyPlan(settings = {}) {
|
|
165
|
-
return {
|
|
166
|
-
version: PLAN_VERSION,
|
|
167
|
-
settings: {
|
|
168
|
-
price: 0,
|
|
169
|
-
preserveShortenedNames: false,
|
|
170
|
-
preserveFileNames: false,
|
|
171
|
-
...settings,
|
|
172
|
-
},
|
|
173
|
-
fonts: {},
|
|
174
|
-
subfamilyGroups: {},
|
|
175
|
-
phase: PLAN_PHASE.IDLE,
|
|
176
|
-
processingProgress: {
|
|
177
|
-
total: 0,
|
|
178
|
-
completed: 0,
|
|
179
|
-
failed: 0,
|
|
180
|
-
currentFile: null,
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
1
|
+
// Type constants and enums for the two-phase upload plan — single source of truth
|
|
2
|
+
|
|
3
|
+
/** @enum {string} — Font processing status within the plan */
|
|
4
|
+
export const FONT_STATUS = {
|
|
5
|
+
PENDING: 'pending',
|
|
6
|
+
PROCESSING: 'processing',
|
|
7
|
+
PROCESSED: 'processed',
|
|
8
|
+
ERROR: 'error',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** @enum {string} — Modal phase state machine */
|
|
12
|
+
export const PLAN_PHASE = {
|
|
13
|
+
IDLE: 'idle',
|
|
14
|
+
PROCESSING: 'processing',
|
|
15
|
+
REVIEWING: 'reviewing',
|
|
16
|
+
READY: 'ready',
|
|
17
|
+
EXECUTING: 'executing',
|
|
18
|
+
COMPLETE: 'complete',
|
|
19
|
+
ERROR: 'error',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** @enum {string} — Document resolution recommendation from resolveExistingFont */
|
|
23
|
+
export const RECOMMENDATION = {
|
|
24
|
+
USE_EXACT: 'use-exact',
|
|
25
|
+
USE_CANDIDATE: 'use-candidate',
|
|
26
|
+
AMBIGUOUS: 'ambiguous',
|
|
27
|
+
CREATE: 'create',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** @enum {string} — Per-font execution progress status */
|
|
31
|
+
export const EXECUTION_STATUS = {
|
|
32
|
+
QUEUED: 'queued',
|
|
33
|
+
UPLOADING_ASSETS: 'uploading-assets',
|
|
34
|
+
GENERATING_CSS: 'generating-css',
|
|
35
|
+
GENERATING_METADATA: 'generating-metadata',
|
|
36
|
+
CREATING_DOCUMENT: 'creating-document',
|
|
37
|
+
PATCHING_TYPEFACE: 'patching-typeface',
|
|
38
|
+
COMPLETE: 'complete',
|
|
39
|
+
ERROR: 'error',
|
|
40
|
+
SKIPPED: 'skipped',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Processing-owned fields — only written by ADD_PROCESSED_FONT, never by user edit actions */
|
|
44
|
+
export const PROCESSING_OWNED_FIELDS = ['parsedMetadata', 'glyphCount', 'opentypeFeatures', 'variationAxes', 'status'];
|
|
45
|
+
|
|
46
|
+
/** User-owned fields — only written by user edit actions via decisions.*.userOverride */
|
|
47
|
+
export const USER_OWNED_FIELDS = ['title', 'documentId', 'weight', 'weightName', 'style', 'subfamily'];
|
|
48
|
+
|
|
49
|
+
/** Current plan schema version — increment on breaking shape changes */
|
|
50
|
+
export const PLAN_VERSION = 1;
|
|
51
|
+
|
|
52
|
+
/** Maximum concurrent asset uploads */
|
|
53
|
+
export const CONCURRENCY_LIMIT = 3;
|
|
54
|
+
|
|
55
|
+
/** Maximum retry attempts for 429 rate-limited requests */
|
|
56
|
+
export const MAX_RETRIES = 3;
|
|
57
|
+
|
|
58
|
+
/** Base backoff delay in ms for exponential retry */
|
|
59
|
+
export const BASE_BACKOFF_MS = 1000;
|
|
60
|
+
|
|
61
|
+
/** Jitter factor for exponential backoff (±25%) */
|
|
62
|
+
export const JITTER_FACTOR = 0.25;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Calculate backoff delay with jitter for retry logic.
|
|
66
|
+
* @param {number} attempt - Zero-based attempt number
|
|
67
|
+
* @returns {number} Delay in milliseconds
|
|
68
|
+
*/
|
|
69
|
+
export function backoffWithJitter(attempt) {
|
|
70
|
+
const base = BASE_BACKOFF_MS * Math.pow(2, attempt);
|
|
71
|
+
const jitter = base * JITTER_FACTOR * (Math.random() * 2 - 1);
|
|
72
|
+
return Math.round(base + jitter);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Creates an empty FontDecisions object with default sources.
|
|
77
|
+
* @param {object} params
|
|
78
|
+
* @param {string} params.titleSource
|
|
79
|
+
* @param {string} params.title
|
|
80
|
+
* @param {string} params.titleOriginal
|
|
81
|
+
* @param {string} params.documentId
|
|
82
|
+
* @param {number} params.weight
|
|
83
|
+
* @param {string} params.weightSource
|
|
84
|
+
* @param {string|null} params.matchedKeyword
|
|
85
|
+
* @param {string} params.weightName
|
|
86
|
+
* @param {string} params.weightNameSource
|
|
87
|
+
* @param {string} params.style
|
|
88
|
+
* @param {string} params.styleSource
|
|
89
|
+
* @param {string} params.styleReason
|
|
90
|
+
* @param {string} params.subfamily
|
|
91
|
+
* @param {string} params.subfamilySource
|
|
92
|
+
* @param {Array} params.titleAlternatives
|
|
93
|
+
* @returns {object}
|
|
94
|
+
*/
|
|
95
|
+
export function createFontDecisions({
|
|
96
|
+
titleSource = 'fontkit-fullName',
|
|
97
|
+
title = '',
|
|
98
|
+
titleOriginal = '',
|
|
99
|
+
documentId = '',
|
|
100
|
+
weight = 400,
|
|
101
|
+
weightSource = 'default-400',
|
|
102
|
+
matchedKeyword = null,
|
|
103
|
+
weightName = '',
|
|
104
|
+
weightNameSource = 'nameId17-preferredSubfamily',
|
|
105
|
+
style = 'Regular',
|
|
106
|
+
styleSource = 'default-regular',
|
|
107
|
+
styleReason = '',
|
|
108
|
+
subfamily = '',
|
|
109
|
+
subfamilySource = 'default-empty',
|
|
110
|
+
titleAlternatives = [],
|
|
111
|
+
}) {
|
|
112
|
+
return {
|
|
113
|
+
title: {
|
|
114
|
+
source: titleSource,
|
|
115
|
+
original: titleOriginal,
|
|
116
|
+
processed: title,
|
|
117
|
+
alternatives: titleAlternatives,
|
|
118
|
+
userOverride: null,
|
|
119
|
+
},
|
|
120
|
+
documentId: {
|
|
121
|
+
source: 'derived-from-title',
|
|
122
|
+
generated: documentId,
|
|
123
|
+
userOverride: null,
|
|
124
|
+
},
|
|
125
|
+
weight: {
|
|
126
|
+
source: weightSource,
|
|
127
|
+
detected: weight,
|
|
128
|
+
matchedKeyword,
|
|
129
|
+
rawWeightName: weightName,
|
|
130
|
+
userOverride: null,
|
|
131
|
+
},
|
|
132
|
+
weightName: {
|
|
133
|
+
source: weightNameSource,
|
|
134
|
+
detected: weightName,
|
|
135
|
+
userOverride: null,
|
|
136
|
+
},
|
|
137
|
+
style: {
|
|
138
|
+
source: styleSource,
|
|
139
|
+
detected: style,
|
|
140
|
+
reason: styleReason,
|
|
141
|
+
userOverride: null,
|
|
142
|
+
},
|
|
143
|
+
subfamily: {
|
|
144
|
+
source: subfamilySource,
|
|
145
|
+
detected: subfamily,
|
|
146
|
+
userOverride: null,
|
|
147
|
+
},
|
|
148
|
+
existingDocument: {
|
|
149
|
+
recommendation: RECOMMENDATION.CREATE,
|
|
150
|
+
exact: null,
|
|
151
|
+
candidates: [],
|
|
152
|
+
userChoice: null,
|
|
153
|
+
selectedCandidate: null,
|
|
154
|
+
lookupFailed: false,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Creates an initial empty UploadPlan.
|
|
161
|
+
* @param {object} settings
|
|
162
|
+
* @returns {object}
|
|
163
|
+
*/
|
|
164
|
+
export function createEmptyPlan(settings = {}) {
|
|
165
|
+
return {
|
|
166
|
+
version: PLAN_VERSION,
|
|
167
|
+
settings: {
|
|
168
|
+
price: 0,
|
|
169
|
+
preserveShortenedNames: false,
|
|
170
|
+
preserveFileNames: false,
|
|
171
|
+
...settings,
|
|
172
|
+
},
|
|
173
|
+
fonts: {},
|
|
174
|
+
subfamilyGroups: {},
|
|
175
|
+
phase: PLAN_PHASE.IDLE,
|
|
176
|
+
processingProgress: {
|
|
177
|
+
total: 0,
|
|
178
|
+
completed: 0,
|
|
179
|
+
failed: 0,
|
|
180
|
+
currentFile: null,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|