@strapi/content-manager 0.0.0-experimental.0af49f5c5ec496b0fad61ac9bfd4d0127b89d8d3 → 0.0.0-experimental.0e4ee97541bf8b600fc5272e0fee2b733aaf283b

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 (94) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-CtIa3aa2.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-CtIa3aa2.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BLWQy8ru.js → ComponentConfigurationPage-DdkVGfXC.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-BLWQy8ru.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-DsPR2DVk.mjs → EditConfigurationPage-D1nvB7Br.mjs} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-DsPR2DVk.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-RQkymxCy.js → EditConfigurationPage-LYEvR4fW.js} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-RQkymxCy.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-BPyVuPfM.mjs → EditViewPage-Bcnff6Vd.mjs} +11 -74
  10. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-B-kExt8C.js → EditViewPage-DqelJ9UK.js} +13 -76
  12. package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
  13. package/dist/_chunks/{Form-BFi4MXMT.js → Form-CnHfBeiB.js} +2 -2
  14. package/dist/_chunks/{Form-BFi4MXMT.js.map → Form-CnHfBeiB.js.map} +1 -1
  15. package/dist/_chunks/{Form-C1IcWm1u.mjs → Form-CzPCJi3B.mjs} +2 -2
  16. package/dist/_chunks/{Form-C1IcWm1u.mjs.map → Form-CzPCJi3B.mjs.map} +1 -1
  17. package/dist/_chunks/{History-04ChQ4pl.mjs → History-CcmSn3Mj.mjs} +4 -4
  18. package/dist/_chunks/{History-04ChQ4pl.mjs.map → History-CcmSn3Mj.mjs.map} +1 -1
  19. package/dist/_chunks/{History-wjcK4L0C.js → History-zArjENzj.js} +15 -15
  20. package/dist/_chunks/{History-wjcK4L0C.js.map → History-zArjENzj.js.map} +1 -1
  21. package/dist/_chunks/{Field-DPIsQRre.js → Input-CDHKQd7o.js} +1150 -1182
  22. package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
  23. package/dist/_chunks/{Field-Dltnt1km.mjs → Input-aV8SSoTa.mjs} +1193 -1225
  24. package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-BYqPYLSU.mjs → ListConfigurationPage-BPvzENJJ.mjs} +2 -2
  26. package/dist/_chunks/{ListConfigurationPage-BYqPYLSU.mjs.map → ListConfigurationPage-BPvzENJJ.mjs.map} +1 -1
  27. package/dist/_chunks/{ListConfigurationPage-CRbxIC3J.js → ListConfigurationPage-ByZAO_9H.js} +2 -2
  28. package/dist/_chunks/{ListConfigurationPage-CRbxIC3J.js.map → ListConfigurationPage-ByZAO_9H.js.map} +1 -1
  29. package/dist/_chunks/{ListViewPage-D5NY9183.js → ListViewPage-BVKBeQAA.js} +13 -10
  30. package/dist/_chunks/{ListViewPage-D5NY9183.js.map → ListViewPage-BVKBeQAA.js.map} +1 -1
  31. package/dist/_chunks/{ListViewPage-FU2LBuhl.mjs → ListViewPage-HljQVnFH.mjs} +8 -5
  32. package/dist/_chunks/{ListViewPage-FU2LBuhl.mjs.map → ListViewPage-HljQVnFH.mjs.map} +1 -1
  33. package/dist/_chunks/{NoContentTypePage-BgQVE_Qb.js → NoContentTypePage-BV5zfDxr.js} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-BgQVE_Qb.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-DCKUkwb8.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-DCKUkwb8.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-jqve7C8l.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-jqve7C8l.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-C5jwn70o.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-C5jwn70o.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
  41. package/dist/_chunks/{Preview-DaOihysv.js → Preview-DEHdENT1.js} +8 -15
  42. package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
  43. package/dist/_chunks/{Preview-BMYN548c.mjs → Preview-vfWOtPG5.mjs} +8 -15
  44. package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
  45. package/dist/_chunks/{Relations-gscPkxjF.mjs → Relations-B7_hbF0w.mjs} +6 -5
  46. package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
  47. package/dist/_chunks/{Relations-CTGM7Hv5.js → Relations-DcoOBejP.js} +6 -5
  48. package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
  49. package/dist/_chunks/{en-BzQmavmK.js → en-BR48D_RH.js} +3 -1
  50. package/dist/_chunks/{en-BzQmavmK.js.map → en-BR48D_RH.js.map} +1 -1
  51. package/dist/_chunks/{en-CSxLmrh1.mjs → en-D65uIF6Y.mjs} +3 -1
  52. package/dist/_chunks/{en-CSxLmrh1.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  53. package/dist/_chunks/{fr-B2Kyv8Z9.js → fr-C43IbhA_.js} +4 -1
  54. package/dist/_chunks/{fr-B2Kyv8Z9.js.map → fr-C43IbhA_.js.map} +1 -1
  55. package/dist/_chunks/{fr--pg5jUbt.mjs → fr-DBseuRuB.mjs} +4 -1
  56. package/dist/_chunks/{fr--pg5jUbt.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  57. package/dist/_chunks/{index-Ca7YWlAA.js → index-CxLSGwnk.js} +254 -57
  58. package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
  59. package/dist/_chunks/{index-DqasUQ6Q.mjs → index-EH8ZtHd5.mjs} +273 -76
  60. package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
  61. package/dist/_chunks/{layout-W3clJSCy.mjs → layout-CxDMdJ13.mjs} +3 -3
  62. package/dist/_chunks/{layout-W3clJSCy.mjs.map → layout-CxDMdJ13.mjs.map} +1 -1
  63. package/dist/_chunks/{layout-BW80JSCd.js → layout-DSeUTfMv.js} +3 -3
  64. package/dist/_chunks/{layout-BW80JSCd.js.map → layout-DSeUTfMv.js.map} +1 -1
  65. package/dist/_chunks/{relations-BlDkoeWh.mjs → relations-B8_Uu38Q.mjs} +17 -3
  66. package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
  67. package/dist/_chunks/{relations-C9Usz9k5.js → relations-S5nNKdN3.js} +16 -2
  68. package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
  69. package/dist/_chunks/{useDebounce-CtcjDB3L.js → usePrev-B9w_-eYc.js} +1 -14
  70. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  71. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  72. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  73. package/dist/admin/index.js +1 -1
  74. package/dist/admin/index.mjs +5 -5
  75. package/dist/admin/src/hooks/useDocument.d.ts +19 -2
  76. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  77. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  78. package/dist/admin/src/preview/pages/Preview.d.ts +1 -1
  79. package/package.json +6 -7
  80. package/dist/_chunks/EditViewPage-B-kExt8C.js.map +0 -1
  81. package/dist/_chunks/EditViewPage-BPyVuPfM.mjs.map +0 -1
  82. package/dist/_chunks/Field-DPIsQRre.js.map +0 -1
  83. package/dist/_chunks/Field-Dltnt1km.mjs.map +0 -1
  84. package/dist/_chunks/Preview-BMYN548c.mjs.map +0 -1
  85. package/dist/_chunks/Preview-DaOihysv.js.map +0 -1
  86. package/dist/_chunks/Relations-CTGM7Hv5.js.map +0 -1
  87. package/dist/_chunks/Relations-gscPkxjF.mjs.map +0 -1
  88. package/dist/_chunks/index-Ca7YWlAA.js.map +0 -1
  89. package/dist/_chunks/index-DqasUQ6Q.mjs.map +0 -1
  90. package/dist/_chunks/relations-BlDkoeWh.mjs.map +0 -1
  91. package/dist/_chunks/relations-C9Usz9k5.js.map +0 -1
  92. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +0 -1
  93. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +0 -29
  94. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +0 -1
@@ -1,19 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { useState, useEffect, useCallback, memo } from "react";
4
- import { useStrapiApp, createContext, useField, useNotification, useForm, useAPIErrorHandler, useQueryParams, useFocusInputField, InputRenderer as InputRenderer$1 } from "@strapi/admin/strapi-admin";
5
- import { Box, SingleSelect, SingleSelectOption, Typography, Flex, BaseLink, Button, Popover, Field, Tooltip, IconButton, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Grid as Grid$1, Accordion, TextButton, TextInput, IconButtonGroup, Menu, MenuItem } from "@strapi/design-system";
6
- import pipe$1 from "lodash/fp/pipe";
4
+ import { useStrapiApp, createContext, useField, useForm, useNotification, useAPIErrorHandler, useQueryParams, useFocusInputField, InputRenderer as InputRenderer$1 } from "@strapi/admin/strapi-admin";
5
+ import { Box, SingleSelect, SingleSelectOption, Typography, Flex, BaseLink, Button, Popover, Field, Tooltip, IconButton, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, Menu, 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, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, More, EyeStriked, CheckCircle, WarningCircle, Loader, ArrowClockwise, Plus } from "@strapi/icons";
7
7
  import { useIntl } from "react-intl";
8
- import { m as DOCUMENT_META_FIELDS, g as getTranslation, c as useDoc, e as contentManagerApi, n as CLONE_PATH, d as buildValidParams, f as useDocumentRBAC, S as SINGLE_TYPES, o as useDocLayout } from "./index-DqasUQ6Q.mjs";
9
- import { generateNKeysBetween } from "fractional-indexing";
10
- import { u as useComponent, C as ComponentProvider, M as MemoizedRelationsField } from "./Relations-gscPkxjF.mjs";
11
- import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Plus, Trash, EyeStriked, CheckCircle, WarningCircle, Loader, ArrowClockwise, More } from "@strapi/icons";
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-EH8ZtHd5.mjs";
12
9
  import { styled, css, keyframes } from "styled-components";
13
- import { C as ComponentIcon, a as COMPONENT_ICONS } from "./ComponentIcon-u4bIXTFY.mjs";
14
- import { getEmptyImage } from "react-dnd-html5-backend";
15
- import { a as DIRECTIONS, u as useDragAndDrop, I as ItemTypes } from "./useDragAndDrop-DJ6jqvZN.mjs";
16
- import { g as getIn } from "./objects-D6yBsdmx.mjs";
17
10
  import { Editor as Editor$1, Transforms, Node, Element, Range, Path, Point, createEditor } from "slate";
18
11
  import { withHistory } from "slate-history";
19
12
  import { useFocused, useSelected, ReactEditor, Editable, useSlate, Slate, withReact } from "slate-react";
@@ -68,9 +61,16 @@ import "prismjs/components/prism-typescript";
68
61
  import "prismjs/components/prism-tsx";
69
62
  import "prismjs/components/prism-vbnet";
70
63
  import "prismjs/components/prism-yaml";
71
- import { p as prefixFileUrlWithBackendUrl, u as usePrev, a as useDebounce } from "./useDebounce-DmuSJIF3.mjs";
64
+ import { p as prefixFileUrlWithBackendUrl, u as usePrev } from "./usePrev-DH6iah0A.mjs";
65
+ import { a as DIRECTIONS, u as useDragAndDrop, I as ItemTypes } from "./useDragAndDrop-DJ6jqvZN.mjs";
72
66
  import * as Toolbar from "@radix-ui/react-toolbar";
73
- import { useLocation, useMatch } from "react-router-dom";
67
+ import { getEmptyImage } from "react-dnd-html5-backend";
68
+ import { useMatch, useLocation } from "react-router-dom";
69
+ import { g as getIn } from "./objects-D6yBsdmx.mjs";
70
+ import { u as useComponent, C as ComponentProvider, M as MemoizedRelationsField } from "./Relations-B7_hbF0w.mjs";
71
+ import pipe$1 from "lodash/fp/pipe";
72
+ import { C as ComponentIcon, a as COMPONENT_ICONS } from "./ComponentIcon-u4bIXTFY.mjs";
73
+ import { a as useDebounce } from "./relations-B8_Uu38Q.mjs";
74
74
  import CodeMirror from "codemirror5";
75
75
  import sanitizeHtml from "sanitize-html";
76
76
  import { getLanguage, highlight, highlightAuto } from "highlight.js";
@@ -86,93 +86,6 @@ import sub from "markdown-it-sub";
86
86
  import sup from "markdown-it-sup";
87
87
  import "highlight.js/styles/solarized-dark.css";
88
88
  import "codemirror5/addon/display/placeholder";
89
- const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
90
- const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
91
- const traverse = (datum, attributes) => {
92
- return Object.entries(datum).reduce((acc, [key, value]) => {
93
- const attribute = attributes[key];
94
- if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
95
- acc[key] = value;
96
- return acc;
97
- }
98
- if (attribute.type === "component") {
99
- if (attribute.repeatable) {
100
- const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
101
- acc[key] = componentValue.map(
102
- (componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
103
- );
104
- } else {
105
- const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
106
- acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
107
- }
108
- } else if (attribute.type === "dynamiczone") {
109
- const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
110
- acc[key] = dynamicZoneValue.map(
111
- (componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
112
- );
113
- } else if (predicate(attribute, value)) {
114
- acc[key] = transform(value, attribute);
115
- } else {
116
- acc[key] = value;
117
- }
118
- return acc;
119
- }, {});
120
- };
121
- return traverse(data, schema.attributes);
122
- };
123
- const removeProhibitedFields = (prohibitedFields) => traverseData(
124
- (attribute) => prohibitedFields.includes(attribute.type),
125
- () => ""
126
- );
127
- const prepareRelations = traverseData(
128
- (attribute) => attribute.type === "relation",
129
- () => ({
130
- connect: [],
131
- disconnect: []
132
- })
133
- );
134
- const prepareTempKeys = traverseData(
135
- (attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
136
- (data) => {
137
- if (Array.isArray(data) && data.length > 0) {
138
- const keys = generateNKeysBetween(void 0, void 0, data.length);
139
- return data.map((datum, index) => ({
140
- ...datum,
141
- __temp_key__: keys[index]
142
- }));
143
- }
144
- return data;
145
- }
146
- );
147
- const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
148
- const schemaKeys = Object.keys(schema.attributes);
149
- const dataKeys = Object.keys(data);
150
- const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
151
- const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
152
- delete acc[key];
153
- return acc;
154
- }, structuredClone(data));
155
- return revisedData;
156
- };
157
- const removeNullValues = (data) => {
158
- return Object.entries(data).reduce((acc, [key, value]) => {
159
- if (value === null) {
160
- return acc;
161
- }
162
- acc[key] = value;
163
- return acc;
164
- }, {});
165
- };
166
- const transformDocument = (schema, components = {}) => (document2) => {
167
- const transformations = pipe$1(
168
- removeFieldsThatDontExistOnSchema(schema),
169
- removeProhibitedFields(["password"])(schema, components),
170
- removeNullValues,
171
- prepareRelations(schema, components),
172
- prepareTempKeys(schema, components)
173
- );
174
- return transformations(document2);
175
- };
176
89
  const componentStore = /* @__PURE__ */ new Map();
177
90
  const useLazyComponents = (componentUids = []) => {
178
91
  const [lazyComponentStore, setLazyComponentStore] = useState(Object.fromEntries(componentStore));
@@ -2665,26 +2578,6 @@ const BlocksInput = React.forwardRef(
2665
2578
  }
2666
2579
  );
