@liiift-studio/sanity-font-manager 2.3.19 → 2.4.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 (42) hide show
  1. package/README.md +437 -437
  2. package/dist/index.js +103 -48
  3. package/dist/index.mjs +103 -48
  4. package/package.json +85 -85
  5. package/src/components/BatchUploadFonts.jsx +640 -639
  6. package/src/components/FontScriptUploaderComponent.jsx +463 -463
  7. package/src/components/GenerateCollectionsPairsComponent.jsx +259 -259
  8. package/src/components/KeyValueInput.jsx +95 -95
  9. package/src/components/KeyValueReferenceInput.jsx +254 -254
  10. package/src/components/NestedObjectArraySelector.jsx +146 -146
  11. package/src/components/PriceInput.jsx +26 -26
  12. package/src/components/PrimaryCollectionGeneratorTypeface.jsx +116 -116
  13. package/src/components/RegenerateSubfamiliesComponent.jsx +185 -185
  14. package/src/components/SetOTF.jsx +87 -87
  15. package/src/components/SingleUploaderTool.jsx +673 -673
  16. package/src/components/StatusDisplay.jsx +26 -26
  17. package/src/components/StyleCountInput.jsx +16 -16
  18. package/src/components/UpdateScriptsComponent.jsx +76 -76
  19. package/src/components/UploadButton.jsx +43 -43
  20. package/src/components/UploadScriptsComponent.jsx +537 -537
  21. package/src/components/VariableInstanceReferencesInput.jsx +190 -190
  22. package/src/hooks/useNestedObjects.js +92 -92
  23. package/src/hooks/useSanityClient.js +9 -9
  24. package/src/index.js +70 -70
  25. package/src/schema/openTypeField.js +1945 -1945
  26. package/src/schema/styleCountField.js +12 -12
  27. package/src/schema/stylesField.js +268 -268
  28. package/src/schema/stylisticSetField.js +301 -301
  29. package/src/utils/generateCssFile.js +205 -205
  30. package/src/utils/generateFontData.js +145 -145
  31. package/src/utils/generateFontFile.js +38 -38
  32. package/src/utils/generateKeywords.js +185 -185
  33. package/src/utils/generateSubset.js +45 -45
  34. package/src/utils/getEmptyFontKit.js +99 -99
  35. package/src/utils/parseVariableFontInstances.js +211 -211
  36. package/src/utils/processFontFiles.js +487 -477
  37. package/src/utils/regenerateFontData.js +146 -146
  38. package/src/utils/sanitizeForSanityId.js +65 -65
  39. package/src/utils/updateFontPrices.js +94 -94
  40. package/src/utils/updateTypefaceDocument.js +149 -160
  41. package/src/utils/uploadFontFiles.js +115 -26
  42. package/src/utils/utils.js +24 -24
