@sanity/document-internationalization 2.0.0-studio-v3-plugin-v2.7 → 2.0.0-studio-v3-plugin-v2.8

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/lib/index.js CHANGED
@@ -4,71 +4,180 @@ Object.defineProperty(exports, '__esModule', {
4
4
  value: true
5
5
  });
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var ui = require('@sanity/ui');
7
8
  var sanity = require('sanity');
8
9
  var sanityPluginInternationalizedArray = require('sanity-plugin-internationalized-array');
9
- var ui = require('@sanity/ui');
10
- var icons = require('@sanity/icons');
11
10
  var React = require('react');
12
- var uuid = require('@sanity/uuid');
11
+ var icons = require('@sanity/icons');
12
+ var sanityPluginUtils = require('sanity-plugin-utils');
13
13
  var desk = require('sanity/desk');
14
14
  var router = require('sanity/router');
15
- var sanityPluginUtils = require('sanity-plugin-utils');
15
+ var uuid = require('@sanity/uuid');
16
16
  function _interopDefaultCompat(e) {
17
17
  return e && typeof e === 'object' && 'default' in e ? e : {
18
18
  default: e
19
19
  };
20
20
  }
21
21
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
22
+ function LanguageBadge(props, supportedLanguages, languageField) {
23
+ var _a, _b;
24
+ const source = (props == null ? void 0 : props.draft) || (props == null ? void 0 : props.published);
25
+ const languageId = source == null ? void 0 : source[languageField];
26
+ if (!languageId) {
27
+ return null;
28
+ }
29
+ const language = Array.isArray(supportedLanguages) ? supportedLanguages.find(l => l.id === languageId) : null;
30
+ return {
31
+ label: (_a = language == null ? void 0 : language.id) != null ? _a : String(languageId),
32
+ title: (_b = language == null ? void 0 : language.title) != null ? _b : void 0,
33
+ color: "primary"
34
+ };
35
+ }
22
36
  const METADATA_SCHEMA_NAME = "translation.metadata";
23
37
  const API_VERSION = "2022-11-27";
