@strapi/content-manager 0.0.0-experimental.a4161dd0ce4a6742074cbfc43734281e14a29baa → 0.0.0-experimental.a4cee39f4705cbd534afa66170f94f2f68e65b75

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 (89) hide show
  1. package/dist/admin/chunks/{ComponentConfigurationPage-CDKJ1saA.js → ComponentConfigurationPage-BWB_urBW.js} +3 -3
  2. package/dist/admin/chunks/{ComponentConfigurationPage-CDKJ1saA.js.map → ComponentConfigurationPage-BWB_urBW.js.map} +1 -1
  3. package/dist/admin/chunks/{ComponentConfigurationPage-BdKTyTdt.mjs → ComponentConfigurationPage-Bw3SD5w3.mjs} +3 -3
  4. package/dist/admin/chunks/{ComponentConfigurationPage-BdKTyTdt.mjs.map → ComponentConfigurationPage-Bw3SD5w3.mjs.map} +1 -1
  5. package/dist/admin/chunks/{EditConfigurationPage-BW5fpvkO.js → EditConfigurationPage-BazMqkY5.js} +3 -3
  6. package/dist/admin/chunks/{EditConfigurationPage-BW5fpvkO.js.map → EditConfigurationPage-BazMqkY5.js.map} +1 -1
  7. package/dist/admin/chunks/{EditConfigurationPage-CaJ_CmJz.mjs → EditConfigurationPage-bP8cL5u8.mjs} +3 -3
  8. package/dist/admin/chunks/{EditConfigurationPage-CaJ_CmJz.mjs.map → EditConfigurationPage-bP8cL5u8.mjs.map} +1 -1
  9. package/dist/admin/chunks/{EditViewPage-BDekCXSy.mjs → EditViewPage-D3F0FbHV.mjs} +10 -7
  10. package/dist/admin/chunks/EditViewPage-D3F0FbHV.mjs.map +1 -0
  11. package/dist/admin/chunks/{EditViewPage-CNacGhk_.js → EditViewPage-DjB2aEuN.js} +11 -8
  12. package/dist/admin/chunks/EditViewPage-DjB2aEuN.js.map +1 -0
  13. package/dist/admin/chunks/{Form-2LZDIqUE.mjs → Form-CO-twQva.mjs} +2 -2
  14. package/dist/admin/chunks/{Form-2LZDIqUE.mjs.map → Form-CO-twQva.mjs.map} +1 -1
  15. package/dist/admin/chunks/{Form-CouVf26p.js → Form-Dyr8enar.js} +2 -2
  16. package/dist/admin/chunks/{Form-CouVf26p.js.map → Form-Dyr8enar.js.map} +1 -1
  17. package/dist/admin/chunks/{History-Cv3uNjvV.js → History-BsZCxc7e.js} +6 -6
  18. package/dist/admin/chunks/{History-Cv3uNjvV.js.map → History-BsZCxc7e.js.map} +1 -1
  19. package/dist/admin/chunks/{History-B7zZvnQF.mjs → History-DJ_pI0gL.mjs} +5 -5
  20. package/dist/admin/chunks/{History-B7zZvnQF.mjs.map → History-DJ_pI0gL.mjs.map} +1 -1
  21. package/dist/admin/chunks/{Input-DPH5j7Yl.js → Input-D-yPzkxz.js} +634 -848
  22. package/dist/admin/chunks/Input-D-yPzkxz.js.map +1 -0
  23. package/dist/admin/chunks/{Input-BPTHgeyh.mjs → Input-DWQWd5MK.mjs} +634 -847
  24. package/dist/admin/chunks/Input-DWQWd5MK.mjs.map +1 -0
  25. package/dist/admin/chunks/{ListConfigurationPage-FS8YuoKF.mjs → ListConfigurationPage-DlvGrjR_.mjs} +2 -2
  26. package/dist/admin/chunks/{ListConfigurationPage-FS8YuoKF.mjs.map → ListConfigurationPage-DlvGrjR_.mjs.map} +1 -1
  27. package/dist/admin/chunks/{ListConfigurationPage-Cj1tt01r.js → ListConfigurationPage-dHbA6tve.js} +2 -2
  28. package/dist/admin/chunks/{ListConfigurationPage-Cj1tt01r.js.map → ListConfigurationPage-dHbA6tve.js.map} +1 -1
  29. package/dist/admin/chunks/{ListViewPage-Xv5mmaJq.mjs → ListViewPage-DaxIL_8o.mjs} +3 -3
  30. package/dist/admin/chunks/{ListViewPage-Xv5mmaJq.mjs.map → ListViewPage-DaxIL_8o.mjs.map} +1 -1
  31. package/dist/admin/chunks/{ListViewPage-BCmGmK7N.js → ListViewPage-gsJS3ulI.js} +3 -3
  32. package/dist/admin/chunks/{ListViewPage-BCmGmK7N.js.map → ListViewPage-gsJS3ulI.js.map} +1 -1
  33. package/dist/admin/chunks/{NoContentTypePage-DpvfQfhU.js → NoContentTypePage-BD-VEn6M.js} +2 -2
  34. package/dist/admin/chunks/{NoContentTypePage-DpvfQfhU.js.map → NoContentTypePage-BD-VEn6M.js.map} +1 -1
  35. package/dist/admin/chunks/{NoContentTypePage-Bbqw5ZV9.mjs → NoContentTypePage-xzAGzlVY.mjs} +2 -2
  36. package/dist/admin/chunks/{NoContentTypePage-Bbqw5ZV9.mjs.map → NoContentTypePage-xzAGzlVY.mjs.map} +1 -1
  37. package/dist/admin/chunks/{NoPermissionsPage-igrvpcW0.mjs → NoPermissionsPage-BAKqxUK7.mjs} +2 -2
  38. package/dist/admin/chunks/{NoPermissionsPage-igrvpcW0.mjs.map → NoPermissionsPage-BAKqxUK7.mjs.map} +1 -1
  39. package/dist/admin/chunks/{NoPermissionsPage-BYEkhBnk.js → NoPermissionsPage-BmE5T_Mq.js} +2 -2
  40. package/dist/admin/chunks/{NoPermissionsPage-BYEkhBnk.js.map → NoPermissionsPage-BmE5T_Mq.js.map} +1 -1
  41. package/dist/admin/chunks/{Preview-DR-9uYxZ.mjs → Preview-Bz2ir5R5.mjs} +102 -182
  42. package/dist/admin/chunks/Preview-Bz2ir5R5.mjs.map +1 -0
  43. package/dist/admin/chunks/{Preview-DlRltQbE.js → Preview-CP4m2RBm.js} +101 -181
  44. package/dist/admin/chunks/Preview-CP4m2RBm.js.map +1 -0
  45. package/dist/admin/chunks/{en-DBP0Gaid.mjs → en-C2zEwS3-.mjs} +3 -1
  46. package/dist/admin/chunks/{en-DBP0Gaid.mjs.map → en-C2zEwS3-.mjs.map} +1 -1
  47. package/dist/admin/chunks/{en-CH__IC8g.js → en-G976DLsg.js} +3 -1
  48. package/dist/admin/chunks/{en-CH__IC8g.js.map → en-G976DLsg.js.map} +1 -1
  49. package/dist/admin/chunks/{index-CISU19oJ.js → index-CFa6xmgK.js} +197 -127
  50. package/dist/admin/chunks/index-CFa6xmgK.js.map +1 -0
  51. package/dist/admin/chunks/{index-C_e5v8f7.mjs → index-ZyDJIuQ1.mjs} +196 -129
  52. package/dist/admin/chunks/index-ZyDJIuQ1.mjs.map +1 -0
  53. package/dist/admin/chunks/{layout-CrqscUTi.mjs → layout-D2tOWWAq.mjs} +4 -4
  54. package/dist/admin/chunks/{layout-CrqscUTi.mjs.map → layout-D2tOWWAq.mjs.map} +1 -1
  55. package/dist/admin/chunks/{layout-CajJum-G.js → layout-XA97mHoN.js} +4 -4
  56. package/dist/admin/chunks/{layout-CajJum-G.js.map → layout-XA97mHoN.js.map} +1 -1
  57. package/dist/admin/chunks/uk-BtM6WnaE.mjs +313 -0
  58. package/dist/admin/chunks/uk-BtM6WnaE.mjs.map +1 -0
  59. package/dist/admin/chunks/uk-DB6OgySY.js +318 -0
  60. package/dist/admin/chunks/uk-DB6OgySY.js.map +1 -0
  61. package/dist/admin/chunks/{usePrev-CHotxABl.js → usePrev-BEkg-rKP.js} +2 -2
  62. package/dist/admin/chunks/{usePrev-CHotxABl.js.map → usePrev-BEkg-rKP.js.map} +1 -1
  63. package/dist/admin/chunks/{usePrev-DF3ZO0z4.mjs → usePrev-DAPoUN3D.mjs} +2 -2
  64. package/dist/admin/chunks/{usePrev-DF3ZO0z4.mjs.map → usePrev-DAPoUN3D.mjs.map} +1 -1
  65. package/dist/admin/index.js +1 -1
  66. package/dist/admin/index.mjs +1 -1
  67. package/dist/admin/src/content-manager.d.ts +1 -0
  68. package/dist/admin/src/features/DocumentContext.d.ts +13 -2
  69. package/dist/admin/src/hooks/useDocument.d.ts +2 -0
  70. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +5 -7
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/Relations.d.ts +1 -2
  73. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +3 -1
  74. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +5 -2
  75. package/dist/admin/src/preview/components/PreviewHeader.d.ts +1 -2
  76. package/package.json +8 -8
  77. package/dist/admin/chunks/EditViewPage-BDekCXSy.mjs.map +0 -1
  78. package/dist/admin/chunks/EditViewPage-CNacGhk_.js.map +0 -1
  79. package/dist/admin/chunks/Input-BPTHgeyh.mjs.map +0 -1
  80. package/dist/admin/chunks/Input-DPH5j7Yl.js.map +0 -1
  81. package/dist/admin/chunks/Preview-DR-9uYxZ.mjs.map +0 -1
  82. package/dist/admin/chunks/Preview-DlRltQbE.js.map +0 -1
  83. package/dist/admin/chunks/index-CISU19oJ.js.map +0 -1
  84. package/dist/admin/chunks/index-C_e5v8f7.mjs.map +0 -1
  85. package/dist/admin/chunks/uk-B24MoTVg.js +0 -145
  86. package/dist/admin/chunks/uk-B24MoTVg.js.map +0 -1
  87. package/dist/admin/chunks/uk-Cpgmm7gE.mjs +0 -140
  88. package/dist/admin/chunks/uk-Cpgmm7gE.mjs.map +0 -1
  89. package/dist/admin/src/preview/components/PreviewContent.d.ts +0 -3
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { useState, useEffect, useCallback } from 'react';
4
- import { createContext, useStrapiApp, useElementOnScreen, useField, useForm, useNotification, useRBAC, Form, useQueryParams, useFocusInputField, useAPIErrorHandler, InputRenderer as InputRenderer$1 } from '@strapi/admin/strapi-admin';
5
- import { Box, SingleSelect, SingleSelectOption, Typography, Flex, Button, Popover, Field, Menu, IconButton, Tooltip, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, MenuItem, Grid as Grid$1, TextInput, Modal, Loader, EmptyStateLayout, TextButton, Link as Link$2, Combobox, ComboboxOption, IconButtonGroup } from '@strapi/design-system';
6
- import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, More, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, EyeStriked, ArrowLeft, WarningCircle, ArrowClockwise, Cross, CheckCircle, Loader as Loader$1, Plus } from '@strapi/icons';
4
+ import { useStrapiApp, useElementOnScreen, createContext, useField, useForm, useNotification, Form, ConfirmDialog, useRBAC, DescriptionComponentRenderer, useQueryParams, useFocusInputField, useAPIErrorHandler, InputRenderer as InputRenderer$1 } from '@strapi/admin/strapi-admin';
5
+ import { Box, SingleSelect, SingleSelectOption, Typography, Flex, Button, Popover, Field, Menu, IconButton, Tooltip, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, MenuItem, Grid as Grid$1, TextInput, Modal, TextButton, Dialog, Loader, EmptyStateLayout, Link as Link$2, Combobox, ComboboxOption, IconButtonGroup } from '@strapi/design-system';
6
+ import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, More, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, EyeStriked, ArrowLeft, ArrowsOut, WarningCircle, ArrowClockwise, Cross, CheckCircle, Loader as Loader$1, Plus } from '@strapi/icons';
7
7
  import { useIntl } from 'react-intl';
