multi-content-type-relation 2.1.1 → 2.2.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.
Files changed (43) hide show
  1. package/README.md +6 -0
  2. package/dist/_chunks/en-Bk9okOMP.js +0 -1
  3. package/dist/_chunks/en-Cj4T04Z2.mjs +0 -1
  4. package/dist/_chunks/fr-KHPiQOFP.mjs +0 -1
  5. package/dist/_chunks/fr-ZS3aTnjj.js +0 -1
  6. package/dist/_chunks/{index-BHcolZ4N.mjs → index-BGSdnZnr.mjs} +37 -13
  7. package/dist/_chunks/index-Bu99PZdl.js +470 -0
  8. package/dist/_chunks/{index-BtldAbIW.js → index-CEXSrD4g.js} +40 -16
  9. package/dist/_chunks/index-DEkcD0zR.mjs +470 -0
  10. package/dist/admin/index.js +1 -2
  11. package/dist/admin/index.mjs +1 -2
  12. package/dist/admin/src/components/Input/InputContentSuggestions.d.ts +1 -2
  13. package/dist/admin/src/components/Input/TableItem.d.ts +2 -3
  14. package/dist/admin/src/helpers/content.d.ts +1 -1
  15. package/dist/server/index.js +129 -61
  16. package/dist/server/index.mjs +129 -61
  17. package/dist/server/src/controllers/controller.d.ts +1 -0
  18. package/dist/server/src/controllers/index.d.ts +1 -0
  19. package/dist/server/src/index.d.ts +1 -0
  20. package/dist/server/src/interface.d.ts +2 -0
  21. package/package.json +2 -1
  22. package/dist/_chunks/en-Bk9okOMP.js.map +0 -1
  23. package/dist/_chunks/en-Cj4T04Z2.mjs.map +0 -1
  24. package/dist/_chunks/fr-KHPiQOFP.mjs.map +0 -1
  25. package/dist/_chunks/fr-ZS3aTnjj.js.map +0 -1
  26. package/dist/_chunks/index-BHcolZ4N.mjs.map +0 -1
  27. package/dist/_chunks/index-BtldAbIW.js.map +0 -1
  28. package/dist/_chunks/index-CktBIBSM.js +0 -333
  29. package/dist/_chunks/index-CktBIBSM.js.map +0 -1
  30. package/dist/_chunks/index-CxWt3llJ.js +0 -3567
  31. package/dist/_chunks/index-CxWt3llJ.js.map +0 -1
  32. package/dist/_chunks/index-CyBD50Lc.js +0 -3568
  33. package/dist/_chunks/index-CyBD50Lc.js.map +0 -1
  34. package/dist/_chunks/index-D6nv39Fp.mjs +0 -3565
  35. package/dist/_chunks/index-D6nv39Fp.mjs.map +0 -1
  36. package/dist/_chunks/index-DGcImy9s.mjs +0 -3566
  37. package/dist/_chunks/index-DGcImy9s.mjs.map +0 -1
  38. package/dist/_chunks/index-DdX2rVzB.mjs +0 -334
  39. package/dist/_chunks/index-DdX2rVzB.mjs.map +0 -1
  40. package/dist/admin/index.js.map +0 -1
  41. package/dist/admin/index.mjs.map +0 -1
  42. package/dist/server/index.js.map +0 -1
  43. package/dist/server/index.mjs.map +0 -1
package/README.md CHANGED
@@ -74,6 +74,12 @@ If, for some reasons, you want to hydrate the relations of the relations of the
74
74
 
75
75
  This setting show debug log of the plugin for better understanding
76
76
 
77
+ ###### Key: `disableRevertRelations`
78
+
79
+ > `required:` no | `type:` Boolean | default false
80
+
81
+ This setting disable relaction MCTR if needed for performances/stability concerns
82
+
77
83
  ## Submit an issue
78
84
 
79
85
  You can use github issues to raise an issue about this plugin
@@ -30,4 +30,3 @@ const en = {
30
30
  "common.locale": "en"
31
31
  };
32
32
  exports.default = en;