24
- var metadata = schemaTypes => sanity.defineType({
25
- type: "document",
26
- name: METADATA_SCHEMA_NAME,
27
- title: "Translation metadata",
28
- icon: icons.TranslateIcon,
29
- liveEdit: true,
30
- fields: [sanity.defineField({
31
- name: "translations",
32
- type: "internationalizedArrayReference"
33
- }), sanity.defineField({
34
- name: "schemaTypes",
35
- description: "Used to filter the reference fields above so all translations share the same types.",
36
- type: "array",
37
- // For some reason TS dislikes this line because of the DocumentDefinition return type
38
- // @ts-expect-error
39
- of: [{
40
- type: "string"
41
- }],
42
- options: {
43
- list: schemaTypes
44
- },
45
- readOnly: _ref => {
46
- let {
47
- value
48
- } = _ref;
49
- return Boolean(value);
38
+ function DocumentCheck(props) {
39
+ const {
40
+ id,
41
+ addInvalidId,
42
+ removeInvalidId,
43
+ addDraftId,
44
+ removeDraftId
45
+ } = props;
46
+ const editState = sanity.useEditState(id, "");
47
+ const {
48
+ isValidating,
49
+ validation
50
+ } = sanity.useValidationStatus(id, "");
51
+ const schema = sanity.useSchema();
52
+ const validationHasErrors = React__default.default.useMemo(() => {
53
+ return !isValidating && validation.length > 0 && validation.some(item => item.level === "error");
54
+ }, [isValidating, validation]);
55
+ React__default.default.useEffect(() => {
56
+ if (validationHasErrors) {
57
+ addInvalidId(id);
58
+ } else {
59
+ removeInvalidId(id);
50
60
  }
51
- })],
52
- preview: {
53
- select: {
54
- translations: "translations",
55
- documentSchemaTypes: "schemaTypes"
56
- },
57
- prepare(selection) {
58
- const {
59
- translations,
60
- documentSchemaTypes
61
- } = selection;
62
- const title = translations.length === 1 ? "1 Translation" : "".concat(translations.length, " Translations");
63
- const languageKeys = translations.length ? translations.map(t => t._key.toUpperCase()).join(", ") : "";
64
- const subtitle = [languageKeys ? "(".concat(languageKeys, ")") : null, (documentSchemaTypes == null ? void 0 : documentSchemaTypes.length) ? documentSchemaTypes.map(s => s.toUpperCase()).join(", ") : "No Schemas Defined"].filter(Boolean).join(" ");
65
- return {
66
- title,
67
- subtitle
68
- };
61
+ if (editState.draft) {
62
+ addDraftId(id);
63
+ } else {
64
+ removeDraftId(id);
69
65
  }
66
+ }, [addDraftId, addInvalidId, editState.draft, id, removeDraftId, removeInvalidId, validationHasErrors]);
67
+ if (!editState.draft) {
68
+ return null;
70
69
  }
71
- });
70
+ const schemaType = schema.get(editState.draft._type);
71
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
72
+ border: true,
73
+ padding: 2,
74
+ tone: validationHasErrors ? "critical" : "positive",
75
+ children: editState.draft && schemaType ? /* @__PURE__ */jsxRuntime.jsx(sanity.Preview, {
76
+ layout: "default",
77
+ value: editState.draft,
78
+ schemaType
79
+ }) : /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
80
+ });
81
+ }
82
+ function BulkPublish(props) {
83
+ const {
84
+ translations
85
+ } = props;
86
+ const client = sanity.useClient({
87
+ apiVersion: API_VERSION
88
+ });
89
+ const {
90
+ projectId,
91
+ dataset
92
+ } = sanity.useWorkspace();
93
+ const toast = ui.useToast();
94
+ const [invalidIds, setInvalidIds] = React__default.default.useState(null);
95
+ const addInvalidId = React.useCallback(id => {
96
+ setInvalidIds(ids => ids ? Array.from( /* @__PURE__ */new Set([...ids, id])) : [id]);
97
+ }, []);
98
+ const removeInvalidId = React.useCallback(id => {
99
+ setInvalidIds(ids => ids ? ids.filter(i => i !== id) : []);
100
+ }, []);
101
+ const [draftIds, setDraftIds] = React__default.default.useState([]);
102
+ const addDraftId = React.useCallback(id => {
103
+ setDraftIds(ids => Array.from( /* @__PURE__ */new Set([...ids, id])));
104
+ }, []);
105
+ const removeDraftId = React.useCallback(id => {
106
+ setDraftIds(ids => ids.filter(i => i !== id));
107
+ }, []);
108
+ const handleBulkPublish = React.useCallback(() => {
109
+ const body = translations.map(translation => ({
110
+ documentId: translation.value._ref
111
+ }));
112
+ client.request({
113
+ uri: "/publish/".concat(projectId, "/").concat(dataset),
114
+ method: "POST",
115
+ body
116
+ }).then(res => {
117
+ toast.push({
118
+ status: "success",
119
+ title: "Success",
120
+ description: "Bulk publish complete"
121
+ });
122
+ }).catch(err => {
123
+ console.error(err);
124
+ toast.push({
125
+ status: "error",
126
+ title: "Error",
127
+ description: "Bulk publish failed"
128
+ });
129
+ });
130
+ }, [translations, client, projectId, dataset, toast]);
131
+ return (translations == null ? void 0 : translations.length) > 0 ? /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
132
+ padding: 4,
133
+ border: true,
134
+ radius: 2,
135
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
136
+ space: 3,
137
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Text, {
138
+ weight: "bold",
139
+ size: 1,
140
+ children: "Bulk publishing"
141
+ }), draftIds.length > 0 ? /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
142
+ space: 2,
143
+ children: [/* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
144
+ size: 1,
145
+ children: ["There", " ", draftIds.length === 1 ? "is 1 draft document" : "are ".concat(draftIds.length, " draft documents"), "."]
146
+ }), invalidIds && invalidIds.length > 0 ? /* @__PURE__ */jsxRuntime.jsxs(sanity.TextWithTone, {
147
+ tone: "caution",
148
+ size: 1,
149
+ children: [invalidIds && invalidIds.length === 1 ? "1 draft document has" : "".concat(invalidIds && invalidIds.length, " draft documents have"), " ", "validation issues that must addressed first"]
150
+ }) : /* @__PURE__ */jsxRuntime.jsx(sanity.TextWithTone, {
151
+ tone: "positive",
152
+ size: 1,
153
+ children: "All drafts are valid and can be bulk published"
154
+ })]
155
+ }) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
156
+ space: 1,
157
+ children: translations.filter(translation => {
158
+ var _a;
159
+ return (_a = translation == null ? void 0 : translation.value) == null ? void 0 : _a._ref;
160
+ }).map(translation => /* @__PURE__ */jsxRuntime.jsx(DocumentCheck, {
161
+ id: translation.value._ref,
162
+ addInvalidId,
163
+ removeInvalidId,
164
+ addDraftId,
165
+ removeDraftId
166
+ }, translation._key))
167
+ }), draftIds.length > 0 ? /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
168
+ mode: "ghost",
169
+ tone: invalidIds && (invalidIds == null ? void 0 : invalidIds.length) > 0 ? "caution" : "positive",
170
+ text: draftIds.length === 1 ? "Publish draft document" : "Bulk publish ".concat(draftIds.length, " draft documents"),
171
+ onClick: handleBulkPublish,
172
+ disabled: Boolean(invalidIds && (invalidIds == null ? void 0 : invalidIds.length) > 0) || !draftIds.length
173
+ }) : /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
174
+ muted: true,
175
+ size: 1,
176
+ children: "No draft documents to publish"
177
+ })]
178
+ })
179
+ }) : null;
180
+ }
72
181
  function shallowEqualArrays(arrA, arrB) {
73
182
  let equal = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (a, b) => a === b;
74
183
  if (arrA === arrB) return true;
@@ -120,6 +229,24 @@ function query(fn, keys) {
120
229
  return undefined;
121
230
  }
122
231
  const suspend = (fn, keys, config) => query(fn, keys, false, config);
232
+ function useTranslationMetadata(id, schemaType) {
233
+ const query = "*[_type == $translationSchema && $id in translations[].value._ref][0]";
234
+ const {
235
+ data,
236
+ loading,
237
+ error
238
+ } = sanityPluginUtils.useListeningQuery(query, {
239
+ params: {
240
+ id,
241
+ translationSchema: METADATA_SCHEMA_NAME
242
+ }
243
+ });
244
+ return {
245
+ data,
246
+ loading,
247
+ error
248
+ };
249
+ }
123
250
  function useOpenInNewPane(id, type) {
124
251
  const routerContext = React__default.default.useContext(router.RouterContext);
125
252
  const {
@@ -146,9 +273,23 @@ function useOpenInNewPane(id, type) {
146
273
  }, [id, type, routerContext, routerPanesState, groupIndex]);
147
274
  return openInNewPane;
148
275
  }
276
+ function LanguageManage(props) {
277
+ const {
278
+ id
279
+ } = props;
280
+ const open = useOpenInNewPane(id, METADATA_SCHEMA_NAME);
281
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
282
+ disabled: !id,
283
+ mode: "ghost",
284
+ text: "Manage Translations",
285
+ icon: icons.CogIcon,
286
+ onClick: () => open()
287
+ });
288
+ }
149
289
  function createReference(key, ref, type) {
150
290
  return {
151
291
  _key: key,
292
+ _type: "internationalizedArrayReferenceValue",
152
293
  value: {
153
294
  _type: "reference",
154
295
  _ref: ref,
@@ -227,59 +368,49 @@ function LanguageOption(props) {
227
368
  });
228
369
  });
