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