2667
2580
  const MemoizedBlocksInput = React.memo(BlocksInput);
2668
- const createDefaultForm = (contentType, components = {}) => {
2669
- const traverseSchema = (attributes) => {
2670
- return Object.entries(attributes).reduce((acc, [key, attribute]) => {
2671
- if ("default" in attribute) {
2672
- acc[key] = attribute.default;
2673
- } else if (attribute.type === "component" && attribute.required) {
2674
- const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
2675
- if (attribute.repeatable) {
2676
- acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
2677
- } else {
2678
- acc[key] = defaultComponentForm;
2679
- }
2680
- } else if (attribute.type === "dynamiczone" && attribute.required) {
2681
- acc[key] = [];
2682
- }
2683
- return acc;
2684
- }, {});
2685
- };
2686
- return traverseSchema(contentType.attributes);
2687
- };
2688
2581
  const Initializer = ({ disabled, name: name2, onClick }) => {
2689
2582
  const { formatMessage } = useIntl();
2690
2583
  const field = useField(name2);
@@ -2719,595 +2612,619 @@ const Initializer = ({ disabled, name: name2, onClick }) => {
2719
2612
  }
2720
2613
  ) });
2721
2614
  };
2722
- const NonRepeatableComponent = ({
2723
- attribute,
2724
- name: name2,
2615
+ const AddComponentButton = ({
2616
+ hasError,
2617
+ isDisabled,
2618
+ isOpen,
2725
2619
  children,
2726
- layout
2620
+ onClick
2621
+ }) => {
2622
+ return /* @__PURE__ */ jsx(
2623
+ StyledButton,
2624
+ {
2625
+ type: "button",
2626
+ onClick,
2627
+ disabled: isDisabled,
2628
+ background: "neutral0",
2629
+ style: { cursor: isDisabled ? "not-allowed" : "pointer" },
2630
+ variant: "tertiary",
2631
+ children: /* @__PURE__ */ jsxs(Flex, { tag: "span", gap: 2, children: [
2632
+ /* @__PURE__ */ jsx(StyledAddIcon, { "aria-hidden": true, $isOpen: isOpen, $hasError: hasError && !isOpen }),
2633
+ /* @__PURE__ */ jsx(
2634
+ Typography,
2635
+ {
2636
+ variant: "pi",
2637
+ fontWeight: "bold",
2638
+ textColor: hasError && !isOpen ? "danger600" : "neutral600",
2639
+ children
2640
+ }
2641
+ )
2642
+ ] })
2643
+ }
2644
+ );
2645
+ };
2646
+ const StyledAddIcon = styled(PlusCircle)`
2647
+ height: ${({ theme }) => theme.spaces[6]};
2648
+ width: ${({ theme }) => theme.spaces[6]};
2649
+ transform: ${({ $isOpen }) => $isOpen ? "rotate(45deg)" : "rotate(0deg)"};
2650
+
2651
+ > circle {
2652
+ fill: ${({ theme, $hasError }) => $hasError ? theme.colors.danger200 : theme.colors.neutral150};
2653
+ }
2654
+ > path {
2655
+ fill: ${({ theme, $hasError }) => $hasError ? theme.colors.danger600 : theme.colors.neutral500};
2656
+ }
2657
+ `;
2658
+ const StyledButton = styled(Button)`
2659
+ padding-left: ${({ theme }) => theme.spaces[3]};
2660
+ border-radius: 26px;
2661
+ box-shadow: ${({ theme }) => theme.shadows.filterShadow};
2662
+ height: 5rem;
2663
+ `;
2664
+ const ComponentCategory = ({
2665
+ category,
2666
+ components = [],
2667
+ variant = "primary",
2668
+ onAddComponent
2727
2669
  }) => {
2728
2670
  const { formatMessage } = useIntl();
2729
- const { value } = useField(name2);
2730
- const level = useComponent("NonRepeatableComponent", (state) => state.level);
2731
- const isNested = level > 0;
2732
- return /* @__PURE__ */ jsx(ComponentProvider, { id: value?.id, uid: attribute.component, level: level + 1, type: "component", children: /* @__PURE__ */ jsx(
2671
+ return /* @__PURE__ */ jsxs(Accordion.Item, { value: category, children: [
2672
+ /* @__PURE__ */ jsx(Accordion.Header, { variant, children: /* @__PURE__ */ jsx(Accordion.Trigger, { children: formatMessage({ id: category, defaultMessage: category }) }) }),
2673
+ /* @__PURE__ */ jsx(ResponsiveAccordionContent, { children: /* @__PURE__ */ jsx(Grid, { paddingTop: 4, paddingBottom: 4, paddingLeft: 3, paddingRight: 3, children: components.map(({ uid, displayName, icon }) => /* @__PURE__ */ jsx(
2674
+ ComponentBox,
2675
+ {
2676
+ tag: "button",
2677
+ type: "button",
2678
+ background: "neutral100",
2679
+ justifyContent: "center",
2680
+ onClick: onAddComponent(uid),
2681
+ hasRadius: true,
2682
+ height: "8.4rem",
2683
+ shrink: 0,
2684
+ borderColor: "neutral200",
2685
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, alignItems: "center", justifyContent: "center", children: [
2686
+ /* @__PURE__ */ jsx(ComponentIcon, { color: "currentColor", background: "primary200", icon }),
2687
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: displayName })
2688
+ ] })
2689
+ },
2690
+ uid
2691
+ )) }) })
2692
+ ] });
2693
+ };
2694
+ const ResponsiveAccordionContent = styled(Accordion.Content)`
2695
+ container-type: inline-size;
2696
+ `;
2697
+ const Grid = styled(Box)`
2698
+ display: grid;
2699
+ grid-template-columns: repeat(auto-fill, 100%);
2700
+ grid-gap: ${({ theme }) => theme.spaces[1]};
2701
+
2702
+ @container (min-width: ${() => RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
2703
+ grid-template-columns: repeat(auto-fill, 14rem);
2704
+ }
2705
+ `;
2706
+ const ComponentBox = styled(Flex)`
2707
+ color: ${({ theme }) => theme.colors.neutral600};
2708
+ cursor: pointer;
2709
+
2710
+ @media (prefers-reduced-motion: no-preference) {
2711
+ transition: color 120ms ${(props) => props.theme.motion.easings.easeOutQuad};
2712
+ }
2713
+
2714
+ &:focus,
2715
+ &:hover {
2716
+ border: 1px solid ${({ theme }) => theme.colors.primary200};
2717
+ background: ${({ theme }) => theme.colors.primary100};
2718
+ color: ${({ theme }) => theme.colors.primary600};
2719
+ }
2720
+ `;
2721
+ const ComponentPicker = ({
2722
+ dynamicComponentsByCategory = {},
2723
+ isOpen,
2724
+ onClickAddComponent
2725
+ }) => {
2726
+ const { formatMessage } = useIntl();
2727
+ const handleAddComponentToDz = (componentUid) => () => {
2728
+ onClickAddComponent(componentUid);
2729
+ };
2730
+ if (!isOpen) {
2731
+ return null;
2732
+ }
2733
+ return /* @__PURE__ */ jsxs(
2733
2734
  Box,
2734
2735
  {
2735
- background: "neutral100",
2736
- paddingLeft: 6,
2737
- paddingRight: 6,
2738
2736
  paddingTop: 6,
2739
2737
  paddingBottom: 6,
2740
- hasRadius: isNested,
2741
- borderColor: isNested ? "neutral200" : void 0,
2742
- children: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: layout.map((row, index) => {
2743
- return /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: row.map(({ size, ...field }) => {
2744
- const completeFieldName = `${name2}.${field.name}`;
2745
- const translatedLabel = formatMessage({
2746
- id: `content-manager.components.${attribute.component}.${field.name}`,
2747
- defaultMessage: field.label
2748
- });
2749
- return /* @__PURE__ */ jsx(
2750
- Grid$1.Item,
2751
- {
2752
- col: size,
2753
- s: 12,
2754
- xs: 12,
2755
- direction: "column",
2756
- alignItems: "stretch",
2757
- children: children({ ...field, label: translatedLabel, name: completeFieldName })
2758
- },
2759
- completeFieldName
2760
- );
2761
- }) }, index);
2762
- }) })
2738
+ paddingLeft: 5,
2739
+ paddingRight: 5,
2740
+ background: "neutral0",
2741
+ shadow: "tableShadow",
2742
+ borderColor: "neutral150",
2743
+ hasRadius: true,
2744
+ children: [
2745
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral600", children: formatMessage({
2746
+ id: getTranslation("components.DynamicZone.ComponentPicker-label"),
2747
+ defaultMessage: "Pick one component"
2748
+ }) }) }),
2749
+ /* @__PURE__ */ jsx(Box, { paddingTop: 2, children: /* @__PURE__ */ jsx(Accordion.Root, { defaultValue: Object.keys(dynamicComponentsByCategory)[0], children: Object.entries(dynamicComponentsByCategory).map(([category, components], index) => /* @__PURE__ */ jsx(
2750
+ ComponentCategory,
2751
+ {
2752
+ category,
2753
+ components,
2754
+ onAddComponent: handleAddComponentToDz,
2755
+ variant: index % 2 === 1 ? "primary" : "secondary"
2756
+ },
2757
+ category
2758
+ )) }) })
2759
+ ]
2763
2760
  }
2764
- ) });
2761
+ );
2765
2762
  };