229
370
  }, [client, documentId, index, language, languageField, metadata == null ? void 0 : metadata._id, schemaType, sourceId, sourceLanguageId, toast]);
230
- return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
231
- onClick: translation ? handleOpen : handleCreate,
232
- mode: current ? "default" : "bleed",
233
- disabled: disabled || current,
234
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
235
- gap: 3,
236
- align: "center",
237
- children: [disabled ? /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {}) : /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
238
- size: 2,
239
- children: translation ? /* @__PURE__ */jsxRuntime.jsx(icons.SplitVerticalIcon, {}) : current ? /* @__PURE__ */jsxRuntime.jsx(icons.CheckmarkIcon, {}) : /* @__PURE__ */jsxRuntime.jsx(icons.AddIcon, {})
240
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
241
- flex: 1,
242
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
243
- children: language.title
244
- })
245
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Badge, {
246
- tone: disabled || current ? "default" : "primary",
247
- children: language.id
248
- })]
371
+ let message;
372
+ if (current) {
373
+ message = "Current document";
374
+ } else if (translation) {
375
+ message = "Open ".concat(language.title, " translation");
376
+ } else if (!translation) {
377
+ message = "Create new ".concat(language.title, " translation");
378
+ }
379
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Tooltip, {
380
+ content: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
381
+ padding: 2,
382
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
383
+ muted: true,
384
+ size: 1,
385
+ children: message
386
+ })
387
+ }),
388
+ fallbackPlacements: ["right", "left"],
389
+ placement: "top",
390
+ portal: true,
391
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
392
+ onClick: translation ? handleOpen : handleCreate,
393
+ mode: current && disabled ? "default" : "bleed",
394
+ disabled: disabled || current,
395
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
396
+ gap: 3,
397
+ align: "center",
398
+ children: [disabled ? /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {}) : /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
399
+ size: 2,
400
+ children: translation ? /* @__PURE__ */jsxRuntime.jsx(icons.SplitVerticalIcon, {}) : current ? /* @__PURE__ */jsxRuntime.jsx(icons.CheckmarkIcon, {}) : /* @__PURE__ */jsxRuntime.jsx(icons.AddIcon, {})
401
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
402
+ flex: 1,
403
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
404
+ children: language.title
405
+ })
406
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Badge, {
407
+ tone: disabled || current ? "default" : "primary",
408
+ children: language.id
409
+ })]
410
+ })
249
411
  })
