@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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +695 -437
  3. package/dist/index.js +1628 -17701
  4. package/dist/index.mjs +1537 -17599
  5. package/package.json +83 -83
  6. package/src/components/BatchUploadFonts.jsx +655 -653
  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 -304
  25. package/src/components/UploadScriptsComponent.jsx +539 -539
  26. package/src/components/UploadStep1Settings.jsx +272 -272
  27. package/src/components/UploadStep2Review.jsx +478 -474
  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 -267
  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 -517
  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 -0
  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,196 +1,196 @@
1
- // Post-upload summary — results display with retry for failed fonts and typeface patch
2
-
3
- import React, { useState, useCallback } from 'react';
4
- import { Stack, Flex, Text, Card, Badge, Button, Box, Spinner } from '@sanity/ui';
5
- import { CheckmarkCircleIcon, WarningOutlineIcon, ResetIcon } from '@sanity/icons';
6
- import { updateTypefaceDocument } from '../utils/updateTypefaceDocument';
7
-
8
- /**
9
- * Post-upload summary — shows execution results with retry options.
10
- */
11
- export default function UploadSummary({
12
- plan,
13
- result,
14
- onClose,
15
- onRetry,
16
- client,
17
- docId,
18
- stylesObject,
19
- preferredStyleRef,
20
- }) {
21
- const [retryingPatch, setRetryingPatch] = useState(false);
22
- const [patchRetryResult, setPatchRetryResult] = useState(null);
23
-
24
- const hasFailedFonts = result?.failedFonts?.length > 0;
25
- const hasTypefacePatchError = result?.typefacePatchError && !patchRetryResult?.success;
26
- const allSuccess = result?.success && !hasTypefacePatchError;
27
-
28
- /** Retry the typeface document patch only */
29
- const handleRetryTypefacePatch = useCallback(async () => {
30
- if (!result || !client || !docId) return;
31
- setRetryingPatch(true);
32
- setPatchRetryResult(null);
33
-
34
- try {
35
- const subfamilies = {};
36
- const uniqueSubfamilies = new Set();
37
- for (const entry of Object.values(plan.fonts)) {
38
- if (entry.status === 'error') continue;
39
- subfamilies[entry.documentId] = entry.subfamily;
40
- if (entry.subfamily) uniqueSubfamilies.add(entry.subfamily);
41
- }
42
-
43
- await updateTypefaceDocument(
44
- docId,
45
- result.fontRefs || [],
46
- result.variableRefs || [],
47
- subfamilies,
48
- [...uniqueSubfamilies],
49
- stylesObject?.subfamilies || [],
50
- preferredStyleRef || {},
51
- { weight: -100, style: 'Italic', _ref: result.fontRefs?.[0]?._ref || '' },
52
- stylesObject || {},
53
- client,
54
- () => {},
55
- () => {},
56
- );
57
-
58
- setPatchRetryResult({ success: true });
59
- } catch (err) {
60
- console.error('Typeface patch retry failed:', err);
61
- setPatchRetryResult({ success: false, error: err.message });
62
- }
63
-
64
- setRetryingPatch(false);
65
- }, [result, client, docId, plan, stylesObject, preferredStyleRef]);
66
-
67
- return (
68
- <Stack space={4}>
69
- {/* Header */}
70
- <Flex align="center" gap={3} ref={(el) => el?.focus?.()} tabIndex={-1}>
71
- {allSuccess ? (
72
- <CheckmarkCircleIcon style={{ color: '#43b649', fontSize: 28 }} />
73
- ) : (
74
- <WarningOutlineIcon style={{ color: '#f03e2f', fontSize: 28 }} />
75
- )}
76
- <Text size={2} weight="semibold">
77
- {allSuccess ? 'Upload Complete' : 'Upload Completed with Issues'}
78
- </Text>
79
- </Flex>
80
-
81
- {/* Stats */}
82
- {result && (
83
- <Card border padding={4} radius={2}>
84
- <Stack space={3}>
85
- <Flex gap={2} wrap="wrap">
86
- {result.created > 0 && (
87
- <Badge tone="positive" fontSize={1}>
88
- {result.created} created
89
- </Badge>
90
- )}
91
- {result.updated > 0 && (
92
- <Badge tone="caution" fontSize={1}>
93
- {result.updated} updated
94
- </Badge>
95
- )}
96
- {result.failed > 0 && (
97
- <Badge tone="critical" fontSize={1}>
98
- {result.failed} failed
99
- </Badge>
100
- )}
101
- {result.skipped > 0 && (
102
- <Badge mode="outline" fontSize={1}>
103
- {result.skipped} skipped
104
- </Badge>
105
- )}
106
- </Flex>
107
- </Stack>
108
- </Card>
109
- )}
110
-
111
- {/* Failed fonts */}
112
- {hasFailedFonts && (
113
- <Stack space={3}>
114
- <Flex align="center" justify="space-between">
115
- <Flex align="center" gap={2}>
116
- <Text size={1} weight="semibold">Failed Fonts</Text>
117
- <Badge tone="critical" fontSize={0}>{result.failedFonts.length}</Badge>
118
- </Flex>
119
- <Button
120
- mode="ghost"
121
- tone="primary"
122
- icon={ResetIcon}
123
- text="Retry Failed"
124
- fontSize={1}
125
- padding={2}
126
- onClick={() => onRetry(result.failedFonts.map(f => f.tempId).filter(Boolean))}
127
- />
128
- </Flex>
129
- <Stack space={2}>
130
- {result.failedFonts.map((f, i) => (
131
- <Card key={i} tone="critical" border padding={3} radius={2}>
132
- <Stack space={2}>
133
- <Flex align="center" gap={2}>
134
- <Text size={1} weight="semibold">{f.title}</Text>
135
- {f.failedAt && f.failedAt !== 'unknown' && (
136
- <Badge tone="critical" fontSize={0} mode="outline">Failed at: {f.failedAt}</Badge>
137
- )}
138
- </Flex>
139
- <Text size={1}>{f.error}</Text>
140
- </Stack>
141
- </Card>
142
- ))}
143
- </Stack>
144
- </Stack>
145
- )}
146
-
147
- {/* Typeface patch error */}
148
- {hasTypefacePatchError && (
149
- <Card tone="caution" border padding={4} radius={2}>
150
- <Stack space={3}>
151
- <Text size={1} weight="semibold">Typeface Document Not Updated</Text>
152
- <Text size={1}>
153
- {result.created + result.updated} font document{result.created + result.updated === 1 ? '' : 's'} created/updated successfully, but the typeface document could not be patched to reference them.
154
- </Text>
155
- <Text size={1} muted>{result.typefacePatchError}</Text>
156
- <Flex gap={2}>
157
- <Button
158
- mode="default"
159
- tone="primary"
160
- icon={retryingPatch ? undefined : ResetIcon}
161
- text={retryingPatch ? 'Retrying...' : 'Retry Typeface Patch'}
162
- disabled={retryingPatch}
163
- onClick={handleRetryTypefacePatch}
164
- />
165
- {retryingPatch && <Spinner />}
166
- </Flex>
167
- </Stack>
168
- </Card>
169
- )}
170
-
171
- {/* Successful typeface patch retry */}
172
- {patchRetryResult?.success && (
173
- <Card tone="positive" border padding={3} radius={2}>
174
- <Text size={1}>Typeface document updated successfully on retry.</Text>
175
- </Card>
176
- )}
177
-
178
- {/* Failed typeface patch retry */}
179
- {patchRetryResult && !patchRetryResult.success && (
180
- <Card tone="critical" border padding={3} radius={2}>
181
- <Text size={1}>Retry failed: {patchRetryResult.error}</Text>
182
- </Card>
183
- )}
184
-
185
- {/* Close */}
186
- <Flex justify="flex-end">
187
- <Button
188
- mode="default"
189
- tone="primary"
190
- text="Close"
191
- onClick={onClose}
192
- />
193
- </Flex>
194
- </Stack>
195
- );
196
- }
1
+ // Post-upload summary — results display with retry for failed fonts and typeface patch
2
+
3
+ import React, { useState, useCallback } from 'react';
4
+ import { Stack, Flex, Text, Card, Badge, Button, Box, Spinner } from '@sanity/ui';
5
+ import { CheckmarkCircleIcon, WarningOutlineIcon, ResetIcon } from '@sanity/icons';
6
+ import { updateTypefaceDocument } from '../utils/updateTypefaceDocument';
7
+
8
+ /**
9
+ * Post-upload summary — shows execution results with retry options.
10
+ */
11
+ export default function UploadSummary({
12
+ plan,
13
+ result,
14
+ onClose,
15
+ onRetry,
16
+ client,
17
+ docId,
18
+ stylesObject,
19
+ preferredStyleRef,
20
+ }) {
21
+ const [retryingPatch, setRetryingPatch] = useState(false);
22
+ const [patchRetryResult, setPatchRetryResult] = useState(null);
23
+
24
+ const hasFailedFonts = result?.failedFonts?.length > 0;
25
+ const hasTypefacePatchError = result?.typefacePatchError && !patchRetryResult?.success;
26
+ const allSuccess = result?.success && !hasTypefacePatchError;
27
+
28
+ /** Retry the typeface document patch only */
29
+ const handleRetryTypefacePatch = useCallback(async () => {
30
+ if (!result || !client || !docId) return;
31
+ setRetryingPatch(true);
32
+ setPatchRetryResult(null);
33
+
34
+ try {
35
+ const subfamilies = {};
36
+ const uniqueSubfamilies = new Set();
37
+ for (const entry of Object.values(plan.fonts)) {
38
+ if (entry.status === 'error') continue;
39
+ subfamilies[entry.documentId] = entry.subfamily;
40
+ if (entry.subfamily) uniqueSubfamilies.add(entry.subfamily);
41
+ }
42
+
43
+ await updateTypefaceDocument(
44
+ docId,
45
+ result.fontRefs || [],
46
+ result.variableRefs || [],
47
+ subfamilies,
48
+ [...uniqueSubfamilies],
49
+ stylesObject?.subfamilies || [],
50
+ preferredStyleRef || {},
51
+ { weight: -100, style: 'Italic', _ref: result.fontRefs?.[0]?._ref || '' },
52
+ stylesObject || {},
53
+ client,
54
+ () => {},
55
+ () => {},
56
+ );
57
+
58
+ setPatchRetryResult({ success: true });
59
+ } catch (err) {
60
+ console.error('Typeface patch retry failed:', err);
61
+ setPatchRetryResult({ success: false, error: err.message });
62
+ }
63
+
64
+ setRetryingPatch(false);
65
+ }, [result, client, docId, plan, stylesObject, preferredStyleRef]);
66
+
67
+ return (
68
+ <Stack space={4}>
69
+ {/* Header */}
70
+ <Flex align="center" gap={3} ref={(el) => el?.focus?.()} tabIndex={-1}>
71
+ {allSuccess ? (
72
+ <CheckmarkCircleIcon style={{ color: '#43b649', fontSize: 28 }} />
73
+ ) : (
74
+ <WarningOutlineIcon style={{ color: '#f03e2f', fontSize: 28 }} />
75
+ )}
76
+ <Text size={2} weight="semibold">
77
+ {allSuccess ? 'Upload Complete' : 'Upload Completed with Issues'}
78
+ </Text>
79
+ </Flex>
80
+
81
+ {/* Stats */}
82
+ {result && (
83
+ <Card border padding={4} radius={2}>
84
+ <Stack space={3}>
85
+ <Flex gap={2} wrap="wrap">
86
+ {result.created > 0 && (
87
+ <Badge tone="positive" fontSize={1}>
88
+ {result.created} created
89
+ </Badge>
90
+ )}
91
+ {result.updated > 0 && (
92
+ <Badge tone="caution" fontSize={1}>
93
+ {result.updated} updated
94
+ </Badge>
95
+ )}
96
+ {result.failed > 0 && (
97
+ <Badge tone="critical" fontSize={1}>
98
+ {result.failed} failed
99
+ </Badge>
100
+ )}
101
+ {result.skipped > 0 && (
102
+ <Badge mode="outline" fontSize={1}>
103
+ {result.skipped} skipped
104
+ </Badge>
105
+ )}
106
+ </Flex>
107
+ </Stack>
108
+ </Card>
109
+ )}
110
+
111
+ {/* Failed fonts */}
112
+ {hasFailedFonts && (
113
+ <Stack space={3}>
114
+ <Flex align="center" justify="space-between">
115
+ <Flex align="center" gap={2}>
116
+ <Text size={1} weight="semibold">Failed Fonts</Text>
117
+ <Badge tone="critical" fontSize={0}>{result.failedFonts.length}</Badge>
118
+ </Flex>
119
+ <Button
120
+ mode="ghost"
121
+ tone="primary"
122
+ icon={ResetIcon}
123
+ text="Retry Failed"
124
+ fontSize={1}
125
+ padding={2}
126
+ onClick={() => onRetry(result.failedFonts.map(f => f.tempId).filter(Boolean))}
127
+ />
128
+ </Flex>
129
+ <Stack space={2}>
130
+ {result.failedFonts.map((f, i) => (
131
+ <Card key={i} tone="critical" border padding={3} radius={2}>
132
+ <Stack space={2}>
133
+ <Flex align="center" gap={2}>
134
+ <Text size={1} weight="semibold">{f.title}</Text>
135
+ {f.failedAt && f.failedAt !== 'unknown' && (
136
+ <Badge tone="critical" fontSize={0} mode="outline">Failed at: {f.failedAt}</Badge>
137
+ )}
138
+ </Flex>
139
+ <Text size={1}>{f.error}</Text>
140
+ </Stack>
141
+ </Card>
142
+ ))}
143
+ </Stack>
144
+ </Stack>
145
+ )}
146
+
147
+ {/* Typeface patch error */}
148
+ {hasTypefacePatchError && (
149
+ <Card tone="caution" border padding={4} radius={2}>
150
+ <Stack space={3}>
151
+ <Text size={1} weight="semibold">Typeface Document Not Updated</Text>
152
+ <Text size={1}>
153
+ {result.created + result.updated} font document{result.created + result.updated === 1 ? '' : 's'} created/updated successfully, but the typeface document could not be patched to reference them.
154
+ </Text>
155
+ <Text size={1} muted>{result.typefacePatchError}</Text>
156
+ <Flex gap={2}>
157
+ <Button
158
+ mode="default"
159
+ tone="primary"
160
+ icon={retryingPatch ? undefined : ResetIcon}
161
+ text={retryingPatch ? 'Retrying...' : 'Retry Typeface Patch'}
162
+ disabled={retryingPatch}
163
+ onClick={handleRetryTypefacePatch}
164
+ />
165
+ {retryingPatch && <Spinner />}
166
+ </Flex>
167
+ </Stack>
168
+ </Card>
169
+ )}
170
+
171
+ {/* Successful typeface patch retry */}
172
+ {patchRetryResult?.success && (
173
+ <Card tone="positive" border padding={3} radius={2}>
174
+ <Text size={1}>Typeface document updated successfully on retry.</Text>
175
+ </Card>
176
+ )}
177
+
178
+ {/* Failed typeface patch retry */}
179
+ {patchRetryResult && !patchRetryResult.success && (
180
+ <Card tone="critical" border padding={3} radius={2}>
181
+ <Text size={1}>Retry failed: {patchRetryResult.error}</Text>
182
+ </Card>
183
+ )}
184
+
185
+ {/* Close */}
186
+ <Flex justify="flex-end">
187
+ <Button
188
+ mode="default"
189
+ tone="primary"
190
+ text="Close"
191
+ onClick={onClose}
192
+ />
193
+ </Flex>
194
+ </Stack>
195
+ );
196
+ }