8
- import { c as useDocument, g as getTranslation, d as useDocumentLayout, e as createDefaultForm, t as transformDocument, P as PERMISSIONS, f as DocumentRBAC, D as DocumentStatus, C as COLLECTION_TYPES, S as SINGLE_TYPES, h as buildValidParams, i as useDoc, j as contentManagerApi, k as CLONE_PATH, l as useDocumentRBAC, m as useDocLayout } from './index-C_e5v8f7.mjs';
8
+ import { g as getTranslation, c as useDocumentContext, d as useDocumentLayout, e as createDefaultForm, t as transformDocument, f as useLazyGetDocumentQuery, h as createYupSchema, P as PERMISSIONS, i as DocumentRBAC, j as DocumentActionButton, D as DocumentStatus, C as COLLECTION_TYPES, S as SINGLE_TYPES, k as buildValidParams, l as contentManagerApi, m as useDoc, n as CLONE_PATH, o as useDocumentRBAC } from './index-ZyDJIuQ1.mjs';
9
9
  import { styled, css, keyframes } from 'styled-components';
10
10
  import { Editor as Editor$1, Transforms, Node, Element, Range, Path, Point, createEditor } from 'slate';
11
11
  import { withHistory } from 'slate-history';
@@ -61,11 +61,11 @@ import 'prismjs/components/prism-typescript';
61
61
  import 'prismjs/components/prism-tsx';
62
62
  import 'prismjs/components/prism-vbnet';
63
63
  import 'prismjs/components/prism-yaml';
64
- import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-DF3ZO0z4.mjs';
64
+ import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-DAPoUN3D.mjs';
65
65
  import { D as DIRECTIONS, u as useDragAndDrop, I as ItemTypes, g as getIn, a as DROP_SENSITIVITY } from './objects-D2z-IJgu.mjs';
66
66
  import * as Toolbar from '@radix-ui/react-toolbar';
67
67
  import { getEmptyImage } from 'react-dnd-html5-backend';
68
- import { NavLink, useMatch, useLocation } from 'react-router-dom';
68
+ import { useNavigate, useLocation, useMatch } from 'react-router-dom';
69
69
  import pipe$1 from 'lodash/fp/pipe';
70
70
  import { C as ComponentIcon, a as COMPONENT_ICONS } from './ComponentIcon-BZcTc4rj.mjs';
71
71
  import { generateNKeysBetween } from 'fractional-indexing';
@@ -86,31 +86,6 @@ import sup from 'markdown-it-sup';
86
86
  import 'highlight.js/styles/solarized-dark.css';
87
87
  import 'codemirror5/addon/display/placeholder';
88
88
 
89
- const [DocumentProvider, useDocumentContext] = createContext('DocumentContext');
90
- /**
91
- * TODO: Document in contributor docs, Add unit test
92
- *
93
- * This context provider and its associated hook are used to access a document at its root level
94
- * and expose a function to change the current document being viewed to one of the root level docuemnt's relations.
95
- *
96
- * The useDocumentContext hook exposes:
97
- * - meta: information about the currentDocument,
98
- * - document: the actual document,
99
- * - changeDocument: a function to change the current document to one of its relations.
100
- */ const DocumentContextProvider = ({ children, initialDocument })=>{
101
- /**
102
- * Initialize with the "root" document and expose a setter method to change to
103
- * one of the root level document's relations.
104
- */ const [currentDocumentMeta, changeDocument] = React.useState(initialDocument);
105
- const document = useDocument(currentDocumentMeta);
106
- return /*#__PURE__*/ jsx(DocumentProvider, {
107
- changeDocument: changeDocument,
108
- document: document,
109
- meta: currentDocumentMeta,
110
- children: children
111
- });
112
- };
113
-
114
89
  const componentStore = new Map();
115
90
  /**
116
91
  * @description A hook to lazy load custom field components
@@ -3606,15 +3581,24 @@ const ComponentCategory = ({ category, components = [], variant = 'primary', onA
3606
3581
  const ResponsiveAccordionContent = styled(Accordion.Content)`
3607
3582
  container-type: inline-size;
3608
3583
  `;
3609
- const Grid = styled(Box)`
3610
- display: grid;
3611
- grid-template-columns: repeat(auto-fill, 100%);
3612
- grid-gap: ${({ theme })=>theme.spaces[1]};
3613
-
3614
- @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3615
- grid-template-columns: repeat(auto-fill, 14rem);
3616
- }
3617
- `;
3584
+ /**
3585
+ * TODO:
3586
+ * JSDOM cannot handle container queries.
3587
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
3588
+ * for failing to parse the stylesheet.
3589
+ */ const Grid = process.env.NODE_ENV !== 'test' ? styled(Box)`
3590
+ display: grid;
3591
+ grid-template-columns: repeat(auto-fill, 100%);
3592
+ grid-gap: 4px;
3593
+
3594
+ @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3595
+ grid-template-columns: repeat(auto-fill, 14rem);
3596
+ }
3597
+ ` : styled(Box)`
3598
+ display: grid;
3599
+ grid-template-columns: repeat(auto-fill, 100%);
3600
+ grid-gap: 4px;
3601
+ `;
3618
3602
  const ComponentBox = styled(Flex)`
3619
3603
  color: ${({ theme })=>theme.colors.neutral600};
3620
3604
  cursor: pointer;
@@ -3680,7 +3664,18 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
3680
3664
  const { formatMessage } = useIntl();
3681
3665
  const formValues = useForm('DynamicComponent', (state)=>state.values);
3682
3666
  const documentMeta = useDocumentContext('DynamicComponent', (state)=>state.meta);
3683
- const { edit: { components } } = useDocumentLayout(documentMeta.model);
3667
+ const rootDocumentMeta = useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
3668
+ const { edit: { components: rootComponents } } = useDocumentLayout(rootDocumentMeta.model);
3669
+ const { edit: { components: relatedComponents } } = useDocumentLayout(documentMeta.model);
3670
+ // Merge the root level components and dynamic zone components
3671
+ const components = React.useMemo(()=>({
3672
+ ...rootComponents,
3673
+ ...relatedComponents
3674
+ }), [
3675
+ rootComponents,
3676
+ relatedComponents
3677
+ ]);
3678
+ const document = useDocumentContext('DynamicComponent', (state)=>state.document);
3684
3679
  const title = React.useMemo(()=>{
3685
3680
  const { mainField } = components[componentUid]?.settings ?? {
3686
3681
  mainField: 'id'
@@ -3912,9 +3907,11 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
3912
3907
  alignItems: "stretch",
3913
3908
  children: children ? children({
3914
3909
  ...fieldWithTranslatedLabel,
3910
+ document,
3915
3911
  name: fieldName
3916
3912
  }) : /*#__PURE__*/ jsx(MemoizedInputRenderer, {
3917
3913
  ...fieldWithTranslatedLabel,
3914
+ document: document,
3918
3915
  name: fieldName
3919
3916
  })
3920
3917
  }, fieldName);
@@ -4277,68 +4274,278 @@ const CustomModalContent = styled(Modal.Content)`
4277
4274
  height: 90%;
4278
4275
  max-height: 100%;