2766
- const RepeatableComponent = ({
2767
- attribute,
2763
+ const DynamicComponent = ({
2764
+ componentUid,
2768
2765
  disabled,
2766
+ index,
2769
2767
  name: name2,
2770
- mainField,
2771
- children,
2772
- layout
2768
+ onRemoveComponentClick,
2769
+ onMoveComponent,
2770
+ onGrabItem,
2771
+ onDropItem,
2772
+ onCancel,
2773
+ dynamicComponentsByCategory = {},
2774
+ onAddComponent,
2775
+ children
2773
2776
  }) => {
2774
- const { toggleNotification } = useNotification();
2775
2777
  const { formatMessage } = useIntl();
2776
- const { search: searchString } = useLocation();
2777
- const search = React.useMemo(() => new URLSearchParams(searchString), [searchString]);
2778
- const { components } = useDoc();
2778
+ const formValues = useForm("DynamicComponent", (state) => state.values);
2779
2779
  const {
2780
- value = [],
2781
- error,
2782
- rawError
2783
- } = useField(name2);
2784
- const addFieldRow = useForm("RepeatableComponent", (state) => state.addFieldRow);
2785
- const moveFieldRow = useForm("RepeatableComponent", (state) => state.moveFieldRow);
2786
- const removeFieldRow = useForm("RepeatableComponent", (state) => state.removeFieldRow);
2787
- const { max = Infinity } = attribute;
2788
- const [collapseToOpen, setCollapseToOpen] = React.useState("");
2789
- const [liveText, setLiveText] = React.useState("");
2790
- React.useEffect(() => {
2791
- const hasNestedErrors = rawError && Array.isArray(rawError) && rawError.length > 0;
2792
- const hasNestedValue = value && Array.isArray(value) && value.length > 0;
2793
- if (hasNestedErrors && hasNestedValue) {
2794
- const errorOpenItems = rawError.map((_, idx) => {
2795
- return value[idx] ? value[idx].__temp_key__ : null;
2796
- }).filter((value2) => !!value2);
2797
- if (errorOpenItems && errorOpenItems.length > 0) {
2798
- setCollapseToOpen((collapseToOpen2) => {
2799
- if (!errorOpenItems.includes(collapseToOpen2)) {
2800
- return errorOpenItems[0];
2801
- }
2802
- return collapseToOpen2;
2803
- });
2804
- }
2805
- }
2806
- }, [rawError, value]);
2807
- const componentTmpKeyWithFocussedField = React.useMemo(() => {
2808
- if (search.has("field")) {
2809
- const fieldParam = search.get("field");
2810
- if (!fieldParam) {
2811
- return void 0;
2812
- }
2813
- const [, path] = fieldParam.split(`${name2}.`);
2814
- if (getIn(value, path, void 0) !== void 0) {
2815
- const [subpath] = path.split(".");
2816
- return getIn(value, subpath, void 0)?.__temp_key__;
2817
- }
2818
- }
2819
- return void 0;
2820
- }, [search, name2, value]);
2821
- const prevValue = usePrev(value);
2822
- React.useEffect(() => {
2823
- if (prevValue && prevValue.length < value.length) {
2824
- setCollapseToOpen(value[value.length - 1].__temp_key__);
2825
- }
2826
- }, [value, prevValue]);
2827
- React.useEffect(() => {
2828
- if (typeof componentTmpKeyWithFocussedField === "string") {
2829
- setCollapseToOpen(componentTmpKeyWithFocussedField);
2830
- }
2831
- }, [componentTmpKeyWithFocussedField]);
2832
- const toggleCollapses = () => {
2833
- setCollapseToOpen("");
2834
- };
2835
- const handleClick = () => {
2836
- if (value.length < max) {
2837
- const schema = components[attribute.component];
2838
- const form = createDefaultForm(schema, components);
2839
- const data = transformDocument(schema, components)(form);
2840
- addFieldRow(name2, data);
2841
- } else if (value.length >= max) {
2842
- toggleNotification({
2843
- type: "info",
2844
- message: formatMessage({
2845
- id: getTranslation("components.notification.info.maximum-requirement")
2846
- })
2847
- });
2848
- }
2849
- };
2850
- const handleMoveComponentField = (newIndex, currentIndex) => {
2851
- setLiveText(
2852
- formatMessage(
2853
- {
2854
- id: getTranslation("dnd.reorder"),
2855
- defaultMessage: "{item}, moved. New position in list: {position}."
2856
- },
2857
- {
2858
- item: `${name2}.${currentIndex}`,
2859
- position: getItemPos(newIndex)
2860
- }
2861
- )
2862
- );
2863
- moveFieldRow(name2, currentIndex, newIndex);
2864
- };
2865
- const handleValueChange = (key) => {
2866
- setCollapseToOpen(key);
2867
- };
2868
- const getItemPos = (index) => `${index + 1} of ${value.length}`;
2869
- const handleCancel = (index) => {
2870
- setLiveText(
2871
- formatMessage(
2872
- {
2873
- id: getTranslation("dnd.cancel-item"),
2874
- defaultMessage: "{item}, dropped. Re-order cancelled."
2875
- },
2876
- {
2877
- item: `${name2}.${index}`
2878
- }
2879
- )
2880
- );
2881
- };
2882
- const handleGrabItem = (index) => {
2883
- setLiveText(
2884
- formatMessage(
2885
- {
2886
- id: getTranslation("dnd.grab-item"),
2887
- defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
2888
- },
2889
- {
2890
- item: `${name2}.${index}`,
2891
- position: getItemPos(index)
2892
- }
2893
- )
2894
- );
2895
- };
2896
- const handleDropItem = (index) => {
2897
- setLiveText(
2898
- formatMessage(
2899
- {
2900
- id: getTranslation("dnd.drop-item"),
2901
- defaultMessage: `{item}, dropped. Final position in list: {position}.`
2902
- },
2903
- {
2904
- item: `${name2}.${index}`,
2905
- position: getItemPos(index)
2906
- }
2907
- )
2908
- );
2909
- };
2910
- const ariaDescriptionId = React.useId();
2911
- const level = useComponent("RepeatableComponent", (state) => state.level);
2912
- if (value.length === 0) {
2913
- return /* @__PURE__ */ jsx(Initializer, { disabled, name: name2, onClick: handleClick });
2914
- }
2915
- return /* @__PURE__ */ jsxs(Box, { hasRadius: true, children: [
2916
- /* @__PURE__ */ jsx(VisuallyHidden, { id: ariaDescriptionId, children: formatMessage({
2917
- id: getTranslation("dnd.instructions"),
2918
- defaultMessage: `Press spacebar to grab and re-order`
2919
- }) }),
2920
- /* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "assertive", children: liveText }),
2921
- /* @__PURE__ */ jsxs(
2922
- AccordionRoot,
2923
- {
2924
- $error: error,
2925
- value: collapseToOpen,
2926
- onValueChange: handleValueChange,
2927
- "aria-describedby": ariaDescriptionId,
2928
- children: [
2929
- value.map(({ __temp_key__: key, id }, index) => {
2930
- const nameWithIndex = `${name2}.${index}`;
2931
- return /* @__PURE__ */ jsx(
2932
- ComponentProvider,
2933
- {
2934
- id,
2935
- uid: attribute.component,
2936
- level: level + 1,
2937
- type: "repeatable",
2938
- children: /* @__PURE__ */ jsx(
2939
- Component,
2940
- {
2941
- disabled,
2942
- name: nameWithIndex,
2943
- attribute,
2944
- index,
2945
- mainField,
2946
- onMoveItem: handleMoveComponentField,
2947
- onDeleteComponent: () => {
2948
- removeFieldRow(name2, index);
2949
- toggleCollapses();
2950
- },
2951
- toggleCollapses,
2952
- onCancel: handleCancel,
2953
- onDropItem: handleDropItem,
2954
- onGrabItem: handleGrabItem,
2955
- __temp_key__: key,
2956
- children: layout.map((row, index2) => {
2957
- return /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: row.map(({ size, ...field }) => {
2958
- const completeFieldName = `${nameWithIndex}.${field.name}`;
2959
- const translatedLabel = formatMessage({
2960
- id: `content-manager.components.${attribute.component}.${field.name}`,
2961
- defaultMessage: field.label
2962
- });
2963
- return /* @__PURE__ */ jsx(
2964
- Grid$1.Item,
2965
- {
2966
- col: size,
2967
- s: 12,
2968
- xs: 12,
2969
- direction: "column",
2970
- alignItems: "stretch",
2971
- children: children({
2972
- ...field,
2973
- label: translatedLabel,
2974
- name: completeFieldName
2975
- })
2976
- },
2977
- completeFieldName
2978
- );
2979
- }) }, index2);
2980
- })
2981
- }
2982
- )
2983
- },
2984
- key
2985
- );
2986
- }),
2987
- /* @__PURE__ */ jsx(TextButtonCustom, { disabled, onClick: handleClick, startIcon: /* @__PURE__ */ jsx(Plus, {}), children: formatMessage({
2988
- id: getTranslation("containers.EditView.add.new-entry"),
2989
- defaultMessage: "Add an entry"
2990
- }) })
2991
- ]
2992
- }
2993
- )
2994
- ] });
2995
- };
2996
- const AccordionRoot = styled(Accordion.Root)`
2997
- border: 1px solid
2998
- ${({ theme, $error }) => $error ? theme.colors.danger600 : theme.colors.neutral200};
2999
- `;
3000
- const TextButtonCustom = styled(TextButton)`
3001
- width: 100%;
3002
- display: flex;
3003
- justify-content: center;
3004
- border-top: 1px solid ${({ theme }) => theme.colors.neutral200};
3005
- padding-inline: ${(props) => props.theme.spaces[6]};
3006
- padding-block: ${(props) => props.theme.spaces[3]};
3007
-
3008
- &:not([disabled]) {
3009
- cursor: pointer;
3010
-
3011
- &:hover {
3012
- background-color: ${(props) => props.theme.colors.primary100};
3013
- }
3014
- }
3015
-
3016
- span {
3017
- font-weight: 600;
3018
- font-size: 1.4rem;
3019
- line-height: 2.4rem;
3020
- }
3021
-
3022
- @media (prefers-reduced-motion: no-preference) {
3023
- transition: background-color 120ms ${(props) => props.theme.motion.easings.easeOutQuad};
3024
- }
3025
- `;
3026
- const Component = ({
3027
- disabled,
3028
- index,
3029
- name: name2,
3030
- mainField = {
3031
- name: "id",
3032
- type: "integer"
3033
- },
3034
- children,
3035
- onDeleteComponent,
3036
- toggleCollapses,
3037
- __temp_key__,
3038
- ...dragProps
3039
- }) => {
3040
- const { formatMessage } = useIntl();
3041
- const displayValue = useForm("RepeatableComponent", (state) => {
3042
- return getIn(state.values, [...name2.split("."), mainField.name]);
3043
- });
3044
- const accordionRef = React.useRef(null);
3045
- const componentKey = name2.split(".").slice(0, -1).join(".");
2780
+ edit: { components }
2781
+ } = useDocLayout();
2782
+ const title = React.useMemo(() => {
2783
+ const { mainField } = components[componentUid]?.settings ?? { mainField: "id" };
2784
+ const mainFieldValue = getIn(formValues, `${name2}.${index}.${mainField}`);
2785
+ const displayedValue = mainField === "id" || !mainFieldValue ? "" : String(mainFieldValue).trim();
2786
+ const mainValue = displayedValue.length > 0 ? `- ${displayedValue}` : displayedValue;
2787
+ return mainValue;
2788
+ }, [componentUid, components, formValues, name2, index]);
2789
+ const { icon, displayName } = React.useMemo(() => {
2790
+ const [category] = componentUid.split(".");
2791
+ const { icon: icon2, displayName: displayName2 } = (dynamicComponentsByCategory[category] ?? []).find(
2792
+ (component) => component.uid === componentUid
2793
+ ) ?? { icon: null, displayName: null };
2794
+ return { icon: icon2, displayName: displayName2 };
2795
+ }, [componentUid, dynamicComponentsByCategory]);
3046
2796
  const [{ handlerId, isDragging, handleKeyDown }, boxRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(!disabled, {
3047
- type: `${ItemTypes.COMPONENT}_${componentKey}`,
2797
+ type: `${ItemTypes.DYNAMIC_ZONE}_${name2}`,
3048
2798
  index,
3049
2799
  item: {
3050
2800
  index,
3051
- displayedValue: displayValue
3052
- },
3053
- onStart() {
3054
- toggleCollapses();
2801
+ displayedValue: `${displayName} ${title}`,
2802
+ icon
3055
2803
  },
3056
- ...dragProps
2804
+ onMoveItem: onMoveComponent,
2805
+ onDropItem,
2806
+ onGrabItem,
2807
+ onCancel
3057
2808
  });
3058
2809
  React.useEffect(() => {
3059
2810
  dragPreviewRef(getEmptyImage(), { captureDraggingState: false });
3060
2811
  }, [dragPreviewRef, index]);
3061
- const composedAccordionRefs = useComposedRefs(accordionRef, dragRef);
3062
- const composedBoxRefs = useComposedRefs(
3063
- boxRef,
3064
- dropRef
3065
- );
3066
- return /* @__PURE__ */ jsx(Fragment, { children: isDragging ? /* @__PURE__ */ jsx(Preview$1, {}) : /* @__PURE__ */ jsxs(Accordion.Item, { ref: composedBoxRefs, value: __temp_key__, children: [
3067
- /* @__PURE__ */ jsxs(Accordion.Header, { children: [
3068
- /* @__PURE__ */ jsx(Accordion.Trigger, { children: displayValue }),
3069
- /* @__PURE__ */ jsxs(Accordion.Actions, { children: [
3070
- /* @__PURE__ */ jsx(
3071
- IconButton,
2812
+ const accordionValue = React.useId();
2813
+ const { value = [], rawError } = useField(`${name2}.${index}`);
2814
+ const [collapseToOpen, setCollapseToOpen] = React.useState("");
2815
+ React.useEffect(() => {
2816
+ if (rawError && value) {
2817
+ setCollapseToOpen(accordionValue);
2818
+ }
2819
+ }, [rawError, value, accordionValue]);
2820
+ const composedBoxRefs = useComposedRefs(boxRef, dropRef);
2821
+ const accordionActions = disabled ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
2822
+ /* @__PURE__ */ jsx(
2823
+ IconButton,
2824
+ {
2825
+ variant: "ghost",
2826
+ label: formatMessage(
3072
2827
  {
3073
- variant: "ghost",
3074
- onClick: onDeleteComponent,
3075
- label: formatMessage({
3076
- id: getTranslation("containers.Edit.delete"),
3077
- defaultMessage: "Delete"
3078
- }),
3079
- children: /* @__PURE__ */ jsx(Trash, {})
3080
- }
2828
+ id: getTranslation("components.DynamicZone.delete-label"),
2829
+ defaultMessage: "Delete {name}"
2830
+ },
2831
+ { name: title }
3081
2832
  ),
2833
+ onClick: onRemoveComponentClick,
2834
+ children: /* @__PURE__ */ jsx(Trash, {})
2835
+ }
2836
+ ),
2837
+ /* @__PURE__ */ jsx(
2838
+ IconButton,
2839
+ {
2840
+ variant: "ghost",
2841
+ onClick: (e) => e.stopPropagation(),
2842
+ "data-handler-id": handlerId,
2843
+ ref: dragRef,
2844
+ label: formatMessage({
2845
+ id: getTranslation("components.DragHandle-label"),
2846
+ defaultMessage: "Drag"
2847
+ }),
2848
+ onKeyDown: handleKeyDown,
2849
+ children: /* @__PURE__ */ jsx(Drag, {})
2850
+ }
2851
+ ),
2852
+ /* @__PURE__ */ jsxs(Menu.Root, { children: [
2853
+ /* @__PURE__ */ jsx(Menu.Trigger, { size: "S", endIcon: null, paddingLeft: 0, paddingRight: 0, children: /* @__PURE__ */ jsx(
2854
+ IconButton,
2855
+ {
2856
+ variant: "ghost",
2857
+ label: formatMessage({
2858
+ id: getTranslation("components.DynamicZone.more-actions"),
2859
+ defaultMessage: "More actions"
2860
+ }),
2861
+ tag: "span",
2862
+ children: /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false })
2863
+ }
2864
+ ) }),
2865
+ /* @__PURE__ */ jsxs(Menu.Content, { children: [
2866
+ /* @__PURE__ */ jsxs(Menu.SubRoot, { children: [
2867
+ /* @__PURE__ */ jsx(Menu.SubTrigger, { children: formatMessage({
2868
+ id: getTranslation("components.DynamicZone.add-item-above"),
2869
+ defaultMessage: "Add component above"
2870
+ }) }),
2871
+ /* @__PURE__ */ jsx(Menu.SubContent, { children: Object.entries(dynamicComponentsByCategory).map(([category, components2]) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
2872
+ /* @__PURE__ */ jsx(Menu.Label, { children: category }),
2873
+ components2.map(({ displayName: displayName2, uid }) => /* @__PURE__ */ jsx(MenuItem, { onSelect: () => onAddComponent(uid, index), children: displayName2 }, componentUid))
2874
+ ] }, category)) })
2875
+ ] }),
2876
+ /* @__PURE__ */ jsxs(Menu.SubRoot, { children: [
2877
+ /* @__PURE__ */ jsx(Menu.SubTrigger, { children: formatMessage({
2878
+ id: getTranslation("components.DynamicZone.add-item-below"),
2879
+ defaultMessage: "Add component below"
2880
+ }) }),
2881
+ /* @__PURE__ */ jsx(Menu.SubContent, { children: Object.entries(dynamicComponentsByCategory).map(([category, components2]) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
2882
+ /* @__PURE__ */ jsx(Menu.Label, { children: category }),
2883
+ components2.map(({ displayName: displayName2, uid }) => /* @__PURE__ */ jsx(MenuItem, { onSelect: () => onAddComponent(uid, index + 1), children: displayName2 }, componentUid))
2884
+ ] }, category)) })
2885
+ ] })
2886
+ ] })
2887
+ ] })
2888
+ ] });
2889
+ const accordionTitle = title ? `${displayName} ${title}` : displayName;
2890
+ return /* @__PURE__ */ jsxs(ComponentContainer, { tag: "li", width: "100%", children: [
2891
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Rectangle, { background: "neutral200" }) }),
2892
+ /* @__PURE__ */ jsx(StyledBox, { ref: composedBoxRefs, hasRadius: true, children: isDragging ? /* @__PURE__ */ jsx(Preview$1, {}) : /* @__PURE__ */ jsx(Accordion.Root, { value: collapseToOpen, onValueChange: setCollapseToOpen, children: /* @__PURE__ */ jsxs(Accordion.Item, { value: accordionValue, children: [
2893
+ /* @__PURE__ */ jsxs(Accordion.Header, { children: [
3082
2894
  /* @__PURE__ */ jsx(
3083
- IconButton,
2895
+ Accordion.Trigger,
3084
2896
  {
3085
- ref: composedAccordionRefs,
3086
- variant: "ghost",
3087
- onClick: (e) => e.stopPropagation(),
3088
- "data-handler-id": handlerId,
3089
- label: formatMessage({
3090
- id: getTranslation("components.DragHandle-label"),
3091
- defaultMessage: "Drag"
3092
- }),
3093
- onKeyDown: handleKeyDown,
3094
- children: /* @__PURE__ */ jsx(Drag, {})
2897
+ icon: icon && COMPONENT_ICONS[icon] ? COMPONENT_ICONS[icon] : COMPONENT_ICONS.dashboard,
2898
+ children: accordionTitle
3095
2899
  }
3096
- )
3097
- ] })
3098
- ] }),
3099
- /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(
3100
- Flex,
3101
- {
3102
- direction: "column",
3103
- alignItems: "stretch",
3104
- background: "neutral100",
3105
- padding: 6,
3106
- gap: 6,
3107
- children
3108
- }
3109
- ) })
3110
- ] }) });
3111
- };
3112
- const Preview$1 = () => {
3113
- return /* @__PURE__ */ jsx(StyledSpan, { tag: "span", padding: 6, background: "primary100" });
2900
+ ),
2901
+ /* @__PURE__ */ jsx(Accordion.Actions, { children: accordionActions })
2902
+ ] }),
2903
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(AccordionContentRadius, { background: "neutral0", children: /* @__PURE__ */ jsx(Box, { paddingLeft: 6, paddingRight: 6, paddingTop: 6, paddingBottom: 6, children: /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: components[componentUid]?.layout?.map((row, rowInd) => /* @__PURE__ */ jsx(
2904
+ Grid$1.Item,
2905
+ {
2906
+ col: 12,
2907
+ s: 12,
2908
+ xs: 12,
2909
+ direction: "column",
2910
+ alignItems: "stretch",
2911
+ children: /* @__PURE__ */ jsx(ResponsiveGridRoot, { gap: 4, children: row.map(({ size, ...field }) => {
2912
+ const fieldName = `${name2}.${index}.${field.name}`;
2913
+ const fieldWithTranslatedLabel = {
2914
+ ...field,
2915
+ label: formatMessage({
2916
+ id: `content-manager.components.${componentUid}.${field.name}`,
2917
+ defaultMessage: field.label
2918
+ })
2919
+ };
2920
+ return /* @__PURE__ */ jsx(
2921
+ ResponsiveGridItem,
2922
+ {
2923
+ col: size,
2924
+ s: 12,
2925
+ xs: 12,
2926
+ direction: "column",
2927
+ alignItems: "stretch",
2928
+ children: children ? children({ ...fieldWithTranslatedLabel, name: fieldName }) : /* @__PURE__ */ jsx(MemoizedInputRenderer, { ...fieldWithTranslatedLabel, name: fieldName })
2929
+ },
2930
+ fieldName
2931
+ );
2932
+ }) })
2933
+ },
2934
+ rowInd
2935
+ )) }) }) }) })
2936
+ ] }) }) })
2937
+ ] });
3114
2938
  };
