@contentful/experiences-visual-editor-react 1.39.0-alpha-20250528T1201-58ca01e.0 → 1.39.0-alpha-20250528T1549-bd210e1.0
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/dist/index.js +828 -2613
- package/dist/index.js.map +1 -1
- package/dist/renderApp.js +14655 -26412
- package/dist/renderApp.js.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -1,38 +1,268 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useState, useEffect, useCallback, forwardRef, useMemo, useLayoutEffect, useRef } from 'react';
|
|
3
|
+
import { create } from 'zustand';
|
|
4
|
+
import { produce } from 'immer';
|
|
5
|
+
import { isEqual, omit, isArray, get as get$1 } from 'lodash-es';
|
|
3
6
|
import { z } from 'zod';
|
|
4
|
-
import { omit, isArray, isEqual, get as get$1 } from 'lodash-es';
|
|
5
7
|
import md5 from 'md5';
|
|
6
8
|
import { BLOCKS } from '@contentful/rich-text-types';
|
|
7
|
-
import { create } from 'zustand';
|
|
8
|
-
import { Droppable, Draggable, DragDropContext } from '@hello-pangea/dnd';
|
|
9
|
-
import { produce } from 'immer';
|
|
10
9
|
import '@contentful/rich-text-react-renderer';
|
|
11
|
-
import { v4 } from 'uuid';
|
|
12
|
-
import { createPortal } from 'react-dom';
|
|
13
|
-
import classNames from 'classnames';
|
|
14
10
|
|
|
15
11
|
var css_248z$b = "html,\nbody {\n margin: 0;\n padding: 0;\n}\n\n/*\n * All of these variables are tokens from Forma-36 and should not be adjusted as these\n * are global variables that may affect multiple places.\n * As our customers may use other design libraries, we try to avoid overlapping global\n * variables by always using the prefix `--exp-builder-` inside this SDK.\n */\n\n:root {\n /* Color tokens from Forma 36: https://f36.contentful.com/tokens/color-system */\n --exp-builder-blue100: #e8f5ff;\n --exp-builder-blue200: #ceecff;\n --exp-builder-blue300: #98cbff;\n --exp-builder-blue400: #40a0ff;\n --exp-builder-blue500: #036fe3;\n --exp-builder-blue600: #0059c8;\n --exp-builder-blue700: #0041ab;\n --exp-builder-blue800: #003298;\n --exp-builder-blue900: #002a8e;\n --exp-builder-gray100: #f7f9fa;\n --exp-builder-gray200: #e7ebee;\n --exp-builder-gray300: #cfd9e0;\n --exp-builder-gray400: #aec1cc;\n --exp-builder-gray500: #67728a;\n --exp-builder-gray600: #5a657c;\n --exp-builder-gray700: #414d63;\n --exp-builder-gray800: #1b273a;\n --exp-builder-gray900: #111b2b;\n --exp-builder-purple600: #6c3ecf;\n --exp-builder-red200: #ffe0e0;\n --exp-builder-red800: #7f0010;\n --exp-builder-color-white: #ffffff;\n --exp-builder-glow-primary: 0px 0px 0px 3px #e8f5ff;\n\n /* RGB colors for applying opacity */\n --exp-builder-blue100-rgb: 232, 245, 255;\n --exp-builder-blue300-rgb: 152, 203, 255;\n\n /* Spacing tokens from Forma 36: https://f36.contentful.com/tokens/spacing */\n --exp-builder-spacing-s: 0.75rem;\n --exp-builder-spacing-2xs: 0.25rem;\n\n /* Typography tokens from Forma 36: https://f36.contentful.com/tokens/typography */\n --exp-builder-font-size-l: 1rem;\n --exp-builder-font-size-m: 0.875rem;\n --exp-builder-font-stack-primary: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;\n --exp-builder-line-height-condensed: 1.25;\n}\n";
|
|
16
12
|
styleInject(css_248z$b);
|
|
17
13
|
|
|
14
|
+
const ROOT_ID = 'root';
|
|
15
|
+
var TreeAction;
|
|
16
|
+
(function (TreeAction) {
|
|
17
|
+
TreeAction[TreeAction["REMOVE_NODE"] = 0] = "REMOVE_NODE";
|
|
18
|
+
TreeAction[TreeAction["ADD_NODE"] = 1] = "ADD_NODE";
|
|
19
|
+
TreeAction[TreeAction["MOVE_NODE"] = 2] = "MOVE_NODE";
|
|
20
|
+
TreeAction[TreeAction["UPDATE_NODE"] = 3] = "UPDATE_NODE";
|
|
21
|
+
TreeAction[TreeAction["REORDER_NODE"] = 4] = "REORDER_NODE";
|
|
22
|
+
TreeAction[TreeAction["REPLACE_NODE"] = 5] = "REPLACE_NODE";
|
|
23
|
+
})(TreeAction || (TreeAction = {}));
|
|
24
|
+
|
|
25
|
+
function updateNode(nodeId, updatedNode, node) {
|
|
26
|
+
if (node.data.id === nodeId) {
|
|
27
|
+
node.data = updatedNode.data;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
node.children.forEach((childNode) => updateNode(nodeId, updatedNode, childNode));
|
|
31
|
+
}
|
|
32
|
+
function replaceNode(indexToReplace, updatedNode, node) {
|
|
33
|
+
if (node.data.id === updatedNode.parentId) {
|
|
34
|
+
node.children = [
|
|
35
|
+
...node.children.slice(0, indexToReplace),
|
|
36
|
+
updatedNode,
|
|
37
|
+
...node.children.slice(indexToReplace + 1),
|
|
38
|
+
];
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
node.children.forEach((childNode) => replaceNode(indexToReplace, updatedNode, childNode));
|
|
42
|
+
}
|
|
43
|
+
function removeChildNode(indexToRemove, nodeId, parentNodeId, node) {
|
|
44
|
+
if (node.data.id === parentNodeId) {
|
|
45
|
+
const childIndex = node.children.findIndex((child) => child.data.id === nodeId);
|
|
46
|
+
node.children.splice(childIndex === -1 ? indexToRemove : childIndex, 1);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
node.children.forEach((childNode) => removeChildNode(indexToRemove, nodeId, parentNodeId, childNode));
|
|
50
|
+
}
|
|
51
|
+
function addChildNode(indexToAdd, parentNodeId, nodeToAdd, node) {
|
|
52
|
+
if (node.data.id === parentNodeId) {
|
|
53
|
+
node.children = [
|
|
54
|
+
...node.children.slice(0, indexToAdd),
|
|
55
|
+
nodeToAdd,
|
|
56
|
+
...node.children.slice(indexToAdd),
|
|
57
|
+
];
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
node.children.forEach((childNode) => addChildNode(indexToAdd, parentNodeId, nodeToAdd, childNode));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getItemFromTree(id, node) {
|
|
64
|
+
// Check if the current node's id matches the search id
|
|
65
|
+
if (node.data.id === id) {
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
// Recursively search through each child
|
|
69
|
+
for (const child of node.children) {
|
|
70
|
+
const foundNode = getItemFromTree(id, child);
|
|
71
|
+
if (foundNode) {
|
|
72
|
+
// Node found in children
|
|
73
|
+
return foundNode;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// If the node is not found in this branch of the tree, return undefined
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const getItem = (selector, tree) => {
|
|
80
|
+
return getItemFromTree(selector.id, {
|
|
81
|
+
type: 'block',
|
|
82
|
+
data: {
|
|
83
|
+
id: ROOT_ID,
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
},
|
|
86
|
+
children: tree.root.children,
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
function missingNodeAction({ index, nodeAdded, child, tree, parentNodeId, currentNode, }) {
|
|
91
|
+
if (nodeAdded) {
|
|
92
|
+
return { type: TreeAction.ADD_NODE, indexToAdd: index, nodeToAdd: child, parentNodeId };
|
|
93
|
+
}
|
|
94
|
+
const item = getItem({ id: child.data.id }, tree);
|
|
95
|
+
if (item) {
|
|
96
|
+
const parentNode = getItem({ id: item.parentId }, tree);
|
|
97
|
+
if (!parentNode) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const sourceIndex = parentNode.children.findIndex((c) => c.data.id === child.data.id);
|
|
101
|
+
return { type: TreeAction.MOVE_NODE, sourceIndex, destinationIndex: index, parentNodeId };
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
type: TreeAction.REPLACE_NODE,
|
|
105
|
+
originalId: currentNode.children[index].data.id,
|
|
106
|
+
indexToReplace: index,
|
|
107
|
+
node: child,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function matchingNodeAction({ index, originalIndex, nodeRemoved, nodeAdded, parentNodeId, }) {
|
|
111
|
+
if (index !== originalIndex && !nodeRemoved && !nodeAdded) {
|
|
112
|
+
return {
|
|
113
|
+
type: TreeAction.REORDER_NODE,
|
|
114
|
+
sourceIndex: originalIndex,
|
|
115
|
+
destinationIndex: index,
|
|
116
|
+
parentNodeId,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function compareNodes({ currentNode, updatedNode, originalTree, differences = [], }) {
|
|
122
|
+
// In the end, this map contains the list of nodes that are not present
|
|
123
|
+
// in the updated tree and must be removed
|
|
124
|
+
const map = new Map();
|
|
125
|
+
if (!currentNode || !updatedNode) {
|
|
126
|
+
return differences;
|
|
127
|
+
}
|
|
128
|
+
// On each tree level, consider only the children of the current node to differentiate between added, removed, or replaced case
|
|
129
|
+
const currentNodeCount = currentNode.children.length;
|
|
130
|
+
const updatedNodeCount = updatedNode.children.length;
|
|
131
|
+
const nodeRemoved = currentNodeCount > updatedNodeCount;
|
|
132
|
+
const nodeAdded = currentNodeCount < updatedNodeCount;
|
|
133
|
+
const parentNodeId = updatedNode.data.id;
|
|
134
|
+
/**
|
|
135
|
+
* The data of the current node has changed, we need to update
|
|
136
|
+
* this node to reflect the data change. (design, content, unbound values)
|
|
137
|
+
*/
|
|
138
|
+
if (!isEqual(currentNode.data, updatedNode.data)) {
|
|
139
|
+
differences.push({
|
|
140
|
+
type: TreeAction.UPDATE_NODE,
|
|
141
|
+
nodeId: currentNode.data.id,
|
|
142
|
+
node: updatedNode,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// Map children of the first tree by their ID
|
|
146
|
+
currentNode.children.forEach((child, index) => map.set(child.data.id, index));
|
|
147
|
+
// Compare with the second tree
|
|
148
|
+
updatedNode.children.forEach((child, index) => {
|
|
149
|
+
const childId = child.data.id;
|
|
150
|
+
// The original tree does not have this node in the updated tree.
|
|
151
|
+
if (!map.has(childId)) {
|
|
152
|
+
const diff = missingNodeAction({
|
|
153
|
+
index,
|
|
154
|
+
child,
|
|
155
|
+
nodeAdded,
|
|
156
|
+
parentNodeId,
|
|
157
|
+
tree: originalTree,
|
|
158
|
+
currentNode,
|
|
159
|
+
});
|
|
160
|
+
if (diff?.type === TreeAction.REPLACE_NODE) {
|
|
161
|
+
// Remove it from the deletion map to avoid adding another REMOVE_NODE action
|
|
162
|
+
map.delete(diff.originalId);
|
|
163
|
+
}
|
|
164
|
+
return differences.push(diff);
|
|
165
|
+
}
|
|
166
|
+
const originalIndex = map.get(childId);
|
|
167
|
+
const diff = matchingNodeAction({
|
|
168
|
+
index,
|
|
169
|
+
originalIndex,
|
|
170
|
+
nodeAdded,
|
|
171
|
+
nodeRemoved,
|
|
172
|
+
parentNodeId,
|
|
173
|
+
});
|
|
174
|
+
differences.push(diff);
|
|
175
|
+
map.delete(childId);
|
|
176
|
+
compareNodes({
|
|
177
|
+
currentNode: currentNode.children[originalIndex],
|
|
178
|
+
updatedNode: child,
|
|
179
|
+
originalTree,
|
|
180
|
+
differences,
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
map.forEach((index, key) => {
|
|
184
|
+
// If the node count of the entire tree doesn't signify
|
|
185
|
+
// a node was removed, don't add that as a diff
|
|
186
|
+
if (!nodeRemoved) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Remaining nodes in the map are removed in the second tree
|
|
190
|
+
differences.push({
|
|
191
|
+
type: TreeAction.REMOVE_NODE,
|
|
192
|
+
indexToRemove: index,
|
|
193
|
+
parentNodeId,
|
|
194
|
+
idToRemove: key,
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
return differences;
|
|
198
|
+
}
|
|
199
|
+
function getTreeDiffs(tree1, tree2, originalTree) {
|
|
200
|
+
const differences = [];
|
|
201
|
+
compareNodes({
|
|
202
|
+
currentNode: tree1,
|
|
203
|
+
updatedNode: tree2,
|
|
204
|
+
originalTree,
|
|
205
|
+
differences,
|
|
206
|
+
});
|
|
207
|
+
return differences.filter((diff) => diff);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
211
|
+
const OUTGOING_EVENTS = {
|
|
212
|
+
Connected: 'connected',
|
|
213
|
+
DesignTokens: 'registerDesignTokens',
|
|
214
|
+
RegisteredBreakpoints: 'registeredBreakpoints',
|
|
215
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
216
|
+
MouseMove: 'mouseMove',
|
|
217
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
218
|
+
ComponentSelected: 'componentSelected',
|
|
219
|
+
RegisteredComponents: 'registeredComponents',
|
|
220
|
+
RequestComponentTreeUpdate: 'requestComponentTreeUpdate',
|
|
221
|
+
CanvasReload: 'canvasReload',
|
|
222
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
223
|
+
UpdateSelectedComponentCoordinates: 'updateSelectedComponentCoordinates',
|
|
224
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
225
|
+
CanvasScroll: 'canvasScrolling',
|
|
226
|
+
CanvasError: 'canvasError',
|
|
227
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
228
|
+
OutsideCanvasClick: 'outsideCanvasClick',
|
|
229
|
+
SDKFeatures: 'sdkFeatures',
|
|
230
|
+
RequestEntities: 'REQUEST_ENTITIES',
|
|
231
|
+
};
|
|
18
232
|
const INCOMING_EVENTS$1 = {
|
|
19
233
|
RequestEditorMode: 'requestEditorMode',
|
|
20
234
|
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
21
235
|
ExperienceUpdated: 'componentTreeUpdated',
|
|
236
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
22
237
|
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
238
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
23
239
|
ComponentDragCanceled: 'componentDragCanceled',
|
|
240
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
24
241
|
ComponentDragStarted: 'componentDragStarted',
|
|
242
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
25
243
|
ComponentDragEnded: 'componentDragEnded',
|
|
244
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
26
245
|
ComponentMoveEnded: 'componentMoveEnded',
|
|
246
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
27
247
|
CanvasResized: 'canvasResized',
|
|
248
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
28
249
|
SelectComponent: 'selectComponent',
|
|
250
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
29
251
|
HoverComponent: 'hoverComponent',
|
|
30
252
|
UpdatedEntity: 'updatedEntity',
|
|
31
253
|
AssembliesAdded: 'assembliesAdded',
|
|
32
254
|
AssembliesRegistered: 'assembliesRegistered',
|
|
255
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
33
256
|
MouseMove: 'mouseMove',
|
|
34
257
|
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
35
258
|
};
|
|
259
|
+
const INTERNAL_EVENTS = {
|
|
260
|
+
ComponentsRegistered: 'cfComponentsRegistered',
|
|
261
|
+
VisualEditorInitialize: 'cfVisualEditorInitialize',
|
|
262
|
+
};
|
|
263
|
+
const VISUAL_EDITOR_EVENTS = {
|
|
264
|
+
Ready: 'cfVisualEditorReady',
|
|
265
|
+
};
|
|
36
266
|
/**
|
|
37
267
|
* These modes are ONLY intended to be internally used within the context of
|
|
38
268
|
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
@@ -44,40 +274,89 @@ var StudioCanvasMode$3;
|
|
|
44
274
|
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
45
275
|
StudioCanvasMode["NONE"] = "none";
|
|
46
276
|
})(StudioCanvasMode$3 || (StudioCanvasMode$3 = {}));
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
277
|
+
const ASSEMBLY_NODE_TYPE = 'assembly';
|
|
278
|
+
const ASSEMBLY_DEFAULT_CATEGORY = 'Assemblies';
|
|
279
|
+
const EMPTY_CONTAINER_HEIGHT$1 = '80px';
|
|
280
|
+
const HYPERLINK_DEFAULT_PATTERN = `/{locale}/{entry.fields.slug}/`;
|
|
281
|
+
var PostMessageMethods$3;
|
|
282
|
+
(function (PostMessageMethods) {
|
|
283
|
+
PostMessageMethods["REQUEST_ENTITIES"] = "REQUEST_ENTITIES";
|
|
284
|
+
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
285
|
+
})(PostMessageMethods$3 || (PostMessageMethods$3 = {}));
|
|
286
|
+
|
|
287
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
288
|
+
const INCOMING_EVENTS = {
|
|
289
|
+
RequestEditorMode: 'requestEditorMode',
|
|
290
|
+
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
291
|
+
ExperienceUpdated: 'componentTreeUpdated',
|
|
292
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
293
|
+
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
294
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
295
|
+
ComponentDragCanceled: 'componentDragCanceled',
|
|
296
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
297
|
+
ComponentDragStarted: 'componentDragStarted',
|
|
298
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
299
|
+
ComponentDragEnded: 'componentDragEnded',
|
|
300
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
301
|
+
ComponentMoveEnded: 'componentMoveEnded',
|
|
302
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
303
|
+
CanvasResized: 'canvasResized',
|
|
304
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
305
|
+
SelectComponent: 'selectComponent',
|
|
306
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
307
|
+
HoverComponent: 'hoverComponent',
|
|
308
|
+
UpdatedEntity: 'updatedEntity',
|
|
309
|
+
AssembliesAdded: 'assembliesAdded',
|
|
310
|
+
AssembliesRegistered: 'assembliesRegistered',
|
|
311
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
312
|
+
MouseMove: 'mouseMove',
|
|
313
|
+
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* These modes are ONLY intended to be internally used within the context of
|
|
317
|
+
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
318
|
+
* intentionally do not include preview/delivery modes.
|
|
319
|
+
*/
|
|
320
|
+
var StudioCanvasMode$2;
|
|
321
|
+
(function (StudioCanvasMode) {
|
|
322
|
+
StudioCanvasMode["READ_ONLY"] = "readOnlyMode";
|
|
323
|
+
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
324
|
+
StudioCanvasMode["NONE"] = "none";
|
|
325
|
+
})(StudioCanvasMode$2 || (StudioCanvasMode$2 = {}));
|
|
326
|
+
const CONTENTFUL_COMPONENTS$1 = {
|
|
327
|
+
section: {
|
|
328
|
+
id: 'contentful-section',
|
|
329
|
+
name: 'Section',
|
|
330
|
+
},
|
|
331
|
+
container: {
|
|
332
|
+
id: 'contentful-container',
|
|
333
|
+
name: 'Container',
|
|
334
|
+
},
|
|
335
|
+
columns: {
|
|
336
|
+
id: 'contentful-columns',
|
|
337
|
+
name: 'Columns',
|
|
338
|
+
},
|
|
339
|
+
singleColumn: {
|
|
340
|
+
id: 'contentful-single-column',
|
|
341
|
+
name: 'Column',
|
|
342
|
+
},
|
|
343
|
+
button: {
|
|
344
|
+
id: 'contentful-button',
|
|
345
|
+
name: 'Button',
|
|
346
|
+
},
|
|
347
|
+
heading: {
|
|
348
|
+
id: 'contentful-heading',
|
|
349
|
+
name: 'Heading',
|
|
350
|
+
},
|
|
351
|
+
image: {
|
|
352
|
+
id: 'contentful-image',
|
|
353
|
+
name: 'Image',
|
|
354
|
+
},
|
|
355
|
+
richText: {
|
|
356
|
+
id: 'contentful-richText',
|
|
357
|
+
name: 'Rich Text',
|
|
358
|
+
},
|
|
359
|
+
text: {
|
|
81
360
|
id: 'contentful-text',
|
|
82
361
|
name: 'Text',
|
|
83
362
|
},
|
|
@@ -90,9 +369,6 @@ const CONTENTFUL_COMPONENTS$2 = {
|
|
|
90
369
|
name: 'Carousel',
|
|
91
370
|
},
|
|
92
371
|
};
|
|
93
|
-
const ASSEMBLY_NODE_TYPE$1 = 'assembly';
|
|
94
|
-
const ASSEMBLY_DEFAULT_CATEGORY$1 = 'Assemblies';
|
|
95
|
-
const ASSEMBLY_BLOCK_NODE_TYPE$1 = 'assemblyBlock';
|
|
96
372
|
const CF_STYLE_ATTRIBUTES = [
|
|
97
373
|
'cfVisibility',
|
|
98
374
|
'cfHorizontalAlignment',
|
|
@@ -135,30 +411,24 @@ const CF_STYLE_ATTRIBUTES = [
|
|
|
135
411
|
'cfBackgroundImageAlignmentVertical',
|
|
136
412
|
'cfBackgroundImageAlignmentHorizontal',
|
|
137
413
|
];
|
|
138
|
-
const EMPTY_CONTAINER_HEIGHT
|
|
414
|
+
const EMPTY_CONTAINER_HEIGHT = '80px';
|
|
139
415
|
const DEFAULT_IMAGE_WIDTH = '500px';
|
|
140
|
-
var PostMessageMethods$
|
|
416
|
+
var PostMessageMethods$2;
|
|
141
417
|
(function (PostMessageMethods) {
|
|
142
418
|
PostMessageMethods["REQUEST_ENTITIES"] = "REQUEST_ENTITIES";
|
|
143
419
|
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
144
|
-
})(PostMessageMethods$
|
|
420
|
+
})(PostMessageMethods$2 || (PostMessageMethods$2 = {}));
|
|
145
421
|
const SUPPORTED_IMAGE_FORMATS = ['jpg', 'png', 'webp', 'gif', 'avif'];
|
|
146
422
|
|
|
147
423
|
const structureComponentIds = new Set([
|
|
148
|
-
CONTENTFUL_COMPONENTS$
|
|
149
|
-
CONTENTFUL_COMPONENTS$
|
|
150
|
-
CONTENTFUL_COMPONENTS$
|
|
151
|
-
CONTENTFUL_COMPONENTS$
|
|
424
|
+
CONTENTFUL_COMPONENTS$1.section.id,
|
|
425
|
+
CONTENTFUL_COMPONENTS$1.columns.id,
|
|
426
|
+
CONTENTFUL_COMPONENTS$1.container.id,
|
|
427
|
+
CONTENTFUL_COMPONENTS$1.singleColumn.id,
|
|
152
428
|
]);
|
|
153
|
-
const
|
|
154
|
-
const allContentfulComponentIds = new Set(Object.values(CONTENTFUL_COMPONENTS$2).map((component) => component.id));
|
|
155
|
-
const isPatternComponent = (type) => patternTypes.has(type ?? '');
|
|
429
|
+
const allContentfulComponentIds = new Set(Object.values(CONTENTFUL_COMPONENTS$1).map((component) => component.id));
|
|
156
430
|
const isContentfulStructureComponent = (componentId) => structureComponentIds.has((componentId ?? ''));
|
|
157
431
|
const isContentfulComponent = (componentId) => allContentfulComponentIds.has((componentId ?? ''));
|
|
158
|
-
const isComponentAllowedOnRoot = ({ type, category, componentId }) => isPatternComponent(type) ||
|
|
159
|
-
category === ASSEMBLY_DEFAULT_CATEGORY$1 ||
|
|
160
|
-
isContentfulStructureComponent(componentId) ||
|
|
161
|
-
componentId === CONTENTFUL_COMPONENTS$2.divider.id;
|
|
162
432
|
const isStructureWithRelativeHeight = (componentId, height) => {
|
|
163
433
|
return isContentfulStructureComponent(componentId) && !height?.toString().endsWith('px');
|
|
164
434
|
};
|
|
@@ -597,17 +867,16 @@ const PrimitiveValueSchema$1 = z.union([
|
|
|
597
867
|
z.record(z.any(), z.any()),
|
|
598
868
|
z.undefined(),
|
|
599
869
|
]);
|
|
870
|
+
const UsedComponentsSchema$1 = z.array(z.object({
|
|
871
|
+
sys: z.object({
|
|
872
|
+
type: z.literal('Link'),
|
|
873
|
+
id: z.string(),
|
|
874
|
+
linkType: z.literal('Entry'),
|
|
875
|
+
}),
|
|
876
|
+
}));
|
|
600
877
|
const uuidKeySchema$1 = z
|
|
601
878
|
.string()
|
|
602
879
|
.regex(/^[a-zA-Z0-9-_]{1,21}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,21}$/' });
|
|
603
|
-
/**
|
|
604
|
-
* Property keys for imported components have a limit of 32 characters (to be implemented) while
|
|
605
|
-
* property keys for patterns have a limit of 54 characters (<32-char-variabl-name>_<21-char-nanoid-id>).
|
|
606
|
-
* Because we cannot distinguish between the two in the componentTree, we will use the larger limit for both.
|
|
607
|
-
*/
|
|
608
|
-
const propertyKeySchema$1 = z
|
|
609
|
-
.string()
|
|
610
|
-
.regex(/^[a-zA-Z0-9-_]{1,54}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,54}$/' });
|
|
611
880
|
const DataSourceSchema$1 = z.record(uuidKeySchema$1, z.object({
|
|
612
881
|
sys: z.object({
|
|
613
882
|
type: z.literal('Link'),
|
|
@@ -615,7 +884,62 @@ const DataSourceSchema$1 = z.record(uuidKeySchema$1, z.object({
|
|
|
615
884
|
linkType: z.enum(['Entry', 'Asset']),
|
|
616
885
|
}),
|
|
617
886
|
}));
|
|
887
|
+
const UnboundValuesSchema$1 = z.record(uuidKeySchema$1, z.object({
|
|
888
|
+
value: PrimitiveValueSchema$1,
|
|
889
|
+
}));
|
|
890
|
+
/**
|
|
891
|
+
* Property keys for imported components have a limit of 32 characters (to be implemented) while
|
|
892
|
+
* property keys for patterns have a limit of 54 characters (<32-char-variable-name>_<21-char-nanoid-id>).
|
|
893
|
+
* Because we cannot distinguish between the two in the componentTree, we will use the larger limit for both.
|
|
894
|
+
*/
|
|
895
|
+
const propertyKeySchema$1 = z
|
|
896
|
+
.string()
|
|
897
|
+
.regex(/^[a-zA-Z0-9-_]{1,54}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,54}$/' });
|
|
898
|
+
const ComponentTreeNodeIdSchema$1 = z
|
|
899
|
+
.string()
|
|
900
|
+
.regex(/^[a-zA-Z0-9]{1,8}$/, { message: 'Does not match /^[a-zA-Z0-9]{1,8}$/' });
|
|
901
|
+
const breakpointsRefinement$1 = (value, ctx) => {
|
|
902
|
+
if (!value.length || value[0].query !== '*') {
|
|
903
|
+
ctx.addIssue({
|
|
904
|
+
code: z.ZodIssueCode.custom,
|
|
905
|
+
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
const hasDuplicateIds = value.some((currentBreakpoint, currentBreakpointIndex) => {
|
|
909
|
+
// check if the current breakpoint id is found in the rest of the array
|
|
910
|
+
const breakpointIndex = value.findIndex((breakpoint) => breakpoint.id === currentBreakpoint.id);
|
|
911
|
+
return breakpointIndex !== currentBreakpointIndex;
|
|
912
|
+
});
|
|
913
|
+
if (hasDuplicateIds) {
|
|
914
|
+
ctx.addIssue({
|
|
915
|
+
code: z.ZodIssueCode.custom,
|
|
916
|
+
message: `Breakpoint IDs must be unique`,
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
// Extract the queries boundary by removing the special characters around it
|
|
920
|
+
const queries = value.map((bp) => bp.query === '*' ? bp.query : parseInt(bp.query.replace(/px|<|>/, '')));
|
|
921
|
+
// sort updates queries array in place so we need to create a copy
|
|
922
|
+
const originalQueries = [...queries];
|
|
923
|
+
queries.sort((q1, q2) => {
|
|
924
|
+
if (q1 === '*') {
|
|
925
|
+
return -1;
|
|
926
|
+
}
|
|
927
|
+
if (q2 === '*') {
|
|
928
|
+
return 1;
|
|
929
|
+
}
|
|
930
|
+
return q1 > q2 ? -1 : 1;
|
|
931
|
+
});
|
|
932
|
+
if (originalQueries.join('') !== queries.join('')) {
|
|
933
|
+
ctx.addIssue({
|
|
934
|
+
code: z.ZodIssueCode.custom,
|
|
935
|
+
message: `Breakpoints should be ordered from largest to smallest pixel value`,
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
};
|
|
618
939
|
const ValuesByBreakpointSchema$1 = z.record(z.lazy(() => PrimitiveValueSchema$1));
|
|
940
|
+
const BindingSourceTypeEnumSchema$1 = z
|
|
941
|
+
.array(z.enum(['entry', 'asset', 'manual', 'experience']))
|
|
942
|
+
.nonempty();
|
|
619
943
|
const DesignValueSchema$1 = z
|
|
620
944
|
.object({
|
|
621
945
|
type: z.literal('DesignValue'),
|
|
@@ -648,8 +972,6 @@ const ComponentValueSchema$1 = z
|
|
|
648
972
|
key: z.string(),
|
|
649
973
|
})
|
|
650
974
|
.strict();
|
|
651
|
-
// TODO: finalize schema structure before release
|
|
652
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
653
975
|
const NoValueSchema$1 = z.object({ type: z.literal('NoValue') }).strict();
|
|
654
976
|
const ComponentPropertyValueSchema$1 = z.discriminatedUnion('type', [
|
|
655
977
|
DesignValueSchema$1,
|
|
@@ -661,41 +983,12 @@ const ComponentPropertyValueSchema$1 = z.discriminatedUnion('type', [
|
|
|
661
983
|
]);
|
|
662
984
|
// TODO: finalize schema structure before release
|
|
663
985
|
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
664
|
-
const VariableMappingSchema$1 = z.object({
|
|
665
|
-
patternPropertyDefinitionId: propertyKeySchema$1,
|
|
666
|
-
type: z.literal('ContentTypeMapping'),
|
|
667
|
-
pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
|
|
668
|
-
});
|
|
669
|
-
const VariableMappingsSchema$1 = z.record(propertyKeySchema$1, VariableMappingSchema$1);
|
|
670
|
-
// TODO: finalize schema structure before release
|
|
671
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
672
|
-
const PatternPropertyDefinitionSchema$1 = z.object({
|
|
673
|
-
defaultValue: z
|
|
674
|
-
.record(z.string(), z.object({
|
|
675
|
-
sys: z.object({
|
|
676
|
-
type: z.literal('Link'),
|
|
677
|
-
id: z.string(),
|
|
678
|
-
linkType: z.enum(['Entry']),
|
|
679
|
-
}),
|
|
680
|
-
}))
|
|
681
|
-
.optional(),
|
|
682
|
-
contentTypes: z.record(z.string(), z.object({
|
|
683
|
-
sys: z.object({
|
|
684
|
-
type: z.literal('Link'),
|
|
685
|
-
id: z.string(),
|
|
686
|
-
linkType: z.enum(['ContentType']),
|
|
687
|
-
}),
|
|
688
|
-
})),
|
|
689
|
-
});
|
|
690
|
-
const PatternPropertyDefinitionsSchema$1 = z.record(propertyKeySchema$1, PatternPropertyDefinitionSchema$1);
|
|
691
|
-
// TODO: finalize schema structure before release
|
|
692
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
693
986
|
const PatternPropertySchema$1 = z.object({
|
|
694
987
|
type: z.literal('BoundValue'),
|
|
695
988
|
path: z.string(),
|
|
696
989
|
contentType: z.string(),
|
|
697
990
|
});
|
|
698
|
-
const
|
|
991
|
+
const PatternPropertiesSchema$1 = z.record(propertyKeySchema$1, PatternPropertySchema$1);
|
|
699
992
|
const BreakpointSchema$1 = z
|
|
700
993
|
.object({
|
|
701
994
|
id: propertyKeySchema$1,
|
|
@@ -705,12 +998,6 @@ const BreakpointSchema$1 = z
|
|
|
705
998
|
displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
|
|
706
999
|
})
|
|
707
1000
|
.strict();
|
|
708
|
-
const UnboundValuesSchema$1 = z.record(uuidKeySchema$1, z.object({
|
|
709
|
-
value: PrimitiveValueSchema$1,
|
|
710
|
-
}));
|
|
711
|
-
const ComponentTreeNodeIdSchema$1 = z
|
|
712
|
-
.string()
|
|
713
|
-
.regex(/^[a-zA-Z0-9]{1,8}$/, { message: 'Does not match /^[a-zA-Z0-9]{1,8}$/' });
|
|
714
1001
|
// Use helper schema to define a recursive schema with its type correctly below
|
|
715
1002
|
const BaseComponentTreeNodeSchema$1 = z.object({
|
|
716
1003
|
id: ComponentTreeNodeIdSchema$1.optional(),
|
|
@@ -718,14 +1005,8 @@ const BaseComponentTreeNodeSchema$1 = z.object({
|
|
|
718
1005
|
displayName: z.string().optional(),
|
|
719
1006
|
slotId: z.string().optional(),
|
|
720
1007
|
variables: z.record(propertyKeySchema$1, ComponentPropertyValueSchema$1),
|
|
721
|
-
patternProperties:
|
|
1008
|
+
patternProperties: PatternPropertiesSchema$1.optional(),
|
|
722
1009
|
});
|
|
723
|
-
const ComponentTreeNodeSchema$1 = BaseComponentTreeNodeSchema$1.extend({
|
|
724
|
-
children: z.lazy(() => ComponentTreeNodeSchema$1.array()),
|
|
725
|
-
});
|
|
726
|
-
const BindingSourceTypeEnumSchema$1 = z
|
|
727
|
-
.array(z.enum(['entry', 'asset', 'manual', 'experience']))
|
|
728
|
-
.nonempty();
|
|
729
1010
|
const ComponentVariableSchema$1 = z.object({
|
|
730
1011
|
displayName: z.string().optional(),
|
|
731
1012
|
type: DefinitionPropertyTypeSchema$1,
|
|
@@ -746,8 +1027,25 @@ const ComponentVariableSchema$1 = z.object({
|
|
|
746
1027
|
})
|
|
747
1028
|
.optional(),
|
|
748
1029
|
});
|
|
749
|
-
const
|
|
750
|
-
|
|
1030
|
+
const ComponentTreeNodeSchema$1 = BaseComponentTreeNodeSchema$1.extend({
|
|
1031
|
+
children: z.lazy(() => ComponentTreeNodeSchema$1.array()),
|
|
1032
|
+
});
|
|
1033
|
+
const ComponentTreeSchema$1 = z
|
|
1034
|
+
.object({
|
|
1035
|
+
breakpoints: z.array(BreakpointSchema$1).superRefine(breakpointsRefinement$1),
|
|
1036
|
+
children: z.array(ComponentTreeNodeSchema$1),
|
|
1037
|
+
schemaVersion: SchemaVersions$1,
|
|
1038
|
+
})
|
|
1039
|
+
.strict();
|
|
1040
|
+
const localeWrapper$1 = (fieldSchema) => z.record(z.string(), fieldSchema);
|
|
1041
|
+
|
|
1042
|
+
z.object({
|
|
1043
|
+
componentTree: localeWrapper$1(ComponentTreeSchema$1),
|
|
1044
|
+
dataSource: localeWrapper$1(DataSourceSchema$1),
|
|
1045
|
+
unboundValues: localeWrapper$1(UnboundValuesSchema$1),
|
|
1046
|
+
usedComponents: localeWrapper$1(UsedComponentsSchema$1).optional(),
|
|
1047
|
+
});
|
|
1048
|
+
|
|
751
1049
|
const THUMBNAIL_IDS$1 = [
|
|
752
1050
|
'columns',
|
|
753
1051
|
'columnsPlusRight',
|
|
@@ -773,6 +1071,37 @@ const THUMBNAIL_IDS$1 = [
|
|
|
773
1071
|
'textColumns',
|
|
774
1072
|
'duplex',
|
|
775
1073
|
];
|
|
1074
|
+
// TODO: finalize schema structure before release
|
|
1075
|
+
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
1076
|
+
const VariableMappingSchema$1 = z.object({
|
|
1077
|
+
patternPropertyDefinitionId: propertyKeySchema$1,
|
|
1078
|
+
type: z.literal('ContentTypeMapping'),
|
|
1079
|
+
pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
|
|
1080
|
+
});
|
|
1081
|
+
// TODO: finalize schema structure before release
|
|
1082
|
+
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
1083
|
+
const PatternPropertyDefinitionSchema$1 = z.object({
|
|
1084
|
+
defaultValue: z
|
|
1085
|
+
.record(z.string(), z.object({
|
|
1086
|
+
sys: z.object({
|
|
1087
|
+
type: z.literal('Link'),
|
|
1088
|
+
id: z.string(),
|
|
1089
|
+
linkType: z.enum(['Entry']),
|
|
1090
|
+
}),
|
|
1091
|
+
}))
|
|
1092
|
+
.optional(),
|
|
1093
|
+
contentTypes: z.record(z.string(), z.object({
|
|
1094
|
+
sys: z.object({
|
|
1095
|
+
type: z.literal('Link'),
|
|
1096
|
+
id: z.string(),
|
|
1097
|
+
linkType: z.enum(['ContentType']),
|
|
1098
|
+
}),
|
|
1099
|
+
})),
|
|
1100
|
+
});
|
|
1101
|
+
const PatternPropertyDefinitionsSchema$1 = z.record(propertyKeySchema$1, PatternPropertyDefinitionSchema$1);
|
|
1102
|
+
const VariableMappingsSchema$1 = z.record(propertyKeySchema$1, VariableMappingSchema$1);
|
|
1103
|
+
const ComponentVariablesSchema$1 = z.record(z.string().regex(/^[a-zA-Z0-9-_]{1,54}$/), // Here the key is <variableName>_<nanoidId> so we need to allow for a longer length
|
|
1104
|
+
ComponentVariableSchema$1);
|
|
776
1105
|
const ComponentSettingsSchema$1 = z.object({
|
|
777
1106
|
variableDefinitions: ComponentVariablesSchema$1,
|
|
778
1107
|
thumbnailId: z.enum(THUMBNAIL_IDS$1).optional(),
|
|
@@ -780,65 +1109,12 @@ const ComponentSettingsSchema$1 = z.object({
|
|
|
780
1109
|
variableMappings: VariableMappingsSchema$1.optional(),
|
|
781
1110
|
patternPropertyDefinitions: PatternPropertyDefinitionsSchema$1.optional(),
|
|
782
1111
|
});
|
|
783
|
-
const UsedComponentsSchema$1 = z.array(z.object({
|
|
784
|
-
sys: z.object({
|
|
785
|
-
type: z.literal('Link'),
|
|
786
|
-
id: z.string(),
|
|
787
|
-
linkType: z.literal('Entry'),
|
|
788
|
-
}),
|
|
789
|
-
}));
|
|
790
|
-
const breakpointsRefinement$1 = (value, ctx) => {
|
|
791
|
-
if (!value.length || value[0].query !== '*') {
|
|
792
|
-
ctx.addIssue({
|
|
793
|
-
code: z.ZodIssueCode.custom,
|
|
794
|
-
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
const hasDuplicateIds = value.some((currentBreakpoint, currentBreakpointIndex) => {
|
|
798
|
-
// check if the current breakpoint id is found in the rest of the array
|
|
799
|
-
const breakpointIndex = value.findIndex((breakpoint) => breakpoint.id === currentBreakpoint.id);
|
|
800
|
-
return breakpointIndex !== currentBreakpointIndex;
|
|
801
|
-
});
|
|
802
|
-
if (hasDuplicateIds) {
|
|
803
|
-
ctx.addIssue({
|
|
804
|
-
code: z.ZodIssueCode.custom,
|
|
805
|
-
message: `Breakpoint IDs must be unique`,
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
// Extract the queries boundary by removing the special characters around it
|
|
809
|
-
const queries = value.map((bp) => bp.query === '*' ? bp.query : parseInt(bp.query.replace(/px|<|>/, '')));
|
|
810
|
-
// sort updates queries array in place so we need to create a copy
|
|
811
|
-
const originalQueries = [...queries];
|
|
812
|
-
queries.sort((q1, q2) => {
|
|
813
|
-
if (q1 === '*') {
|
|
814
|
-
return -1;
|
|
815
|
-
}
|
|
816
|
-
if (q2 === '*') {
|
|
817
|
-
return 1;
|
|
818
|
-
}
|
|
819
|
-
return q1 > q2 ? -1 : 1;
|
|
820
|
-
});
|
|
821
|
-
if (originalQueries.join('') !== queries.join('')) {
|
|
822
|
-
ctx.addIssue({
|
|
823
|
-
code: z.ZodIssueCode.custom,
|
|
824
|
-
message: `Breakpoints should be ordered from largest to smallest pixel value`,
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
};
|
|
828
|
-
const ComponentTreeSchema$1 = z
|
|
829
|
-
.object({
|
|
830
|
-
breakpoints: z.array(BreakpointSchema$1).superRefine(breakpointsRefinement$1),
|
|
831
|
-
children: z.array(ComponentTreeNodeSchema$1),
|
|
832
|
-
schemaVersion: SchemaVersions$1,
|
|
833
|
-
})
|
|
834
|
-
.strict();
|
|
835
|
-
const localeWrapper$1 = (fieldSchema) => z.record(z.string(), fieldSchema);
|
|
836
1112
|
z.object({
|
|
837
1113
|
componentTree: localeWrapper$1(ComponentTreeSchema$1),
|
|
838
1114
|
dataSource: localeWrapper$1(DataSourceSchema$1),
|
|
839
1115
|
unboundValues: localeWrapper$1(UnboundValuesSchema$1),
|
|
840
1116
|
usedComponents: localeWrapper$1(UsedComponentsSchema$1).optional(),
|
|
841
|
-
componentSettings: localeWrapper$1(ComponentSettingsSchema$1)
|
|
1117
|
+
componentSettings: localeWrapper$1(ComponentSettingsSchema$1),
|
|
842
1118
|
});
|
|
843
1119
|
|
|
844
1120
|
z.object({
|
|
@@ -1122,51 +1398,6 @@ let DebugLogger$1 = class DebugLogger {
|
|
|
1122
1398
|
DebugLogger$1.instance = null;
|
|
1123
1399
|
DebugLogger$1.getInstance();
|
|
1124
1400
|
|
|
1125
|
-
const findOutermostCoordinates = (first, second) => {
|
|
1126
|
-
return {
|
|
1127
|
-
top: Math.min(first.top, second.top),
|
|
1128
|
-
right: Math.max(first.right, second.right),
|
|
1129
|
-
bottom: Math.max(first.bottom, second.bottom),
|
|
1130
|
-
left: Math.min(first.left, second.left),
|
|
1131
|
-
};
|
|
1132
|
-
};
|
|
1133
|
-
const getElementCoordinates = (element) => {
|
|
1134
|
-
const rect = element.getBoundingClientRect();
|
|
1135
|
-
/**
|
|
1136
|
-
* If element does not have children, or element has it's own width or height,
|
|
1137
|
-
* return the element's coordinates.
|
|
1138
|
-
*/
|
|
1139
|
-
if (element.children.length === 0 || rect.width !== 0 || rect.height !== 0) {
|
|
1140
|
-
return rect;
|
|
1141
|
-
}
|
|
1142
|
-
const rects = [];
|
|
1143
|
-
/**
|
|
1144
|
-
* If element has children, or element does not have it's own width and height,
|
|
1145
|
-
* we find the cordinates of the children, and assume the outermost coordinates of the children
|
|
1146
|
-
* as the coordinate of the element.
|
|
1147
|
-
*
|
|
1148
|
-
* E.g child1 => {top: 2, bottom: 3, left: 4, right: 6} & child2 => {top: 1, bottom: 8, left: 12, right: 24}
|
|
1149
|
-
* The final assumed coordinates of the element would be => { top: 1, right: 24, bottom: 8, left: 4 }
|
|
1150
|
-
*/
|
|
1151
|
-
for (const child of element.children) {
|
|
1152
|
-
const childRect = getElementCoordinates(child);
|
|
1153
|
-
if (childRect.width !== 0 || childRect.height !== 0) {
|
|
1154
|
-
const { top, right, bottom, left } = childRect;
|
|
1155
|
-
rects.push({ top, right, bottom, left });
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
if (rects.length === 0) {
|
|
1159
|
-
return rect;
|
|
1160
|
-
}
|
|
1161
|
-
const { top, right, bottom, left } = rects.reduce(findOutermostCoordinates);
|
|
1162
|
-
return DOMRect.fromRect({
|
|
1163
|
-
x: left,
|
|
1164
|
-
y: top,
|
|
1165
|
-
height: bottom - top,
|
|
1166
|
-
width: right - left,
|
|
1167
|
-
});
|
|
1168
|
-
};
|
|
1169
|
-
|
|
1170
1401
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1171
1402
|
const isLinkToAsset = (variable) => {
|
|
1172
1403
|
if (!variable)
|
|
@@ -1578,7 +1809,7 @@ const calculateNodeDefaultHeight = ({ blockId, children, value, }) => {
|
|
|
1578
1809
|
if (children.length) {
|
|
1579
1810
|
return '100%';
|
|
1580
1811
|
}
|
|
1581
|
-
return EMPTY_CONTAINER_HEIGHT
|
|
1812
|
+
return EMPTY_CONTAINER_HEIGHT;
|
|
1582
1813
|
};
|
|
1583
1814
|
|
|
1584
1815
|
function getOptimizedImageUrl(url, width, quality, format) {
|
|
@@ -2009,10 +2240,10 @@ const tryParseMessage = (event) => {
|
|
|
2009
2240
|
throw new ParseError(`Field eventData.source must be equal to 'composability-app', instead of '${eventData.source}'`);
|
|
2010
2241
|
}
|
|
2011
2242
|
// check eventData.eventType
|
|
2012
|
-
const supportedEventTypes = Object.values(INCOMING_EVENTS
|
|
2243
|
+
const supportedEventTypes = Object.values(INCOMING_EVENTS);
|
|
2013
2244
|
if (!supportedEventTypes.includes(eventData.eventType)) {
|
|
2014
2245
|
// Expected message: This message is handled in the EntityStore to store fetched entities
|
|
2015
|
-
if (eventData.eventType !== PostMessageMethods$
|
|
2246
|
+
if (eventData.eventType !== PostMessageMethods$2.REQUESTED_ENTITIES) {
|
|
2016
2247
|
throw new ParseError(`Field eventData.eventType must be one of the supported values: [${supportedEventTypes.join(', ')}]`);
|
|
2017
2248
|
}
|
|
2018
2249
|
}
|
|
@@ -2277,7 +2508,7 @@ class EditorEntityStore extends EntityStoreBase {
|
|
|
2277
2508
|
}
|
|
2278
2509
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2279
2510
|
const newPromise = new Promise((resolve, reject) => {
|
|
2280
|
-
const unsubscribe = this.subscribe(PostMessageMethods$
|
|
2511
|
+
const unsubscribe = this.subscribe(PostMessageMethods$2.REQUESTED_ENTITIES, (message) => {
|
|
2281
2512
|
const messageIds = [
|
|
2282
2513
|
...message.entities.map((entity) => entity.sys.id),
|
|
2283
2514
|
...(message.missingEntityIds ?? []),
|
|
@@ -2299,7 +2530,7 @@ class EditorEntityStore extends EntityStoreBase {
|
|
|
2299
2530
|
ids.forEach((id) => this.cleanupPromise(id));
|
|
2300
2531
|
unsubscribe();
|
|
2301
2532
|
}, this.timeoutDuration);
|
|
2302
|
-
this.sendMessage(PostMessageMethods$
|
|
2533
|
+
this.sendMessage(PostMessageMethods$2.REQUEST_ENTITIES, {
|
|
2303
2534
|
entityIds: missing,
|
|
2304
2535
|
entityType: type,
|
|
2305
2536
|
locale: this.locale,
|
|
@@ -2388,580 +2619,87 @@ class EditorModeEntityStore extends EditorEntityStore {
|
|
|
2388
2619
|
async fetchEntities({ missingEntryIds, missingAssetIds, skipCache = false, }) {
|
|
2389
2620
|
// Entries and assets will be stored in entryMap and assetMap
|
|
2390
2621
|
await Promise.all([
|
|
2391
|
-
super.fetchEntries(missingEntryIds, skipCache),
|
|
2392
|
-
super.fetchAssets(missingAssetIds, skipCache),
|
|
2393
|
-
]);
|
|
2394
|
-
}
|
|
2395
|
-
getMissingEntityIds(entityLinks) {
|
|
2396
|
-
const entryLinks = entityLinks.filter((link) => link.sys?.linkType === 'Entry');
|
|
2397
|
-
const assetLinks = entityLinks.filter((link) => link.sys?.linkType === 'Asset');
|
|
2398
|
-
const uniqueEntryIds = [...new Set(entryLinks.map((link) => link.sys.id))];
|
|
2399
|
-
const uniqueAssetIds = [...new Set(assetLinks.map((link) => link.sys.id))];
|
|
2400
|
-
const { missing: missingEntryIds } = this.getEntitiesFromMap('Entry', uniqueEntryIds);
|
|
2401
|
-
const { missing: missingAssetIds } = this.getEntitiesFromMap('Asset', uniqueAssetIds);
|
|
2402
|
-
return { missingEntryIds, missingAssetIds };
|
|
2403
|
-
}
|
|
2404
|
-
getValue(entityLinkOrEntity, path) {
|
|
2405
|
-
const entity = this.getEntryOrAsset(entityLinkOrEntity, path.join('/'));
|
|
2406
|
-
if (!entity) {
|
|
2407
|
-
return;
|
|
2408
|
-
}
|
|
2409
|
-
const fieldValue = get(entity, path);
|
|
2410
|
-
return transformAssetFileToUrl(fieldValue);
|
|
2411
|
-
}
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
var VisualEditorMode$1;
|
|
2415
|
-
(function (VisualEditorMode) {
|
|
2416
|
-
VisualEditorMode["LazyLoad"] = "lazyLoad";
|
|
2417
|
-
VisualEditorMode["InjectScript"] = "injectScript";
|
|
2418
|
-
})(VisualEditorMode$1 || (VisualEditorMode$1 = {}));
|
|
2419
|
-
|
|
2420
|
-
class DeepReference {
|
|
2421
|
-
constructor({ path, dataSource }) {
|
|
2422
|
-
const { key, field, referentField } = parseDataSourcePathWithL1DeepBindings(path);
|
|
2423
|
-
this.originalPath = path;
|
|
2424
|
-
this.entityId = dataSource[key].sys.id;
|
|
2425
|
-
this.entityLink = dataSource[key];
|
|
2426
|
-
this.field = field;
|
|
2427
|
-
this.referentField = referentField;
|
|
2428
|
-
}
|
|
2429
|
-
get headEntityId() {
|
|
2430
|
-
return this.entityId;
|
|
2431
|
-
}
|
|
2432
|
-
/**
|
|
2433
|
-
* Extracts referent from the path, using EntityStore as source of
|
|
2434
|
-
* entities during the resolution path.
|
|
2435
|
-
*/
|
|
2436
|
-
extractReferent(entityStore) {
|
|
2437
|
-
const headEntity = entityStore.getEntityFromLink(this.entityLink);
|
|
2438
|
-
const maybeReferentLink = headEntity?.fields[this.field];
|
|
2439
|
-
if (undefined === maybeReferentLink) {
|
|
2440
|
-
// field references nothing (or even field doesn't exist)
|
|
2441
|
-
return undefined;
|
|
2442
|
-
}
|
|
2443
|
-
if (!isLink(maybeReferentLink)) {
|
|
2444
|
-
// Scenario of "impostor referent", where one of the deepPath's segments is not a Link but some other type
|
|
2445
|
-
// Under normal circumstance we expect field to be a Link, but it could be an "impostor"
|
|
2446
|
-
// eg. `Text` or `Number` or anything like that; could be due to CT changes or manual path creation via CMA
|
|
2447
|
-
return undefined;
|
|
2448
|
-
}
|
|
2449
|
-
return maybeReferentLink;
|
|
2450
|
-
}
|
|
2451
|
-
static from(opt) {
|
|
2452
|
-
return new DeepReference(opt);
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
|
-
function gatherDeepReferencesFromTree(startingNode, dataSource) {
|
|
2456
|
-
const deepReferences = [];
|
|
2457
|
-
treeVisit(startingNode, (node) => {
|
|
2458
|
-
if (!node.data.props)
|
|
2459
|
-
return;
|
|
2460
|
-
for (const [, variableMapping] of Object.entries(node.data.props)) {
|
|
2461
|
-
if (variableMapping.type !== 'BoundValue')
|
|
2462
|
-
continue;
|
|
2463
|
-
if (!isDeepPath(variableMapping.path))
|
|
2464
|
-
continue;
|
|
2465
|
-
deepReferences.push(DeepReference.from({
|
|
2466
|
-
path: variableMapping.path,
|
|
2467
|
-
dataSource,
|
|
2468
|
-
}));
|
|
2469
|
-
}
|
|
2470
|
-
});
|
|
2471
|
-
return deepReferences;
|
|
2472
|
-
}
|
|
2473
|
-
|
|
2474
|
-
const useDraggedItemStore = create((set) => ({
|
|
2475
|
-
draggedItem: undefined,
|
|
2476
|
-
hoveredComponentId: undefined,
|
|
2477
|
-
domRect: undefined,
|
|
2478
|
-
componentId: '',
|
|
2479
|
-
isDraggingOnCanvas: false,
|
|
2480
|
-
onBeforeCaptureId: '',
|
|
2481
|
-
mouseX: 0,
|
|
2482
|
-
mouseY: 0,
|
|
2483
|
-
scrollY: 0,
|
|
2484
|
-
setComponentId(id) {
|
|
2485
|
-
set({ componentId: id });
|
|
2486
|
-
},
|
|
2487
|
-
setHoveredComponentId(id) {
|
|
2488
|
-
set({ hoveredComponentId: id });
|
|
2489
|
-
},
|
|
2490
|
-
updateItem: (item) => {
|
|
2491
|
-
set({ draggedItem: item });
|
|
2492
|
-
},
|
|
2493
|
-
setDraggingOnCanvas: (isDraggingOnCanvas) => {
|
|
2494
|
-
set({ isDraggingOnCanvas });
|
|
2495
|
-
},
|
|
2496
|
-
setOnBeforeCaptureId: (onBeforeCaptureId) => {
|
|
2497
|
-
set({ onBeforeCaptureId });
|
|
2498
|
-
},
|
|
2499
|
-
setMousePosition(x, y) {
|
|
2500
|
-
set({ mouseX: x, mouseY: y });
|
|
2501
|
-
},
|
|
2502
|
-
setDomRect(domRect) {
|
|
2503
|
-
set({ domRect });
|
|
2504
|
-
},
|
|
2505
|
-
setScrollY(y) {
|
|
2506
|
-
set({ scrollY: y });
|
|
2507
|
-
},
|
|
2508
|
-
}));
|
|
2509
|
-
|
|
2510
|
-
const SCROLL_STATES = {
|
|
2511
|
-
Start: 'scrollStart',
|
|
2512
|
-
IsScrolling: 'isScrolling',
|
|
2513
|
-
End: 'scrollEnd',
|
|
2514
|
-
};
|
|
2515
|
-
const OUTGOING_EVENTS = {
|
|
2516
|
-
Connected: 'connected',
|
|
2517
|
-
DesignTokens: 'registerDesignTokens',
|
|
2518
|
-
RegisteredBreakpoints: 'registeredBreakpoints',
|
|
2519
|
-
MouseMove: 'mouseMove',
|
|
2520
|
-
NewHoveredElement: 'newHoveredElement',
|
|
2521
|
-
ComponentSelected: 'componentSelected',
|
|
2522
|
-
RegisteredComponents: 'registeredComponents',
|
|
2523
|
-
RequestComponentTreeUpdate: 'requestComponentTreeUpdate',
|
|
2524
|
-
ComponentDragCanceled: 'componentDragCanceled',
|
|
2525
|
-
ComponentDropped: 'componentDropped',
|
|
2526
|
-
ComponentMoved: 'componentMoved',
|
|
2527
|
-
CanvasReload: 'canvasReload',
|
|
2528
|
-
UpdateSelectedComponentCoordinates: 'updateSelectedComponentCoordinates',
|
|
2529
|
-
CanvasScroll: 'canvasScrolling',
|
|
2530
|
-
CanvasError: 'canvasError',
|
|
2531
|
-
ComponentMoveStarted: 'componentMoveStarted',
|
|
2532
|
-
ComponentMoveEnded: 'componentMoveEnded',
|
|
2533
|
-
OutsideCanvasClick: 'outsideCanvasClick',
|
|
2534
|
-
SDKFeatures: 'sdkFeatures',
|
|
2535
|
-
RequestEntities: 'REQUEST_ENTITIES',
|
|
2536
|
-
};
|
|
2537
|
-
const INCOMING_EVENTS = {
|
|
2538
|
-
RequestEditorMode: 'requestEditorMode',
|
|
2539
|
-
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
2540
|
-
ExperienceUpdated: 'componentTreeUpdated',
|
|
2541
|
-
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
2542
|
-
ComponentDragCanceled: 'componentDragCanceled',
|
|
2543
|
-
ComponentDragStarted: 'componentDragStarted',
|
|
2544
|
-
ComponentDragEnded: 'componentDragEnded',
|
|
2545
|
-
ComponentMoveEnded: 'componentMoveEnded',
|
|
2546
|
-
CanvasResized: 'canvasResized',
|
|
2547
|
-
SelectComponent: 'selectComponent',
|
|
2548
|
-
HoverComponent: 'hoverComponent',
|
|
2549
|
-
UpdatedEntity: 'updatedEntity',
|
|
2550
|
-
AssembliesAdded: 'assembliesAdded',
|
|
2551
|
-
AssembliesRegistered: 'assembliesRegistered',
|
|
2552
|
-
MouseMove: 'mouseMove',
|
|
2553
|
-
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
2554
|
-
};
|
|
2555
|
-
const INTERNAL_EVENTS = {
|
|
2556
|
-
ComponentsRegistered: 'cfComponentsRegistered',
|
|
2557
|
-
VisualEditorInitialize: 'cfVisualEditorInitialize',
|
|
2558
|
-
};
|
|
2559
|
-
const VISUAL_EDITOR_EVENTS = {
|
|
2560
|
-
Ready: 'cfVisualEditorReady',
|
|
2561
|
-
};
|
|
2562
|
-
/**
|
|
2563
|
-
* These modes are ONLY intended to be internally used within the context of
|
|
2564
|
-
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
2565
|
-
* intentionally do not include preview/delivery modes.
|
|
2566
|
-
*/
|
|
2567
|
-
var StudioCanvasMode$2;
|
|
2568
|
-
(function (StudioCanvasMode) {
|
|
2569
|
-
StudioCanvasMode["READ_ONLY"] = "readOnlyMode";
|
|
2570
|
-
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
2571
|
-
StudioCanvasMode["NONE"] = "none";
|
|
2572
|
-
})(StudioCanvasMode$2 || (StudioCanvasMode$2 = {}));
|
|
2573
|
-
const CONTENTFUL_COMPONENTS$1 = {
|
|
2574
|
-
section: {
|
|
2575
|
-
id: 'contentful-section',
|
|
2576
|
-
name: 'Section',
|
|
2577
|
-
},
|
|
2578
|
-
container: {
|
|
2579
|
-
id: 'contentful-container',
|
|
2580
|
-
name: 'Container',
|
|
2581
|
-
},
|
|
2582
|
-
columns: {
|
|
2583
|
-
id: 'contentful-columns',
|
|
2584
|
-
name: 'Columns',
|
|
2585
|
-
},
|
|
2586
|
-
singleColumn: {
|
|
2587
|
-
id: 'contentful-single-column',
|
|
2588
|
-
name: 'Column',
|
|
2589
|
-
},
|
|
2590
|
-
button: {
|
|
2591
|
-
id: 'contentful-button',
|
|
2592
|
-
name: 'Button',
|
|
2593
|
-
},
|
|
2594
|
-
heading: {
|
|
2595
|
-
id: 'contentful-heading',
|
|
2596
|
-
name: 'Heading',
|
|
2597
|
-
},
|
|
2598
|
-
image: {
|
|
2599
|
-
id: 'contentful-image',
|
|
2600
|
-
name: 'Image',
|
|
2601
|
-
},
|
|
2602
|
-
richText: {
|
|
2603
|
-
id: 'contentful-richText',
|
|
2604
|
-
name: 'Rich Text',
|
|
2605
|
-
},
|
|
2606
|
-
text: {
|
|
2607
|
-
id: 'contentful-text',
|
|
2608
|
-
name: 'Text',
|
|
2609
|
-
},
|
|
2610
|
-
divider: {
|
|
2611
|
-
id: 'contentful-divider',
|
|
2612
|
-
name: 'Divider',
|
|
2613
|
-
},
|
|
2614
|
-
carousel: {
|
|
2615
|
-
id: 'contentful-carousel',
|
|
2616
|
-
name: 'Carousel',
|
|
2617
|
-
},
|
|
2618
|
-
};
|
|
2619
|
-
const ASSEMBLY_NODE_TYPE = 'assembly';
|
|
2620
|
-
const ASSEMBLY_DEFAULT_CATEGORY = 'Assemblies';
|
|
2621
|
-
const ASSEMBLY_BLOCK_NODE_TYPE = 'assemblyBlock';
|
|
2622
|
-
const ASSEMBLY_NODE_TYPES = [ASSEMBLY_NODE_TYPE, ASSEMBLY_BLOCK_NODE_TYPE];
|
|
2623
|
-
const EMPTY_CONTAINER_HEIGHT = '80px';
|
|
2624
|
-
const HYPERLINK_DEFAULT_PATTERN = `/{locale}/{entry.fields.slug}/`;
|
|
2625
|
-
var PostMessageMethods$2;
|
|
2626
|
-
(function (PostMessageMethods) {
|
|
2627
|
-
PostMessageMethods["REQUEST_ENTITIES"] = "REQUEST_ENTITIES";
|
|
2628
|
-
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
2629
|
-
})(PostMessageMethods$2 || (PostMessageMethods$2 = {}));
|
|
2630
|
-
|
|
2631
|
-
const DRAGGABLE_HEIGHT = 30;
|
|
2632
|
-
const DRAGGABLE_WIDTH = 50;
|
|
2633
|
-
const DRAG_PADDING = 4;
|
|
2634
|
-
const ROOT_ID = 'root';
|
|
2635
|
-
const COMPONENT_LIST_ID = 'component-list';
|
|
2636
|
-
const NEW_COMPONENT_ID = 'ctfl-new-draggable';
|
|
2637
|
-
const CTFL_ZONE_ID = 'data-ctfl-zone-id';
|
|
2638
|
-
const CTFL_DRAGGING_ELEMENT = 'data-ctfl-dragging-element';
|
|
2639
|
-
const HITBOX = {
|
|
2640
|
-
WIDTH: 70,
|
|
2641
|
-
HEIGHT: 20,
|
|
2642
|
-
INITIAL_OFFSET: 10,
|
|
2643
|
-
OFFSET_INCREMENT: 8,
|
|
2644
|
-
MIN_HEIGHT: 45,
|
|
2645
|
-
MIN_DEPTH_HEIGHT: 20,
|
|
2646
|
-
DEEP_ZONE: 5,
|
|
2647
|
-
};
|
|
2648
|
-
var TreeAction;
|
|
2649
|
-
(function (TreeAction) {
|
|
2650
|
-
TreeAction[TreeAction["REMOVE_NODE"] = 0] = "REMOVE_NODE";
|
|
2651
|
-
TreeAction[TreeAction["ADD_NODE"] = 1] = "ADD_NODE";
|
|
2652
|
-
TreeAction[TreeAction["MOVE_NODE"] = 2] = "MOVE_NODE";
|
|
2653
|
-
TreeAction[TreeAction["UPDATE_NODE"] = 3] = "UPDATE_NODE";
|
|
2654
|
-
TreeAction[TreeAction["REORDER_NODE"] = 4] = "REORDER_NODE";
|
|
2655
|
-
TreeAction[TreeAction["REPLACE_NODE"] = 5] = "REPLACE_NODE";
|
|
2656
|
-
})(TreeAction || (TreeAction = {}));
|
|
2657
|
-
var HitboxDirection;
|
|
2658
|
-
(function (HitboxDirection) {
|
|
2659
|
-
HitboxDirection[HitboxDirection["TOP"] = 0] = "TOP";
|
|
2660
|
-
HitboxDirection[HitboxDirection["LEFT"] = 1] = "LEFT";
|
|
2661
|
-
HitboxDirection[HitboxDirection["RIGHT"] = 2] = "RIGHT";
|
|
2662
|
-
HitboxDirection[HitboxDirection["BOTTOM"] = 3] = "BOTTOM";
|
|
2663
|
-
HitboxDirection[HitboxDirection["SELF_VERTICAL"] = 4] = "SELF_VERTICAL";
|
|
2664
|
-
HitboxDirection[HitboxDirection["SELF_HORIZONTAL"] = 5] = "SELF_HORIZONTAL";
|
|
2665
|
-
})(HitboxDirection || (HitboxDirection = {}));
|
|
2666
|
-
var DraggablePosition;
|
|
2667
|
-
(function (DraggablePosition) {
|
|
2668
|
-
DraggablePosition[DraggablePosition["CENTERED"] = 0] = "CENTERED";
|
|
2669
|
-
DraggablePosition[DraggablePosition["MOUSE_POSITION"] = 1] = "MOUSE_POSITION";
|
|
2670
|
-
})(DraggablePosition || (DraggablePosition = {}));
|
|
2671
|
-
|
|
2672
|
-
function useDraggablePosition({ draggableId, draggableRef, position }) {
|
|
2673
|
-
const isDraggingOnCanvas = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
2674
|
-
const draggingId = useDraggedItemStore((state) => state.onBeforeCaptureId);
|
|
2675
|
-
const preDragDomRect = useDraggedItemStore((state) => state.domRect);
|
|
2676
|
-
useEffect(() => {
|
|
2677
|
-
const el = draggableRef?.current ??
|
|
2678
|
-
document.querySelector(`[${CTFL_DRAGGING_ELEMENT}][data-cf-node-id="${draggableId}"]`);
|
|
2679
|
-
if (!isDraggingOnCanvas || draggingId !== draggableId || !el) {
|
|
2680
|
-
return;
|
|
2681
|
-
}
|
|
2682
|
-
const isCentered = position === DraggablePosition.CENTERED || !preDragDomRect;
|
|
2683
|
-
const domRect = isCentered ? el.getBoundingClientRect() : preDragDomRect;
|
|
2684
|
-
const { mouseX, mouseY } = useDraggedItemStore.getState();
|
|
2685
|
-
const top = isCentered ? mouseY - domRect.height / 2 : domRect.top;
|
|
2686
|
-
const left = isCentered ? mouseX - domRect.width / 2 : domRect.left;
|
|
2687
|
-
el.style.position = 'fixed';
|
|
2688
|
-
el.style.left = `${left}px`;
|
|
2689
|
-
el.style.top = `${top}px`;
|
|
2690
|
-
el.style.width = `${domRect.width}px`;
|
|
2691
|
-
el.style.height = `${domRect.height}px`;
|
|
2692
|
-
}, [draggableRef, draggableId, isDraggingOnCanvas, draggingId, position, preDragDomRect]);
|
|
2693
|
-
}
|
|
2694
|
-
|
|
2695
|
-
function getStyle$2(style, snapshot) {
|
|
2696
|
-
if (!snapshot.isDropAnimating) {
|
|
2697
|
-
return style;
|
|
2698
|
-
}
|
|
2699
|
-
return {
|
|
2700
|
-
...style,
|
|
2701
|
-
// cannot be 0, but make it super tiny
|
|
2702
|
-
transitionDuration: `0.001s`,
|
|
2703
|
-
};
|
|
2704
|
-
}
|
|
2705
|
-
const DraggableContainer = ({ id }) => {
|
|
2706
|
-
const ref = useRef(null);
|
|
2707
|
-
useDraggablePosition({
|
|
2708
|
-
draggableId: id,
|
|
2709
|
-
draggableRef: ref,
|
|
2710
|
-
position: DraggablePosition.CENTERED,
|
|
2711
|
-
});
|
|
2712
|
-
return (React.createElement("div", { id: COMPONENT_LIST_ID, style: {
|
|
2713
|
-
position: 'absolute',
|
|
2714
|
-
top: 0,
|
|
2715
|
-
left: 0,
|
|
2716
|
-
pointerEvents: 'none',
|
|
2717
|
-
zIndex: -1,
|
|
2718
|
-
} },
|
|
2719
|
-
React.createElement(Droppable, { droppableId: COMPONENT_LIST_ID, isDropDisabled: true }, (provided) => (React.createElement("div", { ...provided.droppableProps, ref: provided.innerRef },
|
|
2720
|
-
React.createElement(Draggable, { draggableId: id, key: id, index: 0 }, (provided, snapshot) => (React.createElement("div", { id: NEW_COMPONENT_ID, "data-ctfl-dragging-element": true, ref: (node) => {
|
|
2721
|
-
provided.innerRef(node);
|
|
2722
|
-
ref.current = node;
|
|
2723
|
-
}, ...provided.draggableProps, ...provided.dragHandleProps, style: {
|
|
2724
|
-
...getStyle$2(provided.draggableProps.style, snapshot),
|
|
2725
|
-
width: DRAGGABLE_WIDTH,
|
|
2726
|
-
height: DRAGGABLE_HEIGHT,
|
|
2727
|
-
pointerEvents: 'none',
|
|
2728
|
-
} }))),
|
|
2729
|
-
provided.placeholder)))));
|
|
2730
|
-
};
|
|
2731
|
-
|
|
2732
|
-
function getItemFromTree(id, node) {
|
|
2733
|
-
// Check if the current node's id matches the search id
|
|
2734
|
-
if (node.data.id === id) {
|
|
2735
|
-
return node;
|
|
2736
|
-
}
|
|
2737
|
-
// Recursively search through each child
|
|
2738
|
-
for (const child of node.children) {
|
|
2739
|
-
const foundNode = getItemFromTree(id, child);
|
|
2740
|
-
if (foundNode) {
|
|
2741
|
-
// Node found in children
|
|
2742
|
-
return foundNode;
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
// If the node is not found in this branch of the tree, return undefined
|
|
2746
|
-
return undefined;
|
|
2747
|
-
}
|
|
2748
|
-
function findDepthById(node, id, currentDepth = 1) {
|
|
2749
|
-
if (node.data.id === id) {
|
|
2750
|
-
return currentDepth;
|
|
2751
|
-
}
|
|
2752
|
-
// If the node has children, check each one
|
|
2753
|
-
for (const child of node.children) {
|
|
2754
|
-
const childDepth = findDepthById(child, id, currentDepth + 1);
|
|
2755
|
-
if (childDepth !== -1) {
|
|
2756
|
-
return childDepth; // Found the node in a child
|
|
2757
|
-
}
|
|
2758
|
-
}
|
|
2759
|
-
return -1; // Node not found in this branch
|
|
2760
|
-
}
|
|
2761
|
-
const getChildFromTree = (parentId, index, node) => {
|
|
2762
|
-
// Check if the current node's id matches the search id
|
|
2763
|
-
if (node.data.id === parentId) {
|
|
2764
|
-
return node.children[index];
|
|
2765
|
-
}
|
|
2766
|
-
// Recursively search through each child
|
|
2767
|
-
for (const child of node.children) {
|
|
2768
|
-
const foundNode = getChildFromTree(parentId, index, child);
|
|
2769
|
-
if (foundNode) {
|
|
2770
|
-
// Node found in children
|
|
2771
|
-
return foundNode;
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
// If the node is not found in this branch of the tree, return undefined
|
|
2775
|
-
return undefined;
|
|
2776
|
-
};
|
|
2777
|
-
const getItem = (selector, tree) => {
|
|
2778
|
-
return getItemFromTree(selector.id, {
|
|
2779
|
-
type: 'block',
|
|
2780
|
-
data: {
|
|
2781
|
-
id: ROOT_ID,
|
|
2782
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2783
|
-
},
|
|
2784
|
-
children: tree.root.children,
|
|
2785
|
-
});
|
|
2786
|
-
};
|
|
2787
|
-
const getItemDepthFromNode = (selector, node) => {
|
|
2788
|
-
return findDepthById(node, selector.id);
|
|
2789
|
-
};
|
|
2790
|
-
|
|
2791
|
-
function updateNode(nodeId, updatedNode, node) {
|
|
2792
|
-
if (node.data.id === nodeId) {
|
|
2793
|
-
node.data = updatedNode.data;
|
|
2794
|
-
return;
|
|
2795
|
-
}
|
|
2796
|
-
node.children.forEach((childNode) => updateNode(nodeId, updatedNode, childNode));
|
|
2797
|
-
}
|
|
2798
|
-
function replaceNode(indexToReplace, updatedNode, node) {
|
|
2799
|
-
if (node.data.id === updatedNode.parentId) {
|
|
2800
|
-
node.children = [
|
|
2801
|
-
...node.children.slice(0, indexToReplace),
|
|
2802
|
-
updatedNode,
|
|
2803
|
-
...node.children.slice(indexToReplace + 1),
|
|
2804
|
-
];
|
|
2805
|
-
return;
|
|
2806
|
-
}
|
|
2807
|
-
node.children.forEach((childNode) => replaceNode(indexToReplace, updatedNode, childNode));
|
|
2808
|
-
}
|
|
2809
|
-
function removeChildNode(indexToRemove, nodeId, parentNodeId, node) {
|
|
2810
|
-
if (node.data.id === parentNodeId) {
|
|
2811
|
-
const childIndex = node.children.findIndex((child) => child.data.id === nodeId);
|
|
2812
|
-
node.children.splice(childIndex === -1 ? indexToRemove : childIndex, 1);
|
|
2813
|
-
return;
|
|
2814
|
-
}
|
|
2815
|
-
node.children.forEach((childNode) => removeChildNode(indexToRemove, nodeId, parentNodeId, childNode));
|
|
2816
|
-
}
|
|
2817
|
-
function addChildNode(indexToAdd, parentNodeId, nodeToAdd, node) {
|
|
2818
|
-
if (node.data.id === parentNodeId) {
|
|
2819
|
-
node.children = [
|
|
2820
|
-
...node.children.slice(0, indexToAdd),
|
|
2821
|
-
nodeToAdd,
|
|
2822
|
-
...node.children.slice(indexToAdd),
|
|
2823
|
-
];
|
|
2824
|
-
return;
|
|
2825
|
-
}
|
|
2826
|
-
node.children.forEach((childNode) => addChildNode(indexToAdd, parentNodeId, nodeToAdd, childNode));
|
|
2827
|
-
}
|
|
2828
|
-
function reorderChildNode(oldIndex, newIndex, parentNodeId, node) {
|
|
2829
|
-
if (node.data.id === parentNodeId) {
|
|
2830
|
-
// Remove the child from the old position
|
|
2831
|
-
const [childToMove] = node.children.splice(oldIndex, 1);
|
|
2832
|
-
// Insert the child at the new position
|
|
2833
|
-
node.children.splice(newIndex, 0, childToMove);
|
|
2834
|
-
return;
|
|
2835
|
-
}
|
|
2836
|
-
node.children.forEach((childNode) => reorderChildNode(oldIndex, newIndex, parentNodeId, childNode));
|
|
2837
|
-
}
|
|
2838
|
-
function reparentChildNode(oldIndex, newIndex, sourceNodeId, destinationNodeId, node) {
|
|
2839
|
-
const nodeToMove = getChildFromTree(sourceNodeId, oldIndex, node);
|
|
2840
|
-
if (!nodeToMove) {
|
|
2841
|
-
return;
|
|
2622
|
+
super.fetchEntries(missingEntryIds, skipCache),
|
|
2623
|
+
super.fetchAssets(missingAssetIds, skipCache),
|
|
2624
|
+
]);
|
|
2842
2625
|
}
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2626
|
+
getMissingEntityIds(entityLinks) {
|
|
2627
|
+
const entryLinks = entityLinks.filter((link) => link.sys?.linkType === 'Entry');
|
|
2628
|
+
const assetLinks = entityLinks.filter((link) => link.sys?.linkType === 'Asset');
|
|
2629
|
+
const uniqueEntryIds = [...new Set(entryLinks.map((link) => link.sys.id))];
|
|
2630
|
+
const uniqueAssetIds = [...new Set(assetLinks.map((link) => link.sys.id))];
|
|
2631
|
+
const { missing: missingEntryIds } = this.getEntitiesFromMap('Entry', uniqueEntryIds);
|
|
2632
|
+
const { missing: missingAssetIds } = this.getEntitiesFromMap('Asset', uniqueAssetIds);
|
|
2633
|
+
return { missingEntryIds, missingAssetIds };
|
|
2850
2634
|
}
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
return null;
|
|
2635
|
+
getValue(entityLinkOrEntity, path) {
|
|
2636
|
+
const entity = this.getEntryOrAsset(entityLinkOrEntity, path.join('/'));
|
|
2637
|
+
if (!entity) {
|
|
2638
|
+
return;
|
|
2856
2639
|
}
|
|
2857
|
-
const
|
|
2858
|
-
return
|
|
2640
|
+
const fieldValue = get(entity, path);
|
|
2641
|
+
return transformAssetFileToUrl(fieldValue);
|
|
2859
2642
|
}
|
|
2860
|
-
return {
|
|
2861
|
-
type: TreeAction.REPLACE_NODE,
|
|
2862
|
-
originalId: currentNode.children[index].data.id,
|
|
2863
|
-
indexToReplace: index,
|
|
2864
|
-
node: child,
|
|
2865
|
-
};
|
|
2866
2643
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2644
|
+
|
|
2645
|
+
var VisualEditorMode$1;
|
|
2646
|
+
(function (VisualEditorMode) {
|
|
2647
|
+
VisualEditorMode["LazyLoad"] = "lazyLoad";
|
|
2648
|
+
VisualEditorMode["InjectScript"] = "injectScript";
|
|
2649
|
+
})(VisualEditorMode$1 || (VisualEditorMode$1 = {}));
|
|
2650
|
+
|
|
2651
|
+
class DeepReference {
|
|
2652
|
+
constructor({ path, dataSource }) {
|
|
2653
|
+
const { key, field, referentField } = parseDataSourcePathWithL1DeepBindings(path);
|
|
2654
|
+
this.originalPath = path;
|
|
2655
|
+
this.entityId = dataSource[key].sys.id;
|
|
2656
|
+
this.entityLink = dataSource[key];
|
|
2657
|
+
this.field = field;
|
|
2658
|
+
this.referentField = referentField;
|
|
2875
2659
|
}
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
function compareNodes({ currentNode, updatedNode, originalTree, differences = [], }) {
|
|
2879
|
-
// In the end, this map contains the list of nodes that are not present
|
|
2880
|
-
// in the updated tree and must be removed
|
|
2881
|
-
const map = new Map();
|
|
2882
|
-
if (!currentNode || !updatedNode) {
|
|
2883
|
-
return differences;
|
|
2660
|
+
get headEntityId() {
|
|
2661
|
+
return this.entityId;
|
|
2884
2662
|
}
|
|
2885
|
-
// On each tree level, consider only the children of the current node to differentiate between added, removed, or replaced case
|
|
2886
|
-
const currentNodeCount = currentNode.children.length;
|
|
2887
|
-
const updatedNodeCount = updatedNode.children.length;
|
|
2888
|
-
const nodeRemoved = currentNodeCount > updatedNodeCount;
|
|
2889
|
-
const nodeAdded = currentNodeCount < updatedNodeCount;
|
|
2890
|
-
const parentNodeId = updatedNode.data.id;
|
|
2891
2663
|
/**
|
|
2892
|
-
*
|
|
2893
|
-
*
|
|
2664
|
+
* Extracts referent from the path, using EntityStore as source of
|
|
2665
|
+
* entities during the resolution path.
|
|
2894
2666
|
*/
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
}
|
|
2902
|
-
// Map children of the first tree by their ID
|
|
2903
|
-
currentNode.children.forEach((child, index) => map.set(child.data.id, index));
|
|
2904
|
-
// Compare with the second tree
|
|
2905
|
-
updatedNode.children.forEach((child, index) => {
|
|
2906
|
-
const childId = child.data.id;
|
|
2907
|
-
// The original tree does not have this node in the updated tree.
|
|
2908
|
-
if (!map.has(childId)) {
|
|
2909
|
-
const diff = missingNodeAction({
|
|
2910
|
-
index,
|
|
2911
|
-
child,
|
|
2912
|
-
nodeAdded,
|
|
2913
|
-
parentNodeId,
|
|
2914
|
-
tree: originalTree,
|
|
2915
|
-
currentNode,
|
|
2916
|
-
});
|
|
2917
|
-
if (diff?.type === TreeAction.REPLACE_NODE) {
|
|
2918
|
-
// Remove it from the deletion map to avoid adding another REMOVE_NODE action
|
|
2919
|
-
map.delete(diff.originalId);
|
|
2920
|
-
}
|
|
2921
|
-
return differences.push(diff);
|
|
2667
|
+
extractReferent(entityStore) {
|
|
2668
|
+
const headEntity = entityStore.getEntityFromLink(this.entityLink);
|
|
2669
|
+
const maybeReferentLink = headEntity?.fields[this.field];
|
|
2670
|
+
if (undefined === maybeReferentLink) {
|
|
2671
|
+
// field references nothing (or even field doesn't exist)
|
|
2672
|
+
return undefined;
|
|
2922
2673
|
}
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
nodeRemoved,
|
|
2929
|
-
parentNodeId,
|
|
2930
|
-
});
|
|
2931
|
-
differences.push(diff);
|
|
2932
|
-
map.delete(childId);
|
|
2933
|
-
compareNodes({
|
|
2934
|
-
currentNode: currentNode.children[originalIndex],
|
|
2935
|
-
updatedNode: child,
|
|
2936
|
-
originalTree,
|
|
2937
|
-
differences,
|
|
2938
|
-
});
|
|
2939
|
-
});
|
|
2940
|
-
map.forEach((index, key) => {
|
|
2941
|
-
// If the node count of the entire tree doesn't signify
|
|
2942
|
-
// a node was removed, don't add that as a diff
|
|
2943
|
-
if (!nodeRemoved) {
|
|
2944
|
-
return;
|
|
2674
|
+
if (!isLink(maybeReferentLink)) {
|
|
2675
|
+
// Scenario of "impostor referent", where one of the deepPath's segments is not a Link but some other type
|
|
2676
|
+
// Under normal circumstance we expect field to be a Link, but it could be an "impostor"
|
|
2677
|
+
// eg. `Text` or `Number` or anything like that; could be due to CT changes or manual path creation via CMA
|
|
2678
|
+
return undefined;
|
|
2945
2679
|
}
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
idToRemove: key,
|
|
2952
|
-
});
|
|
2953
|
-
});
|
|
2954
|
-
return differences;
|
|
2680
|
+
return maybeReferentLink;
|
|
2681
|
+
}
|
|
2682
|
+
static from(opt) {
|
|
2683
|
+
return new DeepReference(opt);
|
|
2684
|
+
}
|
|
2955
2685
|
}
|
|
2956
|
-
function
|
|
2957
|
-
const
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2686
|
+
function gatherDeepReferencesFromTree(startingNode, dataSource) {
|
|
2687
|
+
const deepReferences = [];
|
|
2688
|
+
treeVisit(startingNode, (node) => {
|
|
2689
|
+
if (!node.data.props)
|
|
2690
|
+
return;
|
|
2691
|
+
for (const [, variableMapping] of Object.entries(node.data.props)) {
|
|
2692
|
+
if (variableMapping.type !== 'BoundValue')
|
|
2693
|
+
continue;
|
|
2694
|
+
if (!isDeepPath(variableMapping.path))
|
|
2695
|
+
continue;
|
|
2696
|
+
deepReferences.push(DeepReference.from({
|
|
2697
|
+
path: variableMapping.path,
|
|
2698
|
+
dataSource,
|
|
2699
|
+
}));
|
|
2700
|
+
}
|
|
2963
2701
|
});
|
|
2964
|
-
return
|
|
2702
|
+
return deepReferences;
|
|
2965
2703
|
}
|
|
2966
2704
|
|
|
2967
2705
|
const useTreeStore = create((set, get) => ({
|
|
@@ -2995,20 +2733,6 @@ const useTreeStore = create((set, get) => ({
|
|
|
2995
2733
|
});
|
|
2996
2734
|
}));
|
|
2997
2735
|
},
|
|
2998
|
-
/**
|
|
2999
|
-
* NOTE: this is for debugging purposes only as it causes ugly canvas flash.
|
|
3000
|
-
*
|
|
3001
|
-
* Force updates entire tree. Usually shouldn't be used as updateTree()
|
|
3002
|
-
* uses smart update algorithm based on diffs. But for troubleshooting
|
|
3003
|
-
* you may want to force update the tree so leaving this in.
|
|
3004
|
-
*/
|
|
3005
|
-
updateTreeForced: (tree) => {
|
|
3006
|
-
set({
|
|
3007
|
-
tree,
|
|
3008
|
-
// Breakpoints must be updated, as we receive completely new tree with possibly new breakpoints
|
|
3009
|
-
breakpoints: tree?.root?.data?.breakpoints || [],
|
|
3010
|
-
});
|
|
3011
|
-
},
|
|
3012
2736
|
updateTree: (tree) => {
|
|
3013
2737
|
const currentTree = get().tree;
|
|
3014
2738
|
/**
|
|
@@ -3054,21 +2778,6 @@ const useTreeStore = create((set, get) => ({
|
|
|
3054
2778
|
state.breakpoints = tree?.root?.data?.breakpoints || [];
|
|
3055
2779
|
}));
|
|
3056
2780
|
},
|
|
3057
|
-
addChild: (index, parentId, node) => {
|
|
3058
|
-
set(produce((state) => {
|
|
3059
|
-
addChildNode(index, parentId, node, state.tree.root);
|
|
3060
|
-
}));
|
|
3061
|
-
},
|
|
3062
|
-
reorderChildren: (destinationIndex, destinationParentId, sourceIndex) => {
|
|
3063
|
-
set(produce((state) => {
|
|
3064
|
-
reorderChildNode(sourceIndex, destinationIndex, destinationParentId, state.tree.root);
|
|
3065
|
-
}));
|
|
3066
|
-
},
|
|
3067
|
-
reparentChild: (destinationIndex, destinationParentId, sourceIndex, sourceParentId) => {
|
|
3068
|
-
set(produce((state) => {
|
|
3069
|
-
reparentChildNode(sourceIndex, destinationIndex, sourceParentId, destinationParentId, state.tree.root);
|
|
3070
|
-
}));
|
|
3071
|
-
},
|
|
3072
2781
|
}));
|
|
3073
2782
|
const hasBreakpointDiffs = (currentTree, newTree) => {
|
|
3074
2783
|
const currentBreakpoints = currentTree?.root?.data?.breakpoints ?? [];
|
|
@@ -3086,8 +2795,8 @@ const cloneDeepAsPOJO = (obj) => {
|
|
|
3086
2795
|
return JSON.parse(JSON.stringify(obj));
|
|
3087
2796
|
};
|
|
3088
2797
|
|
|
3089
|
-
var css_248z$a = ".
|
|
3090
|
-
var styles$
|
|
2798
|
+
var css_248z$a = ".RootRenderer-module_rootContainer__9UawM {\n position: relative;\n display: flex;\n flex-direction: column;\n}\n\nbody {\n margin: 0;\n}\n\nhtml {\n -ms-overflow-style: none; /* Internet Explorer 10+ */\n scrollbar-width: none; /* Firefox */\n}\n\nhtml::-webkit-scrollbar {\n display: none;\n}\n";
|
|
2799
|
+
var styles$2 = {"rootContainer":"RootRenderer-module_rootContainer__9UawM"};
|
|
3091
2800
|
styleInject(css_248z$a);
|
|
3092
2801
|
|
|
3093
2802
|
// TODO: In order to support integrations without React, we should extract this heavy logic into simple
|
|
@@ -3126,66 +2835,6 @@ const useBreakpoints = (breakpoints) => {
|
|
|
3126
2835
|
return { resolveDesignValue };
|
|
3127
2836
|
};
|
|
3128
2837
|
|
|
3129
|
-
/**
|
|
3130
|
-
* This function gets the element co-ordinates of a specified component in the DOM and its parent
|
|
3131
|
-
* and sends the DOM Rect to the client app
|
|
3132
|
-
*/
|
|
3133
|
-
const sendSelectedComponentCoordinates = (instanceId) => {
|
|
3134
|
-
const selection = getSelectionNodes(instanceId);
|
|
3135
|
-
if (selection?.target) {
|
|
3136
|
-
const sendUpdateSelectedComponentCoordinates = () => {
|
|
3137
|
-
sendMessage(OUTGOING_EVENTS.UpdateSelectedComponentCoordinates, {
|
|
3138
|
-
selectedNodeCoordinates: getElementCoordinates(selection.target),
|
|
3139
|
-
selectedAssemblyChildCoordinates: selection.patternChild
|
|
3140
|
-
? getElementCoordinates(selection.patternChild)
|
|
3141
|
-
: undefined,
|
|
3142
|
-
parentCoordinates: selection.parent ? getElementCoordinates(selection.parent) : undefined,
|
|
3143
|
-
});
|
|
3144
|
-
};
|
|
3145
|
-
// If the target contains an image, wait for this image to be loaded before sending the coordinates
|
|
3146
|
-
const childImage = selection.target.querySelector('img');
|
|
3147
|
-
if (childImage) {
|
|
3148
|
-
const handleImageLoad = () => {
|
|
3149
|
-
sendUpdateSelectedComponentCoordinates();
|
|
3150
|
-
childImage.removeEventListener('load', handleImageLoad);
|
|
3151
|
-
};
|
|
3152
|
-
childImage.addEventListener('load', handleImageLoad);
|
|
3153
|
-
}
|
|
3154
|
-
sendUpdateSelectedComponentCoordinates();
|
|
3155
|
-
}
|
|
3156
|
-
};
|
|
3157
|
-
const getSelectionNodes = (instanceId) => {
|
|
3158
|
-
if (!instanceId)
|
|
3159
|
-
return;
|
|
3160
|
-
let selectedNode = document.querySelector(`[data-cf-node-id="${instanceId}"]`);
|
|
3161
|
-
let selectedPatternChild = null;
|
|
3162
|
-
let selectedParent = null;
|
|
3163
|
-
// Use RegEx instead of split to match the last occurrence of '---' in the instanceId instead of the first one
|
|
3164
|
-
const idMatch = instanceId.match(/(.*)---(.*)/);
|
|
3165
|
-
const rootNodeId = idMatch?.[1] ?? instanceId;
|
|
3166
|
-
const nodeLocation = idMatch?.[2];
|
|
3167
|
-
const isNestedPattern = nodeLocation && selectedNode?.dataset?.cfNodeBlockType === ASSEMBLY_NODE_TYPE;
|
|
3168
|
-
const isPatternChild = !isNestedPattern && nodeLocation;
|
|
3169
|
-
if (isPatternChild) {
|
|
3170
|
-
// For pattern child nodes, render the pattern itself as selected component
|
|
3171
|
-
selectedPatternChild = selectedNode;
|
|
3172
|
-
selectedNode = document.querySelector(`[data-cf-node-id="${rootNodeId}"]`);
|
|
3173
|
-
}
|
|
3174
|
-
else if (isNestedPattern) {
|
|
3175
|
-
// For nested patterns, return the upper pattern as parent
|
|
3176
|
-
selectedParent = document.querySelector(`[data-cf-node-id="${rootNodeId}"]`);
|
|
3177
|
-
}
|
|
3178
|
-
else {
|
|
3179
|
-
// Find the next valid parent of the selected element
|
|
3180
|
-
selectedParent = selectedNode?.parentElement ?? null;
|
|
3181
|
-
// Ensure that the selection parent is a VisualEditorBlock
|
|
3182
|
-
while (selectedParent && !selectedParent.dataset?.cfNodeId) {
|
|
3183
|
-
selectedParent = selectedParent?.parentElement;
|
|
3184
|
-
}
|
|
3185
|
-
}
|
|
3186
|
-
return { target: selectedNode, patternChild: selectedPatternChild, parent: selectedParent };
|
|
3187
|
-
};
|
|
3188
|
-
|
|
3189
2838
|
// Note: During development, the hot reloading might empty this and it
|
|
3190
2839
|
// stays empty leading to not rendering assemblies. Ideally, this is
|
|
3191
2840
|
// integrated into the state machine to keep track of its state.
|
|
@@ -3219,14 +2868,10 @@ const useEditorStore = create((set, get) => ({
|
|
|
3219
2868
|
dataSource: {},
|
|
3220
2869
|
hyperLinkPattern: undefined,
|
|
3221
2870
|
unboundValues: {},
|
|
3222
|
-
selectedNodeId: null,
|
|
3223
2871
|
locale: null,
|
|
3224
2872
|
setHyperLinkPattern: (pattern) => {
|
|
3225
2873
|
set({ hyperLinkPattern: pattern });
|
|
3226
2874
|
},
|
|
3227
|
-
setSelectedNodeId: (id) => {
|
|
3228
|
-
set({ selectedNodeId: id });
|
|
3229
|
-
},
|
|
3230
2875
|
setDataSource(data) {
|
|
3231
2876
|
const dataSource = get().dataSource;
|
|
3232
2877
|
const newDataSource = { ...dataSource, ...data };
|
|
@@ -3258,6 +2903,7 @@ const useEditorStore = create((set, get) => ({
|
|
|
3258
2903
|
var css_248z$8 = "/* Initially added with PR #253 for each component, this is now a global setting\n * It is recommended on MDN to use this as a default for layouting.\n*/\n* {\n box-sizing: border-box;\n}\n";
|
|
3259
2904
|
styleInject(css_248z$8);
|
|
3260
2905
|
|
|
2906
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
3261
2907
|
/**
|
|
3262
2908
|
* These modes are ONLY intended to be internally used within the context of
|
|
3263
2909
|
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
@@ -3386,17 +3032,16 @@ const PrimitiveValueSchema = z.union([
|
|
|
3386
3032
|
z.record(z.any(), z.any()),
|
|
3387
3033
|
z.undefined(),
|
|
3388
3034
|
]);
|
|
3035
|
+
const UsedComponentsSchema = z.array(z.object({
|
|
3036
|
+
sys: z.object({
|
|
3037
|
+
type: z.literal('Link'),
|
|
3038
|
+
id: z.string(),
|
|
3039
|
+
linkType: z.literal('Entry'),
|
|
3040
|
+
}),
|
|
3041
|
+
}));
|
|
3389
3042
|
const uuidKeySchema = z
|
|
3390
3043
|
.string()
|
|
3391
3044
|
.regex(/^[a-zA-Z0-9-_]{1,21}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,21}$/' });
|
|
3392
|
-
/**
|
|
3393
|
-
* Property keys for imported components have a limit of 32 characters (to be implemented) while
|
|
3394
|
-
* property keys for patterns have a limit of 54 characters (<32-char-variabl-name>_<21-char-nanoid-id>).
|
|
3395
|
-
* Because we cannot distinguish between the two in the componentTree, we will use the larger limit for both.
|
|
3396
|
-
*/
|
|
3397
|
-
const propertyKeySchema = z
|
|
3398
|
-
.string()
|
|
3399
|
-
.regex(/^[a-zA-Z0-9-_]{1,54}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,54}$/' });
|
|
3400
3045
|
const DataSourceSchema = z.record(uuidKeySchema, z.object({
|
|
3401
3046
|
sys: z.object({
|
|
3402
3047
|
type: z.literal('Link'),
|
|
@@ -3404,7 +3049,62 @@ const DataSourceSchema = z.record(uuidKeySchema, z.object({
|
|
|
3404
3049
|
linkType: z.enum(['Entry', 'Asset']),
|
|
3405
3050
|
}),
|
|
3406
3051
|
}));
|
|
3052
|
+
const UnboundValuesSchema = z.record(uuidKeySchema, z.object({
|
|
3053
|
+
value: PrimitiveValueSchema,
|
|
3054
|
+
}));
|
|
3055
|
+
/**
|
|
3056
|
+
* Property keys for imported components have a limit of 32 characters (to be implemented) while
|
|
3057
|
+
* property keys for patterns have a limit of 54 characters (<32-char-variable-name>_<21-char-nanoid-id>).
|
|
3058
|
+
* Because we cannot distinguish between the two in the componentTree, we will use the larger limit for both.
|
|
3059
|
+
*/
|
|
3060
|
+
const propertyKeySchema = z
|
|
3061
|
+
.string()
|
|
3062
|
+
.regex(/^[a-zA-Z0-9-_]{1,54}$/, { message: 'Does not match /^[a-zA-Z0-9-_]{1,54}$/' });
|
|
3063
|
+
const ComponentTreeNodeIdSchema = z
|
|
3064
|
+
.string()
|
|
3065
|
+
.regex(/^[a-zA-Z0-9]{1,8}$/, { message: 'Does not match /^[a-zA-Z0-9]{1,8}$/' });
|
|
3066
|
+
const breakpointsRefinement = (value, ctx) => {
|
|
3067
|
+
if (!value.length || value[0].query !== '*') {
|
|
3068
|
+
ctx.addIssue({
|
|
3069
|
+
code: z.ZodIssueCode.custom,
|
|
3070
|
+
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
3071
|
+
});
|
|
3072
|
+
}
|
|
3073
|
+
const hasDuplicateIds = value.some((currentBreakpoint, currentBreakpointIndex) => {
|
|
3074
|
+
// check if the current breakpoint id is found in the rest of the array
|
|
3075
|
+
const breakpointIndex = value.findIndex((breakpoint) => breakpoint.id === currentBreakpoint.id);
|
|
3076
|
+
return breakpointIndex !== currentBreakpointIndex;
|
|
3077
|
+
});
|
|
3078
|
+
if (hasDuplicateIds) {
|
|
3079
|
+
ctx.addIssue({
|
|
3080
|
+
code: z.ZodIssueCode.custom,
|
|
3081
|
+
message: `Breakpoint IDs must be unique`,
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
// Extract the queries boundary by removing the special characters around it
|
|
3085
|
+
const queries = value.map((bp) => bp.query === '*' ? bp.query : parseInt(bp.query.replace(/px|<|>/, '')));
|
|
3086
|
+
// sort updates queries array in place so we need to create a copy
|
|
3087
|
+
const originalQueries = [...queries];
|
|
3088
|
+
queries.sort((q1, q2) => {
|
|
3089
|
+
if (q1 === '*') {
|
|
3090
|
+
return -1;
|
|
3091
|
+
}
|
|
3092
|
+
if (q2 === '*') {
|
|
3093
|
+
return 1;
|
|
3094
|
+
}
|
|
3095
|
+
return q1 > q2 ? -1 : 1;
|
|
3096
|
+
});
|
|
3097
|
+
if (originalQueries.join('') !== queries.join('')) {
|
|
3098
|
+
ctx.addIssue({
|
|
3099
|
+
code: z.ZodIssueCode.custom,
|
|
3100
|
+
message: `Breakpoints should be ordered from largest to smallest pixel value`,
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
3103
|
+
};
|
|
3407
3104
|
const ValuesByBreakpointSchema = z.record(z.lazy(() => PrimitiveValueSchema));
|
|
3105
|
+
const BindingSourceTypeEnumSchema = z
|
|
3106
|
+
.array(z.enum(['entry', 'asset', 'manual', 'experience']))
|
|
3107
|
+
.nonempty();
|
|
3408
3108
|
const DesignValueSchema = z
|
|
3409
3109
|
.object({
|
|
3410
3110
|
type: z.literal('DesignValue'),
|
|
@@ -3437,8 +3137,6 @@ const ComponentValueSchema = z
|
|
|
3437
3137
|
key: z.string(),
|
|
3438
3138
|
})
|
|
3439
3139
|
.strict();
|
|
3440
|
-
// TODO: finalize schema structure before release
|
|
3441
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3442
3140
|
const NoValueSchema = z.object({ type: z.literal('NoValue') }).strict();
|
|
3443
3141
|
const ComponentPropertyValueSchema = z.discriminatedUnion('type', [
|
|
3444
3142
|
DesignValueSchema,
|
|
@@ -3450,41 +3148,12 @@ const ComponentPropertyValueSchema = z.discriminatedUnion('type', [
|
|
|
3450
3148
|
]);
|
|
3451
3149
|
// TODO: finalize schema structure before release
|
|
3452
3150
|
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3453
|
-
const VariableMappingSchema = z.object({
|
|
3454
|
-
patternPropertyDefinitionId: propertyKeySchema,
|
|
3455
|
-
type: z.literal('ContentTypeMapping'),
|
|
3456
|
-
pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
|
|
3457
|
-
});
|
|
3458
|
-
const VariableMappingsSchema = z.record(propertyKeySchema, VariableMappingSchema);
|
|
3459
|
-
// TODO: finalize schema structure before release
|
|
3460
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3461
|
-
const PatternPropertyDefinitionSchema = z.object({
|
|
3462
|
-
defaultValue: z
|
|
3463
|
-
.record(z.string(), z.object({
|
|
3464
|
-
sys: z.object({
|
|
3465
|
-
type: z.literal('Link'),
|
|
3466
|
-
id: z.string(),
|
|
3467
|
-
linkType: z.enum(['Entry']),
|
|
3468
|
-
}),
|
|
3469
|
-
}))
|
|
3470
|
-
.optional(),
|
|
3471
|
-
contentTypes: z.record(z.string(), z.object({
|
|
3472
|
-
sys: z.object({
|
|
3473
|
-
type: z.literal('Link'),
|
|
3474
|
-
id: z.string(),
|
|
3475
|
-
linkType: z.enum(['ContentType']),
|
|
3476
|
-
}),
|
|
3477
|
-
})),
|
|
3478
|
-
});
|
|
3479
|
-
const PatternPropertyDefinitionsSchema = z.record(propertyKeySchema, PatternPropertyDefinitionSchema);
|
|
3480
|
-
// TODO: finalize schema structure before release
|
|
3481
|
-
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3482
3151
|
const PatternPropertySchema = z.object({
|
|
3483
3152
|
type: z.literal('BoundValue'),
|
|
3484
3153
|
path: z.string(),
|
|
3485
3154
|
contentType: z.string(),
|
|
3486
3155
|
});
|
|
3487
|
-
const
|
|
3156
|
+
const PatternPropertiesSchema = z.record(propertyKeySchema, PatternPropertySchema);
|
|
3488
3157
|
const BreakpointSchema = z
|
|
3489
3158
|
.object({
|
|
3490
3159
|
id: propertyKeySchema,
|
|
@@ -3494,12 +3163,6 @@ const BreakpointSchema = z
|
|
|
3494
3163
|
displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
|
|
3495
3164
|
})
|
|
3496
3165
|
.strict();
|
|
3497
|
-
const UnboundValuesSchema = z.record(uuidKeySchema, z.object({
|
|
3498
|
-
value: PrimitiveValueSchema,
|
|
3499
|
-
}));
|
|
3500
|
-
const ComponentTreeNodeIdSchema = z
|
|
3501
|
-
.string()
|
|
3502
|
-
.regex(/^[a-zA-Z0-9]{1,8}$/, { message: 'Does not match /^[a-zA-Z0-9]{1,8}$/' });
|
|
3503
3166
|
// Use helper schema to define a recursive schema with its type correctly below
|
|
3504
3167
|
const BaseComponentTreeNodeSchema = z.object({
|
|
3505
3168
|
id: ComponentTreeNodeIdSchema.optional(),
|
|
@@ -3507,14 +3170,8 @@ const BaseComponentTreeNodeSchema = z.object({
|
|
|
3507
3170
|
displayName: z.string().optional(),
|
|
3508
3171
|
slotId: z.string().optional(),
|
|
3509
3172
|
variables: z.record(propertyKeySchema, ComponentPropertyValueSchema),
|
|
3510
|
-
patternProperties:
|
|
3511
|
-
});
|
|
3512
|
-
const ComponentTreeNodeSchema = BaseComponentTreeNodeSchema.extend({
|
|
3513
|
-
children: z.lazy(() => ComponentTreeNodeSchema.array()),
|
|
3173
|
+
patternProperties: PatternPropertiesSchema.optional(),
|
|
3514
3174
|
});
|
|
3515
|
-
const BindingSourceTypeEnumSchema = z
|
|
3516
|
-
.array(z.enum(['entry', 'asset', 'manual', 'experience']))
|
|
3517
|
-
.nonempty();
|
|
3518
3175
|
const ComponentVariableSchema = z.object({
|
|
3519
3176
|
displayName: z.string().optional(),
|
|
3520
3177
|
type: DefinitionPropertyTypeSchema,
|
|
@@ -3535,8 +3192,25 @@ const ComponentVariableSchema = z.object({
|
|
|
3535
3192
|
})
|
|
3536
3193
|
.optional(),
|
|
3537
3194
|
});
|
|
3538
|
-
const
|
|
3539
|
-
|
|
3195
|
+
const ComponentTreeNodeSchema = BaseComponentTreeNodeSchema.extend({
|
|
3196
|
+
children: z.lazy(() => ComponentTreeNodeSchema.array()),
|
|
3197
|
+
});
|
|
3198
|
+
const ComponentTreeSchema = z
|
|
3199
|
+
.object({
|
|
3200
|
+
breakpoints: z.array(BreakpointSchema).superRefine(breakpointsRefinement),
|
|
3201
|
+
children: z.array(ComponentTreeNodeSchema),
|
|
3202
|
+
schemaVersion: SchemaVersions,
|
|
3203
|
+
})
|
|
3204
|
+
.strict();
|
|
3205
|
+
const localeWrapper = (fieldSchema) => z.record(z.string(), fieldSchema);
|
|
3206
|
+
|
|
3207
|
+
z.object({
|
|
3208
|
+
componentTree: localeWrapper(ComponentTreeSchema),
|
|
3209
|
+
dataSource: localeWrapper(DataSourceSchema),
|
|
3210
|
+
unboundValues: localeWrapper(UnboundValuesSchema),
|
|
3211
|
+
usedComponents: localeWrapper(UsedComponentsSchema).optional(),
|
|
3212
|
+
});
|
|
3213
|
+
|
|
3540
3214
|
const THUMBNAIL_IDS = [
|
|
3541
3215
|
'columns',
|
|
3542
3216
|
'columnsPlusRight',
|
|
@@ -3562,6 +3236,37 @@ const THUMBNAIL_IDS = [
|
|
|
3562
3236
|
'textColumns',
|
|
3563
3237
|
'duplex',
|
|
3564
3238
|
];
|
|
3239
|
+
// TODO: finalize schema structure before release
|
|
3240
|
+
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3241
|
+
const VariableMappingSchema = z.object({
|
|
3242
|
+
patternPropertyDefinitionId: propertyKeySchema,
|
|
3243
|
+
type: z.literal('ContentTypeMapping'),
|
|
3244
|
+
pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
|
|
3245
|
+
});
|
|
3246
|
+
// TODO: finalize schema structure before release
|
|
3247
|
+
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
3248
|
+
const PatternPropertyDefinitionSchema = z.object({
|
|
3249
|
+
defaultValue: z
|
|
3250
|
+
.record(z.string(), z.object({
|
|
3251
|
+
sys: z.object({
|
|
3252
|
+
type: z.literal('Link'),
|
|
3253
|
+
id: z.string(),
|
|
3254
|
+
linkType: z.enum(['Entry']),
|
|
3255
|
+
}),
|
|
3256
|
+
}))
|
|
3257
|
+
.optional(),
|
|
3258
|
+
contentTypes: z.record(z.string(), z.object({
|
|
3259
|
+
sys: z.object({
|
|
3260
|
+
type: z.literal('Link'),
|
|
3261
|
+
id: z.string(),
|
|
3262
|
+
linkType: z.enum(['ContentType']),
|
|
3263
|
+
}),
|
|
3264
|
+
})),
|
|
3265
|
+
});
|
|
3266
|
+
const PatternPropertyDefinitionsSchema = z.record(propertyKeySchema, PatternPropertyDefinitionSchema);
|
|
3267
|
+
const VariableMappingsSchema = z.record(propertyKeySchema, VariableMappingSchema);
|
|
3268
|
+
const ComponentVariablesSchema = z.record(z.string().regex(/^[a-zA-Z0-9-_]{1,54}$/), // Here the key is <variableName>_<nanoidId> so we need to allow for a longer length
|
|
3269
|
+
ComponentVariableSchema);
|
|
3565
3270
|
const ComponentSettingsSchema = z.object({
|
|
3566
3271
|
variableDefinitions: ComponentVariablesSchema,
|
|
3567
3272
|
thumbnailId: z.enum(THUMBNAIL_IDS).optional(),
|
|
@@ -3569,65 +3274,12 @@ const ComponentSettingsSchema = z.object({
|
|
|
3569
3274
|
variableMappings: VariableMappingsSchema.optional(),
|
|
3570
3275
|
patternPropertyDefinitions: PatternPropertyDefinitionsSchema.optional(),
|
|
3571
3276
|
});
|
|
3572
|
-
const UsedComponentsSchema = z.array(z.object({
|
|
3573
|
-
sys: z.object({
|
|
3574
|
-
type: z.literal('Link'),
|
|
3575
|
-
id: z.string(),
|
|
3576
|
-
linkType: z.literal('Entry'),
|
|
3577
|
-
}),
|
|
3578
|
-
}));
|
|
3579
|
-
const breakpointsRefinement = (value, ctx) => {
|
|
3580
|
-
if (!value.length || value[0].query !== '*') {
|
|
3581
|
-
ctx.addIssue({
|
|
3582
|
-
code: z.ZodIssueCode.custom,
|
|
3583
|
-
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
3584
|
-
});
|
|
3585
|
-
}
|
|
3586
|
-
const hasDuplicateIds = value.some((currentBreakpoint, currentBreakpointIndex) => {
|
|
3587
|
-
// check if the current breakpoint id is found in the rest of the array
|
|
3588
|
-
const breakpointIndex = value.findIndex((breakpoint) => breakpoint.id === currentBreakpoint.id);
|
|
3589
|
-
return breakpointIndex !== currentBreakpointIndex;
|
|
3590
|
-
});
|
|
3591
|
-
if (hasDuplicateIds) {
|
|
3592
|
-
ctx.addIssue({
|
|
3593
|
-
code: z.ZodIssueCode.custom,
|
|
3594
|
-
message: `Breakpoint IDs must be unique`,
|
|
3595
|
-
});
|
|
3596
|
-
}
|
|
3597
|
-
// Extract the queries boundary by removing the special characters around it
|
|
3598
|
-
const queries = value.map((bp) => bp.query === '*' ? bp.query : parseInt(bp.query.replace(/px|<|>/, '')));
|
|
3599
|
-
// sort updates queries array in place so we need to create a copy
|
|
3600
|
-
const originalQueries = [...queries];
|
|
3601
|
-
queries.sort((q1, q2) => {
|
|
3602
|
-
if (q1 === '*') {
|
|
3603
|
-
return -1;
|
|
3604
|
-
}
|
|
3605
|
-
if (q2 === '*') {
|
|
3606
|
-
return 1;
|
|
3607
|
-
}
|
|
3608
|
-
return q1 > q2 ? -1 : 1;
|
|
3609
|
-
});
|
|
3610
|
-
if (originalQueries.join('') !== queries.join('')) {
|
|
3611
|
-
ctx.addIssue({
|
|
3612
|
-
code: z.ZodIssueCode.custom,
|
|
3613
|
-
message: `Breakpoints should be ordered from largest to smallest pixel value`,
|
|
3614
|
-
});
|
|
3615
|
-
}
|
|
3616
|
-
};
|
|
3617
|
-
const ComponentTreeSchema = z
|
|
3618
|
-
.object({
|
|
3619
|
-
breakpoints: z.array(BreakpointSchema).superRefine(breakpointsRefinement),
|
|
3620
|
-
children: z.array(ComponentTreeNodeSchema),
|
|
3621
|
-
schemaVersion: SchemaVersions,
|
|
3622
|
-
})
|
|
3623
|
-
.strict();
|
|
3624
|
-
const localeWrapper = (fieldSchema) => z.record(z.string(), fieldSchema);
|
|
3625
3277
|
z.object({
|
|
3626
3278
|
componentTree: localeWrapper(ComponentTreeSchema),
|
|
3627
3279
|
dataSource: localeWrapper(DataSourceSchema),
|
|
3628
3280
|
unboundValues: localeWrapper(UnboundValuesSchema),
|
|
3629
3281
|
usedComponents: localeWrapper(UsedComponentsSchema).optional(),
|
|
3630
|
-
componentSettings: localeWrapper(ComponentSettingsSchema)
|
|
3282
|
+
componentSettings: localeWrapper(ComponentSettingsSchema),
|
|
3631
3283
|
});
|
|
3632
3284
|
|
|
3633
3285
|
z.object({
|
|
@@ -3804,8 +3456,8 @@ var VisualEditorMode;
|
|
|
3804
3456
|
VisualEditorMode["InjectScript"] = "injectScript";
|
|
3805
3457
|
})(VisualEditorMode || (VisualEditorMode = {}));
|
|
3806
3458
|
|
|
3807
|
-
var css_248z$2
|
|
3808
|
-
styleInject(css_248z$2
|
|
3459
|
+
var css_248z$2 = ".contentful-container {\n position: relative;\n display: flex;\n box-sizing: border-box;\n pointer-events: all;\n}\n\n.contentful-container::-webkit-scrollbar {\n display: none; /* Safari and Chrome */\n}\n\n.cf-container-wrapper {\n position: relative;\n width: 100%;\n}\n\n.contentful-container:after {\n content: '';\n display: block;\n position: absolute;\n pointer-events: none;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow-x: clip;\n font-family: var(--exp-builder-font-stack-primary);\n font-size: 12px;\n color: var(--exp-builder-gray400);\n z-index: 1;\n}\n\n.contentful-section-label:after {\n content: 'Section';\n}\n\n.contentful-container-label:after {\n content: 'Container';\n}\n\n/* used by ContentfulSectionAsHyperlink.tsx */\n\n.contentful-container-link,\n.contentful-container-link:active,\n.contentful-container-link:visited,\n.contentful-container-link:hover,\n.contentful-container-link:read-write,\n.contentful-container-link:focus-visible {\n color: inherit;\n text-decoration: unset;\n outline: unset;\n}\n";
|
|
3460
|
+
styleInject(css_248z$2);
|
|
3809
3461
|
|
|
3810
3462
|
const Flex = forwardRef(({ id, children, onMouseEnter, onMouseUp, onMouseLeave, onMouseDown, onClick, flex, flexBasis, flexShrink, flexDirection, gap, justifyContent, justifyItems, justifySelf, alignItems, alignSelf, alignContent, order, flexWrap, flexGrow, className, cssStyles, ...props }, ref) => {
|
|
3811
3463
|
return (React.createElement("div", { id: id, ref: ref, style: {
|
|
@@ -3829,34 +3481,14 @@ const Flex = forwardRef(({ id, children, onMouseEnter, onMouseUp, onMouseLeave,
|
|
|
3829
3481
|
});
|
|
3830
3482
|
Flex.displayName = 'Flex';
|
|
3831
3483
|
|
|
3832
|
-
var css_248z$1$1 = ".cf-divider {\n display: contents;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.cf-divider hr {\n border: none;\n}\n
|
|
3484
|
+
var css_248z$1$1 = ".cf-divider {\n display: contents;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.cf-divider hr {\n border: none;\n}\n";
|
|
3833
3485
|
styleInject(css_248z$1$1);
|
|
3834
3486
|
|
|
3835
|
-
var css_248z$9 = ".cf-columns {\n display: flex;\n gap: 24px;\n grid-template-columns: repeat(12, 1fr);\n flex-direction: column;\n min-height: 0; /* NEW */\n min-width: 0; /* NEW; needed for Firefox */\n}\n\n@media (min-width: 768px) {\n .cf-columns {\n display: grid;\n }\n}\n\n.cf-single-column-wrapper {\n position: relative;\n
|
|
3487
|
+
var css_248z$9 = ".cf-columns {\n display: flex;\n gap: 24px;\n grid-template-columns: repeat(12, 1fr);\n flex-direction: column;\n min-height: 0; /* NEW */\n min-width: 0; /* NEW; needed for Firefox */\n}\n\n@media (min-width: 768px) {\n .cf-columns {\n display: grid;\n }\n}\n\n.cf-single-column-wrapper {\n position: relative;\n}\n\n.cf-single-column-wrapper:after {\n content: '';\n display: block;\n position: absolute;\n pointer-events: none;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow-x: clip;\n font-family: var(--exp-builder-font-stack-primary);\n font-size: 12px;\n color: var(--exp-builder-gray400);\n z-index: 1;\n}\n\n.cf-single-column-label:after {\n content: 'Column';\n}\n";
|
|
3836
3488
|
styleInject(css_248z$9);
|
|
3837
3489
|
|
|
3838
|
-
const ColumnWrapper = forwardRef((props, ref) => {
|
|
3839
|
-
return (React.createElement("div", { ref: ref, ...props, style: {
|
|
3840
|
-
...(props.style || {}),
|
|
3841
|
-
display: 'grid',
|
|
3842
|
-
gridTemplateColumns: 'repeat(12, [col-start] 1fr)',
|
|
3843
|
-
} }, props.children));
|
|
3844
|
-
});
|
|
3845
|
-
ColumnWrapper.displayName = 'ColumnWrapper';
|
|
3846
|
-
|
|
3847
3490
|
const assemblyStyle = { display: 'contents' };
|
|
3848
|
-
// Feel free to do any magic as regards variable definitions for assemblies
|
|
3849
|
-
// Or if this isn't necessary by the time we figure that part out, we can bid this part farewell
|
|
3850
3491
|
const Assembly = (props) => {
|
|
3851
|
-
if (props.editorMode) {
|
|
3852
|
-
const { node, dragProps, ...editorModeProps } = props;
|
|
3853
|
-
return props.renderDropzone(node, {
|
|
3854
|
-
...editorModeProps,
|
|
3855
|
-
['data-test-id']: 'contentful-assembly',
|
|
3856
|
-
className: props.className,
|
|
3857
|
-
dragProps,
|
|
3858
|
-
});
|
|
3859
|
-
}
|
|
3860
3492
|
// Using a display contents so assembly content/children
|
|
3861
3493
|
// can appear as if they are direct children of the div wrapper's parent
|
|
3862
3494
|
return React.createElement("div", { "data-test-id": "assembly", ...props, style: assemblyStyle });
|
|
@@ -3879,75 +3511,6 @@ const useEntityStore = create((set) => ({
|
|
|
3879
3511
|
},
|
|
3880
3512
|
}));
|
|
3881
3513
|
|
|
3882
|
-
class DragState {
|
|
3883
|
-
constructor() {
|
|
3884
|
-
this.isDragStartedOnParent = false;
|
|
3885
|
-
this.isDraggingItem = false;
|
|
3886
|
-
}
|
|
3887
|
-
get isDragging() {
|
|
3888
|
-
return this.isDraggingItem;
|
|
3889
|
-
}
|
|
3890
|
-
get isDraggingOnParent() {
|
|
3891
|
-
return this.isDragStartedOnParent;
|
|
3892
|
-
}
|
|
3893
|
-
updateIsDragging(isDraggingItem) {
|
|
3894
|
-
this.isDraggingItem = isDraggingItem;
|
|
3895
|
-
}
|
|
3896
|
-
updateIsDragStartedOnParent(isDragStartedOnParent) {
|
|
3897
|
-
this.isDragStartedOnParent = isDragStartedOnParent;
|
|
3898
|
-
}
|
|
3899
|
-
resetState() {
|
|
3900
|
-
this.isDraggingItem = false;
|
|
3901
|
-
this.isDragStartedOnParent = false;
|
|
3902
|
-
}
|
|
3903
|
-
}
|
|
3904
|
-
|
|
3905
|
-
class SimulateDnD extends DragState {
|
|
3906
|
-
constructor() {
|
|
3907
|
-
super();
|
|
3908
|
-
this.draggingElement = null;
|
|
3909
|
-
}
|
|
3910
|
-
setupDrag() {
|
|
3911
|
-
this.updateIsDragStartedOnParent(true);
|
|
3912
|
-
}
|
|
3913
|
-
startDrag(coordX, coordY) {
|
|
3914
|
-
this.draggingElement = document.getElementById(NEW_COMPONENT_ID);
|
|
3915
|
-
this.updateIsDragging(true);
|
|
3916
|
-
this.simulateMouseEvent(coordX, coordY, 'mousedown');
|
|
3917
|
-
}
|
|
3918
|
-
updateDrag(coordX, coordY) {
|
|
3919
|
-
if (!this.draggingElement) {
|
|
3920
|
-
this.draggingElement = document.querySelector(`[${CTFL_DRAGGING_ELEMENT}]`);
|
|
3921
|
-
}
|
|
3922
|
-
this.simulateMouseEvent(coordX, coordY);
|
|
3923
|
-
}
|
|
3924
|
-
endDrag(coordX, coordY) {
|
|
3925
|
-
this.simulateMouseEvent(coordX, coordY, 'mouseup');
|
|
3926
|
-
this.reset();
|
|
3927
|
-
}
|
|
3928
|
-
reset() {
|
|
3929
|
-
this.draggingElement = null;
|
|
3930
|
-
this.resetState();
|
|
3931
|
-
}
|
|
3932
|
-
simulateMouseEvent(coordX, coordY, eventName = 'mousemove') {
|
|
3933
|
-
if (!this.draggingElement) {
|
|
3934
|
-
return;
|
|
3935
|
-
}
|
|
3936
|
-
const options = {
|
|
3937
|
-
bubbles: true,
|
|
3938
|
-
cancelable: true,
|
|
3939
|
-
view: window,
|
|
3940
|
-
pageX: 0,
|
|
3941
|
-
pageY: 0,
|
|
3942
|
-
clientX: coordX,
|
|
3943
|
-
clientY: coordY,
|
|
3944
|
-
};
|
|
3945
|
-
const event = new MouseEvent(eventName, options);
|
|
3946
|
-
this.draggingElement.dispatchEvent(event);
|
|
3947
|
-
}
|
|
3948
|
-
}
|
|
3949
|
-
var SimulateDnD$1 = new SimulateDnD();
|
|
3950
|
-
|
|
3951
3514
|
function useEditorSubscriber() {
|
|
3952
3515
|
const entityStore = useEntityStore((state) => state.entityStore);
|
|
3953
3516
|
const areEntitiesFetched = useEntityStore((state) => state.areEntitiesFetched);
|
|
@@ -3961,14 +3524,7 @@ function useEditorSubscriber() {
|
|
|
3961
3524
|
const setLocale = useEditorStore((state) => state.setLocale);
|
|
3962
3525
|
const setUnboundValues = useEditorStore((state) => state.setUnboundValues);
|
|
3963
3526
|
const setDataSource = useEditorStore((state) => state.setDataSource);
|
|
3964
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
3965
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
3966
3527
|
const resetEntityStore = useEntityStore((state) => state.resetEntityStore);
|
|
3967
|
-
const setComponentId = useDraggedItemStore((state) => state.setComponentId);
|
|
3968
|
-
const setHoveredComponentId = useDraggedItemStore((state) => state.setHoveredComponentId);
|
|
3969
|
-
const setDraggingOnCanvas = useDraggedItemStore((state) => state.setDraggingOnCanvas);
|
|
3970
|
-
const setMousePosition = useDraggedItemStore((state) => state.setMousePosition);
|
|
3971
|
-
const setScrollY = useDraggedItemStore((state) => state.setScrollY);
|
|
3972
3528
|
const reloadApp = () => {
|
|
3973
3529
|
sendMessage(OUTGOING_EVENTS.CanvasReload, undefined);
|
|
3974
3530
|
// Wait a moment to ensure that the message was sent
|
|
@@ -4069,12 +3625,12 @@ function useEditorSubscriber() {
|
|
|
4069
3625
|
}
|
|
4070
3626
|
const eventData = tryParseMessage(event);
|
|
4071
3627
|
console.debug(`[experiences-sdk-react::onMessage] Received message [${eventData.eventType}]`, eventData);
|
|
4072
|
-
if (eventData.eventType === PostMessageMethods$
|
|
3628
|
+
if (eventData.eventType === PostMessageMethods$3.REQUESTED_ENTITIES) {
|
|
4073
3629
|
// Expected message: This message is handled in the EntityStore to store fetched entities
|
|
4074
3630
|
return;
|
|
4075
3631
|
}
|
|
4076
3632
|
switch (eventData.eventType) {
|
|
4077
|
-
case INCOMING_EVENTS.ExperienceUpdated: {
|
|
3633
|
+
case INCOMING_EVENTS$1.ExperienceUpdated: {
|
|
4078
3634
|
const { tree, locale, changedNode, changedValueType, assemblies } = eventData.payload;
|
|
4079
3635
|
// Make sure to first store the assemblies before setting the tree and thus triggering a rerender
|
|
4080
3636
|
if (assemblies) {
|
|
@@ -4118,7 +3674,7 @@ function useEditorSubscriber() {
|
|
|
4118
3674
|
updateTree(tree);
|
|
4119
3675
|
break;
|
|
4120
3676
|
}
|
|
4121
|
-
case INCOMING_EVENTS.AssembliesRegistered: {
|
|
3677
|
+
case INCOMING_EVENTS$1.AssembliesRegistered: {
|
|
4122
3678
|
const { assemblies } = eventData.payload;
|
|
4123
3679
|
assemblies.forEach((definition) => {
|
|
4124
3680
|
addComponentRegistration({
|
|
@@ -4128,7 +3684,7 @@ function useEditorSubscriber() {
|
|
|
4128
3684
|
});
|
|
4129
3685
|
break;
|
|
4130
3686
|
}
|
|
4131
|
-
case INCOMING_EVENTS.AssembliesAdded: {
|
|
3687
|
+
case INCOMING_EVENTS$1.AssembliesAdded: {
|
|
4132
3688
|
const { assembly, assemblyDefinition, } = eventData.payload;
|
|
4133
3689
|
entityStore.updateEntity(assembly);
|
|
4134
3690
|
// Using a Map here to avoid setting state and rerending all existing assemblies when a new assembly is added
|
|
@@ -4145,28 +3701,7 @@ function useEditorSubscriber() {
|
|
|
4145
3701
|
}
|
|
4146
3702
|
break;
|
|
4147
3703
|
}
|
|
4148
|
-
case INCOMING_EVENTS.
|
|
4149
|
-
const { selectedNodeId } = eventData.payload;
|
|
4150
|
-
if (selectedNodeId) {
|
|
4151
|
-
sendSelectedComponentCoordinates(selectedNodeId);
|
|
4152
|
-
}
|
|
4153
|
-
break;
|
|
4154
|
-
}
|
|
4155
|
-
case INCOMING_EVENTS.HoverComponent: {
|
|
4156
|
-
const { hoveredNodeId } = eventData.payload;
|
|
4157
|
-
setHoveredComponentId(hoveredNodeId);
|
|
4158
|
-
break;
|
|
4159
|
-
}
|
|
4160
|
-
case INCOMING_EVENTS.ComponentDraggingChanged: {
|
|
4161
|
-
const { isDragging } = eventData.payload;
|
|
4162
|
-
if (!isDragging) {
|
|
4163
|
-
setComponentId('');
|
|
4164
|
-
setDraggingOnCanvas(false);
|
|
4165
|
-
SimulateDnD$1.reset();
|
|
4166
|
-
}
|
|
4167
|
-
break;
|
|
4168
|
-
}
|
|
4169
|
-
case INCOMING_EVENTS.UpdatedEntity: {
|
|
3704
|
+
case INCOMING_EVENTS$1.UpdatedEntity: {
|
|
4170
3705
|
const { entity: updatedEntity, shouldRerender } = eventData.payload;
|
|
4171
3706
|
if (updatedEntity) {
|
|
4172
3707
|
const storedEntity = entityStore.entities.find((entity) => entity.sys.id === updatedEntity.sys.id);
|
|
@@ -4179,52 +3714,7 @@ function useEditorSubscriber() {
|
|
|
4179
3714
|
}
|
|
4180
3715
|
break;
|
|
4181
3716
|
}
|
|
4182
|
-
case INCOMING_EVENTS.RequestEditorMode: {
|
|
4183
|
-
break;
|
|
4184
|
-
}
|
|
4185
|
-
case INCOMING_EVENTS.ComponentDragCanceled: {
|
|
4186
|
-
if (SimulateDnD$1.isDragging) {
|
|
4187
|
-
//simulate a mouseup event to cancel the drag
|
|
4188
|
-
SimulateDnD$1.endDrag(0, 0);
|
|
4189
|
-
}
|
|
4190
|
-
break;
|
|
4191
|
-
}
|
|
4192
|
-
case INCOMING_EVENTS.ComponentDragStarted: {
|
|
4193
|
-
const { id, isAssembly } = eventData.payload;
|
|
4194
|
-
SimulateDnD$1.setupDrag();
|
|
4195
|
-
setComponentId(`${id}:${isAssembly}` || '');
|
|
4196
|
-
setDraggingOnCanvas(true);
|
|
4197
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
4198
|
-
nodeId: '',
|
|
4199
|
-
});
|
|
4200
|
-
break;
|
|
4201
|
-
}
|
|
4202
|
-
case INCOMING_EVENTS.ComponentDragEnded: {
|
|
4203
|
-
SimulateDnD$1.reset();
|
|
4204
|
-
setComponentId('');
|
|
4205
|
-
setDraggingOnCanvas(false);
|
|
4206
|
-
break;
|
|
4207
|
-
}
|
|
4208
|
-
case INCOMING_EVENTS.SelectComponent: {
|
|
4209
|
-
const { selectedNodeId: nodeId } = eventData.payload;
|
|
4210
|
-
setSelectedNodeId(nodeId);
|
|
4211
|
-
sendSelectedComponentCoordinates(nodeId);
|
|
4212
|
-
break;
|
|
4213
|
-
}
|
|
4214
|
-
case INCOMING_EVENTS.MouseMove: {
|
|
4215
|
-
const { mouseX, mouseY } = eventData.payload;
|
|
4216
|
-
setMousePosition(mouseX, mouseY);
|
|
4217
|
-
if (SimulateDnD$1.isDraggingOnParent && !SimulateDnD$1.isDragging) {
|
|
4218
|
-
SimulateDnD$1.startDrag(mouseX, mouseY);
|
|
4219
|
-
}
|
|
4220
|
-
else {
|
|
4221
|
-
SimulateDnD$1.updateDrag(mouseX, mouseY);
|
|
4222
|
-
}
|
|
4223
|
-
break;
|
|
4224
|
-
}
|
|
4225
|
-
case INCOMING_EVENTS.ComponentMoveEnded: {
|
|
4226
|
-
const { mouseX, mouseY } = eventData.payload;
|
|
4227
|
-
SimulateDnD$1.endDrag(mouseX, mouseY);
|
|
3717
|
+
case INCOMING_EVENTS$1.RequestEditorMode: {
|
|
4228
3718
|
break;
|
|
4229
3719
|
}
|
|
4230
3720
|
default:
|
|
@@ -4237,340 +3727,101 @@ function useEditorSubscriber() {
|
|
|
4237
3727
|
};
|
|
4238
3728
|
}, [
|
|
4239
3729
|
entityStore,
|
|
4240
|
-
setComponentId,
|
|
4241
|
-
setDraggingOnCanvas,
|
|
4242
3730
|
setDataSource,
|
|
4243
3731
|
setLocale,
|
|
4244
|
-
setSelectedNodeId,
|
|
4245
3732
|
dataSource,
|
|
4246
3733
|
areEntitiesFetched,
|
|
4247
3734
|
fetchMissingEntities,
|
|
4248
3735
|
setUnboundValues,
|
|
4249
3736
|
unboundValues,
|
|
4250
|
-
updateTree,
|
|
4251
|
-
updateNodesByUpdatedEntity,
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
]);
|
|
4256
|
-
/*
|
|
4257
|
-
* Handles on scroll business
|
|
4258
|
-
*/
|
|
4259
|
-
useEffect(() => {
|
|
4260
|
-
let timeoutId = 0;
|
|
4261
|
-
let isScrolling = false;
|
|
4262
|
-
const onScroll = () => {
|
|
4263
|
-
setScrollY(window.scrollY);
|
|
4264
|
-
if (isScrolling === false) {
|
|
4265
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.Start);
|
|
4266
|
-
}
|
|
4267
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.IsScrolling);
|
|
4268
|
-
isScrolling = true;
|
|
4269
|
-
clearTimeout(timeoutId);
|
|
4270
|
-
timeoutId = window.setTimeout(() => {
|
|
4271
|
-
if (isScrolling === false) {
|
|
4272
|
-
return;
|
|
4273
|
-
}
|
|
4274
|
-
isScrolling = false;
|
|
4275
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.End);
|
|
4276
|
-
/**
|
|
4277
|
-
* On scroll end, send new co-ordinates of selected node
|
|
4278
|
-
*/
|
|
4279
|
-
if (selectedNodeId) {
|
|
4280
|
-
sendSelectedComponentCoordinates(selectedNodeId);
|
|
4281
|
-
}
|
|
4282
|
-
}, 150);
|
|
4283
|
-
};
|
|
4284
|
-
window.addEventListener('scroll', onScroll, { capture: true, passive: true });
|
|
4285
|
-
return () => {
|
|
4286
|
-
window.removeEventListener('scroll', onScroll, { capture: true });
|
|
4287
|
-
clearTimeout(timeoutId);
|
|
4288
|
-
};
|
|
4289
|
-
}, [selectedNodeId, setScrollY]);
|
|
4290
|
-
}
|
|
4291
|
-
|
|
4292
|
-
const onComponentMoved = (options) => {
|
|
4293
|
-
sendMessage(OUTGOING_EVENTS.ComponentMoved, options);
|
|
4294
|
-
};
|
|
4295
|
-
|
|
4296
|
-
const generateId = (type) => `${type}-${v4()}`;
|
|
4297
|
-
|
|
4298
|
-
const createTreeNode = ({ blockId, parentId, slotId }) => {
|
|
4299
|
-
const node = {
|
|
4300
|
-
type: 'block',
|
|
4301
|
-
data: {
|
|
4302
|
-
id: generateId(blockId),
|
|
4303
|
-
blockId,
|
|
4304
|
-
slotId,
|
|
4305
|
-
props: {},
|
|
4306
|
-
dataSource: {},
|
|
4307
|
-
breakpoints: [],
|
|
4308
|
-
unboundValues: {},
|
|
4309
|
-
},
|
|
4310
|
-
parentId,
|
|
4311
|
-
children: [],
|
|
4312
|
-
};
|
|
4313
|
-
return node;
|
|
4314
|
-
};
|
|
4315
|
-
|
|
4316
|
-
const onComponentDropped = ({ node, index, parentBlockId, parentType, parentId, }) => {
|
|
4317
|
-
sendMessage(OUTGOING_EVENTS.ComponentDropped, {
|
|
4318
|
-
node,
|
|
4319
|
-
index: index ?? node.children.length,
|
|
4320
|
-
parentNode: {
|
|
4321
|
-
type: parentType,
|
|
4322
|
-
data: {
|
|
4323
|
-
blockId: parentBlockId,
|
|
4324
|
-
id: parentId,
|
|
4325
|
-
},
|
|
4326
|
-
},
|
|
4327
|
-
});
|
|
4328
|
-
};
|
|
4329
|
-
|
|
4330
|
-
const onDrop = ({ destinationIndex, componentType, destinationZoneId, data, slotId, }) => {
|
|
4331
|
-
const parentId = destinationZoneId;
|
|
4332
|
-
const parentNode = getItem({ id: parentId }, data);
|
|
4333
|
-
const parentIsRoot = parentId === ROOT_ID;
|
|
4334
|
-
const emptyComponentData = {
|
|
4335
|
-
type: 'block',
|
|
4336
|
-
parentId,
|
|
4337
|
-
children: [],
|
|
4338
|
-
data: {
|
|
4339
|
-
blockId: componentType,
|
|
4340
|
-
id: generateId(componentType),
|
|
4341
|
-
slotId,
|
|
4342
|
-
breakpoints: [],
|
|
4343
|
-
dataSource: {},
|
|
4344
|
-
props: {},
|
|
4345
|
-
unboundValues: {},
|
|
4346
|
-
},
|
|
4347
|
-
};
|
|
4348
|
-
onComponentDropped({
|
|
4349
|
-
node: emptyComponentData,
|
|
4350
|
-
index: destinationIndex,
|
|
4351
|
-
parentType: parentIsRoot ? 'root' : parentNode?.type,
|
|
4352
|
-
parentBlockId: parentNode?.data.blockId,
|
|
4353
|
-
parentId: parentIsRoot ? 'root' : parentId,
|
|
4354
|
-
});
|
|
4355
|
-
};
|
|
3737
|
+
updateTree,
|
|
3738
|
+
updateNodesByUpdatedEntity,
|
|
3739
|
+
resetEntityStore,
|
|
3740
|
+
]);
|
|
3741
|
+
}
|
|
4356
3742
|
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
3743
|
+
const CircularDependencyErrorPlaceholder = ({ node, wrappingPatternIds, }) => {
|
|
3744
|
+
const entityStore = useEntityStore((state) => state.entityStore);
|
|
3745
|
+
return (React.createElement("div", { "data-cf-node-id": node.data.id, "data-cf-node-block-id": node.data.blockId, "data-cf-node-block-type": node.type, "data-cf-node-error": "circular-pattern-dependency", style: {
|
|
3746
|
+
border: '1px solid red',
|
|
3747
|
+
background: 'rgba(255, 0, 0, 0.1)',
|
|
3748
|
+
padding: '1rem 1rem 0 1rem',
|
|
3749
|
+
width: '100%',
|
|
3750
|
+
height: '100%',
|
|
3751
|
+
} },
|
|
3752
|
+
"Circular usage of patterns detected:",
|
|
3753
|
+
React.createElement("ul", null, Array.from(wrappingPatternIds).map((patternId) => {
|
|
3754
|
+
const entryLink = { sys: { type: 'Link', linkType: 'Entry', id: patternId } };
|
|
3755
|
+
const entry = entityStore.getEntityFromLink(entryLink);
|
|
3756
|
+
const entryTitle = entry?.fields?.title;
|
|
3757
|
+
const text = entryTitle ? `${entryTitle} (${patternId})` : patternId;
|
|
3758
|
+
return React.createElement("li", { key: patternId }, text);
|
|
3759
|
+
}))));
|
|
4367
3760
|
};
|
|
4368
3761
|
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
if (droppingOnRoot && !isValidRootComponent) {
|
|
4389
|
-
const wrappingContainer = createTreeNode({
|
|
4390
|
-
blockId: CONTENTFUL_COMPONENTS$1.container.id,
|
|
4391
|
-
parentId,
|
|
4392
|
-
});
|
|
4393
|
-
const childNode = createTreeNode({
|
|
4394
|
-
blockId,
|
|
4395
|
-
parentId: wrappingContainer.data.id,
|
|
4396
|
-
});
|
|
4397
|
-
node = wrappingContainer;
|
|
4398
|
-
node.children = [childNode];
|
|
4399
|
-
}
|
|
4400
|
-
/**
|
|
4401
|
-
* isAssembly comes from a string ID so we need to check if it's 'true' or 'false'
|
|
4402
|
-
* in string format.
|
|
4403
|
-
*/
|
|
4404
|
-
if (isAssembly === 'false') {
|
|
4405
|
-
addChild(destination.index, parentId, node);
|
|
4406
|
-
}
|
|
4407
|
-
onDrop({
|
|
4408
|
-
data: tree,
|
|
4409
|
-
componentType: blockId,
|
|
4410
|
-
destinationIndex: destination.index,
|
|
4411
|
-
destinationZoneId: parentId,
|
|
4412
|
-
slotId,
|
|
4413
|
-
});
|
|
4414
|
-
};
|
|
4415
|
-
const onMoveComponent = (droppedItem) => {
|
|
4416
|
-
const { destination, source, draggableId } = droppedItem;
|
|
4417
|
-
if (!destination || !source) {
|
|
4418
|
-
return;
|
|
4419
|
-
}
|
|
4420
|
-
if (destination.droppableId === source.droppableId) {
|
|
4421
|
-
reorderChildren(destination.index, destination.droppableId, source.index);
|
|
4422
|
-
}
|
|
4423
|
-
if (destination.droppableId !== source.droppableId) {
|
|
4424
|
-
reparentChild(destination.index, destination.droppableId, source.index, source.droppableId);
|
|
3762
|
+
class ImportedComponentError extends Error {
|
|
3763
|
+
constructor(message) {
|
|
3764
|
+
super(message);
|
|
3765
|
+
this.name = 'ImportedComponentError';
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
class ExperienceSDKError extends Error {
|
|
3769
|
+
constructor(message) {
|
|
3770
|
+
super(message);
|
|
3771
|
+
this.name = 'ExperienceSDKError';
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
class ImportedComponentErrorBoundary extends React.Component {
|
|
3775
|
+
componentDidCatch(error, _errorInfo) {
|
|
3776
|
+
if (error.name === 'ImportedComponentError' || error.name === 'ExperienceSDKError') {
|
|
3777
|
+
// This error was already handled by a nested error boundary and should be passed upwards
|
|
3778
|
+
// We have to do this as we wrap every component on every layer with this error boundary and
|
|
3779
|
+
// thus an error deep in the tree bubbles through many layers of error boundaries.
|
|
3780
|
+
throw error;
|
|
4425
3781
|
}
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
}
|
|
4434
|
-
|
|
3782
|
+
// Differentiate between custom and SDK-provided components for error tracking
|
|
3783
|
+
const ErrorClass = isContentfulComponent(this.props.componentId)
|
|
3784
|
+
? ExperienceSDKError
|
|
3785
|
+
: ImportedComponentError;
|
|
3786
|
+
const err = new ErrorClass(error.message);
|
|
3787
|
+
err.stack = error.stack;
|
|
3788
|
+
throw err;
|
|
3789
|
+
}
|
|
3790
|
+
render() {
|
|
3791
|
+
return this.props.children;
|
|
3792
|
+
}
|
|
4435
3793
|
}
|
|
4436
3794
|
|
|
4437
|
-
const
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
onBeforeDragStart(start);
|
|
4447
|
-
onDragStart(start, {});
|
|
4448
|
-
};
|
|
4449
|
-
const handleDrag = (event) => {
|
|
4450
|
-
const draggedItem = event.nativeEvent;
|
|
4451
|
-
const update = {
|
|
4452
|
-
mode: draggedItem.mode,
|
|
4453
|
-
draggableId: draggedItem.draggableId,
|
|
4454
|
-
type: draggedItem.type,
|
|
4455
|
-
source: draggedItem.source,
|
|
4456
|
-
destination: draggedItem.destination,
|
|
4457
|
-
combine: draggedItem.combine,
|
|
4458
|
-
};
|
|
4459
|
-
onDragUpdate(update, {});
|
|
4460
|
-
};
|
|
4461
|
-
const handleDragEnd = (event) => {
|
|
4462
|
-
const draggedItem = event.nativeEvent;
|
|
4463
|
-
const result = {
|
|
4464
|
-
mode: draggedItem.mode,
|
|
4465
|
-
draggableId: draggedItem.draggableId,
|
|
4466
|
-
type: draggedItem.type,
|
|
4467
|
-
source: draggedItem.source,
|
|
4468
|
-
destination: draggedItem.destination,
|
|
4469
|
-
combine: draggedItem.combine,
|
|
4470
|
-
reason: draggedItem.reason,
|
|
4471
|
-
};
|
|
4472
|
-
onDragEnd(result, {});
|
|
4473
|
-
};
|
|
4474
|
-
return (React.createElement("div", { "data-test-id": "dnd-context-substitute", onDragStart: handleDragStart, onDrag: handleDrag, onDragEnd: handleDragEnd }, children));
|
|
3795
|
+
const MissingComponentPlaceholder = ({ blockId }) => {
|
|
3796
|
+
return (React.createElement("div", { style: {
|
|
3797
|
+
border: '1px solid red',
|
|
3798
|
+
width: '100%',
|
|
3799
|
+
height: '100%',
|
|
3800
|
+
} },
|
|
3801
|
+
"Missing component '",
|
|
3802
|
+
blockId,
|
|
3803
|
+
"'"));
|
|
4475
3804
|
};
|
|
4476
3805
|
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
const setOnBeforeCaptureId = useDraggedItemStore((state) => state.setOnBeforeCaptureId);
|
|
4481
|
-
const setDraggingOnCanvas = useDraggedItemStore((state) => state.setDraggingOnCanvas);
|
|
4482
|
-
const updateItem = useDraggedItemStore((state) => state.updateItem);
|
|
4483
|
-
const { onAddComponent, onMoveComponent } = useCanvasInteractions();
|
|
4484
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
4485
|
-
const prevSelectedNodeId = useRef(null);
|
|
4486
|
-
const isTestRun = typeof window !== 'undefined' && Object.prototype.hasOwnProperty.call(window, 'Cypress');
|
|
4487
|
-
const beforeDragStart = ({ source }) => {
|
|
4488
|
-
prevSelectedNodeId.current = selectedNodeId;
|
|
4489
|
-
// Unselect the current node when dragging and remove the outline
|
|
4490
|
-
setSelectedNodeId('');
|
|
4491
|
-
// Set dragging state here to make sure that DnD capture phase has completed
|
|
4492
|
-
setDraggingOnCanvas(true);
|
|
4493
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
4494
|
-
nodeId: '',
|
|
4495
|
-
});
|
|
4496
|
-
if (source.droppableId !== COMPONENT_LIST_ID) {
|
|
4497
|
-
sendMessage(OUTGOING_EVENTS.ComponentMoveStarted, undefined);
|
|
4498
|
-
}
|
|
4499
|
-
};
|
|
4500
|
-
const beforeCapture = ({ draggableId }) => {
|
|
4501
|
-
setOnBeforeCaptureId(draggableId);
|
|
4502
|
-
};
|
|
4503
|
-
const dragStart = (start) => {
|
|
4504
|
-
updateItem(start);
|
|
4505
|
-
};
|
|
4506
|
-
const dragUpdate = (update) => {
|
|
4507
|
-
updateItem(update);
|
|
4508
|
-
};
|
|
4509
|
-
const dragEnd = (dropResult) => {
|
|
4510
|
-
setDraggingOnCanvas(false);
|
|
4511
|
-
setOnBeforeCaptureId('');
|
|
4512
|
-
updateItem();
|
|
4513
|
-
SimulateDnD$1.reset();
|
|
4514
|
-
// If the component is being dropped onto itself, do nothing
|
|
4515
|
-
// This can happen from an apparent race condition where the hovering zone gets set
|
|
4516
|
-
// to the component after its dropped.
|
|
4517
|
-
if (dropResult.destination?.droppableId === dropResult.draggableId) {
|
|
4518
|
-
return;
|
|
4519
|
-
}
|
|
4520
|
-
if (!dropResult.destination) {
|
|
4521
|
-
if (!draggedItem?.destination) {
|
|
4522
|
-
// User cancel drag
|
|
4523
|
-
sendMessage(OUTGOING_EVENTS.ComponentDragCanceled, undefined);
|
|
4524
|
-
//select the previously selected node if drag was canceled
|
|
4525
|
-
if (prevSelectedNodeId.current) {
|
|
4526
|
-
setSelectedNodeId(prevSelectedNodeId.current);
|
|
4527
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
4528
|
-
nodeId: prevSelectedNodeId.current,
|
|
4529
|
-
});
|
|
4530
|
-
prevSelectedNodeId.current = null;
|
|
4531
|
-
}
|
|
4532
|
-
return;
|
|
4533
|
-
}
|
|
4534
|
-
// Use the destination from the draggedItem (when clicking the canvas)
|
|
4535
|
-
dropResult.destination = draggedItem.destination;
|
|
4536
|
-
}
|
|
4537
|
-
// New component added to canvas
|
|
4538
|
-
if (dropResult.source.droppableId.startsWith('component-list')) {
|
|
4539
|
-
onAddComponent(dropResult);
|
|
4540
|
-
}
|
|
4541
|
-
else {
|
|
4542
|
-
onMoveComponent(dropResult);
|
|
4543
|
-
}
|
|
4544
|
-
// If a node was previously selected prior to dragging, re-select it
|
|
4545
|
-
setSelectedNodeId(dropResult.draggableId);
|
|
4546
|
-
sendMessage(OUTGOING_EVENTS.ComponentMoveEnded, undefined);
|
|
4547
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
4548
|
-
nodeId: dropResult.draggableId,
|
|
4549
|
-
});
|
|
4550
|
-
};
|
|
4551
|
-
return (React.createElement(DragDropContext, { onBeforeCapture: beforeCapture, onDragUpdate: dragUpdate, onBeforeDragStart: beforeDragStart, onDragStart: dragStart, onDragEnd: dragEnd }, isTestRun ? (React.createElement(TestDNDContainer, { onDragEnd: dragEnd, onBeforeDragStart: beforeDragStart, onDragStart: dragStart, onDragUpdate: dragUpdate }, children)) : (children)));
|
|
4552
|
-
};
|
|
3806
|
+
var css_248z$1 = ".EditorBlock-module_emptySlot__za-Bi {\n min-height: 80px;\n min-width: 80px;\n}\n";
|
|
3807
|
+
var styles$1 = {"emptySlot":"EditorBlock-module_emptySlot__za-Bi"};
|
|
3808
|
+
styleInject(css_248z$1);
|
|
4553
3809
|
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
return;
|
|
3810
|
+
const useComponentRegistration = (node) => {
|
|
3811
|
+
return useMemo(() => {
|
|
3812
|
+
let registration = componentRegistry.get(node.data.blockId);
|
|
3813
|
+
if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
|
|
3814
|
+
registration = createAssemblyRegistration({
|
|
3815
|
+
definitionId: node.data.blockId,
|
|
3816
|
+
component: Assembly,
|
|
3817
|
+
});
|
|
4563
3818
|
}
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
}, [node
|
|
4570
|
-
const selectedElement = node.data.id
|
|
4571
|
-
? document.querySelector(`[data-cf-node-id="${selectedNodeId}"]`)
|
|
4572
|
-
: undefined;
|
|
4573
|
-
return selectedElement ? getElementCoordinates(selectedElement) : null;
|
|
3819
|
+
if (!registration) {
|
|
3820
|
+
console.warn(`Component registration not found for component with id: "${node.data.blockId}". The registered component might have been removed from the code. To proceed, remove the component manually from the layers tab.`);
|
|
3821
|
+
return undefined;
|
|
3822
|
+
}
|
|
3823
|
+
return registration;
|
|
3824
|
+
}, [node]);
|
|
4574
3825
|
};
|
|
4575
3826
|
|
|
4576
3827
|
/**
|
|
@@ -4618,15 +3869,13 @@ const getUnboundValues = ({ key, fallback, unboundValues, }) => {
|
|
|
4618
3869
|
return get$1(unboundValues, lodashPath, fallback);
|
|
4619
3870
|
};
|
|
4620
3871
|
|
|
4621
|
-
const useComponentProps = ({ node,
|
|
3872
|
+
const useComponentProps = ({ node, resolveDesignValue, definition, options, }) => {
|
|
4622
3873
|
const unboundValues = useEditorStore((state) => state.unboundValues);
|
|
4623
3874
|
const hyperlinkPattern = useEditorStore((state) => state.hyperLinkPattern);
|
|
4624
3875
|
const locale = useEditorStore((state) => state.locale);
|
|
4625
3876
|
const dataSource = useEditorStore((state) => state.dataSource);
|
|
4626
3877
|
const entityStore = useEntityStore((state) => state.entityStore);
|
|
4627
|
-
const
|
|
4628
|
-
const nodeRect = useDraggedItemStore((state) => state.domRect);
|
|
4629
|
-
const isEmptyZone = !node.children.length;
|
|
3878
|
+
const areEntitiesFetched = useEntityStore((state) => state.areEntitiesFetched);
|
|
4630
3879
|
const props = useMemo(() => {
|
|
4631
3880
|
const propsBase = {
|
|
4632
3881
|
cfSsrClassName: node.data.props.cfSsrClassName
|
|
@@ -4704,1145 +3953,138 @@ const useComponentProps = ({ node, areEntitiesFetched, resolveDesignValue, rende
|
|
|
4704
3953
|
};
|
|
4705
3954
|
}
|
|
4706
3955
|
else if (variableMapping.type === 'ComponentValue') {
|
|
4707
|
-
// We are rendering a pattern (assembly) entry. Content properties cannot be edited in this,
|
|
4708
|
-
// so we always render the default value
|
|
4709
|
-
return {
|
|
4710
|
-
...acc,
|
|
4711
|
-
// This can either a design (style) or a content variable
|
|
4712
|
-
[variableName]: variableDefinition.defaultValue,
|
|
4713
|
-
};
|
|
4714
|
-
}
|
|
4715
|
-
else {
|
|
4716
|
-
return { ...acc };
|
|
4717
|
-
}
|
|
4718
|
-
}, {});
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
}
|
|
4726
|
-
}
|
|
4727
|
-
return {
|
|
4728
|
-
...propsBase,
|
|
4729
|
-
...extractedProps,
|
|
4730
|
-
...slotProps,
|
|
4731
|
-
};
|
|
4732
|
-
}, [
|
|
4733
|
-
hyperlinkPattern,
|
|
4734
|
-
node,
|
|
4735
|
-
locale,
|
|
4736
|
-
definition,
|
|
4737
|
-
resolveDesignValue,
|
|
4738
|
-
dataSource,
|
|
4739
|
-
areEntitiesFetched,
|
|
4740
|
-
unboundValues,
|
|
4741
|
-
entityStore,
|
|
4742
|
-
renderDropzone,
|
|
4743
|
-
]);
|
|
4744
|
-
const cfStyles = useMemo(() => buildCfStyles(props), [props]);
|
|
4745
|
-
const cfVisibility = props['cfVisibility'];
|
|
4746
|
-
const isAssemblyBlock = node.type === ASSEMBLY_BLOCK_NODE_TYPE;
|
|
4747
|
-
const isSingleColumn = node?.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id;
|
|
4748
|
-
const isStructureComponent = isContentfulStructureComponent(node?.data.blockId);
|
|
4749
|
-
const isPatternNode = node.type === ASSEMBLY_NODE_TYPE;
|
|
4750
|
-
const { overrideStyles, wrapperStyles } = useMemo(() => {
|
|
4751
|
-
// Move size styles to the wrapping div and override the component styles
|
|
4752
|
-
const overrideStyles = {};
|
|
4753
|
-
const wrapperStyles = { width: options?.wrapContainerWidth };
|
|
4754
|
-
if (requiresDragWrapper) {
|
|
4755
|
-
// when element is marked by user as not-visible, on that element the node `display: none !important`
|
|
4756
|
-
// will be set and it will disappear. However, when such a node has a wrapper div, the wrapper
|
|
4757
|
-
// should not have any css properties (at least not ones which force size), as such div should
|
|
4758
|
-
// simply be a zero height wrapper around element with `display: none !important`.
|
|
4759
|
-
// Hence we guard all wrapperStyles with `cfVisibility` check.
|
|
4760
|
-
if (cfVisibility && cfStyles.width)
|
|
4761
|
-
wrapperStyles.width = cfStyles.width;
|
|
4762
|
-
if (cfVisibility && cfStyles.height)
|
|
4763
|
-
wrapperStyles.height = cfStyles.height;
|
|
4764
|
-
if (cfVisibility && cfStyles.maxWidth)
|
|
4765
|
-
wrapperStyles.maxWidth = cfStyles.maxWidth;
|
|
4766
|
-
if (cfVisibility && cfStyles.margin)
|
|
4767
|
-
wrapperStyles.margin = cfStyles.margin;
|
|
4768
|
-
}
|
|
4769
|
-
// Override component styles to fill the wrapper
|
|
4770
|
-
if (wrapperStyles.width)
|
|
4771
|
-
overrideStyles.width = '100%';
|
|
4772
|
-
if (wrapperStyles.height)
|
|
4773
|
-
overrideStyles.height = '100%';
|
|
4774
|
-
if (wrapperStyles.margin)
|
|
4775
|
-
overrideStyles.margin = '0';
|
|
4776
|
-
if (wrapperStyles.maxWidth)
|
|
4777
|
-
overrideStyles.maxWidth = 'none';
|
|
4778
|
-
// Prevent the dragging element from changing sizes when it has a percentage width or height
|
|
4779
|
-
if (draggingId === node.data.id && nodeRect) {
|
|
4780
|
-
if (requiresDragWrapper) {
|
|
4781
|
-
if (isPercentValue(cfStyles.width))
|
|
4782
|
-
wrapperStyles.maxWidth = nodeRect.width;
|
|
4783
|
-
if (isPercentValue(cfStyles.height))
|
|
4784
|
-
wrapperStyles.maxHeight = nodeRect.height;
|
|
4785
|
-
}
|
|
4786
|
-
else {
|
|
4787
|
-
if (isPercentValue(cfStyles.width))
|
|
4788
|
-
overrideStyles.maxWidth = nodeRect.width;
|
|
4789
|
-
if (isPercentValue(cfStyles.height))
|
|
4790
|
-
overrideStyles.maxHeight = nodeRect.height;
|
|
4791
|
-
}
|
|
4792
|
-
}
|
|
4793
|
-
return { overrideStyles, wrapperStyles };
|
|
4794
|
-
}, [
|
|
4795
|
-
cfStyles,
|
|
4796
|
-
options?.wrapContainerWidth,
|
|
4797
|
-
requiresDragWrapper,
|
|
4798
|
-
node.data.id,
|
|
4799
|
-
draggingId,
|
|
4800
|
-
nodeRect,
|
|
4801
|
-
cfVisibility,
|
|
4802
|
-
]);
|
|
4803
|
-
// Styles that will be applied to the component element
|
|
4804
|
-
// This has to be memoized to avoid recreating the styles in useEditorModeClassName on every render
|
|
4805
|
-
const componentStyles = useMemo(() => ({
|
|
4806
|
-
...cfStyles,
|
|
4807
|
-
...overrideStyles,
|
|
4808
|
-
...(isEmptyZone &&
|
|
4809
|
-
isStructureWithRelativeHeight(node?.data.blockId, cfStyles.height) && {
|
|
4810
|
-
minHeight: EMPTY_CONTAINER_HEIGHT,
|
|
4811
|
-
}),
|
|
4812
|
-
...(userIsDragging &&
|
|
4813
|
-
isStructureComponent &&
|
|
4814
|
-
!isSingleColumn &&
|
|
4815
|
-
!isAssemblyBlock && {
|
|
4816
|
-
padding: addExtraDropzonePadding(cfStyles.padding?.toString() || '0 0 0 0'),
|
|
4817
|
-
}),
|
|
4818
|
-
}), [
|
|
4819
|
-
cfStyles,
|
|
4820
|
-
isAssemblyBlock,
|
|
4821
|
-
isEmptyZone,
|
|
4822
|
-
isSingleColumn,
|
|
4823
|
-
isStructureComponent,
|
|
4824
|
-
node?.data.blockId,
|
|
4825
|
-
overrideStyles,
|
|
4826
|
-
userIsDragging,
|
|
4827
|
-
]);
|
|
4828
|
-
const componentClass = useEditorModeClassName({
|
|
4829
|
-
styles: componentStyles,
|
|
4830
|
-
nodeId: node.data.id,
|
|
4831
|
-
});
|
|
4832
|
-
const sharedProps = {
|
|
4833
|
-
'data-cf-node-id': node.data.id,
|
|
4834
|
-
'data-cf-node-block-id': node.data.blockId,
|
|
4835
|
-
'data-cf-node-block-type': node.type,
|
|
4836
|
-
className: props.cfSsrClassName ?? componentClass,
|
|
4837
|
-
...(definition?.children ? { children: renderDropzone(node) } : {}),
|
|
4838
|
-
};
|
|
4839
|
-
const customComponentProps = {
|
|
4840
|
-
...sharedProps,
|
|
4841
|
-
// Allows custom components to render differently in the editor. This needs to be activated
|
|
4842
|
-
// through options as the component has to be aware of this prop to not cause any React warnings.
|
|
4843
|
-
...(options?.enableCustomEditorView ? { isInExpEditorMode: true } : {}),
|
|
4844
|
-
...sanitizeNodeProps(props),
|
|
4845
|
-
};
|
|
4846
|
-
const structuralOrPatternComponentProps = {
|
|
4847
|
-
...sharedProps,
|
|
4848
|
-
editorMode: true,
|
|
4849
|
-
node,
|
|
4850
|
-
renderDropzone,
|
|
4851
|
-
};
|
|
4852
|
-
return {
|
|
4853
|
-
componentProps: isStructureComponent || isPatternNode
|
|
4854
|
-
? structuralOrPatternComponentProps
|
|
4855
|
-
: customComponentProps,
|
|
4856
|
-
componentStyles,
|
|
4857
|
-
wrapperStyles,
|
|
4858
|
-
};
|
|
4859
|
-
};
|
|
4860
|
-
const addExtraDropzonePadding = (padding) => padding
|
|
4861
|
-
.split(' ')
|
|
4862
|
-
.map((value) => parseFloat(value) === 0 ? `${DRAG_PADDING}px` : `calc(${value} + ${DRAG_PADDING}px)`)
|
|
4863
|
-
.join(' ');
|
|
4864
|
-
const isPercentValue = (value) => typeof value === 'string' && value.endsWith('%');
|
|
4865
|
-
|
|
4866
|
-
class ImportedComponentError extends Error {
|
|
4867
|
-
constructor(message) {
|
|
4868
|
-
super(message);
|
|
4869
|
-
this.name = 'ImportedComponentError';
|
|
4870
|
-
}
|
|
4871
|
-
}
|
|
4872
|
-
class ExperienceSDKError extends Error {
|
|
4873
|
-
constructor(message) {
|
|
4874
|
-
super(message);
|
|
4875
|
-
this.name = 'ExperienceSDKError';
|
|
4876
|
-
}
|
|
4877
|
-
}
|
|
4878
|
-
class ImportedComponentErrorBoundary extends React.Component {
|
|
4879
|
-
componentDidCatch(error, _errorInfo) {
|
|
4880
|
-
if (error.name === 'ImportedComponentError' || error.name === 'ExperienceSDKError') {
|
|
4881
|
-
// This error was already handled by a nested error boundary and should be passed upwards
|
|
4882
|
-
// We have to do this as we wrap every component on every layer with this error boundary and
|
|
4883
|
-
// thus an error deep in the tree bubbles through many layers of error boundaries.
|
|
4884
|
-
throw error;
|
|
4885
|
-
}
|
|
4886
|
-
// Differentiate between custom and SDK-provided components for error tracking
|
|
4887
|
-
const ErrorClass = isContentfulComponent(this.props.componentId)
|
|
4888
|
-
? ExperienceSDKError
|
|
4889
|
-
: ImportedComponentError;
|
|
4890
|
-
const err = new ErrorClass(error.message);
|
|
4891
|
-
err.stack = error.stack;
|
|
4892
|
-
throw err;
|
|
4893
|
-
}
|
|
4894
|
-
render() {
|
|
4895
|
-
return this.props.children;
|
|
4896
|
-
}
|
|
4897
|
-
}
|
|
4898
|
-
|
|
4899
|
-
const MissingComponentPlaceholder = ({ blockId }) => {
|
|
4900
|
-
return (React.createElement("div", { style: {
|
|
4901
|
-
border: '1px solid red',
|
|
4902
|
-
width: '100%',
|
|
4903
|
-
height: '100%',
|
|
4904
|
-
} },
|
|
4905
|
-
"Missing component '",
|
|
4906
|
-
blockId,
|
|
4907
|
-
"'"));
|
|
4908
|
-
};
|
|
4909
|
-
|
|
4910
|
-
const CircularDependencyErrorPlaceholder = forwardRef(({ wrappingPatternIds, ...props }, ref) => {
|
|
4911
|
-
const entityStore = useEntityStore((state) => state.entityStore);
|
|
4912
|
-
return (React.createElement("div", { ...props,
|
|
4913
|
-
// Pass through ref to avoid DND errors being logged
|
|
4914
|
-
ref: ref, "data-cf-node-error": "circular-pattern-dependency", style: {
|
|
4915
|
-
border: '1px solid red',
|
|
4916
|
-
background: 'rgba(255, 0, 0, 0.1)',
|
|
4917
|
-
padding: '1rem 1rem 0 1rem',
|
|
4918
|
-
width: '100%',
|
|
4919
|
-
height: '100%',
|
|
4920
|
-
} },
|
|
4921
|
-
"Circular usage of patterns detected:",
|
|
4922
|
-
React.createElement("ul", null, Array.from(wrappingPatternIds).map((patternId) => {
|
|
4923
|
-
const entryLink = { sys: { type: 'Link', linkType: 'Entry', id: patternId } };
|
|
4924
|
-
const entry = entityStore.getEntityFromLink(entryLink);
|
|
4925
|
-
const entryTitle = entry?.fields?.title;
|
|
4926
|
-
const text = entryTitle ? `${entryTitle} (${patternId})` : patternId;
|
|
4927
|
-
return React.createElement("li", { key: patternId }, text);
|
|
4928
|
-
}))));
|
|
4929
|
-
});
|
|
4930
|
-
CircularDependencyErrorPlaceholder.displayName = 'CircularDependencyErrorPlaceholder';
|
|
4931
|
-
|
|
4932
|
-
const useComponent = ({ node, resolveDesignValue, renderDropzone, userIsDragging, wrappingPatternIds, }) => {
|
|
4933
|
-
const areEntitiesFetched = useEntityStore((state) => state.areEntitiesFetched);
|
|
4934
|
-
const tree = useTreeStore((state) => state.tree);
|
|
4935
|
-
const componentRegistration = useMemo(() => {
|
|
4936
|
-
let registration = componentRegistry.get(node.data.blockId);
|
|
4937
|
-
if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
|
|
4938
|
-
registration = createAssemblyRegistration({
|
|
4939
|
-
definitionId: node.data.blockId,
|
|
4940
|
-
component: Assembly,
|
|
4941
|
-
});
|
|
4942
|
-
}
|
|
4943
|
-
if (!registration) {
|
|
4944
|
-
console.warn(`Component registration not found for component with id: "${node.data.blockId}". The registered component might have been removed from the code. To proceed, remove the component manually from the layers tab.`);
|
|
4945
|
-
return undefined;
|
|
4946
|
-
}
|
|
4947
|
-
return registration;
|
|
4948
|
-
}, [node]);
|
|
4949
|
-
const componentId = node.data.id;
|
|
4950
|
-
const isPatternNode = node.type === ASSEMBLY_NODE_TYPE;
|
|
4951
|
-
const isPatternComponent = node.type === ASSEMBLY_BLOCK_NODE_TYPE;
|
|
4952
|
-
const parentComponentNode = getItem({ id: node.parentId }, tree);
|
|
4953
|
-
const isNestedPattern = isPatternNode &&
|
|
4954
|
-
[ASSEMBLY_BLOCK_NODE_TYPE, ASSEMBLY_NODE_TYPE].includes(parentComponentNode?.type ?? '');
|
|
4955
|
-
const isStructureComponent = isContentfulStructureComponent(node.data.blockId);
|
|
4956
|
-
const requiresDragWrapper = !isPatternNode && !isStructureComponent && !componentRegistration?.options?.wrapComponent;
|
|
4957
|
-
const { componentProps, wrapperStyles } = useComponentProps({
|
|
3956
|
+
// We are rendering a pattern (assembly) entry. Content properties cannot be edited in this,
|
|
3957
|
+
// so we always render the default value
|
|
3958
|
+
return {
|
|
3959
|
+
...acc,
|
|
3960
|
+
// This can either a design (style) or a content variable
|
|
3961
|
+
[variableName]: variableDefinition.defaultValue,
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
else {
|
|
3965
|
+
return { ...acc };
|
|
3966
|
+
}
|
|
3967
|
+
}, {});
|
|
3968
|
+
return {
|
|
3969
|
+
...propsBase,
|
|
3970
|
+
...extractedProps,
|
|
3971
|
+
};
|
|
3972
|
+
}, [
|
|
3973
|
+
hyperlinkPattern,
|
|
4958
3974
|
node,
|
|
4959
|
-
|
|
3975
|
+
locale,
|
|
3976
|
+
definition,
|
|
4960
3977
|
resolveDesignValue,
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
3978
|
+
dataSource,
|
|
3979
|
+
areEntitiesFetched,
|
|
3980
|
+
unboundValues,
|
|
3981
|
+
entityStore,
|
|
3982
|
+
]);
|
|
3983
|
+
const cfStyles = useMemo(() => buildCfStyles(props), [props]);
|
|
3984
|
+
// Styles that will be applied to the component element
|
|
3985
|
+
const componentStyles = useMemo(() => ({
|
|
3986
|
+
...cfStyles,
|
|
3987
|
+
...(!node.children.length &&
|
|
3988
|
+
isStructureWithRelativeHeight(node.data.blockId, cfStyles.height) && {
|
|
3989
|
+
minHeight: EMPTY_CONTAINER_HEIGHT$1,
|
|
3990
|
+
}),
|
|
3991
|
+
}), [cfStyles, node.children.length, node.data.blockId]);
|
|
3992
|
+
const cfCsrClassName = useEditorModeClassName({
|
|
3993
|
+
styles: componentStyles,
|
|
3994
|
+
nodeId: node.data.id,
|
|
4966
3995
|
});
|
|
4967
|
-
const
|
|
4968
|
-
const
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
innerRef(refNode);
|
|
4974
|
-
};
|
|
4975
|
-
if (!componentRegistration) {
|
|
4976
|
-
return React.createElement(MissingComponentPlaceholder, { blockId: node.data.blockId });
|
|
4977
|
-
}
|
|
4978
|
-
if (node.data.blockId && wrappingPatternIds.has(node.data.blockId)) {
|
|
4979
|
-
return (React.createElement(CircularDependencyErrorPlaceholder, { ref: refCallback, "data-cf-node-id": dataCfNodeId, "data-cf-node-block-id": dataCfNodeBlockId, "data-cf-node-block-type": dataCfNodeBlockType, wrappingPatternIds: wrappingPatternIds }));
|
|
4980
|
-
}
|
|
4981
|
-
const element = React.createElement(ImportedComponentErrorBoundary, { componentId: node.data.blockId }, React.createElement(componentRegistration.component, {
|
|
4982
|
-
...componentProps,
|
|
4983
|
-
dragProps,
|
|
4984
|
-
}));
|
|
4985
|
-
if (!requiresDragWrapper) {
|
|
4986
|
-
return element;
|
|
4987
|
-
}
|
|
4988
|
-
return (React.createElement(Tag, { ...rest, style: { ...style, ...wrapperStyles }, ref: refCallback, "data-cf-node-id": dataCfNodeId, "data-cf-node-block-id": dataCfNodeBlockId, "data-cf-node-block-type": dataCfNodeBlockType },
|
|
4989
|
-
ToolTipAndPlaceholder,
|
|
4990
|
-
element));
|
|
4991
|
-
};
|
|
4992
|
-
return {
|
|
4993
|
-
node,
|
|
4994
|
-
parentComponentNode,
|
|
4995
|
-
isAssembly: isPatternNode,
|
|
4996
|
-
isPatternNode,
|
|
4997
|
-
isPatternComponent,
|
|
4998
|
-
isNestedPattern,
|
|
4999
|
-
componentId,
|
|
5000
|
-
elementToRender,
|
|
5001
|
-
definition: componentRegistration?.definition,
|
|
5002
|
-
};
|
|
5003
|
-
};
|
|
5004
|
-
|
|
5005
|
-
const calcOffsetLeft = (parentElement, placeholderWidth, nodeWidth) => {
|
|
5006
|
-
if (!parentElement) {
|
|
5007
|
-
return 0;
|
|
5008
|
-
}
|
|
5009
|
-
const alignItems = window.getComputedStyle(parentElement).alignItems;
|
|
5010
|
-
if (alignItems === 'center') {
|
|
5011
|
-
return -(placeholderWidth - nodeWidth) / 2;
|
|
5012
|
-
}
|
|
5013
|
-
if (alignItems === 'end') {
|
|
5014
|
-
return -placeholderWidth + nodeWidth + 2;
|
|
5015
|
-
}
|
|
5016
|
-
return 0;
|
|
5017
|
-
};
|
|
5018
|
-
const calcOffsetTop = (parentElement, placeholderHeight, nodeHeight) => {
|
|
5019
|
-
if (!parentElement) {
|
|
5020
|
-
return 0;
|
|
5021
|
-
}
|
|
5022
|
-
const alignItems = window.getComputedStyle(parentElement).alignItems;
|
|
5023
|
-
if (alignItems === 'center') {
|
|
5024
|
-
return -(placeholderHeight - nodeHeight) / 2;
|
|
5025
|
-
}
|
|
5026
|
-
if (alignItems === 'end') {
|
|
5027
|
-
return -placeholderHeight + nodeHeight + 2;
|
|
5028
|
-
}
|
|
5029
|
-
return 0;
|
|
5030
|
-
};
|
|
5031
|
-
const getPaddingOffset = (element) => {
|
|
5032
|
-
const paddingLeft = parseFloat(window.getComputedStyle(element).paddingLeft);
|
|
5033
|
-
const paddingRight = parseFloat(window.getComputedStyle(element).paddingRight);
|
|
5034
|
-
const paddingTop = parseFloat(window.getComputedStyle(element).paddingTop);
|
|
5035
|
-
const paddingBottom = parseFloat(window.getComputedStyle(element).paddingBottom);
|
|
5036
|
-
const horizontalOffset = paddingLeft + paddingRight;
|
|
5037
|
-
const verticalOffset = paddingTop + paddingBottom;
|
|
5038
|
-
return [horizontalOffset, verticalOffset];
|
|
5039
|
-
};
|
|
5040
|
-
/**
|
|
5041
|
-
* Calculate the size and position of the dropzone indicator
|
|
5042
|
-
* when dragging a new component onto the canvas
|
|
5043
|
-
*/
|
|
5044
|
-
const calcNewComponentStyles = (params) => {
|
|
5045
|
-
const { destinationIndex, elementIndex, dropzoneElementId, id, direction, totalIndexes } = params;
|
|
5046
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5047
|
-
const isHorizontal = direction === 'horizontal';
|
|
5048
|
-
const isRightAlign = isHorizontal && isEnd;
|
|
5049
|
-
const isBottomAlign = !isHorizontal && isEnd;
|
|
5050
|
-
const dropzone = document.querySelector(`[data-rfd-droppable-id="${dropzoneElementId}"]`);
|
|
5051
|
-
const element = document.querySelector(`[data-ctfl-draggable-id="${id}"]`);
|
|
5052
|
-
if (!dropzone || !element) {
|
|
5053
|
-
return emptyStyles;
|
|
5054
|
-
}
|
|
5055
|
-
const elementSizes = element.getBoundingClientRect();
|
|
5056
|
-
const dropzoneSizes = dropzone.getBoundingClientRect();
|
|
5057
|
-
const [horizontalPadding, verticalPadding] = getPaddingOffset(dropzone);
|
|
5058
|
-
const width = isHorizontal ? DRAGGABLE_WIDTH : dropzoneSizes.width - horizontalPadding;
|
|
5059
|
-
const height = isHorizontal ? dropzoneSizes.height - verticalPadding : DRAGGABLE_HEIGHT;
|
|
5060
|
-
const top = isHorizontal
|
|
5061
|
-
? calcOffsetTop(element.parentElement, height, elementSizes.height)
|
|
5062
|
-
: -height;
|
|
5063
|
-
const left = isHorizontal
|
|
5064
|
-
? -width
|
|
5065
|
-
: calcOffsetLeft(element.parentElement, width, elementSizes.width);
|
|
5066
|
-
return {
|
|
5067
|
-
width,
|
|
5068
|
-
height,
|
|
5069
|
-
top: !isBottomAlign ? top : 'unset',
|
|
5070
|
-
right: isRightAlign ? -width : 'unset',
|
|
5071
|
-
bottom: isBottomAlign ? -height : 'unset',
|
|
5072
|
-
left: !isRightAlign ? left : 'unset',
|
|
5073
|
-
};
|
|
5074
|
-
};
|
|
5075
|
-
/**
|
|
5076
|
-
* Calculate the size and position of the dropzone indicator
|
|
5077
|
-
* when moving an existing component on the canvas
|
|
5078
|
-
*/
|
|
5079
|
-
const calcMovementStyles = (params) => {
|
|
5080
|
-
const { destinationIndex, sourceIndex, destinationId, sourceId, elementIndex, dropzoneElementId, id, direction, totalIndexes, draggableId, } = params;
|
|
5081
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5082
|
-
const isHorizontal = direction === 'horizontal';
|
|
5083
|
-
const isSameZone = destinationId === sourceId;
|
|
5084
|
-
const isBelowSourceIndex = destinationIndex > sourceIndex;
|
|
5085
|
-
const isRightAlign = isHorizontal && (isEnd || (isSameZone && isBelowSourceIndex));
|
|
5086
|
-
const isBottomAlign = !isHorizontal && (isEnd || (isSameZone && isBelowSourceIndex));
|
|
5087
|
-
const dropzone = document.querySelector(`[data-rfd-droppable-id="${dropzoneElementId}"]`);
|
|
5088
|
-
const draggable = document.querySelector(`[data-rfd-draggable-id="${draggableId}"]`);
|
|
5089
|
-
const element = document.querySelector(`[data-ctfl-draggable-id="${id}"]`);
|
|
5090
|
-
if (!dropzone || !element || !draggable) {
|
|
5091
|
-
return emptyStyles;
|
|
5092
|
-
}
|
|
5093
|
-
const elementSizes = element.getBoundingClientRect();
|
|
5094
|
-
const dropzoneSizes = dropzone.getBoundingClientRect();
|
|
5095
|
-
const draggableSizes = draggable.getBoundingClientRect();
|
|
5096
|
-
const [horizontalPadding, verticalPadding] = getPaddingOffset(dropzone);
|
|
5097
|
-
const width = isHorizontal ? draggableSizes.width : dropzoneSizes.width - horizontalPadding;
|
|
5098
|
-
const height = isHorizontal ? dropzoneSizes.height - verticalPadding : draggableSizes.height;
|
|
5099
|
-
const top = isHorizontal
|
|
5100
|
-
? calcOffsetTop(element.parentElement, height, elementSizes.height)
|
|
5101
|
-
: -height;
|
|
5102
|
-
const left = isHorizontal
|
|
5103
|
-
? -width
|
|
5104
|
-
: calcOffsetLeft(element.parentElement, width, elementSizes.width);
|
|
5105
|
-
return {
|
|
5106
|
-
width,
|
|
5107
|
-
height,
|
|
5108
|
-
top: !isBottomAlign ? top : 'unset',
|
|
5109
|
-
right: isRightAlign ? -width : 'unset',
|
|
5110
|
-
bottom: isBottomAlign ? -height : 'unset',
|
|
5111
|
-
left: !isRightAlign ? left : 'unset',
|
|
5112
|
-
};
|
|
5113
|
-
};
|
|
5114
|
-
const emptyStyles = { width: 0, height: 0 };
|
|
5115
|
-
const calcPlaceholderStyles = (params) => {
|
|
5116
|
-
const { isDraggingOver, sourceId } = params;
|
|
5117
|
-
if (!isDraggingOver) {
|
|
5118
|
-
return emptyStyles;
|
|
5119
|
-
}
|
|
5120
|
-
if (sourceId === COMPONENT_LIST_ID) {
|
|
5121
|
-
return calcNewComponentStyles(params);
|
|
5122
|
-
}
|
|
5123
|
-
return calcMovementStyles(params);
|
|
5124
|
-
};
|
|
5125
|
-
const Placeholder = (props) => {
|
|
5126
|
-
const sourceIndex = useDraggedItemStore((state) => state.draggedItem?.source.index) ?? -1;
|
|
5127
|
-
const draggableId = useDraggedItemStore((state) => state.draggedItem?.draggableId) ?? '';
|
|
5128
|
-
const sourceId = useDraggedItemStore((state) => state.draggedItem?.source.droppableId) ?? '';
|
|
5129
|
-
const destinationIndex = useDraggedItemStore((state) => state.draggedItem?.destination?.index) ?? -1;
|
|
5130
|
-
const destinationId = useDraggedItemStore((state) => state.draggedItem?.destination?.droppableId) ?? '';
|
|
5131
|
-
const { elementIndex, totalIndexes, isDraggingOver } = props;
|
|
5132
|
-
const isActive = destinationIndex === elementIndex;
|
|
5133
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5134
|
-
const isVisible = isEnd || isActive;
|
|
5135
|
-
const isComponentList = destinationId === COMPONENT_LIST_ID;
|
|
5136
|
-
return (!isComponentList &&
|
|
5137
|
-
isDraggingOver &&
|
|
5138
|
-
isVisible && (React.createElement("div", { style: {
|
|
5139
|
-
...calcPlaceholderStyles({
|
|
5140
|
-
...props,
|
|
5141
|
-
sourceId,
|
|
5142
|
-
sourceIndex,
|
|
5143
|
-
destinationId,
|
|
5144
|
-
destinationIndex,
|
|
5145
|
-
draggableId,
|
|
5146
|
-
}),
|
|
5147
|
-
backgroundColor: 'rgba(var(--exp-builder-blue300-rgb), 0.5)',
|
|
5148
|
-
position: 'absolute',
|
|
5149
|
-
pointerEvents: 'none',
|
|
5150
|
-
} })));
|
|
5151
|
-
};
|
|
5152
|
-
|
|
5153
|
-
var css_248z$2 = ".styles-module_hitbox__i3wKV {\n position: fixed;\n pointer-events: all;\n}\n";
|
|
5154
|
-
var styles$2 = {"hitbox":"styles-module_hitbox__i3wKV"};
|
|
5155
|
-
styleInject(css_248z$2);
|
|
5156
|
-
|
|
5157
|
-
const useZoneStore = create()((set) => ({
|
|
5158
|
-
zones: {},
|
|
5159
|
-
hoveringZone: '',
|
|
5160
|
-
setHoveringZone(zoneId) {
|
|
5161
|
-
set({
|
|
5162
|
-
hoveringZone: zoneId,
|
|
5163
|
-
});
|
|
5164
|
-
},
|
|
5165
|
-
upsertZone(id, data) {
|
|
5166
|
-
set(produce((state) => {
|
|
5167
|
-
state.zones[id] = { ...(state.zones[id] || {}), ...data };
|
|
5168
|
-
}));
|
|
5169
|
-
},
|
|
5170
|
-
}));
|
|
5171
|
-
|
|
5172
|
-
const { WIDTH, HEIGHT, INITIAL_OFFSET, OFFSET_INCREMENT, MIN_HEIGHT, MIN_DEPTH_HEIGHT, DEEP_ZONE } = HITBOX;
|
|
5173
|
-
const calcOffsetDepth = (depth) => {
|
|
5174
|
-
return INITIAL_OFFSET - OFFSET_INCREMENT * depth;
|
|
5175
|
-
};
|
|
5176
|
-
const getHitboxStyles = ({ direction, zoneDepth, domRect, scrollY, offsetRect, }) => {
|
|
5177
|
-
if (!domRect) {
|
|
5178
|
-
return {
|
|
5179
|
-
display: 'none',
|
|
3996
|
+
const componentProps = useMemo(() => {
|
|
3997
|
+
const sharedProps = {
|
|
3998
|
+
'data-cf-node-id': node.data.id,
|
|
3999
|
+
'data-cf-node-block-id': node.data.blockId,
|
|
4000
|
+
'data-cf-node-block-type': node.type,
|
|
4001
|
+
className: props.cfSsrClassName ?? cfCsrClassName,
|
|
5180
4002
|
};
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
const MAX_SELF_HEIGHT = DRAGGABLE_HEIGHT * 2;
|
|
5185
|
-
const isDeepZone = zoneDepth > DEEP_ZONE;
|
|
5186
|
-
const isAboveMaxHeight = height > MAX_SELF_HEIGHT;
|
|
5187
|
-
switch (direction) {
|
|
5188
|
-
case HitboxDirection.TOP:
|
|
5189
|
-
return {
|
|
5190
|
-
width,
|
|
5191
|
-
height: HEIGHT,
|
|
5192
|
-
top: top + offsetHeight - calcOffsetDepth(zoneDepth) - scrollY,
|
|
5193
|
-
left,
|
|
5194
|
-
zIndex: 100 + zoneDepth,
|
|
5195
|
-
};
|
|
5196
|
-
case HitboxDirection.BOTTOM:
|
|
5197
|
-
return {
|
|
5198
|
-
width,
|
|
5199
|
-
height: HEIGHT,
|
|
5200
|
-
top: bottom + offsetHeight + calcOffsetDepth(zoneDepth) - scrollY,
|
|
5201
|
-
left,
|
|
5202
|
-
zIndex: 100 + zoneDepth,
|
|
5203
|
-
};
|
|
5204
|
-
case HitboxDirection.LEFT:
|
|
5205
|
-
return {
|
|
5206
|
-
width: WIDTH,
|
|
5207
|
-
height: height - HEIGHT,
|
|
5208
|
-
left: left + offsetWidth - calcOffsetDepth(zoneDepth) - WIDTH / 2,
|
|
5209
|
-
top: top + HEIGHT / 2 - scrollY,
|
|
5210
|
-
zIndex: 100 + zoneDepth,
|
|
5211
|
-
};
|
|
5212
|
-
case HitboxDirection.RIGHT:
|
|
5213
|
-
return {
|
|
5214
|
-
width: WIDTH,
|
|
5215
|
-
height: height - HEIGHT,
|
|
5216
|
-
left: right + offsetWidth + calcOffsetDepth(zoneDepth) - WIDTH / 2,
|
|
5217
|
-
top: top + HEIGHT / 2 - scrollY,
|
|
5218
|
-
zIndex: 100 + zoneDepth,
|
|
5219
|
-
};
|
|
5220
|
-
case HitboxDirection.SELF_VERTICAL: {
|
|
5221
|
-
if (isAboveMaxHeight && !isDeepZone) {
|
|
5222
|
-
return { display: 'none' };
|
|
5223
|
-
}
|
|
5224
|
-
const selfHeight = isDeepZone ? MIN_DEPTH_HEIGHT : MIN_HEIGHT;
|
|
5225
|
-
return {
|
|
5226
|
-
width,
|
|
5227
|
-
height: selfHeight,
|
|
5228
|
-
left,
|
|
5229
|
-
top: top + height / 2 - selfHeight / 2 - scrollY,
|
|
5230
|
-
zIndex: 1000 + zoneDepth,
|
|
5231
|
-
};
|
|
5232
|
-
}
|
|
5233
|
-
case HitboxDirection.SELF_HORIZONTAL: {
|
|
5234
|
-
if (width > DRAGGABLE_WIDTH) {
|
|
5235
|
-
return { display: 'none' };
|
|
5236
|
-
}
|
|
4003
|
+
// Only pass `editorMode` and `node` to structure components and assembly root nodes.
|
|
4004
|
+
const isStructureComponent = isContentfulStructureComponent(node.data.blockId);
|
|
4005
|
+
if (isStructureComponent) {
|
|
5237
4006
|
return {
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
top: top - scrollY,
|
|
5242
|
-
zIndex: 1000 + zoneDepth,
|
|
4007
|
+
...sharedProps,
|
|
4008
|
+
editorMode: true,
|
|
4009
|
+
node,
|
|
5243
4010
|
};
|
|
5244
4011
|
}
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
const zoneDepth = useMemo(() => getItemDepthFromNode({ id: parentZoneId }, tree.root), [tree, parentZoneId]);
|
|
5255
|
-
const zones = useZoneStore((state) => state.zones);
|
|
5256
|
-
const hoveringZone = useZoneStore((state) => state.hoveringZone);
|
|
5257
|
-
const isHoveringZone = hoveringZone === zoneId;
|
|
5258
|
-
const hitboxContainer = useMemo(() => {
|
|
5259
|
-
return document.querySelector('[data-ctfl-hitboxes]');
|
|
5260
|
-
}, []);
|
|
5261
|
-
const domRect = useMemo(() => {
|
|
5262
|
-
if (!isDraggingOnCanvas)
|
|
5263
|
-
return;
|
|
5264
|
-
return document.querySelector(`[${CTFL_ZONE_ID}="${zoneId}"]`)?.getBoundingClientRect();
|
|
5265
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5266
|
-
}, [zoneId, isDraggingOnCanvas]);
|
|
5267
|
-
// Use the size of the cloned dragging element to offset the position of the hitboxes
|
|
5268
|
-
// So that when dragging causes a dropzone to expand, the hitboxes will be in the correct position
|
|
5269
|
-
const offsetRect = useMemo(() => {
|
|
5270
|
-
if (!isDraggingOnCanvas || isEmptyZone || !isHoveringZone)
|
|
5271
|
-
return;
|
|
5272
|
-
return document.querySelector(`[${CTFL_DRAGGING_ELEMENT}]`)?.getBoundingClientRect();
|
|
5273
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5274
|
-
}, [isEmptyZone, isHoveringZone, isDraggingOnCanvas]);
|
|
5275
|
-
const zoneDirection = zones[parentZoneId]?.direction || 'vertical';
|
|
5276
|
-
const isVertical = zoneDirection === 'vertical';
|
|
5277
|
-
const isRoot = parentZoneId === ROOT_ID;
|
|
5278
|
-
const { slotId: parentSlotId } = parseZoneId(parentZoneId);
|
|
5279
|
-
const getStyles = useCallback((direction) => getHitboxStyles({
|
|
5280
|
-
direction,
|
|
5281
|
-
zoneDepth,
|
|
5282
|
-
domRect,
|
|
5283
|
-
scrollY,
|
|
5284
|
-
offsetRect,
|
|
5285
|
-
}), [zoneDepth, domRect, scrollY, offsetRect]);
|
|
5286
|
-
const renderFinalRootHitbox = () => {
|
|
5287
|
-
if (!isRoot)
|
|
5288
|
-
return null;
|
|
5289
|
-
return (React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(HitboxDirection.BOTTOM) }));
|
|
5290
|
-
};
|
|
5291
|
-
const renderSurroundingHitboxes = () => {
|
|
5292
|
-
if (isRoot || parentSlotId)
|
|
5293
|
-
return null;
|
|
5294
|
-
return (React.createElement(React.Fragment, null,
|
|
5295
|
-
React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.TOP : HitboxDirection.LEFT) }),
|
|
5296
|
-
React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.BOTTOM : HitboxDirection.RIGHT) })));
|
|
5297
|
-
};
|
|
5298
|
-
const ActiveHitboxes = (React.createElement(React.Fragment, null,
|
|
5299
|
-
React.createElement("div", { "data-ctfl-zone-id": zoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.SELF_VERTICAL : HitboxDirection.SELF_HORIZONTAL) }),
|
|
5300
|
-
renderSurroundingHitboxes(),
|
|
5301
|
-
renderFinalRootHitbox()));
|
|
5302
|
-
if (!hitboxContainer) {
|
|
5303
|
-
return null;
|
|
5304
|
-
}
|
|
5305
|
-
return createPortal(ActiveHitboxes, hitboxContainer);
|
|
5306
|
-
};
|
|
5307
|
-
|
|
5308
|
-
const isRelativePreviewSize = (width) => {
|
|
5309
|
-
// For now, we solely allow 100% as relative value
|
|
5310
|
-
return width === '100%';
|
|
5311
|
-
};
|
|
5312
|
-
const getTooltipPositions = ({ previewSize, tooltipRect, coordinates, }) => {
|
|
5313
|
-
if (!coordinates || !tooltipRect) {
|
|
5314
|
-
return { display: 'none' };
|
|
5315
|
-
}
|
|
5316
|
-
/**
|
|
5317
|
-
* By default, the tooltip floats to the left of the element
|
|
5318
|
-
*/
|
|
5319
|
-
const newTooltipStyles = { display: 'flex' };
|
|
5320
|
-
// If the preview size is relative, we don't change the floating direction
|
|
5321
|
-
if (!isRelativePreviewSize(previewSize)) {
|
|
5322
|
-
const previewSizeMatch = previewSize.match(/(\d{1,})px/);
|
|
5323
|
-
if (!previewSizeMatch) {
|
|
5324
|
-
return { display: 'none' };
|
|
5325
|
-
}
|
|
5326
|
-
const previewSizePx = parseInt(previewSizeMatch[1]);
|
|
5327
|
-
/**
|
|
5328
|
-
* If the element is at the right edge of the canvas, and the element isn't wide enough to fit the tooltip width,
|
|
5329
|
-
* we float the tooltip to the right of the element.
|
|
5330
|
-
*/
|
|
5331
|
-
if (tooltipRect.width > previewSizePx - coordinates.right &&
|
|
5332
|
-
tooltipRect.width > coordinates.width) {
|
|
5333
|
-
newTooltipStyles['float'] = 'right';
|
|
5334
|
-
}
|
|
5335
|
-
}
|
|
5336
|
-
const tooltipHeight = tooltipRect.height === 0 ? 32 : tooltipRect.height;
|
|
5337
|
-
/**
|
|
5338
|
-
* For elements with small heights, we don't want the tooltip covering the content in the element,
|
|
5339
|
-
* so we show the tooltip at the top or bottom.
|
|
5340
|
-
*/
|
|
5341
|
-
if (tooltipHeight * 2 > coordinates.height) {
|
|
5342
|
-
/**
|
|
5343
|
-
* If there's enough space for the tooltip at the top of the element, we show the tooltip at the top of the element,
|
|
5344
|
-
* else we show the tooltip at the bottom.
|
|
5345
|
-
*/
|
|
5346
|
-
if (tooltipHeight < coordinates.top) {
|
|
5347
|
-
newTooltipStyles['bottom'] = coordinates.height;
|
|
5348
|
-
}
|
|
5349
|
-
else {
|
|
5350
|
-
newTooltipStyles['top'] = coordinates.height;
|
|
5351
|
-
}
|
|
5352
|
-
}
|
|
5353
|
-
/**
|
|
5354
|
-
* If the component draws outside of the borders of the canvas to the left we move the tooltip to the right
|
|
5355
|
-
* so that it is fully visible.
|
|
5356
|
-
*/
|
|
5357
|
-
if (coordinates.left < 0) {
|
|
5358
|
-
newTooltipStyles['left'] = -coordinates.left;
|
|
5359
|
-
}
|
|
5360
|
-
/**
|
|
5361
|
-
* If for any reason, the element's top is negative, we show the tooltip at the bottom
|
|
5362
|
-
*/
|
|
5363
|
-
if (coordinates.top < 0) {
|
|
5364
|
-
newTooltipStyles['top'] = coordinates.height;
|
|
5365
|
-
}
|
|
5366
|
-
return newTooltipStyles;
|
|
5367
|
-
};
|
|
5368
|
-
|
|
5369
|
-
var css_248z$1 = ".styles-module_DraggableComponent__oyE7Q,\n.styles-module_Dropzone__3R-sm:not(.styles-module_isSlot__HI9yO) {\n position: relative;\n transition: background-color 0.2s;\n pointer-events: all;\n box-sizing: border-box;\n cursor: grab;\n}\n\n.styles-module_DraggableComponent__oyE7Q:before,\n.styles-module_Dropzone__3R-sm:not(.styles-module_isSlot__HI9yO):before {\n content: '';\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n outline-offset: -2px;\n outline: 2px solid transparent;\n z-index: 1;\n transition: outline 0.2s;\n pointer-events: none;\n}\n\n.styles-module_DraggableComponent__oyE7Q.styles-module_isDragging__hldL4.styles-module_Dropzone__3R-sm:before {\n outline-offset: -1px;\n}\n\n.styles-module_DraggableComponent__oyE7Q.styles-module_isDragging__hldL4.styles-module_Dropzone__3R-sm {\n pointer-events: all;\n}\n\n.styles-module_Dropzone__3R-sm.styles-module_fullHeight__afMfT {\n height: 100%;\n}\n\n.styles-module_Dropzone__3R-sm.styles-module_fullWidth__Od117 {\n width: 100%;\n}\n\n.styles-module_isRoot__c-c-x,\n.styles-module_isEmptyCanvas__Mm6Al {\n flex: 1;\n}\n\n.styles-module_isEmptyZone__XZ1Ej {\n min-height: 80px;\n min-width: 80px;\n}\n\n.styles-module_isDragging__hldL4:not(.styles-module_isRoot__c-c-x):not(.styles-module_DraggableClone__CdKIH):before {\n outline: 2px dashed var(--exp-builder-gray300);\n}\n\n.styles-module_Dropzone__3R-sm.styles-module_isDestination__sE70P:not(.styles-module_isRoot__c-c-x):before {\n transition:\n outline 0.2s,\n background-color 0.2s;\n outline: 2px dashed var(--exp-builder-blue400);\n background-color: rgba(var(--exp-builder-blue100-rgb), 0.5);\n z-index: 2;\n}\n\n.styles-module_DraggableClone__CdKIH:before {\n outline: 2px solid var(--exp-builder-blue500);\n}\n\n.styles-module_DropzoneClone__xiT8j,\n.styles-module_DraggableClone__CdKIH,\n.styles-module_DropzoneClone__xiT8j *,\n.styles-module_DraggableClone__CdKIH * {\n pointer-events: none !important;\n}\n\n.styles-module_DraggableComponent__oyE7Q:not(.styles-module_isDragging__hldL4) :not(.styles-module_DraggableComponent__oyE7Q) {\n pointer-events: none;\n}\n\n.styles-module_isDraggingThisComponent__yCZTp {\n overflow: hidden;\n}\n\n.styles-module_isSelected__c2QEJ:before {\n outline: 2px solid transparent !important;\n}\n\n.styles-module_tooltipWrapper__kqvmR {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n z-index: 10;\n pointer-events: none;\n}\n\n.styles-module_DraggableComponent__oyE7Q.styles-module_isDragging__hldL4 .styles-module_tooltipWrapper__kqvmR {\n display: none;\n}\n\n.styles-module_overlay__knwhE {\n position: absolute;\n display: flex;\n align-items: center;\n min-width: max-content;\n height: 24px;\n z-index: 2;\n font-family: var(--exp-builder-font-stack-primary);\n font-size: 14px;\n font-weight: 500;\n background-color: var(--exp-builder-gray500);\n color: var(--exp-builder-color-white);\n padding: 4px 12px 4px 12px;\n transition: opacity 0.1s;\n opacity: 0;\n text-wrap: nowrap;\n}\n\n.styles-module_overlayContainer__lUsiC {\n opacity: 0;\n}\n\n.styles-module_overlayAssembly__3BKl4 {\n background-color: var(--exp-builder-purple600);\n}\n\n.styles-module_isDragging__hldL4 > .styles-module_overlay__knwhE,\n.styles-module_isDragging__hldL4 > .styles-module_overlayContainer__lUsiC {\n opacity: 0 !important;\n}\n\n.styles-module_isDragging__hldL4:not(.styles-module_Dropzone__3R-sm):before {\n outline: 2px solid transparent !important;\n}\n\n.styles-module_isHoveringComponent__f7G5m > div > .styles-module_overlay__knwhE,\n.styles-module_DraggableComponent__oyE7Q:hover:not(:has(.styles-module_DraggableComponent__oyE7Q:hover)) > div > .styles-module_overlay__knwhE {\n opacity: 1;\n}\n\n/* hovering related component in layers tab */\n\n.styles-module_DraggableComponent__oyE7Q:has(.styles-module_isHoveringComponent__f7G5m):not(.styles-module_isAssemblyBlock__goT9z):before,\n.styles-module_DraggableComponent__oyE7Q:has(.styles-module_isHoveringComponent__f7G5m):not(.styles-module_isAssemblyBlock__goT9z) .styles-module_DraggableComponent__oyE7Q:not(.styles-module_isHoveringComponent__f7G5m):not(.styles-module_isAssemblyBlock__goT9z):before,\n.styles-module_isHoveringComponent__f7G5m:not(.styles-module_isAssemblyBlock__goT9z) .styles-module_DraggableComponent__oyE7Q:not(.styles-module_isAssemblyBlock__goT9z):before,\n\n.styles-module_DraggableComponent__oyE7Q:not(.styles-module_isAssemblyBlock__goT9z):not(.styles-module_isDragging__hldL4):hover:before,\n.styles-module_DraggableComponent__oyE7Q:not(.styles-module_isDragging__hldL4):hover .styles-module_DraggableComponent__oyE7Q:before {\n outline: 2px dashed var(--exp-builder-gray500);\n}\n\n/* hovering component in layers tab */\n\n.styles-module_isHoveringComponent__f7G5m:not(.styles-module_isAssemblyBlock__goT9z):before,\n\n.styles-module_DraggableComponent__oyE7Q:not(.styles-module_isAssemblyBlock__goT9z):not(.styles-module_isDragging__hldL4):hover:not(:has(.styles-module_DraggableComponent__oyE7Q:hover)):before {\n outline: 2px solid var(--exp-builder-gray500);\n}\n\n/* hovering related pattern in layers tab */\n\n.styles-module_isAssemblyBlock__goT9z:has(.styles-module_isHoveringComponent__f7G5m):before,\n.styles-module_isAssemblyBlock__goT9z:has(.styles-module_isHoveringComponent__f7G5m) .styles-module_isAssemblyBlock__goT9z:not(.styles-module_isHoveringComponent__f7G5m):before,\n.styles-module_isHoveringComponent__f7G5m .styles-module_isAssemblyBlock__goT9z:before,\n\n.styles-module_isAssemblyBlock__goT9z:hover:before,\n.styles-module_isAssemblyBlock__goT9z:hover .styles-module_DraggableComponent__oyE7Q:before,\n.styles-module_DraggableComponent__oyE7Q:not(.styles-module_isDragging__hldL4):hover .styles-module_isAssemblyBlock__goT9z:before {\n outline: 2px dashed var(--exp-builder-purple600);\n}\n\n/* hovering pattern in layers tab */\n\n.styles-module_isAssemblyBlock__goT9z.styles-module_isHoveringComponent__f7G5m:before,\n\n.styles-module_isAssemblyBlock__goT9z:hover:not(:has(.styles-module_DraggableComponent__oyE7Q:hover)):before {\n outline: 2px solid var(--exp-builder-purple600);\n}\n";
|
|
5370
|
-
var styles$1 = {"DraggableComponent":"styles-module_DraggableComponent__oyE7Q","Dropzone":"styles-module_Dropzone__3R-sm","isSlot":"styles-module_isSlot__HI9yO","isDragging":"styles-module_isDragging__hldL4","fullHeight":"styles-module_fullHeight__afMfT","fullWidth":"styles-module_fullWidth__Od117","isRoot":"styles-module_isRoot__c-c-x","isEmptyCanvas":"styles-module_isEmptyCanvas__Mm6Al","isEmptyZone":"styles-module_isEmptyZone__XZ1Ej","DraggableClone":"styles-module_DraggableClone__CdKIH","isDestination":"styles-module_isDestination__sE70P","DropzoneClone":"styles-module_DropzoneClone__xiT8j","isDraggingThisComponent":"styles-module_isDraggingThisComponent__yCZTp","isSelected":"styles-module_isSelected__c2QEJ","tooltipWrapper":"styles-module_tooltipWrapper__kqvmR","overlay":"styles-module_overlay__knwhE","overlayContainer":"styles-module_overlayContainer__lUsiC","overlayAssembly":"styles-module_overlayAssembly__3BKl4","isHoveringComponent":"styles-module_isHoveringComponent__f7G5m","isAssemblyBlock":"styles-module_isAssemblyBlock__goT9z"};
|
|
5371
|
-
styleInject(css_248z$1);
|
|
5372
|
-
|
|
5373
|
-
const Tooltip = ({ coordinates, id, label, isAssemblyBlock, isContainer, isSelected, }) => {
|
|
5374
|
-
const tooltipRef = useRef(null);
|
|
5375
|
-
const previewSize = '100%'; // This should be based on breakpoints and added to usememo dependency array
|
|
5376
|
-
const tooltipStyles = useMemo(() => {
|
|
5377
|
-
const tooltipRect = tooltipRef.current?.getBoundingClientRect();
|
|
5378
|
-
const draggableRect = document
|
|
5379
|
-
.querySelector(`[data-ctfl-draggable-id="${id}"]`)
|
|
5380
|
-
?.getBoundingClientRect();
|
|
5381
|
-
const newTooltipStyles = getTooltipPositions({
|
|
5382
|
-
previewSize,
|
|
5383
|
-
tooltipRect,
|
|
5384
|
-
coordinates: draggableRect,
|
|
5385
|
-
});
|
|
5386
|
-
return newTooltipStyles;
|
|
5387
|
-
// Ignore eslint because we intentionally want to trigger this whenever a user clicks on a container/component which is tracked by these coordinates of the component being clicked being changed
|
|
5388
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5389
|
-
}, [coordinates, id, tooltipRef.current]);
|
|
5390
|
-
if (isSelected) {
|
|
5391
|
-
return null;
|
|
5392
|
-
}
|
|
5393
|
-
return (React.createElement("div", { "data-tooltip": true, className: styles$1.tooltipWrapper },
|
|
5394
|
-
React.createElement("div", { "data-tooltip": true, ref: tooltipRef, style: tooltipStyles, className: classNames(styles$1.overlay, {
|
|
5395
|
-
[styles$1.overlayContainer]: isContainer,
|
|
5396
|
-
[styles$1.overlayAssembly]: isAssemblyBlock,
|
|
5397
|
-
}) }, label)));
|
|
4012
|
+
return {
|
|
4013
|
+
...sharedProps,
|
|
4014
|
+
// Allows custom components to render differently in the editor. This needs to be activated
|
|
4015
|
+
// through options as the component has to be aware of this prop to not cause any React warnings.
|
|
4016
|
+
...(options?.enableCustomEditorView ? { isInExpEditorMode: true } : {}),
|
|
4017
|
+
...sanitizeNodeProps(props),
|
|
4018
|
+
};
|
|
4019
|
+
}, [cfCsrClassName, node, options?.enableCustomEditorView, props]);
|
|
4020
|
+
return { componentProps };
|
|
5398
4021
|
};
|
|
5399
4022
|
|
|
5400
|
-
function
|
|
5401
|
-
const
|
|
5402
|
-
const
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
return false;
|
|
5406
|
-
}
|
|
5407
|
-
const parentNode = getItem({ id: node.parentId }, tree);
|
|
5408
|
-
if (!parentNode || parentNode.data.blockId !== CONTENTFUL_COMPONENTS$1.columns.id) {
|
|
5409
|
-
return false;
|
|
5410
|
-
}
|
|
5411
|
-
const { cfWrapColumns } = parentNode.data.props;
|
|
5412
|
-
if (cfWrapColumns.type !== 'DesignValue') {
|
|
5413
|
-
return false;
|
|
4023
|
+
function EditorBlock({ node, resolveDesignValue, wrappingPatternIds: parentWrappingPatternIds = new Set(), }) {
|
|
4024
|
+
const isRootAssemblyNode = node.type === ASSEMBLY_NODE_TYPE;
|
|
4025
|
+
const wrappingPatternIds = useMemo(() => {
|
|
4026
|
+
if (isRootAssemblyNode && node.data.blockId) {
|
|
4027
|
+
return new Set([node.data.blockId, ...parentWrappingPatternIds]);
|
|
5414
4028
|
}
|
|
5415
|
-
return
|
|
5416
|
-
}, [
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
}
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
4029
|
+
return parentWrappingPatternIds;
|
|
4030
|
+
}, [isRootAssemblyNode, node, parentWrappingPatternIds]);
|
|
4031
|
+
const componentRegistration = useComponentRegistration(node);
|
|
4032
|
+
if (!componentRegistration) {
|
|
4033
|
+
return React.createElement(MissingComponentPlaceholder, { blockId: node.data.blockId });
|
|
4034
|
+
}
|
|
4035
|
+
if (isRootAssemblyNode && node.data.blockId && parentWrappingPatternIds.has(node.data.blockId)) {
|
|
4036
|
+
return (React.createElement(CircularDependencyErrorPlaceholder, { node: node, wrappingPatternIds: wrappingPatternIds }));
|
|
4037
|
+
}
|
|
4038
|
+
const slotNodes = {};
|
|
4039
|
+
for (const slotId in componentRegistration.definition.slots) {
|
|
4040
|
+
const nodes = node.children.filter((child) => child.data.slotId === slotId);
|
|
4041
|
+
slotNodes[slotId] =
|
|
4042
|
+
nodes.length === 0 ? (React.createElement("div", { className: styles$1.emptySlot })) : (React.createElement(React.Fragment, null, nodes.map((slotChildNode) => (React.createElement(EditorBlock, { key: slotChildNode.data.id, node: slotChildNode, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds })))));
|
|
4043
|
+
}
|
|
4044
|
+
const children = componentRegistration.definition.children
|
|
4045
|
+
? node.children
|
|
4046
|
+
.filter((node) => node.data.slotId === undefined)
|
|
4047
|
+
.map((childNode) => (React.createElement(EditorBlock, { key: childNode.data.id, node: childNode, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds })))
|
|
4048
|
+
: null;
|
|
4049
|
+
return (React.createElement(RegistrationComponent, { node: node, resolveDesignValue: resolveDesignValue, componentRegistration: componentRegistration, slotNodes: slotNodes }, children));
|
|
5432
4050
|
}
|
|
5433
|
-
const
|
|
5434
|
-
const {
|
|
5435
|
-
|
|
5436
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
5437
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
5438
|
-
const { node, componentId, elementToRender, definition, isPatternNode, isPatternComponent, isNestedPattern, } = useComponent({
|
|
5439
|
-
node: rawNode,
|
|
4051
|
+
const RegistrationComponent = ({ node, resolveDesignValue, componentRegistration, slotNodes, children, }) => {
|
|
4052
|
+
const { componentProps } = useComponentProps({
|
|
4053
|
+
node,
|
|
5440
4054
|
resolveDesignValue,
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
wrappingPatternIds,
|
|
4055
|
+
definition: componentRegistration.definition,
|
|
4056
|
+
options: componentRegistration.options,
|
|
5444
4057
|
});
|
|
5445
|
-
|
|
5446
|
-
const setDomRect = useDraggedItemStore((state) => state.setDomRect);
|
|
5447
|
-
const isHoveredComponent = useDraggedItemStore((state) => state.hoveredComponentId === componentId);
|
|
5448
|
-
const coordinates = useSelectedInstanceCoordinates({ node });
|
|
5449
|
-
const displayName = node.data.displayName || rawNode.data.displayName || definition?.name;
|
|
5450
|
-
const testId = `draggable-${node.data.blockId ?? 'node'}`;
|
|
5451
|
-
const isSelected = node.data.id === selectedNodeId;
|
|
5452
|
-
const isContainer = node.data.blockId === CONTENTFUL_COMPONENTS$1.container.id;
|
|
5453
|
-
const isSlotComponent = Boolean(node.data.slotId);
|
|
5454
|
-
const isDragDisabled = isNestedPattern || isPatternComponent || (isSingleColumn && isWrapped) || isSlotComponent;
|
|
5455
|
-
const isEmptyZone = useMemo(() => {
|
|
5456
|
-
return !node.children.filter((node) => node.data.slotId === slotId).length;
|
|
5457
|
-
}, [node.children, slotId]);
|
|
5458
|
-
useDraggablePosition({
|
|
5459
|
-
draggableId: componentId,
|
|
5460
|
-
draggableRef: ref,
|
|
5461
|
-
position: DraggablePosition.MOUSE_POSITION,
|
|
5462
|
-
});
|
|
5463
|
-
const onClick = (e) => {
|
|
5464
|
-
e.stopPropagation();
|
|
5465
|
-
if (!userIsDragging) {
|
|
5466
|
-
setSelectedNodeId(node.data.id);
|
|
5467
|
-
// if it is the assembly directly we just want to select it as a normal component
|
|
5468
|
-
if (isPatternNode) {
|
|
5469
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5470
|
-
nodeId: node.data.id,
|
|
5471
|
-
});
|
|
5472
|
-
return;
|
|
5473
|
-
}
|
|
5474
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5475
|
-
assembly: node.data.assembly,
|
|
5476
|
-
nodeId: node.data.id,
|
|
5477
|
-
});
|
|
5478
|
-
}
|
|
5479
|
-
};
|
|
5480
|
-
const onMouseOver = (e) => {
|
|
5481
|
-
e.stopPropagation();
|
|
5482
|
-
if (userIsDragging)
|
|
5483
|
-
return;
|
|
5484
|
-
sendMessage(OUTGOING_EVENTS.NewHoveredElement, {
|
|
5485
|
-
nodeId: componentId,
|
|
5486
|
-
});
|
|
5487
|
-
};
|
|
5488
|
-
const onMouseDown = (e) => {
|
|
5489
|
-
if (isDragDisabled) {
|
|
5490
|
-
return;
|
|
5491
|
-
}
|
|
5492
|
-
e.stopPropagation();
|
|
5493
|
-
setDomRect(e.currentTarget.getBoundingClientRect());
|
|
5494
|
-
};
|
|
5495
|
-
const ToolTipAndPlaceholder = (React.createElement(React.Fragment, null,
|
|
5496
|
-
React.createElement(Tooltip, { id: componentId, coordinates: coordinates, isAssemblyBlock: isPatternNode || isPatternComponent, isContainer: isContainer, isSelected: isSelected, label: displayName || 'No label specified' }),
|
|
5497
|
-
React.createElement(Placeholder, { ...placeholder, id: componentId }),
|
|
5498
|
-
userIsDragging && !isPatternComponent && (React.createElement(Hitboxes, { parentZoneId: zoneId, zoneId: componentId, isEmptyZone: isEmptyZone }))));
|
|
5499
|
-
return (React.createElement(Draggable, { key: componentId, draggableId: componentId, index: index, isDragDisabled: isDragDisabled, disableInteractiveElementBlocking: true }, (provided, snapshot) => elementToRender({
|
|
5500
|
-
dragProps: {
|
|
5501
|
-
...provided.draggableProps,
|
|
5502
|
-
...provided.dragHandleProps,
|
|
5503
|
-
'data-ctfl-draggable-id': componentId,
|
|
5504
|
-
'data-test-id': testId,
|
|
5505
|
-
innerRef: (refNode) => {
|
|
5506
|
-
provided?.innerRef(refNode);
|
|
5507
|
-
ref.current = refNode;
|
|
5508
|
-
},
|
|
5509
|
-
className: classNames(styles$1.DraggableComponent, {
|
|
5510
|
-
[styles$1.isAssemblyBlock]: isPatternComponent || isPatternNode,
|
|
5511
|
-
[styles$1.isDragging]: snapshot?.isDragging || userIsDragging,
|
|
5512
|
-
[styles$1.isSelected]: isSelected,
|
|
5513
|
-
[styles$1.isHoveringComponent]: isHoveredComponent,
|
|
5514
|
-
}),
|
|
5515
|
-
style: getStyle$1(provided.draggableProps.style, snapshot),
|
|
5516
|
-
onMouseDown,
|
|
5517
|
-
onMouseOver,
|
|
5518
|
-
onClick,
|
|
5519
|
-
ToolTipAndPlaceholder,
|
|
5520
|
-
},
|
|
5521
|
-
})));
|
|
4058
|
+
return React.createElement(ImportedComponentErrorBoundary, { componentId: node.data.blockId }, React.createElement(componentRegistration.component, { ...componentProps, ...slotNodes }, children));
|
|
5522
4059
|
};
|
|
5523
4060
|
|
|
5524
|
-
var css_248z = ".
|
|
5525
|
-
var styles = {"container":"
|
|
4061
|
+
var css_248z = ".EmptyCanvasMessage-module_empty-canvas-container__7K-0l {\n height: 200px;\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: center;\n flex-direction: row;\n transition: all 0.2s;\n color: var(--exp-builder-gray400);\n font-size: var(--exp-builder-font-size-l);\n font-family: var(--exp-builder-font-stack-primary);\n outline: 2px dashed var(--exp-builder-gray400);\n outline-offset: -2px;\n}\n\n.EmptyCanvasMessage-module_empty-canvas-icon__EztFr rect {\n fill: var(--exp-builder-gray400);\n}\n\n.EmptyCanvasMessage-module_empty-canvas-label__cbIrR {\n margin-left: var(--exp-builder-spacing-s);\n}\n";
|
|
4062
|
+
var styles = {"empty-canvas-container":"EmptyCanvasMessage-module_empty-canvas-container__7K-0l","empty-canvas-icon":"EmptyCanvasMessage-module_empty-canvas-icon__EztFr","empty-canvas-label":"EmptyCanvasMessage-module_empty-canvas-label__cbIrR"};
|
|
5526
4063
|
styleInject(css_248z);
|
|
5527
4064
|
|
|
5528
|
-
const
|
|
5529
|
-
return (React.createElement("div", { className:
|
|
5530
|
-
|
|
5531
|
-
}), "data-type": "empty-container" },
|
|
5532
|
-
React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "37", height: "36", fill: "none", className: styles.icon },
|
|
4065
|
+
const EmptyCanvasMessage = () => {
|
|
4066
|
+
return (React.createElement("div", { className: styles['empty-canvas-container'], "data-type": "empty-container" },
|
|
4067
|
+
React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "37", height: "36", fill: "none", className: styles['empty-canvas-icon'] },
|
|
5533
4068
|
React.createElement("rect", { width: "11.676", height: "11.676", x: "18.512", y: ".153", rx: "1.621", transform: "rotate(45 18.512 .153)" }),
|
|
5534
4069
|
React.createElement("rect", { width: "11.676", height: "11.676", x: "9.254", y: "9.139", rx: "1.621", transform: "rotate(45 9.254 9.139)" }),
|
|
5535
4070
|
React.createElement("rect", { width: "11.676", height: "11.676", x: "18.011", y: "18.625", rx: "1.621", transform: "rotate(45 18.01 18.625)" }),
|
|
5536
4071
|
React.createElement("rect", { width: "11.676", height: "11.676", x: "30.557", y: "10.131", rx: "1.621", transform: "rotate(60 30.557 10.13)" }),
|
|
5537
4072
|
React.createElement("path", { fill: "#fff", stroke: "#fff", strokeWidth: ".243", d: "M31.113 17.038a.463.463 0 0 0-.683-.517l-1.763 1.032-1.033-1.763a.464.464 0 0 0-.8.469l1.034 1.763-1.763 1.033a.463.463 0 1 0 .468.8l1.763-1.033 1.033 1.763a.463.463 0 1 0 .8-.469l-1.033-1.763 1.763-1.033a.463.463 0 0 0 .214-.282Z" })),
|
|
5538
|
-
React.createElement("span", { className: styles
|
|
5539
|
-
};
|
|
5540
|
-
|
|
5541
|
-
const useDropzoneDirection = ({ resolveDesignValue, node, zoneId }) => {
|
|
5542
|
-
const zone = useZoneStore((state) => state.zones);
|
|
5543
|
-
const upsertZone = useZoneStore((state) => state.upsertZone);
|
|
5544
|
-
useEffect(() => {
|
|
5545
|
-
function getDirection() {
|
|
5546
|
-
if (!node || !node.data.blockId) {
|
|
5547
|
-
return 'vertical';
|
|
5548
|
-
}
|
|
5549
|
-
if (!isContentfulStructureComponent(node.data.blockId)) {
|
|
5550
|
-
return 'vertical';
|
|
5551
|
-
}
|
|
5552
|
-
if (node.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id) {
|
|
5553
|
-
return 'horizontal';
|
|
5554
|
-
}
|
|
5555
|
-
const designValues = node.data.props['cfFlexDirection'];
|
|
5556
|
-
if (!designValues || !resolveDesignValue || designValues.type !== 'DesignValue') {
|
|
5557
|
-
return 'vertical';
|
|
5558
|
-
}
|
|
5559
|
-
const direction = resolveDesignValue(designValues.valuesByBreakpoint);
|
|
5560
|
-
if (direction === 'row') {
|
|
5561
|
-
return 'horizontal';
|
|
5562
|
-
}
|
|
5563
|
-
return 'vertical';
|
|
5564
|
-
}
|
|
5565
|
-
upsertZone(zoneId, { direction: getDirection() });
|
|
5566
|
-
}, [node, resolveDesignValue, zoneId, upsertZone]);
|
|
5567
|
-
return zone[zoneId]?.direction || 'vertical';
|
|
5568
|
-
};
|
|
5569
|
-
|
|
5570
|
-
function getStyle(style = {}, snapshot) {
|
|
5571
|
-
if (!snapshot?.isDropAnimating) {
|
|
5572
|
-
return style;
|
|
5573
|
-
}
|
|
5574
|
-
return {
|
|
5575
|
-
...style,
|
|
5576
|
-
// cannot be 0, but make it super tiny
|
|
5577
|
-
transitionDuration: `0.001s`,
|
|
5578
|
-
};
|
|
5579
|
-
}
|
|
5580
|
-
const EditorBlockClone = ({ node: rawNode, resolveDesignValue, snapshot, provided, renderDropzone, wrappingPatternIds, }) => {
|
|
5581
|
-
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5582
|
-
const { node, elementToRender } = useComponent({
|
|
5583
|
-
node: rawNode,
|
|
5584
|
-
resolveDesignValue,
|
|
5585
|
-
renderDropzone,
|
|
5586
|
-
userIsDragging,
|
|
5587
|
-
wrappingPatternIds,
|
|
5588
|
-
});
|
|
5589
|
-
const isAssemblyBlock = node.type === ASSEMBLY_BLOCK_NODE_TYPE;
|
|
5590
|
-
return elementToRender({
|
|
5591
|
-
dragProps: {
|
|
5592
|
-
...provided?.draggableProps,
|
|
5593
|
-
...provided?.dragHandleProps,
|
|
5594
|
-
'data-ctfl-dragging-element': 'true',
|
|
5595
|
-
innerRef: provided?.innerRef,
|
|
5596
|
-
className: classNames(styles$1.DraggableComponent, styles$1.DraggableClone, {
|
|
5597
|
-
[styles$1.isAssemblyBlock]: isAssemblyBlock,
|
|
5598
|
-
[styles$1.isDragging]: snapshot?.isDragging,
|
|
5599
|
-
}),
|
|
5600
|
-
style: getStyle(provided?.draggableProps.style, snapshot),
|
|
5601
|
-
},
|
|
5602
|
-
});
|
|
4073
|
+
React.createElement("span", { className: styles['empty-canvas-label'] }, "Add components to begin")));
|
|
5603
4074
|
};
|
|
5604
4075
|
|
|
5605
|
-
const
|
|
5606
|
-
if (dragProps) {
|
|
5607
|
-
const { ToolTipAndPlaceholder, Tag, innerRef, wrapComponent, ...htmlDragProps } = dragProps;
|
|
5608
|
-
return htmlDragProps;
|
|
5609
|
-
}
|
|
5610
|
-
return {};
|
|
5611
|
-
};
|
|
5612
|
-
const getHtmlComponentProps = (props) => {
|
|
5613
|
-
if (props) {
|
|
5614
|
-
const { editorMode, renderDropzone, node, ...htmlProps } = props;
|
|
5615
|
-
return htmlProps;
|
|
5616
|
-
}
|
|
5617
|
-
return {};
|
|
5618
|
-
};
|
|
5619
|
-
|
|
5620
|
-
function DropzoneClone({ node, zoneId, resolveDesignValue, WrapperComponent = 'div', renderDropzone, dragProps, wrappingPatternIds, ...rest }) {
|
|
5621
|
-
const tree = useTreeStore((state) => state.tree);
|
|
5622
|
-
const content = node?.children || tree.root?.children || [];
|
|
5623
|
-
const { slotId } = parseZoneId(zoneId);
|
|
5624
|
-
const htmlDraggableProps = getHtmlDragProps(dragProps);
|
|
5625
|
-
const htmlProps = getHtmlComponentProps(rest);
|
|
5626
|
-
const isRootZone = zoneId === ROOT_ID;
|
|
5627
|
-
if (!resolveDesignValue) {
|
|
5628
|
-
return null;
|
|
5629
|
-
}
|
|
5630
|
-
return (React.createElement(WrapperComponent, { ...htmlDraggableProps, ...htmlProps, className: classNames(dragProps?.className, styles$1.Dropzone, styles$1.DropzoneClone, rest.className, {
|
|
5631
|
-
[styles$1.isRoot]: isRootZone,
|
|
5632
|
-
[styles$1.isEmptyZone]: !content.length,
|
|
5633
|
-
}), "data-ctfl-slot-id": slotId, ref: (refNode) => {
|
|
5634
|
-
if (dragProps?.innerRef) {
|
|
5635
|
-
dragProps.innerRef(refNode);
|
|
5636
|
-
}
|
|
5637
|
-
} }, content
|
|
5638
|
-
.filter((node) => node.data.slotId === slotId)
|
|
5639
|
-
.map((item) => {
|
|
5640
|
-
const componentId = item.data.id;
|
|
5641
|
-
return (React.createElement(EditorBlockClone, { key: componentId, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds }));
|
|
5642
|
-
})));
|
|
5643
|
-
}
|
|
5644
|
-
|
|
5645
|
-
function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponent = 'div', dragProps, wrappingPatternIds: parentWrappingPatternIds = new Set(), ...rest }) {
|
|
5646
|
-
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5647
|
-
const draggedItem = useDraggedItemStore((state) => state.draggedItem);
|
|
5648
|
-
const isDraggingNewComponent = useDraggedItemStore((state) => Boolean(state.componentId));
|
|
5649
|
-
const isHoveringZone = useZoneStore((state) => state.hoveringZone === zoneId);
|
|
5650
|
-
const tree = useTreeStore((state) => state.tree);
|
|
5651
|
-
const content = node?.children || tree.root?.children || [];
|
|
5652
|
-
const { slotId } = parseZoneId(zoneId);
|
|
5653
|
-
const direction = useDropzoneDirection({ resolveDesignValue, node, zoneId });
|
|
5654
|
-
const draggedDestinationId = draggedItem && draggedItem.destination?.droppableId;
|
|
5655
|
-
const draggedNode = useMemo(() => {
|
|
5656
|
-
if (!draggedItem)
|
|
5657
|
-
return;
|
|
5658
|
-
return getItem({ id: draggedItem.draggableId }, tree);
|
|
5659
|
-
}, [draggedItem, tree]);
|
|
5660
|
-
const isRootZone = zoneId === ROOT_ID;
|
|
5661
|
-
const isDestination = draggedDestinationId === zoneId;
|
|
5662
|
-
const isEmptyCanvas = isRootZone && !content.length;
|
|
5663
|
-
const isAssembly = ASSEMBLY_NODE_TYPES.includes(node?.type || '');
|
|
5664
|
-
const isRootAssembly = node?.type === ASSEMBLY_NODE_TYPE;
|
|
5665
|
-
const htmlDraggableProps = getHtmlDragProps(dragProps);
|
|
5666
|
-
const htmlProps = getHtmlComponentProps(rest);
|
|
5667
|
-
const wrappingPatternIds = useMemo(() => {
|
|
5668
|
-
// On the top level, the node is not defined. If the root blockId is not the default string,
|
|
5669
|
-
// we assume that it is the entry ID of the experience/ pattern to properly detect circular dependencies
|
|
5670
|
-
if (!node && tree.root.data.blockId && tree.root.data.blockId !== ROOT_ID) {
|
|
5671
|
-
return new Set([tree.root.data.blockId, ...parentWrappingPatternIds]);
|
|
5672
|
-
}
|
|
5673
|
-
if (isRootAssembly && node?.data.blockId) {
|
|
5674
|
-
return new Set([node.data.blockId, ...parentWrappingPatternIds]);
|
|
5675
|
-
}
|
|
5676
|
-
return parentWrappingPatternIds;
|
|
5677
|
-
}, [isRootAssembly, node, parentWrappingPatternIds, tree.root.data.blockId]);
|
|
5678
|
-
// To avoid a circular dependency, we create the recursive rendering function here and trickle it down
|
|
5679
|
-
const renderDropzone = useCallback((node, props) => {
|
|
5680
|
-
return (React.createElement(Dropzone, { zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
5681
|
-
}, [wrappingPatternIds, resolveDesignValue]);
|
|
5682
|
-
const renderClonedDropzone = useCallback((node, props) => {
|
|
5683
|
-
return (React.createElement(DropzoneClone, { zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
5684
|
-
}, [resolveDesignValue, wrappingPatternIds]);
|
|
5685
|
-
const isDropzoneEnabled = useMemo(() => {
|
|
5686
|
-
const isColumns = node?.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id;
|
|
5687
|
-
const isDraggingSingleColumn = draggedNode?.data.blockId === CONTENTFUL_COMPONENTS$1.singleColumn.id;
|
|
5688
|
-
const isParentOfDraggedNode = node?.data.id === draggedNode?.parentId;
|
|
5689
|
-
// If dragging a single column, only enable the dropzone of the parent
|
|
5690
|
-
// columns component
|
|
5691
|
-
if (isDraggingSingleColumn && isColumns && isParentOfDraggedNode) {
|
|
5692
|
-
return true;
|
|
5693
|
-
}
|
|
5694
|
-
// If dragging a single column, disable dropzones for any component besides
|
|
5695
|
-
// the parent of the dragged single column
|
|
5696
|
-
if (isDraggingSingleColumn && !isParentOfDraggedNode) {
|
|
5697
|
-
return false;
|
|
5698
|
-
}
|
|
5699
|
-
// Disable dropzone for Columns component
|
|
5700
|
-
if (isColumns) {
|
|
5701
|
-
return false;
|
|
5702
|
-
}
|
|
5703
|
-
// Disable dropzone for Assembly
|
|
5704
|
-
if (isAssembly) {
|
|
5705
|
-
return false;
|
|
5706
|
-
}
|
|
5707
|
-
// Enable dropzone for the non-root hovered zones if component is not allowed on root
|
|
5708
|
-
if (!isDraggingNewComponent &&
|
|
5709
|
-
!isComponentAllowedOnRoot({ type: draggedNode?.type, componentId: draggedNode?.data.blockId })) {
|
|
5710
|
-
return isHoveringZone && !isRootZone;
|
|
5711
|
-
}
|
|
5712
|
-
// Enable dropzone for the hovered zone only
|
|
5713
|
-
return isHoveringZone;
|
|
5714
|
-
}, [isAssembly, isHoveringZone, isRootZone, isDraggingNewComponent, draggedNode, node]);
|
|
5715
|
-
if (!resolveDesignValue) {
|
|
5716
|
-
return null;
|
|
5717
|
-
}
|
|
5718
|
-
const isPatternWrapperComponentFullHeight = isRootAssembly
|
|
5719
|
-
? node.children.length === 1 &&
|
|
5720
|
-
resolveDesignValue(node?.children[0]?.data.props.cfHeight?.valuesByBreakpoint ?? {}, 'cfHeight') === '100%'
|
|
5721
|
-
: false;
|
|
5722
|
-
const isPatternWrapperComponentFullWidth = isRootAssembly
|
|
5723
|
-
? node.children.length === 1 &&
|
|
5724
|
-
resolveDesignValue(node?.children[0]?.data.props.cfWidth?.valuesByBreakpoint ?? {}, 'cfWidth') === '100%'
|
|
5725
|
-
: false;
|
|
5726
|
-
return (React.createElement(Droppable, { droppableId: zoneId, direction: direction, isDropDisabled: !isDropzoneEnabled, renderClone: (provided, snapshot, rubic) => (React.createElement(EditorBlockClone, { node: content[rubic.source.index], resolveDesignValue: resolveDesignValue, provided: provided, snapshot: snapshot, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds })) }, (provided, snapshot) => {
|
|
5727
|
-
return (React.createElement(WrapperComponent, { ...(provided || { droppableProps: {} }).droppableProps, ...htmlDraggableProps, ...htmlProps, ref: (refNode) => {
|
|
5728
|
-
if (dragProps?.innerRef) {
|
|
5729
|
-
dragProps.innerRef(refNode);
|
|
5730
|
-
}
|
|
5731
|
-
provided?.innerRef(refNode);
|
|
5732
|
-
}, id: zoneId, "data-ctfl-zone-id": zoneId, "data-ctfl-slot-id": slotId, className: classNames(dragProps?.className, styles$1.Dropzone, className, {
|
|
5733
|
-
[styles$1.isEmptyCanvas]: isEmptyCanvas,
|
|
5734
|
-
[styles$1.isDragging]: userIsDragging,
|
|
5735
|
-
[styles$1.isDestination]: isDestination && !isAssembly,
|
|
5736
|
-
[styles$1.isRoot]: isRootZone,
|
|
5737
|
-
[styles$1.isEmptyZone]: !content.length,
|
|
5738
|
-
[styles$1.isSlot]: Boolean(slotId),
|
|
5739
|
-
[styles$1.fullHeight]: isPatternWrapperComponentFullHeight,
|
|
5740
|
-
[styles$1.fullWidth]: isPatternWrapperComponentFullWidth,
|
|
5741
|
-
}) },
|
|
5742
|
-
isEmptyCanvas ? (React.createElement(EmptyContainer, { isDragging: isRootZone && userIsDragging })) : (content
|
|
5743
|
-
.filter((node) => node.data.slotId === slotId)
|
|
5744
|
-
.map((item, i) => (React.createElement(EditorBlock, { placeholder: {
|
|
5745
|
-
isDraggingOver: snapshot?.isDraggingOver,
|
|
5746
|
-
totalIndexes: content.length,
|
|
5747
|
-
elementIndex: i,
|
|
5748
|
-
dropzoneElementId: zoneId,
|
|
5749
|
-
direction,
|
|
5750
|
-
}, index: i, zoneId: zoneId, key: item.data.id, userIsDragging: userIsDragging, draggingNewComponent: isDraggingNewComponent, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds })))),
|
|
5751
|
-
provided?.placeholder,
|
|
5752
|
-
dragProps?.ToolTipAndPlaceholder));
|
|
5753
|
-
}));
|
|
5754
|
-
}
|
|
5755
|
-
|
|
5756
|
-
const RootRenderer = ({ onChange }) => {
|
|
4076
|
+
const RootRenderer = () => {
|
|
5757
4077
|
useEditorSubscriber();
|
|
5758
|
-
const dragItem = useDraggedItemStore((state) => state.componentId);
|
|
5759
|
-
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5760
|
-
const setHoveredComponentId = useDraggedItemStore((state) => state.setHoveredComponentId);
|
|
5761
4078
|
const breakpoints = useTreeStore((state) => state.breakpoints);
|
|
5762
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
5763
4079
|
const containerRef = useRef(null);
|
|
5764
4080
|
const { resolveDesignValue } = useBreakpoints(breakpoints);
|
|
5765
|
-
const [containerStyles, setContainerStyles] = useState({});
|
|
5766
4081
|
const tree = useTreeStore((state) => state.tree);
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
const handleClickOutside = useCallback((e) => {
|
|
5774
|
-
const element = e.target;
|
|
5775
|
-
const isRoot = element.getAttribute('data-ctfl-zone-id') === ROOT_ID;
|
|
5776
|
-
const clickedOnCanvas = element.closest(`[data-ctfl-root]`);
|
|
5777
|
-
if (clickedOnCanvas && !isRoot) {
|
|
5778
|
-
return;
|
|
5779
|
-
}
|
|
5780
|
-
sendMessage(OUTGOING_EVENTS.OutsideCanvasClick, {
|
|
5781
|
-
outsideCanvasClick: true,
|
|
5782
|
-
});
|
|
5783
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5784
|
-
nodeId: '',
|
|
5785
|
-
});
|
|
5786
|
-
setSelectedNodeId('');
|
|
5787
|
-
}, [setSelectedNodeId]);
|
|
5788
|
-
const handleResizeCanvas = useCallback(() => {
|
|
5789
|
-
const parentElement = containerRef.current?.parentElement;
|
|
5790
|
-
if (!parentElement) {
|
|
5791
|
-
return;
|
|
5792
|
-
}
|
|
5793
|
-
let siblingHeight = 0;
|
|
5794
|
-
for (const child of parentElement.children) {
|
|
5795
|
-
if (!child.hasAttribute('data-ctfl-root')) {
|
|
5796
|
-
siblingHeight += child.getBoundingClientRect().height;
|
|
5797
|
-
}
|
|
5798
|
-
}
|
|
5799
|
-
if (!siblingHeight) {
|
|
5800
|
-
/**
|
|
5801
|
-
* DRAGGABLE_HEIGHT is subtracted here due to an uninteded scrolling effect
|
|
5802
|
-
* when dragging a new component onto the canvas
|
|
5803
|
-
*
|
|
5804
|
-
* The DRAGGABLE_HEIGHT is then added as margin bottom to offset this value
|
|
5805
|
-
* so that visually there is no difference to the user.
|
|
5806
|
-
*/
|
|
5807
|
-
setContainerStyles({
|
|
5808
|
-
minHeight: `${window.innerHeight - DRAGGABLE_HEIGHT}px`,
|
|
5809
|
-
});
|
|
5810
|
-
return;
|
|
5811
|
-
}
|
|
5812
|
-
setContainerStyles({
|
|
5813
|
-
minHeight: `${window.innerHeight - siblingHeight}px`,
|
|
5814
|
-
});
|
|
5815
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5816
|
-
}, [containerRef.current]);
|
|
5817
|
-
useEffect(() => {
|
|
5818
|
-
if (onChange)
|
|
5819
|
-
onChange(tree);
|
|
5820
|
-
}, [tree, onChange]);
|
|
5821
|
-
useEffect(() => {
|
|
5822
|
-
window.addEventListener('mouseover', handleMouseOver);
|
|
5823
|
-
return () => {
|
|
5824
|
-
window.removeEventListener('mouseover', handleMouseOver);
|
|
5825
|
-
};
|
|
5826
|
-
}, [handleMouseOver]);
|
|
5827
|
-
useEffect(() => {
|
|
5828
|
-
document.addEventListener('click', handleClickOutside);
|
|
5829
|
-
return () => {
|
|
5830
|
-
document.removeEventListener('click', handleClickOutside);
|
|
5831
|
-
};
|
|
5832
|
-
}, [handleClickOutside]);
|
|
5833
|
-
useEffect(() => {
|
|
5834
|
-
handleResizeCanvas();
|
|
5835
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5836
|
-
}, [containerRef.current]);
|
|
5837
|
-
return (React.createElement(DNDProvider, null,
|
|
5838
|
-
dragItem && React.createElement(DraggableContainer, { id: dragItem }),
|
|
5839
|
-
React.createElement("div", { "data-ctfl-root": true, className: styles$3.container, ref: containerRef, style: containerStyles },
|
|
5840
|
-
userIsDragging && React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitbox }),
|
|
5841
|
-
React.createElement(Dropzone, { zoneId: ROOT_ID, resolveDesignValue: resolveDesignValue }),
|
|
5842
|
-
userIsDragging && (React.createElement(React.Fragment, null,
|
|
5843
|
-
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitboxLower }),
|
|
5844
|
-
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.canvasBottomSpacer })))),
|
|
5845
|
-
React.createElement("div", { "data-ctfl-hitboxes": true })));
|
|
4082
|
+
// If the root blockId is defined but not the default string, it is the entry ID
|
|
4083
|
+
// of the experience/ pattern to properly detect circular dependencies.
|
|
4084
|
+
const rootBlockId = tree.root.data.blockId ?? ROOT_ID;
|
|
4085
|
+
const wrappingPatternIds = rootBlockId !== ROOT_ID ? new Set([rootBlockId]) : new Set();
|
|
4086
|
+
return (React.createElement(React.Fragment, null,
|
|
4087
|
+
React.createElement("div", { "data-ctfl-root": true, className: styles$2.rootContainer, ref: containerRef }, !tree.root.children.length ? (React.createElement(EmptyCanvasMessage, null)) : (tree.root.children.map((topLevelChildNode) => (React.createElement(EditorBlock, { key: topLevelChildNode.data.id, node: topLevelChildNode, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds })))))));
|
|
5846
4088
|
};
|
|
5847
4089
|
|
|
5848
4090
|
const useInitializeEditor = () => {
|
|
@@ -5886,38 +4128,11 @@ const useInitializeEditor = () => {
|
|
|
5886
4128
|
const VisualEditorRoot = ({ experience }) => {
|
|
5887
4129
|
const initialized = useInitializeEditor();
|
|
5888
4130
|
const setHyperLinkPattern = useEditorStore((state) => state.setHyperLinkPattern);
|
|
5889
|
-
const setMousePosition = useDraggedItemStore((state) => state.setMousePosition);
|
|
5890
|
-
const setHoveringZone = useZoneStore((state) => state.setHoveringZone);
|
|
5891
4131
|
useEffect(() => {
|
|
5892
4132
|
if (experience?.hyperlinkPattern) {
|
|
5893
4133
|
setHyperLinkPattern(experience.hyperlinkPattern);
|
|
5894
4134
|
}
|
|
5895
4135
|
}, [experience?.hyperlinkPattern, setHyperLinkPattern]);
|
|
5896
|
-
useEffect(() => {
|
|
5897
|
-
const onMouseMove = (e) => {
|
|
5898
|
-
setMousePosition(e.clientX, e.clientY);
|
|
5899
|
-
const target = e.target;
|
|
5900
|
-
const zoneId = target.closest(`[${CTFL_ZONE_ID}]`)?.getAttribute(CTFL_ZONE_ID);
|
|
5901
|
-
if (zoneId) {
|
|
5902
|
-
setHoveringZone(zoneId);
|
|
5903
|
-
}
|
|
5904
|
-
if (!SimulateDnD$1.isDragging) {
|
|
5905
|
-
return;
|
|
5906
|
-
}
|
|
5907
|
-
if (target.id === NEW_COMPONENT_ID) {
|
|
5908
|
-
return;
|
|
5909
|
-
}
|
|
5910
|
-
SimulateDnD$1.updateDrag(e.clientX, e.clientY);
|
|
5911
|
-
sendMessage(OUTGOING_EVENTS.MouseMove, {
|
|
5912
|
-
clientX: e.pageX - window.scrollX,
|
|
5913
|
-
clientY: e.pageY - window.scrollY,
|
|
5914
|
-
});
|
|
5915
|
-
};
|
|
5916
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
5917
|
-
return () => {
|
|
5918
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
5919
|
-
};
|
|
5920
|
-
}, [setHoveringZone, setMousePosition]);
|
|
5921
4136
|
if (!initialized)
|
|
5922
4137
|
return null;
|
|
5923
4138
|
return React.createElement(RootRenderer, null);
|