250
412
  });
251
413
  }
252
- function useTranslationMetadata(id, schemaType) {
253
- const query = "*[_type == $translationSchema && $id in translations[].value._ref][0]";
254
- const {
255
- data,
256
- loading,
257
- error
258
- } = sanityPluginUtils.useListeningQuery(query, {
259
- params: {
260
- id,
261
- translationSchema: METADATA_SCHEMA_NAME
262
- }
263
- });
264
- return {
265
- data,
266
- loading,
267
- error
268
- };
269
- }
270
- function LanguageManage(props) {
271
- const {
272
- id
273
- } = props;
274
- const open = useOpenInNewPane(id, METADATA_SCHEMA_NAME);
275
- return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
276
- disabled: !id,
277
- mode: "ghost",
278
- text: "Manage Translations",
279
- icon: icons.CogIcon,
280
- onClick: () => open()
281
- });
282
- }
283
414
  function LanguagePatch(props) {
284
415
  const {
285
416
  apiVersion = API_VERSION,
@@ -321,12 +452,25 @@ function LanguagePatch(props) {
321
452
  });
322
453
  }, [source, documentId, client, languageField, language, schemaType, toast]);
323
454
  return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
324
- mode: "ghost",
325
- text: language.title,
326
- icon: icons.ChevronRightIcon,
327
- onClick: () => handleClick(),
455
+ mode: "bleed",
456
+ onClick: handleClick,
328
457
  disabled,
329
- justify: "flex-start"
458
+ justify: "flex-start",
459
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
460
+ gap: 3,
461
+ align: "center",
462
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Text, {
463
+ size: 2,
464
+ children: /* @__PURE__ */jsxRuntime.jsx(icons.EditIcon, {})
465
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
466
+ flex: 1,
467
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
468
+ children: language.title
469
+ })
470
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Badge, {
471
+ children: language.id
472
+ })]
473
+ })
330
474
  });
331
475
  }