3115
- const StyledSpan = styled(Box)`
2939
+ const StyledBox = styled(Box)`
2940
+ > div:first-child {
2941
+ box-shadow: ${({ theme }) => theme.shadows.tableShadow};
2942
+ }
2943
+ `;
2944
+ const AccordionContentRadius = styled(Box)`
2945
+ border-radius: 0 0 ${({ theme }) => theme.spaces[1]} ${({ theme }) => theme.spaces[1]};
2946
+ `;
2947
+ const Rectangle = styled(Box)`
2948
+ width: ${({ theme }) => theme.spaces[2]};
2949
+ height: ${({ theme }) => theme.spaces[4]};
2950
+ `;
2951
+ const Preview$1 = styled.span`
3116
2952
  display: block;
2953
+ background-color: ${({ theme }) => theme.colors.primary100};
3117
2954
  outline: 1px dashed ${({ theme }) => theme.colors.primary500};
3118
2955
  outline-offset: -1px;
2956
+ padding: ${({ theme }) => theme.spaces[6]};
2957
+ `;
2958
+ const ComponentContainer = styled(Box)`
2959
+ list-style: none;
2960
+ padding: 0;
2961
+ margin: 0;
3119
2962
  `;
3120
- const ComponentInput = ({
2963
+ const DynamicZoneLabel = ({
2964
+ hint,
3121
2965
  label,
3122
- required,
3123
- name: name2,
3124
- attribute,
3125
- disabled,
3126
2966
  labelAction,
3127
- ...props
3128
- }) => {
3129
- const { formatMessage } = useIntl();
3130
- const field = useField(name2);
3131
- const showResetComponent = !attribute.repeatable && field.value && !disabled;
3132
- const { components } = useDoc();
3133
- const handleInitialisationClick = () => {
3134
- const schema = components[attribute.component];
3135
- const form = createDefaultForm(schema, components);
3136
- const data = transformDocument(schema, components)(form);
3137
- field.onChange(name2, data);
3138
- };
3139
- return /* @__PURE__ */ jsxs(Field.Root, { error: field.error, required, children: [
3140
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3141
- /* @__PURE__ */ jsxs(Field.Label, { action: labelAction, children: [
3142
- label,
3143
- attribute.repeatable && /* @__PURE__ */ jsxs(Fragment, { children: [
3144
- " (",
3145
- Array.isArray(field.value) ? field.value.length : 0,
3146
- ")"
3147
- ] })
3148
- ] }),
3149
- showResetComponent && /* @__PURE__ */ jsx(
3150
- IconButton,
3151
- {
3152
- label: formatMessage({
3153
- id: getTranslation("components.reset-entry"),
3154
- defaultMessage: "Reset Entry"
3155
- }),
3156
- variant: "ghost",
3157
- onClick: () => {
3158
- field.onChange(name2, null);
3159
- },
3160
- children: /* @__PURE__ */ jsx(Trash, {})
3161
- }
3162
- )
3163
- ] }),
3164
- !attribute.repeatable && !field.value && /* @__PURE__ */ jsx(Initializer, { disabled, name: name2, onClick: handleInitialisationClick }),
3165
- !attribute.repeatable && field.value ? /* @__PURE__ */ jsx(NonRepeatableComponent, { attribute, name: name2, disabled, ...props, children: props.children }) : null,
3166
- attribute.repeatable && /* @__PURE__ */ jsx(RepeatableComponent, { attribute, name: name2, disabled, ...props, children: props.children }),
3167
- /* @__PURE__ */ jsx(Field.Error, {})
3168
- ] });
3169
- };
3170
- const MemoizedComponentInput = React.memo(ComponentInput);
3171
- const AddComponentButton = ({
3172
- hasError,
3173
- isDisabled,
3174
- isOpen,
3175
- children,
3176
- onClick
2967
+ name: name2,
2968
+ numberOfComponents = 0,
2969
+ required
3177
2970
  }) => {
3178
- return /* @__PURE__ */ jsx(
3179
- StyledButton,
2971
+ return /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(
2972
+ Box,
3180
2973
  {
3181
- type: "button",
3182
- onClick,
3183
- disabled: isDisabled,
2974
+ paddingTop: 3,
2975
+ paddingBottom: 3,
2976
+ paddingRight: 4,
2977
+ paddingLeft: 4,
2978
+ borderRadius: "26px",
3184
2979
  background: "neutral0",
3185
- style: { cursor: isDisabled ? "not-allowed" : "pointer" },
3186
- variant: "tertiary",
3187
- children: /* @__PURE__ */ jsxs(Flex, { tag: "span", gap: 2, children: [
3188
- /* @__PURE__ */ jsx(StyledAddIcon, { "aria-hidden": true, $isOpen: isOpen, $hasError: hasError && !isOpen }),
3189
- /* @__PURE__ */ jsx(
3190
- Typography,
3191
- {
3192
- variant: "pi",
3193
- fontWeight: "bold",
3194
- textColor: hasError && !isOpen ? "danger600" : "neutral600",
3195
- children
3196
- }
3197
- )
2980
+ shadow: "filterShadow",
2981
+ color: "neutral500",
2982
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", justifyContent: "center", children: [
2983
+ /* @__PURE__ */ jsxs(Flex, { maxWidth: "35.6rem", children: [
2984
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", fontWeight: "bold", ellipsis: true, children: [
2985
+ label || name2,
2986
+ " "
2987
+ ] }),
2988
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", fontWeight: "bold", children: [
2989
+ "(",
2990
+ numberOfComponents,
2991
+ ")"
2992
+ ] }),
2993
+ required && /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: "*" }),
2994
+ labelAction && /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: labelAction })
2995
+ ] }),
2996
+ hint && /* @__PURE__ */ jsx(Box, { paddingTop: 1, maxWidth: "35.6rem", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", ellipsis: true, children: hint }) })
3198
2997
  ] })
3199
2998
  }
3200
- );
2999
+ ) });
3201
3000
  };
3202
- const StyledAddIcon = styled(PlusCircle)`
3203
- height: ${({ theme }) => theme.spaces[6]};
3204
- width: ${({ theme }) => theme.spaces[6]};
3205
- transform: ${({ $isOpen }) => $isOpen ? "rotate(45deg)" : "rotate(0deg)"};
3206
-
3207
- > circle {
3208
- fill: ${({ theme, $hasError }) => $hasError ? theme.colors.danger200 : theme.colors.neutral150};
3209
- }
3210
- > path {
3211
- fill: ${({ theme, $hasError }) => $hasError ? theme.colors.danger600 : theme.colors.neutral500};
3001
+ const [DynamicZoneProvider, useDynamicZone] = createContext(
3002
+ "DynamicZone",
3003
+ {
3004
+ isInDynamicZone: false
3212
3005
  }
3213
- `;
3214
- const StyledButton = styled(Button)`
3215
- padding-left: ${({ theme }) => theme.spaces[3]};
3216
- border-radius: 26px;
3217
- box-shadow: ${({ theme }) => theme.shadows.filterShadow};
3218
- height: 5rem;
3219
- `;
3220
- const ComponentCategory = ({
3221
- category,
3222
- components = [],
3223
- variant = "primary",
3224
- onAddComponent
3006
+ );
3007
+ const DynamicZone = ({
3008
+ attribute,
3009
+ disabled: disabledProp,
3010
+ hint,
3011
+ label,
3012
+ labelAction,
3013
+ name: name2,
3014
+ required = false,
3015
+ children
3225
3016
  }) => {
3017
+ const { max = Infinity, min = -Infinity } = attribute ?? {};
3018
+ const [addComponentIsOpen, setAddComponentIsOpen] = React.useState(false);
3019
+ const [liveText, setLiveText] = React.useState("");
3020
+ const { components, isLoading } = useDoc();
3021
+ const disabled = disabledProp || isLoading;
3022
+ const { addFieldRow, removeFieldRow, moveFieldRow } = useForm(
3023
+ "DynamicZone",
3024
+ ({ addFieldRow: addFieldRow2, removeFieldRow: removeFieldRow2, moveFieldRow: moveFieldRow2 }) => ({
3025
+ addFieldRow: addFieldRow2,
3026
+ removeFieldRow: removeFieldRow2,
3027
+ moveFieldRow: moveFieldRow2
3028
+ })
3029
+ );
3030
+ const { value = [], error } = useField(name2);
3031
+ const dynamicComponentsByCategory = React.useMemo(() => {
3032
+ return attribute.components.reduce((acc, componentUid) => {
3033
+ const { category, info } = components[componentUid] ?? { info: {} };
3034
+ const component = { uid: componentUid, displayName: info.displayName, icon: info.icon };
3035
+ if (!acc[category]) {
3036
+ acc[category] = [];
3037
+ }
3038
+ acc[category] = [...acc[category], component];
3039
+ return acc;
3040
+ }, {});
3041
+ }, [attribute.components, components]);
3226
3042
  const { formatMessage } = useIntl();
3227
- return /* @__PURE__ */ jsxs(Accordion.Item, { value: category, children: [
3228
- /* @__PURE__ */ jsx(Accordion.Header, { variant, children: /* @__PURE__ */ jsx(Accordion.Trigger, { children: formatMessage({ id: category, defaultMessage: category }) }) }),
3229
- /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(Grid, { paddingTop: 4, paddingBottom: 4, paddingLeft: 3, paddingRight: 3, children: components.map(({ uid, displayName, icon }) => /* @__PURE__ */ jsx(
3230
- ComponentBox,
3043
+ const { toggleNotification } = useNotification();
3044
+ const dynamicDisplayedComponentsLength = value.length;
3045
+ const handleAddComponent = (uid, position) => {
3046
+ setAddComponentIsOpen(false);
3047
+ const schema = components[uid];
3048
+ const form = createDefaultForm(schema, components);
3049
+ const transformations = pipe$1(transformDocument(schema, components), (data2) => ({
3050
+ ...data2,
3051
+ __component: uid
3052
+ }));
3053
+ const data = transformations(form);
3054
+ addFieldRow(name2, data, position);
3055
+ };
3056
+ const handleClickOpenPicker = () => {
3057
+ if (dynamicDisplayedComponentsLength < max) {
3058
+ setAddComponentIsOpen((prev) => !prev);
3059
+ } else {
3060
+ toggleNotification({
3061
+ type: "info",
3062
+ message: formatMessage({
3063
+ id: getTranslation("components.notification.info.maximum-requirement")
3064
+ })
3065
+ });
3066
+ }
3067
+ };
3068
+ const handleMoveComponent = (newIndex, currentIndex) => {
3069
+ setLiveText(
3070
+ formatMessage(
3071
+ {
3072
+ id: getTranslation("dnd.reorder"),
3073
+ defaultMessage: "{item}, moved. New position in list: {position}."
3074
+ },
3075
+ {
3076
+ item: `${name2}.${currentIndex}`,
3077
+ position: getItemPos(newIndex)
3078
+ }
3079
+ )
3080
+ );
3081
+ moveFieldRow(name2, currentIndex, newIndex);
3082
+ };
3083
+ const getItemPos = (index) => `${index + 1} of ${value.length}`;
3084
+ const handleCancel = (index) => {
3085
+ setLiveText(
3086
+ formatMessage(
3087
+ {
3088
+ id: getTranslation("dnd.cancel-item"),
3089
+ defaultMessage: "{item}, dropped. Re-order cancelled."
3090
+ },
3091
+ {
3092
+ item: `${name2}.${index}`
3093
+ }
3094
+ )
3095
+ );
3096
+ };
3097
+ const handleGrabItem = (index) => {
3098
+ setLiveText(
3099
+ formatMessage(
3100
+ {
3101
+ id: getTranslation("dnd.grab-item"),
3102
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
3103
+ },
3104
+ {
3105
+ item: `${name2}.${index}`,
3106
+ position: getItemPos(index)
3107
+ }
3108
+ )
3109
+ );
3110
+ };
3111
+ const handleDropItem = (index) => {
3112
+ setLiveText(
3113
+ formatMessage(
3114
+ {
3115
+ id: getTranslation("dnd.drop-item"),
3116
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`
3117
+ },
3118
+ {
3119
+ item: `${name2}.${index}`,
3120
+ position: getItemPos(index)
3121
+ }
3122
+ )
3123
+ );
3124
+ };
3125
+ const handleRemoveComponent = (name22, currentIndex) => () => {
3126
+ removeFieldRow(name22, currentIndex);
3127
+ };
3128
+ const hasError = error !== void 0;
3129
+ const renderButtonLabel = () => {
3130
+ if (addComponentIsOpen) {
3131
+ return formatMessage({ id: "app.utils.close-label", defaultMessage: "Close" });
3132
+ }
3133
+ if (hasError && dynamicDisplayedComponentsLength > max) {
3134
+ return formatMessage(
3135
+ {
3136
+ id: getTranslation(`components.DynamicZone.extra-components`),
3137
+ defaultMessage: "There {number, plural, =0 {are # extra components} one {is # extra component} other {are # extra components}}"
3138
+ },
3139
+ {
3140
+ number: dynamicDisplayedComponentsLength - max
3141
+ }
3142
+ );
3143
+ }
3144
+ if (hasError && dynamicDisplayedComponentsLength < min) {
3145
+ return formatMessage(
3146
+ {
3147
+ id: getTranslation(`components.DynamicZone.missing-components`),
3148
+ defaultMessage: "There {number, plural, =0 {are # missing components} one {is # missing component} other {are # missing components}}"
3149
+ },
3150
+ { number: min - dynamicDisplayedComponentsLength }
3151
+ );
3152
+ }
3153
+ return formatMessage(
3231
3154
  {
3232
- tag: "button",
3233
- type: "button",
3234
- background: "neutral100",
3235
- justifyContent: "center",
3236
- onClick: onAddComponent(uid),
3237
- hasRadius: true,
3238
- height: "8.4rem",
3239
- shrink: 0,
3240
- borderColor: "neutral200",
3241
- children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, alignItems: "center", justifyContent: "center", children: [
3242
- /* @__PURE__ */ jsx(ComponentIcon, { color: "currentColor", background: "primary200", icon }),
3243
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: displayName })
3244
- ] })
3155
+ id: getTranslation("components.DynamicZone.add-component"),
3156
+ defaultMessage: "Add a component to {componentName}"
3245
3157
  },