package/dist/index.js CHANGED
@@ -321,17 +321,22 @@ var processFontFiles = async (files, title, weightKeywordList, italicKeywordList
321
321
  if (file.name.endsWith(".woff2") || file.name.endsWith(".woff")) {
322
322
  await handleWebfontMetadata(file, font, files);
323
323
  }
324
- const { weightName, subfamilyName, fontTitle, style, italicKW, variableFont } = extractFontMetadata(
324
+ let { weightName, subfamilyName, fontTitle, style, italicKW, variableFont } = extractFontMetadata(
325
325
  font,
326
326
  title,
327
327
  weightKeywordList,
328
328
  italicKeywordList,
329
329
  preserveShortenedNames
330
330
  );
331
- const id = sanitizeForSanityId(fontTitle);
331
+ let id;
332
332
  let originalFilename = null;
333
333
  if (preserveFileNames) {
334
334
  originalFilename = file.name.replace(/\.(ttf|otf|woff2?|eot|svg)$/i, "");
335
+ const normalizedName = originalFilename.replace(/-/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").trim();
336
+ fontTitle = normalizedName;
337
+ id = sanitizeForSanityId(normalizedName);
338
+ } else {
339
+ id = sanitizeForSanityId(fontTitle);
335
340
  }
336
341
  logFontInfo(id, fontTitle, font, file.name, subfamilyName, style, weightName, variableFont, italicKW);
337
342
  subfamilies[id] = subfamilyName;
@@ -999,7 +1004,7 @@ var parseVariableFontInstances = async (font, client) => {
999
1004
  var parseVariableFontInstances_default = parseVariableFontInstances;
1000
1005
 
1001
1006
  // src/utils/uploadFontFiles.js
1002
- var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, stylesObject, setStatus, setError) => {
1007
+ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, stylesObject, setStatus, setError, preserveFileNames = false) => {
1003
1008
  let fontRefs = [];
1004
1009
  let variableRefs = [];
1005
1010
  let failedFiles = [];
@@ -1016,10 +1021,18 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
1016
1021
  for (let j = 0; j < files.length; j++) {
1017
1022
  const file = files[j];
1018
1023
  const fileType = determineFileType(file);
1019
- console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${fontObject._id}.${fileType}`);
1020
- setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${fontObject._id}.${fileType}`);
1024
+ const assetFilename = preserveFileNames && fontObject.originalFilename ? `${fontObject.originalFilename}.${fileType}` : `${fontObject._id}.${fileType}`;
1025
+ console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${assetFilename}`);
1026
+ setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${assetFilename}`);
1021
1027
  try {
1022
- const baseAsset = await client.assets.upload("file", file, { filename: fontObject._id + "." + fileType });
1028
+ const baseAsset = await client.assets.upload("file", file, { filename: assetFilename });
1029
+ if (preserveFileNames && baseAsset.originalFilename !== assetFilename) {
1030
+ try {
1031
+ await client.patch(baseAsset._id).set({ originalFilename: assetFilename }).commit();
1032
+ } catch (renameErr) {
1033
+ console.warn("Could not rename asset \u2014 permissions may be restricted:", renameErr.message);
1034
+ }
1035
+ }
1023
1036
  newFileInput[fileType] = {
1024
1037
  _type: "file",
1025
1038
  asset: { _ref: baseAsset._id, _type: "reference" }
@@ -1051,7 +1064,7 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
1051
1064
  Object.assign(fontObject, metadata);
1052
1065
  }
1053
1066
  } catch (err) {
1054
- console.error("Error uploading font: ", fontObject.title, err.message);
1067
+ console.error("Error uploading font:", fontObject.title, err.message);
1055
1068
  setStatus("Error uploading font: " + err.message);
1056
1069
  setError(true);
1057
1070
  failedFiles.push({ name: file.name, fk: fontKit });
@@ -1087,22 +1100,68 @@ var determineFileType = (file) => {
1087
1100
  if (file.name.endsWith(".svg")) return "svg";
1088
1101
  return "";
1089
1102
  };
1090
- var createOrUpdateFontDocument = async (font, client, setError) => {
1103
+ var resolveExistingFont = async (font, client) => {
1104
+ const result = { exact: null, candidates: [], recommendation: "create" };
1091
1105
  try {
1092
- const existingFont = await client.fetch(
1093
- `*[_type == 'font' && _id == $fontId]{
1094
- fileInput,
1095
- description,
1096
- metaData,
1097
- metrics,
1098
- opentypeFeatures,
1099
- characterSet,
1100
- subfamily,
1101
- scriptFileInput,
1102
- variableInstanceReferences
1106
+ const idMatches = await client.fetch(
1107
+ `*[_type == 'font' && (_id == $id || _id == $draftId || slug.current == $id)]{
1108
+ _id, title, weight, style, weightName, typefaceName, subfamily, variableFont,
1109
+ fileInput, description, metaData, metrics, opentypeFeatures, characterSet,
1110
+ scriptFileInput, variableInstanceReferences
1111
+ }`,
1112
+ { id: font._id, draftId: `drafts.${font._id}` }
1113
+ );
1114
+ if (idMatches.length > 0) {
1115
+ result.exact = idMatches[0];
1116
+ result.recommendation = "use-exact";
1117
+ return result;
1118
+ }
1119
+ const subfamily = font.subfamily || "";
1120
+ const contentMatches = await client.fetch(
1121
+ `*[_type == 'font'
1122
+ && lower(typefaceName) == lower($typefaceName)
1123
+ && lower(weightName) == lower($weightName)
1124
+ && lower(style) == lower($style)
1125
+ && (variableFont == $variableFont || (!defined(variableFont) && $variableFont == false))
1126
+ && (
1127
+ lower(coalesce(subfamily, '')) == lower($subfamily)
1128
+ || (lower(coalesce(subfamily, '')) in ['', 'regular'] && lower($subfamily) in ['', 'regular'])
1129
+ )
1130
+ ]{
1131
+ _id, title, weight, style, weightName, typefaceName, subfamily, variableFont,
1132
+ fileInput, description, metaData, metrics, opentypeFeatures, characterSet,
1133
+ scriptFileInput, variableInstanceReferences
1103
1134
  }`,
1104
- { fontId: font._id }
1105
- ).then((res) => res[0]);
1135
+ {
1136
+ typefaceName: font.typefaceName,
1137
+ weightName: font.weightName || "",
1138
+ style: font.style || "Regular",
1139
+ variableFont: font.variableFont || false,
1140
+ subfamily: subfamily === "" ? "regular" : subfamily
1141
+ }
1142
+ );
1143
+ if (contentMatches.length === 1) {
1144
+ result.candidates = contentMatches;
1145
+ result.recommendation = "use-candidate";
1146
+ return result;
1147
+ }
1148
+ if (contentMatches.length > 1) {
1149
+ result.candidates = contentMatches;
1150
+ result.recommendation = "ambiguous";
1151
+ console.warn(
1152
+ `Ambiguous font match for "${font.title}" \u2014 ${contentMatches.length} candidates found:`,
1153
+ contentMatches.map((c) => c._id)
1154
+ );
1155
+ return result;
1156
+ }
1157
+ } catch (err) {
1158
+ console.error("Error resolving existing font:", font._id, err.message);
1159
+ }
1160
+ return result;
1161
+ };
1162
+ var createOrUpdateFontDocument = async (font, client, setError) => {
1163
+ try {
1164
+ const { exact, candidates, recommendation } = await resolveExistingFont(font, client);
1106
1165
  const { files, fontKit } = font;
1107
1166
  delete font.files;
1108
1167
  delete font.fontKit;
@@ -1114,8 +1173,12 @@ var createOrUpdateFontDocument = async (font, client, setError) => {
1114
1173
  }
1115
1174
  }
1116
1175
  let fontResponse;
1117
- if (existingFont) {
1118
- fontResponse = await updateExistingFont(font, existingFont, client);
1176
+ if (recommendation === "use-exact" && exact) {
1177
+ fontResponse = await updateExistingFont(font, exact, client);
1178
+ } else if (recommendation === "use-candidate" && candidates.length === 1) {
1179
+ console.log(`Content-match: reassigning "${font._id}" \u2192 "${candidates[0]._id}"`);
1180
+ font._id = candidates[0]._id;
1181
+ fontResponse = await updateExistingFont(font, candidates[0], client);
1119
1182
  } else {
1120
1183
  fontResponse = await createNewFont(font, client);
1121
1184
  }
@@ -1126,7 +1189,7 @@ var createOrUpdateFontDocument = async (font, client, setError) => {
1126
1189
  _weak: true
1127
1190
  };
1128
1191
  } catch (e) {
1129
- console.error("Error creating font: ", font.title, font.subfamily, e);
1192
+ console.error("Error creating font:", font.title, font.subfamily, e);
1130
1193
  setError(true);
1131
1194
  return null;
1132
1195
  }
@@ -1148,7 +1211,7 @@ var updateExistingFont = async (font, existingFont, client) => {
1148
1211
  if (font.variableFont && (existingFont == null ? void 0 : existingFont.variableInstanceReferences) && (!font.variableInstanceReferences || font.variableInstanceReferences.length === 0)) {
1149
1212
  font.variableInstanceReferences = existingFont.variableInstanceReferences;
1150
1213
  }
1151
- console.log("Updating existing font: ", font._id, font.title);
1214
+ console.log("Updating existing font:", font._id, font.title);
1152
1215
  const patchObject = {
1153
1216
  fileInput: font.fileInput,
1154
1217
  subfamily: font.subfamily,
@@ -1160,7 +1223,7 @@ var updateExistingFont = async (font, existingFont, client) => {
1160
1223
  return await client.patch(font._id).set(patchObject).commit();
1161
1224
  };
1162
1225
  var createNewFont = async (font, client) => {
1163
- console.log("Creating new font: ", font._id, font.title);
1226
+ console.log("Creating new font:", font._id, font.title);
1164
1227
  if (font.metaData) cleanMetadataValues(font);
1165
1228
  const newDocument = {
1166
1229
  _key: (0, import_nanoid3.nanoid)(),
@@ -1176,7 +1239,7 @@ var cleanMetadataValues = (font) => {
1176
1239
  if (font.metaData[key] == null) {
1177
1240
  font.metaData[key] = "";
1178
1241
  } else {
1179
- font.metaData[key] = font.metaData[key].replace(/[-]/g, "");
1242
+ font.metaData[key] = font.metaData[key].replace(/[\x00-\x1f]/g, "");
1180
1243
  }
1181
1244
  });
1182
1245
  };
@@ -1206,11 +1269,8 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1206
1269
  console.log("Updating typeface document with new fonts:", { fontRefs, variableRefs, subfamilies, uniqueSubfamilies });
1207
1270
  setStatus("Updating typeface references...");
1208
1271
  let patch = {
1209
- styles: {
1210
- fonts: stylesObject.fonts ? [...stylesObject.fonts, ...fontRefs] : [...fontRefs],
1211
- subfamilies: uniqueSubfamilies.length > 1 ? uniqueSubfamilies : [],
1212
- variableFont: (stylesObject == null ? void 0 : stylesObject.variableFont) ? [...stylesObject.variableFont, ...variableRefs] : [...variableRefs]
1213
- }
1272
+ "styles.fonts": stylesObject.fonts ? [...stylesObject.fonts, ...fontRefs] : [...fontRefs],
1273
+ "styles.variableFont": (stylesObject == null ? void 0 : stylesObject.variableFont) ? [...stylesObject.variableFont, ...variableRefs] : [...variableRefs]
1214
1274
  };
1215
1275
  setStatus("Organising font subfamilies...");
1216
1276
  subfamiliesArray = subfamiliesArray || [];
@@ -1244,7 +1304,7 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1244
1304
  )
1245
1305
  }));
1246
1306
  }
1247
- patch.styles.subfamilies = subfamiliesArray;
1307
+ patch["styles.subfamilies"] = subfamiliesArray;
1248
1308
  await updatePreferredStyle(doc_id, preferredStyleRef, newPreferredStyle, patch, client);
1249
1309
  console.log("doc_id: ", doc_id);
1250
1310
  console.log("Typeface patch: ", patch);
@@ -1263,20 +1323,14 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1263
1323
  }
1264
1324
  };
1265
1325
  var updatePreferredStyle = async (doc_id, preferredStyleRef, newPreferredStyle, patch, client) => {
1266
- var _a;
1267
- if ((preferredStyleRef == null ? void 0 : preferredStyleRef._ref) && preferredStyleRef._ref !== "" && preferredStyleRef._ref !== null && newPreferredStyle._ref !== preferredStyleRef._ref) {
1268
- const prefStyleResult = await client.fetch(
1269
- `*[_id == $docId]{ preferredStyle->{ weight, style, _id } }`,
1270
- { docId: doc_id }
1271
- );
1272
- const prefStyle = (_a = prefStyleResult[0]) == null ? void 0 : _a.preferredStyle;
1273
- if (!(prefStyle == null ? void 0 : prefStyle.weight) || prefStyle === null || prefStyle.weight < newPreferredStyle.weight) {
1274
- patch.preferredStyle = {
1275
- _type: "reference",
1276
- _ref: newPreferredStyle._ref,
1277
- _weak: true
1278
- };
1279
- }
1326
+ const isCurrentlyEmpty = !(preferredStyleRef == null ? void 0 : preferredStyleRef._ref) || preferredStyleRef._ref === "" || preferredStyleRef._ref === null;
1327
+ const hasCandidate = (newPreferredStyle == null ? void 0 : newPreferredStyle._ref) && newPreferredStyle._ref !== "";
1328
+ if (isCurrentlyEmpty && hasCandidate) {
1329
+ patch.preferredStyle = {
1330
+ _type: "reference",
1331
+ _ref: newPreferredStyle._ref,
1332
+ _weak: true
1333
+ };
1280
1334
  }
1281
1335
  };
1282
1336
  var updatePublishedDocument = async (doc_id, patch, client) => {
@@ -1760,7 +1814,8 @@ var BatchUploadFonts = () => {
1760
1814
  inputPrice,
1761
1815
  stylesObject,
1762
1816
  setStatus,
1763
- setError
1817
+ setError,
1818
+ preserveFileNames
1764
1819
  );
1765
1820
  await updateTypefaceDocument(
1766
1821
  doc_id,
package/dist/index.mjs CHANGED
@@ -231,17 +231,22 @@ var processFontFiles = async (files, title, weightKeywordList, italicKeywordList
231
231
  if (file.name.endsWith(".woff2") || file.name.endsWith(".woff")) {
232
232
  await handleWebfontMetadata(file, font, files);
233
233
  }
234
- const { weightName, subfamilyName, fontTitle, style, italicKW, variableFont } = extractFontMetadata(
234
+ let { weightName, subfamilyName, fontTitle, style, italicKW, variableFont } = extractFontMetadata(
235
235
  font,
236
236
  title,
237
237
  weightKeywordList,
238
238
  italicKeywordList,
239
239
  preserveShortenedNames
240
240
  );
241
- const id = sanitizeForSanityId(fontTitle);
241
+ let id;
242
242
  let originalFilename = null;
243
243
  if (preserveFileNames) {
244
244
  originalFilename = file.name.replace(/\.(ttf|otf|woff2?|eot|svg)$/i, "");
245
+ const normalizedName = originalFilename.replace(/-/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").trim();
246
+ fontTitle = normalizedName;
247
+ id = sanitizeForSanityId(normalizedName);
248
+ } else {
249
+ id = sanitizeForSanityId(fontTitle);
245
250
  }
246
251
  logFontInfo(id, fontTitle, font, file.name, subfamilyName, style, weightName, variableFont, italicKW);
247
252
  subfamilies[id] = subfamilyName;
@@ -909,7 +914,7 @@ var parseVariableFontInstances = async (font, client) => {
909
914
  var parseVariableFontInstances_default = parseVariableFontInstances;
910
915
 
911
916
  // src/utils/uploadFontFiles.js
912
- var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, stylesObject, setStatus, setError) => {
917
+ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, stylesObject, setStatus, setError, preserveFileNames = false) => {
913
918
  let fontRefs = [];
914
919
  let variableRefs = [];
915
920
  let failedFiles = [];
@@ -926,10 +931,18 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
926
931
  for (let j = 0; j < files.length; j++) {
927
932
  const file = files[j];
928
933
  const fileType = determineFileType(file);
929
- console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${fontObject._id}.${fileType}`);
930
- setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${fontObject._id}.${fileType}`);
934
+ const assetFilename = preserveFileNames && fontObject.originalFilename ? `${fontObject.originalFilename}.${fileType}` : `${fontObject._id}.${fileType}`;
935
+ console.log(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${assetFilename}`);
936
+ setStatus(`[${i + 1}/${fontObjectKeys.length}][${j + 1}/${files.length}] Uploading font file: ${assetFilename}`);
931
937
  try {
932
- const baseAsset = await client.assets.upload("file", file, { filename: fontObject._id + "." + fileType });
938
+ const baseAsset = await client.assets.upload("file", file, { filename: assetFilename });
939
+ if (preserveFileNames && baseAsset.originalFilename !== assetFilename) {
940
+ try {
941
+ await client.patch(baseAsset._id).set({ originalFilename: assetFilename }).commit();
942
+ } catch (renameErr) {
943
+ console.warn("Could not rename asset \u2014 permissions may be restricted:", renameErr.message);
944
+ }
945
+ }
933
946
  newFileInput[fileType] = {
934
947
  _type: "file",
935
948
  asset: { _ref: baseAsset._id, _type: "reference" }
@@ -961,7 +974,7 @@ var uploadFontFiles = async (fontsObjects, subfamilies, client, inputPrice, styl
961
974
  Object.assign(fontObject, metadata);
962
975
  }
963
976
  } catch (err) {
964
- console.error("Error uploading font: ", fontObject.title, err.message);
977
+ console.error("Error uploading font:", fontObject.title, err.message);
965
978
  setStatus("Error uploading font: " + err.message);
966
979
  setError(true);
967
980
  failedFiles.push({ name: file.name, fk: fontKit });
@@ -997,22 +1010,68 @@ var determineFileType = (file) => {
997
1010
  if (file.name.endsWith(".svg")) return "svg";
998
1011
  return "";
999
1012
  };
1000
- var createOrUpdateFontDocument = async (font, client, setError) => {
1013
+ var resolveExistingFont = async (font, client) => {
1014
+ const result = { exact: null, candidates: [], recommendation: "create" };
1001
1015
  try {
1002
- const existingFont = await client.fetch(
1003
- `*[_type == 'font' && _id == $fontId]{
1004
- fileInput,
1005
- description,
1006
- metaData,
1007
- metrics,
1008
- opentypeFeatures,
1009
- characterSet,
1010
- subfamily,
1011
- scriptFileInput,
1012
- variableInstanceReferences
1016
+ const idMatches = await client.fetch(
1017
+ `*[_type == 'font' && (_id == $id || _id == $draftId || slug.current == $id)]{
1018
+ _id, title, weight, style, weightName, typefaceName, subfamily, variableFont,
1019
+ fileInput, description, metaData, metrics, opentypeFeatures, characterSet,
1020
+ scriptFileInput, variableInstanceReferences
1021
+ }`,
1022
+ { id: font._id, draftId: `drafts.${font._id}` }
1023
+ );
1024
+ if (idMatches.length > 0) {
1025
+ result.exact = idMatches[0];
1026
+ result.recommendation = "use-exact";
1027
+ return result;
1028
+ }
1029
+ const subfamily = font.subfamily || "";
1030
+ const contentMatches = await client.fetch(
1031
+ `*[_type == 'font'
1032
+ && lower(typefaceName) == lower($typefaceName)
1033
+ && lower(weightName) == lower($weightName)
1034
+ && lower(style) == lower($style)
1035
+ && (variableFont == $variableFont || (!defined(variableFont) && $variableFont == false))
1036
+ && (
1037
+ lower(coalesce(subfamily, '')) == lower($subfamily)
1038
+ || (lower(coalesce(subfamily, '')) in ['', 'regular'] && lower($subfamily) in ['', 'regular'])
1039
+ )
1040
+ ]{
1041
+ _id, title, weight, style, weightName, typefaceName, subfamily, variableFont,
1042
+ fileInput, description, metaData, metrics, opentypeFeatures, characterSet,
1043
+ scriptFileInput, variableInstanceReferences
1013
1044
  }`,
1014
- { fontId: font._id }
1015
- ).then((res) => res[0]);
1045
+ {
1046
+ typefaceName: font.typefaceName,
1047
+ weightName: font.weightName || "",
1048
+ style: font.style || "Regular",
1049
+ variableFont: font.variableFont || false,
1050
+ subfamily: subfamily === "" ? "regular" : subfamily
1051
+ }
1052
+ );
1053
+ if (contentMatches.length === 1) {
1054
+ result.candidates = contentMatches;
1055
+ result.recommendation = "use-candidate";
1056
+ return result;
1057
+ }
1058
+ if (contentMatches.length > 1) {
1059
+ result.candidates = contentMatches;
1060
+ result.recommendation = "ambiguous";
1061
+ console.warn(
1062
+ `Ambiguous font match for "${font.title}" \u2014 ${contentMatches.length} candidates found:`,
1063
+ contentMatches.map((c) => c._id)
1064
+ );
1065
+ return result;
1066
+ }
1067
+ } catch (err) {
1068
+ console.error("Error resolving existing font:", font._id, err.message);
1069
+ }
1070
+ return result;
1071
+ };
1072
+ var createOrUpdateFontDocument = async (font, client, setError) => {
1073
+ try {
1074
+ const { exact, candidates, recommendation } = await resolveExistingFont(font, client);
1016
1075
  const { files, fontKit } = font;
1017
1076
  delete font.files;
1018
1077
  delete font.fontKit;
@@ -1024,8 +1083,12 @@ var createOrUpdateFontDocument = async (font, client, setError) => {
1024
1083
  }
1025
1084
  }
1026
1085
  let fontResponse;
1027
- if (existingFont) {
1028
- fontResponse = await updateExistingFont(font, existingFont, client);
1086
+ if (recommendation === "use-exact" && exact) {
1087
+ fontResponse = await updateExistingFont(font, exact, client);
1088
+ } else if (recommendation === "use-candidate" && candidates.length === 1) {
1089
+ console.log(`Content-match: reassigning "${font._id}" \u2192 "${candidates[0]._id}"`);
1090
+ font._id = candidates[0]._id;
1091
+ fontResponse = await updateExistingFont(font, candidates[0], client);
1029
1092
  } else {
1030
1093
  fontResponse = await createNewFont(font, client);
1031
1094
  }
@@ -1036,7 +1099,7 @@ var createOrUpdateFontDocument = async (font, client, setError) => {
1036
1099
  _weak: true
1037
1100
  };
1038
1101
  } catch (e) {
1039
- console.error("Error creating font: ", font.title, font.subfamily, e);
1102
+ console.error("Error creating font:", font.title, font.subfamily, e);
1040
1103
  setError(true);
1041
1104
  return null;
1042
1105
  }
@@ -1058,7 +1121,7 @@ var updateExistingFont = async (font, existingFont, client) => {
1058
1121
  if (font.variableFont && (existingFont == null ? void 0 : existingFont.variableInstanceReferences) && (!font.variableInstanceReferences || font.variableInstanceReferences.length === 0)) {
1059
1122
  font.variableInstanceReferences = existingFont.variableInstanceReferences;
1060
1123
  }
1061
- console.log("Updating existing font: ", font._id, font.title);
1124
+ console.log("Updating existing font:", font._id, font.title);
1062
1125
  const patchObject = {
1063
1126
  fileInput: font.fileInput,
1064
1127
  subfamily: font.subfamily,
@@ -1070,7 +1133,7 @@ var updateExistingFont = async (font, existingFont, client) => {
1070
1133
  return await client.patch(font._id).set(patchObject).commit();
1071
1134
  };
1072
1135
  var createNewFont = async (font, client) => {
1073
- console.log("Creating new font: ", font._id, font.title);
1136
+ console.log("Creating new font:", font._id, font.title);
1074
1137
  if (font.metaData) cleanMetadataValues(font);
1075
1138
  const newDocument = {
1076
1139
  _key: nanoid3(),
@@ -1086,7 +1149,7 @@ var cleanMetadataValues = (font) => {
1086
1149
  if (font.metaData[key] == null) {
1087
1150
  font.metaData[key] = "";
1088
1151
  } else {
1089
- font.metaData[key] = font.metaData[key].replace(/[-]/g, "");
1152
+ font.metaData[key] = font.metaData[key].replace(/[\x00-\x1f]/g, "");
1090
1153
  }
1091
1154
  });
1092
1155
  };
@@ -1116,11 +1179,8 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1116
1179
  console.log("Updating typeface document with new fonts:", { fontRefs, variableRefs, subfamilies, uniqueSubfamilies });
1117
1180
  setStatus("Updating typeface references...");
1118
1181
  let patch = {
1119
- styles: {
1120
- fonts: stylesObject.fonts ? [...stylesObject.fonts, ...fontRefs] : [...fontRefs],
1121
- subfamilies: uniqueSubfamilies.length > 1 ? uniqueSubfamilies : [],
1122
- variableFont: (stylesObject == null ? void 0 : stylesObject.variableFont) ? [...stylesObject.variableFont, ...variableRefs] : [...variableRefs]
1123
- }
1182
+ "styles.fonts": stylesObject.fonts ? [...stylesObject.fonts, ...fontRefs] : [...fontRefs],
1183
+ "styles.variableFont": (stylesObject == null ? void 0 : stylesObject.variableFont) ? [...stylesObject.variableFont, ...variableRefs] : [...variableRefs]
1124
1184
  };
1125
1185
  setStatus("Organising font subfamilies...");
1126
1186
  subfamiliesArray = subfamiliesArray || [];
@@ -1154,7 +1214,7 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1154
1214
  )
1155
1215
  }));
1156
1216
  }
1157
- patch.styles.subfamilies = subfamiliesArray;
1217
+ patch["styles.subfamilies"] = subfamiliesArray;
1158
1218
  await updatePreferredStyle(doc_id, preferredStyleRef, newPreferredStyle, patch, client);
1159
1219
  console.log("doc_id: ", doc_id);
1160
1220
  console.log("Typeface patch: ", patch);
@@ -1173,20 +1233,14 @@ var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies,
1173
1233
  }
1174
1234
  };
1175
1235
  var updatePreferredStyle = async (doc_id, preferredStyleRef, newPreferredStyle, patch, client) => {
1176
- var _a;
1177
- if ((preferredStyleRef == null ? void 0 : preferredStyleRef._ref) && preferredStyleRef._ref !== "" && preferredStyleRef._ref !== null && newPreferredStyle._ref !== preferredStyleRef._ref) {
1178
- const prefStyleResult = await client.fetch(
1179
- `*[_id == $docId]{ preferredStyle->{ weight, style, _id } }`,
1180
- { docId: doc_id }
1181
- );
1182
- const prefStyle = (_a = prefStyleResult[0]) == null ? void 0 : _a.preferredStyle;
1183
- if (!(prefStyle == null ? void 0 : prefStyle.weight) || prefStyle === null || prefStyle.weight < newPreferredStyle.weight) {
1184
- patch.preferredStyle = {
1185
- _type: "reference",
1186
- _ref: newPreferredStyle._ref,
1187
- _weak: true
1188
- };
1189
- }
1236
+ const isCurrentlyEmpty = !(preferredStyleRef == null ? void 0 : preferredStyleRef._ref) || preferredStyleRef._ref === "" || preferredStyleRef._ref === null;
1237
+ const hasCandidate = (newPreferredStyle == null ? void 0 : newPreferredStyle._ref) && newPreferredStyle._ref !== "";
1238
+ if (isCurrentlyEmpty && hasCandidate) {
1239
+ patch.preferredStyle = {
1240
+ _type: "reference",
1241
+ _ref: newPreferredStyle._ref,
1242
+ _weak: true
1243
+ };
1190
1244
  }
1191
1245
  };
1192
1246
  var updatePublishedDocument = async (doc_id, patch, client) => {
@@ -1670,7 +1724,8 @@ var BatchUploadFonts = () => {
1670
1724
  inputPrice,
1671
1725
  stylesObject,
1672
1726
  setStatus,
1673
- setError
1727
+ setError,
1728
+ preserveFileNames
1674
1729
  );
1675
1730
  await updateTypefaceDocument(
1676
1731
  doc_id,