@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
@@ -6,7 +6,7 @@ var strapiAdmin = require('@strapi/admin/strapi-admin');
6
6
  var designSystem = require('@strapi/design-system');
7
7
  var Icons = require('@strapi/icons');
8
8
  var reactIntl = require('react-intl');
9
- var index = require('./index-CISU19oJ.js');
9
+ var index = require('./index-CFa6xmgK.js');
10
10
  var styledComponents = require('styled-components');
11
11
  var slate = require('slate');
12
12
  var slateHistory = require('slate-history');
@@ -62,7 +62,7 @@ require('prismjs/components/prism-typescript');
62
62
  require('prismjs/components/prism-tsx');
63
63
  require('prismjs/components/prism-vbnet');
64
64
  require('prismjs/components/prism-yaml');
65
- var usePrev = require('./usePrev-CHotxABl.js');
65
+ var usePrev = require('./usePrev-BEkg-rKP.js');
66
66
  var objects = require('./objects-BJTP843m.js');
67
67
  var Toolbar = require('@radix-ui/react-toolbar');
68
68
  var reactDndHtml5Backend = require('react-dnd-html5-backend');
@@ -108,31 +108,6 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
108
108
  var Prism__namespace = /*#__PURE__*/_interopNamespaceDefault(Prism);
109
109
  var Toolbar__namespace = /*#__PURE__*/_interopNamespaceDefault(Toolbar);
110
110
 
111
- const [DocumentProvider, useDocumentContext] = strapiAdmin.createContext('DocumentContext');
112
- /**
113
- * TODO: Document in contributor docs, Add unit test
114
- *
115
- * This context provider and its associated hook are used to access a document at its root level
116
- * and expose a function to change the current document being viewed to one of the root level docuemnt's relations.
117
- *
118
- * The useDocumentContext hook exposes:
119
- * - meta: information about the currentDocument,
120
- * - document: the actual document,
121
- * - changeDocument: a function to change the current document to one of its relations.
122
- */ const DocumentContextProvider = ({ children, initialDocument })=>{
123
- /**
124
- * Initialize with the "root" document and expose a setter method to change to
125
- * one of the root level document's relations.
126
- */ const [currentDocumentMeta, changeDocument] = React__namespace.useState(initialDocument);
127
- const document = index.useDocument(currentDocumentMeta);
128
- return /*#__PURE__*/ jsxRuntime.jsx(DocumentProvider, {
129
- changeDocument: changeDocument,
130
- document: document,
131
- meta: currentDocumentMeta,
132
- children: children
133
- });
134
- };
135
-
136
111
  const componentStore = new Map();
137
112
  /**
138
113
  * @description A hook to lazy load custom field components
@@ -3628,15 +3603,24 @@ const ComponentCategory = ({ category, components = [], variant = 'primary', onA
3628
3603
  const ResponsiveAccordionContent = styledComponents.styled(designSystem.Accordion.Content)`
3629
3604
  container-type: inline-size;
3630
3605
  `;
3631
- const Grid = styledComponents.styled(designSystem.Box)`
3632
- display: grid;
3633
- grid-template-columns: repeat(auto-fill, 100%);
3634
- grid-gap: ${({ theme })=>theme.spaces[1]};
3635
-
3636
- @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3637
- grid-template-columns: repeat(auto-fill, 14rem);
3638
- }
3639
- `;
3606
+ /**
3607
+ * TODO:
3608
+ * JSDOM cannot handle container queries.
3609
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
3610
+ * for failing to parse the stylesheet.
3611
+ */ const Grid = process.env.NODE_ENV !== 'test' ? styledComponents.styled(designSystem.Box)`
3612
+ display: grid;
3613
+ grid-template-columns: repeat(auto-fill, 100%);
3614
+ grid-gap: 4px;
3615
+
3616
+ @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3617
+ grid-template-columns: repeat(auto-fill, 14rem);
3618
+ }
3619
+ ` : styledComponents.styled(designSystem.Box)`
3620
+ display: grid;
3621
+ grid-template-columns: repeat(auto-fill, 100%);
3622
+ grid-gap: 4px;
3623
+ `;
3640
3624
  const ComponentBox = styledComponents.styled(designSystem.Flex)`
3641
3625
  color: ${({ theme })=>theme.colors.neutral600};
3642
3626
  cursor: pointer;
@@ -3701,8 +3685,19 @@ const ComponentPicker = ({ dynamicComponentsByCategory = {}, isOpen, onClickAddC
3701
3685
  const DynamicComponent = ({ componentUid, disabled, index: index$1, name, onRemoveComponentClick, onMoveComponent, onGrabItem, onDropItem, onCancel, dynamicComponentsByCategory = {}, onAddComponent, children })=>{
3702
3686
  const { formatMessage } = reactIntl.useIntl();
3703
3687
  const formValues = strapiAdmin.useForm('DynamicComponent', (state)=>state.values);
3704
- const documentMeta = useDocumentContext('DynamicComponent', (state)=>state.meta);
3705
- const { edit: { components } } = index.useDocumentLayout(documentMeta.model);
3688
+ const documentMeta = index.useDocumentContext('DynamicComponent', (state)=>state.meta);
3689
+ const rootDocumentMeta = index.useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
3690
+ const { edit: { components: rootComponents } } = index.useDocumentLayout(rootDocumentMeta.model);
3691
+ const { edit: { components: relatedComponents } } = index.useDocumentLayout(documentMeta.model);
3692
+ // Merge the root level components and dynamic zone components
3693
+ const components = React__namespace.useMemo(()=>({
3694
+ ...rootComponents,
3695
+ ...relatedComponents
3696
+ }), [
3697
+ rootComponents,
3698
+ relatedComponents
3699
+ ]);
3700
+ const document = index.useDocumentContext('DynamicComponent', (state)=>state.document);
3706
3701
  const title = React__namespace.useMemo(()=>{
3707
3702
  const { mainField } = components[componentUid]?.settings ?? {
3708
3703
  mainField: 'id'
@@ -3934,9 +3929,11 @@ const DynamicComponent = ({ componentUid, disabled, index: index$1, name, onRemo
3934
3929
  alignItems: "stretch",
3935
3930
  children: children ? children({
3936
3931
  ...fieldWithTranslatedLabel,
3932
+ document,
3937
3933
  name: fieldName
3938
3934
  }) : /*#__PURE__*/ jsxRuntime.jsx(MemoizedInputRenderer, {
3939
3935
  ...fieldWithTranslatedLabel,
3936
+ document: document,
3940
3937
  name: fieldName
3941
3938
  })
3942
3939
  }, fieldName);
@@ -4054,7 +4051,7 @@ const DynamicZone = ({ attribute, disabled: disabledProp, hint, label, labelActi
4054
4051
  const { max = Infinity, min = -Infinity } = attribute ?? {};
4055
4052
  const [addComponentIsOpen, setAddComponentIsOpen] = React__namespace.useState(false);
4056
4053
  const [liveText, setLiveText] = React__namespace.useState('');
4057
- const document = useDocumentContext('DynamicZone', (state)=>state.document);
4054
+ const document = index.useDocumentContext('DynamicZone', (state)=>state.document);
4058
4055
  const { components, isLoading } = document;
4059
4056
  const disabled = disabledProp || isLoading;
4060
4057
  const { addFieldRow, removeFieldRow, moveFieldRow } = strapiAdmin.useForm('DynamicZone', ({ addFieldRow, removeFieldRow, moveFieldRow })=>({
@@ -4299,68 +4296,278 @@ const CustomModalContent = styledComponents.styled(designSystem.Modal.Content)`
4299
4296
  height: 90%;
4300
4297
  max-height: 100%;