4279
4276
  `;
4280
- const RelationModal = ({ open, onToggle, id, model, relationUrl })=>{
4277
+ const [RelationModalProvider, useRelationModal] = createContext('RelationModal', {
4278
+ parentModified: false,
4279
+ depth: 0
4280
+ });
4281
+ const RelationModalForm = ({ relation, triggerButtonLabel })=>{
4282
+ const navigate = useNavigate();
4283
+ const { pathname, search } = useLocation();
4281
4284
  const { formatMessage } = useIntl();
4282
- return /*#__PURE__*/ jsx(Modal.Root, {
4283
- open: open,
4284
- onOpenChange: onToggle,
4285
- children: /*#__PURE__*/ jsxs(CustomModalContent, {
4286
- children: [
4287
- /*#__PURE__*/ jsx(Modal.Header, {
4288
- children: /*#__PURE__*/ jsxs(Flex, {
4285
+ const [triggerRefetchDocument] = useLazyGetDocumentQuery();
4286
+ const currentDocument = useDocumentContext('RelationModalForm', (state)=>state.document);
4287
+ const rootDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.rootDocumentMeta);
4288
+ const currentDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.meta);
4289
+ const changeDocument = useDocumentContext('RelationModalForm', (state)=>state.changeDocument);
4290
+ const documentHistory = useDocumentContext('RelationModalForm', (state)=>state.documentHistory);
4291
+ const setDocumentHistory = useDocumentContext('RelationModalForm', (state)=>state.setDocumentHistory);
4292
+ const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
4293
+ const [actionPosition, setActionPosition] = React.useState('cancel');
4294
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
4295
+ // NOTE: Not sure about this relation modal context, maybe we should move this to DocumentContext?
4296
+ // Get parent modal context if it exists
4297
+ const parentContext = useRelationModal('RelationModalForm', (state)=>state);
4298
+ // Get depth of nested modals
4299
+ const depth = parentContext ? parentContext.depth + 1 : 0;
4300
+ // Check if this is a nested modal
4301
+ const isNested = depth > 0;
4302
+ const addDocumentToHistory = (document)=>setDocumentHistory((prev)=>[
4303
+ ...prev,
4304
+ document
4305
+ ]);
4306
+ const getPreviousDocument = ()=>{
4307
+ if (documentHistory.length === 0) return undefined;
4308
+ const lastDocument = documentHistory[documentHistory.length - 1];
4309
+ return lastDocument;
4310
+ };
4311
+ const removeLastDocumentFromHistory = ()=>{
4312
+ setDocumentHistory((prev)=>[
4313
+ ...prev
4314
+ ].slice(0, prev.length - 1));
4315
+ };
4316
+ const handleToggleModal = ()=>{
4317
+ if (isModalOpen) {
4318
+ setIsModalOpen(false);
4319
+ const document = {
4320
+ collectionType: rootDocumentMeta.collectionType,
4321
+ model: rootDocumentMeta.model,
4322
+ documentId: rootDocumentMeta.documentId
4323
+ };
4324
+ // Change back to the root document
4325
+ changeDocument(document);
4326
+ // Reset the document history
4327
+ setDocumentHistory([]);
4328
+ // Reset action position
4329
+ setActionPosition('cancel');
4330
+ // Read from cache or refetch root document
4331
+ triggerRefetchDocument(document, // Favor the cache
4332
+ true);
4333
+ } else {
4334
+ changeDocument(relation);
4335
+ setIsModalOpen(true);
4336
+ }
4337
+ };
4338
+ const getFullPageLink = ()=>{
4339
+ const isSingleType = currentDocumentMeta.collectionType === SINGLE_TYPES;
4340
+ const queryParams = currentDocumentMeta.params?.locale ? `?plugins[i18n][locale]=${currentDocumentMeta.params.locale}` : '';
4341
+ return `/content-manager/${currentDocumentMeta.collectionType}/${currentDocumentMeta.model}${isSingleType ? '' : '/' + currentDocumentMeta.documentId}${queryParams}`;
4342
+ };
4343
+ const handleRedirection = ()=>{
4344
+ const editViewUrl = `${pathname}${search}`;
4345
+ const isRootDocumentUrl = editViewUrl.includes(getFullPageLink());
4346
+ if (isRootDocumentUrl) {
4347
+ handleToggleModal();
4348
+ } else {
4349
+ navigate(getFullPageLink());
4350
+ }
4351
+ };
4352
+ const handleConfirm = ()=>{
4353
+ if (actionPosition === 'navigate') {
4354
+ handleRedirection();
4355
+ } else if (actionPosition === 'back') {
4356
+ const previousRelation = getPreviousDocument();
4357
+ if (previousRelation) {
4358
+ removeLastDocumentFromHistory();
4359
+ changeDocument(previousRelation);
4360
+ }
4361
+ } else {
4362
+ handleToggleModal();
4363
+ }
4364
+ };
4365
+ return /*#__PURE__*/ jsx(Form, {
4366
+ method: "PUT",
4367
+ initialValues: currentDocument.getInitialFormValues(),
4368
+ validate: (values, options)=>{
4369
+ const yupSchema = createYupSchema(currentDocument.schema?.attributes, currentDocument.components, {
4370
+ status: currentDocument.document?.status,
4371
+ ...options
4372
+ });
4373
+ return yupSchema.validate(values, {
4374
+ abortEarly: false
4375
+ });
4376
+ },
4377
+ children: ({ modified, isSubmitting, resetForm })=>{
4378
+ // We don't count the root document, so history starts after 1
4379
+ const hasHistory = documentHistory.length > 1;
4380
+ return /*#__PURE__*/ jsxs(RelationModalProvider, {
4381
+ parentModified: modified,
4382
+ depth: depth,
4383
+ children: [
4384
+ /*#__PURE__*/ jsxs(Modal.Root, {
4385
+ open: isModalOpen,
4386
+ onOpenChange: ()=>{
4387
+ if (isModalOpen) {
4388
+ if (modified && !isSubmitting) {
4389
+ setIsConfirmationOpen(true);
4390
+ } else {
4391
+ handleToggleModal();
4392
+ }
4393
+ }
4394
+ },
4289
4395
  children: [
4290
- /*#__PURE__*/ jsx(IconButton, {
4291
- withTooltip: false,
4292
- label: "Back",
4293
- variant: "ghost",
4294
- disabled: true,
4295
- onClick: ()=>{},
4296
- marginRight: 1,
4297
- children: /*#__PURE__*/ jsx(ArrowLeft, {})
4298
- }),
4299
- /*#__PURE__*/ jsx(Typography, {
4300
- tag: "span",
4301
- fontWeight: 600,
4302
- children: formatMessage({
4303
- id: 'content-manager.components.RelationInputModal.modal-title',
4304
- defaultMessage: 'Edit a relation'
4396
+ /*#__PURE__*/ jsx(Modal.Trigger, {
4397
+ children: /*#__PURE__*/ jsx(Tooltip, {
4398
+ description: triggerButtonLabel,
4399
+ children: /*#__PURE__*/ jsx(CustomTextButton, {
4400
+ onClick: ()=>{
4401
+ // Check if parent modal has unsaved changes
4402
+ if (isNested && parentContext.parentModified) {
4403
+ setIsConfirmationOpen(true);
4404
+ // Return early to avoid opening the modal
4405
+ return;
4406
+ } else {
4407
+ if (modified && !isSubmitting) {
4408
+ setIsConfirmationOpen(true);
4409
+ } else {
4410
+ // Add current relation to history before opening a new one
4411
+ if (currentDocumentMeta && Object.keys(currentDocumentMeta).length > 0) {
4412
+ addDocumentToHistory(currentDocumentMeta);
4413
+ }
4414
+ handleToggleModal();
4415
+ }
4416
+ if (!isModalOpen) {
4417
+ setIsModalOpen(true);
4418
+ }
4419
+ }
4420
+ },
4421
+ children: triggerButtonLabel
4422
+ })
4305
4423
  })
4424
+ }),
4425
+ /*#__PURE__*/ jsxs(CustomModalContent, {
4426
+ children: [
4427
+ /*#__PURE__*/ jsx(Modal.Header, {
4428
+ gap: 2,
4429
+ children: /*#__PURE__*/ jsx(Flex, {
4430
+ justifyContent: "space-between",
4431
+ alignItems: "center",
4432
+ width: "100%",
4433
+ children: /*#__PURE__*/ jsxs(Flex, {
4434
+ gap: 2,
4435
+ children: [
4436
+ /*#__PURE__*/ jsx(IconButton, {
4437
+ withTooltip: false,
4438
+ label: "Back",
4439
+ variant: "ghost",
4440
+ disabled: !hasHistory,
4441
+ onClick: ()=>{
4442
+ setActionPosition('back');
4443
+ if (modified && !isSubmitting) {
4444
+ setIsConfirmationOpen(true);
4445
+ } else {
4446
+ const previousRelation = getPreviousDocument();
4447
+ if (previousRelation) {
4448
+ removeLastDocumentFromHistory();
4449
+ changeDocument(previousRelation);
4450
+ }
4451
+ }
4452
+ },
4453
+ marginRight: 1,
4454
+ children: /*#__PURE__*/ jsx(ArrowLeft, {})
4455
+ }),
4456
+ /*#__PURE__*/ jsx(Typography, {
4457
+ tag: "span",
4458
+ fontWeight: 600,
4459
+ children: formatMessage({
4460
+ id: 'content-manager.components.RelationInputModal.modal-title',
4461
+ defaultMessage: 'Edit a relation'
4462
+ })
4463
+ })
4464
+ ]
4465
+ })
4466
+ })
4467
+ }),
4468
+ /*#__PURE__*/ jsx(RelationModalBody, {
4469
+ children: /*#__PURE__*/ jsx(IconButton, {
4470
+ onClick: ()=>{
4471
+ setActionPosition('navigate');
4472
+ if (modified && !isSubmitting) {
4473
+ setIsConfirmationOpen(true);
4474
+ } else {
4475
+ navigate(getFullPageLink());
4476
+ }
4477
+ },
4478
+ variant: "tertiary",
4479
+ label: formatMessage({
4480
+ id: 'content-manager.components.RelationInputModal.button-fullpage',
4481
+ defaultMessage: 'Go to entry'
4482
+ }),
4483
+ children: /*#__PURE__*/ jsx(ArrowsOut, {})
4484
+ })
4485
+ }),
4486
+ /*#__PURE__*/ jsx(Modal.Footer, {
4487
+ children: /*#__PURE__*/ jsx(Button, {
4488
+ onClick: ()=>{
4489
+ if (modified && !isSubmitting) {
4490
+ setIsConfirmationOpen(true);
4491
+ } else {
4492
+ handleToggleModal();
4493
+ }
4494
+ },
4495
+ variant: "tertiary",
4496
+ children: formatMessage({
4497
+ id: 'app.components.Button.cancel',
4498
+ defaultMessage: 'Cancel'
4499
+ })
4500
+ })
4501
+ })
4502
+ ]
4306
4503
  })
4307
4504
  ]
4308
- })
4309
- }),
4310
- /*#__PURE__*/ jsx(RelationModalBody, {
4311
- id: id,
4312
- model: model,
4313
- collectionType: getCollectionType(relationUrl),
4314
- isModalOpen: open,
4315
- onToggleModal: onToggle
4316
- }),
4317
- /*#__PURE__*/ jsx(Modal.Footer, {
4318
- children: /*#__PURE__*/ jsx(Button, {
4319
- onClick: onToggle,
4320
- variant: "tertiary",
4321
- children: formatMessage({
4322
- id: 'app.components.Button.cancel',
4323
- defaultMessage: 'Cancel'
4505
+ }),
4506
+ /*#__PURE__*/ jsx(Dialog.Root, {
4507
+ open: isConfirmationOpen,
4508
+ onOpenChange: setIsConfirmationOpen,
4509
+ children: /*#__PURE__*/ jsx(ConfirmDialog, {
4510
+ onConfirm: ()=>{
4511
+ handleConfirm();
4512
+ setIsConfirmationOpen(false);
4513
+ resetForm();
4514
+ },
4515
+ onCancel: ()=>{
4516
+ setIsConfirmationOpen(false);
4517
+ },
4518
+ variant: "danger",
4519
+ children: formatMessage({
4520
+ id: 'content-manager.components.RelationInputModal.confirmation-message',
4521
+ defaultMessage: 'Some changes were not saved. Are you sure you want to close this relation? All changes that were not saved will be lost.'
4522
+ })
4324
4523
  })
4325
4524
  })
4326
- })
4327
- ]
4328
- })
4525
+ ]
4526
+ });
4527
+ }
4329
4528
  });
4330
4529
  };
4331
- const RelationModalBody = ({ id })=>{
4530
+ const CustomTextButton = styled(TextButton)`
4531
+ & > span {
4532
+ font-size: ${({ theme })=>theme.fontSizes[2]};
4533
+ }
4534
+ `;
4535
+ const RelationModalBody = ({ children })=>{
4332
4536
  const { formatMessage } = useIntl();
4333
4537
  const documentMeta = useDocumentContext('RelationModalBody', (state)=>state.meta);
4334
4538
  const documentResponse = useDocumentContext('RelationModalBody', (state)=>state.document);
4539
+ const onPreview = useDocumentContext('RelationModalBody', (state)=>state.onPreview);
4335
4540
  const documentLayoutResponse = useDocumentLayout(documentMeta.model);
4541
+ const plugins = useStrapiApp('RelationModalBody', (state)=>state.plugins);
4336
4542
  const initialValues = documentResponse.getInitialFormValues();
4337
- const { permissions = [], isLoading, error } = useRBAC(PERMISSIONS.map((action)=>({
4543
+ const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
4338
4544
  action,
4339
4545
  subject: documentMeta.model
4340
4546
  })));
4341
- if (isLoading || documentResponse.isLoading || documentLayoutResponse.isLoading) {
4547
+ const isLoading = isLoadingPermissions || documentLayoutResponse.isLoading || documentResponse.isLoading;
4548
+ if (isLoading && !documentResponse.document?.documentId) {
4342
4549
  return /*#__PURE__*/ jsx(Loader, {
4343
4550
  small: true,
4344
4551
  children: formatMessage({
@@ -4365,44 +4572,95 @@ const RelationModalBody = ({ id })=>{
4365
4572
  }
4366
4573
  const documentTitle = documentResponse.getTitle(documentLayoutResponse.edit.settings.mainField);
4367
4574
  const hasDraftAndPublished = documentResponse.schema?.options?.draftAndPublish ?? false;
4575
+ const props = {
4576
+ activeTab: 'draft',
4577
+ collectionType: documentMeta.collectionType,
4578
+ model: documentMeta.model,
4579
+ documentId: documentMeta.documentId,
4580
+ document: documentResponse.document,
4581
+ meta: documentResponse.meta,
4582
+ onPreview
4583
+ };
4368
4584
  return /*#__PURE__*/ jsx(Modal.Body, {
4369
4585
  children: /*#__PURE__*/ jsxs(DocumentRBAC, {
4370
4586
  permissions: permissions,
4371
4587
  model: documentMeta.model,
4372
4588
  children: [
4373
4589
  /*#__PURE__*/ jsxs(Flex, {
4374
- direction: "column",
4375
4590
  alignItems: "flex-start",
4591
+ direction: "column",
4376
4592
  gap: 2,
4377
4593
  children: [
4378
- /*#__PURE__*/ jsx(Typography, {
4379
- tag: "h2",
4380
- variant: "alpha",
4381
- children: documentTitle
4594
+ /*#__PURE__*/ jsxs(Flex, {
4595
+ width: "100%",
4596
+ justifyContent: "space-between",
4597
+ gap: 2,
4598
+ children: [
4599
+ /*#__PURE__*/ jsx(Typography, {
4600
+ tag: "h2",
4601
+ variant: "alpha",
4602
+ children: documentTitle
4603
+ }),
4604
+ /*#__PURE__*/ jsxs(Flex, {
4605
+ gap: 2,
4606
+ children: [
4607
+ children,
4608
+ /*#__PURE__*/ jsx(DescriptionComponentRenderer, {
4609
+ props: props,
4610
+ descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
4611
+ children: (actions)=>{
4612
+ const filteredActions = actions.filter((action)=>{
4613
+ return [
4614
+ action.position
4615
+ ].flat().includes('relation-modal');
4616
+ });
4617
+ const [primaryAction, secondaryAction] = filteredActions;
4618
+ if (!primaryAction && !secondaryAction) return null;
4619
+ // Both actions are available when draft and publish enabled
4620
+ if (primaryAction && secondaryAction) {
4621
+ return /*#__PURE__*/ jsxs(Fragment, {
4622
+ children: [
4623
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4624
+ ...secondaryAction,
4625
+ variant: secondaryAction.variant || 'secondary'
4626
+ }),
4627
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4628
+ ...primaryAction,
4629
+ variant: primaryAction.variant || 'default'
4630
+ })
4631
+ ]
4632
+ });
4633
+ }
4634
+ // Otherwise we just have the save action
4635
+ return /*#__PURE__*/ jsx(DocumentActionButton, {
4636
+ ...primaryAction,
4637
+ variant: primaryAction.variant || 'secondary'
4638
+ });
4639
+ }
4640
+ })
4641
+ ]
4642
+ })
4643
+ ]
4382
4644
  }),
4383
4645
  hasDraftAndPublished ? /*#__PURE__*/ jsx(Box, {
4384
- marginTop: 1,
4385
4646
  children: /*#__PURE__*/ jsx(DocumentStatus, {
4386
4647
  status: documentResponse.document?.status
4387
4648
  })
4388
4649
  }) : null
4389
4650
  ]
4390
4651
  }),
4391
- /*#__PURE__*/ jsx(Form, {
4392
- initialValues: initialValues,
4393
- method: id ? 'PUT' : 'POST',
4394
- children: /*#__PURE__*/ jsx(Flex, {
4395
- flex: 1,
4652
+ /*#__PURE__*/ jsx(Flex, {
4653
+ flex: 1,
4654
+ overflow: "auto",
4655
+ alignItems: "stretch",
4656
+ paddingTop: 7,
4657
+ children: /*#__PURE__*/ jsx(Box, {
4396
4658
  overflow: "auto",
4397
- alignItems: "stretch",
4398
- paddingTop: 7,
4399
- children: /*#__PURE__*/ jsx(Box, {
4400
- overflow: "auto",
4401
- flex: 1,
4402
- children: /*#__PURE__*/ jsx(FormLayout, {
4403
- layout: documentLayoutResponse.edit.layout,
4404
- hasBackground: false
4405
- })
4659
+ flex: 1,
4660
+ children: /*#__PURE__*/ jsx(FormLayout, {
4661
+ layout: documentLayoutResponse.edit.layout,
4662
+ document: documentResponse,
4663
+ hasBackground: false
4406
4664
  })
4407
4665
  })
4408
4666
  })
@@ -4463,15 +4721,18 @@ const ONE_WAY_RELATIONS = [
4463
4721
  * @description The relations field holds a lot of domain logic for handling relations which is rather complicated
4464
4722
  * At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
4465
4723
  * they wish to do so.
4466
- */ const UnstableRelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4467
- const documentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4468
- const documentResponse = useDocumentContext('RelationsField', (state)=>state.document);
4469
- const changeDocument = useDocumentContext('RelationsField', (state)=>state.changeDocument);
4724
+ */ const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4725
+ const currentDocumentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4726
+ const currentDocument = useDocumentContext('RelationsField', (state)=>state.document);
4727
+ const rootDocumentMeta = useDocumentContext('RelationsField', (state)=>state.rootDocumentMeta);
4470
4728
  const [currentPage, setCurrentPage] = React.useState(1);
4471
- const documentId = documentResponse.document?.documentId;
4729
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4730
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4731
+ // Use the documentId from the actual document, not the params (meta)
4732
+ const documentId = currentDocument.document?.documentId;
4472
4733
  const { formatMessage } = useIntl();
4473
4734
  const [{ query }] = useQueryParams();
4474
- const params = buildValidParams(query);
4735
+ const params = documentMeta.params ?? buildValidParams(query);
4475
4736
  const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4476
4737
  const isDisabled = isMorph || disabled;
4477
4738
  const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
@@ -4484,17 +4745,24 @@ const ONE_WAY_RELATIONS = [
4484
4745
  }, [
4485
4746
  isSubmitting
4486
4747
  ]);
4748
+ const component = componentUID && currentDocument.components[componentUID];
4487
4749
  /**
4488
4750
  * We'll always have a documentId in a created entry, so we look for a componentId first.
4489
4751
  * Same with `uid` and `documentModel`.
4490
- */ const id = componentId ? componentId.toString() : documentId;
4491
- const model = componentUID ?? documentMeta.model;
4752
+ */ const model = component ? component.uid : documentMeta.model;
4753
+ const id = component && componentId ? componentId.toString() : documentId;
4492
4754
  /**
4493
4755
  * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4494
4756
  * Where the above example would a nested field within two components, however
4495
4757
  * we only require the field on the component not the complete path since we query
4496
4758
  * individual components. Therefore we split the string and take the last item.
4497
4759
  */ const [targetField] = props.name.split('.').slice(-1);
4760
+ const schemaAttributes = component ? component.attributes ?? {} : currentDocument.schema?.attributes ?? {};
4761
+ /**
4762
+ * Confirm the target field is related to the current document.
4763
+ * Since relations can exist in a modal on top of the root document,
4764
+ * we need to ensure we are fetching relations for the correct document (root document vs related document),
4765
+ */ const isRelatedToCurrentDocument = Object.values(schemaAttributes).filter((attribute)=>attribute.type === 'relation' && 'target' in attribute && 'target' in props.attribute && attribute.target === props.attribute.target).length > 0;
4498
4766
  const { data, isLoading, isFetching } = useGetRelationsQuery({
4499
4767
  model,
4500
4768
  targetField,
@@ -4507,7 +4775,7 @@ const ONE_WAY_RELATIONS = [
4507
4775
  }
4508
4776
  }, {
4509
4777
  refetchOnMountOrArgChange: true,
4510
- skip: !id,
4778
+ skip: !id || !isRelatedToCurrentDocument,
4511
4779
  selectFromResult: (result)=>{
4512
4780
  return {
4513
4781
  ...result,
@@ -4616,10 +4884,11 @@ const ONE_WAY_RELATIONS = [
4616
4884
  /*#__PURE__*/ jsx(RelationsInput, {
4617
4885
  disabled: isDisabled,
4618
4886
  // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4619
- id: componentUID ? componentId ? `${componentId}` : '' : documentId,
4887
+ id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
4620
4888
  label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4621
4889
  model: model,
4622
4890
  onChange: handleConnect,
4891
+ isRelatedToCurrentDocument: isRelatedToCurrentDocument,
4623
4892
  ...props
4624
4893
  }),
4625
4894
  'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
@@ -4636,7 +4905,7 @@ const ONE_WAY_RELATIONS = [
4636
4905
  }) : null
4637
4906
  ]
4638
4907
  }),
4639
- /*#__PURE__*/ jsx(UnstableRelationsList, {
4908
+ /*#__PURE__*/ jsx(RelationsList, {
4640
4909
  data: relations,
4641
4910
  serverData: data.results,
4642
4911
  disabled: isDisabled,
@@ -4644,575 +4913,226 @@ const ONE_WAY_RELATIONS = [
4644
4913
  isLoading: isFetchingMoreRelations,
4645
4914
  relationType: props.attribute.relation,
4646
4915
  // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4647
- targetModel: props.attribute.targetModel,
4648
- setCurrentDocument: changeDocument
4916
+ targetModel: props.attribute.targetModel
4649
4917
  })
4650
4918
  ]
4651
4919
  });
4652
4920
  });
4653
- const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4654
- const [currentPage, setCurrentPage] = React.useState(1);
4655
- const { document, model: documentModel } = useDoc();
4656
- const documentId = document?.documentId;
4657
- const { formatMessage } = useIntl();
4921
+ /**
4922
+ * TODO: this can be removed once we stop shipping Inputs with
4923
+ * labels wrapped round in DS@2.
4924
+ */ const StyledFlex = styled(Flex)`
4925
+ & > div {
4926
+ width: 100%;
4927
+ }
4928
+ `;
4929
+ /**
4930
+ * If it's in the connected array, it can get out of our data array,
4931
+ * we'll be putting it back in later and sorting it anyway.
4932
+ */ const removeConnected = ({ field })=>(relations)=>{
4933
+ return relations.filter((relation)=>{
4934
+ const connectedRelations = field?.connect ?? [];
4935
+ return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4936
+ });
4937
+ };
4938
+ /**
4939
+ * @description Removes relations that are in the `disconnect` array of the field
4940
+ */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4941
+ const disconnectedRelations = field?.disconnect ?? [];
4942
+ return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4943
+ });
4944
+ /**
4945
+ * @description Adds a label and href to the relation object we use this to render
4946
+ * a better UI where we can link to the relation and display a human-readable label.
4947
+ */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4948
+ return {
4949
+ ...relation,
4950
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4951
+ [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4952
+ label: getRelationLabel(relation, mainField),
4953
+ href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4954
+ };
4955
+ });
4956
+ /**
4957
+ * @description Contains all the logic for the combobox that can search
4958
+ * for relations and then add them to the field's connect array.
4959
+ */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
4960
+ const [textValue, setTextValue] = React.useState('');
4961
+ const [searchParams, setSearchParams] = React.useState({
4962
+ _q: '',
4963
+ page: 1
4964
+ });
4965
+ const { toggleNotification } = useNotification();
4658
4966
  const [{ query }] = useQueryParams();
4659
- const params = buildValidParams(query);
4660
- const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4661
- const isDisabled = isMorph || disabled;
4662
- const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
4663
- componentId: id,
4664
- componentUID: uid
4665
- }));
4666
- const isSubmitting = useForm('RelationsList', (state)=>state.isSubmitting);
4667
- React.useEffect(()=>{
4668
- setCurrentPage(1);
4669
- }, [
4670
- isSubmitting
4671
- ]);
4672
- /**
4673
- * We'll always have a documentId in a created entry, so we look for a componentId first.
4674
- * Same with `uid` and `documentModel`.
4675
- */ const id = componentId ? componentId.toString() : documentId;
4676
- const model = componentUID ?? documentModel;
4967
+ const currentDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.meta);
4968
+ const rootDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.rootDocumentMeta);
4969
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4970
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4971
+ const { formatMessage } = useIntl();
4972
+ const fieldRef = useFocusInputField(name);
4973
+ const field = useField(name);
4974
+ const searchParamsDebounced = useDebounce(searchParams, 300);
4975
+ const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
4677
4976
  /**
4977
+ * Because we're using a lazy query, we need to trigger the search
4978
+ * when the component mounts and when the search params change.
4979
+ * We also need to trigger the search when the field value changes
4980
+ * so that we can filter out the relations that are already connected.
4981
+ */ React.useEffect(()=>{
4982
+ /**
4678
4983
  * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4679
4984
  * Where the above example would a nested field within two components, however
4680
4985
  * we only require the field on the component not the complete path since we query
4681
4986
  * individual components. Therefore we split the string and take the last item.
4682
- */ const [targetField] = props.name.split('.').slice(-1);
4683
- const { data, isLoading, isFetching } = useGetRelationsQuery({
4987
+ */ const [targetField] = name.split('.').slice(-1);
4988
+ // Return early if there is no relation to the document
4989
+ if (!isRelatedToCurrentDocument) return;
4990
+ const params = documentMeta.params ?? buildValidParams(query);
4991
+ searchForTrigger({
4992
+ model,
4993
+ targetField,
4994
+ params: {
4995
+ ...params,
4996
+ id: id ?? '',
4997
+ pageSize: 10,
4998
+ idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
4999
+ idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
5000
+ ...searchParamsDebounced
5001
+ }
5002
+ });
5003
+ }, [
5004
+ field.value?.connect,
5005
+ field.value?.disconnect,
5006
+ id,
4684
5007
  model,
4685
- targetField,
4686
- // below we don't run the query if there is no id.
4687
- id: id,
4688
- params: {
4689
- ...params,
4690
- pageSize: RELATIONS_TO_DISPLAY,
4691
- page: currentPage
5008
+ name,
5009
+ query,
5010
+ searchForTrigger,
5011
+ searchParamsDebounced,
5012
+ isRelatedToCurrentDocument,
5013
+ documentMeta
5014
+ ]);
5015
+ const handleSearch = async (search)=>{
5016
+ setSearchParams((s)=>({
5017
+ ...s,
5018
+ _q: search,
5019
+ page: 1
5020
+ }));
5021
+ };
5022
+ const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
5023
+ const options = data?.results ?? [];
5024
+ const handleChange = (relationId)=>{
5025
+ if (!relationId) {
5026
+ return;
4692
5027
  }
4693
- }, {
4694
- refetchOnMountOrArgChange: true,
4695
- skip: !id,
4696
- selectFromResult: (result)=>{
4697
- return {
4698
- ...result,
4699
- data: {
4700
- ...result.data,
4701
- results: result.data?.results ? result.data.results : []
4702
- }
4703
- };
5028
+ const relation = options.find((opt)=>opt.id.toString() === relationId);
5029
+ if (!relation) {
5030
+ // This is very unlikely to happen, but it ensures we don't have any data for.
5031
+ console.error("You've tried to add a relation with an id that does not exist in the options you can see, this is likely a bug with Strapi. Please open an issue.");
5032
+ toggleNotification({
5033
+ message: formatMessage({
5034
+ id: getTranslation('relation.error-adding-relation'),
5035
+ defaultMessage: 'An error occurred while trying to add the relation.'
5036
+ }),
5037
+ type: 'danger'
5038
+ });
5039
+ return;
4704
5040
  }
4705
- });
4706
- const handleLoadMore = ()=>{
4707
- setCurrentPage((prev)=>prev + 1);
4708
- };
4709
- const field = useField(props.name);
4710
- const isFetchingMoreRelations = isLoading || isFetching;
4711
- const realServerRelationsCount = 'pagination' in data && data.pagination ? data.pagination.total : 0;
4712
- /**
4713
- * Items that are already connected, but reordered would be in
4714
- * this list, so to get an accurate figure, we remove them.
4715
- */ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
4716
- const relationsDisconnected = field.value?.disconnect?.length ?? 0;
4717
- const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
4718
- /**
4719
- * This is it, the source of truth for reordering in conjunction with partial loading & updating
4720
- * of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
4721
- * create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
4722
- */ const relations = React.useMemo(()=>{
4723
- const ctx = {
4724
- field: field.value,
4725
- // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4726
- href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
4727
- mainField: props.mainField
4728
- };
4729
- /**
4730
- * Tidy up our data.
4731
- */ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
4732
- const transformedRels = transformations([
4733
- ...data.results
4734
- ]);
4735
- /**
4736
- * THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
4737
- * then the list will be in the wrong order.
4738
- */ return [
4739
- ...transformedRels,
4740
- ...field.value?.connect ?? []
4741
- ].sort((a, b)=>{
4742
- if (a.__temp_key__ < b.__temp_key__) return -1;
4743
- if (a.__temp_key__ > b.__temp_key__) return 1;
4744
- return 0;
4745
- });
4746
- }, [
4747
- data.results,
4748
- field.value,
4749
- // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4750
- props.attribute.targetModel,
4751
- props.mainField
4752
- ]);
4753
- const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
4754
- const handleConnect = (relation)=>{
4755
- const [lastItemInList] = relations.slice(-1);
4756
- const item = {
4757
- id: relation.id,
4758
- apiData: {
4759
- id: relation.id,
4760
- documentId: relation.documentId,
4761
- locale: relation.locale
4762
- },
4763
- status: relation.status,
4764
- /**
4765
- * If there's a last item, that's the first key we use to generate out next one.
4766
- */ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
4767
- // Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
4768
- [props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
4769
- label: getRelationLabel(relation, props.mainField),
4770
- // @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
4771
- href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4772
- };
4773
- if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
4774
- // Remove any existing relation so they can be replaced with the new one
4775
- field.value?.connect?.forEach(handleDisconnect);
4776
- relations.forEach(handleDisconnect);
4777
- field.onChange(`${props.name}.connect`, [
4778
- item
4779
- ]);
4780
- } else {
4781
- field.onChange(`${props.name}.connect`, [
4782
- ...field.value?.connect ?? [],
4783
- item
4784
- ]);
4785
- }
4786
- };
4787
- return /*#__PURE__*/ jsxs(Flex, {
4788
- ref: ref,
4789
- direction: "column",
4790
- gap: 3,
4791
- justifyContent: "space-between",
4792
- alignItems: "stretch",
4793
- wrap: "wrap",
4794
- children: [
4795
- /*#__PURE__*/ jsxs(StyledFlex, {
4796
- direction: "column",
4797
- alignItems: "start",
4798
- gap: 2,
4799
- width: "100%",
4800
- children: [
4801
- /*#__PURE__*/ jsx(RelationsInput, {
4802
- disabled: isDisabled,
4803
- // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4804
- id: componentUID ? componentId ? `${componentId}` : '' : documentId,
4805
- label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4806
- model: model,
4807
- onChange: handleConnect,
4808
- ...props
4809
- }),
4810
- 'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
4811
- disabled: isFetchingMoreRelations,
4812
- onClick: handleLoadMore,
4813
- loading: isFetchingMoreRelations,
4814
- startIcon: /*#__PURE__*/ jsx(ArrowClockwise, {}),
4815
- // prevent the label from line-wrapping
4816
- shrink: 0,
4817
- children: formatMessage({
4818
- id: getTranslation('relation.loadMore'),
4819
- defaultMessage: 'Load More'
4820
- })
4821
- }) : null
4822
- ]
4823
- }),
4824
- /*#__PURE__*/ jsx(RelationsList, {
4825
- data: relations,
4826
- serverData: data.results,
4827
- disabled: isDisabled,
4828
- name: props.name,
4829
- isLoading: isFetchingMoreRelations,
4830
- relationType: props.attribute.relation
4831
- })
4832
- ]
4833
- });
4834
- });
4835
- /**
4836
- * TODO: this can be removed once we stop shipping Inputs with
4837
- * labels wrapped round in DS@2.
4838
- */ const StyledFlex = styled(Flex)`
4839
- & > div {
4840
- width: 100%;
4841
- }
4842
- `;
4843
- /**
4844
- * If it's in the connected array, it can get out of our data array,
4845
- * we'll be putting it back in later and sorting it anyway.
4846
- */ const removeConnected = ({ field })=>(relations)=>{
4847
- return relations.filter((relation)=>{
4848
- const connectedRelations = field?.connect ?? [];
4849
- return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4850
- });
4851
- };
4852
- /**
4853
- * @description Removes relations that are in the `disconnect` array of the field
4854
- */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4855
- const disconnectedRelations = field?.disconnect ?? [];
4856
- return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4857
- });
4858
- /**
4859
- * @description Adds a label and href to the relation object we use this to render
4860
- * a better UI where we can link to the relation and display a human-readable label.
4861
- */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4862
- return {
4863
- ...relation,
4864
- // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4865
- [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4866
- label: getRelationLabel(relation, mainField),
4867
- href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4868
- };
4869
- });
4870
- /**
4871
- * @description Contains all the logic for the combobox that can search
4872
- * for relations and then add them to the field's connect array.
4873
- */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, ...props })=>{
4874
- const [textValue, setTextValue] = React.useState('');
4875
- const [searchParams, setSearchParams] = React.useState({
4876
- _q: '',
4877
- page: 1
4878
- });
4879
- const { toggleNotification } = useNotification();
4880
- const [{ query }] = useQueryParams();
4881
- const { formatMessage } = useIntl();
4882
- const fieldRef = useFocusInputField(name);
4883
- const field = useField(name);
4884
- const searchParamsDebounced = useDebounce(searchParams, 300);
4885
- const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
4886
- /**
4887
- * Because we're using a lazy query, we need to trigger the search
4888
- * when the component mounts and when the search params change.
4889
- * We also need to trigger the search when the field value changes
4890
- * so that we can filter out the relations that are already connected.
4891
- */ React.useEffect(()=>{
4892
- /**
4893
- * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4894
- * Where the above example would a nested field within two components, however
4895
- * we only require the field on the component not the complete path since we query
4896
- * individual components. Therefore we split the string and take the last item.
4897
- */ const [targetField] = name.split('.').slice(-1);
4898
- searchForTrigger({
4899
- model,
4900
- targetField,
4901
- params: {
4902
- ...buildValidParams(query),
4903
- id: id ?? '',
4904
- pageSize: 10,
4905
- idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
4906
- idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
4907
- ...searchParamsDebounced
4908
- }
4909
- });
4910
- }, [
4911
- field.value?.connect,
4912
- field.value?.disconnect,
4913
- id,
4914
- model,
4915
- name,
4916
- query,
4917
- searchForTrigger,
4918
- searchParamsDebounced
4919
- ]);
4920
- const handleSearch = async (search)=>{
4921
- setSearchParams((s)=>({
4922
- ...s,
4923
- _q: search,
4924
- page: 1
4925
- }));
4926
- };
4927
- const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
4928
- const options = data?.results ?? [];
4929
- const handleChange = (relationId)=>{
4930
- if (!relationId) {
4931
- return;
4932
- }
4933
- const relation = options.find((opt)=>opt.id.toString() === relationId);
4934
- if (!relation) {
4935
- // This is very unlikely to happen, but it ensures we don't have any data for.
4936
- console.error("You've tried to add a relation with an id that does not exist in the options you can see, this is likely a bug with Strapi. Please open an issue.");
4937
- toggleNotification({
4938
- message: formatMessage({
4939
- id: getTranslation('relation.error-adding-relation'),
4940
- defaultMessage: 'An error occurred while trying to add the relation.'
4941
- }),
4942
- type: 'danger'
4943
- });
4944
- return;
4945
- }
4946
- /**
4947
- * You need to give this relation a correct _temp_key_ but
4948
- * this component doesn't know about those ones, you can't rely
4949
- * on the connect array because that doesn't hold items that haven't
4950
- * moved. So use a callback to fill in the gaps when connecting.
4951
- *
4952
- */ onChange(relation);
4953
- };
4954
- const handleLoadMore = ()=>{
4955
- if (!data || !data.pagination) {
4956
- return;
4957
- } else if (data.pagination.page < data.pagination.pageCount) {
4958
- setSearchParams((s)=>({
4959
- ...s,
4960
- page: s.page + 1
4961
- }));
4962
- }
4963
- };
4964
- React.useLayoutEffect(()=>{
4965
- setTextValue('');
4966
- }, [
4967
- field.value
4968
- ]);
4969
- return /*#__PURE__*/ jsxs(Field.Root, {
4970
- error: field.error,
4971
- hint: hint,
4972
- name: name,
4973
- required: required,
4974
- children: [
4975
- /*#__PURE__*/ jsx(Field.Label, {
4976
- action: labelAction,
4977
- children: label
4978
- }),
4979
- /*#__PURE__*/ jsx(Combobox, {
4980
- ref: fieldRef,
4981
- name: name,
4982
- autocomplete: "list",
4983
- placeholder: placeholder || formatMessage({
4984
- id: getTranslation('relation.add'),
4985
- defaultMessage: 'Add relation'
4986
- }),
4987
- hasMoreItems: hasNextPage,
4988
- loading: isLoading,
4989
- onOpenChange: ()=>{
4990
- handleSearch(textValue ?? '');
4991
- },
4992
- noOptionsMessage: ()=>formatMessage({
4993
- id: getTranslation('relation.notAvailable'),
4994
- defaultMessage: 'No relations available'
4995
- }),
4996
- loadingMessage: formatMessage({
4997
- id: getTranslation('relation.isLoading'),
4998
- defaultMessage: 'Relations are loading'
4999
- }),
5000
- onLoadMore: handleLoadMore,
5001
- textValue: textValue,
5002
- onChange: handleChange,
5003
- onTextValueChange: (text)=>{
5004
- setTextValue(text);
5005
- },
5006
- onInputChange: (event)=>{
5007
- handleSearch(event.currentTarget.value);
5008
- },
5009
- ...props,
5010
- children: options.map((opt)=>{
5011
- const textValue = getRelationLabel(opt, mainField);
5012
- return /*#__PURE__*/ jsx(ComboboxOption, {
5013
- value: opt.id.toString(),
5014
- textValue: textValue,
5015
- children: /*#__PURE__*/ jsxs(Flex, {
5016
- gap: 2,
5017
- justifyContent: "space-between",
5018
- children: [
5019
- /*#__PURE__*/ jsx(Typography, {
5020
- ellipsis: true,
5021
- children: textValue
5022
- }),
5023
- opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
5024
- status: opt.status
5025
- }) : null
5026
- ]
5027
- })
5028
- }, opt.id);
5029
- })
5030
- }),
5031
- /*#__PURE__*/ jsx(Field.Error, {}),
5032
- /*#__PURE__*/ jsx(Field.Hint, {})
5033
- ]
5034
- });
5035
- };
5036
- /* -------------------------------------------------------------------------------------------------
5037
- * RelationsList
5038
- * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5039
- const RELATION_GUTTER = 4;
5040
- const UnstableRelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel, setCurrentDocument })=>{
5041
- const ariaDescriptionId = React.useId();
5042
- const { formatMessage } = useIntl();
5043
- const listRef = React.useRef(null);
5044
- const outerListRef = React.useRef(null);
5045
- const [overflow, setOverflow] = React.useState();
5046
- const [liveText, setLiveText] = React.useState('');
5047
- const field = useField(name);
5048
- React.useEffect(()=>{
5049
- if (data.length <= RELATIONS_TO_DISPLAY) {
5050
- return setOverflow(undefined);
5051
- }
5052
- const handleNativeScroll = (e)=>{
5053
- const el = e.target;
5054
- const parentScrollContainerHeight = el.parentNode.scrollHeight;
5055
- const maxScrollBottom = el.scrollHeight - el.scrollTop;
5056
- if (el.scrollTop === 0) {
5057
- return setOverflow('bottom');
5058
- }
5059
- if (maxScrollBottom === parentScrollContainerHeight) {
5060
- return setOverflow('top');
5061
- }
5062
- return setOverflow('top-bottom');
5063
- };
5064
- const outerListRefCurrent = outerListRef?.current;
5065
- if (!isLoading && data.length > 0 && outerListRefCurrent) {
5066
- outerListRef.current.addEventListener('scroll', handleNativeScroll);
5067
- }
5068
- return ()=>{
5069
- if (outerListRefCurrent) {
5070
- outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
5071
- }
5072
- };
5073
- }, [
5074
- isLoading,
5075
- data.length
5076
- ]);
5077
- const getItemPos = (index)=>`${index + 1} of ${data.length}`;
5078
- const handleMoveItem = (newIndex, oldIndex)=>{
5079
- const item = data[oldIndex];
5080
- setLiveText(formatMessage({
5081
- id: getTranslation('dnd.reorder'),
5082
- defaultMessage: '{item}, moved. New position in list: {position}.'
5083
- }, {
5084
- item: item.label ?? item.documentId,
5085
- position: getItemPos(newIndex)
5086
- }));
5087
- /**
5088
- * Splicing mutates the array, so we need to create a new array
5089
- */ const newData = [
5090
- ...data
5091
- ];
5092
- const currentRow = data[oldIndex];
5093
- const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
5094
- const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
5095
- /**
5096
- * We're moving the relation between two other relations, so
5097
- * we need to generate a new key that keeps the order
5098
- */ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
5099
- newData.splice(oldIndex, 1);
5100
- newData.splice(newIndex, 0, {
5101
- ...currentRow,
5102
- __temp_key__: newKey
5103
- });
5104
- /**
5105
- * Now we diff against the server to understand what's different so we
5106
- * can keep the connect array nice and tidy. It also needs reversing because
5107
- * we reverse the relations from the server in the first place.
5108
- */ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
5109
- const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
5110
- const relationInFront = array[currentIndex + 1];
5111
- if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
5112
- const position = relationInFront ? {
5113
- before: relationInFront.documentId,
5114
- locale: relationInFront.locale,
5115
- status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
5116
- } : {
5117
- end: true
5118
- };
5119
- const relationWithPosition = {
5120
- ...relation,
5121
- ...{
5122
- apiData: {
5123
- id: relation.id,
5124
- documentId: relation.documentId,
5125
- locale: relation.locale,
5126
- position
5127
- }
5128
- }
5129
- };
5130
- return [
5131
- ...acc,
5132
- relationWithPosition
5133
- ];
5134
- }
5135
- return acc;
5136
- }, []).toReversed();
5137
- field.onChange(`${name}.connect`, connectedRelations);
5138
- };
5139
- const handleGrabItem = (index)=>{
5140
- const item = data[index];
5141
- setLiveText(formatMessage({
5142
- id: getTranslation('dnd.grab-item'),
5143
- defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5144
- }, {
5145
- item: item.label ?? item.documentId,
5146
- position: getItemPos(index)
5147
- }));
5148
- };
5149
- const handleDropItem = (index)=>{
5150
- const { href: _href, label, ...item } = data[index];
5151
- setLiveText(formatMessage({
5152
- id: getTranslation('dnd.drop-item'),
5153
- defaultMessage: `{item}, dropped. Final position in list: {position}.`
5154
- }, {
5155
- item: label ?? item.documentId,
5156
- position: getItemPos(index)
5157
- }));
5041
+ /**
5042
+ * You need to give this relation a correct _temp_key_ but
5043
+ * this component doesn't know about those ones, you can't rely
5044
+ * on the connect array because that doesn't hold items that haven't
5045
+ * moved. So use a callback to fill in the gaps when connecting.
5046
+ *
5047
+ */ onChange(relation);
5158
5048
  };
5159
- const handleCancel = (index)=>{
5160
- const item = data[index];
5161
- setLiveText(formatMessage({
5162
- id: getTranslation('dnd.cancel-item'),
5163
- defaultMessage: '{item}, dropped. Re-order cancelled.'
5164
- }, {
5165
- item: item.label ?? item.documentId
5166
- }));
5049
+ const handleLoadMore = ()=>{
5050
+ if (!data || !data.pagination) {
5051
+ return;
5052
+ } else if (data.pagination.page < data.pagination.pageCount) {
5053
+ setSearchParams((s)=>({
5054
+ ...s,
5055
+ page: s.page + 1
5056
+ }));
5057
+ }
5167
5058
  };
5168
- const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
5169
- /**
5170
- * These relation types will only ever have one item
5171
- * in their list, so you can't reorder a single item!
5172
- */ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
5173
- const dynamicListHeight = data.length > RELATIONS_TO_DISPLAY ? Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER) + RELATION_ITEM_HEIGHT / 2 : Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER);
5174
- return /*#__PURE__*/ jsxs(ShadowBox, {
5175
- $overflowDirection: overflow,
5059
+ React.useLayoutEffect(()=>{
5060
+ setTextValue('');
5061
+ }, [
5062
+ field.value
5063
+ ]);
5064
+ return /*#__PURE__*/ jsxs(Field.Root, {
5065
+ error: field.error,
5066
+ hint: hint,
5067
+ name: name,
5068
+ required: required,
5176
5069
  children: [
5177
- /*#__PURE__*/ jsx(VisuallyHidden, {
5178
- id: ariaDescriptionId,
5179
- children: formatMessage({
5180
- id: getTranslation('dnd.instructions'),
5181
- defaultMessage: `Press spacebar to grab and re-order`
5182
- })
5183
- }),
5184
- /*#__PURE__*/ jsx(VisuallyHidden, {
5185
- "aria-live": "assertive",
5186
- children: liveText
5070
+ /*#__PURE__*/ jsx(Field.Label, {
5071
+ action: labelAction,
5072
+ children: label
5187
5073
  }),
5188
- /*#__PURE__*/ jsx(FixedSizeList, {
5189
- height: dynamicListHeight,
5190
- ref: listRef,
5191
- outerRef: outerListRef,
5192
- itemCount: data.length,
5193
- itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
5194
- itemData: {
5195
- ariaDescribedBy: ariaDescriptionId,
5196
- canDrag: canReorder,
5197
- disabled,
5198
- handleCancel,
5199
- handleDropItem,
5200
- handleGrabItem,
5201
- handleMoveItem,
5202
- name,
5203
- handleDisconnect,
5204
- relations: data,
5205
- targetModel,
5206
- setCurrentDocument
5074
+ /*#__PURE__*/ jsx(Combobox, {
5075
+ ref: fieldRef,
5076
+ name: name,
5077
+ autocomplete: "list",
5078
+ placeholder: placeholder || formatMessage({
5079
+ id: getTranslation('relation.add'),
5080
+ defaultMessage: 'Add relation'
5081
+ }),
5082
+ hasMoreItems: hasNextPage,
5083
+ loading: isLoading,
5084
+ onOpenChange: ()=>{
5085
+ handleSearch(textValue ?? '');
5207
5086
  },
5208
- itemKey: (index)=>data[index].id,
5209
- innerElementType: "ol",
5210
- children: UnstableListItem
5211
- })
5087
+ noOptionsMessage: ()=>formatMessage({
5088
+ id: getTranslation('relation.notAvailable'),
5089
+ defaultMessage: 'No relations available'
5090
+ }),
5091
+ loadingMessage: formatMessage({
5092
+ id: getTranslation('relation.isLoading'),
5093
+ defaultMessage: 'Relations are loading'
5094
+ }),
5095
+ onLoadMore: handleLoadMore,
5096
+ textValue: textValue,
5097
+ onChange: handleChange,
5098
+ onTextValueChange: (text)=>{
5099
+ setTextValue(text);
5100
+ },
5101
+ onInputChange: (event)=>{
5102
+ handleSearch(event.currentTarget.value);
5103
+ },
5104
+ ...props,
5105
+ children: options.map((opt)=>{
5106
+ const textValue = getRelationLabel(opt, mainField);
5107
+ return /*#__PURE__*/ jsx(ComboboxOption, {
5108
+ value: opt.id.toString(),
5109
+ textValue: textValue,
5110
+ children: /*#__PURE__*/ jsxs(Flex, {
5111
+ gap: 2,
5112
+ justifyContent: "space-between",
5113
+ children: [
5114
+ /*#__PURE__*/ jsx(Typography, {
5115
+ ellipsis: true,
5116
+ children: textValue
5117
+ }),
5118
+ opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
5119
+ status: opt.status
5120
+ }) : null
5121
+ ]
5122
+ })
5123
+ }, opt.id);
5124
+ })
5125
+ }),
5126
+ /*#__PURE__*/ jsx(Field.Error, {}),
5127
+ /*#__PURE__*/ jsx(Field.Hint, {})
5212
5128
  ]
5213
5129
  });
5214
5130
  };
5215
- const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType })=>{
5131
+ /* -------------------------------------------------------------------------------------------------
5132
+ * RelationsList
5133
+ * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5134
+ const RELATION_GUTTER = 4;
5135
+ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
5216
5136
  const ariaDescriptionId = React.useId();
5217
5137
  const { formatMessage } = useIntl();
5218
5138
  const listRef = React.useRef(null);
@@ -5376,7 +5296,8 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
5376
5296
  handleMoveItem,
5377
5297
  name,
5378
5298
  handleDisconnect,
5379
- relations: data
5299
+ relations: data,
5300
+ targetModel
5380
5301
  },
5381
5302
  itemKey: (index)=>data[index].id,
5382
5303
  innerElementType: "ol",
@@ -5416,144 +5337,10 @@ const ShadowBox = styled(Box)`
5416
5337
  transition: opacity 0.2s ease-in-out;
