@liiift-studio/sanity-font-manager 2.5.0 → 2.5.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/dist/index.js CHANGED
@@ -59,7 +59,8 @@
59
59
 
60
60
 
61
61
 
62
- var _chunkFH4QKHOHjs = require('./chunk-FH4QKHOH.js');
62
+
63
+ var _chunkJCDZ7SWZjs = require('./chunk-JCDZ7SWZ.js');
63
64
 
64
65
  // src/components/BatchUploadFonts.jsx
65
66
  var _react = require('react'); var _react2 = _interopRequireDefault(_react);
@@ -113,7 +114,7 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
113
114
  if (fileType === "woff2") {
114
115
  console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Generating CSS for: ${fontObject.title}`);
115
116
  setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Generating CSS for: ${fontObject.title}`);
116
- newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
117
+ newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
117
118
  woff2File: file,
118
119
  fileInput: newFileInput,
119
120
  fontName: fontObject.title,
@@ -127,7 +128,7 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
127
128
  if (fileType === "ttf") {
128
129
  console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Generating font data for: ${fontObject.title}`);
129
130
  setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Generating font data for: ${fontObject.title}`);
130
- const metadata = await _chunkFH4QKHOHjs.generateFontData.call(void 0, {
131
+ const metadata = await _chunkJCDZ7SWZjs.generateFontData.call(void 0, {
131
132
  fontId: fontObject._id,
132
133
  url: baseAsset.url,
133
134
  fontKit,
@@ -240,7 +241,7 @@ var createOrUpdateFontDocument = async (font, client, setError) => {
240
241
  delete font.fontKit;
241
242
  delete font.originalFilename;
242
243
  if (font.variableFont && font.variableInstances) {
243
- const instanceMappings = await _chunkFH4QKHOHjs.parseVariableFontInstances.call(void 0, font, client);
244
+ const instanceMappings = await _chunkJCDZ7SWZjs.parseVariableFontInstances.call(void 0, font, client);
244
245
  if (instanceMappings.length > 0) {
245
246
  font.variableInstanceReferences = instanceMappings;
246
247
  }
@@ -405,9 +406,9 @@ var renameFontDocuments = async ({
405
406
  const res = await fetch(ttfAsset.url);
406
407
  file = await res.blob();
407
408
  }
408
- const fontBuffer = await _chunkFH4QKHOHjs.readFontFile.call(void 0, file);
409
- const font = await _chunkFH4QKHOHjs.parseFont.call(void 0, fontBuffer, `${fontDoc._id}.ttf`);
410
- const { weightName, subfamilyName, fontTitle } = _chunkFH4QKHOHjs.extractFontMetadata.call(void 0,
409
+ const fontBuffer = await _chunkJCDZ7SWZjs.readFontFile.call(void 0, file);
410
+ const font = await _chunkJCDZ7SWZjs.parseFont.call(void 0, fontBuffer, `${fontDoc._id}.ttf`);
411
+ const { weightName, subfamilyName, fontTitle } = _chunkJCDZ7SWZjs.extractFontMetadata.call(void 0,
411
412
  font,
412
413
  typefaceName,
413
414
  weightKeywordList,
@@ -587,7 +588,7 @@ var groupFontsBySubfamily = (fonts) => {
587
588
  if ((_a = font.title) == null ? void 0 : _a.includes("VF")) {
588
589
  subfamilies[`VF_${font.title}`] = [font];
589
590
  } else {
590
- const subfamilyName = font.subfamily ? _chunkFH4QKHOHjs.expandAbbreviations.call(void 0, font.subfamily) : "Regular";
591
+ const subfamilyName = font.subfamily ? _chunkJCDZ7SWZjs.expandAbbreviations.call(void 0, font.subfamily) : "Regular";
591
592
  if (!subfamilies[subfamilyName]) subfamilies[subfamilyName] = [];
592
593
  subfamilies[subfamilyName].push(font);
593
594
  }
@@ -635,7 +636,7 @@ var updateTypefaceSubfamilies = async (doc_id, stylesObject, newSubfamiliesArray
635
636
  };
636
637
 
637
638
  // src/components/BatchUploadFonts.jsx
638
- var UploadModal2 = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./UploadModal-6LIX7XOK.js"))));
639
+ var UploadModal2 = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./UploadModal-WPK2CXLR.js"))));
639
640
  var ACCEPTED_EXTENSIONS = ["ttf", "otf", "woff", "woff2", "eot", "svg"];
640
641
  var formatElapsed = (s) => {
641
642
  const m = Math.floor(s / 60);
@@ -664,7 +665,7 @@ var BatchUploadFonts = () => {
664
665
  const slug = _sanity.useFormValue.call(void 0, ["slug"]);
665
666
  const stylesObject = _sanity.useFormValue.call(void 0, ["styles"]) || { fonts: [], variableFont: [] };
666
667
  const subfamiliesArray = (stylesObject == null ? void 0 : stylesObject.subfamilies) || [];
667
- const { weightKeywordList, italicKeywordList } = _react.useMemo.call(void 0, () => _chunkFH4QKHOHjs.generateStyleKeywords.call(void 0, ), []);
668
+ const { weightKeywordList, italicKeywordList } = _react.useMemo.call(void 0, () => _chunkJCDZ7SWZjs.generateStyleKeywords.call(void 0, ), []);
668
669
  _react.useEffect.call(void 0, () => {
669
670
  if (ready !== true) {
670
671
  setElapsedSeconds(0);
@@ -777,7 +778,7 @@ var BatchUploadFonts = () => {
777
778
  }
778
779
  const sortedFiles = sortFilesByType(pendingFiles);
779
780
  setPendingFiles([]);
780
- const { fontsObjects, subfamilies, uniqueSubfamilies, newPreferredStyle, failedFiles } = await _chunkFH4QKHOHjs.processFontFiles.call(void 0,
781
+ const { fontsObjects, subfamilies, uniqueSubfamilies, newPreferredStyle, failedFiles } = await _chunkJCDZ7SWZjs.processFontFiles.call(void 0,
781
782
  sortedFiles,
782
783
  title,
783
784
  weightKeywordList,
@@ -796,7 +797,7 @@ var BatchUploadFonts = () => {
796
797
  setError,
797
798
  preserveFileNames
798
799
  );
799
- await _chunkFH4QKHOHjs.updateTypefaceDocument.call(void 0,
800
+ await _chunkJCDZ7SWZjs.updateTypefaceDocument.call(void 0,
800
801
  doc_id,
801
802
  fontRefs,
802
803
  variableRefs,
@@ -913,7 +914,7 @@ var BatchUploadFonts = () => {
913
914
  const woff2Blob = await woff2Response.blob();
914
915
  const woff2File = new File([woff2Blob], `${fontDoc._id}.woff2`, { type: "font/woff2" });
915
916
  setStatus(`Regenerating CSS for font ${i + 1}/${fontRefs.length}: ${fontDoc.title}`);
916
- const updatedFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
917
+ const updatedFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
917
918
  woff2File,
918
919
  fileInput: fontDoc.fileInput,
919
920
  fileName: fontDoc._id,
@@ -1135,7 +1136,7 @@ var BatchUploadFonts = () => {
1135
1136
  ), renderTooltipLabel(
1136
1137
  "Preserve shortened names",
1137
1138
  'Abbreviations in font names are kept as-is (e.g. "XNarrow" stays "XNarrow", "Bd" stays "Bd").'
1138
- )), ready === "rename" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Rename Existing Fonts", style: { width: "100%" }, onClick: handleRenameExistingFonts, disabled: ready !== true })), /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 3 }, /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, weight: "semibold", style: { lineHeight: 1.6 } }, "Update Font Prices"), ready === "price" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 2 }, /* @__PURE__ */ _react2.default.createElement(_chunkFH4QKHOHjs.PriceInput_default, { inputPrice, handleInputChange }), /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Update All Font Prices", style: { width: "100%" }, onClick: handleChangeFontPrice, disabled: ready !== true }))), /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 3 }, /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, weight: "semibold", style: { lineHeight: 1.6 } }, "Regenerate CSS"), /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, muted: true, style: { lineHeight: 1.6 } }, "Rebuilds the CSS @font-face files for all fonts in the typeface fonts list."), ready === "css" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Regenerate CSS Files", style: { width: "100%" }, onClick: handleRegenerateCssFiles, disabled: ready !== true }))))));
1139
+ )), ready === "rename" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Rename Existing Fonts", style: { width: "100%" }, onClick: handleRenameExistingFonts, disabled: ready !== true })), /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 3 }, /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, weight: "semibold", style: { lineHeight: 1.6 } }, "Update Font Prices"), ready === "price" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 2 }, /* @__PURE__ */ _react2.default.createElement(_chunkJCDZ7SWZjs.PriceInput_default, { inputPrice, handleInputChange }), /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Update All Font Prices", style: { width: "100%" }, onClick: handleChangeFontPrice, disabled: ready !== true }))), /* @__PURE__ */ _react2.default.createElement(_ui.Stack, { space: 3 }, /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, weight: "semibold", style: { lineHeight: 1.6 } }, "Regenerate CSS"), /* @__PURE__ */ _react2.default.createElement(_ui.Text, { size: 1, muted: true, style: { lineHeight: 1.6 } }, "Rebuilds the CSS @font-face files for all fonts in the typeface fonts list."), ready === "css" ? renderProcessing() : /* @__PURE__ */ _react2.default.createElement(_ui.Button, { mode: "ghost", tone: "primary", text: "Regenerate CSS Files", style: { width: "100%" }, onClick: handleRegenerateCssFiles, disabled: ready !== true }))))));
1139
1140
  };