4301
4298
  `;
4302
- const RelationModal = ({ open, onToggle, id, model, relationUrl })=>{
4299
+ const [RelationModalProvider, useRelationModal] = strapiAdmin.createContext('RelationModal', {
4300
+ parentModified: false,
4301
+ depth: 0
4302
+ });
4303
+ const RelationModalForm = ({ relation, triggerButtonLabel })=>{
4304
+ const navigate = reactRouterDom.useNavigate();
4305
+ const { pathname, search } = reactRouterDom.useLocation();
4303
4306
  const { formatMessage } = reactIntl.useIntl();
4304
- return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Root, {
4305
- open: open,
4306
- onOpenChange: onToggle,
4307
- children: /*#__PURE__*/ jsxRuntime.jsxs(CustomModalContent, {
4308
- children: [
4309
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Header, {
4310
- children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4307
+ const [triggerRefetchDocument] = index.useLazyGetDocumentQuery();
4308
+ const currentDocument = index.useDocumentContext('RelationModalForm', (state)=>state.document);
4309
+ const rootDocumentMeta = index.useDocumentContext('RelationModalForm', (state)=>state.rootDocumentMeta);
4310
+ const currentDocumentMeta = index.useDocumentContext('RelationModalForm', (state)=>state.meta);
4311
+ const changeDocument = index.useDocumentContext('RelationModalForm', (state)=>state.changeDocument);
4312
+ const documentHistory = index.useDocumentContext('RelationModalForm', (state)=>state.documentHistory);
4313
+ const setDocumentHistory = index.useDocumentContext('RelationModalForm', (state)=>state.setDocumentHistory);
4314
+ const [isConfirmationOpen, setIsConfirmationOpen] = React__namespace.useState(false);
4315
+ const [actionPosition, setActionPosition] = React__namespace.useState('cancel');
4316
+ const [isModalOpen, setIsModalOpen] = React__namespace.useState(false);
4317
+ // NOTE: Not sure about this relation modal context, maybe we should move this to DocumentContext?
4318
+ // Get parent modal context if it exists
4319
+ const parentContext = useRelationModal('RelationModalForm', (state)=>state);
4320
+ // Get depth of nested modals
4321
+ const depth = parentContext ? parentContext.depth + 1 : 0;
4322
+ // Check if this is a nested modal
4323
+ const isNested = depth > 0;
4324
+ const addDocumentToHistory = (document)=>setDocumentHistory((prev)=>[
4325
+ ...prev,
4326
+ document
4327
+ ]);
4328
+ const getPreviousDocument = ()=>{
4329
+ if (documentHistory.length === 0) return undefined;
4330
+ const lastDocument = documentHistory[documentHistory.length - 1];
4331
+ return lastDocument;
4332
+ };
4333
+ const removeLastDocumentFromHistory = ()=>{
4334
+ setDocumentHistory((prev)=>[
4335
+ ...prev
4336
+ ].slice(0, prev.length - 1));
4337
+ };
4338
+ const handleToggleModal = ()=>{
4339
+ if (isModalOpen) {
4340
+ setIsModalOpen(false);
4341
+ const document = {
4342
+ collectionType: rootDocumentMeta.collectionType,
4343
+ model: rootDocumentMeta.model,
4344
+ documentId: rootDocumentMeta.documentId
4345
+ };
4346
+ // Change back to the root document
4347
+ changeDocument(document);
4348
+ // Reset the document history
4349
+ setDocumentHistory([]);
4350
+ // Reset action position
4351
+ setActionPosition('cancel');
4352
+ // Read from cache or refetch root document
4353
+ triggerRefetchDocument(document, // Favor the cache
4354
+ true);
4355
+ } else {
4356
+ changeDocument(relation);
4357
+ setIsModalOpen(true);
4358
+ }
4359
+ };
4360
+ const getFullPageLink = ()=>{
4361
+ const isSingleType = currentDocumentMeta.collectionType === index.SINGLE_TYPES;
4362
+ const queryParams = currentDocumentMeta.params?.locale ? `?plugins[i18n][locale]=${currentDocumentMeta.params.locale}` : '';
4363
+ return `/content-manager/${currentDocumentMeta.collectionType}/${currentDocumentMeta.model}${isSingleType ? '' : '/' + currentDocumentMeta.documentId}${queryParams}`;
4364
+ };
4365
+ const handleRedirection = ()=>{
4366
+ const editViewUrl = `${pathname}${search}`;
4367
+ const isRootDocumentUrl = editViewUrl.includes(getFullPageLink());
4368
+ if (isRootDocumentUrl) {
4369
+ handleToggleModal();
4370
+ } else {
4371
+ navigate(getFullPageLink());
4372
+ }
4373
+ };
4374
+ const handleConfirm = ()=>{
4375
+ if (actionPosition === 'navigate') {
4376
+ handleRedirection();
4377
+ } else if (actionPosition === 'back') {
4378
+ const previousRelation = getPreviousDocument();
4379
+ if (previousRelation) {
4380
+ removeLastDocumentFromHistory();
4381
+ changeDocument(previousRelation);
4382
+ }
4383
+ } else {
4384
+ handleToggleModal();
4385
+ }
4386
+ };
4387
+ return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Form, {
4388
+ method: "PUT",
4389
+ initialValues: currentDocument.getInitialFormValues(),
4390
+ validate: (values, options)=>{
4391
+ const yupSchema = index.createYupSchema(currentDocument.schema?.attributes, currentDocument.components, {
4392
+ status: currentDocument.document?.status,
4393
+ ...options
4394
+ });
4395
+ return yupSchema.validate(values, {
4396
+ abortEarly: false
4397
+ });
4398
+ },
4399
+ children: ({ modified, isSubmitting, resetForm })=>{
4400
+ // We don't count the root document, so history starts after 1
4401
+ const hasHistory = documentHistory.length > 1;
4402
+ return /*#__PURE__*/ jsxRuntime.jsxs(RelationModalProvider, {
4403
+ parentModified: modified,
4404
+ depth: depth,
4405
+ children: [
4406
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Modal.Root, {
4407
+ open: isModalOpen,
4408
+ onOpenChange: ()=>{
4409
+ if (isModalOpen) {
4410
+ if (modified && !isSubmitting) {
4411
+ setIsConfirmationOpen(true);
4412
+ } else {
4413
+ handleToggleModal();
4414
+ }
4415
+ }
4416
+ },
4311
4417
  children: [
4312
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
4313
- withTooltip: false,
4314
- label: "Back",
4315
- variant: "ghost",
4316
- disabled: true,
4317
- onClick: ()=>{},
4318
- marginRight: 1,
4319
- children: /*#__PURE__*/ jsxRuntime.jsx(Icons.ArrowLeft, {})
4320
- }),
4321
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
4322
- tag: "span",
4323
- fontWeight: 600,
4324
- children: formatMessage({
4325
- id: 'content-manager.components.RelationInputModal.modal-title',
4326
- defaultMessage: 'Edit a relation'
4418
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Trigger, {
4419
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
4420
+ description: triggerButtonLabel,
4421
+ children: /*#__PURE__*/ jsxRuntime.jsx(CustomTextButton, {
4422
+ onClick: ()=>{
4423
+ // Check if parent modal has unsaved changes
4424
+ if (isNested && parentContext.parentModified) {
4425
+ setIsConfirmationOpen(true);
4426
+ // Return early to avoid opening the modal
4427
+ return;
4428
+ } else {
4429
+ if (modified && !isSubmitting) {
4430
+ setIsConfirmationOpen(true);
4431
+ } else {
4432
+ // Add current relation to history before opening a new one
4433
+ if (currentDocumentMeta && Object.keys(currentDocumentMeta).length > 0) {
4434
+ addDocumentToHistory(currentDocumentMeta);
4435
+ }
4436
+ handleToggleModal();
4437
+ }
4438
+ if (!isModalOpen) {
4439
+ setIsModalOpen(true);
4440
+ }
4441
+ }
4442
+ },
4443
+ children: triggerButtonLabel
4444
+ })
4327
4445
  })
4446
+ }),
4447
+ /*#__PURE__*/ jsxRuntime.jsxs(CustomModalContent, {
4448
+ children: [
4449
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Header, {
4450
+ gap: 2,
4451
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
4452
+ justifyContent: "space-between",
4453
+ alignItems: "center",
4454
+ width: "100%",
4455
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4456
+ gap: 2,
4457
+ children: [
4458
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
4459
+ withTooltip: false,
4460
+ label: "Back",
4461
+ variant: "ghost",
4462
+ disabled: !hasHistory,
4463
+ onClick: ()=>{
4464
+ setActionPosition('back');
4465
+ if (modified && !isSubmitting) {
4466
+ setIsConfirmationOpen(true);
4467
+ } else {
4468
+ const previousRelation = getPreviousDocument();
4469
+ if (previousRelation) {
4470
+ removeLastDocumentFromHistory();
4471
+ changeDocument(previousRelation);
4472
+ }
4473
+ }
4474
+ },
4475
+ marginRight: 1,
4476
+ children: /*#__PURE__*/ jsxRuntime.jsx(Icons.ArrowLeft, {})
4477
+ }),
4478
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
4479
+ tag: "span",
4480
+ fontWeight: 600,
4481
+ children: formatMessage({
4482
+ id: 'content-manager.components.RelationInputModal.modal-title',
4483
+ defaultMessage: 'Edit a relation'
4484
+ })
4485
+ })
4486
+ ]
4487
+ })
4488
+ })
4489
+ }),
4490
+ /*#__PURE__*/ jsxRuntime.jsx(RelationModalBody, {
4491
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
4492
+ onClick: ()=>{
4493
+ setActionPosition('navigate');
4494
+ if (modified && !isSubmitting) {
4495
+ setIsConfirmationOpen(true);
4496
+ } else {
4497
+ navigate(getFullPageLink());
4498
+ }
4499
+ },
4500
+ variant: "tertiary",
4501
+ label: formatMessage({
4502
+ id: 'content-manager.components.RelationInputModal.button-fullpage',
4503
+ defaultMessage: 'Go to entry'
4504
+ }),
4505
+ children: /*#__PURE__*/ jsxRuntime.jsx(Icons.ArrowsOut, {})
4506
+ })
4507
+ }),
4508
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Footer, {
4509
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
4510
+ onClick: ()=>{
4511
+ if (modified && !isSubmitting) {
4512
+ setIsConfirmationOpen(true);
4513
+ } else {
4514
+ handleToggleModal();
4515
+ }
4516
+ },
4517
+ variant: "tertiary",
4518
+ children: formatMessage({
4519
+ id: 'app.components.Button.cancel',
4520
+ defaultMessage: 'Cancel'
4521
+ })
4522
+ })
4523
+ })
4524
+ ]
4328
4525
  })
4329
4526
  ]
4330
- })
4331
- }),
4332
- /*#__PURE__*/ jsxRuntime.jsx(RelationModalBody, {
4333
- id: id,
4334
- model: model,
4335
- collectionType: getCollectionType(relationUrl),
4336
- isModalOpen: open,
4337
- onToggleModal: onToggle
4338
- }),
4339
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Footer, {
4340
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
4341
- onClick: onToggle,
4342
- variant: "tertiary",
4343
- children: formatMessage({
4344
- id: 'app.components.Button.cancel',
4345
- defaultMessage: 'Cancel'
4527
+ }),
4528
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Dialog.Root, {
4529
+ open: isConfirmationOpen,
4530
+ onOpenChange: setIsConfirmationOpen,
4531
+ children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.ConfirmDialog, {
4532
+ onConfirm: ()=>{
4533
+ handleConfirm();
4534
+ setIsConfirmationOpen(false);
4535
+ resetForm();
4536
+ },
4537
+ onCancel: ()=>{
4538
+ setIsConfirmationOpen(false);
4539
+ },
4540
+ variant: "danger",
4541
+ children: formatMessage({
4542
+ id: 'content-manager.components.RelationInputModal.confirmation-message',
4543
+ defaultMessage: 'Some changes were not saved. Are you sure you want to close this relation? All changes that were not saved will be lost.'
4544
+ })
4346
4545
  })
4347
4546
  })
4348
- })
4349
- ]
4350
- })
4547
+ ]
4548
+ });
4549
+ }
4351
4550
  });
4352
4551
  };
4353
- const RelationModalBody = ({ id })=>{
4552
+ const CustomTextButton = styledComponents.styled(designSystem.TextButton)`
4553
+ & > span {
4554
+ font-size: ${({ theme })=>theme.fontSizes[2]};
4555
+ }
4556
+ `;
4557
+ const RelationModalBody = ({ children })=>{
4354
4558
  const { formatMessage } = reactIntl.useIntl();
4355
- const documentMeta = useDocumentContext('RelationModalBody', (state)=>state.meta);
4356
- const documentResponse = useDocumentContext('RelationModalBody', (state)=>state.document);
4559
+ const documentMeta = index.useDocumentContext('RelationModalBody', (state)=>state.meta);
4560
+ const documentResponse = index.useDocumentContext('RelationModalBody', (state)=>state.document);
4561
+ const onPreview = index.useDocumentContext('RelationModalBody', (state)=>state.onPreview);
4357
4562
  const documentLayoutResponse = index.useDocumentLayout(documentMeta.model);
4563
+ const plugins = strapiAdmin.useStrapiApp('RelationModalBody', (state)=>state.plugins);
4358
4564
  const initialValues = documentResponse.getInitialFormValues();
4359
- const { permissions = [], isLoading, error } = strapiAdmin.useRBAC(index.PERMISSIONS.map((action)=>({
4565
+ const { permissions = [], isLoading: isLoadingPermissions, error } = strapiAdmin.useRBAC(index.PERMISSIONS.map((action)=>({
4360
4566
  action,
4361
4567
  subject: documentMeta.model
4362
4568
  })));
4363
- if (isLoading || documentResponse.isLoading || documentLayoutResponse.isLoading) {
4569
+ const isLoading = isLoadingPermissions || documentLayoutResponse.isLoading || documentResponse.isLoading;
4570
+ if (isLoading && !documentResponse.document?.documentId) {
4364
4571
  return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Loader, {
4365
4572
  small: true,
4366
4573
  children: formatMessage({
@@ -4387,44 +4594,95 @@ const RelationModalBody = ({ id })=>{
4387
4594
  }
4388
4595
  const documentTitle = documentResponse.getTitle(documentLayoutResponse.edit.settings.mainField);
4389
4596
  const hasDraftAndPublished = documentResponse.schema?.options?.draftAndPublish ?? false;
4597
+ const props = {
4598
+ activeTab: 'draft',
4599
+ collectionType: documentMeta.collectionType,
4600
+ model: documentMeta.model,
4601
+ documentId: documentMeta.documentId,
4602
+ document: documentResponse.document,
4603
+ meta: documentResponse.meta,
4604
+ onPreview
4605
+ };
4390
4606
  return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Body, {
4391
4607
  children: /*#__PURE__*/ jsxRuntime.jsxs(index.DocumentRBAC, {
4392
4608
  permissions: permissions,
4393
4609
  model: documentMeta.model,
4394
4610
  children: [
4395
4611
  /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4396
- direction: "column",
4397
4612
  alignItems: "flex-start",
4613
+ direction: "column",
4398
4614
  gap: 2,
4399
4615
  children: [
4400
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
4401
- tag: "h2",
4402
- variant: "alpha",
4403
- children: documentTitle
4616
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4617
+ width: "100%",
4618
+ justifyContent: "space-between",
4619
+ gap: 2,
4620
+ children: [
4621
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
4622
+ tag: "h2",
4623
+ variant: "alpha",
4624
+ children: documentTitle
4625
+ }),
4626
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4627
+ gap: 2,
4628
+ children: [
4629
+ children,
4630
+ /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.DescriptionComponentRenderer, {
4631
+ props: props,
4632
+ descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
4633
+ children: (actions)=>{
4634
+ const filteredActions = actions.filter((action)=>{
4635
+ return [
4636
+ action.position
4637
+ ].flat().includes('relation-modal');
4638
+ });
4639
+ const [primaryAction, secondaryAction] = filteredActions;
4640
+ if (!primaryAction && !secondaryAction) return null;
4641
+ // Both actions are available when draft and publish enabled
4642
+ if (primaryAction && secondaryAction) {
4643
+ return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
4644
+ children: [
4645
+ /*#__PURE__*/ jsxRuntime.jsx(index.DocumentActionButton, {
4646
+ ...secondaryAction,
4647
+ variant: secondaryAction.variant || 'secondary'
4648
+ }),
4649
+ /*#__PURE__*/ jsxRuntime.jsx(index.DocumentActionButton, {
4650
+ ...primaryAction,
4651
+ variant: primaryAction.variant || 'default'
4652
+ })
4653
+ ]
4654
+ });
4655
+ }
4656
+ // Otherwise we just have the save action
4657
+ return /*#__PURE__*/ jsxRuntime.jsx(index.DocumentActionButton, {
4658
+ ...primaryAction,
4659
+ variant: primaryAction.variant || 'secondary'
4660
+ });
4661
+ }
4662
+ })
4663
+ ]
4664
+ })
4665
+ ]
4404
4666
  }),
4405
4667
  hasDraftAndPublished ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
4406
- marginTop: 1,
4407
4668
  children: /*#__PURE__*/ jsxRuntime.jsx(index.DocumentStatus, {
4408
4669
  status: documentResponse.document?.status
4409
4670
  })
4410
4671
  }) : null
4411
4672
  ]
4412
4673
  }),
4413
- /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Form, {
4414
- initialValues: initialValues,
4415
- method: id ? 'PUT' : 'POST',
4416
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
4417
- flex: 1,
4674
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
4675
+ flex: 1,
4676
+ overflow: "auto",
4677
+ alignItems: "stretch",
4678
+ paddingTop: 7,
4679
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
4418
4680
  overflow: "auto",
4419
- alignItems: "stretch",
4420
- paddingTop: 7,
4421
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
4422
- overflow: "auto",
4423
- flex: 1,
4424
- children: /*#__PURE__*/ jsxRuntime.jsx(FormLayout, {
4425
- layout: documentLayoutResponse.edit.layout,
4426
- hasBackground: false
4427
- })
4681
+ flex: 1,
4682
+ children: /*#__PURE__*/ jsxRuntime.jsx(FormLayout, {
4683
+ layout: documentLayoutResponse.edit.layout,
4684
+ document: documentResponse,
4685
+ hasBackground: false
4428
4686
  })
4429
4687
  })
4430
4688
  })
@@ -4485,15 +4743,18 @@ const ONE_WAY_RELATIONS = [
4485
4743
  * @description The relations field holds a lot of domain logic for handling relations which is rather complicated
4486
4744
  * At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
4487
4745
  * they wish to do so.
4488
- */ const UnstableRelationsField = /*#__PURE__*/ React__namespace.forwardRef(({ disabled, label, ...props }, ref)=>{
4489
- const documentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4490
- const documentResponse = useDocumentContext('RelationsField', (state)=>state.document);
4491
- const changeDocument = useDocumentContext('RelationsField', (state)=>state.changeDocument);
4746
+ */ const RelationsField = /*#__PURE__*/ React__namespace.forwardRef(({ disabled, label, ...props }, ref)=>{
4747
+ const currentDocumentMeta = index.useDocumentContext('RelationsField', (state)=>state.meta);
4748
+ const currentDocument = index.useDocumentContext('RelationsField', (state)=>state.document);
4749
+ const rootDocumentMeta = index.useDocumentContext('RelationsField', (state)=>state.rootDocumentMeta);
4492
4750
  const [currentPage, setCurrentPage] = React__namespace.useState(1);
4493
- const documentId = documentResponse.document?.documentId;
4751
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4752
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4753
+ // Use the documentId from the actual document, not the params (meta)
4754
+ const documentId = currentDocument.document?.documentId;
4494
4755
  const { formatMessage } = reactIntl.useIntl();
4495
4756
  const [{ query }] = strapiAdmin.useQueryParams();
4496
- const params = index.buildValidParams(query);
4757
+ const params = documentMeta.params ?? index.buildValidParams(query);
4497
4758
  const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4498
4759
  const isDisabled = isMorph || disabled;
4499
4760
  const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
@@ -4506,17 +4767,24 @@ const ONE_WAY_RELATIONS = [
4506
4767
  }, [
4507
4768
  isSubmitting
4508
4769
  ]);
4770
+ const component = componentUID && currentDocument.components[componentUID];
4509
4771
  /**
4510
4772
  * We'll always have a documentId in a created entry, so we look for a componentId first.
4511
4773
  * Same with `uid` and `documentModel`.
4512
- */ const id = componentId ? componentId.toString() : documentId;
4513
- const model = componentUID ?? documentMeta.model;
4774
+ */ const model = component ? component.uid : documentMeta.model;
4775
+ const id = component && componentId ? componentId.toString() : documentId;
4514
4776
  /**
4515
4777
  * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4516
4778
  * Where the above example would a nested field within two components, however
4517
4779
  * we only require the field on the component not the complete path since we query
4518
4780
  * individual components. Therefore we split the string and take the last item.
4519
4781
  */ const [targetField] = props.name.split('.').slice(-1);
4782
+ const schemaAttributes = component ? component.attributes ?? {} : currentDocument.schema?.attributes ?? {};
4783
+ /**
4784
+ * Confirm the target field is related to the current document.
4785
+ * Since relations can exist in a modal on top of the root document,
4786
+ * we need to ensure we are fetching relations for the correct document (root document vs related document),
4787
+ */ const isRelatedToCurrentDocument = Object.values(schemaAttributes).filter((attribute)=>attribute.type === 'relation' && 'target' in attribute && 'target' in props.attribute && attribute.target === props.attribute.target).length > 0;
4520
4788
  const { data, isLoading, isFetching } = usePrev.useGetRelationsQuery({
4521
4789
  model,
4522
4790
  targetField,
@@ -4529,7 +4797,7 @@ const ONE_WAY_RELATIONS = [
4529
4797
  }
4530
4798
  }, {
4531
4799
  refetchOnMountOrArgChange: true,
4532
- skip: !id,
4800
+ skip: !id || !isRelatedToCurrentDocument,
4533
4801
  selectFromResult: (result)=>{
4534
4802
  return {
4535
4803
  ...result,
@@ -4638,10 +4906,11 @@ const ONE_WAY_RELATIONS = [
4638
4906
  /*#__PURE__*/ jsxRuntime.jsx(RelationsInput, {
4639
4907
  disabled: isDisabled,
4640
4908
  // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4641
- id: componentUID ? componentId ? `${componentId}` : '' : documentId,
4909
+ id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
4642
4910
  label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4643
4911
  model: model,
4644
4912
  onChange: handleConnect,
4913
+ isRelatedToCurrentDocument: isRelatedToCurrentDocument,
4645
4914
  ...props
4646
4915
  }),
4647
4916
  'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.TextButton, {
@@ -4658,7 +4927,7 @@ const ONE_WAY_RELATIONS = [
4658
4927
  }) : null
4659
4928
  ]
4660
4929
  }),
4661
- /*#__PURE__*/ jsxRuntime.jsx(UnstableRelationsList, {
4930
+ /*#__PURE__*/ jsxRuntime.jsx(RelationsList, {
4662
4931
  data: relations,
4663
4932
  serverData: data.results,
4664
4933
  disabled: isDisabled,
@@ -4666,575 +4935,226 @@ const ONE_WAY_RELATIONS = [
4666
4935
  isLoading: isFetchingMoreRelations,
4667
4936
  relationType: props.attribute.relation,
4668
4937
  // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4669
- targetModel: props.attribute.targetModel,
4670
- setCurrentDocument: changeDocument
4938
+ targetModel: props.attribute.targetModel
4671
4939
  })
4672
4940
  ]
4673
4941
  });
4674
4942
  });
4675
- const RelationsField = /*#__PURE__*/ React__namespace.forwardRef(({ disabled, label, ...props }, ref)=>{
4676
- const [currentPage, setCurrentPage] = React__namespace.useState(1);
4677
- const { document, model: documentModel } = index.useDoc();
4678
- const documentId = document?.documentId;
4679
- const { formatMessage } = reactIntl.useIntl();
4943
+ /**
4944
+ * TODO: this can be removed once we stop shipping Inputs with
4945
+ * labels wrapped round in DS@2.
4946
+ */ const StyledFlex = styledComponents.styled(designSystem.Flex)`
4947
+ & > div {
4948
+ width: 100%;
4949
+ }
4950
+ `;
4951
+ /**
4952
+ * If it's in the connected array, it can get out of our data array,
4953
+ * we'll be putting it back in later and sorting it anyway.
4954
+ */ const removeConnected = ({ field })=>(relations)=>{
4955
+ return relations.filter((relation)=>{
4956
+ const connectedRelations = field?.connect ?? [];
4957
+ return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4958
+ });
4959
+ };
4960
+ /**
4961
+ * @description Removes relations that are in the `disconnect` array of the field
4962
+ */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4963
+ const disconnectedRelations = field?.disconnect ?? [];
4964
+ return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4965
+ });
4966
+ /**
4967
+ * @description Adds a label and href to the relation object we use this to render
4968
+ * a better UI where we can link to the relation and display a human-readable label.
4969
+ */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4970
+ return {
4971
+ ...relation,
4972
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4973
+ [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4974
+ label: usePrev.getRelationLabel(relation, mainField),
4975
+ href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4976
+ };
4977
+ });
4978
+ /**
4979
+ * @description Contains all the logic for the combobox that can search
4980
+ * for relations and then add them to the field's connect array.
4981
+ */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
4982
+ const [textValue, setTextValue] = React__namespace.useState('');
4983
+ const [searchParams, setSearchParams] = React__namespace.useState({
4984
+ _q: '',
4985
+ page: 1
4986
+ });
4987
+ const { toggleNotification } = strapiAdmin.useNotification();
4680
4988
  const [{ query }] = strapiAdmin.useQueryParams();
4681
- const params = index.buildValidParams(query);
4682
- const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4683
- const isDisabled = isMorph || disabled;
4684
- const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
4685
- componentId: id,
4686
- componentUID: uid
4687
- }));
4688
- const isSubmitting = strapiAdmin.useForm('RelationsList', (state)=>state.isSubmitting);
4689
- React__namespace.useEffect(()=>{
4690
- setCurrentPage(1);
4691
- }, [
4692
- isSubmitting
4693
- ]);
4694
- /**
4695
- * We'll always have a documentId in a created entry, so we look for a componentId first.
4696
- * Same with `uid` and `documentModel`.
4697
- */ const id = componentId ? componentId.toString() : documentId;
4698
- const model = componentUID ?? documentModel;
4989
+ const currentDocumentMeta = index.useDocumentContext('RelationsInput', (state)=>state.meta);
4990
+ const rootDocumentMeta = index.useDocumentContext('RelationsInput', (state)=>state.rootDocumentMeta);
4991
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4992
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4993
+ const { formatMessage } = reactIntl.useIntl();
4994
+ const fieldRef = strapiAdmin.useFocusInputField(name);
4995
+ const field = strapiAdmin.useField(name);
4996
+ const searchParamsDebounced = usePrev.useDebounce(searchParams, 300);
4997
+ const [searchForTrigger, { data, isLoading }] = usePrev.useLazySearchRelationsQuery();
4699
4998
  /**
4999
+ * Because we're using a lazy query, we need to trigger the search
5000
+ * when the component mounts and when the search params change.
5001
+ * We also need to trigger the search when the field value changes
5002
+ * so that we can filter out the relations that are already connected.
5003
+ */ React__namespace.useEffect(()=>{
5004
+ /**
4700
5005
  * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4701
5006
  * Where the above example would a nested field within two components, however
4702
5007
  * we only require the field on the component not the complete path since we query
4703
5008
  * individual components. Therefore we split the string and take the last item.
4704
- */ const [targetField] = props.name.split('.').slice(-1);
4705
- const { data, isLoading, isFetching } = usePrev.useGetRelationsQuery({
5009
+ */ const [targetField] = name.split('.').slice(-1);
5010
+ // Return early if there is no relation to the document
5011
+ if (!isRelatedToCurrentDocument) return;
5012
+ const params = documentMeta.params ?? index.buildValidParams(query);
5013
+ searchForTrigger({
5014
+ model,
5015
+ targetField,
5016
+ params: {
5017
+ ...params,
5018
+ id: id ?? '',
5019
+ pageSize: 10,
5020
+ idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
5021
+ idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
5022
+ ...searchParamsDebounced
5023
+ }
5024
+ });
5025
+ }, [
5026
+ field.value?.connect,
5027
+ field.value?.disconnect,
5028
+ id,
4706
5029
  model,
4707
- targetField,
4708
- // below we don't run the query if there is no id.
4709
- id: id,
4710
- params: {
4711
- ...params,
4712
- pageSize: RELATIONS_TO_DISPLAY,
4713
- page: currentPage
5030
+ name,
5031
+ query,
5032
+ searchForTrigger,
5033
+ searchParamsDebounced,
5034
+ isRelatedToCurrentDocument,
5035
+ documentMeta
5036
+ ]);
5037
+ const handleSearch = async (search)=>{
5038
+ setSearchParams((s)=>({
5039
+ ...s,
5040
+ _q: search,
5041
+ page: 1
5042
+ }));
5043
+ };
5044
+ const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
5045
+ const options = data?.results ?? [];
5046
+ const handleChange = (relationId)=>{
5047
+ if (!relationId) {
5048
+ return;
4714
5049
  }
4715
- }, {
4716
- refetchOnMountOrArgChange: true,
4717
- skip: !id,
4718
- selectFromResult: (result)=>{
4719
- return {
4720
- ...result,
4721
- data: {
4722
- ...result.data,
4723
- results: result.data?.results ? result.data.results : []
4724
- }
4725
- };
5050
+ const relation = options.find((opt)=>opt.id.toString() === relationId);
5051
+ if (!relation) {
5052
+ // This is very unlikely to happen, but it ensures we don't have any data for.
5053
+ 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.");
5054
+ toggleNotification({
5055
+ message: formatMessage({
5056
+ id: index.getTranslation('relation.error-adding-relation'),
5057
+ defaultMessage: 'An error occurred while trying to add the relation.'
5058
+ }),
5059
+ type: 'danger'
5060
+ });
5061
+ return;
4726
5062
  }
4727
- });
4728
- const handleLoadMore = ()=>{
4729
- setCurrentPage((prev)=>prev + 1);
4730
- };
4731
- const field = strapiAdmin.useField(props.name);
4732
- const isFetchingMoreRelations = isLoading || isFetching;
4733
- const realServerRelationsCount = 'pagination' in data && data.pagination ? data.pagination.total : 0;
4734
- /**
4735
- * Items that are already connected, but reordered would be in
4736
- * this list, so to get an accurate figure, we remove them.
4737
- */ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
4738
- const relationsDisconnected = field.value?.disconnect?.length ?? 0;
4739
- const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
4740
- /**
4741
- * This is it, the source of truth for reordering in conjunction with partial loading & updating
4742
- * of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
4743
- * create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
4744
- */ const relations = React__namespace.useMemo(()=>{
4745
- const ctx = {
4746
- field: field.value,
4747
- // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4748
- href: `../${index.COLLECTION_TYPES}/${props.attribute.targetModel}`,
4749
- mainField: props.mainField
4750
- };
4751
- /**
4752
- * Tidy up our data.
4753
- */ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
4754
- const transformedRels = transformations([
4755
- ...data.results
4756
- ]);
4757
- /**
4758
- * THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
4759
- * then the list will be in the wrong order.
4760
- */ return [
4761
- ...transformedRels,
4762
- ...field.value?.connect ?? []
4763
- ].sort((a, b)=>{
4764
- if (a.__temp_key__ < b.__temp_key__) return -1;
4765
- if (a.__temp_key__ > b.__temp_key__) return 1;
4766
- return 0;
4767
- });
4768
- }, [
4769
- data.results,
4770
- field.value,
4771
- // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4772
- props.attribute.targetModel,
4773
- props.mainField
4774
- ]);
4775
- const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
4776
- const handleConnect = (relation)=>{
4777
- const [lastItemInList] = relations.slice(-1);
4778
- const item = {
4779
- id: relation.id,
4780
- apiData: {
4781
- id: relation.id,
4782
- documentId: relation.documentId,
4783
- locale: relation.locale
4784
- },
4785
- status: relation.status,
4786
- /**
4787
- * If there's a last item, that's the first key we use to generate out next one.
4788
- */ __temp_key__: fractionalIndexing.generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
4789
- // Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
4790
- [props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
4791
- label: usePrev.getRelationLabel(relation, props.mainField),
4792
- // @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
4793
- href: `../${index.COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4794
- };
4795
- if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
4796
- // Remove any existing relation so they can be replaced with the new one
4797
- field.value?.connect?.forEach(handleDisconnect);
4798
- relations.forEach(handleDisconnect);
4799
- field.onChange(`${props.name}.connect`, [
4800
- item
4801
- ]);
4802
- } else {
4803
- field.onChange(`${props.name}.connect`, [
4804
- ...field.value?.connect ?? [],
4805
- item
4806
- ]);
4807
- }
4808
- };
4809
- return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
4810
- ref: ref,
4811
- direction: "column",
4812
- gap: 3,
4813
- justifyContent: "space-between",
4814
- alignItems: "stretch",
4815
- wrap: "wrap",
4816
- children: [
4817
- /*#__PURE__*/ jsxRuntime.jsxs(StyledFlex, {
4818
- direction: "column",
4819
- alignItems: "start",
4820
- gap: 2,
4821
- width: "100%",
4822
- children: [
4823
- /*#__PURE__*/ jsxRuntime.jsx(RelationsInput, {
4824
- disabled: isDisabled,
4825
- // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4826
- id: componentUID ? componentId ? `${componentId}` : '' : documentId,
4827
- label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4828
- model: model,
4829
- onChange: handleConnect,
4830
- ...props
4831
- }),
4832
- 'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.TextButton, {
4833
- disabled: isFetchingMoreRelations,
4834
- onClick: handleLoadMore,
4835
- loading: isFetchingMoreRelations,
4836
- startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icons.ArrowClockwise, {}),
4837
- // prevent the label from line-wrapping
4838
- shrink: 0,
4839
- children: formatMessage({
4840
- id: index.getTranslation('relation.loadMore'),
4841
- defaultMessage: 'Load More'
4842
- })
4843
- }) : null
4844
- ]
4845
- }),
4846
- /*#__PURE__*/ jsxRuntime.jsx(RelationsList, {
4847
- data: relations,
4848
- serverData: data.results,
4849
- disabled: isDisabled,
4850
- name: props.name,
4851
- isLoading: isFetchingMoreRelations,
4852
- relationType: props.attribute.relation
4853
- })
4854
- ]
4855
- });
4856
- });
4857
- /**
4858
- * TODO: this can be removed once we stop shipping Inputs with
4859
- * labels wrapped round in DS@2.
4860
- */ const StyledFlex = styledComponents.styled(designSystem.Flex)`
4861
- & > div {
4862
- width: 100%;
4863
- }
4864
- `;
4865
- /**
4866
- * If it's in the connected array, it can get out of our data array,
4867
- * we'll be putting it back in later and sorting it anyway.
4868
- */ const removeConnected = ({ field })=>(relations)=>{
4869
- return relations.filter((relation)=>{
4870
- const connectedRelations = field?.connect ?? [];
4871
- return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4872
- });
4873
- };
4874
- /**
4875
- * @description Removes relations that are in the `disconnect` array of the field
4876
- */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4877
- const disconnectedRelations = field?.disconnect ?? [];
4878
- return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4879
- });
4880
- /**
4881
- * @description Adds a label and href to the relation object we use this to render
4882
- * a better UI where we can link to the relation and display a human-readable label.
4883
- */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4884
- return {
4885
- ...relation,
4886
- // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4887
- [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4888
- label: usePrev.getRelationLabel(relation, mainField),
4889
- href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4890
- };
4891
- });
4892
- /**
4893
- * @description Contains all the logic for the combobox that can search
4894
- * for relations and then add them to the field's connect array.
4895
- */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, ...props })=>{
4896
- const [textValue, setTextValue] = React__namespace.useState('');
4897
- const [searchParams, setSearchParams] = React__namespace.useState({
4898
- _q: '',
4899
- page: 1
4900
- });
4901
- const { toggleNotification } = strapiAdmin.useNotification();
4902
- const [{ query }] = strapiAdmin.useQueryParams();
4903
- const { formatMessage } = reactIntl.useIntl();
4904
- const fieldRef = strapiAdmin.useFocusInputField(name);
4905
- const field = strapiAdmin.useField(name);
4906
- const searchParamsDebounced = usePrev.useDebounce(searchParams, 300);
4907
- const [searchForTrigger, { data, isLoading }] = usePrev.useLazySearchRelationsQuery();
4908
- /**
4909
- * Because we're using a lazy query, we need to trigger the search
4910
- * when the component mounts and when the search params change.
4911
- * We also need to trigger the search when the field value changes
4912
- * so that we can filter out the relations that are already connected.
4913
- */ React__namespace.useEffect(()=>{
4914
- /**
4915
- * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4916
- * Where the above example would a nested field within two components, however
4917
- * we only require the field on the component not the complete path since we query
4918
- * individual components. Therefore we split the string and take the last item.
4919
- */ const [targetField] = name.split('.').slice(-1);
4920
- searchForTrigger({
4921
- model,
4922
- targetField,
4923
- params: {
4924
- ...index.buildValidParams(query),
4925
- id: id ?? '',
4926
- pageSize: 10,
4927
- idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
4928
- idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
4929
- ...searchParamsDebounced
4930
- }
4931
- });
4932
- }, [
4933
- field.value?.connect,
4934
- field.value?.disconnect,
4935
- id,
4936
- model,
4937
- name,
4938
- query,
4939
- searchForTrigger,
4940
- searchParamsDebounced
4941
- ]);
4942
- const handleSearch = async (search)=>{
4943
- setSearchParams((s)=>({
4944
- ...s,
4945
- _q: search,
4946
- page: 1
4947
- }));
4948
- };
4949
- const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
4950
- const options = data?.results ?? [];
4951
- const handleChange = (relationId)=>{
4952
- if (!relationId) {
4953
- return;
4954
- }
4955
- const relation = options.find((opt)=>opt.id.toString() === relationId);
4956
- if (!relation) {
4957
- // This is very unlikely to happen, but it ensures we don't have any data for.
4958
- 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.");
4959
- toggleNotification({
4960
- message: formatMessage({
4961
- id: index.getTranslation('relation.error-adding-relation'),
4962
- defaultMessage: 'An error occurred while trying to add the relation.'
4963
- }),
4964
- type: 'danger'
4965
- });
4966
- return;
4967
- }
4968
- /**
4969
- * You need to give this relation a correct _temp_key_ but
4970
- * this component doesn't know about those ones, you can't rely
4971
- * on the connect array because that doesn't hold items that haven't
4972
- * moved. So use a callback to fill in the gaps when connecting.
4973
- *
4974
- */ onChange(relation);
4975
- };
4976
- const handleLoadMore = ()=>{
4977
- if (!data || !data.pagination) {
4978
- return;
4979
- } else if (data.pagination.page < data.pagination.pageCount) {
4980
- setSearchParams((s)=>({
4981
- ...s,
4982
- page: s.page + 1
4983
- }));
4984
- }
4985
- };
4986
- React__namespace.useLayoutEffect(()=>{
4987
- setTextValue('');
4988
- }, [
4989
- field.value
4990
- ]);
4991
- return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
4992
- error: field.error,
4993
- hint: hint,
4994
- name: name,
4995
- required: required,
4996
- children: [
4997
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
4998
- action: labelAction,
4999
- children: label
5000
- }),
5001
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Combobox, {
5002
- ref: fieldRef,
5003
- name: name,
5004
- autocomplete: "list",
5005
- placeholder: placeholder || formatMessage({
5006
- id: index.getTranslation('relation.add'),
5007
- defaultMessage: 'Add relation'
5008
- }),
5009
- hasMoreItems: hasNextPage,
5010
- loading: isLoading,
5011
- onOpenChange: ()=>{
5012
- handleSearch(textValue ?? '');
5013
- },
5014
- noOptionsMessage: ()=>formatMessage({
5015
- id: index.getTranslation('relation.notAvailable'),
5016
- defaultMessage: 'No relations available'
5017
- }),
5018
- loadingMessage: formatMessage({
5019
- id: index.getTranslation('relation.isLoading'),
5020
- defaultMessage: 'Relations are loading'
5021
- }),
5022
- onLoadMore: handleLoadMore,
5023
- textValue: textValue,
5024
- onChange: handleChange,
5025
- onTextValueChange: (text)=>{
5026
- setTextValue(text);
5027
- },
5028
- onInputChange: (event)=>{
5029
- handleSearch(event.currentTarget.value);
5030
- },
5031
- ...props,
5032
- children: options.map((opt)=>{
5033
- const textValue = usePrev.getRelationLabel(opt, mainField);
5034
- return /*#__PURE__*/ jsxRuntime.jsx(designSystem.ComboboxOption, {
5035
- value: opt.id.toString(),
5036
- textValue: textValue,
5037
- children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
5038
- gap: 2,
5039
- justifyContent: "space-between",
5040
- children: [
5041
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
5042
- ellipsis: true,
5043
- children: textValue
5044
- }),
5045
- opt.status ? /*#__PURE__*/ jsxRuntime.jsx(index.DocumentStatus, {
5046
- status: opt.status
5047
- }) : null
5048
- ]
5049
- })
5050
- }, opt.id);
5051
- })
5052
- }),
5053
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {}),
5054
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {})
5055
- ]
5056
- });
5057
- };
5058
- /* -------------------------------------------------------------------------------------------------
5059
- * RelationsList
5060
- * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5061
- const RELATION_GUTTER = 4;
5062
- const UnstableRelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel, setCurrentDocument })=>{
5063
- const ariaDescriptionId = React__namespace.useId();
5064
- const { formatMessage } = reactIntl.useIntl();
5065
- const listRef = React__namespace.useRef(null);
5066
- const outerListRef = React__namespace.useRef(null);
5067
- const [overflow, setOverflow] = React__namespace.useState();
5068
- const [liveText, setLiveText] = React__namespace.useState('');
5069
- const field = strapiAdmin.useField(name);
5070
- React__namespace.useEffect(()=>{
5071
- if (data.length <= RELATIONS_TO_DISPLAY) {
5072
- return setOverflow(undefined);
5073
- }
5074
- const handleNativeScroll = (e)=>{
5075
- const el = e.target;
5076
- const parentScrollContainerHeight = el.parentNode.scrollHeight;
5077
- const maxScrollBottom = el.scrollHeight - el.scrollTop;
5078
- if (el.scrollTop === 0) {
5079
- return setOverflow('bottom');
5080
- }
5081
- if (maxScrollBottom === parentScrollContainerHeight) {
5082
- return setOverflow('top');
5083
- }
5084
- return setOverflow('top-bottom');
5085
- };
5086
- const outerListRefCurrent = outerListRef?.current;
5087
- if (!isLoading && data.length > 0 && outerListRefCurrent) {
5088
- outerListRef.current.addEventListener('scroll', handleNativeScroll);
5089
- }
5090
- return ()=>{
5091
- if (outerListRefCurrent) {
5092
- outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
5093
- }
5094
- };
5095
- }, [
5096
- isLoading,
5097
- data.length
5098
- ]);
5099
- const getItemPos = (index)=>`${index + 1} of ${data.length}`;
5100
- const handleMoveItem = (newIndex, oldIndex)=>{
5101
- const item = data[oldIndex];
5102
- setLiveText(formatMessage({
5103
- id: index.getTranslation('dnd.reorder'),
5104
- defaultMessage: '{item}, moved. New position in list: {position}.'
5105
- }, {
5106
- item: item.label ?? item.documentId,
5107
- position: getItemPos(newIndex)
5108
- }));
5109
- /**
5110
- * Splicing mutates the array, so we need to create a new array
5111
- */ const newData = [
5112
- ...data
5113
- ];
5114
- const currentRow = data[oldIndex];
5115
- const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
5116
- const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
5117
- /**
5118
- * We're moving the relation between two other relations, so
5119
- * we need to generate a new key that keeps the order
5120
- */ const [newKey] = fractionalIndexing.generateNKeysBetween(startKey, endKey, 1);
5121
- newData.splice(oldIndex, 1);
5122
- newData.splice(newIndex, 0, {
5123
- ...currentRow,
5124
- __temp_key__: newKey
5125
- });
5126
- /**
5127
- * Now we diff against the server to understand what's different so we
5128
- * can keep the connect array nice and tidy. It also needs reversing because
5129
- * we reverse the relations from the server in the first place.
5130
- */ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
5131
- const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
5132
- const relationInFront = array[currentIndex + 1];
5133
- if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
5134
- const position = relationInFront ? {
5135
- before: relationInFront.documentId,
5136
- locale: relationInFront.locale,
5137
- status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
5138
- } : {
5139
- end: true
5140
- };
5141
- const relationWithPosition = {
5142
- ...relation,
5143
- ...{
5144
- apiData: {
5145
- id: relation.id,
5146
- documentId: relation.documentId,
5147
- locale: relation.locale,
5148
- position
5149
- }
5150
- }
5151
- };
5152
- return [
5153
- ...acc,
5154
- relationWithPosition
5155
- ];
5156
- }
5157
- return acc;
5158
- }, []).toReversed();
5159
- field.onChange(`${name}.connect`, connectedRelations);
5160
- };
5161
- const handleGrabItem = (index$1)=>{
5162
- const item = data[index$1];
5163
- setLiveText(formatMessage({
5164
- id: index.getTranslation('dnd.grab-item'),
5165
- defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5166
- }, {
5167
- item: item.label ?? item.documentId,
5168
- position: getItemPos(index$1)
5169
- }));
5170
- };
5171
- const handleDropItem = (index$1)=>{
5172
- const { href: _href, label, ...item } = data[index$1];
5173
- setLiveText(formatMessage({
5174
- id: index.getTranslation('dnd.drop-item'),
5175
- defaultMessage: `{item}, dropped. Final position in list: {position}.`
5176
- }, {
5177
- item: label ?? item.documentId,
5178
- position: getItemPos(index$1)
5179
- }));
5063
+ /**
5064
+ * You need to give this relation a correct _temp_key_ but
5065
+ * this component doesn't know about those ones, you can't rely
5066
+ * on the connect array because that doesn't hold items that haven't
5067
+ * moved. So use a callback to fill in the gaps when connecting.
5068
+ *
5069
+ */ onChange(relation);
5180
5070
  };