5417
5338
  }
5418
5339
  `;
5419
- const CustomTextButton = styled(TextButton)`
5420
- & > span {
5421
- font-size: ${({ theme })=>theme.fontSizes[2]};
5422
- }
5423
- `;
5424
- const UnstableListItem = ({ data, index, style })=>{
5425
- const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel, setCurrentDocument } = data;
5426
- const { formatMessage } = useIntl();
5427
- const [isModalOpen, setIsModalOpen] = React.useState(false);
5428
- const { id, label, status, documentId, href, apiData } = relations[index];
5429
- const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
5430
- type: `${ItemTypes.RELATION}_${name}`,
5431
- index,
5432
- item: {
5433
- displayedValue: label,
5434
- status,
5435
- id: id,
5436
- index
5437
- },
5438
- onMoveItem: handleMoveItem,
5439
- onDropItem: handleDropItem,
5440
- onGrabItem: handleGrabItem,
5441
- onCancel: handleCancel,
5442
- dropSensitivity: DROP_SENSITIVITY.REGULAR
5443
- });
5444
- const composedRefs = useComposedRefs(relationRef, dragRef);
5445
- const handleChangeModalContent = ()=>{
5446
- if (setCurrentDocument) {
5447
- const newRelation = {
5448
- documentId: documentId ? documentId : apiData?.documentId || '',
5449
- model: targetModel,
5450
- collectionType: getCollectionType(href)
5451
- };
5452
- setCurrentDocument(newRelation);
5453
- }
5454
- };
5455
- React.useEffect(()=>{
5456
- dragPreviewRef(getEmptyImage());
5457
- }, [
5458
- dragPreviewRef
5459
- ]);
5460
- return /*#__PURE__*/ jsx(Box, {
5461
- style: style,
5462
- tag: "li",
5463
- ref: dropRef,
5464
- "aria-describedby": ariaDescribedBy,
5465
- cursor: canDrag ? 'all-scroll' : 'default',
5466
- children: isDragging ? /*#__PURE__*/ jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxs(Flex, {
5467
- paddingTop: 2,
5468
- paddingBottom: 2,
5469
- paddingLeft: canDrag ? 2 : 4,
5470
- paddingRight: 4,
5471
- hasRadius: true,
5472
- borderColor: "neutral200",
5473
- background: disabled ? 'neutral150' : 'neutral0',
5474
- justifyContent: "space-between",
5475
- ref: composedRefs,
5476
- "data-handler-id": handlerId,
5477
- children: [
5478
- /*#__PURE__*/ jsxs(FlexWrapper, {
5479
- gap: 1,
5480
- children: [
5481
- canDrag ? /*#__PURE__*/ jsx(IconButton, {
5482
- tag: "div",
5483
- role: "button",
5484
- tabIndex: 0,
5485
- withTooltip: false,
5486
- label: formatMessage({
5487
- id: getTranslation('components.RelationInput.icon-button-aria-label'),
5488
- defaultMessage: 'Drag'
5489
- }),
5490
- variant: "ghost",
5491
- onKeyDown: handleKeyDown,
5492
- disabled: disabled,
5493
- children: /*#__PURE__*/ jsx(Drag, {})
5494
- }) : null,
5495
- /*#__PURE__*/ jsxs(Flex, {
5496
- width: "100%",
5497
- minWidth: 0,
5498
- justifyContent: "space-between",
5499
- children: [
5500
- /*#__PURE__*/ jsx(Box, {
5501
- minWidth: 0,
5502
- paddingTop: 1,
5503
- paddingBottom: 1,
5504
- paddingRight: 4,
5505
- children: /*#__PURE__*/ jsx(Tooltip, {
5506
- description: label,
5507
- children: isModalOpen ? /*#__PURE__*/ jsx(CustomTextButton, {
5508
- onClick: handleChangeModalContent,
5509
- children: label
5510
- }) : /*#__PURE__*/ jsx(CustomTextButton, {
5511
- onClick: ()=>{
5512
- setIsModalOpen(true);
5513
- handleChangeModalContent();
5514
- },
5515
- children: label
5516
- })
5517
- })
5518
- }),
5519
- status ? /*#__PURE__*/ jsx(DocumentStatus, {
5520
- status: status
5521
- }) : null,
5522
- isModalOpen && /*#__PURE__*/ jsx(RelationModal, {
5523
- open: isModalOpen,
5524
- onToggle: ()=>{
5525
- setIsModalOpen(!isModalOpen);
5526
- },
5527
- model: targetModel,
5528
- id: documentId ? documentId : apiData?.documentId,
5529
- relationUrl: href
5530
- })
5531
- ]
5532
- })
5533
- ]
5534
- }),
5535
- /*#__PURE__*/ jsx(Box, {
5536
- paddingLeft: 4,
5537
- children: /*#__PURE__*/ jsx(IconButton, {
5538
- onClick: ()=>handleDisconnect(relations[index]),
5539
- disabled: disabled,
5540
- label: formatMessage({
5541
- id: getTranslation('relation.disconnect'),
5542
- defaultMessage: 'Remove'
5543
- }),
5544
- variant: "ghost",
5545
- size: "S",
5546
- children: /*#__PURE__*/ jsx(Cross, {})
5547
- })
5548
- })
5549
- ]
5550
- })
5551
- });
5552
- };
5553
5340
  const ListItem = ({ data, index, style })=>{
5554
- const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations } = data;
5341
+ const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
5555
5342
  const { formatMessage } = useIntl();
5556
- const { href, id, label, status } = relations[index];
5343
+ const { href, id, label, status, documentId, apiData, locale } = relations[index];
5557
5344
  const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
5558
5345
  type: `${ItemTypes.RELATION}_${name}`,
5559
5346
  index,
@@ -5620,18 +5407,16 @@ const ListItem = ({ data, index, style })=>{
5620
5407
  paddingTop: 1,
5621
5408
  paddingBottom: 1,
5622
5409
  paddingRight: 4,
5623
- children: /*#__PURE__*/ jsx(Tooltip, {
5624
- description: label,
5625
- children: href ? /*#__PURE__*/ jsx(LinkEllipsis, {
5626
- tag: NavLink,
5627
- to: href,
5628
- isExternal: false,
5629
- children: label
5630
- }) : /*#__PURE__*/ jsx(Typography, {
5631
- textColor: disabled ? 'neutral600' : 'primary600',
5632
- ellipsis: true,
5633
- children: label
5634
- })
5410
+ children: /*#__PURE__*/ jsx(RelationModalForm, {
5411
+ triggerButtonLabel: label,
5412
+ relation: {
5413
+ documentId: documentId ?? apiData?.documentId,
5414
+ model: targetModel,
5415
+ collectionType: getCollectionType(href),
5416
+ params: {
5417
+ locale: locale || apiData?.locale || null
5418
+ }
5419
+ }
5635
5420
  })
5636
5421
  }),
5637
5422
  status ? /*#__PURE__*/ jsx(DocumentStatus, {
@@ -5701,7 +5486,6 @@ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsx(Box, {
5701
5486
  height: `calc(100% - ${RELATION_GUTTER}px)`
5702
5487
  });
5703
5488
  const MemoizedRelationsField = /*#__PURE__*/ React.memo(RelationsField);
5704
- const MemoizedUnstableRelationsField = /*#__PURE__*/ React.memo(UnstableRelationsField);
5705
5489
 
5706
5490
  const uidApi = contentManagerApi.injectEndpoints({
5707
5491
  endpoints: (builder)=>({
@@ -7871,22 +7655,27 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
7871
7655
  });
7872
7656
  const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
7873
7657
 
7874
- const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7875
- const { id: rootId } = useDoc();
7876
- const documentMeta = useDocumentContext('InputRenderer', (state)=>state.meta);
7877
- const documentResponse = useDocumentContext('InputRenderer', (state)=>state.document);
7878
- const documentLayout = useDocumentLayout(documentMeta.model);
7879
- const document = documentResponse?.document;
7880
- const collectionType = documentMeta.collectionType;
7658
+ /**
7659
+ * @internal
7660
+ *
7661
+ * @description An abstraction around the regular form input renderer designed
7662
+ * specifically to be used in the EditView of the content-manager this understands
7663
+ * the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
7664
+ * components such as Blocks / Relations.
7665
+ */ const InputRenderer = ({ visible, hint: providedHint, document, ...props })=>{
7666
+ const { model: rootModel } = useDoc();
7667
+ const documentLayout = useDocumentLayout(document.schema?.uid ?? rootModel);
7668
+ const components = documentLayout.edit.components;
7669
+ const collectionType = document.schema?.kind === 'collectionType' ? 'collection-types' : 'single-types';
7881
7670
  const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
7882
7671
  const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
7883
7672
  const canCreateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
7884
7673
  const canReadFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
7885
7674
  const canUpdateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
7886
7675
  const canUserAction = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
7887
- let idToCheck = rootId;
7676
+ let idToCheck = document.document?.documentId;
7888
7677
  if (collectionType === SINGLE_TYPES) {
7889
- idToCheck = document?.documentId;
7678
+ idToCheck = document?.document?.documentId;
7890
7679
  }
7891
7680
  const editableFields = idToCheck ? canUpdateFields : canCreateFields;
7892
7681
  const readableFields = idToCheck ? canReadFields : canCreateFields;
@@ -7900,8 +7689,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7900
7689
  props.attribute.customField
7901
7690
  ] : undefined);
7902
7691
  const hint = useFieldHint(providedHint, props.attribute);
7903
- const { edit: { components: rootDocumentComponents } } = useDocLayout();
7904
- const components = Object.keys(rootDocumentComponents).length !== 0 ? rootDocumentComponents : documentLayout.edit.components;
7905
7692
  // We pass field in case of Custom Fields to keep backward compatibility
7906
7693
  const field = useField(props.name);
7907
7694
  if (!visible) {
@@ -7978,13 +7765,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7978
7765
  disabled: fieldIsDisabled
7979
7766
  });
7980
7767
  case 'relation':
7981
- if (window.strapi.future.isEnabled('unstableRelationsOnTheFly')) {
7982
- return /*#__PURE__*/ jsx(MemoizedUnstableRelationsField, {
7983
- ...props,
7984
- hint: hint,
7985
- disabled: fieldIsDisabled
7986
- });
7987
- }
7988
7768
  return /*#__PURE__*/ jsx(MemoizedRelationsField, {
7989
7769
  ...props,
7990
7770
  hint: hint,
@@ -8090,10 +7870,12 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
8090
7870
  const ResponsiveGridRoot = styled(Grid$1.Root)`
