@griddo/ax 11.10.36 → 11.10.37
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.
- package/package.json +2 -2
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +1 -3
- package/src/components/Browser/index.tsx +20 -18
- package/src/components/BrowserContent/index.tsx +8 -6
- package/src/components/Fields/ComponentArray/BulkHeader/index.tsx +1 -2
- package/src/components/Fields/ComponentArray/MixableComponentArray/AddItemButton/index.tsx +1 -1
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +29 -43
- package/src/components/Fields/ComponentArray/{MixableComponentArray/PasteModuleButton → PasteModuleButton}/index.tsx +6 -6
- package/src/components/Fields/ComponentArray/SameComponentArray/AddItemButton/index.tsx +1 -1
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +103 -61
- package/src/components/Fields/ComponentArray/SameComponentArray/style.tsx +7 -1
- package/src/components/Fields/ComponentArray/helpers.tsx +2 -2
- package/src/components/Fields/ComponentArray/index.tsx +4 -4
- package/src/components/Fields/ComponentContainer/EmptyContainer/index.tsx +7 -8
- package/src/components/Fields/ComponentContainer/atoms.tsx +0 -2
- package/src/components/Fields/ComponentContainer/index.tsx +26 -30
- package/src/components/SideModal/SideModalOption/index.tsx +14 -11
- package/src/components/SideModal/index.tsx +16 -19
- package/src/containers/PageEditor/actions.tsx +17 -20
- package/src/helpers/containerEvaluations.tsx +1 -12
- package/src/hooks/iframe.ts +13 -9
- package/src/modules/Forms/FormEditor/PageBrowser/index.tsx +1 -15
- package/src/modules/FramePreview/index.tsx +17 -4
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +5 -2
- package/src/modules/PageEditor/Editor/index.tsx +1 -2
- package/src/modules/PageEditor/PageBrowser/index.tsx +5 -2
- package/src/modules/PageEditor/index.tsx +0 -1
- package/src/types/index.tsx +11 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "11.10.
|
|
4
|
+
"version": "11.10.37",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
7
|
"Diego M. Béjar <diego.bejar@secuoyas.com>",
|
|
@@ -217,5 +217,5 @@
|
|
|
217
217
|
"publishConfig": {
|
|
218
218
|
"access": "public"
|
|
219
219
|
},
|
|
220
|
-
"gitHead": "
|
|
220
|
+
"gitHead": "44575bb6e91aca2e9213a7bbf8de78a05481557c"
|
|
221
221
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import PasteModuleButton, {
|
|
3
|
-
IPasteModuleProps,
|
|
4
|
-
} from "@ax/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton";
|
|
2
|
+
import PasteModuleButton, { IPasteModuleProps } from "@ax/components/Fields/ComponentArray/PasteModuleButton";
|
|
5
3
|
import { ThemeProvider } from "styled-components";
|
|
6
4
|
import { parseTheme } from "@ax/helpers";
|
|
7
5
|
import "@testing-library/jest-dom";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { findByEditorID } from "@ax/forms";
|
|
4
4
|
import { copyTextToClipboard } from "@ax/helpers";
|
|
@@ -38,7 +38,7 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
38
38
|
const isFormEditor = editorType === "form";
|
|
39
39
|
|
|
40
40
|
const [resolution, setResolution] = useState("desktop");
|
|
41
|
-
const { isVisible, toggleToast, setIsVisible } = useToast();
|
|
41
|
+
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
42
42
|
|
|
43
43
|
useOnMessageReceivedFromIframe(actions);
|
|
44
44
|
|
|
@@ -78,33 +78,34 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
78
78
|
const copyUrl = () => {
|
|
79
79
|
const sharedUrl = `${domain}/page-preview/${id}/${entity}`;
|
|
80
80
|
copyTextToClipboard(sharedUrl).then(
|
|
81
|
-
|
|
82
|
-
toggleToast();
|
|
81
|
+
() => {
|
|
82
|
+
toggleToast("URL Copied");
|
|
83
83
|
},
|
|
84
|
-
|
|
84
|
+
(err) => {
|
|
85
85
|
console.error("Could not copy text: ", err);
|
|
86
86
|
},
|
|
87
87
|
);
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
const toastProps = {
|
|
91
|
-
setIsVisible,
|
|
92
|
-
message: "URL Copied",
|
|
93
|
-
};
|
|
94
|
-
|
|
95
90
|
const deleteModuleSelected = (editorID: number) => {
|
|
96
91
|
actions?.setSelectedContentAction(0);
|
|
97
|
-
actions?.deleteModuleAction([editorID]);
|
|
92
|
+
actions?.deleteModuleAction?.([editorID]);
|
|
98
93
|
};
|
|
99
94
|
|
|
100
95
|
const duplicateModuleSelected = (editorID: number) => {
|
|
101
|
-
const duplicatedEditorID = actions?.duplicateModuleAction([editorID]);
|
|
102
|
-
actions?.setSelectedContentAction(duplicatedEditorID);
|
|
96
|
+
const duplicatedEditorID = actions?.duplicateModuleAction?.([editorID]);
|
|
97
|
+
duplicatedEditorID && actions?.setSelectedContentAction(duplicatedEditorID);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const copyModuleSelected = (editorID: number) => {
|
|
101
|
+
const isCopied = actions?.copyModuleAction?.([editorID]);
|
|
102
|
+
isCopied && toggleToast("1 module copied to clipboard");
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
const moduleActions = {
|
|
106
106
|
deleteModuleAction: deleteModuleSelected,
|
|
107
107
|
duplicateModuleAction: duplicateModuleSelected,
|
|
108
|
+
copyModuleAction: copyModuleSelected,
|
|
108
109
|
};
|
|
109
110
|
|
|
110
111
|
return (
|
|
@@ -181,7 +182,7 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
181
182
|
/>
|
|
182
183
|
</S.Wrapper>
|
|
183
184
|
)}
|
|
184
|
-
{isVisible && <Toast {
|
|
185
|
+
{isVisible && <Toast message={toastState} setIsVisible={setIsVisible} />}
|
|
185
186
|
</S.BrowserWrapper>
|
|
186
187
|
);
|
|
187
188
|
};
|
|
@@ -203,10 +204,11 @@ export interface IBrowserProps {
|
|
|
203
204
|
browserRef?: React.RefObject<HTMLDivElement>;
|
|
204
205
|
editorType?: "form" | "page";
|
|
205
206
|
actions?: {
|
|
206
|
-
setSelectedContentAction:
|
|
207
|
-
deleteModuleAction(editorID: number[]): void;
|
|
208
|
-
duplicateModuleAction(editorID: number[]): number;
|
|
209
|
-
|
|
207
|
+
setSelectedContentAction(editorID: number): void;
|
|
208
|
+
deleteModuleAction?(editorID: number[]): void;
|
|
209
|
+
duplicateModuleAction?(editorID: number[]): number;
|
|
210
|
+
copyModuleAction?(editorID: number[]): number | boolean;
|
|
211
|
+
setScrollEditorIDAction?(editorID: number | null): void;
|
|
210
212
|
};
|
|
211
213
|
}
|
|
212
214
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
2
2
|
import * as components from "components";
|
|
3
3
|
import { builderSSR, ssrHelpers, SiteProvider } from "components";
|
|
4
|
-
import { Core, Preview } from "@griddo/core";
|
|
5
|
-
import { ILanguage, ISocialState } from "@ax/types";
|
|
4
|
+
import { type Core, Preview } from "@griddo/core";
|
|
5
|
+
import type { ILanguage, ISocialState } from "@ax/types";
|
|
6
6
|
|
|
7
7
|
const BrowserContent = (props: IProps) => {
|
|
8
8
|
const {
|
|
@@ -28,11 +28,12 @@ const BrowserContent = (props: IProps) => {
|
|
|
28
28
|
const INSTANCE = process.env.REACT_APP_INSTANCE || process.env.GRIDDO_REACT_APP_INSTANCE;
|
|
29
29
|
|
|
30
30
|
const useInstanceExternalAssets = useCallback(() => {
|
|
31
|
-
if (builderSSR
|
|
31
|
+
if (builderSSR?.onRenderBody) {
|
|
32
32
|
builderSSR.onRenderBody(ssrHelpers);
|
|
33
33
|
}
|
|
34
34
|
}, []);
|
|
35
35
|
|
|
36
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: fix
|
|
36
37
|
useEffect(useInstanceExternalAssets, [useInstanceExternalAssets]);
|
|
37
38
|
|
|
38
39
|
return (
|
|
@@ -84,8 +85,9 @@ interface IProps {
|
|
|
84
85
|
): void;
|
|
85
86
|
selectHoverEditorID?(editorID: number, parentEditorID: number): void;
|
|
86
87
|
moduleActions?: {
|
|
87
|
-
deleteModuleAction(editorID: number): void;
|
|
88
|
-
duplicateModuleAction(editorID: number): void;
|
|
88
|
+
deleteModuleAction?(editorID: number): void;
|
|
89
|
+
duplicateModuleAction?(editorID: number): void;
|
|
90
|
+
copyModuleAction?(editorID: number): void;
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
DndContext,
|
|
5
|
-
DragEndEvent,
|
|
6
|
-
DragStartEvent,
|
|
7
|
-
PointerSensor,
|
|
8
|
-
useSensor,
|
|
9
|
-
useSensors,
|
|
10
|
-
} from "@dnd-kit/core";
|
|
1
|
+
import { useEffect, useState, memo } from "react";
|
|
2
|
+
import { closestCenter, DndContext, useSensor, useSensors, PointerSensor } from "@dnd-kit/core";
|
|
3
|
+
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core";
|
|
11
4
|
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
12
5
|
|
|
13
|
-
import { IModule, INotification, ISchemaField } from "@ax/types";
|
|
6
|
+
import type { IComponent, IModule, INotification, ISchemaField, ITemplate, ModuleCategoryInfo } from "@ax/types";
|
|
14
7
|
import { ComponentContainer, SideModal, Toast } from "@ax/components";
|
|
15
8
|
import { useBulkSelection, useModal, useToast } from "@ax/hooks";
|
|
16
9
|
|
|
17
10
|
import { getComponentProps, containerToComponentArray, getTypefromKey, getModulesToPaste } from "../helpers";
|
|
18
11
|
import AddItemButton from "./AddItemButton";
|
|
19
|
-
import PasteModuleButton from "
|
|
12
|
+
import PasteModuleButton from "../PasteModuleButton";
|
|
20
13
|
import BulkHeader from "../BulkHeader";
|
|
21
14
|
|
|
22
15
|
import * as S from "./style";
|
|
@@ -72,11 +65,19 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
72
65
|
field,
|
|
73
66
|
);
|
|
74
67
|
|
|
75
|
-
const selectedID = parseInt(localStorage.getItem("selectedID") || "0");
|
|
68
|
+
const selectedID = parseInt(localStorage.getItem("selectedID") || "0", 10);
|
|
76
69
|
const isComponentModule = contentType === "components";
|
|
77
70
|
const isModuleArr = contentType === "modules" || contentType === "fields";
|
|
78
71
|
const isFormArr = contentType === "fields";
|
|
79
72
|
|
|
73
|
+
const isAbletoAdd = (!maxItems || fixedValue.length < maxItems) && !disabled && whiteList.length > 0;
|
|
74
|
+
const showAddItemButton = isAbletoAdd && (!isFormArr || (isFormArr && !!setSelectedFormFieldAction));
|
|
75
|
+
const showPasteModuleButton = isAbletoAdd && modulesToPaste.length > 0;
|
|
76
|
+
|
|
77
|
+
const canReplace = maxItems === 1 && whiteList.length > 1;
|
|
78
|
+
const displayReplaceSideModal = fixedValue.length > 0 && canReplace;
|
|
79
|
+
const optionsType = isModuleArr ? "modules" : "components";
|
|
80
|
+
|
|
80
81
|
const { isOpen, toggleModal } = useModal(false, false);
|
|
81
82
|
const [isBulkOpen, setIsBulkOpen] = useState(false);
|
|
82
83
|
const [draggingId, setDraggingId] = useState<number | null>(null);
|
|
@@ -103,21 +104,21 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
103
104
|
return fixedValue.length > 1 ? `#${index + 1} ${name}` : name;
|
|
104
105
|
};
|
|
105
106
|
|
|
106
|
-
const handleAddModule = (moduleType: string) =>
|
|
107
|
-
addModuleAction && addModuleAction(moduleType, objKey, editorID, isComponentModule);
|
|
107
|
+
const handleAddModule = (moduleType: string) => addModuleAction?.(moduleType, objKey, editorID, isComponentModule);
|
|
108
108
|
|
|
109
|
-
const handleAddComponent = (componentType: string) => addComponentAction
|
|
109
|
+
const handleAddComponent = (componentType: string) => addComponentAction?.(componentType, objKey);
|
|
110
110
|
|
|
111
111
|
const handleAdd = isModuleArr ? handleAddModule : handleAddComponent;
|
|
112
112
|
|
|
113
|
-
const handleModuleReplace = (moduleType: string) => {
|
|
113
|
+
const handleModuleReplace = (moduleType: string | IComponent) => {
|
|
114
114
|
const { modules } = selectedContent;
|
|
115
|
+
if (typeof moduleType !== "string") return;
|
|
115
116
|
if (isModuleArr && deleteModuleAction && modules?.length > 0) {
|
|
116
117
|
const currentModule: IModule = modules[0];
|
|
117
118
|
deleteModuleAction([currentModule.editorID], objKey);
|
|
118
119
|
handleAddModule(moduleType);
|
|
119
120
|
} else {
|
|
120
|
-
replaceElementsInCollectionAction
|
|
121
|
+
replaceElementsInCollectionAction?.(moduleType);
|
|
121
122
|
}
|
|
122
123
|
};
|
|
123
124
|
|
|
@@ -126,29 +127,15 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
126
127
|
const handleToggleModal = () =>
|
|
127
128
|
isFormArr && setSelectedFormFieldAction ? setSelectedFormFieldAction(field) : toggleModal();
|
|
128
129
|
|
|
129
|
-
const isAbletoAdd = (!maxItems || fixedValue.length < maxItems) && !disabled && whiteList.length > 0;
|
|
130
|
-
|
|
131
|
-
const showAddItemButton = isAbletoAdd && (!isFormArr || (isFormArr && !!setSelectedFormFieldAction));
|
|
132
|
-
|
|
133
|
-
const showPasteModuleButton =
|
|
134
|
-
isAbletoAdd &&
|
|
135
|
-
(isModuleArr || objKey === "componentModules") &&
|
|
136
|
-
(modulesToPaste.length > 0 || unavailableModules.length > 0);
|
|
137
|
-
|
|
138
|
-
const canReplace = maxItems === 1 && whiteList.length > 1;
|
|
139
|
-
const displayReplaceSideModal = fixedValue.length > 0 && canReplace;
|
|
140
|
-
const optionsType = isModuleArr ? "modules" : "components";
|
|
141
|
-
|
|
142
130
|
const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
|
|
143
131
|
|
|
144
|
-
const ComponentList =
|
|
132
|
+
const ComponentList = memo(function ComponentList({ components }: { components: IModule[] }): JSX.Element {
|
|
145
133
|
return (
|
|
146
134
|
<>
|
|
147
135
|
{components.map((element: IModule, i: number) => {
|
|
148
136
|
const { editorID, fixed } = element;
|
|
149
137
|
const componentProps = getComponentProps(element, activatedModules, isModuleArr);
|
|
150
|
-
const { moduleTitle, isModuleDeactivated, componentTitle, displayName,
|
|
151
|
-
componentProps;
|
|
138
|
+
const { moduleTitle, isModuleDeactivated, componentTitle, displayName, isModuleDisabled } = componentProps;
|
|
152
139
|
const text = getText(componentTitle || displayName, i);
|
|
153
140
|
const isItemSelected = isSelected(editorID);
|
|
154
141
|
const isDraggingSelected = selectedItems.all.includes(draggingId);
|
|
@@ -177,7 +164,6 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
177
164
|
parentKey={objKey}
|
|
178
165
|
theme={theme}
|
|
179
166
|
arrayLength={components.length}
|
|
180
|
-
isModule={isModule}
|
|
181
167
|
isSelected={isItemSelected}
|
|
182
168
|
onChange={addToBulkSelection}
|
|
183
169
|
hasMenu={selectedItems.all.length > 0}
|
|
@@ -216,7 +202,7 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
216
202
|
};
|
|
217
203
|
|
|
218
204
|
const handleCopy = () => {
|
|
219
|
-
const modulesCopied = copyModuleAction
|
|
205
|
+
const modulesCopied = copyModuleAction?.(selectedItems.all);
|
|
220
206
|
modulesCopied &&
|
|
221
207
|
toggleToast(`${modulesCopied} module${selectedItems.all.length > 1 ? "s" : ""} copied to clipboard`);
|
|
222
208
|
};
|
|
@@ -227,9 +213,9 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
227
213
|
type: "error",
|
|
228
214
|
text: "Unable to duplicate modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
|
|
229
215
|
};
|
|
230
|
-
setNotificationAction
|
|
216
|
+
setNotificationAction?.(notification);
|
|
231
217
|
} else {
|
|
232
|
-
duplicateModuleAction
|
|
218
|
+
duplicateModuleAction?.(selectedItems.all, objKey);
|
|
233
219
|
resetBulkSelection();
|
|
234
220
|
}
|
|
235
221
|
};
|
|
@@ -238,7 +224,7 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
238
224
|
const modulesToDelete = fixedValue
|
|
239
225
|
.filter((element) => selectedItems.all.includes(element.editorID) && (!isFormArr || !element.fixed))
|
|
240
226
|
.map((element) => element.editorID);
|
|
241
|
-
deleteModuleAction
|
|
227
|
+
deleteModuleAction?.(modulesToDelete, objKey);
|
|
242
228
|
resetBulkSelection();
|
|
243
229
|
};
|
|
244
230
|
|
|
@@ -346,7 +332,7 @@ export interface IMixableComponentArrayProps {
|
|
|
346
332
|
editorID: number;
|
|
347
333
|
goTo: (editorID: number) => void;
|
|
348
334
|
actions?: {
|
|
349
|
-
addComponentAction: (componentType:
|
|
335
|
+
addComponentAction: (componentType: IComponent | string, key?: string) => void;
|
|
350
336
|
addModuleAction: (moduleType: string, key: string, selectedID: number, isComponentModule?: boolean) => void;
|
|
351
337
|
deleteModuleAction: (editorID: number[], key?: string) => void;
|
|
352
338
|
duplicateModuleAction: (editorID: number[], key?: string) => number;
|
|
@@ -355,10 +341,10 @@ export interface IMixableComponentArrayProps {
|
|
|
355
341
|
moveModuleAction: (moduleID: number[], selectedContent: any, newIndex: number, key: string) => void;
|
|
356
342
|
pasteModuleAction: (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>;
|
|
357
343
|
setNotificationAction: (notification: INotification) => void;
|
|
358
|
-
replaceModuleAction: (module:
|
|
344
|
+
replaceModuleAction: (module: IComponent, parent: any, objKey: string) => void;
|
|
359
345
|
setSelectedFormFieldAction: (field: ISchemaField | null) => void;
|
|
360
346
|
};
|
|
361
|
-
categories?:
|
|
347
|
+
categories?: ModuleCategoryInfo[];
|
|
362
348
|
disabled?: boolean;
|
|
363
349
|
activatedModules: string[];
|
|
364
350
|
objKey: string;
|
|
@@ -367,7 +353,7 @@ export interface IMixableComponentArrayProps {
|
|
|
367
353
|
theme: string;
|
|
368
354
|
moduleCopy: { date: Date; elements: IModule[] } | null;
|
|
369
355
|
availableDataPacks: Record<string, any>[];
|
|
370
|
-
template:
|
|
356
|
+
template: ITemplate;
|
|
371
357
|
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
372
358
|
scrollEditorID: number | null;
|
|
373
359
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { memo } from "react";
|
|
2
2
|
|
|
3
3
|
import { useToast } from "@ax/hooks";
|
|
4
4
|
import { Tooltip, IconAction, Toast } from "@ax/components";
|
|
5
|
-
import { IModule, INotification } from "@ax/types";
|
|
5
|
+
import type { IModule, INotification } from "@ax/types";
|
|
6
6
|
|
|
7
7
|
const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
8
8
|
const {
|
|
@@ -24,9 +24,9 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
|
24
24
|
type: "error",
|
|
25
25
|
text: "You are trying to paste a module that is part of a disabled content type package. To copy it, you must first activate it.",
|
|
26
26
|
btnText: "Activate package",
|
|
27
|
-
onClick: () => setHistoryPush
|
|
27
|
+
onClick: () => setHistoryPush?.("/sites/settings/content-types", false),
|
|
28
28
|
};
|
|
29
|
-
setNotification
|
|
29
|
+
setNotification?.(notification);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (slots && modulesToPaste.length > slots) {
|
|
@@ -34,12 +34,12 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
|
34
34
|
type: "error",
|
|
35
35
|
text: "Unable to paste modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
|
|
36
36
|
};
|
|
37
|
-
setNotification
|
|
37
|
+
setNotification?.(notification);
|
|
38
38
|
} else {
|
|
39
39
|
const pasteResult = await pasteModule(editorID, arrayKey, modulesToPaste);
|
|
40
40
|
if (pasteResult?.error) {
|
|
41
41
|
const { type, text } = pasteResult.error;
|
|
42
|
-
setNotification
|
|
42
|
+
setNotification?.({ type, text });
|
|
43
43
|
} else {
|
|
44
44
|
toggleToast(`${modulesToPaste.length} module${modulesToPaste.length > 1 ? "s" : ""} pasted from clipboard`);
|
|
45
45
|
}
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
DndContext,
|
|
5
|
-
DragEndEvent,
|
|
6
|
-
DragStartEvent,
|
|
7
|
-
PointerSensor,
|
|
8
|
-
useSensor,
|
|
9
|
-
useSensors,
|
|
10
|
-
} from "@dnd-kit/core";
|
|
1
|
+
import { useEffect, useState, memo } from "react";
|
|
2
|
+
import { closestCenter, DndContext, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
|
|
3
|
+
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core";
|
|
11
4
|
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
12
5
|
|
|
13
|
-
import { IModule, INotification, ISchemaField } from "@ax/types";
|
|
14
|
-
import { ComponentContainer } from "@ax/components";
|
|
15
|
-
import { useBulkSelection } from "@ax/hooks";
|
|
6
|
+
import type { IComponent, IModule, INotification, ISchemaField, ITemplate, ModuleCategoryInfo } from "@ax/types";
|
|
7
|
+
import { ComponentContainer, Toast } from "@ax/components";
|
|
8
|
+
import { useBulkSelection, useToast } from "@ax/hooks";
|
|
16
9
|
|
|
17
10
|
import AddItemButton from "./AddItemButton";
|
|
18
|
-
import { getComponentProps, getTypefromKey } from "../helpers";
|
|
11
|
+
import { getComponentProps, getModulesToPaste, getTypefromKey } from "../helpers";
|
|
19
12
|
import BulkHeader from "../BulkHeader";
|
|
13
|
+
import PasteModuleButton from "../PasteModuleButton";
|
|
20
14
|
|
|
21
15
|
import * as S from "./style";
|
|
22
16
|
|
|
@@ -37,19 +31,32 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
37
31
|
field,
|
|
38
32
|
mandatory,
|
|
39
33
|
theme,
|
|
34
|
+
moduleCopy,
|
|
35
|
+
availableDataPacks,
|
|
36
|
+
template,
|
|
37
|
+
setHistoryPush,
|
|
40
38
|
} = props;
|
|
41
39
|
|
|
42
40
|
const type = getTypefromKey(objKey);
|
|
43
41
|
const { contentType = type } = field;
|
|
44
|
-
const componentIDs: number[] = value
|
|
42
|
+
const componentIDs: number[] = value?.length ? value.map((element) => element.editorID) : [];
|
|
45
43
|
|
|
46
|
-
const {
|
|
47
|
-
|
|
44
|
+
const {
|
|
45
|
+
addModuleAction,
|
|
46
|
+
addComponentAction,
|
|
47
|
+
setNotificationAction,
|
|
48
|
+
duplicateModuleAction,
|
|
49
|
+
deleteModuleAction,
|
|
50
|
+
pasteModuleAction,
|
|
51
|
+
copyModuleAction,
|
|
52
|
+
} = actions || {};
|
|
48
53
|
|
|
49
54
|
const [isBulkOpen, setIsBulkOpen] = useState(false);
|
|
50
55
|
const [draggingId, setDraggingId] = useState<number | null>(null);
|
|
51
56
|
const { resetBulkSelection, selectedItems, isSelected, checkState, addToBulkSelection, selectAllItems } =
|
|
52
57
|
useBulkSelection(componentIDs);
|
|
58
|
+
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
59
|
+
|
|
53
60
|
|
|
54
61
|
const sensors = useSensors(
|
|
55
62
|
useSensor(PointerSensor, {
|
|
@@ -65,23 +72,31 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
65
72
|
}
|
|
66
73
|
}, [selectedItems.all]);
|
|
67
74
|
|
|
75
|
+
const { modulesToPaste, unavailableModules } = getModulesToPaste(
|
|
76
|
+
moduleCopy,
|
|
77
|
+
whiteList,
|
|
78
|
+
availableDataPacks,
|
|
79
|
+
template,
|
|
80
|
+
field,
|
|
81
|
+
);
|
|
82
|
+
|
|
68
83
|
const getText = (name: string, index: number) => {
|
|
69
84
|
return value && value.length > 1 ? `#${index + 1} ${name}` : name;
|
|
70
85
|
};
|
|
71
86
|
|
|
72
|
-
const componentType = field.reference ? selectedContent[field.reference] : selectedContent
|
|
87
|
+
const componentType = field.reference ? selectedContent[field.reference] : selectedContent.kind;
|
|
73
88
|
|
|
74
89
|
const isModuleArr = contentType === "modules";
|
|
75
90
|
const isComponentModule = contentType === "components";
|
|
91
|
+
const showAddItemButton = !maxItems || (value && value.length < maxItems);
|
|
92
|
+
const showPasteModuleButton = showAddItemButton && modulesToPaste.length > 0;
|
|
76
93
|
|
|
77
94
|
const handleAddModule = (moduleType: string) => addModuleAction(moduleType, objKey, editorID, isComponentModule);
|
|
78
95
|
|
|
79
|
-
const handleAddComponent = () => addComponentAction
|
|
96
|
+
const handleAddComponent = () => addComponentAction?.(componentType, objKey);
|
|
80
97
|
|
|
81
98
|
const handleAdd = isModuleArr ? handleAddModule : handleAddComponent;
|
|
82
99
|
|
|
83
|
-
const showAddItemButton = !maxItems || (value && value.length < maxItems);
|
|
84
|
-
|
|
85
100
|
const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
|
|
86
101
|
|
|
87
102
|
const handleDragStart = (event: DragStartEvent) => {
|
|
@@ -106,15 +121,14 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
106
121
|
setDraggingId(null);
|
|
107
122
|
};
|
|
108
123
|
|
|
109
|
-
const ComponentList =
|
|
124
|
+
const ComponentList = memo(function ComponentList({ components }: { components: IModule[] }): JSX.Element {
|
|
110
125
|
return (
|
|
111
126
|
<>
|
|
112
127
|
{components.map((element, i: number) => {
|
|
113
128
|
const { editorID } = element;
|
|
114
129
|
const componentProps = getComponentProps(element, activatedModules, isModuleArr);
|
|
115
|
-
if (!componentProps) return
|
|
116
|
-
const { moduleTitle, isModuleDeactivated, componentTitle, displayName,
|
|
117
|
-
componentProps;
|
|
130
|
+
if (!componentProps) return null;
|
|
131
|
+
const { moduleTitle, isModuleDeactivated, componentTitle, displayName, isModuleDisabled } = componentProps;
|
|
118
132
|
const text = getText(componentTitle || displayName, i);
|
|
119
133
|
const isItemSelected = isSelected(editorID);
|
|
120
134
|
const isDraggingSelected = selectedItems.all.includes(draggingId);
|
|
@@ -122,33 +136,31 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
122
136
|
const isMultiDragging = selectedItems.all.length > 1 && draggingId === editorID;
|
|
123
137
|
|
|
124
138
|
return (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
/>
|
|
151
|
-
</>
|
|
139
|
+
<ComponentContainer
|
|
140
|
+
isArray={true}
|
|
141
|
+
key={editorID}
|
|
142
|
+
editorID={editorID}
|
|
143
|
+
goTo={goTo}
|
|
144
|
+
text={text}
|
|
145
|
+
moduleTitle={moduleTitle}
|
|
146
|
+
whiteList={whiteList}
|
|
147
|
+
categories={categories}
|
|
148
|
+
actions={actions}
|
|
149
|
+
selectedContent={selectedContent}
|
|
150
|
+
disabled={disabled || isModuleDisabled}
|
|
151
|
+
canDuplicate={showAddItemButton && !isModuleDeactivated}
|
|
152
|
+
canDelete={true}
|
|
153
|
+
parentKey={objKey}
|
|
154
|
+
theme={theme}
|
|
155
|
+
arrayLength={components.length}
|
|
156
|
+
isSelected={isItemSelected}
|
|
157
|
+
onChange={addToBulkSelection}
|
|
158
|
+
hasMenu={selectedItems.all.length > 0}
|
|
159
|
+
isMultiDragging={isMultiDragging}
|
|
160
|
+
draggingCount={selectedItems.all.length}
|
|
161
|
+
className={`${isGhosting ? "ghosting" : ""} ${isMultiDragging ? "dragging" : ""}`}
|
|
162
|
+
toggleToast={toggleToast}
|
|
163
|
+
/>
|
|
152
164
|
);
|
|
153
165
|
})}
|
|
154
166
|
</>
|
|
@@ -161,19 +173,30 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
161
173
|
type: "error",
|
|
162
174
|
text: "Unable to duplicate modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
|
|
163
175
|
};
|
|
164
|
-
setNotificationAction
|
|
176
|
+
setNotificationAction?.(notification);
|
|
165
177
|
} else {
|
|
166
|
-
duplicateModuleAction
|
|
178
|
+
duplicateModuleAction?.(selectedItems.all, objKey);
|
|
167
179
|
resetBulkSelection();
|
|
168
180
|
}
|
|
169
181
|
};
|
|
170
182
|
|
|
171
183
|
const handleDelete = () => {
|
|
172
|
-
deleteModuleAction
|
|
184
|
+
deleteModuleAction?.(selectedItems.all, objKey);
|
|
173
185
|
resetBulkSelection();
|
|
174
186
|
};
|
|
175
187
|
|
|
188
|
+
const handleCopy = () => {
|
|
189
|
+
const modulesCopied = copyModuleAction?.(selectedItems.all);
|
|
190
|
+
modulesCopied &&
|
|
191
|
+
toggleToast(`${modulesCopied} module${selectedItems.all.length > 1 ? "s" : ""} copied to clipboard`);
|
|
192
|
+
};
|
|
193
|
+
|
|
176
194
|
const bulkActions = [
|
|
195
|
+
{
|
|
196
|
+
icon: "copy",
|
|
197
|
+
text: "copy",
|
|
198
|
+
action: handleCopy,
|
|
199
|
+
},
|
|
177
200
|
{
|
|
178
201
|
icon: "duplicate",
|
|
179
202
|
text: "duplicate",
|
|
@@ -210,9 +233,23 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
210
233
|
) : (
|
|
211
234
|
<S.Subtitle>{value?.length || 0} items</S.Subtitle>
|
|
212
235
|
)}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
<S.ActionsWrapper data-testid="mixableComponentWrapper">
|
|
237
|
+
{showPasteModuleButton && pasteModuleAction && (
|
|
238
|
+
<PasteModuleButton
|
|
239
|
+
editorID={editorID}
|
|
240
|
+
isModuleCopyUnavailable={unavailableModules.length > 0}
|
|
241
|
+
pasteModule={pasteModuleAction}
|
|
242
|
+
setNotification={setNotificationAction}
|
|
243
|
+
setHistoryPush={setHistoryPush}
|
|
244
|
+
arrayKey={objKey}
|
|
245
|
+
modulesToPaste={modulesToPaste}
|
|
246
|
+
slots={maxItems ? maxItems - value.length : null}
|
|
247
|
+
/>
|
|
248
|
+
)}
|
|
249
|
+
{showAddItemButton && !disabled && (
|
|
250
|
+
<AddItemButton handleClick={handleAdd} tooltipText={isModuleArr ? "Add module" : "Add component"} />
|
|
251
|
+
)}
|
|
252
|
+
</S.ActionsWrapper>
|
|
216
253
|
</S.ItemRow>
|
|
217
254
|
{value && Array.isArray(value) && (
|
|
218
255
|
<DndContext
|
|
@@ -226,6 +263,7 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
226
263
|
</SortableContext>
|
|
227
264
|
</DndContext>
|
|
228
265
|
)}
|
|
266
|
+
{isVisible && <Toast message={toastState} setIsVisible={setIsVisible} />}
|
|
229
267
|
</S.Wrapper>
|
|
230
268
|
);
|
|
231
269
|
};
|
|
@@ -240,7 +278,7 @@ export interface ISameComponentArrayProps {
|
|
|
240
278
|
editorID: number;
|
|
241
279
|
goTo: (editorID: number) => void;
|
|
242
280
|
actions: {
|
|
243
|
-
addComponentAction: (componentType:
|
|
281
|
+
addComponentAction: (componentType: IComponent | string, key?: string) => void;
|
|
244
282
|
addModuleAction: (moduleType: string, key: string, selectedID: number, isComponentModule?: boolean) => void;
|
|
245
283
|
deleteModuleAction: (editorID: number[], key?: string) => void;
|
|
246
284
|
duplicateModuleAction: (editorID: number[], key?: string) => number;
|
|
@@ -249,15 +287,19 @@ export interface ISameComponentArrayProps {
|
|
|
249
287
|
moveModuleAction: (moduleID: number[], selectedContent: any, newIndex: number, key: string) => void;
|
|
250
288
|
pasteModuleAction: (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>;
|
|
251
289
|
setNotificationAction: (notification: INotification) => void;
|
|
252
|
-
replaceModuleAction: (module:
|
|
290
|
+
replaceModuleAction: (module: IComponent, parent: any, objKey: string) => void;
|
|
253
291
|
};
|
|
254
|
-
categories?:
|
|
292
|
+
categories?: ModuleCategoryInfo[];
|
|
255
293
|
disabled?: boolean;
|
|
256
294
|
activatedModules: string[];
|
|
257
295
|
objKey: string;
|
|
258
296
|
field: ISchemaField;
|
|
259
297
|
mandatory?: boolean;
|
|
260
298
|
theme: string;
|
|
299
|
+
moduleCopy: { date: Date; elements: IModule[] } | null;
|
|
300
|
+
availableDataPacks: Record<string, any>[];
|
|
301
|
+
template: ITemplate;
|
|
302
|
+
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
261
303
|
}
|
|
262
304
|
|
|
263
305
|
export default SameComponentArray;
|