5181
- const handleCancel = (index$1)=>{
5182
- const item = data[index$1];
5183
- setLiveText(formatMessage({
5184
- id: index.getTranslation('dnd.cancel-item'),
5185
- defaultMessage: '{item}, dropped. Re-order cancelled.'
5186
- }, {
5187
- item: item.label ?? item.documentId
5188
- }));
5071
+ const handleLoadMore = ()=>{
5072
+ if (!data || !data.pagination) {
5073
+ return;
5074
+ } else if (data.pagination.page < data.pagination.pageCount) {
5075
+ setSearchParams((s)=>({
5076
+ ...s,
5077
+ page: s.page + 1
5078
+ }));
5079
+ }
5189
5080
  };
5190
- const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
5191
- /**
5192
- * These relation types will only ever have one item
5193
- * in their list, so you can't reorder a single item!
5194
- */ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
5195
- 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);
5196
- return /*#__PURE__*/ jsxRuntime.jsxs(ShadowBox, {
5197
- $overflowDirection: overflow,
5081
+ React__namespace.useLayoutEffect(()=>{
5082
+ setTextValue('');
5083
+ }, [
5084
+ field.value
5085
+ ]);
5086
+ return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
5087
+ error: field.error,
5088
+ hint: hint,
5089
+ name: name,
5090
+ required: required,
5198
5091
  children: [
5199
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
5200
- id: ariaDescriptionId,
5201
- children: formatMessage({
5202
- id: index.getTranslation('dnd.instructions'),
5203
- defaultMessage: `Press spacebar to grab and re-order`
5204
- })
5205
- }),
5206
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
5207
- "aria-live": "assertive",
5208
- children: liveText
5092
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
5093
+ action: labelAction,
5094
+ children: label
5209
5095
  }),
