@strapi/content-manager 0.0.0-experimental.e0df4d50334a17a1beb3d203bff414fbbff62f7b → 0.0.0-experimental.e12978dcee698470990e9c5c63384faf2c307443

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 (120) hide show
  1. package/dist/admin/chunks/{ComponentConfigurationPage-C5H-5L1u.js → ComponentConfigurationPage-Ci3dN40b.js} +5 -6
  2. package/dist/admin/chunks/{ComponentConfigurationPage-C5H-5L1u.js.map → ComponentConfigurationPage-Ci3dN40b.js.map} +1 -1
  3. package/dist/admin/chunks/{ComponentConfigurationPage-BN2kOtDm.mjs → ComponentConfigurationPage-DFPdl9pm.mjs} +5 -6
  4. package/dist/admin/chunks/{ComponentConfigurationPage-BN2kOtDm.mjs.map → ComponentConfigurationPage-DFPdl9pm.mjs.map} +1 -1
  5. package/dist/admin/chunks/{EditConfigurationPage-BExtZuB7.js → EditConfigurationPage-7xe8u-Pp.js} +5 -6
  6. package/dist/admin/chunks/{EditConfigurationPage-BExtZuB7.js.map → EditConfigurationPage-7xe8u-Pp.js.map} +1 -1
  7. package/dist/admin/chunks/{EditConfigurationPage-tMgOELQG.mjs → EditConfigurationPage-BFse-urJ.mjs} +5 -6
  8. package/dist/admin/chunks/{EditConfigurationPage-tMgOELQG.mjs.map → EditConfigurationPage-BFse-urJ.mjs.map} +1 -1
  9. package/dist/admin/chunks/{EditViewPage-CYe7wAXF.mjs → EditViewPage-BNpRr7fZ.mjs} +99 -98
  10. package/dist/admin/chunks/EditViewPage-BNpRr7fZ.mjs.map +1 -0
  11. package/dist/admin/chunks/{EditViewPage-DFkloeMZ.js → EditViewPage-CwYSs8Cq.js} +99 -98
  12. package/dist/admin/chunks/EditViewPage-CwYSs8Cq.js.map +1 -0
  13. package/dist/admin/chunks/{Form-DTO0ZIaB.mjs → Form-D9Ee-exF.mjs} +3 -3
  14. package/dist/admin/chunks/{Form-DTO0ZIaB.mjs.map → Form-D9Ee-exF.mjs.map} +1 -1
  15. package/dist/admin/chunks/{Form-DGUP3zQO.js → Form-DDbxreII.js} +5 -5
  16. package/dist/admin/chunks/{Form-DGUP3zQO.js.map → Form-DDbxreII.js.map} +1 -1
  17. package/dist/admin/chunks/{History-CQznK1pG.js → History-D5joC76n.js} +17 -13
  18. package/dist/admin/chunks/History-D5joC76n.js.map +1 -0
  19. package/dist/admin/chunks/{History-C333pgXF.mjs → History-FuD7Tp5I.mjs} +16 -12
  20. package/dist/admin/chunks/History-FuD7Tp5I.mjs.map +1 -0
  21. package/dist/admin/chunks/{Input-BexkC_pp.mjs → Input-BHucdqva.mjs} +1108 -47
  22. package/dist/admin/chunks/Input-BHucdqva.mjs.map +1 -0
  23. package/dist/admin/chunks/{Input-DLJZHw9Y.js → Input-BJCenRYN.js} +1121 -57
  24. package/dist/admin/chunks/Input-BJCenRYN.js.map +1 -0
  25. package/dist/admin/chunks/{ListConfigurationPage-BX2WR7MI.mjs → ListConfigurationPage-3kSfz9xV.mjs} +4 -5
  26. package/dist/admin/chunks/{ListConfigurationPage-BX2WR7MI.mjs.map → ListConfigurationPage-3kSfz9xV.mjs.map} +1 -1
  27. package/dist/admin/chunks/{ListConfigurationPage-71I_stAM.js → ListConfigurationPage-CgJEcEkD.js} +6 -7
  28. package/dist/admin/chunks/{ListConfigurationPage-71I_stAM.js.map → ListConfigurationPage-CgJEcEkD.js.map} +1 -1
  29. package/dist/admin/chunks/{ListViewPage-DV3heO4F.js → ListViewPage-CvQ1w8IW.js} +7 -8
  30. package/dist/admin/chunks/{ListViewPage-DV3heO4F.js.map → ListViewPage-CvQ1w8IW.js.map} +1 -1
  31. package/dist/admin/chunks/{ListViewPage-BDeT3Dkk.mjs → ListViewPage-DPUYRHss.mjs} +3 -4
  32. package/dist/admin/chunks/{ListViewPage-BDeT3Dkk.mjs.map → ListViewPage-DPUYRHss.mjs.map} +1 -1
  33. package/dist/admin/chunks/{NoContentTypePage-9JHYpYVX.mjs → NoContentTypePage-BRLLtjLb.mjs} +2 -2
  34. package/dist/admin/chunks/{NoContentTypePage-9JHYpYVX.mjs.map → NoContentTypePage-BRLLtjLb.mjs.map} +1 -1
  35. package/dist/admin/chunks/{NoContentTypePage-COih9y2J.js → NoContentTypePage-C5Vut1Af.js} +2 -2
  36. package/dist/admin/chunks/{NoContentTypePage-COih9y2J.js.map → NoContentTypePage-C5Vut1Af.js.map} +1 -1
  37. package/dist/admin/chunks/{NoPermissionsPage-DTe9I47q.mjs → NoPermissionsPage-B5HJbcjm.mjs} +2 -2
  38. package/dist/admin/chunks/{NoPermissionsPage-DTe9I47q.mjs.map → NoPermissionsPage-B5HJbcjm.mjs.map} +1 -1
  39. package/dist/admin/chunks/{NoPermissionsPage-DGAwRIlN.js → NoPermissionsPage-BBXnpc7M.js} +2 -2
  40. package/dist/admin/chunks/{NoPermissionsPage-DGAwRIlN.js.map → NoPermissionsPage-BBXnpc7M.js.map} +1 -1
  41. package/dist/admin/chunks/{Preview-BEq0FXda.mjs → Preview-C3lnOgQx.mjs} +244 -116
  42. package/dist/admin/chunks/Preview-C3lnOgQx.mjs.map +1 -0
  43. package/dist/admin/chunks/{Preview-CXtc9yEV.js → Preview-DB7ZGawL.js} +240 -112
  44. package/dist/admin/chunks/Preview-DB7ZGawL.js.map +1 -0
  45. package/dist/admin/chunks/{en-C1CjdAtC.js → en-CH__IC8g.js} +4 -1
  46. package/dist/admin/chunks/{en-C1CjdAtC.js.map → en-CH__IC8g.js.map} +1 -1
  47. package/dist/admin/chunks/{en-LfhocNG2.mjs → en-DBP0Gaid.mjs} +4 -1
  48. package/dist/admin/chunks/{en-LfhocNG2.mjs.map → en-DBP0Gaid.mjs.map} +1 -1
  49. package/dist/admin/chunks/{index-Cs6qwFQu.mjs → index-DYrCidCq.mjs} +225 -140
  50. package/dist/admin/chunks/index-DYrCidCq.mjs.map +1 -0
  51. package/dist/admin/chunks/{index-BHimg6jW.js → index-DoUQnFTk.js} +227 -138
  52. package/dist/admin/chunks/index-DoUQnFTk.js.map +1 -0
  53. package/dist/admin/chunks/{layout-Dtahn4Ue.js → layout-CqndYVtU.js} +86 -13
  54. package/dist/admin/chunks/layout-CqndYVtU.js.map +1 -0
  55. package/dist/admin/chunks/{layout-DStNia_P.mjs → layout-D2NJmgCw.mjs} +78 -5
  56. package/dist/admin/chunks/layout-D2NJmgCw.mjs.map +1 -0
  57. package/dist/admin/chunks/{useDragAndDrop-gcqEJMnO.js → objects-BJTP843m.js} +73 -1
  58. package/dist/admin/chunks/objects-BJTP843m.js.map +1 -0
  59. package/dist/admin/chunks/{useDragAndDrop-HYwNDExe.mjs → objects-D2z-IJgu.mjs} +72 -2
  60. package/dist/admin/chunks/objects-D2z-IJgu.mjs.map +1 -0
  61. package/dist/admin/chunks/uk-BtM6WnaE.mjs +313 -0
  62. package/dist/admin/chunks/uk-BtM6WnaE.mjs.map +1 -0
  63. package/dist/admin/chunks/uk-DB6OgySY.js +318 -0
  64. package/dist/admin/chunks/uk-DB6OgySY.js.map +1 -0
  65. package/dist/admin/chunks/{relations-XOYEEqMz.js → usePrev-Cm_0-qRC.js} +18 -2
  66. package/dist/admin/chunks/usePrev-Cm_0-qRC.js.map +1 -0
  67. package/dist/admin/chunks/{relations-Cq8NRUto.mjs → usePrev-DinC2aha.mjs} +18 -4
  68. package/dist/admin/chunks/usePrev-DinC2aha.mjs.map +1 -0
  69. package/dist/admin/index.js +1 -1
  70. package/dist/admin/index.mjs +1 -1
  71. package/dist/admin/src/components/InjectionZone.d.ts +7 -1
  72. package/dist/admin/src/content-manager.d.ts +4 -0
  73. package/dist/admin/src/features/DocumentContext.d.ts +48 -0
  74. package/dist/admin/src/features/DocumentRBAC.d.ts +3 -2
  75. package/dist/admin/src/hooks/useDocument.d.ts +2 -0
  76. package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -0
  77. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
  78. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +7 -0
  79. package/dist/admin/src/pages/EditView/components/FormInputs/{Relations.d.ts → Relations/Relations.d.ts} +9 -4
  80. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +5 -2
  81. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +3 -3
  82. package/dist/admin/src/preview/components/PreviewContent.d.ts +1 -2
  83. package/dist/admin/src/preview/pages/Preview.d.ts +2 -0
  84. package/dist/server/index.js +1 -1
  85. package/dist/server/index.js.map +1 -1
  86. package/dist/server/index.mjs +1 -1
  87. package/dist/server/index.mjs.map +1 -1
  88. package/package.json +8 -8
  89. package/dist/admin/chunks/EditViewPage-CYe7wAXF.mjs.map +0 -1
  90. package/dist/admin/chunks/EditViewPage-DFkloeMZ.js.map +0 -1
  91. package/dist/admin/chunks/History-C333pgXF.mjs.map +0 -1
  92. package/dist/admin/chunks/History-CQznK1pG.js.map +0 -1
  93. package/dist/admin/chunks/Input-BexkC_pp.mjs.map +0 -1
  94. package/dist/admin/chunks/Input-DLJZHw9Y.js.map +0 -1
  95. package/dist/admin/chunks/Preview-BEq0FXda.mjs.map +0 -1
  96. package/dist/admin/chunks/Preview-CXtc9yEV.js.map +0 -1
  97. package/dist/admin/chunks/Relations-o7_hVGyK.js +0 -1318
  98. package/dist/admin/chunks/Relations-o7_hVGyK.js.map +0 -1
  99. package/dist/admin/chunks/Relations-qeZyLDgQ.mjs +0 -1291
  100. package/dist/admin/chunks/Relations-qeZyLDgQ.mjs.map +0 -1
  101. package/dist/admin/chunks/index-BHimg6jW.js.map +0 -1
  102. package/dist/admin/chunks/index-Cs6qwFQu.mjs.map +0 -1
  103. package/dist/admin/chunks/layout-DStNia_P.mjs.map +0 -1
  104. package/dist/admin/chunks/layout-Dtahn4Ue.js.map +0 -1
  105. package/dist/admin/chunks/objects-C3EebVVe.js +0 -76
  106. package/dist/admin/chunks/objects-C3EebVVe.js.map +0 -1
  107. package/dist/admin/chunks/objects-wl73iEma.mjs +0 -73
  108. package/dist/admin/chunks/objects-wl73iEma.mjs.map +0 -1
  109. package/dist/admin/chunks/relations-Cq8NRUto.mjs.map +0 -1
  110. package/dist/admin/chunks/relations-XOYEEqMz.js.map +0 -1
  111. package/dist/admin/chunks/uk-B24MoTVg.js +0 -145
  112. package/dist/admin/chunks/uk-B24MoTVg.js.map +0 -1
  113. package/dist/admin/chunks/uk-Cpgmm7gE.mjs +0 -140
  114. package/dist/admin/chunks/uk-Cpgmm7gE.mjs.map +0 -1
  115. package/dist/admin/chunks/useDragAndDrop-HYwNDExe.mjs.map +0 -1
  116. package/dist/admin/chunks/useDragAndDrop-gcqEJMnO.js.map +0 -1
  117. package/dist/admin/chunks/usePrev-Bjw2dhmq.mjs +0 -18
  118. package/dist/admin/chunks/usePrev-Bjw2dhmq.mjs.map +0 -1
  119. package/dist/admin/chunks/usePrev-DIYl-IAL.js +0 -21
  120. package/dist/admin/chunks/usePrev-DIYl-IAL.js.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { useState, useEffect, useCallback, memo } from 'react';