3246
- uid
3247
- )) }) })
3248
- ] });
3249
- };
3250
- const Grid = styled(Box)`
3251
- display: grid;
3252
- grid-template-columns: repeat(auto-fit, 14rem);
3253
- grid-gap: ${({ theme }) => theme.spaces[1]};
3254
- `;
3255
- const ComponentBox = styled(Flex)`
3256
- color: ${({ theme }) => theme.colors.neutral600};
3257
- cursor: pointer;
3258
-
3259
- @media (prefers-reduced-motion: no-preference) {
3260
- transition: color 120ms ${(props) => props.theme.motion.easings.easeOutQuad};
3261
- }
3262
-
3263
- &:focus,
3264
- &:hover {
3265
- border: 1px solid ${({ theme }) => theme.colors.primary200};
3266
- background: ${({ theme }) => theme.colors.primary100};
3267
- color: ${({ theme }) => theme.colors.primary600};
3268
- }
3269
- `;
3270
- const ComponentPicker = ({
3271
- dynamicComponentsByCategory = {},
3272
- isOpen,
3273
- onClickAddComponent
3274
- }) => {
3275
- const { formatMessage } = useIntl();
3276
- const handleAddComponentToDz = (componentUid) => () => {
3277
- onClickAddComponent(componentUid);
3158
+ { componentName: label || name2 }
3159
+ );
3278
3160
  };
3279
- if (!isOpen) {
3280
- return null;
3281
- }
3282
- return /* @__PURE__ */ jsxs(
3283
- Box,
3284
- {
3285
- paddingTop: 6,
3286
- paddingBottom: 6,
3287
- paddingLeft: 5,
3288
- paddingRight: 5,
3289
- background: "neutral0",
3290
- shadow: "tableShadow",
3291
- borderColor: "neutral150",
3292
- hasRadius: true,
3293
- children: [
3294
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral600", children: formatMessage({
3295
- id: getTranslation("components.DynamicZone.ComponentPicker-label"),
3296
- defaultMessage: "Pick one component"
3297
- }) }) }),
3298
- /* @__PURE__ */ jsx(Box, { paddingTop: 2, children: /* @__PURE__ */ jsx(Accordion.Root, { defaultValue: Object.keys(dynamicComponentsByCategory)[0], children: Object.entries(dynamicComponentsByCategory).map(([category, components], index) => /* @__PURE__ */ jsx(
3299
- ComponentCategory,
3300
- {
3301
- category,
3302
- components,
3303
- onAddComponent: handleAddComponentToDz,
3304
- variant: index % 2 === 1 ? "primary" : "secondary"
3305
- },
3306
- category
3307
- )) }) })
3308
- ]
3309
- }
3310
- );
3161
+ const level = useComponent("DynamicZone", (state) => state.level);
3162
+ const ariaDescriptionId = React.useId();
3163
+ return /* @__PURE__ */ jsx(DynamicZoneProvider, { isInDynamicZone: true, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
3164
+ dynamicDisplayedComponentsLength > 0 && /* @__PURE__ */ jsxs(Box, { children: [
3165
+ /* @__PURE__ */ jsx(
3166
+ DynamicZoneLabel,
3167
+ {
3168
+ hint,
3169
+ label,
3170
+ labelAction,
3171
+ name: name2,
3172
+ numberOfComponents: dynamicDisplayedComponentsLength,
3173
+ required
3174
+ }
3175
+ ),
3176
+ /* @__PURE__ */ jsx(VisuallyHidden, { id: ariaDescriptionId, children: formatMessage({
3177
+ id: getTranslation("dnd.instructions"),
3178
+ defaultMessage: `Press spacebar to grab and re-order`
3179
+ }) }),
3180
+ /* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "assertive", children: liveText }),
3181
+ /* @__PURE__ */ jsx("ol", { "aria-describedby": ariaDescriptionId, children: value.map((field, index) => /* @__PURE__ */ jsx(
3182
+ ComponentProvider,
3183
+ {
3184
+ level: level + 1,
3185
+ uid: field.__component,
3186
+ id: field.id,
3187
+ type: "dynamiczone",
3188
+ children: /* @__PURE__ */ jsx(
3189
+ DynamicComponent,
3190
+ {
3191
+ disabled,
3192
+ name: name2,
3193
+ index,
3194
+ componentUid: field.__component,
3195
+ onMoveComponent: handleMoveComponent,
3196
+ onRemoveComponentClick: handleRemoveComponent(name2, index),
3197
+ onCancel: handleCancel,
3198
+ onDropItem: handleDropItem,
3199
+ onGrabItem: handleGrabItem,
3200
+ onAddComponent: handleAddComponent,
3201
+ dynamicComponentsByCategory,
3202
+ children
3203
+ }
3204
+ )
3205
+ },
3206
+ field.__temp_key__
3207
+ )) })
3208
+ ] }),
3209
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(
3210
+ AddComponentButton,
3211
+ {
3212
+ hasError,
3213
+ isDisabled: disabled,
3214
+ isOpen: addComponentIsOpen,
3215
+ onClick: handleClickOpenPicker,
3216
+ children: renderButtonLabel()
3217
+ }
3218
+ ) }),
3219
+ /* @__PURE__ */ jsx(
3220
+ ComponentPicker,
3221
+ {
3222
+ dynamicComponentsByCategory,
3223
+ isOpen: addComponentIsOpen,
3224
+ onClickAddComponent: handleAddComponent
3225
+ }
3226
+ )
3227
+ ] }) });
3311
3228
  };