5210
- /*#__PURE__*/ jsxRuntime.jsx(reactWindow.FixedSizeList, {
5211
- height: dynamicListHeight,
5212
- ref: listRef,
5213
- outerRef: outerListRef,
5214
- itemCount: data.length,
5215
- itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
5216
- itemData: {
5217
- ariaDescribedBy: ariaDescriptionId,
5218
- canDrag: canReorder,
5219
- disabled,
5220
- handleCancel,
5221
- handleDropItem,
5222
- handleGrabItem,
5223
- handleMoveItem,
5224
- name,
5225
- handleDisconnect,
5226
- relations: data,
5227
- targetModel,
5228
- setCurrentDocument
5096
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Combobox, {
5097
+ ref: fieldRef,
5098
+ name: name,
5099
+ autocomplete: "list",
5100
+ placeholder: placeholder || formatMessage({
5101
+ id: index.getTranslation('relation.add'),
5102
+ defaultMessage: 'Add relation'
5103
+ }),
5104
+ hasMoreItems: hasNextPage,
5105
+ loading: isLoading,
5106
+ onOpenChange: ()=>{
5107
+ handleSearch(textValue ?? '');
5229
5108
  },
5230
- itemKey: (index)=>data[index].id,
5231
- innerElementType: "ol",
5232
- children: UnstableListItem
5233
- })
5109
+ noOptionsMessage: ()=>formatMessage({
5110
+ id: index.getTranslation('relation.notAvailable'),
5111
+ defaultMessage: 'No relations available'
5112
+ }),
5113
+ loadingMessage: formatMessage({
5114
+ id: index.getTranslation('relation.isLoading'),
5115
+ defaultMessage: 'Relations are loading'
5116
+ }),
5117
+ onLoadMore: handleLoadMore,
5118
+ textValue: textValue,
5119
+ onChange: handleChange,
5120
+ onTextValueChange: (text)=>{
5121
+ setTextValue(text);
5122
+ },
5123
+ onInputChange: (event)=>{
5124
+ handleSearch(event.currentTarget.value);
5125
+ },
5126
+ ...props,
5127
+ children: options.map((opt)=>{
5128
+ const textValue = usePrev.getRelationLabel(opt, mainField);
5129
+ return /*#__PURE__*/ jsxRuntime.jsx(designSystem.ComboboxOption, {
5130
+ value: opt.id.toString(),
5131
+ textValue: textValue,
5132
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
5133
+ gap: 2,
5134
+ justifyContent: "space-between",
5135
+ children: [
5136
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
5137
+ ellipsis: true,
5138
+ children: textValue
5139
+ }),
5140
+ opt.status ? /*#__PURE__*/ jsxRuntime.jsx(index.DocumentStatus, {
5141
+ status: opt.status
5142
+ }) : null
5143
+ ]
5144
+ })
5145
+ }, opt.id);
5146
+ })
5147
+ }),
5148
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {}),
5149
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {})
5234
5150
  ]