4
- import { useStrapiApp, useElementOnScreen, createContext, useField, useForm, useNotification, useAPIErrorHandler, useQueryParams, useFocusInputField, 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, IconButtonGroup, TextButton } 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, CheckCircle, WarningCircle, Loader, ArrowClockwise, Plus } from '@strapi/icons';
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { useStrapiApp, useElementOnScreen, createContext, useField, useForm, useNotification, useRBAC, Form, 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, 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';
7
7
  import { useIntl } from 'react-intl';
8
- import { g as getTranslation, m as useDocLayout, c as useDoc, n as createDefaultForm, t as transformDocument, e as contentManagerApi, o as CLONE_PATH, d as buildValidParams, f as useDocumentRBAC, S as SINGLE_TYPES } from './index-Cs6qwFQu.mjs';
8
+ import { g as getTranslation, c as useDocumentContext, d as useDocumentLayout, e as createDefaultForm, t as transformDocument, P as PERMISSIONS, f as DocumentRBAC, h as createYupSchema, i as DocumentActionButton, D as DocumentStatus, C as COLLECTION_TYPES, S as SINGLE_TYPES, j as buildValidParams, k as useLazyGetDocumentQuery, l as contentManagerApi, m as useDoc, n as CLONE_PATH, o as useDocumentRBAC, p as useDocLayout } from './index-DYrCidCq.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,16 +61,15 @@ 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 usePrev } from './usePrev-Bjw2dhmq.mjs';
65
- import { a as DIRECTIONS, u as useDragAndDrop, I as ItemTypes } from './useDragAndDrop-HYwNDExe.mjs';
64
+ import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-DinC2aha.mjs';
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
68
  import { useMatch, useLocation } from 'react-router-dom';
69
- import { g as getIn } from './objects-wl73iEma.mjs';
70
- import { u as useComponent, C as ComponentProvider, M as MemoizedUnstableRelationsField, a as MemoizedRelationsField } from './Relations-qeZyLDgQ.mjs';
71
69
  import pipe$1 from 'lodash/fp/pipe';
72
70
  import { C as ComponentIcon, a as COMPONENT_ICONS } from './ComponentIcon-BZcTc4rj.mjs';
73
- import { a as useDebounce } from './relations-Cq8NRUto.mjs';
71
+ import { generateNKeysBetween } from 'fractional-indexing';
72
+ import { FixedSizeList } from 'react-window';
74
73
  import CodeMirror from 'codemirror5';
75
74
  import sanitizeHtml from 'sanitize-html';
76
75
  import { getLanguage, highlight, highlightAuto } from 'highlight.js';
@@ -3463,6 +3462,20 @@ const Initializer = ({ disabled, name, onClick })=>{
3463
3462
  });
3464
3463
  };
3465
3464
 
