@liiift-studio/sanity-font-manager 2.7.0 → 2.8.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/LICENSE +21 -0
  2. package/README.md +695 -437
  3. package/dist/index.js +2330 -7084
  4. package/dist/index.mjs +2331 -7085
  5. package/package.json +84 -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,26 +1,26 @@
1
- // Shared status bar — shows status message in green/red with an optional action slot on the far right
2
-
3
- import React from 'react';
4
- import { Flex, Text } from '@sanity/ui';
5
-
6
- /**
7
- * Shows an upload/operation status string coloured green on success and red on error.
8
- * Accepts an optional `action` element rendered on the far right.
9
- * @param {Object} props
10
- * @param {string} props.status - Status message to display
11
- * @param {boolean} props.error - Whether the current status represents an error
12
- * @param {React.ReactNode} [props.action] - Optional element to render on the far right
13
- */
14
- const StatusDisplay = ({ status, error, action }) => {
15
- return (
16
- <Flex paddingTop={1} paddingBottom={3} align="center" justify="space-between">
17
- <Flex align="center" gap={2}>
18
- <Text size={1}>Status:</Text>
19
- <Text size={1} style={{ color: error ? 'red' : 'green' }}>{status}</Text>
20
- </Flex>
21
- {action && action}
22
- </Flex>
23
- );
24
- };
25
-
26
- export default StatusDisplay;
1
+ // Shared status bar — shows status message in green/red with an optional action slot on the far right
2
+
3
+ import React from 'react';
4
+ import { Flex, Text } from '@sanity/ui';
5
+
6
+ /**
7
+ * Shows an upload/operation status string coloured green on success and red on error.
8
+ * Accepts an optional `action` element rendered on the far right.
9
+ * @param {Object} props
10
+ * @param {string} props.status - Status message to display
11
+ * @param {boolean} props.error - Whether the current status represents an error
12
+ * @param {React.ReactNode} [props.action] - Optional element to render on the far right
13
+ */
14
+ const StatusDisplay = ({ status, error, action }) => {
15
+ return (
16
+ <Flex paddingTop={1} paddingBottom={3} align="center" justify="space-between">
17
+ <Flex align="center" gap={2}>
18
+ <Text size={1}>Status:</Text>
19
+ <Text size={1} style={{ color: error ? 'red' : 'green' }}>{status}</Text>
20
+ </Flex>
21
+ {action && action}
22
+ </Flex>
23
+ );
24
+ };
25
+
26
+ export default StatusDisplay;
@@ -1,16 +1,16 @@
1
- // Displays the total count of static and variable font styles linked to a typeface document
2
-
3
- import React from 'react';
4
- import { Text } from '@sanity/ui';
5
- import { useFormValue } from 'sanity';
6
-
7
- /** Reads styles.fonts and styles.variableFont arrays and displays the combined count. */
8
- export const StyleCountInput = (props) => {
9
- const styles = useFormValue(['styles', 'fonts']) || [];
10
- const vfStyles = useFormValue(['styles', 'variableFont']) || [];
11
- const count = styles.length + vfStyles.length;
12
-
13
- return (
14
- <Text size={1}>{count}</Text>
15
- );
16
- };
1
+ // Displays the total count of static and variable font styles linked to a typeface document
2
+
3
+ import React from 'react';
4
+ import { Text } from '@sanity/ui';
5
+ import { useFormValue } from 'sanity';
6
+
7
+ /** Reads styles.fonts and styles.variableFont arrays and displays the combined count. */
8
+ export const StyleCountInput = (props) => {
9
+ const styles = useFormValue(['styles', 'fonts']) || [];
10
+ const vfStyles = useFormValue(['styles', 'variableFont']) || [];
11
+ const count = styles.length + vfStyles.length;
12
+
13
+ return (
14
+ <Text size={1}>{count}</Text>
15
+ );
16
+ };
@@ -1,76 +1,76 @@
1
- // Updates and re-links existing script font variant references on font documents
2
-
3
- import React, { useState, useCallback, useRef, useEffect } from 'react';
4
- import { Stack, Text, Button } from '@sanity/ui';
5
- import { useFormValue, set } from 'sanity';
6
-
7
- import { useSanityClient } from '../hooks/useSanityClient';
8
-
9
- /**
10
- * Wraps the default Sanity scripts array input with a button that reads
11
- * scriptFileInput from all linked font documents and syncs the list.
12
- * @param {Object} props - Sanity input component props
13
- */
14
- export const UpdateScriptsComponent = (props) => {
15
- const { onChange } = props;
16
-
17
- const client = useSanityClient();
18
- const scripts = useFormValue(['scripts']) || [];
19
- const fonts = useFormValue(['styles', 'fonts']);
20
-
21
- const isReadyRef = useRef(false);
22
- const [message, setMessage] = useState('');
23
-
24
- // Delay ready flag to avoid triggering onChange during initial mount
25
- useEffect(() => {
26
- const timer = setTimeout(() => { isReadyRef.current = true; }, 100);
27
- return () => clearTimeout(timer);
28
- }, []);
29
-
30
- /** Fetches all linked font documents and derives the unique script list from their scriptFileInput fields. */
31
- const updateFromFonts = useCallback(async () => {
32
- if (!fonts || fonts.length === 0) {
33
- setMessage('No fonts found to extract scripts from');
34
- return;
35
- }
36
-
37
- const fontRefs = fonts.map(font => font._ref);
38
-
39
- let result;
40
- try {
41
- result = await client.fetch(
42
- `*[_type == "font" && _id in $fontRefs]{ _id, scriptFileInput }`,
43
- { fontRefs }
44
- );
45
- } catch (err) {
46
- console.error('Failed to fetch font documents:', err);
47
- setMessage('Error updating scripts: ' + err.message);
48
- return;
49
- }
50
-
51
- const newScripts = result.reduce((acc, font) => {
52
- if (!font?.scriptFileInput) return acc;
53
- for (const language of Object.keys(font.scriptFileInput)) {
54
- if (!acc.includes(language)) acc.push(language);
55
- }
56
- return acc;
57
- }, []);
58
-
59
- if (isReadyRef.current) onChange(set(newScripts));
60
- setMessage('Scripts updated');
61
- }, [onChange, fonts, client]);
62
-
63
- return (
64
- <Stack space={3}>
65
- <Button
66
- mode="ghost"
67
- tone="primary"
68
- width="fill"
69
- text="Update Scripts from Font Files"
70
- onClick={updateFromFonts}
71
- />
72
- {message && <Text size={1} style={{ color: 'green' }}>{message}</Text>}
73
- {props.renderDefault(props)}
74
- </Stack>
75
- );
76
- };
1
+ // Updates and re-links existing script font variant references on font documents
2
+
3
+ import React, { useState, useCallback, useRef, useEffect } from 'react';
4
+ import { Stack, Text, Button } from '@sanity/ui';
5
+ import { useFormValue, set } from 'sanity';
6
+
7
+ import { useSanityClient } from '../hooks/useSanityClient';
8
+
9
+ /**
10
+ * Wraps the default Sanity scripts array input with a button that reads
11
+ * scriptFileInput from all linked font documents and syncs the list.
12
+ * @param {Object} props - Sanity input component props
13
+ */
14
+ export const UpdateScriptsComponent = (props) => {
15
+ const { onChange } = props;
16
+
17
+ const client = useSanityClient();
18
+ const scripts = useFormValue(['scripts']) || [];
19
+ const fonts = useFormValue(['styles', 'fonts']);
20
+
21
+ const isReadyRef = useRef(false);
22
+ const [message, setMessage] = useState('');
23
+
24
+ // Delay ready flag to avoid triggering onChange during initial mount
25
+ useEffect(() => {
26
+ const timer = setTimeout(() => { isReadyRef.current = true; }, 100);
27
+ return () => clearTimeout(timer);
28
+ }, []);
29
+
30
+ /** Fetches all linked font documents and derives the unique script list from their scriptFileInput fields. */
31
+ const updateFromFonts = useCallback(async () => {
32
+ if (!fonts || fonts.length === 0) {
33
+ setMessage('No fonts found to extract scripts from');
34
+ return;
35
+ }
36
+
37
+ const fontRefs = fonts.map(font => font._ref);
38
+
39
+ let result;
40
+ try {
41
+ result = await client.fetch(
42
+ `*[_type == "font" && _id in $fontRefs]{ _id, scriptFileInput }`,
43
+ { fontRefs }
44
+ );
45
+ } catch (err) {
46
+ console.error('Failed to fetch font documents:', err);
47
+ setMessage('Error updating scripts: ' + err.message);
48
+ return;
49
+ }
50
+
51
+ const newScripts = result.reduce((acc, font) => {
52
+ if (!font?.scriptFileInput) return acc;
53
+ for (const language of Object.keys(font.scriptFileInput)) {
54
+ if (!acc.includes(language)) acc.push(language);
55
+ }
56
+ return acc;
57
+ }, []);
58
+
59
+ if (isReadyRef.current) onChange(set(newScripts));
60
+ setMessage('Scripts updated');
61
+ }, [onChange, fonts, client]);
62
+
63
+ return (
64
+ <Stack space={3}>
65
+ <Button
66
+ mode="ghost"
67
+ tone="primary"
68
+ width="fill"
69
+ text="Update Scripts from Font Files"
70
+ onClick={updateFromFonts}
71
+ />
72
+ {message && <Text size={1} style={{ color: 'green' }}>{message}</Text>}
73
+ {props.renderDefault(props)}
74
+ </Stack>
75
+ );
76
+ };
@@ -1,43 +1,43 @@
1
- // Label-wrapped button that triggers a hidden file input
2
-
3
- import React, { forwardRef } from 'react';
4
- import { Button, Text } from '@sanity/ui';
5
-
6
- /**
7
- * Primary button with a transparent full-size file input overlay.
8
- * The ref is forwarded to the hidden <input> element.
9
- * @param {Object} props
10
- * @param {Function} props.handleUpload - onChange handler for the file input
11
- */
12
- const UploadButton = forwardRef(({ handleUpload }, ref) => {
13
- return (
14
- <Button
15
- mode="ghost"
16
- tone="primary"
17
- width="fill"
18
- padding={3}
19
- style={{ position: 'relative' }}
20
- >
21
- <Text align="center">Upload (ttf/otf/woff/woff2/etc...)</Text>
22
- <input
23
- ref={ref}
24
- type="file"
25
- multiple
26
- style={{
27
- position: 'absolute',
28
- top: 0,
29
- left: 0,
30
- width: '100%',
31
- height: '100%',
32
- opacity: 0,
33
- cursor: 'pointer',
34
- }}
35
- onChange={handleUpload}
36
- />
37
- </Button>
38
- );
39
- });
40
-
41
- UploadButton.displayName = 'UploadButton';
42
-
43
- export default UploadButton;
1
+ // Label-wrapped button that triggers a hidden file input
2
+
3
+ import React, { forwardRef } from 'react';
4
+ import { Button, Text } from '@sanity/ui';
5
+
6
+ /**
7
+ * Primary button with a transparent full-size file input overlay.
8
+ * The ref is forwarded to the hidden <input> element.
9
+ * @param {Object} props
10
+ * @param {Function} props.handleUpload - onChange handler for the file input
11
+ */
12
+ const UploadButton = forwardRef(({ handleUpload }, ref) => {
13
+ return (
14
+ <Button
15
+ mode="ghost"
16
+ tone="primary"
17
+ width="fill"
18
+ padding={3}
19
+ style={{ position: 'relative' }}
20
+ >
21
+ <Text align="center">Upload (ttf/otf/woff/woff2/etc...)</Text>
22
+ <input
23
+ ref={ref}
24
+ type="file"
25
+ multiple
26
+ style={{
27
+ position: 'absolute',
28
+ top: 0,
29
+ left: 0,
30
+ width: '100%',
31
+ height: '100%',
32
+ opacity: 0,
33
+ cursor: 'pointer',
34
+ }}
35
+ onChange={handleUpload}
36
+ />
37
+ </Button>
38
+ );
39
+ });
40
+
41
+ UploadButton.displayName = 'UploadButton';
42
+
43
+ export default UploadButton;