5235
5151
  });
5236
5152
  };
5237
- const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType })=>{
5153
+ /* -------------------------------------------------------------------------------------------------
5154
+ * RelationsList
5155
+ * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5156
+ const RELATION_GUTTER = 4;
5157
+ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
5238
5158
  const ariaDescriptionId = React__namespace.useId();
5239
5159
  const { formatMessage } = reactIntl.useIntl();
5240
5160
  const listRef = React__namespace.useRef(null);
@@ -5398,7 +5318,8 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
5398
5318
  handleMoveItem,
5399
5319
  name,
5400
5320
  handleDisconnect,
5401
- relations: data
5321
+ relations: data,
5322
+ targetModel
5402
5323
  },
5403
5324
  itemKey: (index)=>data[index].id,
5404
5325
  innerElementType: "ol",
@@ -5438,144 +5359,10 @@ const ShadowBox = styledComponents.styled(designSystem.Box)`
5438
5359
  transition: opacity 0.2s ease-in-out;
5439
5360
  }
5440
5361
  `;
5441
- const CustomTextButton = styledComponents.styled(designSystem.TextButton)`
5442
- & > span {
5443
- font-size: ${({ theme })=>theme.fontSizes[2]};
5444
- }
5445
- `;
5446
- const UnstableListItem = ({ data, index: index$1, style })=>{
5447
- const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel, setCurrentDocument } = data;
5448
- const { formatMessage } = reactIntl.useIntl();
5449
- const [isModalOpen, setIsModalOpen] = React__namespace.useState(false);
5450
- const { id, label, status, documentId, href, apiData } = relations[index$1];
5451
- const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = objects.useDragAndDrop(canDrag && !disabled, {
5452
- type: `${objects.ItemTypes.RELATION}_${name}`,
5453
- index: index$1,
5454
- item: {
5455
- displayedValue: label,
5456
- status,
5457
- id: id,
5458
- index: index$1
5459
- },
5460
- onMoveItem: handleMoveItem,
5461
- onDropItem: handleDropItem,
5462
- onGrabItem: handleGrabItem,
5463
- onCancel: handleCancel,
5464
- dropSensitivity: objects.DROP_SENSITIVITY.REGULAR
5465
- });
5466
- const composedRefs = designSystem.useComposedRefs(relationRef, dragRef);
5467
- const handleChangeModalContent = ()=>{
5468
- if (setCurrentDocument) {
5469
- const newRelation = {
5470
- documentId: documentId ? documentId : apiData?.documentId || '',
5471
- model: targetModel,
5472
- collectionType: getCollectionType(href)
5473
- };
5474
- setCurrentDocument(newRelation);
5475
- }
5476
- };
5477
- React__namespace.useEffect(()=>{
5478
- dragPreviewRef(reactDndHtml5Backend.getEmptyImage());
5479
- }, [
5480
- dragPreviewRef
5481
- ]);
5482
- return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
5483
- style: style,
5484
- tag: "li",
5485
- ref: dropRef,
5486
- "aria-describedby": ariaDescribedBy,
5487
- cursor: canDrag ? 'all-scroll' : 'default',
5488
- children: isDragging ? /*#__PURE__*/ jsxRuntime.jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
5489
- paddingTop: 2,
5490
- paddingBottom: 2,
5491
- paddingLeft: canDrag ? 2 : 4,
5492
- paddingRight: 4,
5493
- hasRadius: true,
5494
- borderColor: "neutral200",
5495
- background: disabled ? 'neutral150' : 'neutral0',
5496
- justifyContent: "space-between",
5497
- ref: composedRefs,
5498
- "data-handler-id": handlerId,
5499
- children: [
5500
- /*#__PURE__*/ jsxRuntime.jsxs(FlexWrapper, {
5501
- gap: 1,
5502
- children: [
5503
- canDrag ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
5504
- tag: "div",
5505
- role: "button",
5506
- tabIndex: 0,
5507
- withTooltip: false,
5508
- label: formatMessage({
5509
- id: index.getTranslation('components.RelationInput.icon-button-aria-label'),
5510
- defaultMessage: 'Drag'
5511
- }),
5512
- variant: "ghost",
5513
- onKeyDown: handleKeyDown,
5514
- disabled: disabled,
5515
- children: /*#__PURE__*/ jsxRuntime.jsx(Icons.Drag, {})
5516
- }) : null,
5517
- /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
5518
- width: "100%",
5519
- minWidth: 0,
5520
- justifyContent: "space-between",
5521
- children: [
5522
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
5523
- minWidth: 0,
5524
- paddingTop: 1,
5525
- paddingBottom: 1,
5526
- paddingRight: 4,
5527
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
5528
- description: label,
5529
- children: isModalOpen ? /*#__PURE__*/ jsxRuntime.jsx(CustomTextButton, {
5530
- onClick: handleChangeModalContent,
5531
- children: label
5532
- }) : /*#__PURE__*/ jsxRuntime.jsx(CustomTextButton, {
5533
- onClick: ()=>{
5534
- setIsModalOpen(true);
5535
- handleChangeModalContent();
5536
- },
5537
- children: label
5538
- })
5539
- })
5540
- }),
5541
- status ? /*#__PURE__*/ jsxRuntime.jsx(index.DocumentStatus, {
5542
- status: status
5543
- }) : null,
5544
- isModalOpen && /*#__PURE__*/ jsxRuntime.jsx(RelationModal, {
5545
- open: isModalOpen,
5546
- onToggle: ()=>{
5547
- setIsModalOpen(!isModalOpen);
5548
- },
5549
- model: targetModel,
5550
- id: documentId ? documentId : apiData?.documentId,
5551
- relationUrl: href
5552
- })
5553
- ]
5554
- })
5555
- ]
5556
- }),
5557
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
5558
- paddingLeft: 4,
5559
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
5560
- onClick: ()=>handleDisconnect(relations[index$1]),
5561
- disabled: disabled,
5562
- label: formatMessage({
5563
- id: index.getTranslation('relation.disconnect'),
5564
- defaultMessage: 'Remove'
5565
- }),
5566
- variant: "ghost",
5567
- size: "S",
5568
- children: /*#__PURE__*/ jsxRuntime.jsx(Icons.Cross, {})
5569
- })
5570
- })
5571
- ]
5572
- })
5573
- });
5574
- };
5575
5362
  const ListItem = ({ data, index: index$1, style })=>{
5576
- const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations } = data;
5363
+ const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
5577
5364
  const { formatMessage } = reactIntl.useIntl();