33
- //# sourceMappingURL=en-Bk9okOMP.js.map
@@ -30,4 +30,3 @@ const en = {
30
30
  export {
31
31
  en as default
32
32
  };
33
- //# sourceMappingURL=en-Cj4T04Z2.mjs.map
@@ -30,4 +30,3 @@ const fr = {
30
30
  export {
31
31
  fr as default
32
32
  };
33
- //# sourceMappingURL=fr-KHPiQOFP.mjs.map
@@ -30,4 +30,3 @@ const fr = {
30
30
  "common.locale": "fr"
31
31
  };
32
32
  exports.default = fr;
33
- //# sourceMappingURL=fr-ZS3aTnjj.js.map
@@ -51,15 +51,22 @@ const fetchMatchingContent = async (keyword, contentTypes, locale) => {
51
51
  total
52
52
  };
53
53
  };
54
- const formatToStrapiField = (entries) => {
54
+ const formatToStrapiField = (entries, locale) => {
55
55
  if (entries.length === 0) return "";
56
- return JSON.stringify(
57
- entries.map((entry) => ({
58
- uid: entry.uid,
59
- documentId: entry.item.documentId,
60
- MRCT: true
61
- })).filter(Boolean)
56
+ const storedData = JSON.stringify(
57
+ entries.map((entry) => {
58
+ const obj = {
59
+ uid: entry.uid,
60
+ documentId: entry.item.documentId,
61
+ MRCT: true
62
+ };
63
+ if (locale) {
64
+ obj.locale = locale;
65
+ }
66
+ return obj;
67
+ }).filter(Boolean)
62
68
  );
69
+ return storedData;
63
70
  };
64
71
  const validateCurrentRelations = async (entries) => {
65
72
  const { post } = getFetchClient();
@@ -108,23 +115,41 @@ const SidePanel = () => {
108
115
  model: uid,
109
116
  isSingleType
110
117
  } = unstable_useContentManagerContext();
118
+ const currentLocale = new URLSearchParams(location.search).get(
119
+ "plugins[i18n][locale]"
120
+ );
111
121
  const [linkedContent, setLinkedContent] = useState([]);
112
- const [loading, setLoading] = useState(false);
122
+ const [loading, setLoading] = useState(true);
123
+ const [disabled, setDisabledFeature] = useState(false);
113
124
  useEffect(() => {
114
125
  const fetchRevertRelations = async () => {
115
126
  const { post } = getFetchClient();
116
127
  const response = await post(`/${pluginId}/fetch-revert-relations`, {
117
128
  documentId,
118
129
  uid,
119
- isSingleType
130
+ isSingleType,
131
+ locale: currentLocale
120
132
  });
121
133
  setLinkedContent(Array.isArray(response.data) ? response.data.filter(Boolean) : []);
122
134
  setLoading(false);
123
135
  };
124
- fetchRevertRelations();
136
+ const fetchConfiguration = async () => {
137
+ const { get } = getFetchClient();
138
+ const response = await get(`/${pluginId}/get-configuration`);
139
+ if (response.data.disableRevertRelations) {
140
+ setDisabledFeature(true);
141
+ setLoading(false);
142
+ } else {
143
+ fetchRevertRelations();
144
+ }
145
+ };
146
+ fetchConfiguration();
125
147
  }, []);
126
148
  if (loading)
127
149
  return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(Loader, {}) });
150
+ if (disabled) {
151
+ return /* @__PURE__ */ jsx("div", {});
152
+ }
128
153
  return /* @__PURE__ */ jsxs(Fragment, { children: [
129
154
  /* @__PURE__ */ jsx(Divider, {}),
130
155
  /* @__PURE__ */ jsxs(Box, { width: "100%", marginTop: 4, children: [
@@ -164,7 +189,7 @@ const SidePanel = () => {
164
189
  /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
165
190
  "a",
166
191
  {
167
- href: content.isSingleType ? `/admin/content-manager/single-types/${content.uid}` : `/admin/content-manager/collection-types/${content.uid}/${content.documentId}`,
192
+ href: content.isSingleType ? `/admin/content-manager/single-types/${content.uid}${currentLocale ? `?plugins[i18n][locale]=${currentLocale}` : ""}` : `/admin/content-manager/collection-types/${content.uid}/${content.documentId}${currentLocale ? `?plugins[i18n][locale]=${currentLocale}` : ""}`,
168
193
  target: "_blank",
169
194
  style: { textDecoration: "none" },
170
195
  children: /* @__PURE__ */ jsx(
@@ -223,7 +248,7 @@ const index = {
223
248
  components: {
224
249
  Input: () => import(
225
250
  /* webpackChunkName: "input-component" */
226
- "./index-D6nv39Fp.mjs"
251
+ "./index-DEkcD0zR.mjs"
227
252
  )
228
253
  },
229
254
  inputSize: {
@@ -331,4 +356,3 @@ export {
331
356
  useTranslate as u,
332
357
  validateCurrentRelations as v
333
358
  };
334
- //# sourceMappingURL=index-BHcolZ4N.mjs.map
@@ -0,0 +1,470 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const reactIntl = require("react-intl");
6
+ const reactRouterDom = require("react-router-dom");
7
+ const designSystem = require("@strapi/design-system");
8
+ const index = require("./index-CEXSrD4g.js");
9
+ const core = require("@dnd-kit/core");
10
+ const sortable = require("@dnd-kit/sortable");
11
+ const icons = require("@strapi/icons");
12
+ function useSearchedEntries(keyword, contentTypes, locale) {
13
+ const [loading, setLoading] = react.useState(false);
14
+ const [results, setResults] = react.useState([]);
15
+ const [total, setTotal] = react.useState(0);
16
+ async function fetchEntries() {
17
+ setResults([]);
18
+ setTotal(0);
19
+ if (loading || !keyword) return;
20
+ try {
21
+ const { data, total: total2 } = await index.fetchMatchingContent(
22
+ keyword,
23
+ contentTypes,
24
+ locale
25
+ );
26
+ setResults(data);
27
+ setTotal(total2);
28
+ } finally {
29
+ setLoading(false);
30
+ }
31
+ }
32
+ react.useEffect(() => {
33
+ const timeout = setTimeout(() => fetchEntries(), 500);
34
+ return () => clearTimeout(timeout);
35
+ }, [keyword]);
36
+ return react.useMemo(
37
+ () => ({
38
+ loading,
39
+ results,
40
+ total
41
+ }),
42
+ [results, total]
43
+ );
44
+ }
45
+ const PublicationState = ({
46
+ isPublished,
47
+ hasDraftAndPublish
48
+ }) => {
49
+ const { translate } = index.useTranslate();
50
+ const configuration = react.useMemo(() => {
51
+ const conf = {
52
+ variant: "alternative",
53
+ text: translate("publicationState.na")
54
+ };
55
+ if (hasDraftAndPublish) {
56
+ conf.variant = isPublished ? "success" : "secondary";
57
+ conf.text = isPublished ? translate("publicationState.published") : translate("publicationState.draft");
58
+ }
59
+ return conf;
60
+ }, [isPublished, hasDraftAndPublish, translate]);
61
+ return /* @__PURE__ */ jsxRuntime.jsx(
62
+ designSystem.Status,
63
+ {
64
+ showbullet: "false",
65
+ variant: configuration.variant,
66
+ size: "S",
67
+ width: "min-content",
68
+ style: { paddingLeft: 12, paddingRight: 12 },
69
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: `${configuration.variant}700`, children: configuration.text })
70
+ }
71
+ );
72
+ };
73
+ const CSS = /* @__PURE__ */ Object.freeze({
74
+ Translate: {
75
+ toString(transform) {
76
+ if (!transform) {
77
+ return;
78
+ }
79
+ const {
80
+ x,
81
+ y
82
+ } = transform;
83
+ return "translate3d(" + (x ? Math.round(x) : 0) + "px, " + (y ? Math.round(y) : 0) + "px, 0)";
84
+ }
85
+ },
86
+ Scale: {
87
+ toString(transform) {
88
+ if (!transform) {
89
+ return;
90
+ }
91
+ const {
92
+ scaleX,
93
+ scaleY
94
+ } = transform;
95
+ return "scaleX(" + scaleX + ") scaleY(" + scaleY + ")";
96
+ }
97
+ },
98
+ Transform: {
99
+ toString(transform) {
100
+ if (!transform) {
101
+ return;
102
+ }
103
+ return [CSS.Translate.toString(transform), CSS.Scale.toString(transform)].join(" ");
104
+ }
105
+ },
106
+ Transition: {
107
+ toString(_ref) {
108
+ let {
109
+ property,
110
+ duration,
111
+ easing
112
+ } = _ref;
113
+ return property + " " + duration + "ms " + easing;
114
+ }
115
+ }
116
+ });
117
+ const TableItem = ({
118
+ entry,
119
+ id,
120
+ type,
121
+ disabled,
122
+ onAdd,
123
+ onDelete
124
+ }) => {
125
+ const { translate } = index.useTranslate();
126
+ const contentType = index.getContentTypeForUid(entry.uid);
127
+ const location = reactRouterDom.useLocation();
128
+ const { setDraggableNodeRef, setDroppableNodeRef, transform, transition, attributes, listeners } = sortable.useSortable({ id });
129
+ const style = {
130
+ transform: CSS.Transform.toString(transform),
131
+ transition
132
+ };
133
+ const [currentLocale, setCurrentLocale] = react.useState("");
134
+ react.useEffect(() => {
135
+ const searchParams = new URLSearchParams(location.search);
136
+ const locale = searchParams.get("plugins[i18n][locale]");
137
+ if (!locale) return;
138
+ setCurrentLocale(locale);
139
+ }, [location]);
140
+ const goToEntry = () => {
141
+ if (!currentLocale) return;
142
+ const contentTypes = window.sessionStorage.getItem("mctr::content_types");
143
+ if (contentTypes) {
144
+ try {
145
+ const parsedContentTypes = JSON.parse(contentTypes);
146
+ if (Array.isArray(parsedContentTypes)) {
147
+ const contentType2 = parsedContentTypes.find(
148
+ (ct) => ct.uid === entry.uid
149
+ );
150
+ if (contentType2) {
151
+ const kind = contentType2.kind;
152
+ let url = "";
153
+ if (kind === "collectionType") {
154
+ url = `/admin/content-manager/collection-types/${entry.uid}/${entry.item.documentId}`;
155
+ } else {
156
+ url = `/admin/content-manager/single-types/${entry.uid}`;
157
+ }
158
+ url += `?plugins[i18n][locale]=${currentLocale}`;
159
+ window.open(url, "_blank");
160
+ return;
161
+ }
162
+ }
163
+ } catch (e) {
164
+ console.error("[MCTR] Failed to retrieve content types");
165
+ }
166
+ } else {
167
+ alert(translate("tableItem.error"));
168
+ }
169
+ };
170
+ return /* @__PURE__ */ jsxRuntime.jsxs(
171
+ "tr",
172
+ {
173
+ style,
174
+ ref: setDroppableNodeRef,
175
+ ...attributes,
176
+ children: [
177
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: type === "selected" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { ref: setDraggableNodeRef, ...listeners, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Drag, {}) }) : null }),
178
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { color: "neutral800", children: entry.item[entry.searchableField] }) }),
179
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { color: "neutral800", children: entry.displayName }) }),
180
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
181
+ PublicationState,
182
+ {
183
+ isPublished: !!entry.item.publishedAt,
184
+ hasDraftAndPublish: contentType?.options?.draftAndPublish
185
+ }
186
+ ) }),
187
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { children: [
188
+ /* @__PURE__ */ jsxRuntime.jsx(
189
+ designSystem.IconButton,
190
+ {
191
+ label: translate("tableItem.goToEntry"),
192
+ onClick: goToEntry,
193
+ style: { "marginRight": "5px" },
194
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Eye, {})
195
+ }
196
+ ),
197
+ type === "suggestion" ? /* @__PURE__ */ jsxRuntime.jsx(
198
+ designSystem.IconButton,
199
+ {
200
+ label: translate("tableItem.add"),
201
+ onClick: () => onAdd(entry),
202
+ disabled,
203
+ marginLeft: 1,
204
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {})
205
+ }
206
+ ) : type === "selected" ? /* @__PURE__ */ jsxRuntime.jsx(
207
+ designSystem.IconButton,
208
+ {
209
+ label: translate("tableItem.delete"),
210
+ onClick: () => onDelete(entry),
211
+ marginLeft: 1,
212
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
213
+ }
214
+ ) : null
215
+ ] }) })
216
+ ]
217
+ }
218
+ );
219
+ };
220
+ function InputContentSuggestions({
221
+ uniqueId,
222
+ suggestions,
223
+ selected,
224
+ onAddEntry,
225
+ onDeleteEntry,
226
+ onEntriesSorted,
227
+ maximum
228
+ }) {
229
+ const { translate } = index.useTranslate();
230
+ const suggestionAsSelectedEntry = react.useMemo(() => {
231
+ return (suggestions || []).flatMap(
232
+ (suggestion) => suggestion.results.map((entrySuggestion) => ({
233
+ displayName: suggestion.displayName,
234
+ item: entrySuggestion,
235
+ searchableField: suggestion.searchableField,
236
+ uid: suggestion.uid
237
+ }))
238
+ ).slice(0, 10);
239
+ }, [suggestions]);
240
+ const buildSelectedId = (entry) => {
241
+ return `${uniqueId}-${entry.uid}-${entry.item.documentId}`;
242
+ };
243
+ const availableSuggestions = react.useMemo(() => {
244
+ const selectedIdentifiers = (selected || []).map(buildSelectedId);
245
+ return suggestionAsSelectedEntry.filter(
246
+ (suggestion) => !selectedIdentifiers.includes(buildSelectedId(suggestion))
247
+ );
248
+ }, [suggestions, selected]);
249
+ const onAdd = (entry) => {
250
+ if (typeof onAddEntry === "function") {
251
+ onAddEntry(entry);
252
+ }
253
+ };
254
+ const onDelete = (entry) => {
255
+ if (typeof onDeleteEntry === "function") {
256
+ onDeleteEntry(entry);
257
+ }
258
+ };
259
+ const onSort = (entries) => {
260
+ if (typeof onEntriesSorted === "function") {
261
+ onEntriesSorted(entries);
262
+ }
263
+ };
264
+ const sensors = core.useSensors(
265
+ core.useSensor(core.PointerSensor)
266
+ );
267
+ const sortableItems = react.useMemo(() => {
268
+ const items = selected?.map((entry) => buildSelectedId(entry)) ?? [];
269
+ return items;
270
+ }, [selected]);
271
+ const handleDragEnd = (event) => {
272
+ const { active, over } = event;
273
+ if (!active || !over) return;
274
+ if (active.id !== over.id) {
275
+ const oldIndex = selected.findIndex(
276
+ (entry) => buildSelectedId(entry) === active.id
277
+ );
278
+ const newIndex = selected.findIndex(
279
+ (entry) => buildSelectedId(entry) === over.id
280
+ );
281
+ onSort(sortable.arrayMove(selected, oldIndex, newIndex));
282
+ }
283
+ };
284
+ if (!availableSuggestions?.length && !selected?.length) return null;
285
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: [2, 0, 2, 0], background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { style: { whiteSpace: "unset", borderCollapse: "separate", borderSpacing: "0 10px" }, children: [
286
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
287
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {}),
288
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.title") }) }),
289
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.contentType") }) }),
290
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.state") }) })
291
+ ] }) }),
292
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
293
+ selected?.length ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
294
+ core.DndContext,
295
+ {
296
+ sensors,
297
+ collisionDetection: core.closestCenter,
298
+ onDragEnd: handleDragEnd,
299
+ children: /* @__PURE__ */ jsxRuntime.jsx(
300
+ sortable.SortableContext,
301
+ {
302
+ items: sortableItems,
303
+ strategy: sortable.verticalListSortingStrategy,
304
+ children: selected.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
305
+ TableItem,
306
+ {
307
+ id: buildSelectedId(entry),
308
+ entry,
309
+ type: "selected",
310
+ onDelete
311
+ },
312
+ buildSelectedId(entry)
313
+ ))
314
+ }
315
+ )
316
+ }
317
+ ) }) : null,
318
+ availableSuggestions.length && selected?.length ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 5, children: /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { width: "100%" } }) }) }) : null,
319
+ availableSuggestions.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
320
+ TableItem,
321
+ {
322
+ id: buildSelectedId(entry),
323
+ entry,
324
+ type: "suggestion",
325
+ onAdd,
326
+ disabled: typeof maximum === "number" ? (selected?.length ?? 0) >= maximum : false
327
+ },
328
+ buildSelectedId(entry)
329
+ ))
330
+ ] })
331
+ ] }) });
332
+ }
333
+ const MainInput = ({
334
+ name,
335
+ error,
336
+ description,
337
+ onChange,
338
+ value,
339
+ labelAction,
340
+ label,
341
+ attribute,
342
+ required
343
+ }) => {
344
+ const { formatMessage } = reactIntl.useIntl();
345
+ const { translate } = index.useTranslate();
346
+ const location = reactRouterDom.useLocation();
347
+ const maximumItems = attribute.options.max;
348
+ const minimumItems = attribute.options.min || 0;
349
+ const currentLocale = new URLSearchParams(location.search).get(
350
+ "plugins[i18n][locale]"
351
+ );
352
+ const [keyword, setKeyword] = react.useState("");
353
+ const [selected, setSelected] = react.useState([]);
354
+ const [loading, setLoading] = react.useState(true);
355
+ react.useEffect(() => {
356
+ const value2 = selected.length > maximumItems || selected.length < minimumItems ? [] : selected;
357
+ onChange({ target: { name, value: index.formatToStrapiField(value2, currentLocale) } });
358
+ }, [selected]);
359
+ const hint = react.useMemo(() => {
360
+ const minLabel = minimumItems > 0 ? `${translate("input.hint.min")} ${minimumItems} ${minimumItems > 1 ? translate("input.hint.entries") : translate("input.hint.entry")}` : "";
361
+ const maxLabel = maximumItems > 0 ? `${translate("input.hint.max")} ${maximumItems} ${maximumItems > 1 ? translate("input.hint.entries") : translate("input.hint.entry")}` : "";
362
+ return `
363
+ ${minLabel ? `${minLabel}` : ""}
364
+ ${minLabel && maxLabel ? ", " : ""}
365
+ ${maxLabel}
366
+ ${minLabel || maxLabel ? translate("input.hint.separator") : ""}
367
+ ${selected.length} ${translate("input.hint.selected")}
368
+ `;
369
+ }, [selected, maximumItems, minimumItems, translate]);
370
+ const inputError = react.useMemo(() => {
371
+ if (!error) return "";
372
+ if (selected.length < minimumItems)
373
+ return `${error} - ${translate("input.error.min")} ${minimumItems} ${translate("input.error.required")}`;
374
+ if (selected.length > maximumItems)
375
+ return `${error} - ${translate("input.error.max")} ${maximumItems} ${translate("input.error.required")}`;
376
+ return error;
377
+ }, [error, maximumItems, minimumItems, selected, translate]);
378
+ const { loading: searchLoading, results } = useSearchedEntries(
379
+ keyword,
380
+ attribute.options.contentTypes,
381
+ currentLocale
382
+ );
383
+ react.useEffect(() => {
384
+ async function validateContent() {
385
+ if (!value) {
386
+ setLoading(false);
387
+ return;
388
+ }
389
+ const entries = JSON.parse(value);
390
+ const result = await index.validateCurrentRelations(entries);
391
+ setSelected(result);
392
+ setLoading(false);
393
+ }
394
+ validateContent();
395
+ }, []);
396
+ const onAddEntry = (entry) => {
397
+ const alreadyDefined = selected.some(
398
+ (selectedEntry) => selectedEntry.uid === entry.uid && selectedEntry.item.id === entry.item.id
399
+ );
400
+ if (alreadyDefined) return;
401
+ setSelected([...selected, entry]);
402
+ };
403
+ const onDeleteEntry = (entry) => {
404
+ const newSelected = selected.filter(
405
+ (selectedEntry) => !(selectedEntry.uid === entry.uid && selectedEntry.item.id === entry.item.id)
406
+ );
407
+ setSelected(newSelected);
408
+ };
409
+ const onEntriesSorted = (entries) => {
410
+ setSelected(entries);
411
+ };
412
+ if (loading) return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, {});
413
+ return /* @__PURE__ */ jsxRuntime.jsxs(
414
+ designSystem.Field.Root,
415
+ {
416
+ name,
417
+ id: name,
418
+ error,
419
+ hint: description,
420
+ required,
421
+ children: [
422
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { action: labelAction, children: label }),
423
+ /* @__PURE__ */ jsxRuntime.jsx(
424
+ designSystem.TextInput,
425
+ {
426
+ placeholder: translate("input.placeholder"),
427
+ required,
428
+ hint,
429
+ error: inputError,
430
+ value: keyword,
431
+ onChange: (e) => setKeyword(e.target.value)
432
+ }
433
+ ),
434
+ searchLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, {}) : /* @__PURE__ */ jsxRuntime.jsx(
435
+ InputContentSuggestions,
436
+ {
437
+ uniqueId: Date.now(),
438
+ suggestions: results,
439
+ selected,
440
+ onAddEntry,
441
+ onDeleteEntry,
442
+ onEntriesSorted,
443
+ maximum: maximumItems
444
+ }
445
+ )
446
+ ]
447
+ }
448
+ );
449
+ };
450
+ const Index = (props) => {
451
+ const { locale } = reactIntl.useIntl();
452
+ const theme = react.useMemo(() => ({}), []);
453
+ const attribute = react.useMemo(() => {
454
+ if (!props.attribute) return props.attribute;
455
+ if (!props.attribute.options) return props.attribute;
456
+ if (!props.attribute.options.contentTypes) return props.attribute;
457
+ const contentTypes = Object.keys(
458
+ props.attribute.options.contentTypes
459
+ ).filter((key) => props.attribute.options.contentTypes[key]);
460
+ return {
461
+ ...props.attribute,
462
+ options: {
463
+ ...props.attribute.options,
464
+ contentTypes: contentTypes.join(",")
465
+ }
466
+ };
467
+ }, [props.attribute]);
468
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.DesignSystemProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(MainInput, { ...props, attribute }) });
469
+ };
470
+ exports.default = Index;