8091
7871
  container-type: inline-size;
8092
7872
  `;
8093
- // We need to use a different grid item for the responsive layout in the test environment
8094
- // because @container is not supported in jsdom and it throws an error
8095
- const ResponsiveGridItem = // TODO: we need to find a better solution to avoid using process.env.NODE_ENV in the code to fix the tests with this styled component
8096
- process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
7873
+ const ResponsiveGridItem = /**
7874
+ * TODO:
7875
+ * JSDOM cannot handle container queries.
7876
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
7877
+ * for failing to parse the stylesheet.
7878
+ */ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
8097
7879
  grid-column: span 12;
8098
7880
  @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
8099
7881
  ${({ col })=>col && `grid-column: span ${col};`}
@@ -8101,10 +7883,9 @@ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
8101
7883
  ` : styled(Grid$1.Item)`
8102
7884
  grid-column: span 12;
8103
7885
  `;
8104
- const FormLayout = ({ layout, hasBackground = true })=>{
7886
+ const FormLayout = ({ layout, document, hasBackground = true })=>{
8105
7887
  const { formatMessage } = useIntl();
8106
- const documentMeta = useDocumentContext('FormLayout', (state)=>state.meta);
8107
- const model = documentMeta.model;
7888
+ const model = document.schema?.modelName;
8108
7889
  return /*#__PURE__*/ jsx(Flex, {
8109
7890
  direction: "column",
8110
7891
  alignItems: "stretch",
@@ -8129,7 +7910,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
8129
7910
  direction: "column",
8130
7911
  alignItems: "stretch",
8131
7912
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
8132
- ...fieldWithTranslatedLabel
7913
+ ...fieldWithTranslatedLabel,
7914
+ document: document
8133
7915
  })
8134
7916
  })