332
476
  function MenuButton(props) {
@@ -383,7 +527,34 @@ function MenuButton(props) {
383
527
  padding: 1,
384
528
  space: 1,
385
529
  children: [supportedLanguages.length > 0 ? /* @__PURE__ */jsxRuntime.jsxs(jsxRuntime.Fragment, {
386
- children: [supportedLanguages.map((language, langIndex) => {
530
+ children: [loading ? null : /* @__PURE__ */jsxRuntime.jsxs(jsxRuntime.Fragment, {
531
+ children: [allLanguagesAreValid ? null : /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
532
+ tone: "caution",
533
+ padding: 3,
534
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
535
+ size: 1,
536
+ children: "Not all language objects are valid. See the console."
537
+ })
538
+ }), sourceLanguageId ? null : /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
539
+ tone: "caution",
540
+ padding: 3,
541
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
542
+ size: 1,
543
+ children: ["Choose a language to ", /* @__PURE__ */jsxRuntime.jsx("br", {}), "apply to ", /* @__PURE__ */jsxRuntime.jsx("strong", {
544
+ children: "this Document"
545
+ })]
546
+ })
547
+ }), sourceLanguageId && !sourceLanguageIsValid ? /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
548
+ tone: "caution",
549
+ padding: 3,
550
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
551
+ size: 1,
552
+ children: ["Select a supported language.", /* @__PURE__ */jsxRuntime.jsx("br", {}), "Current language value: ", /* @__PURE__ */jsxRuntime.jsx("code", {
553
+ children: sourceLanguageId
554
+ })]
555
+ })
556
+ }) : null]
557
+ }), supportedLanguages.map((language, langIndex) => {
387
558
  var _a;
388
559
  return !loading && sourceLanguageId && sourceLanguageIsValid ?
389
560
  // Button to duplicate this document to a new translation
@@ -415,39 +586,13 @@ function MenuButton(props) {
415
586
  return ((_a2 = t == null ? void 0 : t.value) == null ? void 0 : _a2._ref) !== documentId;
416
587
  }).some(t => t._key === language.id))) != null ? _a : false
417
588
  }, language.id || language.title || "lang-".concat(langIndex));
418
- }), loading ? null : /* @__PURE__ */jsxRuntime.jsxs(jsxRuntime.Fragment, {
419
- children: [allLanguagesAreValid ? null : /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
420
- tone: "caution",
421
- padding: 3,
422
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
423
- size: 1,
424
- children: "Not all language objects are valid. See the console."
425
- })
426
- }), sourceLanguageId ? null : /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
427
- tone: "caution",
428
- padding: 3,
429
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
430
- size: 1,
431
- children: ["Choose a language to ", /* @__PURE__ */jsxRuntime.jsx("br", {}), "apply to ", /* @__PURE__ */jsxRuntime.jsx("strong", {
432
- children: "this Document"
433
- })]
434
- })
435
- }), sourceLanguageId && !sourceLanguageIsValid ? /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
436
- tone: "caution",
437
- padding: 3,
438
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
439
- size: 1,
440
- children: ["Change the current language value ", /* @__PURE__ */jsxRuntime.jsx("code", {
441
- children: sourceLanguageId
442
- }), /* @__PURE__ */jsxRuntime.jsx("br", {}), "to one of the supported languages"]
443
- })
444
- }) : null]
445
589
  })]
446
590
  }) : null, /* @__PURE__ */jsxRuntime.jsx(LanguageManage, {
447
591
  id: metadata == null ? void 0 : metadata._id
448
592
  })]
449
593
  })
450
594
  });
595
+ const issueWithTranslations = !loading && sourceLanguageId && !sourceLanguageIsValid;
451
596
  return /* @__PURE__ */jsxRuntime.jsx(ui.Popover, {
452
597
  constrainSize: true,
453
598
  content,
@@ -459,7 +604,7 @@ function MenuButton(props) {
459
604
  text: "Translations",
460
605
  mode: "bleed",
461
606
  disabled: !source,
462
- tone: !source || !loading && sourceLanguageId && sourceLanguageIsValid ? void 0 : "caution",
607
+ tone: !source || loading || !issueWithTranslations ? void 0 : "caution",
463
608
  icon: icons.TranslateIcon,
464
609
  onClick: handleClick,
465
610
  ref: setButton,
@@ -467,20 +612,102 @@ function MenuButton(props) {
467
612
  })
468
613
  });