3465
+ /**
3466
+ * We use this component to wrap any individual component field in the Edit View,
3467
+ * this could be a component field in a dynamic zone, a component within a repeatable space,
3468
+ * or even nested components.
3469
+ *
3470
+ * We primarily need this to provide the component id to the components so that they can
3471
+ * correctly fetch their relations.
3472
+ */ const [ComponentProvider, useComponent] = createContext('ComponentContext', {
3473
+ id: undefined,
3474
+ level: -1,
3475
+ uid: undefined,
3476
+ type: undefined
3477
+ });
3478
+
3466
3479
  const AddComponentButton = ({ hasError, isDisabled, isOpen, children, onClick })=>{
3467
3480
  return /*#__PURE__*/ jsx(StyledButton, {
3468
3481
  type: "button",
@@ -3641,7 +3654,8 @@ const ComponentPicker = ({ dynamicComponentsByCategory = {}, isOpen, onClickAddC
3641
3654
  const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveComponentClick, onMoveComponent, onGrabItem, onDropItem, onCancel, dynamicComponentsByCategory = {}, onAddComponent, children })=>{
3642
3655
  const { formatMessage } = useIntl();
3643
3656
  const formValues = useForm('DynamicComponent', (state)=>state.values);
3644
- const { edit: { components } } = useDocLayout();
3657
+ const documentMeta = useDocumentContext('DynamicComponent', (state)=>state.meta);
3658
+ const { edit: { components } } = useDocumentLayout(documentMeta.model);
3645
3659
  const title = React.useMemo(()=>{
3646
3660
  const { mainField } = components[componentUid]?.settings ?? {
3647
3661
  mainField: 'id'
@@ -3993,7 +4007,8 @@ const DynamicZone = ({ attribute, disabled: disabledProp, hint, label, labelActi
3993
4007
  const { max = Infinity, min = -Infinity } = attribute ?? {};
3994
4008
  const [addComponentIsOpen, setAddComponentIsOpen] = React.useState(false);
3995
4009
  const [liveText, setLiveText] = React.useState('');
3996
- const { components, isLoading } = useDoc();
4010
+ const document = useDocumentContext('DynamicZone', (state)=>state.document);
4011
+ const { components, isLoading } = document;
3997
4012
  const disabled = disabledProp || isLoading;
3998
4013
  const { addFieldRow, removeFieldRow, moveFieldRow } = useForm('DynamicZone', ({ addFieldRow, removeFieldRow, moveFieldRow })=>({
3999
4014
  addFieldRow,
@@ -4226,6 +4241,1055 @@ const NotAllowedInput = ({ hint, label, required, name })=>{
4226
4241
  });
4227
4242
  };
4228
4243
 
4244
+ function getCollectionType(url) {
4245
+ const regex = new RegExp(`(${COLLECTION_TYPES}|${SINGLE_TYPES})`);
4246
+ const match = url.match(regex);
4247
+ return match ? match[1] : undefined;
4248
+ }
4249
+ const CustomModalContent = styled(Modal.Content)`
4250
+ width: 90%;
4251
+ max-width: 100%;
4252
+ height: 90%;
4253
+ max-height: 100%;
4254
+ `;
4255
+ const RelationModal = ({ open, onToggle })=>{
4256
+ const { formatMessage } = useIntl();
4257
+ return /*#__PURE__*/ jsx(Modal.Root, {
4258
+ open: open,
4259
+ onOpenChange: onToggle,
4260
+ children: /*#__PURE__*/ jsxs(CustomModalContent, {
4261
+ children: [
4262
+ /*#__PURE__*/ jsx(Modal.Header, {
4263
+ gap: 2,
4264
+ children: /*#__PURE__*/ jsx(Flex, {
4265
+ justifyContent: "space-between",
4266
+ alignItems: "center",
4267
+ width: "100%",
4268
+ children: /*#__PURE__*/ jsxs(Flex, {
4269
+ gap: 2,
4270
+ children: [
4271
+ /*#__PURE__*/ jsx(IconButton, {
4272
+ withTooltip: false,
4273
+ label: "Back",
4274
+ variant: "ghost",
4275
+ disabled: true,
4276
+ onClick: ()=>{},
4277
+ marginRight: 1,
4278
+ children: /*#__PURE__*/ jsx(ArrowLeft, {})
4279
+ }),
4280
+ /*#__PURE__*/ jsx(Typography, {
4281
+ tag: "span",
4282
+ fontWeight: 600,
4283
+ children: formatMessage({
4284
+ id: 'content-manager.components.RelationInputModal.modal-title',
4285
+ defaultMessage: 'Edit a relation'
4286
+ })
4287
+ })
4288
+ ]
4289
+ })
4290
+ })
4291
+ }),
4292
+ /*#__PURE__*/ jsx(RelationModalBody, {}),
4293
+ /*#__PURE__*/ jsx(Modal.Footer, {
4294
+ children: /*#__PURE__*/ jsx(Button, {
4295
+ onClick: onToggle,
4296
+ variant: "tertiary",
4297
+ children: formatMessage({
4298
+ id: 'app.components.Button.cancel',
4299
+ defaultMessage: 'Cancel'
4300
+ })
4301
+ })
4302
+ })
4303
+ ]
4304
+ })
4305
+ });
4306
+ };
4307
+ const RelationModalBody = ()=>{
4308
+ const { formatMessage } = useIntl();
4309
+ const documentMeta = useDocumentContext('RelationModalBody', (state)=>state.meta);
4310
+ const documentResponse = useDocumentContext('RelationModalBody', (state)=>state.document);
4311
+ const documentLayoutResponse = useDocumentLayout(documentMeta.model);
4312
+ const plugins = useStrapiApp('RelationModalBody', (state)=>state.plugins);
4313
+ const initialValues = documentResponse.getInitialFormValues();
4314
+ const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
4315
+ action,
4316
+ subject: documentMeta.model
4317
+ })));
4318
+ const isLoading = isLoadingPermissions || documentLayoutResponse.isLoading || documentResponse.isLoading;
4319
+ if (isLoading && !documentResponse.document?.documentId) {
4320
+ return /*#__PURE__*/ jsx(Loader, {
4321
+ small: true,
4322
+ children: formatMessage({
4323
+ id: 'content-manager.ListViewTable.relation-loading',
4324
+ defaultMessage: 'Relations are loading'
4325
+ })
4326
+ });
4327
+ }
4328
+ if (error || !documentMeta.model || documentLayoutResponse.error || !documentResponse.document || !documentResponse.meta || !documentResponse.schema || !initialValues) {
4329
+ return /*#__PURE__*/ jsx(Flex, {
4330
+ alignItems: "center",
4331
+ height: "100%",
4332
+ justifyContent: "center",
4333
+ children: /*#__PURE__*/ jsx(EmptyStateLayout, {
4334
+ icon: /*#__PURE__*/ jsx(WarningCircle, {
4335
+ width: "16rem"
4336
+ }),
4337
+ content: formatMessage({
4338
+ id: 'anErrorOccurred',
4339
+ defaultMessage: 'Whoops! Something went wrong. Please, try again.'
4340
+ })
4341
+ })
4342
+ });
4343
+ }
4344
+ const documentTitle = documentResponse.getTitle(documentLayoutResponse.edit.settings.mainField);
4345
+ const hasDraftAndPublished = documentResponse.schema?.options?.draftAndPublish ?? false;
4346
+ const props = {
4347
+ activeTab: 'draft',
4348
+ collectionType: documentMeta.collectionType,
4349
+ model: documentMeta.model,
4350
+ documentId: documentMeta.documentId,
4351
+ document: documentResponse.document,
4352
+ meta: documentResponse.meta
4353
+ };
4354
+ return /*#__PURE__*/ jsx(Modal.Body, {
4355
+ children: /*#__PURE__*/ jsx(DocumentRBAC, {
4356
+ permissions: permissions,
4357
+ model: documentMeta.model,
4358
+ children: /*#__PURE__*/ jsxs(Form, {
4359
+ initialValues: initialValues,
4360
+ validate: (values, options)=>{
4361
+ const yupSchema = createYupSchema(documentResponse.schema?.attributes, documentResponse.components, {
4362
+ status: documentResponse.document?.status,
4363
+ ...options
4364
+ });
4365
+ return yupSchema.validate(values, {
4366
+ abortEarly: false
4367
+ });
4368
+ },
4369
+ method: "PUT",
4370
+ children: [
4371
+ /*#__PURE__*/ jsxs(Flex, {
4372
+ alignItems: "flex-start",
4373
+ direction: "column",
4374
+ gap: 2,
4375
+ children: [
4376
+ /*#__PURE__*/ jsxs(Flex, {
4377
+ width: "100%",
4378
+ justifyContent: "space-between",
4379
+ gap: 2,
4380
+ children: [
4381
+ /*#__PURE__*/ jsx(Typography, {
4382
+ tag: "h2",
4383
+ variant: "alpha",
4384
+ children: documentTitle
4385
+ }),
4386
+ /*#__PURE__*/ jsx(Flex, {
4387
+ gap: 2,
4388
+ children: /*#__PURE__*/ jsx(DescriptionComponentRenderer, {
4389
+ props: props,
4390
+ descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
4391
+ children: (actions)=>{
4392
+ const filteredActions = actions.filter((action)=>{
4393
+ return [
4394
+ action.position
4395
+ ].flat().includes('relation-modal');
4396
+ });
4397
+ const [primaryAction, secondaryAction] = filteredActions;
4398
+ if (!primaryAction && !secondaryAction) return null;
4399
+ // Both actions are available when draft and publish enabled
4400
+ if (primaryAction && secondaryAction) {
4401
+ return /*#__PURE__*/ jsxs(Fragment, {
4402
+ children: [
4403
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4404
+ ...secondaryAction,
4405
+ variant: secondaryAction.variant || 'secondary'
4406
+ }),
4407
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4408
+ ...primaryAction,
4409
+ variant: primaryAction.variant || 'default'
4410
+ })
4411
+ ]
4412
+ });
4413
+ }
4414
+ // Otherwise we just have the save action
4415
+ return /*#__PURE__*/ jsx(DocumentActionButton, {
4416
+ ...primaryAction,
4417
+ variant: primaryAction.variant || 'secondary'
4418
+ });
4419
+ }
4420
+ })
4421
+ })
4422
+ ]
4423
+ }),
4424
+ hasDraftAndPublished ? /*#__PURE__*/ jsx(Box, {
4425
+ children: /*#__PURE__*/ jsx(DocumentStatus, {
4426
+ status: documentResponse.document?.status
4427
+ })
4428
+ }) : null
4429
+ ]
4430
+ }),
4431
+ /*#__PURE__*/ jsx(Flex, {
4432
+ flex: 1,
4433
+ overflow: "auto",
4434
+ alignItems: "stretch",
4435
+ paddingTop: 7,
4436
+ children: /*#__PURE__*/ jsx(Box, {
4437
+ overflow: "auto",
4438
+ flex: 1,
4439
+ children: /*#__PURE__*/ jsx(FormLayout, {
4440
+ layout: documentLayoutResponse.edit.layout,
4441
+ hasBackground: false
4442
+ })
4443
+ })
4444
+ })
4445
+ ]
4446
+ })
4447
+ })
4448
+ });
4449
+ };
4450
+
4451
+ /**
4452
+ * Remove a relation, whether it's been already saved or not.
4453
+ * It's used both in RelationsList, where the "remove relation" button is, and in the input,
4454
+ * because we sometimes need to remove a previous relation when selecting a new one.
4455
+ */ function useHandleDisconnect(fieldName, consumerName) {
4456
+ const field = useField(fieldName);
4457
+ const removeFieldRow = useForm(consumerName, (state)=>state.removeFieldRow);
4458
+ const addFieldRow = useForm(consumerName, (state)=>state.addFieldRow);
4459
+ const handleDisconnect = (relation)=>{
4460
+ if (field.value && field.value.connect) {
4461
+ /**
4462
+ * A relation will exist in the `connect` array _if_ it has
4463
+ * been added without saving. In this case, we just remove it
4464
+ * from the connect array
4465
+ */ const indexOfRelationInConnectArray = field.value.connect.findIndex((rel)=>rel.id === relation.id);
4466
+ if (indexOfRelationInConnectArray >= 0) {
4467
+ removeFieldRow(`${fieldName}.connect`, indexOfRelationInConnectArray);
4468
+ return;
4469
+ }
4470
+ }
4471
+ addFieldRow(`${fieldName}.disconnect`, {
4472
+ id: relation.id,
4473
+ apiData: {
4474
+ id: relation.id,
4475
+ documentId: relation.documentId,
4476
+ locale: relation.locale
4477
+ }
4478
+ });
4479
+ };
4480
+ return handleDisconnect;
4481
+ }
4482
+ /* -------------------------------------------------------------------------------------------------
4483
+ * RelationsField
4484
+ * -----------------------------------------------------------------------------------------------*/ const RELATIONS_TO_DISPLAY = 5;
4485
+ const ONE_WAY_RELATIONS = [
4486
+ 'oneWay',
4487
+ 'oneToOne',
4488
+ 'manyToOne',
4489
+ 'oneToManyMorph',
4490
+ 'oneToOneMorph'
4491
+ ];
4492
+ /**
4493
+ * TODO: we get a rather ugly flash when we remove a single relation from the list leaving
4494
+ * no other relations when we press save. The initial relation re-renders, probably because
4495
+ * of the lag in the Form cleaning it's "disconnect" array, whilst our data has not been invalidated.
4496
+ *
4497
+ * Could we invalidate relation data on the document actions? Should we?
4498
+ */ /**
4499
+ * @internal
4500
+ * @description The relations field holds a lot of domain logic for handling relations which is rather complicated
4501
+ * At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
4502
+ * they wish to do so.
4503
+ */ const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4504
+ const documentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4505
+ const documentResponse = useDocumentContext('RelationsField', (state)=>state.document);
4506
+ const [currentPage, setCurrentPage] = React.useState(1);
4507
+ const documentId = documentResponse.document?.documentId;
4508
+ const { formatMessage } = useIntl();
4509
+ const [{ query }] = useQueryParams();
4510
+ const params = buildValidParams(query);
4511
+ const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4512
+ const isDisabled = isMorph || disabled;
4513
+ const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
4514
+ componentId: id,
4515
+ componentUID: uid
4516
+ }));
4517
+ const isSubmitting = useForm('RelationsList', (state)=>state.isSubmitting);
4518
+ React.useEffect(()=>{
4519
+ setCurrentPage(1);
4520
+ }, [
4521
+ isSubmitting
4522
+ ]);
4523
+ /**
4524
+ * We'll always have a documentId in a created entry, so we look for a componentId first.
4525
+ * Same with `uid` and `documentModel`.
4526
+ */ const id = componentId ? componentId.toString() : documentId;
4527
+ const model = componentUID ?? documentMeta.model;
4528
+ /**
4529
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4530
+ * Where the above example would a nested field within two components, however
4531
+ * we only require the field on the component not the complete path since we query
4532
+ * individual components. Therefore we split the string and take the last item.
4533
+ */ const [targetField] = props.name.split('.').slice(-1);
4534
+ const { data, isLoading, isFetching } = useGetRelationsQuery({
4535
+ model,
4536
+ targetField,
4537
+ // below we don't run the query if there is no id.
4538
+ id,
4539
+ params: {
4540
+ ...params,
4541
+ pageSize: RELATIONS_TO_DISPLAY,
4542
+ page: currentPage
4543
+ }
4544
+ }, {
4545
+ refetchOnMountOrArgChange: true,
4546
+ skip: !id,
4547
+ selectFromResult: (result)=>{
4548
+ return {
4549
+ ...result,
4550
+ data: {
4551
+ ...result.data,
4552
+ results: result.data?.results ? result.data.results : []
4553
+ }
4554
+ };
4555
+ }
4556
+ });
4557
+ const handleLoadMore = ()=>{
4558
+ setCurrentPage((prev)=>prev + 1);
4559
+ };
4560
+ const field = useField(props.name);
4561
+ const isFetchingMoreRelations = isLoading || isFetching;
4562
+ const realServerRelationsCount = 'pagination' in data && data.pagination ? data.pagination.total : 0;
4563
+ /**
4564
+ * Items that are already connected, but reordered would be in
4565
+ * this list, so to get an accurate figure, we remove them.
4566
+ */ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
4567
+ const relationsDisconnected = field.value?.disconnect?.length ?? 0;
4568
+ const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
4569
+ /**
4570
+ * This is it, the source of truth for reordering in conjunction with partial loading & updating
4571
+ * of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
4572
+ * create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
4573
+ */ const relations = React.useMemo(()=>{
4574
+ const ctx = {
4575
+ field: field.value,
4576
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4577
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
4578
+ mainField: props.mainField
4579
+ };
4580
+ /**
4581
+ * Tidy up our data.
4582
+ */ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
4583
+ const transformedRels = transformations([
4584
+ ...data.results
4585
+ ]);
4586
+ /**
4587
+ * THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
4588
+ * then the list will be in the wrong order.
4589
+ */ return [
4590
+ ...transformedRels,
4591
+ ...field.value?.connect ?? []
4592
+ ].sort((a, b)=>{
4593
+ if (a.__temp_key__ < b.__temp_key__) return -1;
4594
+ if (a.__temp_key__ > b.__temp_key__) return 1;
4595
+ return 0;
4596
+ });
4597
+ }, [
4598
+ data.results,
4599
+ field.value,
4600
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4601
+ props.attribute.targetModel,
4602
+ props.mainField
4603
+ ]);
4604
+ const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
4605
+ const handleConnect = (relation)=>{
4606
+ const [lastItemInList] = relations.slice(-1);
4607
+ const item = {
4608
+ id: relation.id,
4609
+ apiData: {
4610
+ id: relation.id,
4611
+ documentId: relation.documentId,
4612
+ locale: relation.locale
4613
+ },
4614
+ status: relation.status,
4615
+ /**
4616
+ * If there's a last item, that's the first key we use to generate out next one.
4617
+ */ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
4618
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
4619
+ [props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
4620
+ label: getRelationLabel(relation, props.mainField),
4621
+ // @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
4622
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4623
+ };
4624
+ if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
4625
+ // Remove any existing relation so they can be replaced with the new one
4626
+ field.value?.connect?.forEach(handleDisconnect);
4627
+ relations.forEach(handleDisconnect);
4628
+ field.onChange(`${props.name}.connect`, [
4629
+ item
4630
+ ]);
4631
+ } else {
4632
+ field.onChange(`${props.name}.connect`, [
4633
+ ...field.value?.connect ?? [],
4634
+ item
4635
+ ]);
4636
+ }
4637
+ };
4638
+ return /*#__PURE__*/ jsxs(Flex, {
4639
+ ref: ref,
4640
+ direction: "column",
4641
+ gap: 3,
4642
+ justifyContent: "space-between",
4643
+ alignItems: "stretch",
4644
+ wrap: "wrap",
4645
+ children: [
4646
+ /*#__PURE__*/ jsxs(StyledFlex, {
4647
+ direction: "column",
4648
+ alignItems: "start",
4649
+ gap: 2,
4650
+ width: "100%",
4651
+ children: [
4652
+ /*#__PURE__*/ jsx(RelationsInput, {
4653
+ disabled: isDisabled,
4654
+ // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4655
+ id: componentUID ? componentId ? `${componentId}` : '' : documentId,
4656
+ label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4657
+ model: model,
4658
+ onChange: handleConnect,
4659
+ ...props
4660
+ }),
4661
+ 'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
4662
+ disabled: isFetchingMoreRelations,
4663
+ onClick: handleLoadMore,
4664
+ loading: isFetchingMoreRelations,
4665
+ startIcon: /*#__PURE__*/ jsx(ArrowClockwise, {}),
4666
+ // prevent the label from line-wrapping
4667
+ shrink: 0,
4668
+ children: formatMessage({
4669
+ id: getTranslation('relation.loadMore'),
4670
+ defaultMessage: 'Load More'
4671
+ })
4672
+ }) : null
4673
+ ]
4674
+ }),
4675
+ /*#__PURE__*/ jsx(RelationsList, {
4676
+ data: relations,
4677
+ serverData: data.results,
4678
+ disabled: isDisabled,
4679
+ name: props.name,
4680
+ isLoading: isFetchingMoreRelations,
4681
+ relationType: props.attribute.relation,
4682
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4683
+ targetModel: props.attribute.targetModel
4684
+ })
4685
+ ]
4686
+ });
4687
+ });
4688
+ /**
4689
+ * TODO: this can be removed once we stop shipping Inputs with
4690
+ * labels wrapped round in DS@2.
4691
+ */ const StyledFlex = styled(Flex)`
4692
+ & > div {
4693
+ width: 100%;
4694
+ }
4695
+ `;
4696
+ /**
4697
+ * If it's in the connected array, it can get out of our data array,
4698
+ * we'll be putting it back in later and sorting it anyway.
4699
+ */ const removeConnected = ({ field })=>(relations)=>{
4700
+ return relations.filter((relation)=>{
4701
+ const connectedRelations = field?.connect ?? [];
4702
+ return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4703
+ });
4704
+ };
4705
+ /**
4706
+ * @description Removes relations that are in the `disconnect` array of the field
4707
+ */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4708
+ const disconnectedRelations = field?.disconnect ?? [];
4709
+ return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4710
+ });
4711
+ /**
4712
+ * @description Adds a label and href to the relation object we use this to render
4713
+ * a better UI where we can link to the relation and display a human-readable label.
4714
+ */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4715
+ return {
4716
+ ...relation,
4717
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4718
+ [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4719
+ label: getRelationLabel(relation, mainField),
4720
+ href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4721
+ };
4722
+ });
4723
+ /**
4724
+ * @description Contains all the logic for the combobox that can search
4725
+ * for relations and then add them to the field's connect array.
4726
+ */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, ...props })=>{
4727
+ const [textValue, setTextValue] = React.useState('');
4728
+ const [searchParams, setSearchParams] = React.useState({
4729
+ _q: '',
4730
+ page: 1
4731
+ });
4732
+ const { toggleNotification } = useNotification();
4733
+ const [{ query }] = useQueryParams();
4734
+ const { formatMessage } = useIntl();
4735
+ const fieldRef = useFocusInputField(name);
4736
+ const field = useField(name);
4737
+ const searchParamsDebounced = useDebounce(searchParams, 300);
4738
+ const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
4739
+ /**
4740
+ * Because we're using a lazy query, we need to trigger the search
4741
+ * when the component mounts and when the search params change.
4742
+ * We also need to trigger the search when the field value changes
4743
+ * so that we can filter out the relations that are already connected.
4744
+ */ React.useEffect(()=>{
4745
+ /**
4746
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4747
+ * Where the above example would a nested field within two components, however
4748
+ * we only require the field on the component not the complete path since we query
4749
+ * individual components. Therefore we split the string and take the last item.
4750
+ */ const [targetField] = name.split('.').slice(-1);
4751
+ searchForTrigger({
4752
+ model,
4753
+ targetField,
4754
+ params: {
4755
+ ...buildValidParams(query),
4756
+ id: id ?? '',
4757
+ pageSize: 10,
4758
+ idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
4759
+ idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
4760
+ ...searchParamsDebounced
4761
+ }
4762
+ });
4763
+ }, [
4764
+ field.value?.connect,
4765
+ field.value?.disconnect,
4766
+ id,
4767
+ model,
4768
+ name,
4769
+ query,
4770
+ searchForTrigger,
4771
+ searchParamsDebounced
4772
+ ]);
4773
+ const handleSearch = async (search)=>{
4774
+ setSearchParams((s)=>({
4775
+ ...s,
4776
+ _q: search,
4777
+ page: 1
4778
+ }));
4779
+ };
4780
+ const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
4781
+ const options = data?.results ?? [];
4782
+ const handleChange = (relationId)=>{
4783
+ if (!relationId) {
4784
+ return;
4785
+ }
4786
+ const relation = options.find((opt)=>opt.id.toString() === relationId);
4787
+ if (!relation) {
4788
+ // This is very unlikely to happen, but it ensures we don't have any data for.
4789
+ 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.");
4790
+ toggleNotification({
4791
+ message: formatMessage({
4792
+ id: getTranslation('relation.error-adding-relation'),
4793
+ defaultMessage: 'An error occurred while trying to add the relation.'
4794
+ }),
4795
+ type: 'danger'
4796
+ });
4797
+ return;
4798
+ }
4799
+ /**
4800
+ * You need to give this relation a correct _temp_key_ but
4801
+ * this component doesn't know about those ones, you can't rely
4802
+ * on the connect array because that doesn't hold items that haven't
4803
+ * moved. So use a callback to fill in the gaps when connecting.
4804
+ *
4805
+ */ onChange(relation);
4806
+ };
4807
+ const handleLoadMore = ()=>{
4808
+ if (!data || !data.pagination) {
4809
+ return;
4810
+ } else if (data.pagination.page < data.pagination.pageCount) {
4811
+ setSearchParams((s)=>({
4812
+ ...s,
4813
+ page: s.page + 1
4814
+ }));
4815
+ }
4816
+ };
4817
+ React.useLayoutEffect(()=>{
4818
+ setTextValue('');
4819
+ }, [
4820
+ field.value
4821
+ ]);
4822
+ return /*#__PURE__*/ jsxs(Field.Root, {
4823
+ error: field.error,
4824
+ hint: hint,
4825
+ name: name,
4826
+ required: required,
4827
+ children: [
4828
+ /*#__PURE__*/ jsx(Field.Label, {
4829
+ action: labelAction,
4830
+ children: label
4831
+ }),
4832
+ /*#__PURE__*/ jsx(Combobox, {
4833
+ ref: fieldRef,
4834
+ name: name,
4835
+ autocomplete: "list",
4836
+ placeholder: placeholder || formatMessage({
4837
+ id: getTranslation('relation.add'),
4838
+ defaultMessage: 'Add relation'
4839
+ }),
4840
+ hasMoreItems: hasNextPage,
4841
+ loading: isLoading,
4842
+ onOpenChange: ()=>{
4843
+ handleSearch(textValue ?? '');
4844
+ },
4845
+ noOptionsMessage: ()=>formatMessage({
4846
+ id: getTranslation('relation.notAvailable'),
4847
+ defaultMessage: 'No relations available'
4848
+ }),
4849
+ loadingMessage: formatMessage({
4850
+ id: getTranslation('relation.isLoading'),
4851
+ defaultMessage: 'Relations are loading'
4852
+ }),
4853
+ onLoadMore: handleLoadMore,
4854
+ textValue: textValue,
4855
+ onChange: handleChange,
4856
+ onTextValueChange: (text)=>{
4857
+ setTextValue(text);
4858
+ },
4859
+ onInputChange: (event)=>{
4860
+ handleSearch(event.currentTarget.value);
4861
+ },
4862
+ ...props,
4863
+ children: options.map((opt)=>{
4864
+ const textValue = getRelationLabel(opt, mainField);
4865
+ return /*#__PURE__*/ jsx(ComboboxOption, {
4866
+ value: opt.id.toString(),
4867
+ textValue: textValue,
4868
+ children: /*#__PURE__*/ jsxs(Flex, {
4869
+ gap: 2,
4870
+ justifyContent: "space-between",
4871
+ children: [
4872
+ /*#__PURE__*/ jsx(Typography, {
4873
+ ellipsis: true,
4874
+ children: textValue
4875
+ }),
4876
+ opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
4877
+ status: opt.status
4878
+ }) : null
4879
+ ]
4880
+ })
4881
+ }, opt.id);
4882
+ })
4883
+ }),
4884
+ /*#__PURE__*/ jsx(Field.Error, {}),
4885
+ /*#__PURE__*/ jsx(Field.Hint, {})
4886
+ ]
4887
+ });
4888
+ };
4889
+ /* -------------------------------------------------------------------------------------------------
4890
+ * RelationsList
4891
+ * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
4892
+ const RELATION_GUTTER = 4;
4893
+ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
4894
+ const ariaDescriptionId = React.useId();
4895
+ const { formatMessage } = useIntl();
4896
+ const listRef = React.useRef(null);
4897
+ const outerListRef = React.useRef(null);
4898
+ const [overflow, setOverflow] = React.useState();
4899
+ const [liveText, setLiveText] = React.useState('');
4900
+ const field = useField(name);
4901
+ React.useEffect(()=>{
4902
+ if (data.length <= RELATIONS_TO_DISPLAY) {
4903
+ return setOverflow(undefined);
4904
+ }
4905
+ const handleNativeScroll = (e)=>{
4906
+ const el = e.target;
4907
+ const parentScrollContainerHeight = el.parentNode.scrollHeight;
4908
+ const maxScrollBottom = el.scrollHeight - el.scrollTop;
4909
+ if (el.scrollTop === 0) {
4910
+ return setOverflow('bottom');
4911
+ }
4912
+ if (maxScrollBottom === parentScrollContainerHeight) {
4913
+ return setOverflow('top');
4914
+ }
4915
+ return setOverflow('top-bottom');
4916
+ };
4917
+ const outerListRefCurrent = outerListRef?.current;
4918
+ if (!isLoading && data.length > 0 && outerListRefCurrent) {
4919
+ outerListRef.current.addEventListener('scroll', handleNativeScroll);
4920
+ }
4921
+ return ()=>{
4922
+ if (outerListRefCurrent) {
4923
+ outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
4924
+ }
4925
+ };
4926
+ }, [
4927
+ isLoading,
4928
+ data.length
4929
+ ]);
4930
+ const getItemPos = (index)=>`${index + 1} of ${data.length}`;
4931
+ const handleMoveItem = (newIndex, oldIndex)=>{
4932
+ const item = data[oldIndex];
4933
+ setLiveText(formatMessage({
4934
+ id: getTranslation('dnd.reorder'),
4935
+ defaultMessage: '{item}, moved. New position in list: {position}.'
4936
+ }, {
4937
+ item: item.label ?? item.documentId,
4938
+ position: getItemPos(newIndex)
4939
+ }));
4940
+ /**
4941
+ * Splicing mutates the array, so we need to create a new array
4942
+ */ const newData = [
4943
+ ...data
4944
+ ];
4945
+ const currentRow = data[oldIndex];
4946
+ const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
4947
+ const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
4948
+ /**
4949
+ * We're moving the relation between two other relations, so
4950
+ * we need to generate a new key that keeps the order
4951
+ */ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
4952
+ newData.splice(oldIndex, 1);
4953
+ newData.splice(newIndex, 0, {
4954
+ ...currentRow,
4955
+ __temp_key__: newKey
4956
+ });
4957
+ /**
4958
+ * Now we diff against the server to understand what's different so we
4959
+ * can keep the connect array nice and tidy. It also needs reversing because
4960
+ * we reverse the relations from the server in the first place.
4961
+ */ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
4962
+ const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
4963
+ const relationInFront = array[currentIndex + 1];
4964
+ if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
4965
+ const position = relationInFront ? {
4966
+ before: relationInFront.documentId,
4967
+ locale: relationInFront.locale,
4968
+ status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
4969
+ } : {
4970
+ end: true
4971
+ };
4972
+ const relationWithPosition = {
4973
+ ...relation,
4974
+ ...{
4975
+ apiData: {
4976
+ id: relation.id,
4977
+ documentId: relation.documentId,
4978
+ locale: relation.locale,
4979
+ position
4980
+ }
4981
+ }
4982
+ };
4983
+ return [
4984
+ ...acc,
4985
+ relationWithPosition
4986
+ ];
4987
+ }
4988
+ return acc;
4989
+ }, []).toReversed();
4990
+ field.onChange(`${name}.connect`, connectedRelations);
4991
+ };
4992
+ const handleGrabItem = (index)=>{
4993
+ const item = data[index];
4994
+ setLiveText(formatMessage({
4995
+ id: getTranslation('dnd.grab-item'),
4996
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
4997
+ }, {
4998
+ item: item.label ?? item.documentId,
4999
+ position: getItemPos(index)
5000
+ }));
5001
+ };
5002
+ const handleDropItem = (index)=>{
5003
+ const { href: _href, label, ...item } = data[index];
5004
+ setLiveText(formatMessage({
5005
+ id: getTranslation('dnd.drop-item'),
5006
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`
5007
+ }, {
5008
+ item: label ?? item.documentId,
5009
+ position: getItemPos(index)
5010
+ }));
5011
+ };
5012
+ const handleCancel = (index)=>{
5013
+ const item = data[index];
5014
+ setLiveText(formatMessage({
5015
+ id: getTranslation('dnd.cancel-item'),
5016
+ defaultMessage: '{item}, dropped. Re-order cancelled.'
5017
+ }, {
5018
+ item: item.label ?? item.documentId
5019
+ }));
5020
+ };
5021
+ const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
5022
+ /**
5023
+ * These relation types will only ever have one item
5024
+ * in their list, so you can't reorder a single item!
5025
+ */ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
5026
+ 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);
5027
+ return /*#__PURE__*/ jsxs(ShadowBox, {
5028
+ $overflowDirection: overflow,
5029
+ children: [
5030
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5031
+ id: ariaDescriptionId,
5032
+ children: formatMessage({
5033
+ id: getTranslation('dnd.instructions'),
5034
+ defaultMessage: `Press spacebar to grab and re-order`
5035
+ })
5036
+ }),
5037
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5038
+ "aria-live": "assertive",
5039
+ children: liveText
5040
+ }),
5041
+ /*#__PURE__*/ jsx(FixedSizeList, {
5042
+ height: dynamicListHeight,
5043
+ ref: listRef,
5044
+ outerRef: outerListRef,
5045
+ itemCount: data.length,
5046
+ itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
5047
+ itemData: {
5048
+ ariaDescribedBy: ariaDescriptionId,
5049
+ canDrag: canReorder,
5050
+ disabled,
5051
+ handleCancel,
5052
+ handleDropItem,
5053
+ handleGrabItem,
5054
+ handleMoveItem,
5055
+ name,
5056
+ handleDisconnect,
5057
+ relations: data,
5058
+ targetModel
5059
+ },
5060
+ itemKey: (index)=>data[index].id,
5061
+ innerElementType: "ol",
5062
+ children: ListItem
5063
+ })
5064
+ ]
5065
+ });
5066
+ };
5067
+ const ShadowBox = styled(Box)`
5068
+ position: relative;
5069
+ overflow: hidden;
5070
+ flex: 1;
5071
+
5072
+ &:before,
5073
+ &:after {
5074
+ position: absolute;
5075
+ width: 100%;
5076
+ height: 4px;
5077
+ z-index: 1;
5078
+ }
5079
+
5080
+ &:before {
5081
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5082
+ content: '';
5083
+ background: linear-gradient(rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5084
+ top: 0;
5085
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'top' ? 1 : 0};
5086
+ transition: opacity 0.2s ease-in-out;
5087
+ }
5088
+
5089
+ &:after {
5090
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5091
+ content: '';
5092
+ background: linear-gradient(0deg, rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5093
+ bottom: 0;
5094
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'bottom' ? 1 : 0};
5095
+ transition: opacity 0.2s ease-in-out;
5096
+ }
5097
+ `;
5098
+ const CustomTextButton = styled(TextButton)`
5099
+ & > span {
5100
+ font-size: ${({ theme })=>theme.fontSizes[2]};
5101
+ }
5102
+ `;
5103
+ const ListItem = ({ data, index, style })=>{
5104
+ const [triggerRefetchDocument] = useLazyGetDocumentQuery();
5105
+ const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
5106
+ const changeDocument = useDocumentContext('RelationsList', (state)=>state.changeDocument);
5107
+ const rootDocumentMeta = useDocumentContext('RelationsList', (state)=>state.rootDocumentMeta);
5108
+ const { formatMessage } = useIntl();
5109
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
5110
+ const { href, id, label, status, documentId, apiData, locale } = relations[index];
5111
+ const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
5112
+ type: `${ItemTypes.RELATION}_${name}`,
5113
+ index,
5114
+ item: {
5115
+ displayedValue: label,
5116
+ status,
5117
+ id: id,
5118
+ index
5119
+ },
5120
+ onMoveItem: handleMoveItem,
5121
+ onDropItem: handleDropItem,
5122
+ onGrabItem: handleGrabItem,
5123
+ onCancel: handleCancel,
5124
+ dropSensitivity: DROP_SENSITIVITY.REGULAR
5125
+ });
5126
+ const composedRefs = useComposedRefs(relationRef, dragRef);
5127
+ const handleChangeModalContent = ()=>{
5128
+ if (changeDocument) {
5129
+ const newRelation = {
5130
+ documentId: documentId ?? apiData?.documentId,
5131
+ model: targetModel,
5132
+ collectionType: getCollectionType(href),
5133
+ params: {
5134
+ locale: locale || null
5135
+ }
5136
+ };
5137
+ changeDocument(newRelation);
5138
+ }
5139
+ };
5140
+ const handleToggleModal = ()=>{
5141
+ if (isModalOpen) {
5142
+ setIsModalOpen(false);
5143
+ const document = {
5144
+ collectionType: rootDocumentMeta.collectionType,
5145
+ model: rootDocumentMeta.model,
5146
+ documentId: rootDocumentMeta.documentId
5147
+ };
5148
+ // Change back to the root document
5149
+ changeDocument(document);
5150
+ // Read from cache or refetch root document
5151
+ triggerRefetchDocument(document, // Favor the cache
5152
+ true);
5153
+ } else {
5154
+ setIsModalOpen(true);
5155
+ }
5156
+ };
5157
+ React.useEffect(()=>{
5158
+ dragPreviewRef(getEmptyImage());
5159
+ }, [
5160
+ dragPreviewRef
5161
+ ]);
5162
+ return /*#__PURE__*/ jsx(Box, {
5163
+ style: style,
5164
+ tag: "li",
5165
+ ref: dropRef,
5166
+ "aria-describedby": ariaDescribedBy,
5167
+ cursor: canDrag ? 'all-scroll' : 'default',
5168
+ children: isDragging ? /*#__PURE__*/ jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxs(Flex, {
5169
+ paddingTop: 2,
5170
+ paddingBottom: 2,
5171
+ paddingLeft: canDrag ? 2 : 4,
5172
+ paddingRight: 4,
5173
+ hasRadius: true,
5174
+ borderColor: "neutral200",
5175
+ background: disabled ? 'neutral150' : 'neutral0',
5176
+ justifyContent: "space-between",
5177
+ ref: composedRefs,
5178
+ "data-handler-id": handlerId,
5179
+ children: [
5180
+ /*#__PURE__*/ jsxs(FlexWrapper, {
5181
+ gap: 1,
5182
+ children: [
5183
+ canDrag ? /*#__PURE__*/ jsx(IconButton, {
5184
+ tag: "div",
5185
+ role: "button",
5186
+ tabIndex: 0,
5187
+ withTooltip: false,
5188
+ label: formatMessage({
5189
+ id: getTranslation('components.RelationInput.icon-button-aria-label'),
5190
+ defaultMessage: 'Drag'
5191
+ }),
5192
+ variant: "ghost",
5193
+ onKeyDown: handleKeyDown,
5194
+ disabled: disabled,
5195
+ children: /*#__PURE__*/ jsx(Drag, {})
5196
+ }) : null,
5197
+ /*#__PURE__*/ jsxs(Flex, {
5198
+ width: "100%",
5199
+ minWidth: 0,
5200
+ justifyContent: "space-between",
5201
+ children: [
5202
+ /*#__PURE__*/ jsx(Box, {
5203
+ minWidth: 0,
5204
+ paddingTop: 1,
5205
+ paddingBottom: 1,
5206
+ paddingRight: 4,
5207
+ children: /*#__PURE__*/ jsx(Tooltip, {
5208
+ description: label,
5209
+ children: isModalOpen ? /*#__PURE__*/ jsx(CustomTextButton, {
5210
+ onClick: handleChangeModalContent,
5211
+ children: label
5212
+ }) : /*#__PURE__*/ jsx(CustomTextButton, {
5213
+ onClick: ()=>{
5214
+ handleChangeModalContent();
5215
+ setIsModalOpen(true);
5216
+ },
5217
+ children: label
5218
+ })
5219
+ })
5220
+ }),
5221
+ status ? /*#__PURE__*/ jsx(DocumentStatus, {
5222
+ status: status
5223
+ }) : null,
5224
+ isModalOpen && /*#__PURE__*/ jsx(RelationModal, {
5225
+ open: isModalOpen,
5226
+ onToggle: handleToggleModal
5227
+ })
5228
+ ]
5229
+ })
5230
+ ]
5231
+ }),
5232
+ /*#__PURE__*/ jsx(Box, {
5233
+ paddingLeft: 4,
5234
+ children: /*#__PURE__*/ jsx(IconButton, {
5235
+ onClick: ()=>handleDisconnect(relations[index]),
5236
+ disabled: disabled,
5237
+ label: formatMessage({
5238
+ id: getTranslation('relation.disconnect'),
5239
+ defaultMessage: 'Remove'
5240
+ }),
5241
+ variant: "ghost",
5242
+ size: "S",
5243
+ children: /*#__PURE__*/ jsx(Cross, {})
5244
+ })
5245
+ })
5246
+ ]
5247
+ })
5248
+ });
5249
+ };
5250
+ const FlexWrapper = styled(Flex)`
5251
+ width: 100%;
5252
+ /* Used to prevent endAction to be pushed out of container */
5253
+ min-width: 0;
5254
+
5255
+ & > div[role='button'] {
5256
+ cursor: all-scroll;
5257
+ }
5258
+ `;
5259
+ const DisconnectButton = styled.button`
5260
+ svg path {
5261
+ fill: ${({ theme, disabled })=>disabled ? theme.colors.neutral600 : theme.colors.neutral500};
5262
+ }
5263
+
5264
+ &:hover svg path,
5265
+ &:focus svg path {
5266
+ fill: ${({ theme, disabled })=>!disabled && theme.colors.neutral600};
5267
+ }
5268
+ `;
5269
+ const LinkEllipsis = styled(Link$2)`
5270
+ display: block;
5271
+
5272
+ & > span {
5273
+ white-space: nowrap;
5274
+ overflow: hidden;
5275
+ text-overflow: ellipsis;
5276
+ display: block;
5277
+ }
5278
+ `;
5279
+ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsx(Box, {
5280
+ paddingTop: 2,
5281
+ paddingBottom: 2,
5282
+ paddingLeft: 4,
5283
+ paddingRight: 4,
5284
+ hasRadius: true,
5285
+ borderStyle: "dashed",
5286
+ borderColor: "primary600",
5287
+ borderWidth: "1px",
5288
+ background: "primary100",
5289
+ height: `calc(100% - ${RELATION_GUTTER}px)`
5290
+ });
5291
+ const MemoizedRelationsField = /*#__PURE__*/ React.memo(RelationsField);
5292
+
4229
5293
  const uidApi = contentManagerApi.injectEndpoints({
4230
5294
  endpoints: (builder)=>({
4231
5295
  getDefaultUID: builder.query({
@@ -4467,7 +5531,7 @@ const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, nam
4467
5531
  onMouseLeave: ()=>setShowRegenerate(false),
4468
5532
  children: isLoading ? /*#__PURE__*/ jsx(LoadingWrapper, {
4469
5533
  "data-testid": "loading-wrapper",
4470
- children: /*#__PURE__*/ jsx(Loader, {})
5534
+ children: /*#__PURE__*/ jsx(Loader$1, {})
4471
5535
  }) : /*#__PURE__*/ jsx(ArrowClockwise, {})
4472
5536
  })
4473
5537
  ]
@@ -6394,22 +7458,20 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
6394
7458
  });
6395
7459
  const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
6396
7460
 
6397
- /**
6398
- * @internal
6399
- *
6400
- * @description An abstraction around the regular form input renderer designed
6401
- * specifically to be used in the EditView of the content-manager this understands
6402
- * the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
6403
- * components such as Blocks / Relations.
6404
- */ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
6405
- const { id, document, collectionType } = useDoc();
6406
- const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
7461
+ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
7462
+ const { id: rootId } = useDoc();
7463
+ const documentMeta = useDocumentContext('InputRenderer', (state)=>state.meta);
7464
+ const documentResponse = useDocumentContext('InputRenderer', (state)=>state.document);
7465
+ const documentLayout = useDocumentLayout(documentMeta.model);
7466
+ const document = documentResponse?.document;
7467
+ const collectionType = documentMeta.collectionType;
6407
7468
  const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
7469
+ const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
6408
7470
  const canCreateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
6409
7471
  const canReadFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
6410
7472
  const canUpdateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
6411
7473
  const canUserAction = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
6412
- let idToCheck = id;
7474
+ let idToCheck = rootId;
6413
7475
  if (collectionType === SINGLE_TYPES) {
6414
7476
  idToCheck = document?.documentId;
6415
7477
  }
@@ -6425,7 +7487,8 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
6425
7487
  props.attribute.customField
6426
7488
  ] : undefined);
6427
7489
  const hint = useFieldHint(providedHint, props.attribute);
6428
- const { edit: { components } } = useDocLayout();
7490
+ const { edit: { components: rootDocumentComponents } } = useDocLayout();
7491
+ const components = Object.keys(rootDocumentComponents).length !== 0 ? rootDocumentComponents : documentLayout.edit.components;
6429
7492
  // We pass field in case of Custom Fields to keep backward compatibility
6430
7493
  const field = useField(props.name);
6431
7494
  if (!visible) {
@@ -6502,13 +7565,6 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
6502
7565
  disabled: fieldIsDisabled
6503
7566
  });
6504
7567
  case 'relation':
6505
- if (window.strapi.future.isEnabled('unstableRelationsOnTheFly')) {
6506
- return /*#__PURE__*/ jsx(MemoizedUnstableRelationsField, {
6507
- ...props,
6508
- hint: hint,
6509
- disabled: fieldIsDisabled
6510
- });
6511
- }
6512
7568
  return /*#__PURE__*/ jsx(MemoizedRelationsField, {
6513
7569
  ...props,
6514
7570
  hint: hint,
@@ -6606,7 +7662,7 @@ const getMinMax = (attribute)=>{
6606
7662
  };
6607
7663
  }
6608
7664
  };
6609
- const MemoizedInputRenderer = /*#__PURE__*/ memo(InputRenderer);
7665
+ const MemoizedInputRenderer = /*#__PURE__*/ React.memo(InputRenderer);
6610
7666
 
6611
7667
  const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6612
7668
  sm: '27.5rem'
@@ -6614,16 +7670,21 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6614
7670
  const ResponsiveGridRoot = styled(Grid$1.Root)`
6615
7671
  container-type: inline-size;
6616
7672
  `;
6617
- const ResponsiveGridItem = styled(Grid$1.Item)`
6618
- grid-column: span 12;
6619
-
6620
- @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
6621
- ${({ col })=>col && `grid-column: span ${col};`}
6622
- }
6623
- `;
6624
- const FormLayout = ({ layout, hasBackground = false })=>{
7673
+ // We need to use a different grid item for the responsive layout in the test environment
7674
+ // because @container is not supported in jsdom and it throws an error
7675
+ 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
7676
+ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
7677
+ grid-column: span 12;
7678
+ @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
7679
+ ${({ col })=>col && `grid-column: span ${col};`}
7680
+ }
7681
+ ` : styled(Grid$1.Item)`
7682
+ grid-column: span 12;
7683
+ `;
7684
+ const FormLayout = ({ layout, hasBackground = true })=>{
6625
7685
  const { formatMessage } = useIntl();
6626
- const { model } = useDoc();
7686
+ const documentMeta = useDocumentContext('FormLayout', (state)=>state.meta);
7687
+ const model = documentMeta.model;
6627
7688
  return /*#__PURE__*/ jsx(Flex, {
6628
7689
  direction: "column",
6629
7690
  alignItems: "stretch",
@@ -6654,7 +7715,7 @@ const FormLayout = ({ layout, hasBackground = false })=>{
6654
7715
  }, field.name);
6655
7716
  }
6656
7717
  return /*#__PURE__*/ jsx(Box, {
6657
- ...!hasBackground && {
7718
+ ...hasBackground && {
6658
7719
  padding: 6,
6659
7720
  borderColor: 'neutral150',
6660
7721
  background: 'neutral0',
@@ -6756,7 +7817,7 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
6756
7817
  const search = React.useMemo(()=>new URLSearchParams(searchString), [
6757
7818
  searchString
6758
7819
  ]);
6759
- const { components } = useDoc();
7820
+ const components = useDocumentContext('RepeatableComponent', (state)=>state.document.components);
6760
7821
  const { value = [], error, rawError } = useField(name);
6761
7822
  const addFieldRow = useForm('RepeatableComponent', (state)=>state.addFieldRow);
6762
7823
  const moveFieldRow = useForm('RepeatableComponent', (state)=>state.moveFieldRow);
@@ -7121,7 +8182,7 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
7121
8182
  const { formatMessage } = useIntl();
7122
8183
  const field = useField(name);
7123
8184
  const showResetComponent = !attribute.repeatable && field.value && !disabled;
7124
- const { components } = useDoc();
8185
+ const components = useDocumentContext('ComponentInput', (state)=>state.document.components);
7125
8186
  const handleInitialisationClick = ()=>{
7126
8187
  const schema = components[attribute.component];
7127
8188
  const form = createDefaultForm(schema, components);
@@ -7186,5 +8247,5 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
7186
8247
  };
7187
8248
  const MemoizedComponentInput = /*#__PURE__*/ React.memo(ComponentInput);
7188
8249
 
7189
- export { DynamicZone as D, FormLayout as F, MemoizedUIDInput as M, NotAllowedInput as N, useDynamicZone as a, useFieldHint as b, MemoizedWysiwyg as c, MemoizedComponentInput as d, MemoizedBlocksInput as e, useLazyComponents as u };
7190
- //# sourceMappingURL=Input-BexkC_pp.mjs.map
8250
+ 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 };
8251
+ //# sourceMappingURL=Input-BHucdqva.mjs.map