8135
7917
  }, field.name);
@@ -8163,7 +7945,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
8163
7945
  direction: "column",
8164
7946
  alignItems: "stretch",
8165
7947
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
8166
- ...fieldWithTranslatedLabel
7948
+ ...fieldWithTranslatedLabel,
7949
+ document: document
8167
7950
  })
8168
7951
  }, field.name);
8169
7952
  })
@@ -8179,6 +7962,7 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
8179
7962
  const { value } = useField(name);
8180
7963
  const level = useComponent('NonRepeatableComponent', (state)=>state.level);
8181
7964
  const isNested = level > 0;
7965
+ const currentDocument = useDocumentContext('NonRepeatableComponent', (state)=>state.document);
8182
7966
  return /*#__PURE__*/ jsx(ComponentProvider, {
8183
7967
  id: value?.id,
8184
7968
  uid: attribute.component,
@@ -8219,7 +8003,8 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
8219
8003
  children: children({
8220
8004
  ...field,
8221
8005
  label: translatedLabel,
8222
- name: completeFieldName
8006
+ name: completeFieldName,
8007
+ document: currentDocument
8223
8008
  })
8224
8009
  }, completeFieldName);
8225
8010
  })
@@ -8237,7 +8022,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
8237
8022
  const search = React.useMemo(()=>new URLSearchParams(searchString), [
8238
8023
  searchString
8239
8024
  ]);
