sanity-plugin-internationalized-array 3.2.2 → 4.0.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 (43) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -34
  3. package/{lib → dist}/index.d.ts +41 -61
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +882 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +36 -74
  8. package/lib/index.d.mts +0 -149
  9. package/lib/index.esm.js +0 -854
  10. package/lib/index.esm.js.map +0 -1
  11. package/lib/index.js +0 -863
  12. package/lib/index.js.map +0 -1
  13. package/lib/index.mjs +0 -854
  14. package/lib/index.mjs.map +0 -1
  15. package/sanity.json +0 -8
  16. package/src/cache.ts +0 -148
  17. package/src/components/AddButtons.tsx +0 -60
  18. package/src/components/DocumentAddButtons.tsx +0 -183
  19. package/src/components/Feedback.tsx +0 -28
  20. package/src/components/InternationalizedArray.tsx +0 -286
  21. package/src/components/InternationalizedArrayContext.tsx +0 -136
  22. package/src/components/InternationalizedField.tsx +0 -57
  23. package/src/components/InternationalizedInput.tsx +0 -257
  24. package/src/components/Preload.tsx +0 -31
  25. package/src/components/createFieldName.ts +0 -20
  26. package/src/components/getSelectedValue.ts +0 -31
  27. package/src/components/getToneFromValidation.ts +0 -20
  28. package/src/constants.ts +0 -18
  29. package/src/fieldActions/index.ts +0 -138
  30. package/src/index.ts +0 -3
  31. package/src/plugin.tsx +0 -87
  32. package/src/schema/array.ts +0 -148
  33. package/src/schema/object.ts +0 -36
  34. package/src/types.ts +0 -135
  35. package/src/utils/checkAllLanguagesArePresent.ts +0 -14
  36. package/src/utils/createAddAllTitle.ts +0 -16
  37. package/src/utils/createAddLanguagePatches.ts +0 -84
  38. package/src/utils/createValueSchemaTypeName.ts +0 -5
  39. package/src/utils/flattenSchemaType.ts +0 -63
  40. package/src/utils/getDocumentsToTranslate.ts +0 -66
  41. package/src/utils/getLanguageDisplay.ts +0 -13
  42. package/src/utils/getLanguagesFieldOption.ts +0 -16
  43. package/v2-incompatible.js +0 -11