3312
3229
  const NotAllowedInput = ({ hint, label, required, name: name2 }) => {
3313
3230
  const { formatMessage } = useIntl();
@@ -5002,617 +4919,668 @@ const InputRenderer = ({ visible, hint: providedHint, ...props }) => {
5002
4919
  if (collectionType === SINGLE_TYPES) {
5003
4920
  idToCheck = document2?.documentId;
5004
4921
  }
5005
- const editableFields = idToCheck ? canUpdateFields : canCreateFields;
5006
- const readableFields = idToCheck ? canReadFields : canCreateFields;
5007
- const canUserReadField = canUserAction(props.name, readableFields, props.type);
5008
- const canUserEditField = canUserAction(props.name, editableFields, props.type);
5009
- const fields = useStrapiApp("InputRenderer", (app) => app.fields);
5010
- const { lazyComponentStore } = useLazyComponents(
5011
- attributeHasCustomFieldProperty(props.attribute) ? [props.attribute.customField] : void 0
4922
+ const editableFields = idToCheck ? canUpdateFields : canCreateFields;
4923
+ const readableFields = idToCheck ? canReadFields : canCreateFields;
4924
+ const canUserReadField = canUserAction(props.name, readableFields, props.type);
4925
+ const canUserEditField = canUserAction(props.name, editableFields, props.type);
4926
+ const fields = useStrapiApp("InputRenderer", (app) => app.fields);
4927
+ const { lazyComponentStore } = useLazyComponents(
4928
+ attributeHasCustomFieldProperty(props.attribute) ? [props.attribute.customField] : void 0
4929
+ );
4930
+ const hint = useFieldHint(providedHint, props.attribute);
4931
+ const {
4932
+ edit: { components }
4933
+ } = useDocLayout();
4934
+ const field = useField(props.name);
4935
+ if (!visible) {
4936
+ return null;
4937
+ }
4938
+ if (!canUserReadField && !isInDynamicZone) {
4939
+ return /* @__PURE__ */ jsx(NotAllowedInput, { hint, ...props });
4940
+ }
4941
+ const fieldIsDisabled = !canUserEditField && !isInDynamicZone || props.disabled || isFormDisabled;
4942
+ if (attributeHasCustomFieldProperty(props.attribute)) {
4943
+ const CustomInput = lazyComponentStore[props.attribute.customField];
4944
+ if (CustomInput) {
4945
+ return /* @__PURE__ */ jsx(CustomInput, { ...props, ...field, hint, disabled: fieldIsDisabled });
4946
+ }
4947
+ return /* @__PURE__ */ jsx(
4948
+ InputRenderer$1,
4949
+ {
4950
+ ...props,
4951
+ hint,
4952
+ type: props.attribute.customField,
4953
+ disabled: fieldIsDisabled
4954
+ }
4955
+ );
4956
+ }
4957
+ const addedInputTypes = Object.keys(fields);
4958
+ if (!attributeHasCustomFieldProperty(props.attribute) && addedInputTypes.includes(props.type)) {
4959
+ const CustomInput = fields[props.type];
4960
+ return /* @__PURE__ */ jsx(CustomInput, { ...props, hint, disabled: fieldIsDisabled });
4961
+ }
4962
+ switch (props.type) {
4963
+ case "blocks":
4964
+ return /* @__PURE__ */ jsx(MemoizedBlocksInput, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
4965
+ case "component":
4966
+ return /* @__PURE__ */ jsx(
4967
+ MemoizedComponentInput,
4968
+ {
4969
+ ...props,
4970
+ hint,
4971
+ layout: components[props.attribute.component].layout,
4972
+ disabled: fieldIsDisabled,
4973
+ children: (inputProps) => /* @__PURE__ */ jsx(InputRenderer, { ...inputProps })
4974
+ }
4975
+ );
4976
+ case "dynamiczone":
4977
+ return /* @__PURE__ */ jsx(DynamicZone, { ...props, hint, disabled: fieldIsDisabled });
4978
+ case "relation":
4979
+ return /* @__PURE__ */ jsx(MemoizedRelationsField, { ...props, hint, disabled: fieldIsDisabled });
4980
+ case "richtext":
4981
+ return /* @__PURE__ */ jsx(MemoizedWysiwyg, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
4982
+ case "uid":
4983
+ return /* @__PURE__ */ jsx(MemoizedUIDInput, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
4984
+ case "enumeration":
4985
+ return /* @__PURE__ */ jsx(
4986
+ InputRenderer$1,
4987
+ {
4988
+ ...props,
4989
+ hint,
4990
+ options: props.attribute.enum.map((value) => ({ value })),
4991
+ type: props.customField ? "custom-field" : props.type,
4992
+ disabled: fieldIsDisabled
4993
+ }
4994
+ );
4995
+ default:
4996
+ const { unique: _unique, mainField: _mainField, ...restProps } = props;
4997
+ return /* @__PURE__ */ jsx(
4998
+ InputRenderer$1,
4999
+ {
5000
+ ...restProps,
5001
+ hint,
5002
+ type: props.customField ? "custom-field" : props.type,
5003
+ disabled: fieldIsDisabled
5004
+ }
5005
+ );
5006
+ }
5007
+ };
5008
+ const attributeHasCustomFieldProperty = (attribute) => "customField" in attribute && typeof attribute.customField === "string";
5009
+ const useFieldHint = (hint = void 0, attribute) => {
5010
+ const { formatMessage } = useIntl();
5011
+ const { maximum, minimum } = getMinMax(attribute);
5012
+ if (!maximum && !minimum) {
5013
+ return hint;
5014
+ }
5015
+ const units = !["biginteger", "integer", "number", "dynamiczone", "component"].includes(
5016
+ attribute.type
5017
+ ) ? formatMessage(
5018
+ {
5019
+ id: "content-manager.form.Input.hint.character.unit",
5020
+ defaultMessage: "{maxValue, plural, one { character} other { characters}}"
5021
+ },
5022
+ {
5023
+ maxValue: Math.max(minimum || 0, maximum || 0)
5024
+ }
5025
+ ) : null;
5026
+ const hasMinAndMax = typeof minimum === "number" && typeof maximum === "number";
5027
+ return formatMessage(
5028
+ {
5029
+ id: "content-manager.form.Input.hint.text",
5030
+ defaultMessage: "{min, select, undefined {} other {min. {min}}}{divider}{max, select, undefined {} other {max. {max}}}{unit}{br}{description}"
5031
+ },
5032
+ {
5033
+ min: minimum,
5034
+ max: maximum,
5035
+ description: hint,
5036
+ unit: units,
5037
+ divider: hasMinAndMax ? formatMessage({
5038
+ id: "content-manager.form.Input.hint.minMaxDivider",
5039
+ defaultMessage: " / "
5040
+ }) : null,
5041
+ br: /* @__PURE__ */ jsx("br", {})
5042
+ }
5012
5043
  );
5013
- const hint = useFieldHint(providedHint, props.attribute);
5014
- const {
5015
- edit: { components }
5016
- } = useDocLayout();
5017
- const field = useField(props.name);
5018
- if (!visible) {
5019
- return null;
5044
+ };
5045
+ const getMinMax = (attribute) => {
5046
+ if ("min" in attribute || "max" in attribute) {
5047
+ return {
5048
+ maximum: !Number.isNaN(Number(attribute.max)) ? Number(attribute.max) : void 0,
5049
+ minimum: !Number.isNaN(Number(attribute.min)) ? Number(attribute.min) : void 0
5050
+ };
5051
+ } else if ("maxLength" in attribute || "minLength" in attribute) {
5052
+ return { maximum: attribute.maxLength, minimum: attribute.minLength };
5053
+ } else {
5054
+ return { maximum: void 0, minimum: void 0 };
5020
5055
  }
5021
- if (!canUserReadField && !isInDynamicZone) {
5022
- return /* @__PURE__ */ jsx(NotAllowedInput, { hint, ...props });
5056
+ };
5057
+ const MemoizedInputRenderer = memo(InputRenderer);
5058
+ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
5059
+ sm: "27.5rem"
5060
+ // 440px
5061
+ };
5062
+ const ResponsiveGridRoot = styled(Grid$1.Root)`
5063
+ container-type: inline-size;
5064
+ `;
5065
+ const ResponsiveGridItem = styled(Grid$1.Item)`
5066
+ grid-column: span 12;
5067
+
5068
+ @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
5069
+ ${({ col }) => col && `grid-column: span ${col};`}
5023
5070
  }
5024
- const fieldIsDisabled = !canUserEditField && !isInDynamicZone || props.disabled || isFormDisabled;
5025
- if (attributeHasCustomFieldProperty(props.attribute)) {
5026
- const CustomInput = lazyComponentStore[props.attribute.customField];
5027
- if (CustomInput) {
5028
- return /* @__PURE__ */ jsx(CustomInput, { ...props, ...field, hint, disabled: fieldIsDisabled });
5071
+ `;
5072
+ const FormLayout = ({ layout }) => {
5073
+ const { formatMessage } = useIntl();
5074
+ const { model } = useDoc();
5075
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: layout.map((panel, index) => {
5076
+ if (panel.some((row) => row.some((field) => field.type === "dynamiczone"))) {
5077
+ const [row] = panel;
5078
+ const [field] = row;
5079
+ const fieldWithTranslatedLabel = {
5080
+ ...field,
5081
+ label: formatMessage({
5082
+ id: `content-manager.content-types.${model}.${field.name}`,
5083
+ defaultMessage: field.label
5084
+ })
5085
+ };
5086
+ return /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: /* @__PURE__ */ jsx(Grid$1.Item, { col: 12, s: 12, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(MemoizedInputRenderer, { ...fieldWithTranslatedLabel }) }) }, field.name);
5029
5087
  }
5030
5088
  return /* @__PURE__ */ jsx(
5031
- InputRenderer$1,
5089
+ Box,
5032
5090
  {
5033
- ...props,
5034
- hint,
5035
- type: props.attribute.customField,
5036
- disabled: fieldIsDisabled
5091
+ hasRadius: true,
5092
+ background: "neutral0",
5093
+ shadow: "tableShadow",
5094
+ paddingLeft: 6,
5095
+ paddingRight: 6,
5096
+ paddingTop: 6,
5097
+ paddingBottom: 6,
5098
+ borderColor: "neutral150",
5099
+ children: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: panel.map((row, gridRowIndex) => /* @__PURE__ */ jsx(ResponsiveGridRoot, { gap: 4, children: row.map(({ size, ...field }) => {
5100
+ const fieldWithTranslatedLabel = {
5101
+ ...field,
5102
+ label: formatMessage({
5103
+ id: `content-manager.content-types.${model}.${field.name}`,
5104
+ defaultMessage: field.label
5105
+ })
5106
+ };
5107
+ return /* @__PURE__ */ jsx(
5108
+ ResponsiveGridItem,
5109
+ {
5110
+ col: size,
5111
+ s: 12,
5112
+ xs: 12,
5113
+ direction: "column",
5114
+ alignItems: "stretch",
5115
+ children: /* @__PURE__ */ jsx(MemoizedInputRenderer, { ...fieldWithTranslatedLabel })
5116
+ },
5117
+ field.name
5118
+ );
5119
+ }) }, gridRowIndex)) })
5120
+ },
5121
+ index
5122
+ );
5123
+ }) });
5124
+ };
5125
+ const NonRepeatableComponent = ({
5126
+ attribute,
5127
+ name: name2,
5128
+ children,
5129
+ layout
5130
+ }) => {
5131
+ const { formatMessage } = useIntl();
5132
+ const { value } = useField(name2);
5133
+ const level = useComponent("NonRepeatableComponent", (state) => state.level);
5134
+ const isNested = level > 0;
5135
+ return /* @__PURE__ */ jsx(ComponentProvider, { id: value?.id, uid: attribute.component, level: level + 1, type: "component", children: /* @__PURE__ */ jsx(
5136
+ Box,
5137
+ {
5138
+ background: "neutral100",
5139
+ paddingLeft: 6,
5140
+ paddingRight: 6,
5141
+ paddingTop: 6,
5142
+ paddingBottom: 6,
5143
+ hasRadius: isNested,
5144
+ borderColor: isNested ? "neutral200" : void 0,
5145
+ children: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: layout.map((row, index) => {
5146
+ return /* @__PURE__ */ jsx(ResponsiveGridRoot, { gap: 4, children: row.map(({ size, ...field }) => {
5147
+ const completeFieldName = `${name2}.${field.name}`;
5148
+ const translatedLabel = formatMessage({
5149
+ id: `content-manager.components.${attribute.component}.${field.name}`,
5150
+ defaultMessage: field.label
5151
+ });
5152
+ return /* @__PURE__ */ jsx(
5153
+ ResponsiveGridItem,
5154
+ {
5155
+ col: size,
5156
+ s: 12,
5157
+ xs: 12,
5158
+ direction: "column",
5159
+ alignItems: "stretch",
5160
+ children: children({ ...field, label: translatedLabel, name: completeFieldName })
5161
+ },
5162
+ completeFieldName
5163
+ );
5164
+ }) }, index);
5165
+ }) })
5166
+ }
5167
+ ) });
5168
+ };
5169
+ const RepeatableComponent = ({
5170
+ attribute,
5171
+ disabled,
5172
+ name: name2,
5173
+ mainField,
5174
+ children,
5175
+ layout
5176
+ }) => {
5177
+ const { toggleNotification } = useNotification();
5178
+ const { formatMessage } = useIntl();
5179
+ const { search: searchString } = useLocation();
5180
+ const search = React.useMemo(() => new URLSearchParams(searchString), [searchString]);
5181
+ const { components } = useDoc();
5182
+ const {
5183
+ value = [],
5184
+ error,
5185
+ rawError
5186
+ } = useField(name2);
5187
+ const addFieldRow = useForm("RepeatableComponent", (state) => state.addFieldRow);
5188
+ const moveFieldRow = useForm("RepeatableComponent", (state) => state.moveFieldRow);
5189
+ const removeFieldRow = useForm("RepeatableComponent", (state) => state.removeFieldRow);
5190
+ const { max = Infinity } = attribute;
5191
+ const [collapseToOpen, setCollapseToOpen] = React.useState("");
5192
+ const [liveText, setLiveText] = React.useState("");
5193
+ React.useEffect(() => {
5194
+ const hasNestedErrors = rawError && Array.isArray(rawError) && rawError.length > 0;
5195
+ const hasNestedValue = value && Array.isArray(value) && value.length > 0;
5196
+ if (hasNestedErrors && hasNestedValue) {
5197
+ const errorOpenItems = rawError.map((_, idx) => {
5198
+ return value[idx] ? value[idx].__temp_key__ : null;
5199
+ }).filter((value2) => !!value2);
5200
+ if (errorOpenItems && errorOpenItems.length > 0) {
5201
+ setCollapseToOpen((collapseToOpen2) => {
5202
+ if (!errorOpenItems.includes(collapseToOpen2)) {
5203
+ return errorOpenItems[0];
5204
+ }
5205
+ return collapseToOpen2;
5206
+ });
5207
+ }
5208
+ }
5209
+ }, [rawError, value]);
5210
+ const componentTmpKeyWithFocussedField = React.useMemo(() => {
5211
+ if (search.has("field")) {
5212
+ const fieldParam = search.get("field");
5213
+ if (!fieldParam) {
5214
+ return void 0;
5215
+ }
5216
+ const [, path] = fieldParam.split(`${name2}.`);
5217
+ if (getIn(value, path, void 0) !== void 0) {
5218
+ const [subpath] = path.split(".");
5219
+ return getIn(value, subpath, void 0)?.__temp_key__;
5037
5220
  }
5221
+ }
5222
+ return void 0;
5223
+ }, [search, name2, value]);
5224
+ const prevValue = usePrev(value);
5225
+ React.useEffect(() => {
5226
+ if (prevValue && prevValue.length < value.length) {
5227
+ setCollapseToOpen(value[value.length - 1].__temp_key__);
5228
+ }
5229
+ }, [value, prevValue]);
5230
+ React.useEffect(() => {
5231
+ if (typeof componentTmpKeyWithFocussedField === "string") {
5232
+ setCollapseToOpen(componentTmpKeyWithFocussedField);
5233
+ }
5234
+ }, [componentTmpKeyWithFocussedField]);
5235
+ const toggleCollapses = () => {
5236
+ setCollapseToOpen("");
5237
+ };
5238
+ const handleClick = () => {
5239
+ if (value.length < max) {
5240
+ const schema = components[attribute.component];
5241
+ const form = createDefaultForm(schema, components);
5242
+ const data = transformDocument(schema, components)(form);
5243
+ addFieldRow(name2, data);
5244
+ } else if (value.length >= max) {
5245
+ toggleNotification({
5246
+ type: "info",
5247
+ message: formatMessage({
5248
+ id: getTranslation("components.notification.info.maximum-requirement")
5249
+ })
5250
+ });
5251
+ }
5252
+ };
5253
+ const handleMoveComponentField = (newIndex, currentIndex) => {
5254
+ setLiveText(
5255
+ formatMessage(
5256
+ {
5257
+ id: getTranslation("dnd.reorder"),
5258
+ defaultMessage: "{item}, moved. New position in list: {position}."
5259
+ },
5260
+ {
5261
+ item: `${name2}.${currentIndex}`,
5262
+ position: getItemPos(newIndex)
5263
+ }
5264
+ )
5038
5265
  );
5039
- }
5040
- const addedInputTypes = Object.keys(fields);
5041
- if (!attributeHasCustomFieldProperty(props.attribute) && addedInputTypes.includes(props.type)) {
5042
- const CustomInput = fields[props.type];
5043
- return /* @__PURE__ */ jsx(CustomInput, { ...props, hint, disabled: fieldIsDisabled });
5044
- }
5045
- switch (props.type) {
5046
- case "blocks":
5047
- return /* @__PURE__ */ jsx(MemoizedBlocksInput, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
5048
- case "component":
5049
- return /* @__PURE__ */ jsx(
5050
- MemoizedComponentInput,
5266
+ moveFieldRow(name2, currentIndex, newIndex);
5267
+ };
5268
+ const handleValueChange = (key) => {
5269
+ setCollapseToOpen(key);
5270
+ };
5271
+ const getItemPos = (index) => `${index + 1} of ${value.length}`;
5272
+ const handleCancel = (index) => {
5273
+ setLiveText(
5274
+ formatMessage(
5051
5275
  {
5052
- ...props,
5053
- hint,
5054
- layout: components[props.attribute.component].layout,
5055
- disabled: fieldIsDisabled,
5056
- children: (inputProps) => /* @__PURE__ */ jsx(InputRenderer, { ...inputProps })
5276
+ id: getTranslation("dnd.cancel-item"),
5277
+ defaultMessage: "{item}, dropped. Re-order cancelled."
5278
+ },
5279
+ {
5280
+ item: `${name2}.${index}`
5057
5281
  }
5058
- );
5059
- case "dynamiczone":
5060
- return /* @__PURE__ */ jsx(DynamicZone, { ...props, hint, disabled: fieldIsDisabled });
5061
- case "relation":
5062
- return /* @__PURE__ */ jsx(MemoizedRelationsField, { ...props, hint, disabled: fieldIsDisabled });
5063
- case "richtext":
5064
- return /* @__PURE__ */ jsx(MemoizedWysiwyg, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
5065
- case "uid":
5066
- return /* @__PURE__ */ jsx(MemoizedUIDInput, { ...props, hint, type: props.type, disabled: fieldIsDisabled });
5067
- case "enumeration":
5068
- return /* @__PURE__ */ jsx(
5069
- InputRenderer$1,
5282
+ )
5283
+ );
5284
+ };
5285
+ const handleGrabItem = (index) => {
5286
+ setLiveText(
5287
+ formatMessage(
5070
5288
  {
5071
- ...props,
5072
- hint,
5073
- options: props.attribute.enum.map((value) => ({ value })),
5074
- type: props.customField ? "custom-field" : props.type,
5075
- disabled: fieldIsDisabled
5289
+ id: getTranslation("dnd.grab-item"),
5290
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5291
+ },
5292
+ {
5293
+ item: `${name2}.${index}`,
5294
+ position: getItemPos(index)
5076
5295
  }
5077
- );
5078
- default:
5079
- const { unique: _unique, mainField: _mainField, ...restProps } = props;
5080
- return /* @__PURE__ */ jsx(
5081
- InputRenderer$1,
5296
+ )
5297
+ );
5298
+ };
5299
+ const handleDropItem = (index) => {
5300
+ setLiveText(
5301
+ formatMessage(
5082
5302
  {
5083
- ...restProps,
5084
- hint,
5085
- type: props.customField ? "custom-field" : props.type,
5086
- disabled: fieldIsDisabled
5303
+ id: getTranslation("dnd.drop-item"),
5304
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`
5305
+ },
5306
+ {
5307
+ item: `${name2}.${index}`,
5308
+ position: getItemPos(index)
5087
5309
  }
5088
- );
5310
+ )
5311
+ );
5312
+ };
5313
+ const ariaDescriptionId = React.useId();
5314
+ const level = useComponent("RepeatableComponent", (state) => state.level);
5315
+ if (value.length === 0) {
5316
+ return /* @__PURE__ */ jsx(Initializer, { disabled, name: name2, onClick: handleClick });
5089
5317
  }
5318
+ return /* @__PURE__ */ jsxs(Box, { hasRadius: true, children: [
5319
+ /* @__PURE__ */ jsx(VisuallyHidden, { id: ariaDescriptionId, children: formatMessage({
5320
+ id: getTranslation("dnd.instructions"),
5321
+ defaultMessage: `Press spacebar to grab and re-order`
5322
+ }) }),
5323
+ /* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "assertive", children: liveText }),
5324
+ /* @__PURE__ */ jsxs(
5325
+ AccordionRoot,
5326
+ {
5327
+ $error: error,
5328
+ value: collapseToOpen,
5329
+ onValueChange: handleValueChange,
5330
+ "aria-describedby": ariaDescriptionId,
5331
+ children: [
5332
+ value.map(({ __temp_key__: key, id }, index) => {
5333
+ const nameWithIndex = `${name2}.${index}`;
5334
+ return /* @__PURE__ */ jsx(
5335
+ ComponentProvider,
5336
+ {
5337
+ id,
5338
+ uid: attribute.component,
5339
+ level: level + 1,
5340
+ type: "repeatable",
5341
+ children: /* @__PURE__ */ jsx(
5342
+ Component,
5343
+ {
5344
+ disabled,
5345
+ name: nameWithIndex,
5346
+ attribute,
5347
+ index,
5348
+ mainField,
5349
+ onMoveItem: handleMoveComponentField,
5350
+ onDeleteComponent: () => {
5351
+ removeFieldRow(name2, index);
5352
+ toggleCollapses();
5353
+ },
5354
+ toggleCollapses,
5355
+ onCancel: handleCancel,
5356
+ onDropItem: handleDropItem,
5357
+ onGrabItem: handleGrabItem,
5358
+ __temp_key__: key,
5359
+ children: layout.map((row, index2) => {
5360
+ return /* @__PURE__ */ jsx(ResponsiveGridRoot, { gap: 4, children: row.map(({ size, ...field }) => {
5361
+ const completeFieldName = `${nameWithIndex}.${field.name}`;
5362
+ const translatedLabel = formatMessage({
5363
+ id: `content-manager.components.${attribute.component}.${field.name}`,
5364
+ defaultMessage: field.label
5365
+ });
5366
+ return /* @__PURE__ */ jsx(
5367
+ ResponsiveGridItem,
5368
+ {
5369
+ col: size,
5370
+ s: 12,
5371
+ xs: 12,
5372
+ direction: "column",
5373
+ alignItems: "stretch",
5374
+ children: children({
5375
+ ...field,
5376
+ label: translatedLabel,
5377
+ name: completeFieldName
5378
+ })
5379
+ },
5380
+ completeFieldName
5381
+ );
5382
+ }) }, index2);
5383
+ })
5384
+ }
5385
+ )
5386
+ },
5387
+ key
5388
+ );
5389
+ }),
5390
+ /* @__PURE__ */ jsx(TextButtonCustom, { disabled, onClick: handleClick, startIcon: /* @__PURE__ */ jsx(Plus, {}), children: formatMessage({
5391
+ id: getTranslation("containers.EditView.add.new-entry"),
5392
+ defaultMessage: "Add an entry"
5393
+ }) })
5394
+ ]
5395
+ }
5396
+ )
5397
+ ] });
5090
5398
  };
5091
- const attributeHasCustomFieldProperty = (attribute) => "customField" in attribute && typeof attribute.customField === "string";
5092
- const useFieldHint = (hint = void 0, attribute) => {
5093
- const { formatMessage } = useIntl();
5094
- const { maximum, minimum } = getMinMax(attribute);
5095
- if (!maximum && !minimum) {
5096
- return hint;
5097
- }
5098
- const units = !["biginteger", "integer", "number", "dynamiczone", "component"].includes(
5099
- attribute.type
5100
- ) ? formatMessage(
5101
- {
5102
- id: "content-manager.form.Input.hint.character.unit",
5103
- defaultMessage: "{maxValue, plural, one { character} other { characters}}"
5104
- },
5105
- {
5106
- maxValue: Math.max(minimum || 0, maximum || 0)
5107
- }
5108
- ) : null;
5109
- const hasMinAndMax = typeof minimum === "number" && typeof maximum === "number";
5110
- return formatMessage(
5111
- {
5112
- id: "content-manager.form.Input.hint.text",
5113
- defaultMessage: "{min, select, undefined {} other {min. {min}}}{divider}{max, select, undefined {} other {max. {max}}}{unit}{br}{description}"
5114
- },
5115
- {
5116
- min: minimum,
5117
- max: maximum,
5118
- description: hint,
5119
- unit: units,
5120
- divider: hasMinAndMax ? formatMessage({
5121
- id: "content-manager.form.Input.hint.minMaxDivider",
5122
- defaultMessage: " / "
5123
- }) : null,
5124
- br: /* @__PURE__ */ jsx("br", {})
5399
+ const AccordionRoot = styled(Accordion.Root)`
5400
+ border: 1px solid
5401
+ ${({ theme, $error }) => $error ? theme.colors.danger600 : theme.colors.neutral200};
5402
+ `;
5403
+ const TextButtonCustom = styled(TextButton)`
5404
+ width: 100%;
5405
+ display: flex;
5406
+ justify-content: center;
5407
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral200};
5408
+ padding-inline: ${(props) => props.theme.spaces[6]};
5409
+ padding-block: ${(props) => props.theme.spaces[3]};
5410
+
5411
+ &:not([disabled]) {
5412
+ cursor: pointer;
5413
+
5414
+ &:hover {
5415
+ background-color: ${(props) => props.theme.colors.primary100};
5125
5416
  }
5126
- );
5127
- };
5128
- const getMinMax = (attribute) => {
5129
- if ("min" in attribute || "max" in attribute) {
5130
- return {
5131
- maximum: !Number.isNaN(Number(attribute.max)) ? Number(attribute.max) : void 0,
5132
- minimum: !Number.isNaN(Number(attribute.min)) ? Number(attribute.min) : void 0
5133
- };
5134
- } else if ("maxLength" in attribute || "minLength" in attribute) {
5135
- return { maximum: attribute.maxLength, minimum: attribute.minLength };
5136
- } else {
5137
- return { maximum: void 0, minimum: void 0 };
5138
5417
  }
5139
- };
5140
- const MemoizedInputRenderer = memo(InputRenderer);
5141
- const DynamicComponent = ({
5142
- componentUid,
5143
- disabled,
5144
- index,
5145
- name: name2,
5146
- onRemoveComponentClick,
5147
- onMoveComponent,
5148
- onGrabItem,
5149
- onDropItem,
5150
- onCancel,
5151
- dynamicComponentsByCategory = {},
5152
- onAddComponent,
5153
- children
5154
- }) => {
5155
- const { formatMessage } = useIntl();
5156
- const formValues = useForm("DynamicComponent", (state) => state.values);
5157
- const {
5158
- edit: { components }
5159
- } = useDocLayout();
5160
- const title = React.useMemo(() => {
5161
- const { mainField } = components[componentUid]?.settings ?? { mainField: "id" };
5162
- const mainFieldValue = getIn(formValues, `${name2}.${index}.${mainField}`);
5163
- const displayedValue = mainField === "id" || !mainFieldValue ? "" : String(mainFieldValue).trim();
5164
- const mainValue = displayedValue.length > 0 ? `- ${displayedValue}` : displayedValue;
5165
- return mainValue;
5166
- }, [componentUid, components, formValues, name2, index]);
5167
- const { icon, displayName } = React.useMemo(() => {
5168
- const [category] = componentUid.split(".");
5169
- const { icon: icon2, displayName: displayName2 } = (dynamicComponentsByCategory[category] ?? []).find(
5170
- (component) => component.uid === componentUid
5171
- ) ?? { icon: null, displayName: null };
5172
- return { icon: icon2, displayName: displayName2 };
5173
- }, [componentUid, dynamicComponentsByCategory]);
5418
+
5419
+ span {
5420
+ font-weight: 600;
5421
+ font-size: 1.4rem;
5422
+ line-height: 2.4rem;
5423
+ }
5424
+
5425
+ @media (prefers-reduced-motion: no-preference) {
5426
+ transition: background-color 120ms ${(props) => props.theme.motion.easings.easeOutQuad};
5427
+ }
5428
+ `;
5429
+ const Component = ({
5430
+ disabled,
5431
+ index,
5432
+ name: name2,
5433
+ mainField = {
5434
+ name: "id",
5435
+ type: "integer"
5436
+ },
5437
+ children,
5438
+ onDeleteComponent,
5439
+ toggleCollapses,
5440
+ __temp_key__,
5441
+ ...dragProps
5442
+ }) => {
5443
+ const { formatMessage } = useIntl();
5444
+ const displayValue = useForm("RepeatableComponent", (state) => {
5445
+ return getIn(state.values, [...name2.split("."), mainField.name]);
5446
+ });
5447
+ const accordionRef = React.useRef(null);
5448
+ const componentKey = name2.split(".").slice(0, -1).join(".");
5174
5449
  const [{ handlerId, isDragging, handleKeyDown }, boxRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(!disabled, {
5175
- type: `${ItemTypes.DYNAMIC_ZONE}_${name2}`,
5450
+ type: `${ItemTypes.COMPONENT}_${componentKey}`,
5176
5451
  index,
5177
5452
  item: {
5178
5453
  index,
5179
- displayedValue: `${displayName} ${title}`,
5180
- icon
5454
+ displayedValue: displayValue
5181
5455
  },
5182
- onMoveItem: onMoveComponent,
5183
- onDropItem,
5184
- onGrabItem,
5185
- onCancel
5456
+ onStart() {
5457
+ toggleCollapses();
5458
+ },
5459
+ ...dragProps
5186
5460
  });
5187
5461
  React.useEffect(() => {
5188
5462
  dragPreviewRef(getEmptyImage(), { captureDraggingState: false });
5189
5463
  }, [dragPreviewRef, index]);
5190
- const accordionValue = React.useId();
5191
- const { value = [], rawError } = useField(`${name2}.${index}`);
5192
- const [collapseToOpen, setCollapseToOpen] = React.useState("");
5193
- React.useEffect(() => {
5194
- if (rawError && value) {
5195
- setCollapseToOpen(accordionValue);
5196
- }
5197
- }, [rawError, value, accordionValue]);
5198
- const composedBoxRefs = useComposedRefs(boxRef, dropRef);
5199
- const accordionActions = disabled ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
5200
- /* @__PURE__ */ jsx(
5201
- IconButton,
5202
- {
5203
- variant: "ghost",
5204
- label: formatMessage(
5464
+ const composedAccordionRefs = useComposedRefs(accordionRef, dragRef);
5465
+ const composedBoxRefs = useComposedRefs(
5466
+ boxRef,
5467
+ dropRef
5468
+ );
5469
+ return /* @__PURE__ */ jsx(Fragment, { children: isDragging ? /* @__PURE__ */ jsx(Preview, {}) : /* @__PURE__ */ jsxs(Accordion.Item, { ref: composedBoxRefs, value: __temp_key__, children: [
5470
+ /* @__PURE__ */ jsxs(Accordion.Header, { children: [
5471
+ /* @__PURE__ */ jsx(Accordion.Trigger, { children: displayValue }),
5472
+ /* @__PURE__ */ jsxs(Accordion.Actions, { children: [
5473
+ /* @__PURE__ */ jsx(
5474
+ IconButton,
5205
5475
  {
5206
- id: getTranslation("components.DynamicZone.delete-label"),
5207
- defaultMessage: "Delete {name}"
5208
- },
5209
- { name: title }
5476
+ variant: "ghost",
5477
+ onClick: onDeleteComponent,
5478
+ label: formatMessage({
5479
+ id: getTranslation("containers.Edit.delete"),
5480
+ defaultMessage: "Delete"
5481
+ }),
5482
+ children: /* @__PURE__ */ jsx(Trash, {})
5483
+ }
5210
5484
  ),
5211
- onClick: onRemoveComponentClick,
5212
- children: /* @__PURE__ */ jsx(Trash, {})
5213
- }
5214
- ),
5215
- /* @__PURE__ */ jsx(
5216
- IconButton,
5217
- {
5218
- variant: "ghost",
5219
- onClick: (e) => e.stopPropagation(),
5220
- "data-handler-id": handlerId,
5221
- ref: dragRef,
5222
- label: formatMessage({
5223
- id: getTranslation("components.DragHandle-label"),
5224
- defaultMessage: "Drag"
5225
- }),
5226
- onKeyDown: handleKeyDown,
5227
- children: /* @__PURE__ */ jsx(Drag, {})
5228
- }
5229
- ),
5230
- /* @__PURE__ */ jsxs(Menu.Root, { children: [
5231
- /* @__PURE__ */ jsxs(Menu.Trigger, { size: "S", endIcon: null, paddingLeft: 2, paddingRight: 2, children: [
5232
- /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
5233
- /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: formatMessage({
5234
- id: getTranslation("components.DynamicZone.more-actions"),
5235
- defaultMessage: "More actions"
5236
- }) })
5237
- ] }),
5238
- /* @__PURE__ */ jsxs(Menu.Content, { children: [
5239
- /* @__PURE__ */ jsxs(Menu.SubRoot, { children: [
5240
- /* @__PURE__ */ jsx(Menu.SubTrigger, { children: formatMessage({
5241
- id: getTranslation("components.DynamicZone.add-item-above"),
5242
- defaultMessage: "Add component above"
5243
- }) }),
5244
- /* @__PURE__ */ jsx(Menu.SubContent, { children: Object.entries(dynamicComponentsByCategory).map(([category, components2]) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
5245
- /* @__PURE__ */ jsx(Menu.Label, { children: category }),
5246
- components2.map(({ displayName: displayName2, uid }) => /* @__PURE__ */ jsx(MenuItem, { onSelect: () => onAddComponent(uid, index), children: displayName2 }, componentUid))
5247
- ] }, category)) })
5248
- ] }),
5249
- /* @__PURE__ */ jsxs(Menu.SubRoot, { children: [
5250
- /* @__PURE__ */ jsx(Menu.SubTrigger, { children: formatMessage({
5251
- id: getTranslation("components.DynamicZone.add-item-below"),
5252
- defaultMessage: "Add component below"
5253
- }) }),
5254
- /* @__PURE__ */ jsx(Menu.SubContent, { children: Object.entries(dynamicComponentsByCategory).map(([category, components2]) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
5255
- /* @__PURE__ */ jsx(Menu.Label, { children: category }),
5256
- components2.map(({ displayName: displayName2, uid }) => /* @__PURE__ */ jsx(MenuItem, { onSelect: () => onAddComponent(uid, index + 1), children: displayName2 }, componentUid))
5257
- ] }, category)) })
5258
- ] })
5259
- ] })
5260
- ] })
5261
- ] });
5262
- const accordionTitle = title ? `${displayName} ${title}` : displayName;
5263
- return /* @__PURE__ */ jsxs(ComponentContainer, { tag: "li", width: "100%", children: [
5264
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Rectangle, { background: "neutral200" }) }),
5265
- /* @__PURE__ */ jsx(StyledBox, { ref: composedBoxRefs, hasRadius: true, children: isDragging ? /* @__PURE__ */ jsx(Preview, {}) : /* @__PURE__ */ jsx(Accordion.Root, { value: collapseToOpen, onValueChange: setCollapseToOpen, children: /* @__PURE__ */ jsxs(Accordion.Item, { value: accordionValue, children: [
5266
- /* @__PURE__ */ jsxs(Accordion.Header, { children: [
5267
5485
  /* @__PURE__ */ jsx(
5268
- Accordion.Trigger,
5486
+ IconButton,
5269
5487
  {
5270
- icon: icon && COMPONENT_ICONS[icon] ? COMPONENT_ICONS[icon] : COMPONENT_ICONS.dashboard,
5271
- children: accordionTitle
5488
+ ref: composedAccordionRefs,
5489
+ variant: "ghost",
5490
+ onClick: (e) => e.stopPropagation(),
5491
+ "data-handler-id": handlerId,
5492
+ label: formatMessage({
5493
+ id: getTranslation("components.DragHandle-label"),
5494
+ defaultMessage: "Drag"
5495
+ }),
5496
+ onKeyDown: handleKeyDown,
5497
+ children: /* @__PURE__ */ jsx(Drag, {})
5272
5498
  }
5273
- ),
5274
- /* @__PURE__ */ jsx(Accordion.Actions, { children: accordionActions })
5275
- ] }),
5276
- /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(AccordionContentRadius, { background: "neutral0", children: /* @__PURE__ */ jsx(Box, { paddingLeft: 6, paddingRight: 6, paddingTop: 6, paddingBottom: 6, children: /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: components[componentUid]?.layout?.map((row, rowInd) => /* @__PURE__ */ jsx(
5277
- Grid$1.Item,
5278
- {
5279
- col: 12,
5280
- s: 12,
5281
- xs: 12,
5282
- direction: "column",
5283
- alignItems: "stretch",
5284
- children: /* @__PURE__ */ jsx(Grid$1.Root, { gap: 4, children: row.map(({ size, ...field }) => {
5285
- const fieldName = `${name2}.${index}.${field.name}`;
5286
- const fieldWithTranslatedLabel = {
5287
- ...field,
5288
- label: formatMessage({
5289
- id: `content-manager.components.${componentUid}.${field.name}`,
5290
- defaultMessage: field.label
5291
- })
5292
- };
5293
- return /* @__PURE__ */ jsx(
5294
- Grid$1.Item,
5295
- {
5296
- col: size,
5297
- s: 12,
5298
- xs: 12,
5299
- direction: "column",
5300
- alignItems: "stretch",
5301
- children: children ? children({ ...fieldWithTranslatedLabel, name: fieldName }) : /* @__PURE__ */ jsx(MemoizedInputRenderer, { ...fieldWithTranslatedLabel, name: fieldName })
5302
- },
5303
- fieldName
5304
- );
5305
- }) })
5306
- },
5307
- rowInd
5308
- )) }) }) }) })
5309
- ] }) }) })
5310
- ] });
5311
- };
5312
- const StyledBox = styled(Box)`
5313
- > div:first-child {
5314
- box-shadow: ${({ theme }) => theme.shadows.tableShadow};
5315
- }
5316
- `;
5317
- const AccordionContentRadius = styled(Box)`
5318
- border-radius: 0 0 ${({ theme }) => theme.spaces[1]} ${({ theme }) => theme.spaces[1]};
5319
- `;
5320
- const Rectangle = styled(Box)`
5321
- width: ${({ theme }) => theme.spaces[2]};
5322
- height: ${({ theme }) => theme.spaces[4]};
5323
- `;
5324
- const Preview = styled.span`
5325
- display: block;
5326
- background-color: ${({ theme }) => theme.colors.primary100};
5327
- outline: 1px dashed ${({ theme }) => theme.colors.primary500};
5328
- outline-offset: -1px;
5329
- padding: ${({ theme }) => theme.spaces[6]};
5330
- `;
5331
- const ComponentContainer = styled(Box)`
5332
- list-style: none;
5333
- padding: 0;
5334
- margin: 0;
5335
- `;
5336
- const DynamicZoneLabel = ({
5337
- hint,
5338
- label,
5339
- labelAction,
5340
- name: name2,
5341
- numberOfComponents = 0,
5342
- required
5343
- }) => {
5344
- return /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(
5345
- Box,
5346
- {
5347
- paddingTop: 3,
5348
- paddingBottom: 3,
5349
- paddingRight: 4,
5350
- paddingLeft: 4,
5351
- borderRadius: "26px",
5352
- background: "neutral0",
5353
- shadow: "filterShadow",
5354
- color: "neutral500",
5355
- children: /* @__PURE__ */ jsxs(Flex, { direction: "column", justifyContent: "center", children: [
5356
- /* @__PURE__ */ jsxs(Flex, { maxWidth: "35.6rem", children: [
5357
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", fontWeight: "bold", ellipsis: true, children: [
5358
- label || name2,
5359
- " "
5360
- ] }),
5361
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", fontWeight: "bold", children: [
5362
- "(",
5363
- numberOfComponents,
5364
- ")"
5365
- ] }),
5366
- required && /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: "*" }),
5367
- labelAction && /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: labelAction })
5368
- ] }),
5369
- hint && /* @__PURE__ */ jsx(Box, { paddingTop: 1, maxWidth: "35.6rem", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", ellipsis: true, children: hint }) })
5499
+ )
5370
5500
  ] })
5371
- }
5372
- ) });
5373
- };
5374
- const [DynamicZoneProvider, useDynamicZone] = createContext(
5375
- "DynamicZone",
5376
- {
5377
- isInDynamicZone: false
5378
- }
5379
- );
5380
- const DynamicZone = ({
5381
- attribute,
5382
- disabled: disabledProp,
5383
- hint,
5501
+ ] }),
5502
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(
5503
+ Flex,
5504
+ {
5505
+ direction: "column",
5506
+ alignItems: "stretch",
5507
+ background: "neutral100",
5508
+ padding: 6,
5509
+ gap: 6,
5510
+ children
5511
+ }
5512
+ ) })
5513
+ ] }) });
5514
+ };
5515
+ const Preview = () => {
5516
+ return /* @__PURE__ */ jsx(StyledSpan, { tag: "span", padding: 6, background: "primary100" });
5517
+ };
5518
+ const StyledSpan = styled(Box)`
5519
+ display: block;
5520
+ outline: 1px dashed ${({ theme }) => theme.colors.primary500};
5521
+ outline-offset: -1px;
5522
+ `;
5523
+ const ComponentInput = ({
5384
5524
  label,
5385
- labelAction,
5525
+ required,
5386
5526
  name: name2,
5387
- required = false,
5388
- children
5527
+ attribute,
5528
+ disabled,
5529
+ labelAction,
5530
+ ...props
5389
5531
  }) => {
5390
- const { max = Infinity, min = -Infinity } = attribute ?? {};
5391
- const [addComponentIsOpen, setAddComponentIsOpen] = React.useState(false);
5392
- const [liveText, setLiveText] = React.useState("");
5393
- const { components, isLoading } = useDoc();
5394
- const disabled = disabledProp || isLoading;
5395
- const { addFieldRow, removeFieldRow, moveFieldRow } = useForm(
5396
- "DynamicZone",
5397
- ({ addFieldRow: addFieldRow2, removeFieldRow: removeFieldRow2, moveFieldRow: moveFieldRow2 }) => ({
5398
- addFieldRow: addFieldRow2,
5399
- removeFieldRow: removeFieldRow2,
5400
- moveFieldRow: moveFieldRow2
5401
- })
5402
- );
5403
- const { value = [], error } = useField(name2);
5404
- const dynamicComponentsByCategory = React.useMemo(() => {
5405
- return attribute.components.reduce((acc, componentUid) => {
5406
- const { category, info } = components[componentUid] ?? { info: {} };
5407
- const component = { uid: componentUid, displayName: info.displayName, icon: info.icon };
5408
- if (!acc[category]) {
5409
- acc[category] = [];
5410
- }
5411
- acc[category] = [...acc[category], component];
5412
- return acc;
5413
- }, {});
5414
- }, [attribute.components, components]);
5415
5532
  const { formatMessage } = useIntl();
5416
- const { toggleNotification } = useNotification();
5417
- const dynamicDisplayedComponentsLength = value.length;
5418
- const handleAddComponent = (uid, position) => {
5419
- setAddComponentIsOpen(false);
5420
- const schema = components[uid];
5533
+ const field = useField(name2);
5534
+ const showResetComponent = !attribute.repeatable && field.value && !disabled;
5535
+ const { components } = useDoc();
5536
+ const handleInitialisationClick = () => {
5537
+ const schema = components[attribute.component];
5421
5538
  const form = createDefaultForm(schema, components);
5422
- const transformations = pipe$1(transformDocument(schema, components), (data2) => ({
5423
- ...data2,
5424
- __component: uid
5425
- }));
5426
- const data = transformations(form);
5427
- addFieldRow(name2, data, position);
5428
- };
5429
- const handleClickOpenPicker = () => {
5430
- if (dynamicDisplayedComponentsLength < max) {
5431
- setAddComponentIsOpen((prev) => !prev);
5432
- } else {
5433
- toggleNotification({
5434
- type: "info",
5435
- message: formatMessage({
5436
- id: getTranslation("components.notification.info.maximum-requirement")
5437
- })
5438
- });
5439
- }
5440
- };
5441
- const handleMoveComponent = (newIndex, currentIndex) => {
5442
- setLiveText(
5443
- formatMessage(
5444
- {
5445
- id: getTranslation("dnd.reorder"),
5446
- defaultMessage: "{item}, moved. New position in list: {position}."
5447
- },
5448
- {
5449
- item: `${name2}.${currentIndex}`,
5450
- position: getItemPos(newIndex)
5451
- }
5452
- )
5453
- );
5454
- moveFieldRow(name2, currentIndex, newIndex);
5455
- };
5456
- const getItemPos = (index) => `${index + 1} of ${value.length}`;
5457
- const handleCancel = (index) => {
5458
- setLiveText(
5459
- formatMessage(
5460
- {
5461
- id: getTranslation("dnd.cancel-item"),
5462
- defaultMessage: "{item}, dropped. Re-order cancelled."
5463
- },
5464
- {
5465
- item: `${name2}.${index}`
5466
- }
5467
- )
5468
- );
5469
- };
5470
- const handleGrabItem = (index) => {
5471
- setLiveText(
5472
- formatMessage(
5473
- {
5474
- id: getTranslation("dnd.grab-item"),
5475
- defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5476
- },
5477
- {
5478
- item: `${name2}.${index}`,
5479
- position: getItemPos(index)
5480
- }
5481
- )
5482
- );
5539
+ const data = transformDocument(schema, components)(form);
5540
+ field.onChange(name2, data);
5483
5541
  };
5484
- const handleDropItem = (index) => {
5485
- setLiveText(
5486
- formatMessage(
5487
- {
5488
- id: getTranslation("dnd.drop-item"),
5489
- defaultMessage: `{item}, dropped. Final position in list: {position}.`
5490
- },
5542
+ return /* @__PURE__ */ jsxs(Field.Root, { error: field.error, required, children: [
5543
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
5544
+ /* @__PURE__ */ jsxs(Field.Label, { action: labelAction, children: [
5545
+ label,
5546
+ attribute.repeatable && /* @__PURE__ */ jsxs(Fragment, { children: [
5547
+ " (",
5548
+ Array.isArray(field.value) ? field.value.length : 0,
5549
+ ")"
5550
+ ] })
5551
+ ] }),
5552
+ showResetComponent && /* @__PURE__ */ jsx(
5553
+ IconButton,
5491
5554
  {
5492
- item: `${name2}.${index}`,
5493
- position: getItemPos(index)
5555
+ label: formatMessage({
5556
+ id: getTranslation("components.reset-entry"),
5557
+ defaultMessage: "Reset Entry"
5558
+ }),
5559
+ variant: "ghost",
5560
+ onClick: () => {
5561
+ field.onChange(name2, null);
5562
+ },
5563
+ children: /* @__PURE__ */ jsx(Trash, {})
5494
5564
  }
5495
5565
  )
5496
- );
5497
- };
5498
- const handleRemoveComponent = (name22, currentIndex) => () => {
5499
- removeFieldRow(name22, currentIndex);
5500
- };
5501
- const hasError = error !== void 0;
5502
- const renderButtonLabel = () => {
5503
- if (addComponentIsOpen) {
5504
- return formatMessage({ id: "app.utils.close-label", defaultMessage: "Close" });
5505
- }
5506
- if (hasError && dynamicDisplayedComponentsLength > max) {
5507
- return formatMessage(
5508
- {
5509
- id: getTranslation(`components.DynamicZone.extra-components`),
5510
- defaultMessage: "There {number, plural, =0 {are # extra components} one {is # extra component} other {are # extra components}}"
5511
- },
5512
- {
5513
- number: dynamicDisplayedComponentsLength - max
5514
- }
5515
- );
5516
- }
5517
- if (hasError && dynamicDisplayedComponentsLength < min) {
5518
- return formatMessage(
5519
- {
5520
- id: getTranslation(`components.DynamicZone.missing-components`),
5521
- defaultMessage: "There {number, plural, =0 {are # missing components} one {is # missing component} other {are # missing components}}"
5522
- },
5523
- { number: min - dynamicDisplayedComponentsLength }
5524
- );
5525
- }
5526
- return formatMessage(
5527
- {
5528
- id: getTranslation("components.DynamicZone.add-component"),
5529
- defaultMessage: "Add a component to {componentName}"
5530
- },
5531
- { componentName: label || name2 }
5532
- );
5533
- };
5534
- const level = useComponent("DynamicZone", (state) => state.level);
5535
- const ariaDescriptionId = React.useId();
5536
- return /* @__PURE__ */ jsx(DynamicZoneProvider, { isInDynamicZone: true, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
5537
- dynamicDisplayedComponentsLength > 0 && /* @__PURE__ */ jsxs(Box, { children: [
5538
- /* @__PURE__ */ jsx(
5539
- DynamicZoneLabel,
5540
- {
5541
- hint,
5542
- label,
5543
- labelAction,
5544
- name: name2,
5545
- numberOfComponents: dynamicDisplayedComponentsLength,
5546
- required
5547
- }
5548
- ),
5549
- /* @__PURE__ */ jsx(VisuallyHidden, { id: ariaDescriptionId, children: formatMessage({
5550
- id: getTranslation("dnd.instructions"),
5551
- defaultMessage: `Press spacebar to grab and re-order`
5552
- }) }),
5553
- /* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "assertive", children: liveText }),
5554
- /* @__PURE__ */ jsx("ol", { "aria-describedby": ariaDescriptionId, children: value.map((field, index) => /* @__PURE__ */ jsx(
5555
- ComponentProvider,
5556
- {
5557
- level: level + 1,
5558
- uid: field.__component,
5559
- id: field.id,
5560
- type: "dynamiczone",
5561
- children: /* @__PURE__ */ jsx(
5562
- DynamicComponent,
5563
- {
5564
- disabled,
5565
- name: name2,
5566
- index,
5567
- componentUid: field.__component,
5568
- onMoveComponent: handleMoveComponent,
5569
- onRemoveComponentClick: handleRemoveComponent(name2, index),
5570
- onCancel: handleCancel,
5571
- onDropItem: handleDropItem,
5572
- onGrabItem: handleGrabItem,
5573
- onAddComponent: handleAddComponent,
5574
- dynamicComponentsByCategory,
5575
- children
5576
- }
5577
- )
5578
- },
5579
- field.__temp_key__
5580
- )) })
5581
5566
  ] }),
5582
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(
5583
- AddComponentButton,
5584
- {
5585
- hasError,
5586
- isDisabled: disabled,
5587
- isOpen: addComponentIsOpen,
5588
- onClick: handleClickOpenPicker,
5589
- children: renderButtonLabel()
5590
- }
5591
- ) }),
5592
- /* @__PURE__ */ jsx(
5593
- ComponentPicker,
5594
- {
5595
- dynamicComponentsByCategory,
5596
- isOpen: addComponentIsOpen,
5597
- onClickAddComponent: handleAddComponent
5598
- }
5599
- )
5600
- ] }) });
5567
+ !attribute.repeatable && !field.value && /* @__PURE__ */ jsx(Initializer, { disabled, name: name2, onClick: handleInitialisationClick }),
5568
+ !attribute.repeatable && field.value ? /* @__PURE__ */ jsx(NonRepeatableComponent, { attribute, name: name2, disabled, ...props, children: props.children }) : null,
5569
+ attribute.repeatable && /* @__PURE__ */ jsx(RepeatableComponent, { attribute, name: name2, disabled, ...props, children: props.children }),
5570
+ /* @__PURE__ */ jsx(Field.Error, {})
5571
+ ] });
5601
5572
  };
5573
+ const MemoizedComponentInput = React.memo(ComponentInput);
5602
5574
  export {
5603
5575
  DynamicZone as D,
5604
- MemoizedInputRenderer as M,
5576
+ FormLayout as F,
5577
+ MemoizedUIDInput as M,
5605
5578
  NotAllowedInput as N,
5606
5579
  useDynamicZone as a,
5607
5580
  useFieldHint as b,
5608
- createDefaultForm as c,
5609
- MemoizedUIDInput as d,
5610
- MemoizedWysiwyg as e,
5611
- MemoizedComponentInput as f,
5612
- MemoizedBlocksInput as g,
5613
- prepareTempKeys as p,
5614
- removeFieldsThatDontExistOnSchema as r,
5615
- transformDocument as t,
5581
+ MemoizedWysiwyg as c,
5582
+ MemoizedComponentInput as d,
5583
+ MemoizedBlocksInput as e,
5616
5584
  useLazyComponents as u
5617
5585
  };
5618
- //# sourceMappingURL=Field-Dltnt1km.mjs.map
5586
+ //# sourceMappingURL=Input-aV8SSoTa.mjs.map