8240
- const components = useDocumentContext('RepeatableComponent', (state)=>state.document.components);
8025
+ const currentDocument = useDocumentContext('RepeatableComponent', (state)=>state.document);
8026
+ const components = currentDocument.components;
8241
8027
  const { value = [], error, rawError } = useField(name);
8242
8028
  const addFieldRow = useForm('RepeatableComponent', (state)=>state.addFieldRow);
8243
8029
  const moveFieldRow = useForm('RepeatableComponent', (state)=>state.moveFieldRow);
@@ -8440,7 +8226,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
8440
8226
  children: children({
8441
8227
  ...field,
8442
8228
  label: translatedLabel,
8443
- name: completeFieldName
8229
+ name: completeFieldName,
8230
+ document: currentDocument
8444
8231
  })
8445
8232
  }, completeFieldName);
8446
8233
  })
@@ -8667,5 +8454,5 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
8667
8454
  };
8668
8455
  const MemoizedComponentInput = /*#__PURE__*/ React.memo(ComponentInput);
8669
8456
 
8670
- export { DisconnectButton as D, FlexWrapper as F, LinkEllipsis as L, MemoizedUIDInput as M, NotAllowedInput as N, DocumentContextProvider as a, FormLayout as b, useDynamicZone as c, useFieldHint as d, MemoizedWysiwyg as e, DynamicZone as f, MemoizedComponentInput as g, MemoizedBlocksInput as h, useLazyComponents as u };
8671
- //# sourceMappingURL=Input-BPTHgeyh.mjs.map
8457
+ export { DisconnectButton as D, FlexWrapper as F, LinkEllipsis as L, MemoizedUIDInput as M, NotAllowedInput as N, FormLayout as a, useDynamicZone as b, useFieldHint as c, MemoizedWysiwyg as d, DynamicZone as e, MemoizedComponentInput as f, MemoizedBlocksInput as g, useLazyComponents as u };
8458
+ //# sourceMappingURL=Input-DWQWd5MK.mjs.map