5578
- const { href, id, label, status } = relations[index$1];
5365
+ const { href, id, label, status, documentId, apiData, locale } = relations[index$1];
5579
5366
  const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = objects.useDragAndDrop(canDrag && !disabled, {
5580
5367
  type: `${objects.ItemTypes.RELATION}_${name}`,
5581
5368
  index: index$1,
@@ -5642,18 +5429,16 @@ const ListItem = ({ data, index: index$1, style })=>{
5642
5429
  paddingTop: 1,
5643
5430
  paddingBottom: 1,
5644
5431
  paddingRight: 4,
5645
- children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
5646
- description: label,
5647
- children: href ? /*#__PURE__*/ jsxRuntime.jsx(LinkEllipsis, {
5648
- tag: reactRouterDom.NavLink,
5649
- to: href,
5650
- isExternal: false,
5651
- children: label
5652
- }) : /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
5653
- textColor: disabled ? 'neutral600' : 'primary600',
5654
- ellipsis: true,
5655
- children: label
5656
- })
5432
+ children: /*#__PURE__*/ jsxRuntime.jsx(RelationModalForm, {
5433
+ triggerButtonLabel: label,
5434
+ relation: {
5435
+ documentId: documentId ?? apiData?.documentId,
5436
+ model: targetModel,
5437
+ collectionType: getCollectionType(href),
5438
+ params: {
5439
+ locale: locale || apiData?.locale || null
5440
+ }
5441
+ }
5657
5442
  })
5658
5443
  }),