1140
1141
 
1141
1142
  // src/components/GenerateCollectionsPairsComponent.jsx
@@ -1487,7 +1488,7 @@ var SingleUploaderTool = (props) => {
1487
1488
  const doc_style = _sanity.useFormValue.call(void 0, ["style"]);
1488
1489
  const doc_slug = _sanity.useFormValue.call(void 0, ["slug"]);
1489
1490
  const doc_metaData = _sanity.useFormValue.call(void 0, ["metaData"]);
1490
- const { weightKeywordList, italicKeywordList } = _react.useMemo.call(void 0, () => _chunkFH4QKHOHjs.generateStyleKeywords.call(void 0, ), []);
1491
+ const { weightKeywordList, italicKeywordList } = _react.useMemo.call(void 0, () => _chunkJCDZ7SWZjs.generateStyleKeywords.call(void 0, ), []);
1491
1492
  _react.useEffect.call(void 0, () => {
1492
1493
  handleSetFilenames();
1493
1494
  }, [fileInput]);
@@ -1541,7 +1542,7 @@ var SingleUploaderTool = (props) => {
1541
1542
  { id: woff2AssetRef }
1542
1543
  );
1543
1544
  const blob = await (await fetch(woff2Asset.url)).blob();
1544
- const newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
1545
+ const newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
1545
1546
  woff2File: blob,
1546
1547
  fileInput,
1547
1548
  fontName: doc_title,
@@ -1632,16 +1633,16 @@ var SingleUploaderTool = (props) => {
1632
1633
  );
1633
1634
  if (!(ttfAsset == null ? void 0 : ttfAsset.url)) throw new Error("Could not fetch TTF file URL");
1634
1635
  const arrayBuffer = await (await fetch(ttfAsset.url)).arrayBuffer();
1635
- const font = await _chunkFH4QKHOHjs.parseFont.call(void 0, arrayBuffer, `${doc_id}.ttf`);
1636
- const { weightName, subfamilyName, style, variableFont } = _chunkFH4QKHOHjs.extractFontMetadata.call(void 0,
1636
+ const font = await _chunkJCDZ7SWZjs.parseFont.call(void 0, arrayBuffer, `${doc_id}.ttf`);
1637
+ const { weightName, subfamilyName, style, variableFont } = _chunkJCDZ7SWZjs.extractFontMetadata.call(void 0,
1637
1638
  font,
1638
1639
  doc_typefaceName,
1639
1640
  weightKeywordList,
1640
1641
  italicKeywordList
1641
1642
  );
1642
- const weight = _chunkFH4QKHOHjs.determineWeight.call(void 0, font, weightName);
1643
+ const weight = _chunkJCDZ7SWZjs.determineWeight.call(void 0, font, weightName);
1643
1644
  await client.patch(doc_id).set({ weightName, subfamily: subfamilyName, style, variableFont, weight }).commit();
1644
- const fontData = await _chunkFH4QKHOHjs.generateFontData.call(void 0, {
1645
+ const fontData = await _chunkJCDZ7SWZjs.generateFontData.call(void 0, {
1645
1646
  url: ttfAsset.url,
1646
1647
  fontKit: font,
1647
1648
  fontId: doc_id,
@@ -1655,7 +1656,7 @@ var SingleUploaderTool = (props) => {
1655
1656
  variableFont,
1656
1657
  variableInstances: fontData.variableInstances
1657
1658
  };
1658
- const instanceMappings = await _chunkFH4QKHOHjs.parseVariableFontInstances.call(void 0, fontObj, client);
1659
+ const instanceMappings = await _chunkJCDZ7SWZjs.parseVariableFontInstances.call(void 0, fontObj, client);
1659
1660
  if (instanceMappings.length > 0) {
1660
1661
  await client.patch(doc_id).set({ variableInstanceReferences: instanceMappings }).commit();
1661
1662
  }
@@ -1774,7 +1775,7 @@ var SingleUploaderTool = (props) => {
1774
1775
  if (code === "woff2") {
1775
1776
  setMessage("Building CSS: " + doc_title + ".css");
1776
1777
  setStatus("Building CSS file");
1777
- newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
1778
+ newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
1778
1779
  woff2File: file,
1779
1780
  fileInput: newFileInput,
1780
1781
  fontName: doc_title,
@@ -1788,15 +1789,15 @@ var SingleUploaderTool = (props) => {
1788
1789
  setStatus("CSS file built successfully");
1789
1790
  }
1790
1791
  if (code === "ttf") {
1791
- const fontBuffer = await _chunkFH4QKHOHjs.readFontFile.call(void 0, file);
1792
- const font = await _chunkFH4QKHOHjs.parseFont.call(void 0, fontBuffer, file.name);
1793
- const { weightName, subfamilyName, style, variableFont } = _chunkFH4QKHOHjs.extractFontMetadata.call(void 0,
1792
+ const fontBuffer = await _chunkJCDZ7SWZjs.readFontFile.call(void 0, file);
1793
+ const font = await _chunkJCDZ7SWZjs.parseFont.call(void 0, fontBuffer, file.name);
1794
+ const { weightName, subfamilyName, style, variableFont } = _chunkJCDZ7SWZjs.extractFontMetadata.call(void 0,
1794
1795
  font,
1795
1796
  doc_typefaceName,
1796
1797
  weightKeywordList,
1797
1798
  italicKeywordList
1798
1799
  );
1799
- const weight = _chunkFH4QKHOHjs.determineWeight.call(void 0, font, weightName);
1800
+ const weight = _chunkJCDZ7SWZjs.determineWeight.call(void 0, font, weightName);
1800
1801
  const normalizedId = doc_id.startsWith("drafts.") ? doc_id.replace("drafts.", "") : doc_id;
1801
1802
  await client.patch(normalizedId).set({ weightName, subfamily: subfamilyName, style, variableFont, weight }).commit();
1802
1803
  }
@@ -2035,7 +2036,7 @@ var UploadScriptsComponent = (props) => {
2035
2036
  const stylesObject = _sanity.useFormValue.call(void 0, ["styles"]);
2036
2037
  let subfamiliesArray = (stylesObject == null ? void 0 : stylesObject.subfamilies) || [];
2037
2038
  const { weightKeywordList, italicKeywordList } = _react.useMemo.call(void 0,
2038
- () => _chunkFH4QKHOHjs.generateStyleKeywords.call(void 0, ),
2039
+ () => _chunkJCDZ7SWZjs.generateStyleKeywords.call(void 0, ),
2039
2040
  []
2040
2041
  );
2041
2042
  const readFontFile3 = (file) => {
@@ -2067,21 +2068,21 @@ var UploadScriptsComponent = (props) => {
2067
2068
  for (var i = 0; i < event.target.files.length; i++) {
2068
2069
  const file = event.target.files[i];
2069
2070
  const fontBuffer = await readFontFile3(file);
2070
- const font = await _chunkFH4QKHOHjs.parseFont.call(void 0, fontBuffer, file.name);
2071
- const fullName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 4);
2072
- const familyName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 1);
2071
+ const font = await _chunkJCDZ7SWZjs.parseFont.call(void 0, fontBuffer, file.name);
2072
+ const fullName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 4);
2073
+ const familyName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 1);
2073
2074
  console.log("Reading font:", fullName, file.name);
2074
- let weightName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 17) || _chunkFH4QKHOHjs.getNameString.call(void 0, font, 2) || "";
2075
+ let weightName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 17) || _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 2) || "";
2075
2076
  weightName = weightName.replace("Italic", "").replace("It", "").trim();
2076
2077
  if ((weightName == "" || weightName.toLowerCase() == "roman") && fullName) {
2077
2078
  weightName = fullName.replace(title + " ", "").replace(title, "").trim();
2078
2079
  weightName = weightName.replace("Italic", "").replace("It", "").trim();
2079
2080
  }
2080
- const axes = _chunkFH4QKHOHjs.getVariationAxes.call(void 0, font);
2081
+ const axes = _chunkJCDZ7SWZjs.getVariationAxes.call(void 0, font);
2081
2082
  let variableFont = axes !== null;
2082
2083
  let subfamilyName = familyName.toLowerCase().trim().replace(title.toLowerCase().trim(), "").trim();
2083
2084
  let fontTitle = fullName;
2084
- const italicAngle = _chunkFH4QKHOHjs.getItalicAngle.call(void 0, font);
2085
+ const italicAngle = _chunkJCDZ7SWZjs.getItalicAngle.call(void 0, font);
2085
2086
  let style = italicAngle !== 0 || fullName.toLowerCase().includes("italic") ? "Italic" : "Regular";
2086
2087
  if (fontTitle.toLowerCase().trim().includes(script)) {
2087
2088
  fontTitle = fontTitle.toLowerCase().trim().replace(script, "").trim();
@@ -2117,7 +2118,7 @@ var UploadScriptsComponent = (props) => {
2117
2118
  }
2118
2119
  if (variableFont && !fontTitle.toLowerCase().trim().endsWith(" vf")) fontTitle = fontTitle + " VF";
2119
2120
  if (italicKW.length > 0) {
2120
- italicKW = italicKW.map((item) => _chunkFH4QKHOHjs.reverseSpellingLookup.call(void 0, item));
2121
+ italicKW = italicKW.map((item) => _chunkJCDZ7SWZjs.reverseSpellingLookup.call(void 0, item));
2121
2122
  fontTitle = fontTitle + italicKW.join(" ");
2122
2123
  style = "Italic";
2123
2124
  }
@@ -2151,7 +2152,7 @@ var UploadScriptsComponent = (props) => {
2151
2152
  variableFont,
2152
2153
  weightName,
2153
2154
  normalWeight: true,
2154
- weight: _chunkFH4QKHOHjs.getWeightClass.call(void 0, font) || (/hairline|extra thin|extrathin/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 100 : /thin|extra light|extralight/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 200 : /light|book/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 300 : /regular|normal/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 400 : /medium/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 500 : /semi bold|semibold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 600 : /bold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 700 : /extra bold|extrabold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 800 : /black|ultra/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 900 : 400),
2155
+ weight: _chunkJCDZ7SWZjs.getWeightClass.call(void 0, font) || (/hairline|extra thin|extrathin/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 100 : /thin|extra light|extralight/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 200 : /light|book/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 300 : /regular|normal/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 400 : /medium/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 500 : /semi bold|semibold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 600 : /bold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 700 : /extra bold|extrabold/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 800 : /black|ultra/.test(weightName == null ? void 0 : weightName.toLowerCase()) ? 900 : 400),
2155
2156
  files: [file],
2156
2157
  fontKit: font,
2157
2158
  scriptFileInput: { [script]: {} }
@@ -2200,7 +2201,7 @@ var UploadScriptsComponent = (props) => {
2200
2201
  if (file.name.endsWith(".woff2")) {
2201
2202
  console.log("generating css file for: ", fontObject.title);
2202
2203
  setStatus("generating css file for: " + fontObject.title);
2203
- newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
2204
+ newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
2204
2205
  woff2File: file,
2205
2206
  fileInput: newFileInput,
2206
2207
  // script: script,
@@ -2452,7 +2453,7 @@ var FontScriptUploaderComponent = (props) => {
2452
2453
  );
2453
2454
  let blob = await fetch(woff2Buffer.url);
2454
2455
  blob = await blob.blob();
2455
- let newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
2456
+ let newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
2456
2457
  woff2File: blob,
2457
2458
  fileInput: scriptFileInput,
2458
2459
  language,
@@ -2537,7 +2538,7 @@ var FontScriptUploaderComponent = (props) => {
2537
2538
  if (code === "woff2") {
2538
2539
  console.log("woff2");
2539
2540
  setMessage({ ...message, [language]: "Generating Css: " + doc_title + ".css" });
2540
- newFileInput = await _chunkFH4QKHOHjs.generateCssFile.call(void 0, {
2541
+ newFileInput = await _chunkJCDZ7SWZjs.generateCssFile.call(void 0, {
2541
2542
  woff2File: file,
2542
2543
  fileInput: newFileInput,
2543
2544
  language,
@@ -2909,7 +2910,7 @@ function VariableInstanceReferencesInput(props) {
2909
2910
  console.warn("Cannot autofill: no variableInstances data on this document");
2910
2911
  return;
2911
2912
  }
2912
- const mappings = await _chunkFH4QKHOHjs.parseVariableFontInstances.call(void 0, formDocument, sanityClient);
2913
+ const mappings = await _chunkJCDZ7SWZjs.parseVariableFontInstances.call(void 0, formDocument, sanityClient);
2913
2914
  if (mappings.length === 0) {
2914
2915
  console.warn("No variable instances could be parsed from this font");
2915
2916
  return;
@@ -3323,12 +3324,12 @@ async function getEmptyFontKit({ title, files, weightKeywordList, italicKeywordL
3323
3324
  for (var i = 0; i < files.length; i++) {
3324
3325
  const file = files[i];
3325
3326
  const fontBuffer = await readFontFile2(file);
3326
- const font = await _chunkFH4QKHOHjs.parseFont.call(void 0, fontBuffer, file.name);
3327
- let weightName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 17) || _chunkFH4QKHOHjs.getNameString.call(void 0, font, 2) || "";
3328
- const axes = _chunkFH4QKHOHjs.getVariationAxes.call(void 0, font);
3327
+ const font = await _chunkJCDZ7SWZjs.parseFont.call(void 0, fontBuffer, file.name);
3328
+ let weightName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 17) || _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 2) || "";
3329
+ const axes = _chunkJCDZ7SWZjs.getVariationAxes.call(void 0, font);
3329
3330
  let variableFont = axes !== null;
3330
- const familyName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 1);
3331
- const fullName = _chunkFH4QKHOHjs.getNameString.call(void 0, font, 4);
3331
+ const familyName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 1);
3332
+ const fullName = _chunkJCDZ7SWZjs.getNameString.call(void 0, font, 4);
3332
3333
  let subfamilyName = familyName.toLowerCase().trim().replace(title.toLowerCase().trim(), "").trim();
3333
3334
  let fontTitle = fullName.toLowerCase().trim();
3334
3335
  weightKeywordList.forEach((keyword) => {
@@ -6173,4 +6174,5 @@ function createStylesField({
6173
6174
 
6174
6175
 
6175
6176
 
6176
- exports.BatchUploadFonts = BatchUploadFonts; exports.BulkActions = _chunkFH4QKHOHjs.BulkActions; exports.DISCOUNT_REQUIREMENT_TYPES = DISCOUNT_REQUIREMENT_TYPES; exports.DISCOUNT_REQUIREMENT_TYPES_OBJECT = DISCOUNT_REQUIREMENT_TYPES_OBJECT; exports.EXECUTION_STATUS = _chunkFH4QKHOHjs.EXECUTION_STATUS; exports.ExistingDocumentResolver = _chunkFH4QKHOHjs.ExistingDocumentResolver; exports.FONT_STATUS = _chunkFH4QKHOHjs.FONT_STATUS; exports.FontReviewCard = _chunkFH4QKHOHjs.FontReviewCard_default; exports.FontScriptUploaderComponent = FontScriptUploaderComponent; exports.GenerateCollectionsPairsComponent = GenerateCollectionsPairsComponent; exports.HtmlDescription = HtmlDescription; exports.KeyValueInput = KeyValueInput; exports.KeyValueReferenceInput = KeyValueReferenceInput; exports.NestedObjectArraySelector = NestedObjectArraySelector; exports.PLAN_PHASE = _chunkFH4QKHOHjs.PLAN_PHASE; exports.PLAN_VERSION = _chunkFH4QKHOHjs.PLAN_VERSION; exports.PriceInput = _chunkFH4QKHOHjs.PriceInput_default; exports.PrimaryCollectionGeneratorTypeface = PrimaryCollectionGeneratorTypeface; exports.RECOMMENDATION = _chunkFH4QKHOHjs.RECOMMENDATION; exports.RegenerateSubfamiliesComponent = RegenerateSubfamiliesComponent; exports.SCRIPTS = SCRIPTS; exports.SCRIPTS_OBJECT = SCRIPTS_OBJECT; exports.SetOTF = SetOTF; exports.SingleUploaderTool = SingleUploaderTool; exports.StatusDisplay = StatusDisplay_default; exports.StyleCountInput = StyleCountInput; exports.UpdateScriptsComponent = UpdateScriptsComponent; exports.UploadButton = UploadButton_default; exports.UploadModal = _chunkFH4QKHOHjs.UploadModal; exports.UploadScriptsComponent = UploadScriptsComponent; exports.UploadStep1Settings = _chunkFH4QKHOHjs.UploadStep1Settings; exports.UploadStep2Review = _chunkFH4QKHOHjs.UploadStep2Review; exports.UploadStep3Execute = _chunkFH4QKHOHjs.UploadStep3Execute; exports.UploadSummary = _chunkFH4QKHOHjs.UploadSummary; exports.VariableInstanceReferencesInput = VariableInstanceReferencesInput; exports.addItalicToFontTitle = _chunkFH4QKHOHjs.addItalicToFontTitle; exports.buildUploadPlan = _chunkFH4QKHOHjs.buildUploadPlan; exports.createEmptyPlan = _chunkFH4QKHOHjs.createEmptyPlan; exports.createFontDecisions = _chunkFH4QKHOHjs.createFontDecisions; exports.createFontObject = _chunkFH4QKHOHjs.createFontObject; exports.createInitialExecutionState = _chunkFH4QKHOHjs.createInitialExecutionState; exports.createStylesField = createStylesField; exports.determineWeight = _chunkFH4QKHOHjs.determineWeight; exports.escapeCssFontName = _chunkFH4QKHOHjs.escapeCssFontName; exports.executeUploadPlan = _chunkFH4QKHOHjs.executeUploadPlan; exports.executionReducer = _chunkFH4QKHOHjs.executionReducer; exports.expandAbbreviations = _chunkFH4QKHOHjs.expandAbbreviations; exports.extractFontMetadata = _chunkFH4QKHOHjs.extractFontMetadata; exports.extractWeightFromFullName = _chunkFH4QKHOHjs.extractWeightFromFullName; exports.extractWeightName = _chunkFH4QKHOHjs.extractWeightName; exports.formatFontTitle = _chunkFH4QKHOHjs.formatFontTitle; exports.generateCssFile = _chunkFH4QKHOHjs.generateCssFile; exports.generateFontData = _chunkFH4QKHOHjs.generateFontData; exports.generateFontFile = generateFontFile; exports.generateStyleKeywords = _chunkFH4QKHOHjs.generateStyleKeywords; exports.generateSubset = generateSubset; exports.getAllFeatureTags = _chunkFH4QKHOHjs.getAllFeatureTags; exports.getCharacterSet = _chunkFH4QKHOHjs.getCharacterSet; exports.getEmptyFontKit = getEmptyFontKit; exports.getFamilyClass = _chunkFH4QKHOHjs.getFamilyClass; exports.getFontMetadata = _chunkFH4QKHOHjs.getFontMetadata; exports.getFontMetrics = _chunkFH4QKHOHjs.getFontMetrics; exports.getFsSelection = _chunkFH4QKHOHjs.getFsSelection; exports.getGlyphCount = _chunkFH4QKHOHjs.getGlyphCount; exports.getItalicAngle = _chunkFH4QKHOHjs.getItalicAngle; exports.getMacStyle = _chunkFH4QKHOHjs.getMacStyle; exports.getNameString = _chunkFH4QKHOHjs.getNameString; exports.getNamedInstances = _chunkFH4QKHOHjs.getNamedInstances; exports.getVariationAxes = _chunkFH4QKHOHjs.getVariationAxes; exports.getWeightClass = _chunkFH4QKHOHjs.getWeightClass; exports.logFontInfo = _chunkFH4QKHOHjs.logFontInfo; exports.openTypeField = openTypeField; exports.parseFont = _chunkFH4QKHOHjs.parseFont; exports.parseVariableFontInstances = _chunkFH4QKHOHjs.parseVariableFontInstances_default; exports.planReducer = _chunkFH4QKHOHjs.planReducer; exports.processFontFiles = _chunkFH4QKHOHjs.processFontFiles; exports.processItalicKeywords = _chunkFH4QKHOHjs.processItalicKeywords; exports.processSubfamilyName = _chunkFH4QKHOHjs.processSubfamilyName; exports.readFontFile = _chunkFH4QKHOHjs.readFontFile; exports.removeWeightNames = _chunkFH4QKHOHjs.removeWeightNames; exports.renameFontDocuments = renameFontDocuments; exports.resolveExistingFont = _chunkFH4QKHOHjs.resolveExistingFont; exports.reverseSpellingLookup = _chunkFH4QKHOHjs.reverseSpellingLookup; exports.sanitizeForSanityId = _chunkFH4QKHOHjs.sanitizeForSanityId; exports.sortFontObjects = _chunkFH4QKHOHjs.sortFontObjects; exports.styleCountField = styleCountField; exports.stylisticSetField = stylisticSetField; exports.updateFontPrices = updateFontPrices; exports.updateTypefaceDocument = _chunkFH4QKHOHjs.updateTypefaceDocument; exports.uploadFontFiles = uploadFontFiles; exports.useNestedObjects = useNestedObjects; exports.useSanityClient = useSanityClient;
6177
+
6178
+ exports.BatchUploadFonts = BatchUploadFonts; exports.BulkActions = _chunkJCDZ7SWZjs.BulkActions; exports.DISCOUNT_REQUIREMENT_TYPES = DISCOUNT_REQUIREMENT_TYPES; exports.DISCOUNT_REQUIREMENT_TYPES_OBJECT = DISCOUNT_REQUIREMENT_TYPES_OBJECT; exports.EXECUTION_STATUS = _chunkJCDZ7SWZjs.EXECUTION_STATUS; exports.ExistingDocumentResolver = _chunkJCDZ7SWZjs.ExistingDocumentResolver; exports.FONT_STATUS = _chunkJCDZ7SWZjs.FONT_STATUS; exports.FontReviewCard = _chunkJCDZ7SWZjs.FontReviewCard_default; exports.FontScriptUploaderComponent = FontScriptUploaderComponent; exports.GenerateCollectionsPairsComponent = GenerateCollectionsPairsComponent; exports.HtmlDescription = HtmlDescription; exports.KeyValueInput = KeyValueInput; exports.KeyValueReferenceInput = KeyValueReferenceInput; exports.NestedObjectArraySelector = NestedObjectArraySelector; exports.PLAN_PHASE = _chunkJCDZ7SWZjs.PLAN_PHASE; exports.PLAN_VERSION = _chunkJCDZ7SWZjs.PLAN_VERSION; exports.PriceInput = _chunkJCDZ7SWZjs.PriceInput_default; exports.PrimaryCollectionGeneratorTypeface = PrimaryCollectionGeneratorTypeface; exports.RECOMMENDATION = _chunkJCDZ7SWZjs.RECOMMENDATION; exports.RegenerateSubfamiliesComponent = RegenerateSubfamiliesComponent; exports.SCRIPTS = SCRIPTS; exports.SCRIPTS_OBJECT = SCRIPTS_OBJECT; exports.SetOTF = SetOTF; exports.SingleUploaderTool = SingleUploaderTool; exports.StatusDisplay = StatusDisplay_default; exports.StyleCountInput = StyleCountInput; exports.UpdateScriptsComponent = UpdateScriptsComponent; exports.UploadButton = UploadButton_default; exports.UploadModal = _chunkJCDZ7SWZjs.UploadModal; exports.UploadScriptsComponent = UploadScriptsComponent; exports.UploadStep1Settings = _chunkJCDZ7SWZjs.UploadStep1Settings; exports.UploadStep2Review = _chunkJCDZ7SWZjs.UploadStep2Review; exports.UploadStep3Execute = _chunkJCDZ7SWZjs.UploadStep3Execute; exports.UploadStep3bInstances = _chunkJCDZ7SWZjs.UploadStep3bInstances; exports.UploadSummary = _chunkJCDZ7SWZjs.UploadSummary; exports.VariableInstanceReferencesInput = VariableInstanceReferencesInput; exports.addItalicToFontTitle = _chunkJCDZ7SWZjs.addItalicToFontTitle; exports.buildUploadPlan = _chunkJCDZ7SWZjs.buildUploadPlan; exports.createEmptyPlan = _chunkJCDZ7SWZjs.createEmptyPlan; exports.createFontDecisions = _chunkJCDZ7SWZjs.createFontDecisions; exports.createFontObject = _chunkJCDZ7SWZjs.createFontObject; exports.createInitialExecutionState = _chunkJCDZ7SWZjs.createInitialExecutionState; exports.createStylesField = createStylesField; exports.determineWeight = _chunkJCDZ7SWZjs.determineWeight; exports.escapeCssFontName = _chunkJCDZ7SWZjs.escapeCssFontName; exports.executeUploadPlan = _chunkJCDZ7SWZjs.executeUploadPlan; exports.executionReducer = _chunkJCDZ7SWZjs.executionReducer; exports.expandAbbreviations = _chunkJCDZ7SWZjs.expandAbbreviations; exports.extractFontMetadata = _chunkJCDZ7SWZjs.extractFontMetadata; exports.extractWeightFromFullName = _chunkJCDZ7SWZjs.extractWeightFromFullName; exports.extractWeightName = _chunkJCDZ7SWZjs.extractWeightName; exports.formatFontTitle = _chunkJCDZ7SWZjs.formatFontTitle; exports.generateCssFile = _chunkJCDZ7SWZjs.generateCssFile; exports.generateFontData = _chunkJCDZ7SWZjs.generateFontData; exports.generateFontFile = generateFontFile; exports.generateStyleKeywords = _chunkJCDZ7SWZjs.generateStyleKeywords; exports.generateSubset = generateSubset; exports.getAllFeatureTags = _chunkJCDZ7SWZjs.getAllFeatureTags; exports.getCharacterSet = _chunkJCDZ7SWZjs.getCharacterSet; exports.getEmptyFontKit = getEmptyFontKit; exports.getFamilyClass = _chunkJCDZ7SWZjs.getFamilyClass; exports.getFontMetadata = _chunkJCDZ7SWZjs.getFontMetadata; exports.getFontMetrics = _chunkJCDZ7SWZjs.getFontMetrics; exports.getFsSelection = _chunkJCDZ7SWZjs.getFsSelection; exports.getGlyphCount = _chunkJCDZ7SWZjs.getGlyphCount; exports.getItalicAngle = _chunkJCDZ7SWZjs.getItalicAngle; exports.getMacStyle = _chunkJCDZ7SWZjs.getMacStyle; exports.getNameString = _chunkJCDZ7SWZjs.getNameString; exports.getNamedInstances = _chunkJCDZ7SWZjs.getNamedInstances; exports.getVariationAxes = _chunkJCDZ7SWZjs.getVariationAxes; exports.getWeightClass = _chunkJCDZ7SWZjs.getWeightClass; exports.logFontInfo = _chunkJCDZ7SWZjs.logFontInfo; exports.openTypeField = openTypeField; exports.parseFont = _chunkJCDZ7SWZjs.parseFont; exports.parseVariableFontInstances = _chunkJCDZ7SWZjs.parseVariableFontInstances_default; exports.planReducer = _chunkJCDZ7SWZjs.planReducer; exports.processFontFiles = _chunkJCDZ7SWZjs.processFontFiles; exports.processItalicKeywords = _chunkJCDZ7SWZjs.processItalicKeywords; exports.processSubfamilyName = _chunkJCDZ7SWZjs.processSubfamilyName; exports.readFontFile = _chunkJCDZ7SWZjs.readFontFile; exports.removeWeightNames = _chunkJCDZ7SWZjs.removeWeightNames; exports.renameFontDocuments = renameFontDocuments; exports.resolveExistingFont = _chunkJCDZ7SWZjs.resolveExistingFont; exports.reverseSpellingLookup = _chunkJCDZ7SWZjs.reverseSpellingLookup; exports.sanitizeForSanityId = _chunkJCDZ7SWZjs.sanitizeForSanityId; exports.sortFontObjects = _chunkJCDZ7SWZjs.sortFontObjects; exports.styleCountField = styleCountField; exports.stylisticSetField = stylisticSetField; exports.updateFontPrices = updateFontPrices; exports.updateTypefaceDocument = _chunkJCDZ7SWZjs.updateTypefaceDocument; exports.uploadFontFiles = uploadFontFiles; exports.useNestedObjects = useNestedObjects; exports.useSanityClient = useSanityClient;
package/dist/index.mjs CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  UploadStep1Settings,
13
13
  UploadStep2Review,
14
14
  UploadStep3Execute,
15
+ UploadStep3bInstances,
15
16
  UploadSummary,
16
17
  addItalicToFontTitle,
17
18
  buildUploadPlan,
@@ -59,7 +60,7 @@ import {
59
60
  sanitizeForSanityId,
60
61
  sortFontObjects,
61
62
  updateTypefaceDocument
62
- } from "./chunk-646WCBRR.mjs";
63
+ } from "./chunk-TMDE4A54.mjs";
63
64
 
64
65
  // src/components/BatchUploadFonts.jsx
65
66
  import React3, { useCallback, useState as useState2, useMemo as useMemo2, useRef, useEffect, lazy, Suspense } from "react";
@@ -635,7 +636,7 @@ var updateTypefaceSubfamilies = async (doc_id, stylesObject, newSubfamiliesArray
635
636
  };
636
637
 
637
638
  // src/components/BatchUploadFonts.jsx
638
- var UploadModal2 = lazy(() => import("./UploadModal-NME2W53V.mjs"));
639
+ var UploadModal2 = lazy(() => import("./UploadModal-ADNRGQUI.mjs"));
639
640
  var ACCEPTED_EXTENSIONS = ["ttf", "otf", "woff", "woff2", "eot", "svg"];
640
641
  var formatElapsed = (s) => {
641
642
  const m = Math.floor(s / 60);
@@ -6114,6 +6115,7 @@ export {
6114
6115
  UploadStep1Settings,
6115
6116
  UploadStep2Review,
6116
6117
  UploadStep3Execute,
6118
+ UploadStep3bInstances,
6117
6119
  UploadSummary,
6118
6120
  VariableInstanceReferencesInput,
6119
6121
  addItalicToFontTitle,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liiift-studio/sanity-font-manager",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "Sanity Studio plugin — full font management suite with batch upload, format conversion, metadata extraction, CSS generation, collection/pair generation, and script variant support. Supports Sanity v3, v4, and v5.",
5
5
  "license": "MIT",
6
6
  "author": "Liiift Studio",
@@ -15,9 +15,10 @@ const EXTENDED_TYPES = ['eot', 'svg', 'css', 'woff2_subset', 'woff2_web'];
15
15
  * Collapsible review card for a single font in the upload plan.
16
16
  * Table-style header row with weight/style/files/action columns.
17
17
  */
18
- const FontReviewCard = memo(function FontReviewCard({ entry, dispatch, allExpanded }) {
18
+ const FontReviewCard = memo(function FontReviewCard({ entry, dispatch, allExpanded, typefaceTitle, price }) {
19
19
  const [expanded, setExpanded] = useState(false);
20
20
  const [showAllFileTypes, setShowAllFileTypes] = useState(false);
21
+ const [showDocPreview, setShowDocPreview] = useState(false);
21
22
 
22
23
  // Sync with allExpanded toggle from BulkActions
23
24
  useEffect(() => {
@@ -382,6 +383,45 @@ const FontReviewCard = memo(function FontReviewCard({ entry, dispatch, allExpand
382
383
  dispatch={dispatch}
383
384
  />
384
385
 
386
+ {/* Document Preview — expandable view of all fields that will be written */}
387
+ <Stack space={2}>
388
+ <Button
389
+ mode="bleed"
390
+ fontSize={0}
391
+ padding={1}
392
+ text={showDocPreview ? 'Hide document preview' : 'Show document preview'}
393
+ onClick={() => setShowDocPreview(v => !v)}
394
+ style={{ cursor: 'pointer', alignSelf: 'flex-start' }}
395
+ />
396
+ {showDocPreview && (
397
+ <Card border padding={3} radius={1} style={{ fontFamily: 'monospace', fontSize: 12 }}>
398
+ <Stack space={2}>
399
+ {[
400
+ ['_id', entry.documentId],
401
+ ['_type', 'font'],
402
+ ['title', entry.title],
403
+ ['slug', entry.documentId],
404
+ ['typefaceName', typefaceTitle || '—'],
405
+ ['weightName', entry.weightName || '—'],
406
+ ['weight', entry.weight],
407
+ ['style', entry.style],
408
+ ['subfamily', entry.subfamily || '—'],
409
+ ['variableFont', String(entry.variableFont)],
410
+ ['price', price ?? '—'],
411
+ ['sell', price > 0 ? 'true' : 'false'],
412
+ ['normalWeight', 'true'],
413
+ ['files', (entry.files || []).map(f => f.name).join(', ') || '—'],
414
+ ].map(([key, value]) => (
415
+ <Flex key={key} gap={2}>
416
+ <Text size={0} muted style={{ width: 120, flexShrink: 0 }}>{key}</Text>
417
+ <Text size={0} style={{ wordBreak: 'break-all' }}>{String(value)}</Text>
418
+ </Flex>
419
+ ))}
420
+ </Stack>
421
+ </Card>
422
+ )}
423
+ </Stack>
424
+
385
425
  {/* Actions — only show reset if user has overridden suggestions */}
386
426
  <Flex justify="flex-end" gap={2}>
387
427
  {hasUserOverrides && (
@@ -1,4 +1,4 @@
1
- // Upload modal — 3-step state machine: Settings → Review → Execute
1
+ // Upload modal — multi-step state machine: Upload Files → Review → Execute → Map Instances → Summary
2
2
 
3
3
  import React, { useReducer, useCallback, useState, useMemo, useRef, useEffect } from 'react';
4
4
  import { Dialog, Box, Flex, Text, Badge, Button } from '@sanity/ui';
@@ -9,6 +9,7 @@ import { generateStyleKeywords } from '../utils/generateKeywords';
9
9
  import UploadStep1Settings from './UploadStep1Settings';
10
10
  import UploadStep2Review from './UploadStep2Review';
11
11
  import UploadStep3Execute from './UploadStep3Execute';
12
+ import UploadStep3bInstances from './UploadStep3bInstances';
12
13
  import UploadSummary from './UploadSummary';
13
14
 
14
15
  /** Step labels for the step indicator */
@@ -16,6 +17,7 @@ const STEPS = [
16
17
  { key: 1, label: 'Upload Files' },
17
18
  { key: 2, label: 'Review' },
18
19
  { key: 3, label: 'Upload' },
20
+ { key: 4, label: 'Map Instances' },
19
21
  ];
20
22
 
21
23
  /** Maps plan phase to active step number */
@@ -49,11 +51,19 @@ export default function UploadModal({
49
51
  const [processingCancelled, setProcessingCancelled] = useState(false);
50
52
  const [executionResult, setExecutionResult] = useState(null);
51
53
  const [retryTempIds, setRetryTempIds] = useState(null);
54
+ const [instanceMappingPhase, setInstanceMappingPhase] = useState(false);
55
+ const [instanceMappingResult, setInstanceMappingResult] = useState(null);
52
56
  const cancelRef = useRef(false);
53
57
  const focusRef = useRef(null);
54
58
 
55
59
  const { weightKeywordList, italicKeywordList } = useMemo(() => generateStyleKeywords(), []);
56
- const currentStep = phaseToStep(plan.phase);
60
+ const hasVFs = useMemo(() =>
61
+ Object.values(plan.fonts).some(f => f.variableFont && f.status !== 'error'),
62
+ [plan.fonts]
63
+ );
64
+ const baseStep = phaseToStep(plan.phase);
65
+ // Instance mapping is step 4 — only shown after execution completes with VFs
66
+ const currentStep = instanceMappingPhase ? 4 : (plan.phase === PLAN_PHASE.COMPLETE && !instanceMappingResult ? baseStep : baseStep);
57
67
  const isExecuting = plan.phase === PLAN_PHASE.EXECUTING;
58
68
 
59
69
  // Prevent accidental close during upload
@@ -85,7 +95,7 @@ export default function UploadModal({
85
95
 
86
96
  /** Start processing — transition to Step 2 and build the plan */
87
97
  const handleStartProcessing = useCallback(async (files, settings) => {
88
- dispatch({ type: 'SET_SETTINGS', settings });
98
+ dispatch({ type: 'SET_SETTINGS', settings: { ...settings, typefaceTitle } });
89
99
  dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.PROCESSING, totalFiles: files.length });
90
100
  cancelRef.current = false;
91
101
  setProcessingCancelled(false);
@@ -135,10 +145,22 @@ export default function UploadModal({
135
145
  dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.EXECUTING });
136
146
  }, []);
137
147
 
138
- /** Receive execution result and mark complete */
148
+ /** Receive execution result transition to instance mapping if VFs exist, otherwise complete */
139
149
  const handleExecutionComplete = useCallback((result) => {
140
150
  setExecutionResult(result);
141
- dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.COMPLETE });
151
+ if (hasVFs && result.success !== false) {
152
+ // Show instance mapping step before summary
153
+ setInstanceMappingPhase(true);
154
+ dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.COMPLETE });
155
+ } else {
156
+ dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.COMPLETE });
157
+ }
158
+ }, [hasVFs]);
159
+
160
+ /** Handle instance mapping completion */
161
+ const handleInstanceMappingComplete = useCallback((result) => {
162
+ setInstanceMappingResult(result);
163
+ setInstanceMappingPhase(false);
142
164
  }, []);
143
165
 
144
166
  if (!open) return null;
@@ -163,7 +185,7 @@ export default function UploadModal({
163
185
  <Flex direction="column" gap={3} style={{ width: '100%' }}>
164
186
  <Text weight="semibold" size={2}>Upload Fonts</Text>
165
187
  <Flex gap={1} style={{ width: '100%' }}>
166
- {STEPS.map((step, i) => {
188
+ {STEPS.filter(step => step.key !== 4 || hasVFs).map((step, i) => {
167
189
  const isActive = currentStep === step.key;
168
190
  const isCompleted = currentStep > step.key;
169
191
  const isClickable = !isExecuting && step.key < currentStep;
@@ -245,15 +267,29 @@ export default function UploadModal({
245
267
  />
246
268
  )}
247
269
 
270
+ {/* Step 4: Variable Font Instance Mapping (only if VFs in batch) */}
271
+ {plan.phase === PLAN_PHASE.COMPLETE && instanceMappingPhase && (
272
+ <UploadStep3bInstances
273
+ plan={plan}
274
+ executionResult={executionResult}
275
+ client={client}
276
+ typefaceTitle={typefaceTitle}
277
+ onComplete={handleInstanceMappingComplete}
278
+ />
279
+ )}
280
+
248
281
  {/* Post-completion Summary */}
249
- {plan.phase === PLAN_PHASE.COMPLETE && (
282
+ {plan.phase === PLAN_PHASE.COMPLETE && !instanceMappingPhase && (
250
283
  <UploadSummary
251
284
  plan={plan}
252
285
  result={executionResult}
286
+ instanceMappingResult={instanceMappingResult}
253
287
  onClose={handleClose}
254
288
  onRetry={(failedTempIds) => {
255
289
  setRetryTempIds(failedTempIds || null);
256
290
  setExecutionResult(null);
291
+ setInstanceMappingPhase(false);
292
+ setInstanceMappingResult(null);
257
293
  dispatch({ type: 'SET_PHASE', phase: PLAN_PHASE.EXECUTING });
258
294
  }}
259
295
  client={client}
@@ -431,6 +431,8 @@ export default function UploadStep2Review({
431
431
  entry={entry}
432
432
  dispatch={dispatch}
433
433
  allExpanded={allExpanded}
434
+ typefaceTitle={plan.settings?.typefaceTitle}
435
+ price={plan.settings?.price}
434
436
  />
435
437
  ))}
436
438
  </Stack>