469
614
  }
470
- function LanguageBadge(props, supportedLanguages, languageField) {
471
- var _a, _b;
472
- const source = (props == null ? void 0 : props.draft) || (props == null ? void 0 : props.published);
473
- const languageId = source == null ? void 0 : source[languageField];
474
- if (!languageId) {
615
+ function ReferencePatcher(props) {
616
+ const {
617
+ translation,
618
+ documentType,
619
+ metadataId
620
+ } = props;
621
+ const editState = sanity.useEditState(translation.value._ref, documentType);
622
+ const client = sanity.useClient({
623
+ apiVersion: API_VERSION
624
+ });
625
+ const {
626
+ onChange
627
+ } = desk.useDocumentPane();
628
+ React__default.default.useEffect(() => {
629
+ if (
630
+ // We have a reference
631
+ translation.value._ref &&
632
+ // It's still weak and not-yet-strengthened
633
+ translation.value._weak && translation.value._strengthenOnPublish &&
634
+ // The referenced document has just been published
635
+ !editState.draft && editState.published && editState.ready) {
636
+ const referencePathBase = ["translations", {
637
+ _key: translation._key
638
+ }, "value"];
639
+ onChange(new sanity.PatchEvent([sanity.unset([...referencePathBase, "_weak"]), sanity.unset([...referencePathBase, "_strengthenOnPublish"])]));
640
+ }
641
+ }, [translation, editState, metadataId, client, onChange]);
642
+ return null;
643
+ }
644
+ function OptimisticallyStrengthen(props) {
645
+ const {
646
+ translations = [],
647
+ metadataId
648
+ } = props;
649
+ if (!translations.length) {
475
650
  return null;
476
651
  }
477
- const language = Array.isArray(supportedLanguages) ? supportedLanguages.find(l => l.id === languageId) : null;
478
- return {
479
- label: (_a = language == null ? void 0 : language.id) != null ? _a : String(languageId),
480
- title: (_b = language == null ? void 0 : language.title) != null ? _b : void 0,
481
- color: "primary"
482
- };
652
+ return /* @__PURE__ */jsxRuntime.jsx(jsxRuntime.Fragment, {
653
+ children: translations.map(translation => {
654
+ var _a;
655
+ return ((_a = translation.value._strengthenOnPublish) == null ? void 0 : _a.type) ? /* @__PURE__ */jsxRuntime.jsx(ReferencePatcher, {
656
+ translation,
657
+ documentType: translation.value._strengthenOnPublish.type,
658
+ metadataId
659
+ }, translation._key) : null;
660
+ })
661
+ });
483
662
  }
663
+ var metadata = schemaTypes => sanity.defineType({
664
+ type: "document",
665
+ name: METADATA_SCHEMA_NAME,
666
+ title: "Translation metadata",
667
+ icon: icons.TranslateIcon,
668
+ liveEdit: true,
669
+ fields: [sanity.defineField({
670
+ name: "translations",
671
+ type: "internationalizedArrayReference"
672
+ }), sanity.defineField({
673
+ name: "schemaTypes",
674
+ description: "Optional: Used to filter the reference fields above so all translations share the same types.",
675
+ type: "array",
676
+ // For some reason TS dislikes this line because of the DocumentDefinition return type
677
+ // @ts-expect-error
678
+ of: [{
679
+ type: "string"
680
+ }],
681
+ options: {
682
+ list: schemaTypes
683
+ },
684
+ readOnly: _ref => {
685
+ let {
686
+ value
687
+ } = _ref;
688
+ return Boolean(value);
689
+ }
690
+ })],
691
+ preview: {
692
+ select: {
693
+ translations: "translations",
694
+ documentSchemaTypes: "schemaTypes"
695
+ },
696
+ prepare(selection) {
697
+ const {
698
+ translations,
699
+ documentSchemaTypes
700
+ } = selection;
701
+ const title = translations.length === 1 ? "1 Translation" : "".concat(translations.length, " Translations");
702
+ const languageKeys = translations.length ? translations.map(t => t._key.toUpperCase()).join(", ") : "";
703
+ const subtitle = [languageKeys ? "(".concat(languageKeys, ")") : null, (documentSchemaTypes == null ? void 0 : documentSchemaTypes.length) ? documentSchemaTypes.map(s => s.toUpperCase()).join(", ") : "No Schemas Defined"].filter(Boolean).join(" ");
704
+ return {
705
+ title,
706
+ subtitle
707
+ };
708
+ }
709
+ }
710
+ });
484
711
  const DEFAULT_CONFIG = {
485
712
  supportedLanguages: [],
486
713
  schemaTypes: [],
@@ -513,10 +740,22 @@ const documentInternationalization = sanity.definePlugin(config => {
513
740
  form: {
514
741
  components: {
515
742
  input: props => {
516
- if (bulkPublish && props.id === "root" && props.schemaType.name === METADATA_SCHEMA_NAME) {
517
- return /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
743
+ var _a, _b, _c;
744
+ if (props.id === "root" && props.schemaType.name === METADATA_SCHEMA_NAME && sanity.isSanityDocument(props == null ? void 0 : props.value)) {
745
+ const metadataId = (_a = props == null ? void 0 : props.value) == null ? void 0 : _a._id;
746
+ const translations = (_c = (_b = props == null ? void 0 : props.value) == null ? void 0 : _b.translations) != null ? _c : [];
747
+ const weakAndTypedTranslations = translations.filter(t => {
748
+ var _a2, _b2;
749
+ return ((_a2 = t == null ? void 0 : t.value) == null ? void 0 : _a2._weak) && ((_b2 = t.value) == null ? void 0 : _b2._strengthenOnPublish);
750
+ });
751
+ return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
518
752
  space: 5,
519
- children: props.renderDefault(props)
753
+ children: [bulkPublish ? /* @__PURE__ */jsxRuntime.jsx(BulkPublish, {
754
+ translations
755
+ }) : null, weakAndTypedTranslations.length > 0 ? /* @__PURE__ */jsxRuntime.jsx(OptimisticallyStrengthen, {
756
+ metadataId,
757
+ translations: weakAndTypedTranslations
758
+ }) : null, props.renderDefault(props)]
520
759
  });
521
760
  }
522
761
  return props.renderDefault(props);
@@ -602,22 +841,34 @@ const documentInternationalization = sanity.definePlugin(config => {
602
841
  // It cuts down on attribute usage and gives UI conveniences to add new translations
603
842
  sanityPluginInternationalizedArray.internationalizedArray({
604
843
  languages: supportedLanguages,
605
- fieldTypes: [
606
- // TODO: The plugin should allow this kind of input
607
- // @ts-ignore
608
- sanity.defineField({
844
+ fieldTypes: [sanity.defineField({
609
845
  name: "reference",
610
846
  type: "reference",
611
847
  to: schemaTypes.map(type => ({
612
848
  type
613
849
  })),
614
- // TODO: Add a validation rule to *ensure* the document's language matches the array key
615
850
  // Reference filters don't actually enforce validation!
616
- // validation: (Rule) => Rule.custom(),
851
+ validation: Rule => Rule.custom(async (item, context) => {
852
+ var _a;
853
+ if (!((_a = item == null ? void 0 : item.value) == null ? void 0 : _a._ref) || !(item == null ? void 0 : item._key)) {
854
+ return true;
855
+ }
856
+ const client = context.getClient({
857
+ apiVersion: API_VERSION
858
+ });
859
+ const valueLanguage = await client.fetch("*[_id in [$ref, $draftRef]][0].".concat(languageField), {
860
+ ref: item.value._ref,
861
+ draftRef: "drafts.".concat(item.value._ref)
862
+ });
863
+ if (valueLanguage && valueLanguage === item._key) {
864
+ return true;
865
+ }
866
+ return "Referenced document does not have the correct language value";
867
+ }),
617
868
  options: {
618
869
  collapsed: false,
619
870
  // TODO: Update type once it knows the values of this filter
620
- // @ts-ignore
871
+ // @ts-expect-error
621
872
  filter: _ref5 => {
622
873
  let {
623
874
  parent,