package/dist/index.js ADDED
@@ -0,0 +1,882 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { isSanityDocument, useSchema, setIfMissing, insert, PatchEvent, useClient, useWorkspace, defineDocumentFieldAction, useFormValue, ArrayOfObjectsItem, MemberItemError, set, defineField, unset, isDocumentSchemaType, definePlugin, isObjectInputProps } from "sanity";
3
+ import { c } from "react/compiler-runtime";
4
+ import { useLanguageFilterStudioContext } from "@sanity/language-filter";
5
+ import { Grid, Button, useToast, Stack, Box, Text, Card, Code, Spinner, Label, MenuButton, Menu, MenuItem, Flex, Tooltip } from "@sanity/ui";
6
+ import { createContext, useContext, useDeferredValue, use, useCallback, useEffect, createElement } from "react";
7
+ import { useDocumentPane } from "sanity/structure";
8
+ import { AddIcon, TranslateIcon, RemoveCircleIcon } from "@sanity/icons";
9
+ import { get, upperFirst, camelCase } from "lodash-es";
10
+ const namespace = "sanity-plugin-internationalized-array", functionCache = /* @__PURE__ */ new Map(), functionKeyCache = /* @__PURE__ */ new WeakMap(), promiseCache = /* @__PURE__ */ new Map();
11
+ function stringifyCacheKey(key) {
12
+ return JSON.stringify(key);
13
+ }
14
+ const preloadWithKey = (fn, key) => {
15
+ const keyStr = stringifyCacheKey(key);
16
+ promiseCache.has(keyStr) || promiseCache.set(keyStr, fn());
17
+ }, clear = () => {
18
+ promiseCache.clear();
19
+ }, peek = (selectedValue) => {
20
+ const key = stringifyCacheKey(["v1", namespace, selectedValue]), promise = promiseCache.get(key);
21
+ if (promise && promise._status === "fulfilled")
22
+ return promise._value;
23
+ }, createCacheKey = (selectedValue, workspaceId) => {
24
+ const selectedValueHash = JSON.stringify(selectedValue);
25
+ return workspaceId ? ["v1", namespace, selectedValueHash, workspaceId] : ["v1", namespace, selectedValueHash];
26
+ }, createOrGetPromise = (fn, key) => {
27
+ const keyStr = stringifyCacheKey(key);
28
+ if (promiseCache.has(keyStr))
29
+ return promiseCache.get(keyStr);
30
+ const promise = fn();
31
+ return promiseCache.set(keyStr, promise), promise;
32
+ }, getFunctionKey = (fn) => {
33
+ const cachedKey = functionKeyCache.get(fn);
34
+ if (cachedKey)
35
+ return cachedKey;
36
+ const fnStr = fn.toString();
37
+ let hash = 0;
38
+ const maxLength = Math.min(fnStr.length, 100);
39
+ for (let i = 0; i < maxLength; i++) {
40
+ const char = fnStr.charCodeAt(i);
41
+ hash = (hash << 5) - hash + char, hash &= hash;
42
+ }
43
+ const key = `anonymous_${Math.abs(hash)}`;
44
+ return functionKeyCache.set(fn, key), key;
45
+ }, createFunctionCacheKey = (fn, selectedValue, workspaceId) => {
46
+ const functionKey = getFunctionKey(fn), selectedValueHash = JSON.stringify(selectedValue);
47
+ return workspaceId ? `${functionKey}:${selectedValueHash}:${workspaceId}` : `${functionKey}:${selectedValueHash}`;
48
+ }, getFunctionCache = (fn, selectedValue, workspaceId) => {
49
+ const key = createFunctionCacheKey(fn, selectedValue, workspaceId);
50
+ return functionCache.get(key);
51
+ }, setFunctionCache = (fn, selectedValue, languages, workspaceId) => {
52
+ const key = createFunctionCacheKey(fn, selectedValue, workspaceId);
53
+ functionCache.set(key, languages);
54
+ }, MAX_COLUMNS = {
55
+ codeOnly: 5,
56
+ titleOnly: 4,
57
+ titleAndCode: 3
58
+ }, CONFIG_DEFAULT = {
59
+ languages: [],
60
+ select: {},
61
+ defaultLanguages: [],
62
+ fieldTypes: [],
63
+ apiVersion: "2025-10-15",
64
+ buttonLocations: ["field"],
65
+ buttonAddAll: !0,
66
+ languageDisplay: "codeOnly"
67
+ }, getDocumentsToTranslate = (value, rootPath = []) => {
68
+ if (Array.isArray(value)) {
69
+ const arrayRootPath = [...rootPath], internationalizedValues = value.filter((item) => {
70
+ if (Array.isArray(item)) return !1;
71
+ if (typeof item == "object") {
72
+ const type = item?._type;
73
+ return type?.startsWith("internationalizedArray") && type?.endsWith("Value");
74
+ }
75
+ return !1;
76
+ });
77
+ return internationalizedValues.length > 0 ? internationalizedValues.map((internationalizedValue) => Object.assign({}, internationalizedValue, {
78
+ path: arrayRootPath,
79
+ pathString: arrayRootPath.join(".")
80
+ })) : value.length > 0 ? value.flatMap((item, index) => getDocumentsToTranslate(item, [...arrayRootPath, index])) : [];
81
+ }
82
+ if (typeof value == "object" && value) {
83
+ const startsWithUnderscoreRegex = /^_/;
84
+ return Object.keys(value).filter((key) => !key.match(startsWithUnderscoreRegex)).flatMap((item) => {
85
+ const selectedValue = value[item], path = [...rootPath, item];
86
+ return getDocumentsToTranslate(selectedValue, path);
87
+ });
88
+ }
89
+ return [];
90
+ };
91
+ function getLanguageDisplay(languageDisplay, title, code) {
92
+ return languageDisplay === "codeOnly" ? code.toUpperCase() : languageDisplay === "titleOnly" ? title : languageDisplay === "titleAndCode" ? `${title} (${code.toUpperCase()})` : title;
93
+ }
94
+ function AddButtons(props) {
95
+ const $ = c(6), {
96
+ languages,
97
+ readOnly,
98
+ value,
99
+ onClick
100
+ } = props, {
101
+ languageDisplay
102
+ } = useInternationalizedArrayContext();
103
+ let t0;
104
+ return $[0] !== languageDisplay || $[1] !== languages || $[2] !== onClick || $[3] !== readOnly || $[4] !== value ? (t0 = languages.length > 0 ? /* @__PURE__ */ jsx(Grid, { columns: Math.min(languages.length, MAX_COLUMNS[languageDisplay]), gap: 2, children: languages.map((language) => {
105
+ const languageTitle = getLanguageDisplay(languageDisplay, language.title, language.id);
106
+ return /* @__PURE__ */ jsx(Button, { tone: "primary", mode: "ghost", fontSize: 1, disabled: readOnly || !!value?.find((item) => item._key === language.id), text: languageTitle, icon: languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === "codeOnly" ? void 0 : AddIcon, value: language.id, onClick }, language.id);
107
+ }) }) : null, $[0] = languageDisplay, $[1] = languages, $[2] = onClick, $[3] = readOnly, $[4] = value, $[5] = t0) : t0 = $[5], t0;
108
+ }
109
+ function DocumentAddButtons(props) {
110
+ const $ = c(13), {
111
+ filteredLanguages
112
+ } = useInternationalizedArrayContext(), value = isSanityDocument(props.value) ? props.value : void 0, toast = useToast(), {
113
+ onChange
114
+ } = useDocumentPane(), schema = useSchema();
115
+ let t0;
116
+ $[0] !== value ? (t0 = getDocumentsToTranslate(value, []), $[0] = value, $[1] = t0) : t0 = $[1];
117
+ const documentsToTranslation = t0;
118
+ let t1;
119
+ $[2] !== schema ? (t1 = (typeName) => {
120
+ if (!typeName)
121
+ return;
122
+ const match = typeName.match(/^internationalizedArray(.+)Value$/);
123
+ if (!match || !match[1])
124
+ return;
125
+ const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1), arrayBasedTypes = /* @__PURE__ */ new Set(["body", "htmlContent", "blockContent", "portableText"]);
126
+ if (arrayBasedTypes.has(baseTypeName))
127
+ return [];
128
+ const schemaType = schema.get(typeName);
129
+ if (schemaType && "fields" in schemaType) {
130
+ const valueField = schemaType.fields.find(_temp$2);
131
+ if (valueField) {
132
+ const fieldType = valueField.type;
133
+ if (fieldType?.jsonType === "array" || fieldType?.name === "array" || fieldType?.type === "array" || fieldType?.of !== void 0 || fieldType?.name && arrayBasedTypes.has(fieldType.name))
134
+ return [];
135
+ }
136
+ }
137
+ }, $[2] = schema, $[3] = t1) : t1 = $[3];
138
+ const getInitialValueForType = t1;
139
+ let t2;
140
+ $[4] !== documentsToTranslation || $[5] !== getInitialValueForType || $[6] !== onChange || $[7] !== toast ? (t2 = async (event) => {
141
+ const languageId = event.currentTarget.value;
142
+ if (!languageId) {
143
+ toast.push({
144
+ status: "error",
145
+ title: "No language selected"
146
+ });
147
+ return;
148
+ }
149
+ const alreadyTranslated = documentsToTranslation.filter((translation) => translation?._key === languageId), removeDuplicates = documentsToTranslation.reduce((filteredTranslations, translation_0) => (alreadyTranslated.filter((alreadyTranslation) => alreadyTranslation.pathString === translation_0.pathString).length > 0 || filteredTranslations.filter((filteredTranslation) => filteredTranslation.path === translation_0.path).length > 0 || filteredTranslations.push(translation_0), filteredTranslations), []);
150
+ if (removeDuplicates.length === 0) {
151
+ toast.push({
152
+ status: "error",
153
+ title: "No internationalizedArray fields found in document root"
154
+ });
155
+ return;
156
+ }
157
+ const patches = [];
158
+ for (const toTranslate of removeDuplicates) {
159
+ const path = toTranslate.path, initialValue = getInitialValueForType(toTranslate._type), ifMissing = setIfMissing([], path), insertValue = insert([{
160
+ _key: languageId,
161
+ _type: toTranslate._type,
162
+ value: initialValue
163
+ }], "after", [...path, -1]);
164
+ patches.push(ifMissing), patches.push(insertValue);
165
+ }
166
+ onChange(PatchEvent.from(patches.flat()));
167
+ }, $[4] = documentsToTranslation, $[5] = getInitialValueForType, $[6] = onChange, $[7] = toast, $[8] = t2) : t2 = $[8];
168
+ const handleDocumentButtonClick = t2;
169
+ let t3;
170
+ $[9] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Add translation to internationalized fields" }) }), $[9] = t3) : t3 = $[9];
171
+ let t4;
172
+ return $[10] !== filteredLanguages || $[11] !== handleDocumentButtonClick ? (t4 = /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
173
+ t3,
174
+ /* @__PURE__ */ jsx(AddButtons, { languages: filteredLanguages, readOnly: !1, value: void 0, onClick: handleDocumentButtonClick })
175
+ ] }), $[10] = filteredLanguages, $[11] = handleDocumentButtonClick, $[12] = t4) : t4 = $[12], t4;
176
+ }
177
+ function _temp$2(f) {
178
+ return f.name === "value";
179
+ }
180
+ const getSelectedValue = (select, document) => {
181
+ if (!select || !document)
182
+ return {};
183
+ const selection = select || {}, selectedValue = {};
184
+ for (const [key, path] of Object.entries(selection)) {
185
+ let value = get(document, path);
186
+ Array.isArray(value) && (value = value.filter((item) => typeof item == "object" ? item?._type === "reference" && "_ref" in item : !0)), selectedValue[key] = value;
187
+ }
188
+ return selectedValue;
189
+ }, InternationalizedArrayContext = createContext({
190
+ ...CONFIG_DEFAULT,
191
+ languages: [],
192
+ filteredLanguages: []
193
+ });
194
+ function useInternationalizedArrayContext() {
195
+ return useContext(InternationalizedArrayContext);
196
+ }
197
+ function InternationalizedArrayProvider(props) {
198
+ const $ = c(38), {
199
+ internationalizedArray: internationalizedArray2
200
+ } = props;
201
+ let t0;
202
+ $[0] !== internationalizedArray2.apiVersion ? (t0 = {
203
+ apiVersion: internationalizedArray2.apiVersion
204
+ }, $[0] = internationalizedArray2.apiVersion, $[1] = t0) : t0 = $[1];
205
+ const client = useClient(t0), workspace = useWorkspace(), {
206
+ formState
207
+ } = useDocumentPane(), deferredDocument = useDeferredValue(formState?.value);
208
+ let t1;
209
+ $[2] !== deferredDocument || $[3] !== internationalizedArray2.select ? (t1 = getSelectedValue(internationalizedArray2.select, deferredDocument), $[2] = deferredDocument, $[3] = internationalizedArray2.select, $[4] = t1) : t1 = $[4];
210
+ const selectedValue = t1;
211
+ let t2;
212
+ bb0: {
213
+ if (workspace?.name) {
214
+ t2 = workspace.name;
215
+ break bb0;
216
+ }
217
+ const t32 = workspace?.name, t42 = workspace?.title;
218
+ let t52;
219
+ $[5] !== t32 || $[6] !== t42 ? (t52 = JSON.stringify({
220
+ name: t32,
221
+ title: t42
222
+ }), $[5] = t32, $[6] = t42, $[7] = t52) : t52 = $[7], t2 = t52;
223
+ }
224
+ const workspaceId = t2;
225
+ let t3;
226
+ $[8] !== selectedValue || $[9] !== workspaceId ? (t3 = createCacheKey(selectedValue, workspaceId), $[8] = selectedValue, $[9] = workspaceId, $[10] = t3) : t3 = $[10];
227
+ const cacheKey = t3;
228
+ let t4;
229
+ bb1: {
230
+ if (Array.isArray(internationalizedArray2.languages)) {
231
+ t4 = null;
232
+ break bb1;
233
+ }
234
+ let t52;
235
+ $[11] !== client || $[12] !== internationalizedArray2 || $[13] !== selectedValue || $[14] !== workspaceId ? (t52 = async () => {
236
+ if (typeof internationalizedArray2.languages == "function") {
237
+ const result = await internationalizedArray2.languages(client, selectedValue);
238
+ return setFunctionCache(internationalizedArray2.languages, selectedValue, result, workspaceId), result;
239
+ }
240
+ return internationalizedArray2.languages;
241
+ }, $[11] = client, $[12] = internationalizedArray2, $[13] = selectedValue, $[14] = workspaceId, $[15] = t52) : t52 = $[15];
242
+ let t62;
243
+ $[16] !== cacheKey || $[17] !== t52 ? (t62 = createOrGetPromise(t52, cacheKey), $[16] = cacheKey, $[17] = t52, $[18] = t62) : t62 = $[18], t4 = t62;
244
+ }
245
+ const languagesPromise = t4, languages = languagesPromise ? use(languagesPromise) : internationalizedArray2.languages, {
246
+ selectedLanguageIds,
247
+ options: languageFilterOptions
248
+ } = useLanguageFilterStudioContext(), documentType = deferredDocument ? deferredDocument._type : void 0;
249
+ let t5;
250
+ $[19] !== documentType || $[20] !== languageFilterOptions ? (t5 = typeof documentType == "string" && languageFilterOptions.documentTypes.includes(documentType), $[19] = documentType, $[20] = languageFilterOptions, $[21] = t5) : t5 = $[21];
251
+ const languageFilterEnabled = t5;
252
+ let t6;
253
+ $[22] !== languageFilterEnabled || $[23] !== languages || $[24] !== selectedLanguageIds ? (t6 = languageFilterEnabled ? languages.filter((language) => selectedLanguageIds.includes(language.id)) : languages, $[22] = languageFilterEnabled, $[23] = languages, $[24] = selectedLanguageIds, $[25] = t6) : t6 = $[25];
254
+ const filteredLanguages = t6;
255
+ let t7;
256
+ $[26] !== internationalizedArray2.buttonLocations ? (t7 = internationalizedArray2.buttonLocations.includes("document"), $[26] = internationalizedArray2.buttonLocations, $[27] = t7) : t7 = $[27];
257
+ const showDocumentButtons = t7;
258
+ let t8;
259
+ $[28] !== filteredLanguages || $[29] !== internationalizedArray2 || $[30] !== languages ? (t8 = {
260
+ ...internationalizedArray2,
261
+ languages,
262
+ filteredLanguages
263
+ }, $[28] = filteredLanguages, $[29] = internationalizedArray2, $[30] = languages, $[31] = t8) : t8 = $[31];
264
+ const context = t8;
265
+ let t9;
266
+ $[32] !== props || $[33] !== showDocumentButtons ? (t9 = showDocumentButtons ? /* @__PURE__ */ jsxs(Stack, { space: 5, children: [
267
+ /* @__PURE__ */ jsx(DocumentAddButtons, { value: props.value }),
268
+ props.renderDefault(props)
269
+ ] }) : props.renderDefault(props), $[32] = props, $[33] = showDocumentButtons, $[34] = t9) : t9 = $[34];
270
+ let t10;
271
+ return $[35] !== context || $[36] !== t9 ? (t10 = /* @__PURE__ */ jsx(InternationalizedArrayContext.Provider, { value: context, children: t9 }), $[35] = context, $[36] = t9, $[37] = t10) : t10 = $[37], t10;
272
+ }
273
+ function InternationalizedField(props) {
274
+ const $ = c(9), {
275
+ languages
276
+ } = useInternationalizedArrayContext(), pathSegment = props.path.slice(0, -1)[1], languageId = typeof pathSegment == "object" && "_key" in pathSegment ? pathSegment._key : void 0, hasValidLanguageId = languageId ? languages.some((l) => l.id === languageId) : !1, t0 = props.title?.toLowerCase() === "value" && hasValidLanguageId ? "" : props.title;
277
+ let t1;
278
+ $[0] !== props || $[1] !== t0 ? (t1 = {
279
+ ...props,
280
+ title: t0
281
+ }, $[0] = props, $[1] = t0, $[2] = t1) : t1 = $[2];
282
+ const customProps = t1;
283
+ if (!customProps.schemaType.name.startsWith("internationalizedArray")) {
284
+ let t22;
285
+ return $[3] !== customProps ? (t22 = customProps.renderDefault(customProps), $[3] = customProps, $[4] = t22) : t22 = $[4], t22;
286
+ }
287
+ if (customProps.schemaType.name === "reference" && customProps.value) {
288
+ let t22;
289
+ return $[5] !== customProps ? (t22 = customProps.renderDefault({
290
+ ...customProps,
291
+ title: "",
292
+ level: 0
293
+ }), $[5] = customProps, $[6] = t22) : t22 = $[6], t22;
294
+ }
295
+ if (customProps.schemaType.name === "string" || customProps.schemaType.name === "number" || customProps.schemaType.name === "text")
296
+ return customProps.children;
297
+ let t2;
298
+ return $[7] !== customProps ? (t2 = customProps.renderDefault({
299
+ ...customProps,
300
+ level: 0
301
+ }), $[7] = customProps, $[8] = t2) : t2 = $[8], t2;
302
+ }
303
+ function Preload(props) {
304
+ const $ = c(2);
305
+ let t0;
306
+ $[0] !== props.apiVersion ? (t0 = {
307
+ apiVersion: props.apiVersion
308
+ }, $[0] = props.apiVersion, $[1] = t0) : t0 = $[1];
309
+ const client = useClient(t0), cacheKey = createCacheKey({});
310
+ return Array.isArray(peek({})) || preloadWithKey(async () => {
311
+ if (Array.isArray(props.languages))
312
+ return props.languages;
313
+ const result = await props.languages(client, {});
314
+ return setFunctionCache(props.languages, {}, result), result;
315
+ }, cacheKey), null;
316
+ }
317
+ function checkAllLanguagesArePresent(languages, value) {
318
+ const filteredLanguageIds = languages.map((l) => l.id), languagesInUseIds = value ? value.map((v) => v._key) : [];
319
+ return languagesInUseIds.length === filteredLanguageIds.length && languagesInUseIds.every((l) => filteredLanguageIds.includes(l));
320
+ }
321
+ function createAddAllTitle(value, languages) {
322
+ return value?.length ? `Add missing ${languages.length - value.length === 1 ? "language" : "languages"}` : languages.length === 1 && languages[0] ? `Add ${languages[0].title} Field` : "Add all languages";
323
+ }
324
+ function createValueSchemaTypeName(schemaType) {
325
+ return `${schemaType.name}Value`;
326
+ }
327
+ function createAddLanguagePatches(config) {
328
+ const {
329
+ addLanguageKeys,
330
+ schemaType,
331
+ languages,
332
+ filteredLanguages,
333
+ value,
334
+ path = []
335
+ } = config, itemBase = {
336
+ _type: createValueSchemaTypeName(schemaType)
337
+ }, newItems = Array.isArray(addLanguageKeys) && addLanguageKeys.length > 0 ? addLanguageKeys.map((id) => Object.assign({}, itemBase, {
338
+ _key: id
339
+ })) : filteredLanguages.filter((language) => value?.length ? !value.find((v) => v._key === language.id) : !0).map((language) => Object.assign({}, itemBase, {
340
+ _key: language.id
341
+ })), languagesInUse = value?.length ? value.map((v) => v) : [];
342
+ return newItems.map((item) => {
343
+ const languageIndex = languages.findIndex((l) => item._key === l.id), remainingLanguages = languages.slice(languageIndex + 1), nextLanguageIndex = languagesInUse.findIndex((l) => remainingLanguages.find((r) => r.id === l._key));
344
+ return nextLanguageIndex < 0 ? languagesInUse.push(item) : languagesInUse.splice(nextLanguageIndex, 0, item), nextLanguageIndex < 0 ? (
345
+ // No next language (-1), add to end of array
346
+ insert([item], "after", [...path, nextLanguageIndex])
347
+ ) : (
348
+ // Next language found, insert before that
349
+ insert([item], "before", [...path, nextLanguageIndex])
350
+ );
351
+ });
352
+ }
353
+ const createTranslateFieldActions = (fieldActionProps, {
354
+ languages,
355
+ filteredLanguages
356
+ }) => languages.map((language) => {
357
+ const value = useFormValue(fieldActionProps.path), disabled = value && Array.isArray(value) ? !!value?.find((item) => item._key === language.id) : !1, hidden = !filteredLanguages.some((f) => f.id === language.id), {
358
+ onChange
359
+ } = useDocumentPane(), onAction = useCallback(() => {
360
+ const {
361
+ schemaType,
362
+ path
363
+ } = fieldActionProps, addLanguageKeys = [language.id], patches = createAddLanguagePatches({
364
+ addLanguageKeys,
365
+ schemaType,
366
+ languages,
367
+ filteredLanguages,
368
+ value,
369
+ path
370
+ });
371
+ onChange(PatchEvent.from([setIfMissing([], path), ...patches]));
372
+ }, [language.id, value, onChange]);
373
+ return {
374
+ type: "action",
375
+ icon: AddIcon,
376
+ onAction,
377
+ title: language.title,
378
+ hidden,
379
+ disabled
380
+ };
381
+ }), AddMissingTranslationsFieldAction = (fieldActionProps, {
382
+ languages,
383
+ filteredLanguages
384
+ }) => {
385
+ const value = useFormValue(fieldActionProps.path), disabled = value && value.length === filteredLanguages.length, hidden = checkAllLanguagesArePresent(filteredLanguages, value), {
386
+ onChange
387
+ } = useDocumentPane(), onAction = useCallback(() => {
388
+ const {
389
+ schemaType,
390
+ path
391
+ } = fieldActionProps, patches = createAddLanguagePatches({
392
+ addLanguageKeys: [],
393
+ schemaType,
394
+ languages,
395
+ filteredLanguages,
396
+ value,
397
+ path
398
+ });
399
+ onChange(PatchEvent.from([setIfMissing([], path), ...patches]));
400
+ }, [fieldActionProps, filteredLanguages, languages, onChange, value]);
401
+ return {
402
+ type: "action",
403
+ icon: AddIcon,
404
+ onAction,
405
+ title: createAddAllTitle(value, filteredLanguages),
406
+ disabled,
407
+ hidden
408
+ };
409
+ }, internationalizedArrayFieldAction = defineDocumentFieldAction({
410
+ name: "internationalizedArray",
411
+ useAction(fieldActionProps) {
412
+ const isInternationalizedArrayField = fieldActionProps?.schemaType?.type?.name.startsWith("internationalizedArray"), {
413
+ languages,
414
+ filteredLanguages
415
+ } = useInternationalizedArrayContext(), translateFieldActions = createTranslateFieldActions(fieldActionProps, {
416
+ languages,
417
+ filteredLanguages
418
+ });
419
+ return {
420
+ type: "group",
421
+ icon: TranslateIcon,
422
+ title: "Add Translation",
423
+ renderAsButton: !0,
424
+ children: isInternationalizedArrayField ? [...translateFieldActions, AddMissingTranslationsFieldAction(fieldActionProps, {
425
+ languages,
426
+ filteredLanguages
427
+ })] : [],
428
+ hidden: !isInternationalizedArrayField
429
+ };
430
+ }
431
+ });
432
+ function pascalCase(string) {
433
+ return upperFirst(camelCase(string));
434
+ }
435
+ function createFieldName(name, addValue = !1) {
436
+ return addValue ? ["internationalizedArray", pascalCase(name), "Value"].join("") : ["internationalizedArray", pascalCase(name)].join("");
437
+ }
438
+ const schemaExample = {
439
+ languages: [{
440
+ id: "en",
441
+ title: "English"
442
+ }, {
443
+ id: "no",
444
+ title: "Norsk"
445
+ }]
446
+ };
447
+ function Feedback() {
448
+ const $ = c(4);
449
+ let t0;
450
+ $[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("code", { children: "internationalizedArray" }), $[0] = t0) : t0 = $[0];
451
+ let t1;
452
+ $[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx("code", { children: "id" }), $[1] = t1) : t1 = $[1];
453
+ let t2;
454
+ $[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsxs(Text, { children: [
455
+ "An array of language objects must be passed into the ",
456
+ t0,
457
+ " ",
458
+ "helper function, each with an ",
459
+ t1,
460
+ " and ",
461
+ /* @__PURE__ */ jsx("code", { children: "title" }),
462
+ " field. Example:"
463
+ ] }), $[2] = t2) : t2 = $[2];
464
+ let t3;
465
+ return $[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Card, { tone: "caution", border: !0, radius: 2, padding: 3, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
466
+ t2,
467
+ /* @__PURE__ */ jsx(Card, { padding: 2, border: !0, radius: 2, children: /* @__PURE__ */ jsx(Code, { size: 1, language: "javascript", children: JSON.stringify(schemaExample, null, 2) }) })
468
+ ] }) }), $[3] = t3) : t3 = $[3], t3;
469
+ }
470
+ function InternationalizedArray(props) {
471
+ const $ = c(85), {
472
+ members,
473
+ value,
474
+ schemaType,
475
+ onChange,
476
+ readOnly: documentReadOnly
477
+ } = props, readOnly = typeof schemaType.readOnly == "boolean" ? schemaType.readOnly : !1, toast = useToast(), {
478
+ languages,
479
+ filteredLanguages,
480
+ defaultLanguages,
481
+ buttonAddAll,
482
+ buttonLocations
483
+ } = useInternationalizedArrayContext(), {
484
+ selectedLanguageIds,
485
+ options: languageFilterOptions
486
+ } = useLanguageFilterStudioContext();
487
+ let t0;
488
+ $[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t0 = ["_type"], $[0] = t0) : t0 = $[0];
489
+ const documentType = useFormValue(t0);
490
+ let t1;
491
+ $[1] !== documentType || $[2] !== languageFilterOptions ? (t1 = typeof documentType == "string" && languageFilterOptions.documentTypes.includes(documentType), $[1] = documentType, $[2] = languageFilterOptions, $[3] = t1) : t1 = $[3];
492
+ const languageFilterEnabled = t1;
493
+ let t2;
494
+ $[4] !== languageFilterEnabled || $[5] !== languageFilterOptions || $[6] !== members || $[7] !== selectedLanguageIds ? (t2 = languageFilterEnabled ? members.filter((member) => {
495
+ if (member.kind !== "item")
496
+ return !1;
497
+ const valueMember = member.item.members[0];
498
+ return !valueMember || valueMember.kind !== "field" ? !1 : languageFilterOptions.filterField(member.item.schemaType, valueMember, selectedLanguageIds);
499
+ }) : members, $[4] = languageFilterEnabled, $[5] = languageFilterOptions, $[6] = members, $[7] = selectedLanguageIds, $[8] = t2) : t2 = $[8];
500
+ const filteredMembers = t2;
501
+ let t3;
502
+ $[9] !== filteredLanguages || $[10] !== languages || $[11] !== onChange || $[12] !== schemaType || $[13] !== value ? (t3 = async (param) => {
503
+ if (!filteredLanguages?.length)
504
+ return;
505
+ const addLanguageKeys = Array.isArray(param) ? param : [param?.currentTarget?.value].filter(Boolean), patches = createAddLanguagePatches({
506
+ addLanguageKeys,
507
+ schemaType,
508
+ languages,
509
+ filteredLanguages,
510
+ value
511
+ });
512
+ onChange([setIfMissing([]), ...patches]);
513
+ }, $[9] = filteredLanguages, $[10] = languages, $[11] = onChange, $[12] = schemaType, $[13] = value, $[14] = t3) : t3 = $[14];
514
+ const handleAddLanguage = t3, {
515
+ isDeleting
516
+ } = useDocumentPane();
517
+ let addedLanguages, t4;
518
+ if ($[15] !== defaultLanguages || $[16] !== languages || $[17] !== members) {
519
+ addedLanguages = members.map(_temp$1);
520
+ let t52;
521
+ $[20] !== languages ? (t52 = (language) => languages.find((l) => l.id === language), $[20] = languages, $[21] = t52) : t52 = $[21], t4 = defaultLanguages.filter(t52).every((language_0) => addedLanguages.includes(language_0)), $[15] = defaultLanguages, $[16] = languages, $[17] = members, $[18] = addedLanguages, $[19] = t4;
522
+ } else
523
+ addedLanguages = $[18], t4 = $[19];
524
+ const hasAddedDefaultLanguages = t4;
525
+ let t5, t6;
526
+ $[22] !== addedLanguages || $[23] !== defaultLanguages || $[24] !== documentReadOnly || $[25] !== handleAddLanguage || $[26] !== hasAddedDefaultLanguages || $[27] !== isDeleting || $[28] !== languages ? (t5 = () => {
527
+ if (!isDeleting && !hasAddedDefaultLanguages) {
528
+ const languagesToAdd = defaultLanguages.filter((language_1) => !addedLanguages.includes(language_1)).filter((language_2) => languages.find((l_0) => l_0.id === language_2)), timeout = setTimeout(() => {
529
+ documentReadOnly || handleAddLanguage(languagesToAdd);
530
+ });
531
+ return () => clearTimeout(timeout);
532
+ }
533
+ }, t6 = [isDeleting, hasAddedDefaultLanguages, handleAddLanguage, defaultLanguages, addedLanguages, languages, documentReadOnly], $[22] = addedLanguages, $[23] = defaultLanguages, $[24] = documentReadOnly, $[25] = handleAddLanguage, $[26] = hasAddedDefaultLanguages, $[27] = isDeleting, $[28] = languages, $[29] = t5, $[30] = t6) : (t5 = $[29], t6 = $[30]), useEffect(t5, t6);
534
+ let t7;
535
+ $[31] !== languages || $[32] !== onChange || $[33] !== toast || $[34] !== value ? (t7 = () => {
536
+ if (!value?.length || !languages?.length)
537
+ return;
538
+ const updatedValue = value.reduce((acc, v) => {
539
+ const newIndex = languages.findIndex((l_1) => l_1.id === v?._key);
540
+ return newIndex > -1 && (acc[newIndex] = v), acc;
541
+ }, []).filter(Boolean);
542
+ value?.length !== updatedValue.length && toast.push({
543
+ title: "There was an error reordering languages",
544
+ status: "warning"
545
+ }), onChange(set(updatedValue));
546
+ }, $[31] = languages, $[32] = onChange, $[33] = toast, $[34] = value, $[35] = t7) : t7 = $[35];
547
+ const handleRestoreOrder = t7;
548
+ let t8;
549
+ bb0: {
550
+ if (!value?.length || !languages?.length) {
551
+ t8 = !0;
552
+ break bb0;
553
+ }
554
+ let t92;
555
+ $[36] !== languages || $[37] !== value ? (t92 = value?.every((v_0) => languages.find((l_2) => l_2?.id === v_0?._key)), $[36] = languages, $[37] = value, $[38] = t92) : t92 = $[38], t8 = t92;
556
+ }
557
+ const allKeysAreLanguages = t8;
558
+ let t9;
559
+ $[39] !== languages || $[40] !== value ? (t9 = languages && languages.length > 1 ? languages.filter((l_3) => value?.find((v_1) => v_1._key === l_3.id)) : [], $[39] = languages, $[40] = value, $[41] = t9) : t9 = $[41];
560
+ const languagesInUse = t9;
561
+ let t10;
562
+ bb1: {
563
+ if (!value?.length || !languagesInUse.length) {
564
+ let t113;
565
+ $[42] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t113 = [], $[42] = t113) : t113 = $[42], t10 = t113;
566
+ break bb1;
567
+ }
568
+ let t112;
569
+ if ($[43] !== languagesInUse || $[44] !== value) {
570
+ let t122;
571
+ $[46] !== languagesInUse ? (t122 = (v_2, vIndex) => vIndex === languagesInUse.findIndex((l_4) => l_4.id === v_2._key) ? null : v_2, $[46] = languagesInUse, $[47] = t122) : t122 = $[47], t112 = value.map(t122).filter(Boolean), $[43] = languagesInUse, $[44] = value, $[45] = t112;
572
+ } else
573
+ t112 = $[45];
574
+ t10 = t112;
575
+ }
576
+ const languagesOutOfOrder = t10, languagesAreValid = !languages?.length || languages?.length && languages.every(_temp2$1);
577
+ let t11;
578
+ $[48] !== allKeysAreLanguages || $[49] !== documentReadOnly || $[50] !== handleRestoreOrder || $[51] !== languagesOutOfOrder.length ? (t11 = () => {
579
+ languagesOutOfOrder.length > 0 && allKeysAreLanguages && !documentReadOnly && handleRestoreOrder();
580
+ }, $[48] = allKeysAreLanguages, $[49] = documentReadOnly, $[50] = handleRestoreOrder, $[51] = languagesOutOfOrder.length, $[52] = t11) : t11 = $[52];
581
+ let t12;
582
+ $[53] !== allKeysAreLanguages || $[54] !== documentReadOnly || $[55] !== handleRestoreOrder || $[56] !== languagesOutOfOrder ? (t12 = [languagesOutOfOrder, allKeysAreLanguages, handleRestoreOrder, documentReadOnly], $[53] = allKeysAreLanguages, $[54] = documentReadOnly, $[55] = handleRestoreOrder, $[56] = languagesOutOfOrder, $[57] = t12) : t12 = $[57], useEffect(t11, t12);
583
+ let t13;
584
+ $[58] !== filteredLanguages || $[59] !== value ? (t13 = checkAllLanguagesArePresent(filteredLanguages, value), $[58] = filteredLanguages, $[59] = value, $[60] = t13) : t13 = $[60];
585
+ const allLanguagesArePresent = t13;
586
+ if (!languagesAreValid) {
587
+ let t142;
588
+ return $[61] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t142 = /* @__PURE__ */ jsx(Feedback, {}), $[61] = t142) : t142 = $[61], t142;
589
+ }
590
+ let t14;
591
+ $[62] !== allLanguagesArePresent || $[63] !== buttonLocations || $[64] !== filteredLanguages?.length ? (t14 = buttonLocations.includes("field") && filteredLanguages?.length > 0 && !allLanguagesArePresent, $[62] = allLanguagesArePresent, $[63] = buttonLocations, $[64] = filteredLanguages?.length, $[65] = t14) : t14 = $[65];
592
+ const addButtonsAreVisible = t14, fieldHasMembers = members?.length > 0;
593
+ let t15;
594
+ $[66] !== fieldHasMembers || $[67] !== filteredMembers || $[68] !== props ? (t15 = fieldHasMembers ? /* @__PURE__ */ jsx(Fragment, { children: filteredMembers.map((member_0) => member_0.kind === "item" ? /* @__PURE__ */ createElement(ArrayOfObjectsItem, { ...props, key: member_0.key, member: member_0 }) : /* @__PURE__ */ jsx(MemberItemError, { member: member_0 }, member_0.key)) }) : null, $[66] = fieldHasMembers, $[67] = filteredMembers, $[68] = props, $[69] = t15) : t15 = $[69];
595
+ let t16;
596
+ $[70] !== addButtonsAreVisible || $[71] !== fieldHasMembers ? (t16 = !addButtonsAreVisible && !fieldHasMembers ? /* @__PURE__ */ jsx(Card, { border: !0, tone: "transparent", padding: 3, radius: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: "This internationalized field currently has no translations." }) }) : null, $[70] = addButtonsAreVisible, $[71] = fieldHasMembers, $[72] = t16) : t16 = $[72];
597
+ let t17;
598
+ $[73] !== addButtonsAreVisible || $[74] !== allLanguagesArePresent || $[75] !== buttonAddAll || $[76] !== filteredLanguages || $[77] !== handleAddLanguage || $[78] !== readOnly || $[79] !== value ? (t17 = addButtonsAreVisible ? /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
599
+ /* @__PURE__ */ jsx(AddButtons, { languages: filteredLanguages, value, readOnly, onClick: handleAddLanguage }),
600
+ buttonAddAll ? /* @__PURE__ */ jsx(Button, { tone: "primary", mode: "ghost", disabled: readOnly || allLanguagesArePresent, icon: AddIcon, text: createAddAllTitle(value, filteredLanguages), onClick: handleAddLanguage }) : null
601
+ ] }) : null, $[73] = addButtonsAreVisible, $[74] = allLanguagesArePresent, $[75] = buttonAddAll, $[76] = filteredLanguages, $[77] = handleAddLanguage, $[78] = readOnly, $[79] = value, $[80] = t17) : t17 = $[80];
602
+ let t18;
603
+ return $[81] !== t15 || $[82] !== t16 || $[83] !== t17 ? (t18 = /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
604
+ t15,
605
+ t16,
606
+ t17
607
+ ] }), $[81] = t15, $[82] = t16, $[83] = t17, $[84] = t18) : t18 = $[84], t18;
608
+ }
609
+ function _temp2$1(item) {
610
+ return item.id && item.title;
611
+ }
612
+ function _temp$1(t0) {
613
+ const {
614
+ key
615
+ } = t0;
616
+ return key;
617
+ }
618
+ function getLanguagesFieldOption(schemaType) {
619
+ return schemaType ? schemaType.options?.languages || getLanguagesFieldOption(schemaType.type) : void 0;
620
+ }
621
+ var array = (config) => {
622
+ const {
623
+ apiVersion,
624
+ select,
625
+ languages,
626
+ type
627
+ } = config, typeName = typeof type == "string" ? type : type.name, arrayName = createFieldName(typeName), objectName = createFieldName(typeName, !0);
628
+ return defineField({
629
+ name: arrayName,
630
+ title: "Internationalized array",
631
+ type: "array",
632
+ components: {
633
+ input: InternationalizedArray
634
+ },
635
+ options: {
636
+ // @ts-expect-error - these options are required for validation rules – not the custom input component
637
+ apiVersion,
638
+ select,
639
+ languages
640
+ },
641
+ of: [defineField({
642
+ ...typeof type == "string" ? {} : type,
643
+ name: objectName,
644
+ type: objectName
645
+ })],
646
+ // @ts-expect-error - fix typings
647
+ validation: (rule) => rule.custom(async (value, context) => {
648
+ if (!value || value.length === 0 || value.length === 1 && !value[0]?._key)
649
+ return !0;
650
+ const selectedValue = getSelectedValue(select, context.document), client = context.getClient({
651
+ apiVersion
652
+ });
653
+ let contextLanguages = [];
654
+ const languagesFieldOption = getLanguagesFieldOption(context?.type);
655
+ if (Array.isArray(languagesFieldOption))
656
+ contextLanguages = languagesFieldOption;
657
+ else if (Array.isArray(peek(selectedValue)))
658
+ contextLanguages = peek(selectedValue) || [];
659
+ else if (typeof languagesFieldOption == "function") {
660
+ const cachedLanguages = getFunctionCache(languagesFieldOption, selectedValue);
661
+ if (Array.isArray(cachedLanguages))
662
+ contextLanguages = cachedLanguages;
663
+ else {
664
+ const suspendCachedLanguages = peek(selectedValue);
665
+ Array.isArray(suspendCachedLanguages) ? contextLanguages = suspendCachedLanguages : (contextLanguages = await languagesFieldOption(client, selectedValue), setFunctionCache(languagesFieldOption, selectedValue, contextLanguages));
666
+ }
667
+ }
668
+ if (value && value.length > contextLanguages.length)
669
+ return `Cannot be more than ${contextLanguages.length === 1 ? "1 item" : `${contextLanguages.length} items`}`;
670
+ const languageIds = new Set(contextLanguages.map((lang) => lang.id)), nonLanguageKeys = value.filter((item) => item?._key && !languageIds.has(item._key));
671
+ if (nonLanguageKeys.length)
672
+ return {
673
+ message: "Array item keys must be valid languages registered to the field type",
674
+ paths: nonLanguageKeys.map((item) => [{
675
+ _key: item._key
676
+ }])
677
+ };
678
+ const seenKeys = /* @__PURE__ */ new Set(), duplicateValues = [];
679
+ for (const item of value)
680
+ item?._key && (seenKeys.has(item._key) ? duplicateValues.push(item) : seenKeys.add(item._key));
681
+ return duplicateValues.length ? {
682
+ message: "There can only be one field per language",
683
+ paths: duplicateValues.map((item) => [{
684
+ _key: item._key
685
+ }])
686
+ } : !0;
687
+ })
688
+ });
689
+ };
690
+ function getToneFromValidation(validations) {
691
+ if (!validations?.length)
692
+ return;
693
+ const validationLevels = new Set(validations.map((v) => v.level));
694
+ if (validationLevels.has("error"))
695
+ return "critical";
696
+ if (validationLevels.has("warning"))
697
+ return "caution";
698
+ }
699
+ function InternationalizedInput(props) {
700
+ const $ = c(13);
701
+ let t0;
702
+ $[0] !== props.path ? (t0 = props.path.slice(0, -1), $[0] = props.path, $[1] = t0) : t0 = $[1];
703
+ const parentValue = useFormValue(t0), originalOnChange = props.inputProps.onChange;
704
+ let t1;
705
+ $[2] !== originalOnChange || $[3] !== props.value?.value ? (t1 = (patches) => {
706
+ if (!Array.isArray(patches))
707
+ return originalOnChange(patches);
708
+ const valueField = props.value?.value;
709
+ if ((valueField == null || Array.isArray(valueField) && valueField.length === 0) && patches.some(_temp)) {
710
+ const initPatch = valueField === void 0 ? {
711
+ type: "setIfMissing",
712
+ path: ["value"],
713
+ value: []
714
+ } : null, fixedPatches = patches.map(_temp2), allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches;
715
+ return originalOnChange(allPatches);
716
+ }
717
+ return originalOnChange(patches);
718
+ }, $[2] = originalOnChange, $[3] = props.value?.value, $[4] = t1) : t1 = $[4];
719
+ const wrappedOnChange = t1, inlineProps = {
720
+ ...props.inputProps,
721
+ members: props.inputProps.members.filter(_temp3),
722
+ value: props.value,
723
+ onChange: wrappedOnChange
724
+ }, {
725
+ validation,
726
+ value,
727
+ onChange,
728
+ readOnly
729
+ } = inlineProps, {
730
+ languages,
731
+ languageDisplay,
732
+ defaultLanguages
733
+ } = useInternationalizedArrayContext();
734
+ let t2;
735
+ $[5] !== parentValue ? (t2 = parentValue?.map(_temp4) ?? [], $[5] = parentValue, $[6] = t2) : t2 = $[6];
736
+ const languageKeysInUse = t2, keyIsValid = languages?.length ? languages.find((l) => l.id === value._key) : !1, handleKeyChange = (event) => {
737
+ const languageId = event?.currentTarget?.value;
738
+ !value || !languages?.length || !languages.find((l_0) => l_0.id === languageId) || onChange([set(languageId, ["_key"])]);
739
+ }, handleUnset = () => {
740
+ onChange(unset());
741
+ };
742
+ if (!languages) {
743
+ let t32;
744
+ return $[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t32 = /* @__PURE__ */ jsx(Spinner, {}), $[7] = t32) : t32 = $[7], t32;
745
+ }
746
+ const language = languages.find((l_1) => l_1.id === value._key), languageTitle = keyIsValid && language ? getLanguageDisplay(languageDisplay, language.title, language.id) : "", isDefault = defaultLanguages.includes(value._key), removeButton = /* @__PURE__ */ jsx(Button, { mode: "bleed", icon: RemoveCircleIcon, tone: "critical", disabled: readOnly || isDefault, onClick: handleUnset }), t3 = getToneFromValidation(validation), t4 = keyIsValid ? /* @__PURE__ */ jsx(Label, { muted: !0, size: 1, children: languageTitle }) : /* @__PURE__ */ jsx(MenuButton, { button: /* @__PURE__ */ jsx(Button, { fontSize: 1, text: `Change "${value._key}"` }), id: `${value._key}-change-key`, menu: /* @__PURE__ */ jsx(Menu, { children: languages.map((lang) => /* @__PURE__ */ jsx(MenuItem, { disabled: languageKeysInUse.includes(lang.id), fontSize: 1, text: lang.id.toLocaleUpperCase(), value: lang.id, onClick: handleKeyChange }, lang.id)) }), popover: {
747
+ portal: !0
748
+ } });
749
+ let t5;
750
+ $[8] !== t4 ? (t5 = /* @__PURE__ */ jsx(Card, { tone: "inherit", children: t4 }), $[8] = t4, $[9] = t5) : t5 = $[9];
751
+ const T0 = Card, t6 = 1, t7 = "inherit", t8 = props.inputProps.renderInput(inlineProps);
752
+ let t9;
753
+ return $[10] !== T0 || $[11] !== t8 ? (t9 = /* @__PURE__ */ jsx(T0, { flex: t6, tone: t7, children: t8 }), $[10] = T0, $[11] = t8, $[12] = t9) : t9 = $[12], /* @__PURE__ */ jsx(Card, { paddingTop: 2, tone: t3, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
754
+ t5,
755
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
756
+ t9,
757
+ /* @__PURE__ */ jsx(Card, { tone: "inherit", children: isDefault ? /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Can't remove default language" }), fallbackPlacements: ["right", "left"], placement: "top", portal: !0, children: /* @__PURE__ */ jsx("span", { children: removeButton }) }) : removeButton })
758
+ ] })
759
+ ] }) });
760
+ }
761
+ function _temp4(v) {
762
+ return v._key;
763
+ }
764
+ function _temp3(m) {
765
+ return m.kind === "field" && m.name === "value";
766
+ }
767
+ function _temp2(patch_0) {
768
+ if (!patch_0 || typeof patch_0 != "object")
769
+ return patch_0;
770
+ if (patch_0.type === "insert" && patch_0.path && Array.isArray(patch_0.path)) {
771
+ const fixedPath = patch_0.path[0] === "value" ? patch_0.path : ["value", ...patch_0.path];
772
+ return {
773
+ ...patch_0,
774
+ path: fixedPath
775
+ };
776
+ }
777
+ return patch_0;
778
+ }
779
+ function _temp(patch) {
780
+ return !patch || typeof patch != "object" ? !1 : patch.type === "insert" && patch.path && Array.isArray(patch.path) && patch.path.length > 0 ? patch.path[0] === "value" || typeof patch.path[0] == "number" : !1;
781
+ }
782
+ var object = (config) => {
783
+ const {
784
+ type
785
+ } = config, typeName = typeof type == "string" ? type : type.name, objectName = createFieldName(typeName, !0);
786
+ return defineField({
787
+ name: objectName,
788
+ title: `Internationalized array ${typeName}`,
789
+ type: "object",
790
+ components: {
791
+ // @ts-expect-error - fix typings
792
+ item: InternationalizedInput
793
+ },
794
+ fields: [defineField({
795
+ ...typeof type == "string" ? {
796
+ type
797
+ } : type,
798
+ name: "value"
799
+ })],
800
+ preview: {
801
+ select: {
802
+ title: "value",
803
+ subtitle: "_key"
804
+ }
805
+ }
806
+ });
807
+ };
808
+ function flattenSchemaType(schemaType) {
809
+ return isDocumentSchemaType(schemaType) ? extractInnerFields(schemaType.fields, [], 3) : (console.error("Schema type is not a document"), []);
810
+ }
811
+ function extractInnerFields(fields, path, maxDepth) {
812
+ return path.length >= maxDepth ? [] : fields.reduce((acc, field) => {
813
+ const thisFieldWithPath = {
814
+ path: [...path, field.name],
815
+ ...field
816
+ };
817
+ if (field.type.jsonType === "object") {
818
+ const innerFields = extractInnerFields(field.type.fields, [...path, field.name], maxDepth);
819
+ return acc.push(thisFieldWithPath, ...innerFields), acc;
820
+ } else if (field.type.jsonType === "array" && field.type.of.length && field.type.of.some((item) => "fields" in item)) {
821
+ const innerFields = field.type.of.flatMap((innerField) => extractInnerFields(
822
+ // @ts-expect-error - Fix TS assertion for array fields
823
+ innerField.fields,
824
+ [...path, field.name],
825
+ maxDepth
826
+ ));
827
+ return acc.push(thisFieldWithPath, ...innerFields), acc;
828
+ }
829
+ return acc.push(thisFieldWithPath), acc;
830
+ }, []);
831
+ }
832
+ const internationalizedArray = definePlugin((config) => {
833
+ const pluginConfig = {
834
+ ...CONFIG_DEFAULT,
835
+ ...config
836
+ }, {
837
+ apiVersion = "2025-10-15",
838
+ select,
839
+ languages,
840
+ fieldTypes,
841
+ buttonLocations
842
+ } = pluginConfig;
843
+ return {
844
+ name: "sanity-plugin-internationalized-array",
845
+ // Preload languages for use throughout the Studio
846
+ studio: Array.isArray(languages) ? void 0 : {
847
+ components: {
848
+ layout: (props) => /* @__PURE__ */ jsxs(Fragment, { children: [
849
+ /* @__PURE__ */ jsx(Preload, { apiVersion, languages }),
850
+ props.renderDefault(props)
851
+ ] })
852
+ }
853
+ },
854
+ // Optional: render "add language" buttons as field actions
855
+ document: {
856
+ unstable_fieldActions: buttonLocations.includes("unstable__fieldAction") ? (prev) => [...prev, internationalizedArrayFieldAction] : void 0
857
+ },
858
+ // Wrap document editor with a language provider
859
+ form: {
860
+ components: {
861
+ field: (props) => /* @__PURE__ */ jsx(InternationalizedField, { ...props }),
862
+ input: (props) => !(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("internationalizedArray")) ? props.renderDefault(props) : /* @__PURE__ */ jsx(InternationalizedArrayProvider, { ...props, internationalizedArray: pluginConfig })
863
+ }
864
+ },
865
+ // Register custom schema types for the outer array and the inner object
866
+ schema: {
867
+ types: [...fieldTypes.map((type) => array({
868
+ type,
869
+ apiVersion,
870
+ select,
871
+ languages
872
+ })), ...fieldTypes.map((type) => object({
873
+ type
874
+ }))]
875
+ }
876
+ };
877
+ });
878
+ export {
879
+ clear,
880
+ internationalizedArray
881
+ };
882
+ //# sourceMappingURL=index.js.map