5659
5444
  status ? /*#__PURE__*/ jsxRuntime.jsx(index.DocumentStatus, {
@@ -5723,7 +5508,6 @@ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Bo
5723
5508
  height: `calc(100% - ${RELATION_GUTTER}px)`
5724
5509
  });
5725
5510
  const MemoizedRelationsField = /*#__PURE__*/ React__namespace.memo(RelationsField);
5726
- const MemoizedUnstableRelationsField = /*#__PURE__*/ React__namespace.memo(UnstableRelationsField);
5727
5511
 
5728
5512
  const uidApi = index.contentManagerApi.injectEndpoints({
5729
5513
  endpoints: (builder)=>({
@@ -7893,22 +7677,27 @@ const Wysiwyg = /*#__PURE__*/ React__namespace.forwardRef(({ hint, disabled, lab
7893
7677
  });
7894
7678
  const MemoizedWysiwyg = /*#__PURE__*/ React__namespace.memo(Wysiwyg);
7895
7679
 
7896
- const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7897
- const { id: rootId } = index.useDoc();
7898
- const documentMeta = useDocumentContext('InputRenderer', (state)=>state.meta);
7899
- const documentResponse = useDocumentContext('InputRenderer', (state)=>state.document);
7900
- const documentLayout = index.useDocumentLayout(documentMeta.model);
7901
- const document = documentResponse?.document;
7902
- const collectionType = documentMeta.collectionType;
7680
+ /**
7681
+ * @internal
7682
+ *
7683
+ * @description An abstraction around the regular form input renderer designed
7684
+ * specifically to be used in the EditView of the content-manager this understands
7685
+ * the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
7686
+ * components such as Blocks / Relations.
7687
+ */ const InputRenderer = ({ visible, hint: providedHint, document, ...props })=>{
7688
+ const { model: rootModel } = index.useDoc();
7689
+ const documentLayout = index.useDocumentLayout(document.schema?.uid ?? rootModel);
7690
+ const components = documentLayout.edit.components;
7691
+ const collectionType = document.schema?.kind === 'collectionType' ? 'collection-types' : 'single-types';
7903
7692
  const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
7904
7693
  const isFormDisabled = strapiAdmin.useForm('InputRenderer', (state)=>state.disabled);
7905
7694
  const canCreateFields = index.useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
7906
7695
  const canReadFields = index.useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
7907
7696
  const canUpdateFields = index.useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
7908
7697
  const canUserAction = index.useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
7909
- let idToCheck = rootId;
7698
+ let idToCheck = document.document?.documentId;
7910
7699
  if (collectionType === index.SINGLE_TYPES) {
7911
- idToCheck = document?.documentId;
7700
+ idToCheck = document?.document?.documentId;
7912
7701
  }
7913
7702
  const editableFields = idToCheck ? canUpdateFields : canCreateFields;
7914
7703
  const readableFields = idToCheck ? canReadFields : canCreateFields;
@@ -7922,8 +7711,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7922
7711
  props.attribute.customField
7923
7712
  ] : undefined);
7924
7713
  const hint = useFieldHint(providedHint, props.attribute);
7925
- const { edit: { components: rootDocumentComponents } } = index.useDocLayout();
7926
- const components = Object.keys(rootDocumentComponents).length !== 0 ? rootDocumentComponents : documentLayout.edit.components;
7927
7714
  // We pass field in case of Custom Fields to keep backward compatibility
7928
7715
  const field = strapiAdmin.useField(props.name);
7929
7716
  if (!visible) {
@@ -8000,13 +7787,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
8000
7787
  disabled: fieldIsDisabled
8001
7788
  });
8002
7789
  case 'relation':
8003
- if (window.strapi.future.isEnabled('unstableRelationsOnTheFly')) {
8004
- return /*#__PURE__*/ jsxRuntime.jsx(MemoizedUnstableRelationsField, {
8005
- ...props,
8006
- hint: hint,
8007
- disabled: fieldIsDisabled
8008
- });
8009
- }
8010
7790
  return /*#__PURE__*/ jsxRuntime.jsx(MemoizedRelationsField, {
8011
7791
  ...props,
8012
7792
  hint: hint,
@@ -8112,10 +7892,12 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
8112
7892
  const ResponsiveGridRoot = styledComponents.styled(designSystem.Grid.Root)`
8113
7893
  container-type: inline-size;
8114
7894
  `;
8115
- // We need to use a different grid item for the responsive layout in the test environment
8116
- // because @container is not supported in jsdom and it throws an error
8117
- 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
8118
- process.env.NODE_ENV !== 'test' ? styledComponents.styled(designSystem.Grid.Item)`
7895
+ const ResponsiveGridItem = /**
7896
+ * TODO:
7897
+ * JSDOM cannot handle container queries.
7898
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
7899
+ * for failing to parse the stylesheet.
7900
+ */ process.env.NODE_ENV !== 'test' ? styledComponents.styled(designSystem.Grid.Item)`
8119
7901
  grid-column: span 12;
8120
7902
  @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
8121
7903
  ${({ col })=>col && `grid-column: span ${col};`}
@@ -8123,10 +7905,9 @@ process.env.NODE_ENV !== 'test' ? styledComponents.styled(designSystem.Grid.Item
8123
7905
  ` : styledComponents.styled(designSystem.Grid.Item)`
8124
7906
  grid-column: span 12;
8125
7907
  `;
8126
- const FormLayout = ({ layout, hasBackground = true })=>{
7908
+ const FormLayout = ({ layout, document, hasBackground = true })=>{
8127
7909
  const { formatMessage } = reactIntl.useIntl();
8128
- const documentMeta = useDocumentContext('FormLayout', (state)=>state.meta);
8129
- const model = documentMeta.model;
7910
+ const model = document.schema?.modelName;
8130
7911
  return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
8131
7912
  direction: "column",
8132
7913
  alignItems: "stretch",
@@ -8151,7 +7932,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
8151
7932
  direction: "column",
8152
7933
  alignItems: "stretch",
8153
7934
  children: /*#__PURE__*/ jsxRuntime.jsx(MemoizedInputRenderer, {
8154
- ...fieldWithTranslatedLabel
7935
+ ...fieldWithTranslatedLabel,
7936
+ document: document
8155
7937
  })
8156
7938
  })
8157
7939
  }, field.name);
@@ -8185,7 +7967,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
8185
7967
  direction: "column",
8186
7968
  alignItems: "stretch",
8187
7969
  children: /*#__PURE__*/ jsxRuntime.jsx(MemoizedInputRenderer, {
8188
- ...fieldWithTranslatedLabel
7970
+ ...fieldWithTranslatedLabel,
7971
+ document: document
8189
7972
  })
8190
7973
  }, field.name);
8191
7974
  })
@@ -8201,6 +7984,7 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
8201
7984
  const { value } = strapiAdmin.useField(name);
8202
7985
  const level = useComponent('NonRepeatableComponent', (state)=>state.level);
8203
7986
  const isNested = level > 0;
7987
+ const currentDocument = index.useDocumentContext('NonRepeatableComponent', (state)=>state.document);
8204
7988
  return /*#__PURE__*/ jsxRuntime.jsx(ComponentProvider, {
8205
7989
  id: value?.id,
8206
7990
  uid: attribute.component,
@@ -8241,7 +8025,8 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
8241
8025
  children: children({
8242
8026
  ...field,
8243
8027
  label: translatedLabel,
8244
- name: completeFieldName
8028
+ name: completeFieldName,
8029
+ document: currentDocument
8245
8030
  })
8246
8031
  }, completeFieldName);
8247
8032
  })
@@ -8259,7 +8044,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
8259
8044
  const search = React__namespace.useMemo(()=>new URLSearchParams(searchString), [
8260
8045
  searchString
8261
8046
  ]);
8262
- const components = useDocumentContext('RepeatableComponent', (state)=>state.document.components);
8047
+ const currentDocument = index.useDocumentContext('RepeatableComponent', (state)=>state.document);
8048
+ const components = currentDocument.components;
8263
8049
  const { value = [], error, rawError } = strapiAdmin.useField(name);
8264
8050
  const addFieldRow = strapiAdmin.useForm('RepeatableComponent', (state)=>state.addFieldRow);
8265
8051
  const moveFieldRow = strapiAdmin.useForm('RepeatableComponent', (state)=>state.moveFieldRow);
@@ -8462,7 +8248,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
8462
8248
  children: children({
8463
8249
  ...field,
8464
8250
  label: translatedLabel,
8465
- name: completeFieldName
8251
+ name: completeFieldName,
8252
+ document: currentDocument
8466
8253
  })
8467
8254
  }, completeFieldName);
8468
8255
  })
@@ -8624,7 +8411,7 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
8624
8411
  const { formatMessage } = reactIntl.useIntl();
8625
8412
  const field = strapiAdmin.useField(name);
8626
8413
  const showResetComponent = !attribute.repeatable && field.value && !disabled;
8627
- const components = useDocumentContext('ComponentInput', (state)=>state.document.components);
8414
+ const components = index.useDocumentContext('ComponentInput', (state)=>state.document.components);
8628
8415
  const handleInitialisationClick = ()=>{
8629
8416
  const schema = components[attribute.component];
8630
8417
  const form = index.createDefaultForm(schema, components);
@@ -8690,7 +8477,6 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
8690
8477
  const MemoizedComponentInput = /*#__PURE__*/ React__namespace.memo(ComponentInput);
8691
8478
 
8692
8479
  exports.DisconnectButton = DisconnectButton;
8693
- exports.DocumentContextProvider = DocumentContextProvider;
8694
8480
  exports.DynamicZone = DynamicZone;
8695
8481
  exports.FlexWrapper = FlexWrapper;
8696
8482
  exports.FormLayout = FormLayout;
@@ -8703,4 +8489,4 @@ exports.NotAllowedInput = NotAllowedInput;
8703
8489
  exports.useDynamicZone = useDynamicZone;
8704
8490
  exports.useFieldHint = useFieldHint;
8705
8491
  exports.useLazyComponents = useLazyComponents;
8706
- //# sourceMappingURL=Input-DPH5j7Yl.js.map
8492
+ //# sourceMappingURL=Input-D-yPzkxz.js.map