@contentful/experiences-visual-editor-react 2.0.0-prerelease-20250703T1150-c529c88.0 → 2.0.0-prerelease-20250704T1603-11d76eb.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 +458 -2090
- package/dist/index.js.map +1 -1
- package/dist/renderApp.js +911 -12216
- package/dist/renderApp.js.map +1 -1
- package/package.json +4 -6
package/dist/index.js
CHANGED
|
@@ -1,35 +1,41 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useState, useEffect, useCallback, forwardRef, useMemo, useLayoutEffect, useRef } from 'react';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { omit, isArray, isEqual, get as get$2 } from 'lodash-es';
|
|
4
|
+
import { omit, isArray, isEqual, get as get$2, debounce } from 'lodash-es';
|
|
5
5
|
import md5 from 'md5';
|
|
6
6
|
import { BLOCKS } from '@contentful/rich-text-types';
|
|
7
7
|
import { create, useStore } from 'zustand';
|
|
8
|
-
import { Droppable, Draggable, DragDropContext } from '@hello-pangea/dnd';
|
|
9
8
|
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
|
-
var css_248z$
|
|
16
|
-
styleInject(css_248z$
|
|
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";
|
|
12
|
+
styleInject(css_248z$b);
|
|
17
13
|
|
|
14
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
18
15
|
const INCOMING_EVENTS$1 = {
|
|
19
16
|
RequestEditorMode: 'requestEditorMode',
|
|
20
17
|
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
21
18
|
ExperienceUpdated: 'componentTreeUpdated',
|
|
19
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
22
20
|
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
21
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
23
22
|
ComponentDragCanceled: 'componentDragCanceled',
|
|
23
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
24
24
|
ComponentDragStarted: 'componentDragStarted',
|
|
25
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
25
26
|
ComponentDragEnded: 'componentDragEnded',
|
|
27
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
26
28
|
ComponentMoveEnded: 'componentMoveEnded',
|
|
29
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
27
30
|
CanvasResized: 'canvasResized',
|
|
31
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
28
32
|
SelectComponent: 'selectComponent',
|
|
33
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
29
34
|
HoverComponent: 'hoverComponent',
|
|
30
35
|
UpdatedEntity: 'updatedEntity',
|
|
31
36
|
AssembliesAdded: 'assembliesAdded',
|
|
32
37
|
AssembliesRegistered: 'assembliesRegistered',
|
|
38
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
33
39
|
MouseMove: 'mouseMove',
|
|
34
40
|
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
35
41
|
};
|
|
@@ -44,7 +50,7 @@ var StudioCanvasMode$3;
|
|
|
44
50
|
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
45
51
|
StudioCanvasMode["NONE"] = "none";
|
|
46
52
|
})(StudioCanvasMode$3 || (StudioCanvasMode$3 = {}));
|
|
47
|
-
const CONTENTFUL_COMPONENTS$
|
|
53
|
+
const CONTENTFUL_COMPONENTS$1 = {
|
|
48
54
|
section: {
|
|
49
55
|
id: 'contentful-section',
|
|
50
56
|
name: 'Section',
|
|
@@ -90,9 +96,6 @@ const CONTENTFUL_COMPONENTS$2 = {
|
|
|
90
96
|
name: 'Carousel',
|
|
91
97
|
},
|
|
92
98
|
};
|
|
93
|
-
const ASSEMBLY_NODE_TYPE$1 = 'assembly';
|
|
94
|
-
const ASSEMBLY_DEFAULT_CATEGORY$1 = 'Assemblies';
|
|
95
|
-
const ASSEMBLY_BLOCK_NODE_TYPE$1 = 'assemblyBlock';
|
|
96
99
|
const CF_STYLE_ATTRIBUTES = [
|
|
97
100
|
'cfVisibility',
|
|
98
101
|
'cfHorizontalAlignment',
|
|
@@ -127,7 +130,7 @@ const CF_STYLE_ATTRIBUTES = [
|
|
|
127
130
|
'cfTextItalic',
|
|
128
131
|
'cfTextUnderline',
|
|
129
132
|
];
|
|
130
|
-
const
|
|
133
|
+
const EMPTY_CONTAINER_SIZE$1 = '80px';
|
|
131
134
|
const DEFAULT_IMAGE_WIDTH = '500px';
|
|
132
135
|
var PostMessageMethods$3;
|
|
133
136
|
(function (PostMessageMethods) {
|
|
@@ -137,20 +140,14 @@ var PostMessageMethods$3;
|
|
|
137
140
|
const SUPPORTED_IMAGE_FORMATS = ['jpg', 'png', 'webp', 'gif', 'avif'];
|
|
138
141
|
|
|
139
142
|
const structureComponentIds = new Set([
|
|
140
|
-
CONTENTFUL_COMPONENTS$
|
|
141
|
-
CONTENTFUL_COMPONENTS$
|
|
142
|
-
CONTENTFUL_COMPONENTS$
|
|
143
|
-
CONTENTFUL_COMPONENTS$
|
|
143
|
+
CONTENTFUL_COMPONENTS$1.section.id,
|
|
144
|
+
CONTENTFUL_COMPONENTS$1.columns.id,
|
|
145
|
+
CONTENTFUL_COMPONENTS$1.container.id,
|
|
146
|
+
CONTENTFUL_COMPONENTS$1.singleColumn.id,
|
|
144
147
|
]);
|
|
145
|
-
const
|
|
146
|
-
const allContentfulComponentIds = new Set(Object.values(CONTENTFUL_COMPONENTS$2).map((component) => component.id));
|
|
147
|
-
const isPatternComponent = (type) => patternTypes.has(type ?? '');
|
|
148
|
+
const allContentfulComponentIds = new Set(Object.values(CONTENTFUL_COMPONENTS$1).map((component) => component.id));
|
|
148
149
|
const isContentfulStructureComponent = (componentId) => structureComponentIds.has((componentId ?? ''));
|
|
149
150
|
const isContentfulComponent = (componentId) => allContentfulComponentIds.has((componentId ?? ''));
|
|
150
|
-
const isComponentAllowedOnRoot = ({ type, category, componentId }) => isPatternComponent(type) ||
|
|
151
|
-
category === ASSEMBLY_DEFAULT_CATEGORY$1 ||
|
|
152
|
-
isContentfulStructureComponent(componentId) ||
|
|
153
|
-
componentId === CONTENTFUL_COMPONENTS$2.divider.id;
|
|
154
151
|
const isStructureWithRelativeHeight = (componentId, height) => {
|
|
155
152
|
return isContentfulStructureComponent(componentId) && !height?.toString().endsWith('px');
|
|
156
153
|
};
|
|
@@ -828,13 +825,7 @@ const ParameterDefinitionSchema$1 = z.object({
|
|
|
828
825
|
}),
|
|
829
826
|
})
|
|
830
827
|
.optional(),
|
|
831
|
-
contentTypes: z.
|
|
832
|
-
sys: z.object({
|
|
833
|
-
type: z.literal('Link'),
|
|
834
|
-
id: z.string(),
|
|
835
|
-
linkType: z.enum(['ContentType']),
|
|
836
|
-
}),
|
|
837
|
-
})),
|
|
828
|
+
contentTypes: z.array(z.string()),
|
|
838
829
|
passToNodes: z.array(PassToNodeSchema$1).optional(),
|
|
839
830
|
});
|
|
840
831
|
const ParameterDefinitionsSchema$1 = z.record(propertyKeySchema$1, ParameterDefinitionSchema$1);
|
|
@@ -854,7 +845,7 @@ const ComponentSettingsSchema$1 = z
|
|
|
854
845
|
variableDefinitions: ComponentVariablesSchema$1,
|
|
855
846
|
thumbnailId: z.enum(THUMBNAIL_IDS$1).optional(),
|
|
856
847
|
category: z.string().max(50, 'Category must contain at most 50 characters').optional(),
|
|
857
|
-
prebindingDefinitions: z.array(PrebindingDefinitionSchema$1).
|
|
848
|
+
prebindingDefinitions: z.array(PrebindingDefinitionSchema$1).length(1).optional(),
|
|
858
849
|
})
|
|
859
850
|
.strict();
|
|
860
851
|
z.object({
|
|
@@ -1099,7 +1090,10 @@ propertyName, resolveDesignTokens = true) => {
|
|
|
1099
1090
|
};
|
|
1100
1091
|
/** Overwrites the default value breakpoint by breakpoint. If a breakpoint
|
|
1101
1092
|
* is not overwritten, it will fall back to the default. */
|
|
1102
|
-
|
|
1093
|
+
function mergeDesignValuesByBreakpoint(defaultValue, overwriteValue) {
|
|
1094
|
+
if (!defaultValue || !overwriteValue) {
|
|
1095
|
+
return defaultValue ?? overwriteValue;
|
|
1096
|
+
}
|
|
1103
1097
|
const mergedValuesByBreakpoint = { ...defaultValue.valuesByBreakpoint };
|
|
1104
1098
|
for (const [breakpointId, value] of Object.entries(overwriteValue.valuesByBreakpoint)) {
|
|
1105
1099
|
if (!isValidBreakpointValue(value)) {
|
|
@@ -1111,7 +1105,7 @@ const mergeDesignValuesByBreakpoint = (defaultValue, overwriteValue) => {
|
|
|
1111
1105
|
type: 'DesignValue',
|
|
1112
1106
|
valuesByBreakpoint: mergedValuesByBreakpoint,
|
|
1113
1107
|
};
|
|
1114
|
-
}
|
|
1108
|
+
}
|
|
1115
1109
|
|
|
1116
1110
|
const CF_DEBUG_KEY$1 = 'cf_debug';
|
|
1117
1111
|
/**
|
|
@@ -1196,6 +1190,10 @@ const findOutermostCoordinates = (first, second) => {
|
|
|
1196
1190
|
left: Math.min(first.left, second.left),
|
|
1197
1191
|
};
|
|
1198
1192
|
};
|
|
1193
|
+
const isElementHidden = (rect) => {
|
|
1194
|
+
/** if the rect has no size and position, its element is not rendered in the DOM */
|
|
1195
|
+
return rect.width === 0 && rect.height === 0 && rect.x === 0 && rect.y === 0;
|
|
1196
|
+
};
|
|
1199
1197
|
const getElementCoordinates = (element) => {
|
|
1200
1198
|
const rect = element.getBoundingClientRect();
|
|
1201
1199
|
/**
|
|
@@ -1435,21 +1433,17 @@ function buildTemplate({ template, context, }) {
|
|
|
1435
1433
|
|
|
1436
1434
|
const stylesToKeep = ['cfImageAsset'];
|
|
1437
1435
|
const stylesToRemove = CF_STYLE_ATTRIBUTES.filter((style) => !stylesToKeep.includes(style));
|
|
1438
|
-
|
|
1436
|
+
// cfWrapColumns & cfWrapColumnsCount are no real style attributes as they are handled on the editor side
|
|
1437
|
+
const propsToRemove = [
|
|
1438
|
+
'cfHyperlink',
|
|
1439
|
+
'cfOpenInNewTab',
|
|
1440
|
+
'cfSsrClassName',
|
|
1441
|
+
'cfWrapColumns',
|
|
1442
|
+
'cfWrapColumnsCount',
|
|
1443
|
+
];
|
|
1439
1444
|
const sanitizeNodeProps = (nodeProps) => {
|
|
1440
1445
|
return omit(nodeProps, stylesToRemove, propsToRemove);
|
|
1441
1446
|
};
|
|
1442
|
-
|
|
1443
|
-
/** Turn the visibility value into a style object that can be used for inline styles in React */
|
|
1444
|
-
const transformVisibility = (value) => {
|
|
1445
|
-
if (value === false) {
|
|
1446
|
-
return {
|
|
1447
|
-
display: 'none !important',
|
|
1448
|
-
};
|
|
1449
|
-
}
|
|
1450
|
-
// Don't explicitly set anything when visible to not overwrite values like `grid` or `flex`.
|
|
1451
|
-
return {};
|
|
1452
|
-
};
|
|
1453
1447
|
const transformGridColumn = (span) => {
|
|
1454
1448
|
if (!span) {
|
|
1455
1449
|
return {};
|
|
@@ -1608,7 +1602,7 @@ const buildCfStyles = (values) => {
|
|
|
1608
1602
|
};
|
|
1609
1603
|
/**
|
|
1610
1604
|
* Container/section default behavior:
|
|
1611
|
-
* Default height => height:
|
|
1605
|
+
* Default height => height: EMPTY_CONTAINER_SIZE
|
|
1612
1606
|
* If a container component has children => height: 'fit-content'
|
|
1613
1607
|
*/
|
|
1614
1608
|
const calculateNodeDefaultHeight = ({ blockId, children, value, }) => {
|
|
@@ -1618,7 +1612,7 @@ const calculateNodeDefaultHeight = ({ blockId, children, value, }) => {
|
|
|
1618
1612
|
if (children.length) {
|
|
1619
1613
|
return '100%';
|
|
1620
1614
|
}
|
|
1621
|
-
return
|
|
1615
|
+
return EMPTY_CONTAINER_SIZE$1;
|
|
1622
1616
|
};
|
|
1623
1617
|
|
|
1624
1618
|
function getOptimizedImageUrl(url, width, quality, format) {
|
|
@@ -2651,180 +2645,7 @@ function gatherDeepReferencesFromTree(startingNode, dataSource) {
|
|
|
2651
2645
|
return deepReferences;
|
|
2652
2646
|
}
|
|
2653
2647
|
|
|
2654
|
-
const useDraggedItemStore = create((set) => ({
|
|
2655
|
-
draggedItem: undefined,
|
|
2656
|
-
hoveredComponentId: undefined,
|
|
2657
|
-
domRect: undefined,
|
|
2658
|
-
componentId: '',
|
|
2659
|
-
isDraggingOnCanvas: false,
|
|
2660
|
-
onBeforeCaptureId: '',
|
|
2661
|
-
mouseX: 0,
|
|
2662
|
-
mouseY: 0,
|
|
2663
|
-
scrollY: 0,
|
|
2664
|
-
setComponentId(id) {
|
|
2665
|
-
set({ componentId: id });
|
|
2666
|
-
},
|
|
2667
|
-
setHoveredComponentId(id) {
|
|
2668
|
-
set({ hoveredComponentId: id });
|
|
2669
|
-
},
|
|
2670
|
-
updateItem: (item) => {
|
|
2671
|
-
set({ draggedItem: item });
|
|
2672
|
-
},
|
|
2673
|
-
setDraggingOnCanvas: (isDraggingOnCanvas) => {
|
|
2674
|
-
set({ isDraggingOnCanvas });
|
|
2675
|
-
},
|
|
2676
|
-
setOnBeforeCaptureId: (onBeforeCaptureId) => {
|
|
2677
|
-
set({ onBeforeCaptureId });
|
|
2678
|
-
},
|
|
2679
|
-
setMousePosition(x, y) {
|
|
2680
|
-
set({ mouseX: x, mouseY: y });
|
|
2681
|
-
},
|
|
2682
|
-
setDomRect(domRect) {
|
|
2683
|
-
set({ domRect });
|
|
2684
|
-
},
|
|
2685
|
-
setScrollY(y) {
|
|
2686
|
-
set({ scrollY: y });
|
|
2687
|
-
},
|
|
2688
|
-
}));
|
|
2689
|
-
|
|
2690
|
-
const SCROLL_STATES = {
|
|
2691
|
-
Start: 'scrollStart',
|
|
2692
|
-
IsScrolling: 'isScrolling',
|
|
2693
|
-
End: 'scrollEnd',
|
|
2694
|
-
};
|
|
2695
|
-
const OUTGOING_EVENTS = {
|
|
2696
|
-
Connected: 'connected',
|
|
2697
|
-
DesignTokens: 'registerDesignTokens',
|
|
2698
|
-
RegisteredBreakpoints: 'registeredBreakpoints',
|
|
2699
|
-
MouseMove: 'mouseMove',
|
|
2700
|
-
NewHoveredElement: 'newHoveredElement',
|
|
2701
|
-
ComponentSelected: 'componentSelected',
|
|
2702
|
-
RegisteredComponents: 'registeredComponents',
|
|
2703
|
-
RequestComponentTreeUpdate: 'requestComponentTreeUpdate',
|
|
2704
|
-
ComponentDragCanceled: 'componentDragCanceled',
|
|
2705
|
-
ComponentDropped: 'componentDropped',
|
|
2706
|
-
ComponentMoved: 'componentMoved',
|
|
2707
|
-
CanvasReload: 'canvasReload',
|
|
2708
|
-
UpdateSelectedComponentCoordinates: 'updateSelectedComponentCoordinates',
|
|
2709
|
-
CanvasScroll: 'canvasScrolling',
|
|
2710
|
-
CanvasError: 'canvasError',
|
|
2711
|
-
ComponentMoveStarted: 'componentMoveStarted',
|
|
2712
|
-
ComponentMoveEnded: 'componentMoveEnded',
|
|
2713
|
-
OutsideCanvasClick: 'outsideCanvasClick',
|
|
2714
|
-
SDKFeatures: 'sdkFeatures',
|
|
2715
|
-
RequestEntities: 'REQUEST_ENTITIES',
|
|
2716
|
-
};
|
|
2717
|
-
const INCOMING_EVENTS = {
|
|
2718
|
-
RequestEditorMode: 'requestEditorMode',
|
|
2719
|
-
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
2720
|
-
ExperienceUpdated: 'componentTreeUpdated',
|
|
2721
|
-
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
2722
|
-
ComponentDragCanceled: 'componentDragCanceled',
|
|
2723
|
-
ComponentDragStarted: 'componentDragStarted',
|
|
2724
|
-
ComponentDragEnded: 'componentDragEnded',
|
|
2725
|
-
ComponentMoveEnded: 'componentMoveEnded',
|
|
2726
|
-
CanvasResized: 'canvasResized',
|
|
2727
|
-
SelectComponent: 'selectComponent',
|
|
2728
|
-
HoverComponent: 'hoverComponent',
|
|
2729
|
-
UpdatedEntity: 'updatedEntity',
|
|
2730
|
-
AssembliesAdded: 'assembliesAdded',
|
|
2731
|
-
AssembliesRegistered: 'assembliesRegistered',
|
|
2732
|
-
MouseMove: 'mouseMove',
|
|
2733
|
-
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
2734
|
-
};
|
|
2735
|
-
const INTERNAL_EVENTS = {
|
|
2736
|
-
ComponentsRegistered: 'cfComponentsRegistered',
|
|
2737
|
-
VisualEditorInitialize: 'cfVisualEditorInitialize',
|
|
2738
|
-
};
|
|
2739
|
-
const VISUAL_EDITOR_EVENTS = {
|
|
2740
|
-
Ready: 'cfVisualEditorReady',
|
|
2741
|
-
};
|
|
2742
|
-
/**
|
|
2743
|
-
* These modes are ONLY intended to be internally used within the context of
|
|
2744
|
-
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
2745
|
-
* intentionally do not include preview/delivery modes.
|
|
2746
|
-
*/
|
|
2747
|
-
var StudioCanvasMode$2;
|
|
2748
|
-
(function (StudioCanvasMode) {
|
|
2749
|
-
StudioCanvasMode["READ_ONLY"] = "readOnlyMode";
|
|
2750
|
-
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
2751
|
-
StudioCanvasMode["NONE"] = "none";
|
|
2752
|
-
})(StudioCanvasMode$2 || (StudioCanvasMode$2 = {}));
|
|
2753
|
-
const CONTENTFUL_COMPONENTS$1 = {
|
|
2754
|
-
section: {
|
|
2755
|
-
id: 'contentful-section',
|
|
2756
|
-
name: 'Section',
|
|
2757
|
-
},
|
|
2758
|
-
container: {
|
|
2759
|
-
id: 'contentful-container',
|
|
2760
|
-
name: 'Container',
|
|
2761
|
-
},
|
|
2762
|
-
columns: {
|
|
2763
|
-
id: 'contentful-columns',
|
|
2764
|
-
name: 'Columns',
|
|
2765
|
-
},
|
|
2766
|
-
singleColumn: {
|
|
2767
|
-
id: 'contentful-single-column',
|
|
2768
|
-
name: 'Column',
|
|
2769
|
-
},
|
|
2770
|
-
button: {
|
|
2771
|
-
id: 'contentful-button',
|
|
2772
|
-
name: 'Button',
|
|
2773
|
-
},
|
|
2774
|
-
heading: {
|
|
2775
|
-
id: 'contentful-heading',
|
|
2776
|
-
name: 'Heading',
|
|
2777
|
-
},
|
|
2778
|
-
image: {
|
|
2779
|
-
id: 'contentful-image',
|
|
2780
|
-
name: 'Image',
|
|
2781
|
-
},
|
|
2782
|
-
richText: {
|
|
2783
|
-
id: 'contentful-richText',
|
|
2784
|
-
name: 'Rich Text',
|
|
2785
|
-
},
|
|
2786
|
-
text: {
|
|
2787
|
-
id: 'contentful-text',
|
|
2788
|
-
name: 'Text',
|
|
2789
|
-
},
|
|
2790
|
-
divider: {
|
|
2791
|
-
id: 'contentful-divider',
|
|
2792
|
-
name: 'Divider',
|
|
2793
|
-
},
|
|
2794
|
-
carousel: {
|
|
2795
|
-
id: 'contentful-carousel',
|
|
2796
|
-
name: 'Carousel',
|
|
2797
|
-
},
|
|
2798
|
-
};
|
|
2799
|
-
const ASSEMBLY_NODE_TYPE = 'assembly';
|
|
2800
|
-
const ASSEMBLY_DEFAULT_CATEGORY = 'Assemblies';
|
|
2801
|
-
const ASSEMBLY_BLOCK_NODE_TYPE = 'assemblyBlock';
|
|
2802
|
-
const ASSEMBLY_NODE_TYPES = [ASSEMBLY_NODE_TYPE, ASSEMBLY_BLOCK_NODE_TYPE];
|
|
2803
|
-
const EMPTY_CONTAINER_HEIGHT = '80px';
|
|
2804
|
-
const HYPERLINK_DEFAULT_PATTERN = `/{locale}/{entry.fields.slug}/`;
|
|
2805
|
-
var PostMessageMethods$2;
|
|
2806
|
-
(function (PostMessageMethods) {
|
|
2807
|
-
PostMessageMethods["REQUEST_ENTITIES"] = "REQUEST_ENTITIES";
|
|
2808
|
-
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
2809
|
-
})(PostMessageMethods$2 || (PostMessageMethods$2 = {}));
|
|
2810
|
-
|
|
2811
|
-
const DRAGGABLE_HEIGHT = 30;
|
|
2812
|
-
const DRAGGABLE_WIDTH = 50;
|
|
2813
|
-
const DRAG_PADDING = 4;
|
|
2814
2648
|
const ROOT_ID = 'root';
|
|
2815
|
-
const COMPONENT_LIST_ID = 'component-list';
|
|
2816
|
-
const NEW_COMPONENT_ID = 'ctfl-new-draggable';
|
|
2817
|
-
const CTFL_ZONE_ID = 'data-ctfl-zone-id';
|
|
2818
|
-
const CTFL_DRAGGING_ELEMENT = 'data-ctfl-dragging-element';
|
|
2819
|
-
const HITBOX = {
|
|
2820
|
-
WIDTH: 70,
|
|
2821
|
-
HEIGHT: 20,
|
|
2822
|
-
INITIAL_OFFSET: 10,
|
|
2823
|
-
OFFSET_INCREMENT: 8,
|
|
2824
|
-
MIN_HEIGHT: 45,
|
|
2825
|
-
MIN_DEPTH_HEIGHT: 20,
|
|
2826
|
-
DEEP_ZONE: 5,
|
|
2827
|
-
};
|
|
2828
2649
|
var TreeAction;
|
|
2829
2650
|
(function (TreeAction) {
|
|
2830
2651
|
TreeAction[TreeAction["REMOVE_NODE"] = 0] = "REMOVE_NODE";
|
|
@@ -2834,139 +2655,6 @@ var TreeAction;
|
|
|
2834
2655
|
TreeAction[TreeAction["REORDER_NODE"] = 4] = "REORDER_NODE";
|
|
2835
2656
|
TreeAction[TreeAction["REPLACE_NODE"] = 5] = "REPLACE_NODE";
|
|
2836
2657
|
})(TreeAction || (TreeAction = {}));
|
|
2837
|
-
var HitboxDirection;
|
|
2838
|
-
(function (HitboxDirection) {
|
|
2839
|
-
HitboxDirection[HitboxDirection["TOP"] = 0] = "TOP";
|
|
2840
|
-
HitboxDirection[HitboxDirection["LEFT"] = 1] = "LEFT";
|
|
2841
|
-
HitboxDirection[HitboxDirection["RIGHT"] = 2] = "RIGHT";
|
|
2842
|
-
HitboxDirection[HitboxDirection["BOTTOM"] = 3] = "BOTTOM";
|
|
2843
|
-
HitboxDirection[HitboxDirection["SELF_VERTICAL"] = 4] = "SELF_VERTICAL";
|
|
2844
|
-
HitboxDirection[HitboxDirection["SELF_HORIZONTAL"] = 5] = "SELF_HORIZONTAL";
|
|
2845
|
-
})(HitboxDirection || (HitboxDirection = {}));
|
|
2846
|
-
var DraggablePosition;
|
|
2847
|
-
(function (DraggablePosition) {
|
|
2848
|
-
DraggablePosition[DraggablePosition["CENTERED"] = 0] = "CENTERED";
|
|
2849
|
-
DraggablePosition[DraggablePosition["MOUSE_POSITION"] = 1] = "MOUSE_POSITION";
|
|
2850
|
-
})(DraggablePosition || (DraggablePosition = {}));
|
|
2851
|
-
|
|
2852
|
-
function useDraggablePosition({ draggableId, draggableRef, position }) {
|
|
2853
|
-
const isDraggingOnCanvas = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
2854
|
-
const draggingId = useDraggedItemStore((state) => state.onBeforeCaptureId);
|
|
2855
|
-
const preDragDomRect = useDraggedItemStore((state) => state.domRect);
|
|
2856
|
-
useEffect(() => {
|
|
2857
|
-
const el = draggableRef?.current ??
|
|
2858
|
-
document.querySelector(`[${CTFL_DRAGGING_ELEMENT}][data-cf-node-id="${draggableId}"]`);
|
|
2859
|
-
if (!isDraggingOnCanvas || draggingId !== draggableId || !el) {
|
|
2860
|
-
return;
|
|
2861
|
-
}
|
|
2862
|
-
const isCentered = position === DraggablePosition.CENTERED || !preDragDomRect;
|
|
2863
|
-
const domRect = isCentered ? el.getBoundingClientRect() : preDragDomRect;
|
|
2864
|
-
const { mouseX, mouseY } = useDraggedItemStore.getState();
|
|
2865
|
-
const top = isCentered ? mouseY - domRect.height / 2 : domRect.top;
|
|
2866
|
-
const left = isCentered ? mouseX - domRect.width / 2 : domRect.left;
|
|
2867
|
-
el.style.position = 'fixed';
|
|
2868
|
-
el.style.left = `${left}px`;
|
|
2869
|
-
el.style.top = `${top}px`;
|
|
2870
|
-
el.style.width = `${domRect.width}px`;
|
|
2871
|
-
el.style.height = `${domRect.height}px`;
|
|
2872
|
-
}, [draggableRef, draggableId, isDraggingOnCanvas, draggingId, position, preDragDomRect]);
|
|
2873
|
-
}
|
|
2874
|
-
|
|
2875
|
-
function getStyle$2(style, snapshot) {
|
|
2876
|
-
if (!snapshot.isDropAnimating) {
|
|
2877
|
-
return style;
|
|
2878
|
-
}
|
|
2879
|
-
return {
|
|
2880
|
-
...style,
|
|
2881
|
-
// cannot be 0, but make it super tiny
|
|
2882
|
-
transitionDuration: `0.001s`,
|
|
2883
|
-
};
|
|
2884
|
-
}
|
|
2885
|
-
const DraggableContainer = ({ id }) => {
|
|
2886
|
-
const ref = useRef(null);
|
|
2887
|
-
useDraggablePosition({
|
|
2888
|
-
draggableId: id,
|
|
2889
|
-
draggableRef: ref,
|
|
2890
|
-
position: DraggablePosition.CENTERED,
|
|
2891
|
-
});
|
|
2892
|
-
return (React.createElement("div", { id: COMPONENT_LIST_ID, style: {
|
|
2893
|
-
position: 'absolute',
|
|
2894
|
-
top: 0,
|
|
2895
|
-
left: 0,
|
|
2896
|
-
pointerEvents: 'none',
|
|
2897
|
-
zIndex: -1,
|
|
2898
|
-
} },
|
|
2899
|
-
React.createElement(Droppable, { droppableId: COMPONENT_LIST_ID, isDropDisabled: true }, (provided) => (React.createElement("div", { ...provided.droppableProps, ref: provided.innerRef },
|
|
2900
|
-
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) => {
|
|
2901
|
-
provided.innerRef(node);
|
|
2902
|
-
ref.current = node;
|
|
2903
|
-
}, ...provided.draggableProps, ...provided.dragHandleProps, style: {
|
|
2904
|
-
...getStyle$2(provided.draggableProps.style, snapshot),
|
|
2905
|
-
width: DRAGGABLE_WIDTH,
|
|
2906
|
-
height: DRAGGABLE_HEIGHT,
|
|
2907
|
-
pointerEvents: 'none',
|
|
2908
|
-
} }))),
|
|
2909
|
-
provided.placeholder)))));
|
|
2910
|
-
};
|
|
2911
|
-
|
|
2912
|
-
function getItemFromTree(id, node) {
|
|
2913
|
-
// Check if the current node's id matches the search id
|
|
2914
|
-
if (node.data.id === id) {
|
|
2915
|
-
return node;
|
|
2916
|
-
}
|
|
2917
|
-
// Recursively search through each child
|
|
2918
|
-
for (const child of node.children) {
|
|
2919
|
-
const foundNode = getItemFromTree(id, child);
|
|
2920
|
-
if (foundNode) {
|
|
2921
|
-
// Node found in children
|
|
2922
|
-
return foundNode;
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
// If the node is not found in this branch of the tree, return undefined
|
|
2926
|
-
return undefined;
|
|
2927
|
-
}
|
|
2928
|
-
function findDepthById(node, id, currentDepth = 1) {
|
|
2929
|
-
if (node.data.id === id) {
|
|
2930
|
-
return currentDepth;
|
|
2931
|
-
}
|
|
2932
|
-
// If the node has children, check each one
|
|
2933
|
-
for (const child of node.children) {
|
|
2934
|
-
const childDepth = findDepthById(child, id, currentDepth + 1);
|
|
2935
|
-
if (childDepth !== -1) {
|
|
2936
|
-
return childDepth; // Found the node in a child
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
return -1; // Node not found in this branch
|
|
2940
|
-
}
|
|
2941
|
-
const getChildFromTree = (parentId, index, node) => {
|
|
2942
|
-
// Check if the current node's id matches the search id
|
|
2943
|
-
if (node.data.id === parentId) {
|
|
2944
|
-
return node.children[index];
|
|
2945
|
-
}
|
|
2946
|
-
// Recursively search through each child
|
|
2947
|
-
for (const child of node.children) {
|
|
2948
|
-
const foundNode = getChildFromTree(parentId, index, child);
|
|
2949
|
-
if (foundNode) {
|
|
2950
|
-
// Node found in children
|
|
2951
|
-
return foundNode;
|
|
2952
|
-
}
|
|
2953
|
-
}
|
|
2954
|
-
// If the node is not found in this branch of the tree, return undefined
|
|
2955
|
-
return undefined;
|
|
2956
|
-
};
|
|
2957
|
-
const getItem = (selector, tree) => {
|
|
2958
|
-
return getItemFromTree(selector.id, {
|
|
2959
|
-
type: 'block',
|
|
2960
|
-
data: {
|
|
2961
|
-
id: ROOT_ID,
|
|
2962
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2963
|
-
},
|
|
2964
|
-
children: tree.root.children,
|
|
2965
|
-
});
|
|
2966
|
-
};
|
|
2967
|
-
const getItemDepthFromNode = (selector, node) => {
|
|
2968
|
-
return findDepthById(node, selector.id);
|
|
2969
|
-
};
|
|
2970
2658
|
|
|
2971
2659
|
function updateNode(nodeId, updatedNode, node) {
|
|
2972
2660
|
if (node.data.id === nodeId) {
|
|
@@ -3005,24 +2693,33 @@ function addChildNode(indexToAdd, parentNodeId, nodeToAdd, node) {
|
|
|
3005
2693
|
}
|
|
3006
2694
|
node.children.forEach((childNode) => addChildNode(indexToAdd, parentNodeId, nodeToAdd, childNode));
|
|
3007
2695
|
}
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
node.children.splice(newIndex, 0, childToMove);
|
|
3014
|
-
return;
|
|
2696
|
+
|
|
2697
|
+
function getItemFromTree(id, node) {
|
|
2698
|
+
// Check if the current node's id matches the search id
|
|
2699
|
+
if (node.data.id === id) {
|
|
2700
|
+
return node;
|
|
3015
2701
|
}
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
2702
|
+
// Recursively search through each child
|
|
2703
|
+
for (const child of node.children) {
|
|
2704
|
+
const foundNode = getItemFromTree(id, child);
|
|
2705
|
+
if (foundNode) {
|
|
2706
|
+
// Node found in children
|
|
2707
|
+
return foundNode;
|
|
2708
|
+
}
|
|
3022
2709
|
}
|
|
3023
|
-
|
|
3024
|
-
|
|
2710
|
+
// If the node is not found in this branch of the tree, return undefined
|
|
2711
|
+
return undefined;
|
|
3025
2712
|
}
|
|
2713
|
+
const getItem = (selector, tree) => {
|
|
2714
|
+
return getItemFromTree(selector.id, {
|
|
2715
|
+
type: 'block',
|
|
2716
|
+
data: {
|
|
2717
|
+
id: ROOT_ID,
|
|
2718
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2719
|
+
},
|
|
2720
|
+
children: tree.root.children,
|
|
2721
|
+
});
|
|
2722
|
+
};
|
|
3026
2723
|
|
|
3027
2724
|
function missingNodeAction({ index, nodeAdded, child, tree, parentNodeId, currentNode, }) {
|
|
3028
2725
|
if (nodeAdded) {
|
|
@@ -3144,50 +2841,115 @@ function getTreeDiffs(tree1, tree2, originalTree) {
|
|
|
3144
2841
|
return differences.filter((diff) => diff);
|
|
3145
2842
|
}
|
|
3146
2843
|
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
/**
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
2844
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2845
|
+
const OUTGOING_EVENTS = {
|
|
2846
|
+
Connected: 'connected',
|
|
2847
|
+
DesignTokens: 'registerDesignTokens',
|
|
2848
|
+
RegisteredBreakpoints: 'registeredBreakpoints',
|
|
2849
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2850
|
+
MouseMove: 'mouseMove',
|
|
2851
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2852
|
+
ComponentSelected: 'componentSelected',
|
|
2853
|
+
RegisteredComponents: 'registeredComponents',
|
|
2854
|
+
RequestComponentTreeUpdate: 'requestComponentTreeUpdate',
|
|
2855
|
+
CanvasReload: 'canvasReload',
|
|
2856
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2857
|
+
UpdateSelectedComponentCoordinates: 'updateSelectedComponentCoordinates',
|
|
2858
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2859
|
+
CanvasScroll: 'canvasScrolling',
|
|
2860
|
+
CanvasError: 'canvasError',
|
|
2861
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2862
|
+
OutsideCanvasClick: 'outsideCanvasClick',
|
|
2863
|
+
SDKFeatures: 'sdkFeatures',
|
|
2864
|
+
RequestEntities: 'REQUEST_ENTITIES',
|
|
2865
|
+
CanvasGeometryUpdated: 'canvasGeometryUpdated',
|
|
2866
|
+
};
|
|
2867
|
+
const INCOMING_EVENTS = {
|
|
2868
|
+
RequestEditorMode: 'requestEditorMode',
|
|
2869
|
+
RequestReadOnlyMode: 'requestReadOnlyMode',
|
|
2870
|
+
ExperienceUpdated: 'componentTreeUpdated',
|
|
2871
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2872
|
+
ComponentDraggingChanged: 'componentDraggingChanged',
|
|
2873
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2874
|
+
ComponentDragCanceled: 'componentDragCanceled',
|
|
2875
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2876
|
+
ComponentDragStarted: 'componentDragStarted',
|
|
2877
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2878
|
+
ComponentDragEnded: 'componentDragEnded',
|
|
2879
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2880
|
+
ComponentMoveEnded: 'componentMoveEnded',
|
|
2881
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2882
|
+
CanvasResized: 'canvasResized',
|
|
2883
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2884
|
+
SelectComponent: 'selectComponent',
|
|
2885
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2886
|
+
HoverComponent: 'hoverComponent',
|
|
2887
|
+
UpdatedEntity: 'updatedEntity',
|
|
2888
|
+
AssembliesAdded: 'assembliesAdded',
|
|
2889
|
+
AssembliesRegistered: 'assembliesRegistered',
|
|
2890
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
2891
|
+
MouseMove: 'mouseMove',
|
|
2892
|
+
RequestedEntities: 'REQUESTED_ENTITIES',
|
|
2893
|
+
};
|
|
2894
|
+
const INTERNAL_EVENTS = {
|
|
2895
|
+
ComponentsRegistered: 'cfComponentsRegistered',
|
|
2896
|
+
VisualEditorInitialize: 'cfVisualEditorInitialize',
|
|
2897
|
+
};
|
|
2898
|
+
const VISUAL_EDITOR_EVENTS = {
|
|
2899
|
+
Ready: 'cfVisualEditorReady',
|
|
2900
|
+
};
|
|
2901
|
+
/**
|
|
2902
|
+
* These modes are ONLY intended to be internally used within the context of
|
|
2903
|
+
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
2904
|
+
* intentionally do not include preview/delivery modes.
|
|
2905
|
+
*/
|
|
2906
|
+
var StudioCanvasMode$2;
|
|
2907
|
+
(function (StudioCanvasMode) {
|
|
2908
|
+
StudioCanvasMode["READ_ONLY"] = "readOnlyMode";
|
|
2909
|
+
StudioCanvasMode["EDITOR"] = "editorMode";
|
|
2910
|
+
StudioCanvasMode["NONE"] = "none";
|
|
2911
|
+
})(StudioCanvasMode$2 || (StudioCanvasMode$2 = {}));
|
|
2912
|
+
const ASSEMBLY_NODE_TYPE = 'assembly';
|
|
2913
|
+
const ASSEMBLY_DEFAULT_CATEGORY = 'Assemblies';
|
|
2914
|
+
const ASSEMBLY_BLOCK_NODE_TYPE = 'assemblyBlock';
|
|
2915
|
+
const EMPTY_CONTAINER_SIZE = '80px';
|
|
2916
|
+
const HYPERLINK_DEFAULT_PATTERN = `/{locale}/{entry.fields.slug}/`;
|
|
2917
|
+
var PostMessageMethods$2;
|
|
2918
|
+
(function (PostMessageMethods) {
|
|
2919
|
+
PostMessageMethods["REQUEST_ENTITIES"] = "REQUEST_ENTITIES";
|
|
2920
|
+
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
2921
|
+
})(PostMessageMethods$2 || (PostMessageMethods$2 = {}));
|
|
2922
|
+
|
|
2923
|
+
const useTreeStore = create((set, get) => ({
|
|
2924
|
+
tree: {
|
|
2925
|
+
root: {
|
|
2926
|
+
children: [],
|
|
2927
|
+
type: 'root',
|
|
2928
|
+
data: {
|
|
2929
|
+
breakpoints: [],
|
|
2930
|
+
dataSource: {},
|
|
2931
|
+
id: ROOT_ID,
|
|
2932
|
+
props: {},
|
|
2933
|
+
unboundValues: {},
|
|
2934
|
+
},
|
|
2935
|
+
},
|
|
2936
|
+
},
|
|
2937
|
+
breakpoints: [],
|
|
2938
|
+
updateNodesByUpdatedEntity: (entityId) => {
|
|
2939
|
+
set(produce((draftState) => {
|
|
2940
|
+
treeVisit(draftState.tree.root, (node) => {
|
|
2941
|
+
if (isAssemblyNode(node) && node.data.blockId === entityId) {
|
|
2942
|
+
// Cannot use `structuredClone()` as node is probably a Proxy object with weird references
|
|
2943
|
+
updateNode(node.data.id, cloneDeepAsPOJO(node), draftState.tree.root);
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
const dataSourceIds = Object.values(node.data.dataSource).map((link) => link.sys.id);
|
|
2947
|
+
if (dataSourceIds.includes(entityId)) {
|
|
2948
|
+
// Cannot use `structuredClone()` as node is probably a Proxy object with weird references
|
|
2949
|
+
updateNode(node.data.id, cloneDeepAsPOJO(node), draftState.tree.root);
|
|
2950
|
+
}
|
|
2951
|
+
});
|
|
2952
|
+
}));
|
|
3191
2953
|
},
|
|
3192
2954
|
updateTree: (tree) => {
|
|
3193
2955
|
const currentTree = get().tree;
|
|
@@ -3234,21 +2996,6 @@ const useTreeStore = create((set, get) => ({
|
|
|
3234
2996
|
state.breakpoints = tree?.root?.data?.breakpoints || [];
|
|
3235
2997
|
}));
|
|
3236
2998
|
},
|
|
3237
|
-
addChild: (index, parentId, node) => {
|
|
3238
|
-
set(produce((state) => {
|
|
3239
|
-
addChildNode(index, parentId, node, state.tree.root);
|
|
3240
|
-
}));
|
|
3241
|
-
},
|
|
3242
|
-
reorderChildren: (destinationIndex, destinationParentId, sourceIndex) => {
|
|
3243
|
-
set(produce((state) => {
|
|
3244
|
-
reorderChildNode(sourceIndex, destinationIndex, destinationParentId, state.tree.root);
|
|
3245
|
-
}));
|
|
3246
|
-
},
|
|
3247
|
-
reparentChild: (destinationIndex, destinationParentId, sourceIndex, sourceParentId) => {
|
|
3248
|
-
set(produce((state) => {
|
|
3249
|
-
reparentChildNode(sourceIndex, destinationIndex, sourceParentId, destinationParentId, state.tree.root);
|
|
3250
|
-
}));
|
|
3251
|
-
},
|
|
3252
2999
|
// breadth first search
|
|
3253
3000
|
findNodeById(nodeId) {
|
|
3254
3001
|
if (!nodeId) {
|
|
@@ -3286,9 +3033,9 @@ const cloneDeepAsPOJO = (obj) => {
|
|
|
3286
3033
|
return JSON.parse(JSON.stringify(obj));
|
|
3287
3034
|
};
|
|
3288
3035
|
|
|
3289
|
-
var css_248z$
|
|
3290
|
-
var styles$
|
|
3291
|
-
styleInject(css_248z$
|
|
3036
|
+
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";
|
|
3037
|
+
var styles$2 = {"rootContainer":"RootRenderer-module_rootContainer__9UawM"};
|
|
3038
|
+
styleInject(css_248z$a);
|
|
3292
3039
|
|
|
3293
3040
|
// TODO: In order to support integrations without React, we should extract this heavy logic into simple
|
|
3294
3041
|
// functions that we can reuse in other frameworks.
|
|
@@ -3326,66 +3073,6 @@ const useBreakpoints = (breakpoints) => {
|
|
|
3326
3073
|
return { resolveDesignValue };
|
|
3327
3074
|
};
|
|
3328
3075
|
|
|
3329
|
-
/**
|
|
3330
|
-
* This function gets the element co-ordinates of a specified component in the DOM and its parent
|
|
3331
|
-
* and sends the DOM Rect to the client app
|
|
3332
|
-
*/
|
|
3333
|
-
const sendSelectedComponentCoordinates = (instanceId) => {
|
|
3334
|
-
const selection = getSelectionNodes(instanceId);
|
|
3335
|
-
if (selection?.target) {
|
|
3336
|
-
const sendUpdateSelectedComponentCoordinates = () => {
|
|
3337
|
-
sendMessage(OUTGOING_EVENTS.UpdateSelectedComponentCoordinates, {
|
|
3338
|
-
selectedNodeCoordinates: getElementCoordinates(selection.target),
|
|
3339
|
-
selectedAssemblyChildCoordinates: selection.patternChild
|
|
3340
|
-
? getElementCoordinates(selection.patternChild)
|
|
3341
|
-
: undefined,
|
|
3342
|
-
parentCoordinates: selection.parent ? getElementCoordinates(selection.parent) : undefined,
|
|
3343
|
-
});
|
|
3344
|
-
};
|
|
3345
|
-
// If the target contains an image, wait for this image to be loaded before sending the coordinates
|
|
3346
|
-
const childImage = selection.target.querySelector('img');
|
|
3347
|
-
if (childImage) {
|
|
3348
|
-
const handleImageLoad = () => {
|
|
3349
|
-
sendUpdateSelectedComponentCoordinates();
|
|
3350
|
-
childImage.removeEventListener('load', handleImageLoad);
|
|
3351
|
-
};
|
|
3352
|
-
childImage.addEventListener('load', handleImageLoad);
|
|
3353
|
-
}
|
|
3354
|
-
sendUpdateSelectedComponentCoordinates();
|
|
3355
|
-
}
|
|
3356
|
-
};
|
|
3357
|
-
const getSelectionNodes = (instanceId) => {
|
|
3358
|
-
if (!instanceId)
|
|
3359
|
-
return;
|
|
3360
|
-
let selectedNode = document.querySelector(`[data-cf-node-id="${instanceId}"]`);
|
|
3361
|
-
let selectedPatternChild = null;
|
|
3362
|
-
let selectedParent = null;
|
|
3363
|
-
// Use RegEx instead of split to match the last occurrence of '---' in the instanceId instead of the first one
|
|
3364
|
-
const idMatch = instanceId.match(/(.*)---(.*)/);
|
|
3365
|
-
const rootNodeId = idMatch?.[1] ?? instanceId;
|
|
3366
|
-
const nodeLocation = idMatch?.[2];
|
|
3367
|
-
const isNestedPattern = nodeLocation && selectedNode?.dataset?.cfNodeBlockType === ASSEMBLY_NODE_TYPE;
|
|
3368
|
-
const isPatternChild = !isNestedPattern && nodeLocation;
|
|
3369
|
-
if (isPatternChild) {
|
|
3370
|
-
// For pattern child nodes, render the pattern itself as selected component
|
|
3371
|
-
selectedPatternChild = selectedNode;
|
|
3372
|
-
selectedNode = document.querySelector(`[data-cf-node-id="${rootNodeId}"]`);
|
|
3373
|
-
}
|
|
3374
|
-
else if (isNestedPattern) {
|
|
3375
|
-
// For nested patterns, return the upper pattern as parent
|
|
3376
|
-
selectedParent = document.querySelector(`[data-cf-node-id="${rootNodeId}"]`);
|
|
3377
|
-
}
|
|
3378
|
-
else {
|
|
3379
|
-
// Find the next valid parent of the selected element
|
|
3380
|
-
selectedParent = selectedNode?.parentElement ?? null;
|
|
3381
|
-
// Ensure that the selection parent is a VisualEditorBlock
|
|
3382
|
-
while (selectedParent && !selectedParent.dataset?.cfNodeId) {
|
|
3383
|
-
selectedParent = selectedParent?.parentElement;
|
|
3384
|
-
}
|
|
3385
|
-
}
|
|
3386
|
-
return { target: selectedNode, patternChild: selectedPatternChild, parent: selectedParent };
|
|
3387
|
-
};
|
|
3388
|
-
|
|
3389
3076
|
// Note: During development, the hot reloading might empty this and it
|
|
3390
3077
|
// stays empty leading to not rendering assemblies. Ideally, this is
|
|
3391
3078
|
// integrated into the state machine to keep track of its state.
|
|
@@ -3419,14 +3106,10 @@ const useEditorStore = create((set, get) => ({
|
|
|
3419
3106
|
dataSource: {},
|
|
3420
3107
|
hyperLinkPattern: undefined,
|
|
3421
3108
|
unboundValues: {},
|
|
3422
|
-
selectedNodeId: null,
|
|
3423
3109
|
locale: null,
|
|
3424
3110
|
setHyperLinkPattern: (pattern) => {
|
|
3425
3111
|
set({ hyperLinkPattern: pattern });
|
|
3426
3112
|
},
|
|
3427
|
-
setSelectedNodeId: (id) => {
|
|
3428
|
-
set({ selectedNodeId: id });
|
|
3429
|
-
},
|
|
3430
3113
|
setDataSource(data) {
|
|
3431
3114
|
const dataSource = get().dataSource;
|
|
3432
3115
|
const newDataSource = { ...dataSource, ...data };
|
|
@@ -3455,6 +3138,10 @@ const useEditorStore = create((set, get) => ({
|
|
|
3455
3138
|
},
|
|
3456
3139
|
}));
|
|
3457
3140
|
|
|
3141
|
+
var css_248z$8 = "@import url(https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,400;0,500;0,600;1,400;1,600&display=swap);:root{--cf-color-white:#fff;--cf-color-black:#000;--cf-color-gray100:#f7f9fa;--cf-color-gray400:#aec1cc;--cf-color-gray400-rgb:174,193,204;--cf-spacing-0:0rem;--cf-spacing-1:0.125rem;--cf-spacing-2:0.25rem;--cf-spacing-3:0.375rem;--cf-spacing-4:0.5rem;--cf-spacing-5:0.625rem;--cf-spacing-6:0.75rem;--cf-spacing-7:0.875rem;--cf-spacing-8:1rem;--cf-spacing-9:1.25rem;--cf-spacing-10:1.5rem;--cf-spacing-11:1.75rem;--cf-spacing-12:2rem;--cf-spacing-13:2.25rem;--cf-text-xs:0.75rem;--cf-text-sm:0.875rem;--cf-text-base:1rem;--cf-text-lg:1.125rem;--cf-text-xl:1.25rem;--cf-text-2xl:1.5rem;--cf-text-3xl:2rem;--cf-text-4xl:2.75rem;--cf-font-light:300;--cf-font-normal:400;--cf-font-medium:500;--cf-font-semibold:600;--cf-font-bold:700;--cf-font-extra-bold:800;--cf-font-black:900;--cf-border-radius-none:0px;--cf-border-radius-sm:0.125rem;--cf-border-radius:0.25rem;--cf-border-radius-md:0.375rem;--cf-border-radius-lg:0.5rem;--cf-border-radius-xl:0.75rem;--cf-border-radius-2xl:1rem;--cf-border-radius-3xl:1.5rem;--cf-border-radius-full:9999px;--cf-font-family-sans:Archivo,Helvetica,Arial,sans-serif;--cf-font-family-serif:Georgia,Cambria,Times New Roman,Times,serif;--cf-max-width-full:100%;--cf-button-bg:var(--cf-color-black);--cf-button-color:var(--cf-color-white);--cf-text-color:var(--cf-color-black)}*{box-sizing:border-box}";
|
|
3142
|
+
styleInject(css_248z$8);
|
|
3143
|
+
|
|
3144
|
+
/** @deprecated will be removed when dropping backward compatibility for old DND */
|
|
3458
3145
|
/**
|
|
3459
3146
|
* These modes are ONLY intended to be internally used within the context of
|
|
3460
3147
|
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
@@ -3472,6 +3159,21 @@ var PostMessageMethods$1;
|
|
|
3472
3159
|
PostMessageMethods["REQUESTED_ENTITIES"] = "REQUESTED_ENTITIES";
|
|
3473
3160
|
})(PostMessageMethods$1 || (PostMessageMethods$1 = {}));
|
|
3474
3161
|
|
|
3162
|
+
var css_248z$7 = ".cf-button:empty:before{content:\"\";display:inline-block}";
|
|
3163
|
+
styleInject(css_248z$7);
|
|
3164
|
+
|
|
3165
|
+
var css_248z$6 = ".cf-heading{white-space:pre-line}";
|
|
3166
|
+
styleInject(css_248z$6);
|
|
3167
|
+
|
|
3168
|
+
var css_248z$5 = ".cf-richtext{white-space:pre-line}.cf-richtext>:first-child{margin-top:0}.cf-richtext>:last-child{margin-bottom:0}";
|
|
3169
|
+
styleInject(css_248z$5);
|
|
3170
|
+
|
|
3171
|
+
var css_248z$4 = ".cf-text{white-space:pre-line}.cf-text-link .cf-text{margin:0}";
|
|
3172
|
+
styleInject(css_248z$4);
|
|
3173
|
+
|
|
3174
|
+
var css_248z$3 = "div.cf-placeholder-wrapper{position:relative}img.cf-placeholder-image{background-color:var(--cf-color-gray100);height:100%;outline:2px solid rgba(var(--cf-color-gray400-rgb),.5);outline-offset:-2px;width:100%}svg.cf-placeholder-icon{height:var(--cf-text-3xl);left:50%;max-height:100%;max-width:100%;position:absolute;top:50%;transform:translate(-50%,-50%);width:var(--cf-text-3xl)}svg.cf-placeholder-icon path{fill:var(--cf-color-gray400)}";
|
|
3175
|
+
styleInject(css_248z$3);
|
|
3176
|
+
|
|
3475
3177
|
/**
|
|
3476
3178
|
* These modes are ONLY intended to be internally used within the context of
|
|
3477
3179
|
* editing an experience inside of Contentful Studio. i.e. these modes
|
|
@@ -3799,13 +3501,7 @@ const ParameterDefinitionSchema = z.object({
|
|
|
3799
3501
|
}),
|
|
3800
3502
|
})
|
|
3801
3503
|
.optional(),
|
|
3802
|
-
contentTypes: z.
|
|
3803
|
-
sys: z.object({
|
|
3804
|
-
type: z.literal('Link'),
|
|
3805
|
-
id: z.string(),
|
|
3806
|
-
linkType: z.enum(['ContentType']),
|
|
3807
|
-
}),
|
|
3808
|
-
})),
|
|
3504
|
+
contentTypes: z.array(z.string()),
|
|
3809
3505
|
passToNodes: z.array(PassToNodeSchema).optional(),
|
|
3810
3506
|
});
|
|
3811
3507
|
const ParameterDefinitionsSchema = z.record(propertyKeySchema, ParameterDefinitionSchema);
|
|
@@ -3825,7 +3521,7 @@ const ComponentSettingsSchema = z
|
|
|
3825
3521
|
variableDefinitions: ComponentVariablesSchema,
|
|
3826
3522
|
thumbnailId: z.enum(THUMBNAIL_IDS).optional(),
|
|
3827
3523
|
category: z.string().max(50, 'Category must contain at most 50 characters').optional(),
|
|
3828
|
-
prebindingDefinitions: z.array(PrebindingDefinitionSchema).
|
|
3524
|
+
prebindingDefinitions: z.array(PrebindingDefinitionSchema).length(1).optional(),
|
|
3829
3525
|
})
|
|
3830
3526
|
.strict();
|
|
3831
3527
|
z.object({
|
|
@@ -4450,6 +4146,9 @@ var VisualEditorMode;
|
|
|
4450
4146
|
VisualEditorMode["InjectScript"] = "injectScript";
|
|
4451
4147
|
})(VisualEditorMode || (VisualEditorMode = {}));
|
|
4452
4148
|
|
|
4149
|
+
var css_248z$2 = ".contentful-container{display:flex;pointer-events:all;position:relative}.contentful-container::-webkit-scrollbar{display:none}.cf-container-wrapper{position:relative;width:100%}.contentful-container:after{align-items:center;bottom:0;color:var(--exp-builder-gray400);content:\"\";display:block;display:flex;font-family:var(--exp-builder-font-stack-primary);font-size:12px;justify-content:center;left:0;overflow-x:clip;pointer-events:none;position:absolute;right:0;top:0;z-index:1}.contentful-section-label:after{content:\"Section\"}.contentful-container-label:after{content:\"Container\"}.contentful-container-link,.contentful-container-link:active,.contentful-container-link:focus-visible,.contentful-container-link:hover,.contentful-container-link:read-write,.contentful-container-link:visited{color:inherit;outline:unset;text-decoration:unset}";
|
|
4150
|
+
styleInject(css_248z$2);
|
|
4151
|
+
|
|
4453
4152
|
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) => {
|
|
4454
4153
|
return (React.createElement("div", { id: id, ref: ref, style: {
|
|
4455
4154
|
display: 'flex',
|
|
@@ -4472,107 +4171,24 @@ const Flex = forwardRef(({ id, children, onMouseEnter, onMouseUp, onMouseLeave,
|
|
|
4472
4171
|
});
|
|
4473
4172
|
Flex.displayName = 'Flex';
|
|
4474
4173
|
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
} }, props.children));
|
|
4481
|
-
});
|
|
4482
|
-
ColumnWrapper.displayName = 'ColumnWrapper';
|
|
4174
|
+
var css_248z$1$1 = ".cf-divider{display:contents;height:100%;position:relative;width:100%}.cf-divider hr{border:none}";
|
|
4175
|
+
styleInject(css_248z$1$1);
|
|
4176
|
+
|
|
4177
|
+
var css_248z$9 = ".cf-columns{display:flex;flex-direction:column;gap:24px;grid-template-columns:repeat(12,1fr);min-height:0;min-width:0}@media (min-width:768px){.cf-columns{display:grid}}.cf-single-column-wrapper{position:relative}.cf-single-column-wrapper:after{align-items:center;bottom:0;color:var(--exp-builder-gray400);content:\"\";display:block;display:flex;font-family:var(--exp-builder-font-stack-primary);font-size:12px;justify-content:center;left:0;overflow-x:clip;pointer-events:none;position:absolute;right:0;top:0;z-index:1}.cf-single-column-label:after{content:\"Column\"}";
|
|
4178
|
+
styleInject(css_248z$9);
|
|
4483
4179
|
|
|
4484
4180
|
const assemblyStyle = { display: 'contents' };
|
|
4485
|
-
// Feel free to do any magic as regards variable definitions for assemblies
|
|
4486
|
-
// Or if this isn't necessary by the time we figure that part out, we can bid this part farewell
|
|
4487
4181
|
const Assembly = (props) => {
|
|
4488
|
-
if (props.editorMode) {
|
|
4489
|
-
const { node, dragProps, ...editorModeProps } = props;
|
|
4490
|
-
return props.renderDropzone(node, {
|
|
4491
|
-
...editorModeProps,
|
|
4492
|
-
['data-test-id']: 'contentful-assembly',
|
|
4493
|
-
className: props.className,
|
|
4494
|
-
dragProps,
|
|
4495
|
-
});
|
|
4496
|
-
}
|
|
4497
4182
|
// Using a display contents so assembly content/children
|
|
4498
4183
|
// can appear as if they are direct children of the div wrapper's parent
|
|
4499
4184
|
return React.createElement("div", { "data-test-id": "assembly", ...props, style: assemblyStyle });
|
|
4500
4185
|
};
|
|
4501
4186
|
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
get isDragging() {
|
|
4508
|
-
return this.isDraggingItem;
|
|
4509
|
-
}
|
|
4510
|
-
get isDraggingOnParent() {
|
|
4511
|
-
return this.isDragStartedOnParent;
|
|
4512
|
-
}
|
|
4513
|
-
updateIsDragging(isDraggingItem) {
|
|
4514
|
-
this.isDraggingItem = isDraggingItem;
|
|
4515
|
-
}
|
|
4516
|
-
updateIsDragStartedOnParent(isDragStartedOnParent) {
|
|
4517
|
-
this.isDragStartedOnParent = isDragStartedOnParent;
|
|
4518
|
-
}
|
|
4519
|
-
resetState() {
|
|
4520
|
-
this.isDraggingItem = false;
|
|
4521
|
-
this.isDragStartedOnParent = false;
|
|
4522
|
-
}
|
|
4523
|
-
}
|
|
4524
|
-
|
|
4525
|
-
class SimulateDnD extends DragState {
|
|
4526
|
-
constructor() {
|
|
4527
|
-
super();
|
|
4528
|
-
this.draggingElement = null;
|
|
4529
|
-
}
|
|
4530
|
-
setupDrag() {
|
|
4531
|
-
this.updateIsDragStartedOnParent(true);
|
|
4532
|
-
}
|
|
4533
|
-
startDrag(coordX, coordY) {
|
|
4534
|
-
this.draggingElement = document.getElementById(NEW_COMPONENT_ID);
|
|
4535
|
-
this.updateIsDragging(true);
|
|
4536
|
-
this.simulateMouseEvent(coordX, coordY, 'mousedown');
|
|
4537
|
-
}
|
|
4538
|
-
updateDrag(coordX, coordY) {
|
|
4539
|
-
if (!this.draggingElement) {
|
|
4540
|
-
this.draggingElement = document.querySelector(`[${CTFL_DRAGGING_ELEMENT}]`);
|
|
4541
|
-
}
|
|
4542
|
-
this.simulateMouseEvent(coordX, coordY);
|
|
4543
|
-
}
|
|
4544
|
-
endDrag(coordX, coordY) {
|
|
4545
|
-
this.simulateMouseEvent(coordX, coordY, 'mouseup');
|
|
4546
|
-
this.reset();
|
|
4547
|
-
}
|
|
4548
|
-
reset() {
|
|
4549
|
-
this.draggingElement = null;
|
|
4550
|
-
this.resetState();
|
|
4551
|
-
}
|
|
4552
|
-
simulateMouseEvent(coordX, coordY, eventName = 'mousemove') {
|
|
4553
|
-
if (!this.draggingElement) {
|
|
4554
|
-
return;
|
|
4555
|
-
}
|
|
4556
|
-
const options = {
|
|
4557
|
-
bubbles: true,
|
|
4558
|
-
cancelable: true,
|
|
4559
|
-
view: window,
|
|
4560
|
-
pageX: 0,
|
|
4561
|
-
pageY: 0,
|
|
4562
|
-
clientX: coordX,
|
|
4563
|
-
clientY: coordY,
|
|
4564
|
-
};
|
|
4565
|
-
const event = new MouseEvent(eventName, options);
|
|
4566
|
-
this.draggingElement.dispatchEvent(event);
|
|
4567
|
-
}
|
|
4568
|
-
}
|
|
4569
|
-
var SimulateDnD$1 = new SimulateDnD();
|
|
4570
|
-
|
|
4571
|
-
function useEditorSubscriber(entityCache) {
|
|
4572
|
-
const entityStore = entityCache((state) => state.entityStore);
|
|
4573
|
-
const areEntitiesFetched = entityCache((state) => state.areEntitiesFetched);
|
|
4574
|
-
const setEntitiesFetched = entityCache((state) => state.setEntitiesFetched);
|
|
4575
|
-
const resetEntityStore = entityCache((state) => state.resetEntityStore);
|
|
4187
|
+
function useEditorSubscriber(inMemoryEntitiesStore) {
|
|
4188
|
+
const entityStore = inMemoryEntitiesStore((state) => state.entityStore);
|
|
4189
|
+
const areEntitiesFetched = inMemoryEntitiesStore((state) => state.areEntitiesFetched);
|
|
4190
|
+
const setEntitiesFetched = inMemoryEntitiesStore((state) => state.setEntitiesFetched);
|
|
4191
|
+
const resetEntityStore = inMemoryEntitiesStore((state) => state.resetEntityStore);
|
|
4576
4192
|
const { updateTree, updateNodesByUpdatedEntity } = useTreeStore((state) => ({
|
|
4577
4193
|
updateTree: state.updateTree,
|
|
4578
4194
|
updateNodesByUpdatedEntity: state.updateNodesByUpdatedEntity,
|
|
@@ -4582,13 +4198,6 @@ function useEditorSubscriber(entityCache) {
|
|
|
4582
4198
|
const setLocale = useEditorStore((state) => state.setLocale);
|
|
4583
4199
|
const setUnboundValues = useEditorStore((state) => state.setUnboundValues);
|
|
4584
4200
|
const setDataSource = useEditorStore((state) => state.setDataSource);
|
|
4585
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
4586
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
4587
|
-
const setComponentId = useDraggedItemStore((state) => state.setComponentId);
|
|
4588
|
-
const setHoveredComponentId = useDraggedItemStore((state) => state.setHoveredComponentId);
|
|
4589
|
-
const setDraggingOnCanvas = useDraggedItemStore((state) => state.setDraggingOnCanvas);
|
|
4590
|
-
const setMousePosition = useDraggedItemStore((state) => state.setMousePosition);
|
|
4591
|
-
const setScrollY = useDraggedItemStore((state) => state.setScrollY);
|
|
4592
4201
|
const reloadApp = () => {
|
|
4593
4202
|
sendMessage(OUTGOING_EVENTS.CanvasReload, undefined);
|
|
4594
4203
|
// Wait a moment to ensure that the message was sent
|
|
@@ -4766,27 +4375,6 @@ function useEditorSubscriber(entityCache) {
|
|
|
4766
4375
|
}
|
|
4767
4376
|
break;
|
|
4768
4377
|
}
|
|
4769
|
-
case INCOMING_EVENTS.CanvasResized: {
|
|
4770
|
-
const { selectedNodeId } = eventData.payload;
|
|
4771
|
-
if (selectedNodeId) {
|
|
4772
|
-
sendSelectedComponentCoordinates(selectedNodeId);
|
|
4773
|
-
}
|
|
4774
|
-
break;
|
|
4775
|
-
}
|
|
4776
|
-
case INCOMING_EVENTS.HoverComponent: {
|
|
4777
|
-
const { hoveredNodeId } = eventData.payload;
|
|
4778
|
-
setHoveredComponentId(hoveredNodeId);
|
|
4779
|
-
break;
|
|
4780
|
-
}
|
|
4781
|
-
case INCOMING_EVENTS.ComponentDraggingChanged: {
|
|
4782
|
-
const { isDragging } = eventData.payload;
|
|
4783
|
-
if (!isDragging) {
|
|
4784
|
-
setComponentId('');
|
|
4785
|
-
setDraggingOnCanvas(false);
|
|
4786
|
-
SimulateDnD$1.reset();
|
|
4787
|
-
}
|
|
4788
|
-
break;
|
|
4789
|
-
}
|
|
4790
4378
|
case INCOMING_EVENTS.UpdatedEntity: {
|
|
4791
4379
|
const { entity: updatedEntity, shouldRerender } = eventData.payload;
|
|
4792
4380
|
if (updatedEntity) {
|
|
@@ -4803,51 +4391,6 @@ function useEditorSubscriber(entityCache) {
|
|
|
4803
4391
|
case INCOMING_EVENTS.RequestEditorMode: {
|
|
4804
4392
|
break;
|
|
4805
4393
|
}
|
|
4806
|
-
case INCOMING_EVENTS.ComponentDragCanceled: {
|
|
4807
|
-
if (SimulateDnD$1.isDragging) {
|
|
4808
|
-
//simulate a mouseup event to cancel the drag
|
|
4809
|
-
SimulateDnD$1.endDrag(0, 0);
|
|
4810
|
-
}
|
|
4811
|
-
break;
|
|
4812
|
-
}
|
|
4813
|
-
case INCOMING_EVENTS.ComponentDragStarted: {
|
|
4814
|
-
const { id, isAssembly } = eventData.payload;
|
|
4815
|
-
SimulateDnD$1.setupDrag();
|
|
4816
|
-
setComponentId(`${id}:${isAssembly}` || '');
|
|
4817
|
-
setDraggingOnCanvas(true);
|
|
4818
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
4819
|
-
nodeId: '',
|
|
4820
|
-
});
|
|
4821
|
-
break;
|
|
4822
|
-
}
|
|
4823
|
-
case INCOMING_EVENTS.ComponentDragEnded: {
|
|
4824
|
-
SimulateDnD$1.reset();
|
|
4825
|
-
setComponentId('');
|
|
4826
|
-
setDraggingOnCanvas(false);
|
|
4827
|
-
break;
|
|
4828
|
-
}
|
|
4829
|
-
case INCOMING_EVENTS.SelectComponent: {
|
|
4830
|
-
const { selectedNodeId: nodeId } = eventData.payload;
|
|
4831
|
-
setSelectedNodeId(nodeId);
|
|
4832
|
-
sendSelectedComponentCoordinates(nodeId);
|
|
4833
|
-
break;
|
|
4834
|
-
}
|
|
4835
|
-
case INCOMING_EVENTS.MouseMove: {
|
|
4836
|
-
const { mouseX, mouseY } = eventData.payload;
|
|
4837
|
-
setMousePosition(mouseX, mouseY);
|
|
4838
|
-
if (SimulateDnD$1.isDraggingOnParent && !SimulateDnD$1.isDragging) {
|
|
4839
|
-
SimulateDnD$1.startDrag(mouseX, mouseY);
|
|
4840
|
-
}
|
|
4841
|
-
else {
|
|
4842
|
-
SimulateDnD$1.updateDrag(mouseX, mouseY);
|
|
4843
|
-
}
|
|
4844
|
-
break;
|
|
4845
|
-
}
|
|
4846
|
-
case INCOMING_EVENTS.ComponentMoveEnded: {
|
|
4847
|
-
const { mouseX, mouseY } = eventData.payload;
|
|
4848
|
-
SimulateDnD$1.endDrag(mouseX, mouseY);
|
|
4849
|
-
break;
|
|
4850
|
-
}
|
|
4851
4394
|
default:
|
|
4852
4395
|
console.error(`[experiences-sdk-react::onMessage] Logic error, unsupported eventType: [${eventData.eventType}]`);
|
|
4853
4396
|
}
|
|
@@ -4858,11 +4401,8 @@ function useEditorSubscriber(entityCache) {
|
|
|
4858
4401
|
};
|
|
4859
4402
|
}, [
|
|
4860
4403
|
entityStore,
|
|
4861
|
-
setComponentId,
|
|
4862
|
-
setDraggingOnCanvas,
|
|
4863
4404
|
setDataSource,
|
|
4864
4405
|
setLocale,
|
|
4865
|
-
setSelectedNodeId,
|
|
4866
4406
|
dataSource,
|
|
4867
4407
|
areEntitiesFetched,
|
|
4868
4408
|
fetchMissingEntities,
|
|
@@ -4870,328 +4410,91 @@ function useEditorSubscriber(entityCache) {
|
|
|
4870
4410
|
unboundValues,
|
|
4871
4411
|
updateTree,
|
|
4872
4412
|
updateNodesByUpdatedEntity,
|
|
4873
|
-
setMousePosition,
|
|
4874
4413
|
resetEntityStore,
|
|
4875
|
-
setHoveredComponentId,
|
|
4876
4414
|
]);
|
|
4877
|
-
/*
|
|
4878
|
-
* Handles on scroll business
|
|
4879
|
-
*/
|
|
4880
|
-
useEffect(() => {
|
|
4881
|
-
let timeoutId = 0;
|
|
4882
|
-
let isScrolling = false;
|
|
4883
|
-
const onScroll = () => {
|
|
4884
|
-
setScrollY(window.scrollY);
|
|
4885
|
-
if (isScrolling === false) {
|
|
4886
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.Start);
|
|
4887
|
-
}
|
|
4888
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.IsScrolling);
|
|
4889
|
-
isScrolling = true;
|
|
4890
|
-
clearTimeout(timeoutId);
|
|
4891
|
-
timeoutId = window.setTimeout(() => {
|
|
4892
|
-
if (isScrolling === false) {
|
|
4893
|
-
return;
|
|
4894
|
-
}
|
|
4895
|
-
isScrolling = false;
|
|
4896
|
-
sendMessage(OUTGOING_EVENTS.CanvasScroll, SCROLL_STATES.End);
|
|
4897
|
-
/**
|
|
4898
|
-
* On scroll end, send new co-ordinates of selected node
|
|
4899
|
-
*/
|
|
4900
|
-
if (selectedNodeId) {
|
|
4901
|
-
sendSelectedComponentCoordinates(selectedNodeId);
|
|
4902
|
-
}
|
|
4903
|
-
}, 150);
|
|
4904
|
-
};
|
|
4905
|
-
window.addEventListener('scroll', onScroll, { capture: true, passive: true });
|
|
4906
|
-
return () => {
|
|
4907
|
-
window.removeEventListener('scroll', onScroll, { capture: true });
|
|
4908
|
-
clearTimeout(timeoutId);
|
|
4909
|
-
};
|
|
4910
|
-
}, [selectedNodeId, setScrollY]);
|
|
4911
4415
|
}
|
|
4912
4416
|
|
|
4913
|
-
const
|
|
4914
|
-
|
|
4417
|
+
const CircularDependencyErrorPlaceholder = ({ wrappingPatternIds, ...props }) => {
|
|
4418
|
+
return (React.createElement("div", { ...props, "data-cf-node-error": "circular-pattern-dependency", style: {
|
|
4419
|
+
border: '1px solid red',
|
|
4420
|
+
background: 'rgba(255, 0, 0, 0.1)',
|
|
4421
|
+
padding: '1rem 1rem 0 1rem',
|
|
4422
|
+
width: '100%',
|
|
4423
|
+
height: '100%',
|
|
4424
|
+
} },
|
|
4425
|
+
"Circular usage of patterns detected:",
|
|
4426
|
+
React.createElement("ul", null, Array.from(wrappingPatternIds).map((patternId) => {
|
|
4427
|
+
const entryLink = { sys: { type: 'Link', linkType: 'Entry', id: patternId } };
|
|
4428
|
+
const entry = inMemoryEntities.maybeResolveLink(entryLink);
|
|
4429
|
+
const entryTitle = entry?.fields?.title;
|
|
4430
|
+
const text = entryTitle ? `${entryTitle} (${patternId})` : patternId;
|
|
4431
|
+
return React.createElement("li", { key: patternId }, text);
|
|
4432
|
+
}))));
|
|
4915
4433
|
};
|
|
4916
4434
|
|
|
4917
|
-
|
|
4435
|
+
class ImportedComponentError extends Error {
|
|
4436
|
+
constructor(message) {
|
|
4437
|
+
super(message);
|
|
4438
|
+
this.name = 'ImportedComponentError';
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
class ExperienceSDKError extends Error {
|
|
4442
|
+
constructor(message) {
|
|
4443
|
+
super(message);
|
|
4444
|
+
this.name = 'ExperienceSDKError';
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
class ImportedComponentErrorBoundary extends React.Component {
|
|
4448
|
+
componentDidCatch(error, _errorInfo) {
|
|
4449
|
+
if (error.name === 'ImportedComponentError' || error.name === 'ExperienceSDKError') {
|
|
4450
|
+
// This error was already handled by a nested error boundary and should be passed upwards
|
|
4451
|
+
// We have to do this as we wrap every component on every layer with this error boundary and
|
|
4452
|
+
// thus an error deep in the tree bubbles through many layers of error boundaries.
|
|
4453
|
+
throw error;
|
|
4454
|
+
}
|
|
4455
|
+
// Differentiate between custom and SDK-provided components for error tracking
|
|
4456
|
+
const ErrorClass = isContentfulComponent(this.props.componentId)
|
|
4457
|
+
? ExperienceSDKError
|
|
4458
|
+
: ImportedComponentError;
|
|
4459
|
+
const err = new ErrorClass(error.message);
|
|
4460
|
+
err.stack = error.stack;
|
|
4461
|
+
throw err;
|
|
4462
|
+
}
|
|
4463
|
+
render() {
|
|
4464
|
+
return this.props.children;
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4918
4467
|
|
|
4919
|
-
const
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
breakpoints: [],
|
|
4929
|
-
unboundValues: {},
|
|
4930
|
-
},
|
|
4931
|
-
parentId,
|
|
4932
|
-
children: [],
|
|
4933
|
-
};
|
|
4934
|
-
return node;
|
|
4468
|
+
const MissingComponentPlaceholder = ({ blockId }) => {
|
|
4469
|
+
return (React.createElement("div", { style: {
|
|
4470
|
+
border: '1px solid red',
|
|
4471
|
+
width: '100%',
|
|
4472
|
+
height: '100%',
|
|
4473
|
+
} },
|
|
4474
|
+
"Missing component '",
|
|
4475
|
+
blockId,
|
|
4476
|
+
"'"));
|
|
4935
4477
|
};
|
|
4936
4478
|
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
index: index ?? node.children.length,
|
|
4941
|
-
parentNode: {
|
|
4942
|
-
type: parentType,
|
|
4943
|
-
data: {
|
|
4944
|
-
blockId: parentBlockId,
|
|
4945
|
-
id: parentId,
|
|
4946
|
-
},
|
|
4947
|
-
},
|
|
4948
|
-
});
|
|
4949
|
-
};
|
|
4950
|
-
|
|
4951
|
-
const onDrop = ({ destinationIndex, componentType, destinationZoneId, data, slotId, }) => {
|
|
4952
|
-
const parentId = destinationZoneId;
|
|
4953
|
-
const parentNode = getItem({ id: parentId }, data);
|
|
4954
|
-
const parentIsRoot = parentId === ROOT_ID;
|
|
4955
|
-
const emptyComponentData = {
|
|
4956
|
-
type: 'block',
|
|
4957
|
-
parentId,
|
|
4958
|
-
children: [],
|
|
4959
|
-
data: {
|
|
4960
|
-
blockId: componentType,
|
|
4961
|
-
id: generateId(componentType),
|
|
4962
|
-
slotId,
|
|
4963
|
-
breakpoints: [],
|
|
4964
|
-
dataSource: {},
|
|
4965
|
-
props: {},
|
|
4966
|
-
unboundValues: {},
|
|
4967
|
-
},
|
|
4968
|
-
};
|
|
4969
|
-
onComponentDropped({
|
|
4970
|
-
node: emptyComponentData,
|
|
4971
|
-
index: destinationIndex,
|
|
4972
|
-
parentType: parentIsRoot ? 'root' : parentNode?.type,
|
|
4973
|
-
parentBlockId: parentNode?.data.blockId,
|
|
4974
|
-
parentId: parentIsRoot ? 'root' : parentId,
|
|
4975
|
-
});
|
|
4976
|
-
};
|
|
4977
|
-
|
|
4978
|
-
/**
|
|
4979
|
-
* Parses a droppable zone ID into a node ID and slot ID.
|
|
4980
|
-
*
|
|
4981
|
-
* The slot ID is optional and only present if the component implements multiple drop zones.
|
|
4982
|
-
*
|
|
4983
|
-
* @param zoneId - Expected formats are `nodeId` or `nodeId|slotId`.
|
|
4984
|
-
*/
|
|
4985
|
-
const parseZoneId = (zoneId) => {
|
|
4986
|
-
const [nodeId, slotId] = zoneId.includes('|') ? zoneId.split('|') : [zoneId, undefined];
|
|
4987
|
-
return { nodeId, slotId };
|
|
4988
|
-
};
|
|
4479
|
+
var css_248z$1 = ".EditorBlock-module_emptySlot__za-Bi {\n min-height: 80px;\n min-width: 80px;\n}\n";
|
|
4480
|
+
var styles$1 = {"emptySlot":"EditorBlock-module_emptySlot__za-Bi"};
|
|
4481
|
+
styleInject(css_248z$1);
|
|
4989
4482
|
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
if (!destination) {
|
|
4998
|
-
return;
|
|
4999
|
-
}
|
|
5000
|
-
/**
|
|
5001
|
-
* We only have the draggableId as information about the new component being dropped.
|
|
5002
|
-
* So we need to split it to get the blockId and the isAssembly flag.
|
|
5003
|
-
*/
|
|
5004
|
-
const [blockId, isAssembly] = draggableId.split(':');
|
|
5005
|
-
const { nodeId: parentId, slotId } = parseZoneId(destination.droppableId);
|
|
5006
|
-
const droppingOnRoot = parentId === ROOT_ID;
|
|
5007
|
-
const isValidRootComponent = blockId === CONTENTFUL_COMPONENTS$1.container.id;
|
|
5008
|
-
let node = createTreeNode({ blockId, parentId, slotId });
|
|
5009
|
-
if (droppingOnRoot && !isValidRootComponent) {
|
|
5010
|
-
const wrappingContainer = createTreeNode({
|
|
5011
|
-
blockId: CONTENTFUL_COMPONENTS$1.container.id,
|
|
5012
|
-
parentId,
|
|
5013
|
-
});
|
|
5014
|
-
const childNode = createTreeNode({
|
|
5015
|
-
blockId,
|
|
5016
|
-
parentId: wrappingContainer.data.id,
|
|
4483
|
+
const useComponentRegistration = (node) => {
|
|
4484
|
+
return useMemo(() => {
|
|
4485
|
+
let registration = componentRegistry.get(node.data.blockId);
|
|
4486
|
+
if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
|
|
4487
|
+
registration = createAssemblyRegistration({
|
|
4488
|
+
definitionId: node.data.blockId,
|
|
4489
|
+
component: Assembly,
|
|
5017
4490
|
});
|
|
5018
|
-
node = wrappingContainer;
|
|
5019
|
-
node.children = [childNode];
|
|
5020
|
-
}
|
|
5021
|
-
/**
|
|
5022
|
-
* isAssembly comes from a string ID so we need to check if it's 'true' or 'false'
|
|
5023
|
-
* in string format.
|
|
5024
|
-
*/
|
|
5025
|
-
if (isAssembly === 'false') {
|
|
5026
|
-
addChild(destination.index, parentId, node);
|
|
5027
|
-
}
|
|
5028
|
-
onDrop({
|
|
5029
|
-
data: tree,
|
|
5030
|
-
componentType: blockId,
|
|
5031
|
-
destinationIndex: destination.index,
|
|
5032
|
-
destinationZoneId: parentId,
|
|
5033
|
-
slotId,
|
|
5034
|
-
});
|
|
5035
|
-
};
|
|
5036
|
-
const onMoveComponent = (droppedItem) => {
|
|
5037
|
-
const { destination, source, draggableId } = droppedItem;
|
|
5038
|
-
if (!destination || !source) {
|
|
5039
|
-
return;
|
|
5040
|
-
}
|
|
5041
|
-
if (destination.droppableId === source.droppableId) {
|
|
5042
|
-
reorderChildren(destination.index, destination.droppableId, source.index);
|
|
5043
|
-
}
|
|
5044
|
-
if (destination.droppableId !== source.droppableId) {
|
|
5045
|
-
reparentChild(destination.index, destination.droppableId, source.index, source.droppableId);
|
|
5046
|
-
}
|
|
5047
|
-
onComponentMoved({
|
|
5048
|
-
nodeId: draggableId,
|
|
5049
|
-
destinationIndex: destination.index,
|
|
5050
|
-
destinationParentId: destination.droppableId,
|
|
5051
|
-
sourceIndex: source.index,
|
|
5052
|
-
sourceParentId: source.droppableId,
|
|
5053
|
-
});
|
|
5054
|
-
};
|
|
5055
|
-
return { onAddComponent, onMoveComponent };
|
|
5056
|
-
}
|
|
5057
|
-
|
|
5058
|
-
const TestDNDContainer = ({ onDragEnd, onBeforeDragStart, onDragStart, onDragUpdate, children, }) => {
|
|
5059
|
-
const handleDragStart = (event) => {
|
|
5060
|
-
const draggedItem = event.nativeEvent;
|
|
5061
|
-
const start = {
|
|
5062
|
-
mode: draggedItem.mode,
|
|
5063
|
-
draggableId: draggedItem.draggableId,
|
|
5064
|
-
type: draggedItem.type,
|
|
5065
|
-
source: draggedItem.source,
|
|
5066
|
-
};
|
|
5067
|
-
onBeforeDragStart(start);
|
|
5068
|
-
onDragStart(start, {});
|
|
5069
|
-
};
|
|
5070
|
-
const handleDrag = (event) => {
|
|
5071
|
-
const draggedItem = event.nativeEvent;
|
|
5072
|
-
const update = {
|
|
5073
|
-
mode: draggedItem.mode,
|
|
5074
|
-
draggableId: draggedItem.draggableId,
|
|
5075
|
-
type: draggedItem.type,
|
|
5076
|
-
source: draggedItem.source,
|
|
5077
|
-
destination: draggedItem.destination,
|
|
5078
|
-
combine: draggedItem.combine,
|
|
5079
|
-
};
|
|
5080
|
-
onDragUpdate(update, {});
|
|
5081
|
-
};
|
|
5082
|
-
const handleDragEnd = (event) => {
|
|
5083
|
-
const draggedItem = event.nativeEvent;
|
|
5084
|
-
const result = {
|
|
5085
|
-
mode: draggedItem.mode,
|
|
5086
|
-
draggableId: draggedItem.draggableId,
|
|
5087
|
-
type: draggedItem.type,
|
|
5088
|
-
source: draggedItem.source,
|
|
5089
|
-
destination: draggedItem.destination,
|
|
5090
|
-
combine: draggedItem.combine,
|
|
5091
|
-
reason: draggedItem.reason,
|
|
5092
|
-
};
|
|
5093
|
-
onDragEnd(result, {});
|
|
5094
|
-
};
|
|
5095
|
-
return (React.createElement("div", { "data-test-id": "dnd-context-substitute", onDragStart: handleDragStart, onDrag: handleDrag, onDragEnd: handleDragEnd }, children));
|
|
5096
|
-
};
|
|
5097
|
-
|
|
5098
|
-
const DNDProvider = ({ children }) => {
|
|
5099
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
5100
|
-
const draggedItem = useDraggedItemStore((state) => state.draggedItem);
|
|
5101
|
-
const setOnBeforeCaptureId = useDraggedItemStore((state) => state.setOnBeforeCaptureId);
|
|
5102
|
-
const setDraggingOnCanvas = useDraggedItemStore((state) => state.setDraggingOnCanvas);
|
|
5103
|
-
const updateItem = useDraggedItemStore((state) => state.updateItem);
|
|
5104
|
-
const { onAddComponent, onMoveComponent } = useCanvasInteractions();
|
|
5105
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
5106
|
-
const prevSelectedNodeId = useRef(null);
|
|
5107
|
-
const isTestRun = typeof window !== 'undefined' && Object.prototype.hasOwnProperty.call(window, 'Cypress');
|
|
5108
|
-
const beforeDragStart = ({ source }) => {
|
|
5109
|
-
prevSelectedNodeId.current = selectedNodeId;
|
|
5110
|
-
// Unselect the current node when dragging and remove the outline
|
|
5111
|
-
setSelectedNodeId('');
|
|
5112
|
-
// Set dragging state here to make sure that DnD capture phase has completed
|
|
5113
|
-
setDraggingOnCanvas(true);
|
|
5114
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5115
|
-
nodeId: '',
|
|
5116
|
-
});
|
|
5117
|
-
if (source.droppableId !== COMPONENT_LIST_ID) {
|
|
5118
|
-
sendMessage(OUTGOING_EVENTS.ComponentMoveStarted, undefined);
|
|
5119
4491
|
}
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
};
|
|
5124
|
-
const dragStart = (start) => {
|
|
5125
|
-
updateItem(start);
|
|
5126
|
-
};
|
|
5127
|
-
const dragUpdate = (update) => {
|
|
5128
|
-
updateItem(update);
|
|
5129
|
-
};
|
|
5130
|
-
const dragEnd = (dropResult) => {
|
|
5131
|
-
setDraggingOnCanvas(false);
|
|
5132
|
-
setOnBeforeCaptureId('');
|
|
5133
|
-
updateItem();
|
|
5134
|
-
SimulateDnD$1.reset();
|
|
5135
|
-
// If the component is being dropped onto itself, do nothing
|
|
5136
|
-
// This can happen from an apparent race condition where the hovering zone gets set
|
|
5137
|
-
// to the component after its dropped.
|
|
5138
|
-
if (dropResult.destination?.droppableId === dropResult.draggableId) {
|
|
5139
|
-
return;
|
|
5140
|
-
}
|
|
5141
|
-
if (!dropResult.destination) {
|
|
5142
|
-
if (!draggedItem?.destination) {
|
|
5143
|
-
// User cancel drag
|
|
5144
|
-
sendMessage(OUTGOING_EVENTS.ComponentDragCanceled, undefined);
|
|
5145
|
-
//select the previously selected node if drag was canceled
|
|
5146
|
-
if (prevSelectedNodeId.current) {
|
|
5147
|
-
setSelectedNodeId(prevSelectedNodeId.current);
|
|
5148
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5149
|
-
nodeId: prevSelectedNodeId.current,
|
|
5150
|
-
});
|
|
5151
|
-
prevSelectedNodeId.current = null;
|
|
5152
|
-
}
|
|
5153
|
-
return;
|
|
5154
|
-
}
|
|
5155
|
-
// Use the destination from the draggedItem (when clicking the canvas)
|
|
5156
|
-
dropResult.destination = draggedItem.destination;
|
|
5157
|
-
}
|
|
5158
|
-
// New component added to canvas
|
|
5159
|
-
if (dropResult.source.droppableId.startsWith('component-list')) {
|
|
5160
|
-
onAddComponent(dropResult);
|
|
5161
|
-
}
|
|
5162
|
-
else {
|
|
5163
|
-
onMoveComponent(dropResult);
|
|
5164
|
-
}
|
|
5165
|
-
// If a node was previously selected prior to dragging, re-select it
|
|
5166
|
-
setSelectedNodeId(dropResult.draggableId);
|
|
5167
|
-
sendMessage(OUTGOING_EVENTS.ComponentMoveEnded, undefined);
|
|
5168
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
5169
|
-
nodeId: dropResult.draggableId,
|
|
5170
|
-
});
|
|
5171
|
-
};
|
|
5172
|
-
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)));
|
|
5173
|
-
};
|
|
5174
|
-
|
|
5175
|
-
/**
|
|
5176
|
-
* This hook gets the element co-ordinates of a specified element in the DOM
|
|
5177
|
-
* and sends the DOM Rect to the client app
|
|
5178
|
-
*/
|
|
5179
|
-
const useSelectedInstanceCoordinates = ({ node }) => {
|
|
5180
|
-
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
5181
|
-
useEffect(() => {
|
|
5182
|
-
if (selectedNodeId !== node.data.id) {
|
|
5183
|
-
return;
|
|
4492
|
+
if (!registration) {
|
|
4493
|
+
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.`);
|
|
4494
|
+
return undefined;
|
|
5184
4495
|
}
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
setTimeout(() => {
|
|
5188
|
-
sendSelectedComponentCoordinates(node.data.id);
|
|
5189
|
-
}, 10);
|
|
5190
|
-
}, [node, selectedNodeId]);
|
|
5191
|
-
const selectedElement = node.data.id
|
|
5192
|
-
? document.querySelector(`[data-cf-node-id="${selectedNodeId}"]`)
|
|
5193
|
-
: undefined;
|
|
5194
|
-
return selectedElement ? getElementCoordinates(selectedElement) : null;
|
|
4496
|
+
return registration;
|
|
4497
|
+
}, [node]);
|
|
5195
4498
|
};
|
|
5196
4499
|
|
|
5197
4500
|
/**
|
|
@@ -5266,20 +4569,17 @@ const maybeMergePatternDefaultDesignValues = ({ variableName, variableMapping, n
|
|
|
5266
4569
|
parentPatternNode = findNodeById(parentPatternNode.data.pattern?.nodeId);
|
|
5267
4570
|
}
|
|
5268
4571
|
const mergedDesignValue = mergeDesignValuesByBreakpoint(exposedDefaultValue, variableMapping);
|
|
5269
|
-
return mergedDesignValue
|
|
4572
|
+
return mergedDesignValue?.valuesByBreakpoint;
|
|
5270
4573
|
}
|
|
5271
4574
|
return variableMapping.valuesByBreakpoint;
|
|
5272
4575
|
};
|
|
5273
4576
|
|
|
5274
|
-
const useComponentProps = ({ node, entityStore, areEntitiesFetched, resolveDesignValue,
|
|
4577
|
+
const useComponentProps = ({ node, entityStore, areEntitiesFetched, resolveDesignValue, definition, options, }) => {
|
|
5275
4578
|
const unboundValues = useEditorStore((state) => state.unboundValues);
|
|
5276
4579
|
const hyperlinkPattern = useEditorStore((state) => state.hyperLinkPattern);
|
|
5277
4580
|
const locale = useEditorStore((state) => state.locale);
|
|
5278
4581
|
const dataSource = useEditorStore((state) => state.dataSource);
|
|
5279
|
-
const draggingId = useDraggedItemStore((state) => state.onBeforeCaptureId);
|
|
5280
|
-
const nodeRect = useDraggedItemStore((state) => state.domRect);
|
|
5281
4582
|
const findNodeById = useTreeStore((state) => state.findNodeById);
|
|
5282
|
-
const isEmptyZone = !node.children.length;
|
|
5283
4583
|
const props = useMemo(() => {
|
|
5284
4584
|
const propsBase = {
|
|
5285
4585
|
cfSsrClassName: node.data.props.cfSsrClassName
|
|
@@ -5375,18 +4675,9 @@ const useComponentProps = ({ node, entityStore, areEntitiesFetched, resolveDesig
|
|
|
5375
4675
|
return { ...acc };
|
|
5376
4676
|
}
|
|
5377
4677
|
}, {});
|
|
5378
|
-
const slotProps = {};
|
|
5379
|
-
if (definition.slots) {
|
|
5380
|
-
for (const slotId in definition.slots) {
|
|
5381
|
-
slotProps[slotId] = renderDropzone(node, {
|
|
5382
|
-
zoneId: [node.data.id, slotId].join('|'),
|
|
5383
|
-
});
|
|
5384
|
-
}
|
|
5385
|
-
}
|
|
5386
4678
|
return {
|
|
5387
4679
|
...propsBase,
|
|
5388
4680
|
...extractedProps,
|
|
5389
|
-
...slotProps,
|
|
5390
4681
|
};
|
|
5391
4682
|
}, [
|
|
5392
4683
|
hyperlinkPattern,
|
|
@@ -5398,1120 +4689,224 @@ const useComponentProps = ({ node, entityStore, areEntitiesFetched, resolveDesig
|
|
|
5398
4689
|
areEntitiesFetched,
|
|
5399
4690
|
unboundValues,
|
|
5400
4691
|
entityStore,
|
|
5401
|
-
renderDropzone,
|
|
5402
4692
|
findNodeById,
|
|
5403
4693
|
]);
|
|
5404
|
-
const cfStyles = useMemo(() => (
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
// Move size styles to the wrapping div and override the component styles
|
|
5416
|
-
const overrideStyles = {};
|
|
5417
|
-
const wrapperStyles = { width: options?.wrapContainerWidth };
|
|
5418
|
-
if (requiresDragWrapper) {
|
|
5419
|
-
// when element is marked by user as not-visible, on that element the node `display: none !important`
|
|
5420
|
-
// will be set and it will disappear. However, when such a node has a wrapper div, the wrapper
|
|
5421
|
-
// should not have any css properties (at least not ones which force size), as such div should
|
|
5422
|
-
// simply be a zero height wrapper around element with `display: none !important`.
|
|
5423
|
-
// Hence we guard all wrapperStyles with `cfVisibility` check.
|
|
5424
|
-
if (cfVisibility && cfStyles.width)
|
|
5425
|
-
wrapperStyles.width = cfStyles.width;
|
|
5426
|
-
if (cfVisibility && cfStyles.height)
|
|
5427
|
-
wrapperStyles.height = cfStyles.height;
|
|
5428
|
-
if (cfVisibility && cfStyles.maxWidth)
|
|
5429
|
-
wrapperStyles.maxWidth = cfStyles.maxWidth;
|
|
5430
|
-
if (cfVisibility && cfStyles.margin)
|
|
5431
|
-
wrapperStyles.margin = cfStyles.margin;
|
|
5432
|
-
}
|
|
5433
|
-
// Override component styles to fill the wrapper
|
|
5434
|
-
if (wrapperStyles.width)
|
|
5435
|
-
overrideStyles.width = '100%';
|
|
5436
|
-
if (wrapperStyles.height)
|
|
5437
|
-
overrideStyles.height = '100%';
|
|
5438
|
-
if (wrapperStyles.margin)
|
|
5439
|
-
overrideStyles.margin = '0';
|
|
5440
|
-
if (wrapperStyles.maxWidth)
|
|
5441
|
-
overrideStyles.maxWidth = 'none';
|
|
5442
|
-
// Prevent the dragging element from changing sizes when it has a percentage width or height
|
|
5443
|
-
if (draggingId === node.data.id && nodeRect) {
|
|
5444
|
-
if (requiresDragWrapper) {
|
|
5445
|
-
if (isPercentValue(cfStyles.width))
|
|
5446
|
-
wrapperStyles.maxWidth = nodeRect.width;
|
|
5447
|
-
if (isPercentValue(cfStyles.height))
|
|
5448
|
-
wrapperStyles.maxHeight = nodeRect.height;
|
|
5449
|
-
}
|
|
5450
|
-
else {
|
|
5451
|
-
if (isPercentValue(cfStyles.width))
|
|
5452
|
-
overrideStyles.maxWidth = nodeRect.width;
|
|
5453
|
-
if (isPercentValue(cfStyles.height))
|
|
5454
|
-
overrideStyles.maxHeight = nodeRect.height;
|
|
5455
|
-
}
|
|
5456
|
-
}
|
|
5457
|
-
return { overrideStyles, wrapperStyles };
|
|
5458
|
-
}, [
|
|
5459
|
-
cfStyles,
|
|
5460
|
-
options?.wrapContainerWidth,
|
|
5461
|
-
requiresDragWrapper,
|
|
5462
|
-
node.data.id,
|
|
5463
|
-
draggingId,
|
|
5464
|
-
nodeRect,
|
|
5465
|
-
cfVisibility,
|
|
5466
|
-
]);
|
|
4694
|
+
const cfStyles = useMemo(() => buildCfStyles(props), [props]);
|
|
4695
|
+
const shouldRenderEmptySpaceWithMinSize = useMemo(() => {
|
|
4696
|
+
if (node.children.length)
|
|
4697
|
+
return false;
|
|
4698
|
+
// Render with minimum height and with in those two scenarios:
|
|
4699
|
+
if (isStructureWithRelativeHeight(node.data.blockId, cfStyles.height))
|
|
4700
|
+
return true;
|
|
4701
|
+
if (definition?.children)
|
|
4702
|
+
return true;
|
|
4703
|
+
return false;
|
|
4704
|
+
}, [cfStyles.height, definition?.children, node.children.length, node.data.blockId]);
|
|
5467
4705
|
// Styles that will be applied to the component element
|
|
5468
|
-
// This has to be memoized to avoid recreating the styles in useEditorModeClassName on every render
|
|
5469
4706
|
const componentStyles = useMemo(() => ({
|
|
5470
4707
|
...cfStyles,
|
|
5471
|
-
...
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
minHeight: EMPTY_CONTAINER_HEIGHT,
|
|
4708
|
+
...(shouldRenderEmptySpaceWithMinSize && {
|
|
4709
|
+
minHeight: EMPTY_CONTAINER_SIZE,
|
|
4710
|
+
minWidth: EMPTY_CONTAINER_SIZE,
|
|
5475
4711
|
}),
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
!isSingleColumn &&
|
|
5479
|
-
!isAssemblyBlock && {
|
|
5480
|
-
padding: addExtraDropzonePadding(cfStyles.padding?.toString() || '0 0 0 0'),
|
|
5481
|
-
}),
|
|
5482
|
-
}), [
|
|
5483
|
-
cfStyles,
|
|
5484
|
-
isAssemblyBlock,
|
|
5485
|
-
isEmptyZone,
|
|
5486
|
-
isSingleColumn,
|
|
5487
|
-
isStructureComponent,
|
|
5488
|
-
node?.data.blockId,
|
|
5489
|
-
overrideStyles,
|
|
5490
|
-
userIsDragging,
|
|
5491
|
-
]);
|
|
5492
|
-
const componentClass = useEditorModeClassName({
|
|
4712
|
+
}), [cfStyles, shouldRenderEmptySpaceWithMinSize]);
|
|
4713
|
+
const cfCsrClassName = useEditorModeClassName({
|
|
5493
4714
|
styles: componentStyles,
|
|
5494
4715
|
nodeId: node.data.id,
|
|
5495
4716
|
});
|
|
5496
|
-
const
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
};
|
|
5503
|
-
const customComponentProps = {
|
|
5504
|
-
...sharedProps,
|
|
5505
|
-
// Allows custom components to render differently in the editor. This needs to be activated
|
|
5506
|
-
// through options as the component has to be aware of this prop to not cause any React warnings.
|
|
5507
|
-
...(options?.enableCustomEditorView ? { isInExpEditorMode: true } : {}),
|
|
5508
|
-
...sanitizeNodeProps(props),
|
|
5509
|
-
};
|
|
5510
|
-
const structuralOrPatternComponentProps = {
|
|
5511
|
-
...sharedProps,
|
|
5512
|
-
editorMode: true,
|
|
5513
|
-
node,
|
|
5514
|
-
renderDropzone,
|
|
5515
|
-
};
|
|
5516
|
-
return {
|
|
5517
|
-
componentProps: isStructureComponent || isPatternNode
|
|
5518
|
-
? structuralOrPatternComponentProps
|
|
5519
|
-
: customComponentProps,
|
|
5520
|
-
componentStyles,
|
|
5521
|
-
wrapperStyles,
|
|
5522
|
-
};
|
|
5523
|
-
};
|
|
5524
|
-
const addExtraDropzonePadding = (padding) => padding
|
|
5525
|
-
.split(' ')
|
|
5526
|
-
.map((value) => parseFloat(value) === 0 ? `${DRAG_PADDING}px` : `calc(${value} + ${DRAG_PADDING}px)`)
|
|
5527
|
-
.join(' ');
|
|
5528
|
-
const isPercentValue = (value) => typeof value === 'string' && value.endsWith('%');
|
|
5529
|
-
|
|
5530
|
-
class ImportedComponentError extends Error {
|
|
5531
|
-
constructor(message) {
|
|
5532
|
-
super(message);
|
|
5533
|
-
this.name = 'ImportedComponentError';
|
|
5534
|
-
}
|
|
5535
|
-
}
|
|
5536
|
-
class ExperienceSDKError extends Error {
|
|
5537
|
-
constructor(message) {
|
|
5538
|
-
super(message);
|
|
5539
|
-
this.name = 'ExperienceSDKError';
|
|
5540
|
-
}
|
|
5541
|
-
}
|
|
5542
|
-
class ImportedComponentErrorBoundary extends React.Component {
|
|
5543
|
-
componentDidCatch(error, _errorInfo) {
|
|
5544
|
-
if (error.name === 'ImportedComponentError' || error.name === 'ExperienceSDKError') {
|
|
5545
|
-
// This error was already handled by a nested error boundary and should be passed upwards
|
|
5546
|
-
// We have to do this as we wrap every component on every layer with this error boundary and
|
|
5547
|
-
// thus an error deep in the tree bubbles through many layers of error boundaries.
|
|
5548
|
-
throw error;
|
|
5549
|
-
}
|
|
5550
|
-
// Differentiate between custom and SDK-provided components for error tracking
|
|
5551
|
-
const ErrorClass = isContentfulComponent(this.props.componentId)
|
|
5552
|
-
? ExperienceSDKError
|
|
5553
|
-
: ImportedComponentError;
|
|
5554
|
-
const err = new ErrorClass(error.message);
|
|
5555
|
-
err.stack = error.stack;
|
|
5556
|
-
throw err;
|
|
5557
|
-
}
|
|
5558
|
-
render() {
|
|
5559
|
-
return this.props.children;
|
|
5560
|
-
}
|
|
5561
|
-
}
|
|
5562
|
-
|
|
5563
|
-
const MissingComponentPlaceholder = ({ blockId }) => {
|
|
5564
|
-
return (React.createElement("div", { style: {
|
|
5565
|
-
border: '1px solid red',
|
|
5566
|
-
width: '100%',
|
|
5567
|
-
height: '100%',
|
|
5568
|
-
} },
|
|
5569
|
-
"Missing component '",
|
|
5570
|
-
blockId,
|
|
5571
|
-
"'"));
|
|
5572
|
-
};
|
|
5573
|
-
|
|
5574
|
-
const CircularDependencyErrorPlaceholder = forwardRef(({ wrappingPatternIds, ...props }, ref) => {
|
|
5575
|
-
return (React.createElement("div", { ...props,
|
|
5576
|
-
// Pass through ref to avoid DND errors being logged
|
|
5577
|
-
ref: ref, "data-cf-node-error": "circular-pattern-dependency", style: {
|
|
5578
|
-
border: '1px solid red',
|
|
5579
|
-
background: 'rgba(255, 0, 0, 0.1)',
|
|
5580
|
-
padding: '1rem 1rem 0 1rem',
|
|
5581
|
-
width: '100%',
|
|
5582
|
-
height: '100%',
|
|
5583
|
-
} },
|
|
5584
|
-
"Circular usage of patterns detected:",
|
|
5585
|
-
React.createElement("ul", null, Array.from(wrappingPatternIds).map((patternId) => {
|
|
5586
|
-
const entryLink = { sys: { type: 'Link', linkType: 'Entry', id: patternId } };
|
|
5587
|
-
const entry = inMemoryEntities.maybeResolveLink(entryLink);
|
|
5588
|
-
const entryTitle = entry?.fields?.title;
|
|
5589
|
-
const text = entryTitle ? `${entryTitle} (${patternId})` : patternId;
|
|
5590
|
-
return React.createElement("li", { key: patternId }, text);
|
|
5591
|
-
}))));
|
|
5592
|
-
});
|
|
5593
|
-
CircularDependencyErrorPlaceholder.displayName = 'CircularDependencyErrorPlaceholder';
|
|
5594
|
-
|
|
5595
|
-
const useComponent = ({ node, entityStore, areEntitiesFetched, resolveDesignValue, renderDropzone, userIsDragging, wrappingPatternIds, }) => {
|
|
5596
|
-
const tree = useTreeStore((state) => state.tree);
|
|
5597
|
-
const componentRegistration = useMemo(() => {
|
|
5598
|
-
let registration = componentRegistry.get(node.data.blockId);
|
|
5599
|
-
if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
|
|
5600
|
-
registration = createAssemblyRegistration({
|
|
5601
|
-
definitionId: node.data.blockId,
|
|
5602
|
-
component: Assembly,
|
|
5603
|
-
});
|
|
5604
|
-
}
|
|
5605
|
-
if (!registration) {
|
|
5606
|
-
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.`);
|
|
5607
|
-
return undefined;
|
|
5608
|
-
}
|
|
5609
|
-
return registration;
|
|
5610
|
-
}, [node]);
|
|
5611
|
-
const componentId = node.data.id;
|
|
5612
|
-
const isPatternNode = node.type === ASSEMBLY_NODE_TYPE;
|
|
5613
|
-
const isPatternComponent = node.type === ASSEMBLY_BLOCK_NODE_TYPE;
|
|
5614
|
-
const parentComponentNode = getItem({ id: node.parentId }, tree);
|
|
5615
|
-
const isNestedPattern = isPatternNode &&
|
|
5616
|
-
[ASSEMBLY_BLOCK_NODE_TYPE, ASSEMBLY_NODE_TYPE].includes(parentComponentNode?.type ?? '');
|
|
5617
|
-
const isStructureComponent = isContentfulStructureComponent(node.data.blockId);
|
|
5618
|
-
const requiresDragWrapper = !isPatternNode && !isStructureComponent && !componentRegistration?.options?.wrapComponent;
|
|
5619
|
-
const { componentProps, wrapperStyles } = useComponentProps({
|
|
5620
|
-
node,
|
|
5621
|
-
entityStore,
|
|
5622
|
-
areEntitiesFetched,
|
|
5623
|
-
resolveDesignValue,
|
|
5624
|
-
renderDropzone,
|
|
5625
|
-
definition: componentRegistration?.definition,
|
|
5626
|
-
options: componentRegistration?.options,
|
|
5627
|
-
userIsDragging,
|
|
5628
|
-
requiresDragWrapper,
|
|
5629
|
-
});
|
|
5630
|
-
const elementToRender = (props) => {
|
|
5631
|
-
const { dragProps = {} } = props || {};
|
|
5632
|
-
const { children, innerRef, Tag = 'div', ToolTipAndPlaceholder, style, ...rest } = dragProps;
|
|
5633
|
-
const { 'data-cf-node-block-id': dataCfNodeBlockId, 'data-cf-node-block-type': dataCfNodeBlockType, 'data-cf-node-id': dataCfNodeId, } = componentProps;
|
|
5634
|
-
const refCallback = (refNode) => {
|
|
5635
|
-
if (innerRef && refNode)
|
|
5636
|
-
innerRef(refNode);
|
|
4717
|
+
const componentProps = useMemo(() => {
|
|
4718
|
+
const sharedProps = {
|
|
4719
|
+
'data-cf-node-id': node.data.id,
|
|
4720
|
+
'data-cf-node-block-id': node.data.blockId,
|
|
4721
|
+
'data-cf-node-block-type': node.type,
|
|
4722
|
+
className: props.cfSsrClassName ?? cfCsrClassName,
|
|
5637
4723
|
};
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
if (node.data.blockId && wrappingPatternIds.has(node.data.blockId)) {
|
|
5642
|
-
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 }));
|
|
5643
|
-
}
|
|
5644
|
-
const element = React.createElement(ImportedComponentErrorBoundary, { componentId: node.data.blockId }, React.createElement(componentRegistration.component, {
|
|
5645
|
-
...componentProps,
|
|
5646
|
-
dragProps,
|
|
5647
|
-
}));
|
|
5648
|
-
if (!requiresDragWrapper) {
|
|
5649
|
-
return element;
|
|
5650
|
-
}
|
|
5651
|
-
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 },
|
|
5652
|
-
ToolTipAndPlaceholder,
|
|
5653
|
-
element));
|
|
5654
|
-
};
|
|
5655
|
-
return {
|
|
5656
|
-
node,
|
|
5657
|
-
parentComponentNode,
|
|
5658
|
-
isAssembly: isPatternNode,
|
|
5659
|
-
isPatternNode,
|
|
5660
|
-
isPatternComponent,
|
|
5661
|
-
isNestedPattern,
|
|
5662
|
-
componentId,
|
|
5663
|
-
elementToRender,
|
|
5664
|
-
definition: componentRegistration?.definition,
|
|
5665
|
-
};
|
|
5666
|
-
};
|
|
5667
|
-
|
|
5668
|
-
const calcOffsetLeft = (parentElement, placeholderWidth, nodeWidth) => {
|
|
5669
|
-
if (!parentElement) {
|
|
5670
|
-
return 0;
|
|
5671
|
-
}
|
|
5672
|
-
const alignItems = window.getComputedStyle(parentElement).alignItems;
|
|
5673
|
-
if (alignItems === 'center') {
|
|
5674
|
-
return -(placeholderWidth - nodeWidth) / 2;
|
|
5675
|
-
}
|
|
5676
|
-
if (alignItems === 'end') {
|
|
5677
|
-
return -placeholderWidth + nodeWidth + 2;
|
|
5678
|
-
}
|
|
5679
|
-
return 0;
|
|
5680
|
-
};
|
|
5681
|
-
const calcOffsetTop = (parentElement, placeholderHeight, nodeHeight) => {
|
|
5682
|
-
if (!parentElement) {
|
|
5683
|
-
return 0;
|
|
5684
|
-
}
|
|
5685
|
-
const alignItems = window.getComputedStyle(parentElement).alignItems;
|
|
5686
|
-
if (alignItems === 'center') {
|
|
5687
|
-
return -(placeholderHeight - nodeHeight) / 2;
|
|
5688
|
-
}
|
|
5689
|
-
if (alignItems === 'end') {
|
|
5690
|
-
return -placeholderHeight + nodeHeight + 2;
|
|
5691
|
-
}
|
|
5692
|
-
return 0;
|
|
5693
|
-
};
|
|
5694
|
-
const getPaddingOffset = (element) => {
|
|
5695
|
-
const paddingLeft = parseFloat(window.getComputedStyle(element).paddingLeft);
|
|
5696
|
-
const paddingRight = parseFloat(window.getComputedStyle(element).paddingRight);
|
|
5697
|
-
const paddingTop = parseFloat(window.getComputedStyle(element).paddingTop);
|
|
5698
|
-
const paddingBottom = parseFloat(window.getComputedStyle(element).paddingBottom);
|
|
5699
|
-
const horizontalOffset = paddingLeft + paddingRight;
|
|
5700
|
-
const verticalOffset = paddingTop + paddingBottom;
|
|
5701
|
-
return [horizontalOffset, verticalOffset];
|
|
5702
|
-
};
|
|
5703
|
-
/**
|
|
5704
|
-
* Calculate the size and position of the dropzone indicator
|
|
5705
|
-
* when dragging a new component onto the canvas
|
|
5706
|
-
*/
|
|
5707
|
-
const calcNewComponentStyles = (params) => {
|
|
5708
|
-
const { destinationIndex, elementIndex, dropzoneElementId, id, direction, totalIndexes } = params;
|
|
5709
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5710
|
-
const isHorizontal = direction === 'horizontal';
|
|
5711
|
-
const isRightAlign = isHorizontal && isEnd;
|
|
5712
|
-
const isBottomAlign = !isHorizontal && isEnd;
|
|
5713
|
-
const dropzone = document.querySelector(`[data-rfd-droppable-id="${dropzoneElementId}"]`);
|
|
5714
|
-
const element = document.querySelector(`[data-ctfl-draggable-id="${id}"]`);
|
|
5715
|
-
if (!dropzone || !element) {
|
|
5716
|
-
return emptyStyles;
|
|
5717
|
-
}
|
|
5718
|
-
const elementSizes = element.getBoundingClientRect();
|
|
5719
|
-
const dropzoneSizes = dropzone.getBoundingClientRect();
|
|
5720
|
-
const [horizontalPadding, verticalPadding] = getPaddingOffset(dropzone);
|
|
5721
|
-
const width = isHorizontal ? DRAGGABLE_WIDTH : dropzoneSizes.width - horizontalPadding;
|
|
5722
|
-
const height = isHorizontal ? dropzoneSizes.height - verticalPadding : DRAGGABLE_HEIGHT;
|
|
5723
|
-
const top = isHorizontal
|
|
5724
|
-
? calcOffsetTop(element.parentElement, height, elementSizes.height)
|
|
5725
|
-
: -height;
|
|
5726
|
-
const left = isHorizontal
|
|
5727
|
-
? -width
|
|
5728
|
-
: calcOffsetLeft(element.parentElement, width, elementSizes.width);
|
|
5729
|
-
return {
|
|
5730
|
-
width,
|
|
5731
|
-
height,
|
|
5732
|
-
top: !isBottomAlign ? top : 'unset',
|
|
5733
|
-
right: isRightAlign ? -width : 'unset',
|
|
5734
|
-
bottom: isBottomAlign ? -height : 'unset',
|
|
5735
|
-
left: !isRightAlign ? left : 'unset',
|
|
5736
|
-
};
|
|
5737
|
-
};
|
|
5738
|
-
/**
|
|
5739
|
-
* Calculate the size and position of the dropzone indicator
|
|
5740
|
-
* when moving an existing component on the canvas
|
|
5741
|
-
*/
|
|
5742
|
-
const calcMovementStyles = (params) => {
|
|
5743
|
-
const { destinationIndex, sourceIndex, destinationId, sourceId, elementIndex, dropzoneElementId, id, direction, totalIndexes, draggableId, } = params;
|
|
5744
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5745
|
-
const isHorizontal = direction === 'horizontal';
|
|
5746
|
-
const isSameZone = destinationId === sourceId;
|
|
5747
|
-
const isBelowSourceIndex = destinationIndex > sourceIndex;
|
|
5748
|
-
const isRightAlign = isHorizontal && (isEnd || (isSameZone && isBelowSourceIndex));
|
|
5749
|
-
const isBottomAlign = !isHorizontal && (isEnd || (isSameZone && isBelowSourceIndex));
|
|
5750
|
-
const dropzone = document.querySelector(`[data-rfd-droppable-id="${dropzoneElementId}"]`);
|
|
5751
|
-
const draggable = document.querySelector(`[data-rfd-draggable-id="${draggableId}"]`);
|
|
5752
|
-
const element = document.querySelector(`[data-ctfl-draggable-id="${id}"]`);
|
|
5753
|
-
if (!dropzone || !element || !draggable) {
|
|
5754
|
-
return emptyStyles;
|
|
5755
|
-
}
|
|
5756
|
-
const elementSizes = element.getBoundingClientRect();
|
|
5757
|
-
const dropzoneSizes = dropzone.getBoundingClientRect();
|
|
5758
|
-
const draggableSizes = draggable.getBoundingClientRect();
|
|
5759
|
-
const [horizontalPadding, verticalPadding] = getPaddingOffset(dropzone);
|
|
5760
|
-
const width = isHorizontal ? draggableSizes.width : dropzoneSizes.width - horizontalPadding;
|
|
5761
|
-
const height = isHorizontal ? dropzoneSizes.height - verticalPadding : draggableSizes.height;
|
|
5762
|
-
const top = isHorizontal
|
|
5763
|
-
? calcOffsetTop(element.parentElement, height, elementSizes.height)
|
|
5764
|
-
: -height;
|
|
5765
|
-
const left = isHorizontal
|
|
5766
|
-
? -width
|
|
5767
|
-
: calcOffsetLeft(element.parentElement, width, elementSizes.width);
|
|
5768
|
-
return {
|
|
5769
|
-
width,
|
|
5770
|
-
height,
|
|
5771
|
-
top: !isBottomAlign ? top : 'unset',
|
|
5772
|
-
right: isRightAlign ? -width : 'unset',
|
|
5773
|
-
bottom: isBottomAlign ? -height : 'unset',
|
|
5774
|
-
left: !isRightAlign ? left : 'unset',
|
|
5775
|
-
};
|
|
5776
|
-
};
|
|
5777
|
-
const emptyStyles = { width: 0, height: 0 };
|
|
5778
|
-
const calcPlaceholderStyles = (params) => {
|
|
5779
|
-
const { isDraggingOver, sourceId } = params;
|
|
5780
|
-
if (!isDraggingOver) {
|
|
5781
|
-
return emptyStyles;
|
|
5782
|
-
}
|
|
5783
|
-
if (sourceId === COMPONENT_LIST_ID) {
|
|
5784
|
-
return calcNewComponentStyles(params);
|
|
5785
|
-
}
|
|
5786
|
-
return calcMovementStyles(params);
|
|
5787
|
-
};
|
|
5788
|
-
const Placeholder = (props) => {
|
|
5789
|
-
const sourceIndex = useDraggedItemStore((state) => state.draggedItem?.source.index) ?? -1;
|
|
5790
|
-
const draggableId = useDraggedItemStore((state) => state.draggedItem?.draggableId) ?? '';
|
|
5791
|
-
const sourceId = useDraggedItemStore((state) => state.draggedItem?.source.droppableId) ?? '';
|
|
5792
|
-
const destinationIndex = useDraggedItemStore((state) => state.draggedItem?.destination?.index) ?? -1;
|
|
5793
|
-
const destinationId = useDraggedItemStore((state) => state.draggedItem?.destination?.droppableId) ?? '';
|
|
5794
|
-
const { elementIndex, totalIndexes, isDraggingOver } = props;
|
|
5795
|
-
const isActive = destinationIndex === elementIndex;
|
|
5796
|
-
const isEnd = destinationIndex === totalIndexes && elementIndex === totalIndexes - 1;
|
|
5797
|
-
const isVisible = isEnd || isActive;
|
|
5798
|
-
const isComponentList = destinationId === COMPONENT_LIST_ID;
|
|
5799
|
-
return (!isComponentList &&
|
|
5800
|
-
isDraggingOver &&
|
|
5801
|
-
isVisible && (React.createElement("div", { style: {
|
|
5802
|
-
...calcPlaceholderStyles({
|
|
5803
|
-
...props,
|
|
5804
|
-
sourceId,
|
|
5805
|
-
sourceIndex,
|
|
5806
|
-
destinationId,
|
|
5807
|
-
destinationIndex,
|
|
5808
|
-
draggableId,
|
|
5809
|
-
}),
|
|
5810
|
-
backgroundColor: 'rgba(var(--exp-builder-blue300-rgb), 0.5)',
|
|
5811
|
-
position: 'absolute',
|
|
5812
|
-
pointerEvents: 'none',
|
|
5813
|
-
} })));
|
|
5814
|
-
};
|
|
5815
|
-
|
|
5816
|
-
var css_248z$2 = ".styles-module_hitbox__i3wKV {\n position: fixed;\n pointer-events: all;\n}\n";
|
|
5817
|
-
var styles$2 = {"hitbox":"styles-module_hitbox__i3wKV"};
|
|
5818
|
-
styleInject(css_248z$2);
|
|
5819
|
-
|
|
5820
|
-
const useZoneStore = create()((set) => ({
|
|
5821
|
-
zones: {},
|
|
5822
|
-
hoveringZone: '',
|
|
5823
|
-
setHoveringZone(zoneId) {
|
|
5824
|
-
set({
|
|
5825
|
-
hoveringZone: zoneId,
|
|
5826
|
-
});
|
|
5827
|
-
},
|
|
5828
|
-
upsertZone(id, data) {
|
|
5829
|
-
set(produce((state) => {
|
|
5830
|
-
state.zones[id] = { ...(state.zones[id] || {}), ...data };
|
|
5831
|
-
}));
|
|
5832
|
-
},
|
|
5833
|
-
}));
|
|
5834
|
-
|
|
5835
|
-
const { WIDTH, HEIGHT, INITIAL_OFFSET, OFFSET_INCREMENT, MIN_HEIGHT, MIN_DEPTH_HEIGHT, DEEP_ZONE } = HITBOX;
|
|
5836
|
-
const calcOffsetDepth = (depth) => {
|
|
5837
|
-
return INITIAL_OFFSET - OFFSET_INCREMENT * depth;
|
|
5838
|
-
};
|
|
5839
|
-
const getHitboxStyles = ({ direction, zoneDepth, domRect, scrollY, offsetRect, }) => {
|
|
5840
|
-
if (!domRect) {
|
|
5841
|
-
return {
|
|
5842
|
-
display: 'none',
|
|
5843
|
-
};
|
|
5844
|
-
}
|
|
5845
|
-
const { width, height, top, left, bottom, right } = domRect;
|
|
5846
|
-
const { height: offsetHeight, width: offsetWidth } = offsetRect || { height: 0, width: 0 };
|
|
5847
|
-
const MAX_SELF_HEIGHT = DRAGGABLE_HEIGHT * 2;
|
|
5848
|
-
const isDeepZone = zoneDepth > DEEP_ZONE;
|
|
5849
|
-
const isAboveMaxHeight = height > MAX_SELF_HEIGHT;
|
|
5850
|
-
switch (direction) {
|
|
5851
|
-
case HitboxDirection.TOP:
|
|
5852
|
-
return {
|
|
5853
|
-
width,
|
|
5854
|
-
height: HEIGHT,
|
|
5855
|
-
top: top + offsetHeight - calcOffsetDepth(zoneDepth) - scrollY,
|
|
5856
|
-
left,
|
|
5857
|
-
zIndex: 100 + zoneDepth,
|
|
5858
|
-
};
|
|
5859
|
-
case HitboxDirection.BOTTOM:
|
|
4724
|
+
// Only pass `editorMode` and `node` to structure components and assembly root nodes.
|
|
4725
|
+
const isStructureComponent = isContentfulStructureComponent(node.data.blockId);
|
|
4726
|
+
if (isStructureComponent) {
|
|
5860
4727
|
return {
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
left,
|
|
5865
|
-
zIndex: 100 + zoneDepth,
|
|
5866
|
-
};
|
|
5867
|
-
case HitboxDirection.LEFT:
|
|
5868
|
-
return {
|
|
5869
|
-
width: WIDTH,
|
|
5870
|
-
height: height - HEIGHT,
|
|
5871
|
-
left: left + offsetWidth - calcOffsetDepth(zoneDepth) - WIDTH / 2,
|
|
5872
|
-
top: top + HEIGHT / 2 - scrollY,
|
|
5873
|
-
zIndex: 100 + zoneDepth,
|
|
5874
|
-
};
|
|
5875
|
-
case HitboxDirection.RIGHT:
|
|
5876
|
-
return {
|
|
5877
|
-
width: WIDTH,
|
|
5878
|
-
height: height - HEIGHT,
|
|
5879
|
-
left: right + offsetWidth + calcOffsetDepth(zoneDepth) - WIDTH / 2,
|
|
5880
|
-
top: top + HEIGHT / 2 - scrollY,
|
|
5881
|
-
zIndex: 100 + zoneDepth,
|
|
5882
|
-
};
|
|
5883
|
-
case HitboxDirection.SELF_VERTICAL: {
|
|
5884
|
-
if (isAboveMaxHeight && !isDeepZone) {
|
|
5885
|
-
return { display: 'none' };
|
|
5886
|
-
}
|
|
5887
|
-
const selfHeight = isDeepZone ? MIN_DEPTH_HEIGHT : MIN_HEIGHT;
|
|
5888
|
-
return {
|
|
5889
|
-
width,
|
|
5890
|
-
height: selfHeight,
|
|
5891
|
-
left,
|
|
5892
|
-
top: top + height / 2 - selfHeight / 2 - scrollY,
|
|
5893
|
-
zIndex: 1000 + zoneDepth,
|
|
4728
|
+
...sharedProps,
|
|
4729
|
+
editorMode: true,
|
|
4730
|
+
node,
|
|
5894
4731
|
};
|
|
5895
4732
|
}
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
zIndex: 1000 + zoneDepth,
|
|
5906
|
-
};
|
|
5907
|
-
}
|
|
5908
|
-
default:
|
|
5909
|
-
return {};
|
|
5910
|
-
}
|
|
5911
|
-
};
|
|
5912
|
-
|
|
5913
|
-
const Hitboxes = ({ zoneId, parentZoneId, isEmptyZone }) => {
|
|
5914
|
-
const tree = useTreeStore((state) => state.tree);
|
|
5915
|
-
const isDraggingOnCanvas = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5916
|
-
const scrollY = useDraggedItemStore((state) => state.scrollY);
|
|
5917
|
-
const zoneDepth = useMemo(() => getItemDepthFromNode({ id: parentZoneId }, tree.root), [tree, parentZoneId]);
|
|
5918
|
-
const zones = useZoneStore((state) => state.zones);
|
|
5919
|
-
const hoveringZone = useZoneStore((state) => state.hoveringZone);
|
|
5920
|
-
const isHoveringZone = hoveringZone === zoneId;
|
|
5921
|
-
const hitboxContainer = useMemo(() => {
|
|
5922
|
-
return document.querySelector('[data-ctfl-hitboxes]');
|
|
5923
|
-
}, []);
|
|
5924
|
-
const domRect = useMemo(() => {
|
|
5925
|
-
if (!isDraggingOnCanvas)
|
|
5926
|
-
return;
|
|
5927
|
-
return document.querySelector(`[${CTFL_ZONE_ID}="${zoneId}"]`)?.getBoundingClientRect();
|
|
5928
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5929
|
-
}, [zoneId, isDraggingOnCanvas]);
|
|
5930
|
-
// Use the size of the cloned dragging element to offset the position of the hitboxes
|
|
5931
|
-
// So that when dragging causes a dropzone to expand, the hitboxes will be in the correct position
|
|
5932
|
-
const offsetRect = useMemo(() => {
|
|
5933
|
-
if (!isDraggingOnCanvas || isEmptyZone || !isHoveringZone)
|
|
5934
|
-
return;
|
|
5935
|
-
return document.querySelector(`[${CTFL_DRAGGING_ELEMENT}]`)?.getBoundingClientRect();
|
|
5936
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5937
|
-
}, [isEmptyZone, isHoveringZone, isDraggingOnCanvas]);
|
|
5938
|
-
const zoneDirection = zones[parentZoneId]?.direction || 'vertical';
|
|
5939
|
-
const isVertical = zoneDirection === 'vertical';
|
|
5940
|
-
const isRoot = parentZoneId === ROOT_ID;
|
|
5941
|
-
const { slotId: parentSlotId } = parseZoneId(parentZoneId);
|
|
5942
|
-
const getStyles = useCallback((direction) => getHitboxStyles({
|
|
5943
|
-
direction,
|
|
5944
|
-
zoneDepth,
|
|
5945
|
-
domRect,
|
|
5946
|
-
scrollY,
|
|
5947
|
-
offsetRect,
|
|
5948
|
-
}), [zoneDepth, domRect, scrollY, offsetRect]);
|
|
5949
|
-
const renderFinalRootHitbox = () => {
|
|
5950
|
-
if (!isRoot)
|
|
5951
|
-
return null;
|
|
5952
|
-
return (React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(HitboxDirection.BOTTOM) }));
|
|
5953
|
-
};
|
|
5954
|
-
const renderSurroundingHitboxes = () => {
|
|
5955
|
-
if (isRoot || parentSlotId)
|
|
5956
|
-
return null;
|
|
5957
|
-
return (React.createElement(React.Fragment, null,
|
|
5958
|
-
React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.TOP : HitboxDirection.LEFT) }),
|
|
5959
|
-
React.createElement("div", { "data-ctfl-zone-id": parentZoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.BOTTOM : HitboxDirection.RIGHT) })));
|
|
5960
|
-
};
|
|
5961
|
-
const ActiveHitboxes = (React.createElement(React.Fragment, null,
|
|
5962
|
-
React.createElement("div", { "data-ctfl-zone-id": zoneId, className: styles$2.hitbox, style: getStyles(isVertical ? HitboxDirection.SELF_VERTICAL : HitboxDirection.SELF_HORIZONTAL) }),
|
|
5963
|
-
renderSurroundingHitboxes(),
|
|
5964
|
-
renderFinalRootHitbox()));
|
|
5965
|
-
if (!hitboxContainer) {
|
|
5966
|
-
return null;
|
|
5967
|
-
}
|
|
5968
|
-
return createPortal(ActiveHitboxes, hitboxContainer);
|
|
5969
|
-
};
|
|
5970
|
-
|
|
5971
|
-
const isRelativePreviewSize = (width) => {
|
|
5972
|
-
// For now, we solely allow 100% as relative value
|
|
5973
|
-
return width === '100%';
|
|
5974
|
-
};
|
|
5975
|
-
const getTooltipPositions = ({ previewSize, tooltipRect, coordinates, }) => {
|
|
5976
|
-
if (!coordinates || !tooltipRect) {
|
|
5977
|
-
return { display: 'none' };
|
|
5978
|
-
}
|
|
5979
|
-
/**
|
|
5980
|
-
* By default, the tooltip floats to the left of the element
|
|
5981
|
-
*/
|
|
5982
|
-
const newTooltipStyles = { display: 'flex' };
|
|
5983
|
-
// If the preview size is relative, we don't change the floating direction
|
|
5984
|
-
if (!isRelativePreviewSize(previewSize)) {
|
|
5985
|
-
const previewSizeMatch = previewSize.match(/(\d{1,})px/);
|
|
5986
|
-
if (!previewSizeMatch) {
|
|
5987
|
-
return { display: 'none' };
|
|
5988
|
-
}
|
|
5989
|
-
const previewSizePx = parseInt(previewSizeMatch[1]);
|
|
5990
|
-
/**
|
|
5991
|
-
* If the element is at the right edge of the canvas, and the element isn't wide enough to fit the tooltip width,
|
|
5992
|
-
* we float the tooltip to the right of the element.
|
|
5993
|
-
*/
|
|
5994
|
-
if (tooltipRect.width > previewSizePx - coordinates.right &&
|
|
5995
|
-
tooltipRect.width > coordinates.width) {
|
|
5996
|
-
newTooltipStyles['float'] = 'right';
|
|
5997
|
-
}
|
|
5998
|
-
}
|
|
5999
|
-
const tooltipHeight = tooltipRect.height === 0 ? 32 : tooltipRect.height;
|
|
6000
|
-
/**
|
|
6001
|
-
* For elements with small heights, we don't want the tooltip covering the content in the element,
|
|
6002
|
-
* so we show the tooltip at the top or bottom.
|
|
6003
|
-
*/
|
|
6004
|
-
if (tooltipHeight * 2 > coordinates.height) {
|
|
6005
|
-
/**
|
|
6006
|
-
* If there's enough space for the tooltip at the top of the element, we show the tooltip at the top of the element,
|
|
6007
|
-
* else we show the tooltip at the bottom.
|
|
6008
|
-
*/
|
|
6009
|
-
if (tooltipHeight < coordinates.top) {
|
|
6010
|
-
newTooltipStyles['bottom'] = coordinates.height;
|
|
6011
|
-
}
|
|
6012
|
-
else {
|
|
6013
|
-
newTooltipStyles['top'] = coordinates.height;
|
|
6014
|
-
}
|
|
6015
|
-
}
|
|
6016
|
-
/**
|
|
6017
|
-
* If the component draws outside of the borders of the canvas to the left we move the tooltip to the right
|
|
6018
|
-
* so that it is fully visible.
|
|
6019
|
-
*/
|
|
6020
|
-
if (coordinates.left < 0) {
|
|
6021
|
-
newTooltipStyles['left'] = -coordinates.left;
|
|
6022
|
-
}
|
|
6023
|
-
/**
|
|
6024
|
-
* If for any reason, the element's top is negative, we show the tooltip at the bottom
|
|
6025
|
-
*/
|
|
6026
|
-
if (coordinates.top < 0) {
|
|
6027
|
-
newTooltipStyles['top'] = coordinates.height;
|
|
6028
|
-
}
|
|
6029
|
-
return newTooltipStyles;
|
|
6030
|
-
};
|
|
6031
|
-
|
|
6032
|
-
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";
|
|
6033
|
-
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"};
|
|
6034
|
-
styleInject(css_248z$1);
|
|
6035
|
-
|
|
6036
|
-
const Tooltip = ({ coordinates, id, label, isAssemblyBlock, isContainer, isSelected, }) => {
|
|
6037
|
-
const tooltipRef = useRef(null);
|
|
6038
|
-
const previewSize = '100%'; // This should be based on breakpoints and added to usememo dependency array
|
|
6039
|
-
const tooltipStyles = useMemo(() => {
|
|
6040
|
-
const tooltipRect = tooltipRef.current?.getBoundingClientRect();
|
|
6041
|
-
const draggableRect = document
|
|
6042
|
-
.querySelector(`[data-ctfl-draggable-id="${id}"]`)
|
|
6043
|
-
?.getBoundingClientRect();
|
|
6044
|
-
const newTooltipStyles = getTooltipPositions({
|
|
6045
|
-
previewSize,
|
|
6046
|
-
tooltipRect,
|
|
6047
|
-
coordinates: draggableRect,
|
|
6048
|
-
});
|
|
6049
|
-
return newTooltipStyles;
|
|
6050
|
-
// 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
|
|
6051
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6052
|
-
}, [coordinates, id, tooltipRef.current]);
|
|
6053
|
-
if (isSelected) {
|
|
6054
|
-
return null;
|
|
6055
|
-
}
|
|
6056
|
-
return (React.createElement("div", { "data-tooltip": true, className: styles$1.tooltipWrapper },
|
|
6057
|
-
React.createElement("div", { "data-tooltip": true, ref: tooltipRef, style: tooltipStyles, className: classNames(styles$1.overlay, {
|
|
6058
|
-
[styles$1.overlayContainer]: isContainer,
|
|
6059
|
-
[styles$1.overlayAssembly]: isAssemblyBlock,
|
|
6060
|
-
}) }, label)));
|
|
4733
|
+
return {
|
|
4734
|
+
...sharedProps,
|
|
4735
|
+
// Allows custom components to render differently in the editor. This needs to be activated
|
|
4736
|
+
// through options as the component has to be aware of this prop to not cause any React warnings.
|
|
4737
|
+
...(options?.enableCustomEditorView ? { isInExpEditorMode: true } : {}),
|
|
4738
|
+
...sanitizeNodeProps(props),
|
|
4739
|
+
};
|
|
4740
|
+
}, [cfCsrClassName, node, options?.enableCustomEditorView, props]);
|
|
4741
|
+
return { componentProps };
|
|
6061
4742
|
};
|
|
6062
4743
|
|
|
6063
|
-
function
|
|
6064
|
-
const
|
|
6065
|
-
const
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
return false;
|
|
6069
|
-
}
|
|
6070
|
-
const parentNode = getItem({ id: node.parentId }, tree);
|
|
6071
|
-
if (!parentNode || parentNode.data.blockId !== CONTENTFUL_COMPONENTS$1.columns.id) {
|
|
6072
|
-
return false;
|
|
6073
|
-
}
|
|
6074
|
-
const { cfWrapColumns } = parentNode.data.props;
|
|
6075
|
-
if (cfWrapColumns?.type !== 'DesignValue') {
|
|
6076
|
-
return false;
|
|
4744
|
+
function EditorBlock({ node, resolveDesignValue, wrappingPatternIds: parentWrappingPatternIds = new Set(), entityStore, areEntitiesFetched, }) {
|
|
4745
|
+
const isRootAssemblyNode = node.type === ASSEMBLY_NODE_TYPE;
|
|
4746
|
+
const wrappingPatternIds = useMemo(() => {
|
|
4747
|
+
if (isRootAssemblyNode && node.data.blockId) {
|
|
4748
|
+
return new Set([node.data.blockId, ...parentWrappingPatternIds]);
|
|
6077
4749
|
}
|
|
6078
|
-
return
|
|
6079
|
-
}, [
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
}
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
4750
|
+
return parentWrappingPatternIds;
|
|
4751
|
+
}, [isRootAssemblyNode, node, parentWrappingPatternIds]);
|
|
4752
|
+
const componentRegistration = useComponentRegistration(node);
|
|
4753
|
+
if (!componentRegistration) {
|
|
4754
|
+
return React.createElement(MissingComponentPlaceholder, { blockId: node.data.blockId });
|
|
4755
|
+
}
|
|
4756
|
+
if (isRootAssemblyNode && node.data.blockId && parentWrappingPatternIds.has(node.data.blockId)) {
|
|
4757
|
+
return React.createElement(CircularDependencyErrorPlaceholder, { wrappingPatternIds: wrappingPatternIds });
|
|
4758
|
+
}
|
|
4759
|
+
const slotNodes = {};
|
|
4760
|
+
for (const slotId in componentRegistration.definition.slots) {
|
|
4761
|
+
const nodes = node.children.filter((child) => child.data.slotId === slotId);
|
|
4762
|
+
slotNodes[slotId] =
|
|
4763
|
+
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, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched })))));
|
|
4764
|
+
}
|
|
4765
|
+
const children = componentRegistration.definition.children
|
|
4766
|
+
? node.children
|
|
4767
|
+
.filter((node) => node.data.slotId === undefined)
|
|
4768
|
+
.map((childNode) => (React.createElement(EditorBlock, { key: childNode.data.id, node: childNode, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched })))
|
|
4769
|
+
: null;
|
|
4770
|
+
return (React.createElement(RegistrationComponent, { node: node, resolveDesignValue: resolveDesignValue, componentRegistration: componentRegistration, slotNodes: slotNodes, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched }, children));
|
|
6095
4771
|
}
|
|
6096
|
-
const
|
|
6097
|
-
const {
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
node: rawNode,
|
|
4772
|
+
const RegistrationComponent = ({ node, resolveDesignValue, componentRegistration, slotNodes, children, entityStore, areEntitiesFetched, }) => {
|
|
4773
|
+
const { componentProps } = useComponentProps({
|
|
4774
|
+
node,
|
|
4775
|
+
resolveDesignValue,
|
|
4776
|
+
definition: componentRegistration.definition,
|
|
4777
|
+
options: componentRegistration.options,
|
|
6103
4778
|
entityStore,
|
|
6104
4779
|
areEntitiesFetched,
|
|
6105
|
-
resolveDesignValue,
|
|
6106
|
-
renderDropzone,
|
|
6107
|
-
userIsDragging,
|
|
6108
|
-
wrappingPatternIds,
|
|
6109
|
-
});
|
|
6110
|
-
const { isSingleColumn, isWrapped } = useSingleColumn(node, resolveDesignValue);
|
|
6111
|
-
const setDomRect = useDraggedItemStore((state) => state.setDomRect);
|
|
6112
|
-
const isHoveredComponent = useDraggedItemStore((state) => state.hoveredComponentId === componentId);
|
|
6113
|
-
const coordinates = useSelectedInstanceCoordinates({ node });
|
|
6114
|
-
const displayName = node.data.displayName || rawNode.data.displayName || definition?.name;
|
|
6115
|
-
const testId = `draggable-${node.data.blockId ?? 'node'}`;
|
|
6116
|
-
const isSelected = node.data.id === selectedNodeId;
|
|
6117
|
-
const isContainer = node.data.blockId === CONTENTFUL_COMPONENTS$1.container.id;
|
|
6118
|
-
const isSlotComponent = Boolean(node.data.slotId);
|
|
6119
|
-
const isDragDisabled = isNestedPattern || isPatternComponent || (isSingleColumn && isWrapped) || isSlotComponent;
|
|
6120
|
-
const isEmptyZone = useMemo(() => {
|
|
6121
|
-
return !node.children.filter((node) => node.data.slotId === slotId).length;
|
|
6122
|
-
}, [node.children, slotId]);
|
|
6123
|
-
useDraggablePosition({
|
|
6124
|
-
draggableId: componentId,
|
|
6125
|
-
draggableRef: ref,
|
|
6126
|
-
position: DraggablePosition.MOUSE_POSITION,
|
|
6127
4780
|
});
|
|
6128
|
-
|
|
6129
|
-
e.stopPropagation();
|
|
6130
|
-
if (!userIsDragging) {
|
|
6131
|
-
setSelectedNodeId(node.data.id);
|
|
6132
|
-
// if it is the assembly directly we just want to select it as a normal component
|
|
6133
|
-
if (isPatternNode) {
|
|
6134
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
6135
|
-
nodeId: node.data.id,
|
|
6136
|
-
});
|
|
6137
|
-
return;
|
|
6138
|
-
}
|
|
6139
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
6140
|
-
assembly: node.data.assembly,
|
|
6141
|
-
nodeId: node.data.id,
|
|
6142
|
-
});
|
|
6143
|
-
}
|
|
6144
|
-
};
|
|
6145
|
-
const onMouseOver = (e) => {
|
|
6146
|
-
e.stopPropagation();
|
|
6147
|
-
if (userIsDragging)
|
|
6148
|
-
return;
|
|
6149
|
-
sendMessage(OUTGOING_EVENTS.NewHoveredElement, {
|
|
6150
|
-
nodeId: componentId,
|
|
6151
|
-
});
|
|
6152
|
-
};
|
|
6153
|
-
const onMouseDown = (e) => {
|
|
6154
|
-
if (isDragDisabled) {
|
|
6155
|
-
return;
|
|
6156
|
-
}
|
|
6157
|
-
e.stopPropagation();
|
|
6158
|
-
setDomRect(e.currentTarget.getBoundingClientRect());
|
|
6159
|
-
};
|
|
6160
|
-
const ToolTipAndPlaceholder = (React.createElement(React.Fragment, null,
|
|
6161
|
-
React.createElement(Tooltip, { id: componentId, coordinates: coordinates, isAssemblyBlock: isPatternNode || isPatternComponent, isContainer: isContainer, isSelected: isSelected, label: displayName || 'No label specified' }),
|
|
6162
|
-
React.createElement(Placeholder, { ...placeholder, id: componentId }),
|
|
6163
|
-
userIsDragging && !isPatternComponent && (React.createElement(Hitboxes, { parentZoneId: zoneId, zoneId: componentId, isEmptyZone: isEmptyZone }))));
|
|
6164
|
-
return (React.createElement(Draggable, { key: componentId, draggableId: componentId, index: index, isDragDisabled: isDragDisabled, disableInteractiveElementBlocking: true }, (provided, snapshot) => elementToRender({
|
|
6165
|
-
dragProps: {
|
|
6166
|
-
...provided.draggableProps,
|
|
6167
|
-
...provided.dragHandleProps,
|
|
6168
|
-
'data-ctfl-draggable-id': componentId,
|
|
6169
|
-
'data-test-id': testId,
|
|
6170
|
-
innerRef: (refNode) => {
|
|
6171
|
-
provided?.innerRef(refNode);
|
|
6172
|
-
ref.current = refNode;
|
|
6173
|
-
},
|
|
6174
|
-
className: classNames(styles$1.DraggableComponent, {
|
|
6175
|
-
[styles$1.isAssemblyBlock]: isPatternComponent || isPatternNode,
|
|
6176
|
-
[styles$1.isDragging]: snapshot?.isDragging || userIsDragging,
|
|
6177
|
-
[styles$1.isSelected]: isSelected,
|
|
6178
|
-
[styles$1.isHoveringComponent]: isHoveredComponent,
|
|
6179
|
-
}),
|
|
6180
|
-
style: getStyle$1(provided.draggableProps.style, snapshot),
|
|
6181
|
-
onMouseDown,
|
|
6182
|
-
onMouseOver,
|
|
6183
|
-
onClick,
|
|
6184
|
-
ToolTipAndPlaceholder,
|
|
6185
|
-
},
|
|
6186
|
-
})));
|
|
4781
|
+
return React.createElement(ImportedComponentErrorBoundary, { componentId: node.data.blockId }, React.createElement(componentRegistration.component, { ...componentProps, ...slotNodes }, children));
|
|
6187
4782
|
};
|
|
6188
4783
|
|
|
6189
|
-
var css_248z = ".
|
|
6190
|
-
var styles = {"container":"
|
|
4784
|
+
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";
|
|
4785
|
+
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"};
|
|
6191
4786
|
styleInject(css_248z);
|
|
6192
4787
|
|
|
6193
|
-
const
|
|
6194
|
-
return (React.createElement("div", { className:
|
|
6195
|
-
|
|
6196
|
-
}), "data-type": "empty-container" },
|
|
6197
|
-
React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "37", height: "36", fill: "none", className: styles.icon },
|
|
4788
|
+
const EmptyCanvasMessage = () => {
|
|
4789
|
+
return (React.createElement("div", { className: styles['empty-canvas-container'], "data-type": "empty-container" },
|
|
4790
|
+
React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "37", height: "36", fill: "none", className: styles['empty-canvas-icon'] },
|
|
6198
4791
|
React.createElement("rect", { width: "11.676", height: "11.676", x: "18.512", y: ".153", rx: "1.621", transform: "rotate(45 18.512 .153)" }),
|
|
6199
4792
|
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)" }),
|
|
6200
4793
|
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)" }),
|
|
6201
4794
|
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)" }),
|
|
6202
4795
|
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" })),
|
|
6203
|
-
React.createElement("span", { className: styles
|
|
6204
|
-
};
|
|
6205
|
-
|
|
6206
|
-
const useDropzoneDirection = ({ resolveDesignValue, node, zoneId }) => {
|
|
6207
|
-
const zone = useZoneStore((state) => state.zones);
|
|
6208
|
-
const upsertZone = useZoneStore((state) => state.upsertZone);
|
|
6209
|
-
useEffect(() => {
|
|
6210
|
-
function getDirection() {
|
|
6211
|
-
if (!node || !node.data.blockId) {
|
|
6212
|
-
return 'vertical';
|
|
6213
|
-
}
|
|
6214
|
-
if (!isContentfulStructureComponent(node.data.blockId)) {
|
|
6215
|
-
return 'vertical';
|
|
6216
|
-
}
|
|
6217
|
-
if (node.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id) {
|
|
6218
|
-
return 'horizontal';
|
|
6219
|
-
}
|
|
6220
|
-
const designValues = node.data.props['cfFlexDirection'];
|
|
6221
|
-
if (!designValues || !resolveDesignValue || designValues.type !== 'DesignValue') {
|
|
6222
|
-
return 'vertical';
|
|
6223
|
-
}
|
|
6224
|
-
const direction = resolveDesignValue(designValues.valuesByBreakpoint);
|
|
6225
|
-
if (direction === 'row') {
|
|
6226
|
-
return 'horizontal';
|
|
6227
|
-
}
|
|
6228
|
-
return 'vertical';
|
|
6229
|
-
}
|
|
6230
|
-
upsertZone(zoneId, { direction: getDirection() });
|
|
6231
|
-
}, [node, resolveDesignValue, zoneId, upsertZone]);
|
|
6232
|
-
return zone[zoneId]?.direction || 'vertical';
|
|
4796
|
+
React.createElement("span", { className: styles['empty-canvas-label'] }, "Add components to begin")));
|
|
6233
4797
|
};
|
|
6234
4798
|
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
const { node, elementToRender } = useComponent({
|
|
6248
|
-
node: rawNode,
|
|
6249
|
-
entityStore,
|
|
6250
|
-
areEntitiesFetched,
|
|
6251
|
-
resolveDesignValue,
|
|
6252
|
-
renderDropzone,
|
|
6253
|
-
userIsDragging,
|
|
6254
|
-
wrappingPatternIds,
|
|
6255
|
-
});
|
|
6256
|
-
const isAssemblyBlock = node.type === ASSEMBLY_BLOCK_NODE_TYPE;
|
|
6257
|
-
return elementToRender({
|
|
6258
|
-
dragProps: {
|
|
6259
|
-
...provided?.draggableProps,
|
|
6260
|
-
...provided?.dragHandleProps,
|
|
6261
|
-
'data-ctfl-dragging-element': 'true',
|
|
6262
|
-
innerRef: provided?.innerRef,
|
|
6263
|
-
className: classNames(styles$1.DraggableComponent, styles$1.DraggableClone, {
|
|
6264
|
-
[styles$1.isAssemblyBlock]: isAssemblyBlock,
|
|
6265
|
-
[styles$1.isDragging]: snapshot?.isDragging,
|
|
6266
|
-
}),
|
|
6267
|
-
style: getStyle(provided?.draggableProps.style, snapshot),
|
|
4799
|
+
/**
|
|
4800
|
+
* This function gets the element co-ordinates of a specified component in the DOM and its parent
|
|
4801
|
+
* and sends the DOM Rect to the client app.
|
|
4802
|
+
*/
|
|
4803
|
+
const sendCanvasGeometryUpdatedMessage = async (tree, sourceEvent) => {
|
|
4804
|
+
const nodeToCoordinatesMap = {};
|
|
4805
|
+
await waitForAllImagesToBeLoaded();
|
|
4806
|
+
collectNodeCoordinates(tree.root, nodeToCoordinatesMap);
|
|
4807
|
+
sendMessage(OUTGOING_EVENTS.CanvasGeometryUpdated, {
|
|
4808
|
+
size: {
|
|
4809
|
+
width: document.documentElement.offsetWidth,
|
|
4810
|
+
height: document.documentElement.offsetHeight,
|
|
6268
4811
|
},
|
|
4812
|
+
nodes: nodeToCoordinatesMap,
|
|
4813
|
+
sourceEvent,
|
|
6269
4814
|
});
|
|
6270
4815
|
};
|
|
6271
|
-
|
|
6272
|
-
const
|
|
6273
|
-
if (
|
|
6274
|
-
const
|
|
6275
|
-
|
|
6276
|
-
}
|
|
6277
|
-
return {};
|
|
6278
|
-
};
|
|
6279
|
-
const getHtmlComponentProps = (props) => {
|
|
6280
|
-
if (props) {
|
|
6281
|
-
const { editorMode, renderDropzone, node, ...htmlProps } = props;
|
|
6282
|
-
return htmlProps;
|
|
6283
|
-
}
|
|
6284
|
-
return {};
|
|
6285
|
-
};
|
|
6286
|
-
|
|
6287
|
-
function DropzoneClone({ node, entityStore, zoneId, resolveDesignValue, WrapperComponent = 'div', renderDropzone, dragProps, wrappingPatternIds, areEntitiesFetched, ...rest }) {
|
|
6288
|
-
const tree = useTreeStore((state) => state.tree);
|
|
6289
|
-
const content = node?.children || tree.root?.children || [];
|
|
6290
|
-
const { slotId } = parseZoneId(zoneId);
|
|
6291
|
-
const htmlDraggableProps = getHtmlDragProps(dragProps);
|
|
6292
|
-
const htmlProps = getHtmlComponentProps(rest);
|
|
6293
|
-
const isRootZone = zoneId === ROOT_ID;
|
|
6294
|
-
if (!resolveDesignValue) {
|
|
6295
|
-
return null;
|
|
6296
|
-
}
|
|
6297
|
-
return (React.createElement(WrapperComponent, { ...htmlDraggableProps, ...htmlProps, className: classNames(dragProps?.className, styles$1.Dropzone, styles$1.DropzoneClone, rest.className, {
|
|
6298
|
-
[styles$1.isRoot]: isRootZone,
|
|
6299
|
-
[styles$1.isEmptyZone]: !content.length,
|
|
6300
|
-
}), "data-ctfl-slot-id": slotId, ref: (refNode) => {
|
|
6301
|
-
if (dragProps?.innerRef) {
|
|
6302
|
-
dragProps.innerRef(refNode);
|
|
6303
|
-
}
|
|
6304
|
-
} }, content
|
|
6305
|
-
.filter((node) => node.data.slotId === slotId)
|
|
6306
|
-
.map((item) => {
|
|
6307
|
-
const componentId = item.data.id;
|
|
6308
|
-
return (React.createElement(EditorBlockClone, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, key: componentId, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds }));
|
|
6309
|
-
})));
|
|
6310
|
-
}
|
|
6311
|
-
|
|
6312
|
-
function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponent = 'div', dragProps, entityStore, areEntitiesFetched, wrappingPatternIds: parentWrappingPatternIds = new Set(), ...rest }) {
|
|
6313
|
-
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
6314
|
-
const draggedItem = useDraggedItemStore((state) => state.draggedItem);
|
|
6315
|
-
const isDraggingNewComponent = useDraggedItemStore((state) => Boolean(state.componentId));
|
|
6316
|
-
const isHoveringZone = useZoneStore((state) => state.hoveringZone === zoneId);
|
|
6317
|
-
const tree = useTreeStore((state) => state.tree);
|
|
6318
|
-
const content = node?.children || tree.root?.children || [];
|
|
6319
|
-
const { slotId } = parseZoneId(zoneId);
|
|
6320
|
-
const direction = useDropzoneDirection({ resolveDesignValue, node, zoneId });
|
|
6321
|
-
const draggedDestinationId = draggedItem && draggedItem.destination?.droppableId;
|
|
6322
|
-
const draggedNode = useMemo(() => {
|
|
6323
|
-
if (!draggedItem)
|
|
4816
|
+
const collectNodeCoordinates = (node, nodeToCoordinatesMap) => {
|
|
4817
|
+
const selectedElement = document.querySelector(`[data-cf-node-id="${node.data.id}"]`);
|
|
4818
|
+
if (selectedElement) {
|
|
4819
|
+
const rect = getElementCoordinates(selectedElement);
|
|
4820
|
+
if (isElementHidden(rect)) {
|
|
6324
4821
|
return;
|
|
6325
|
-
return getItem({ id: draggedItem.draggableId }, tree);
|
|
6326
|
-
}, [draggedItem, tree]);
|
|
6327
|
-
const isRootZone = zoneId === ROOT_ID;
|
|
6328
|
-
const isDestination = draggedDestinationId === zoneId;
|
|
6329
|
-
const isEmptyCanvas = isRootZone && !content.length;
|
|
6330
|
-
const isAssembly = ASSEMBLY_NODE_TYPES.includes(node?.type || '');
|
|
6331
|
-
const isRootAssembly = node?.type === ASSEMBLY_NODE_TYPE;
|
|
6332
|
-
const htmlDraggableProps = getHtmlDragProps(dragProps);
|
|
6333
|
-
const htmlProps = getHtmlComponentProps(rest);
|
|
6334
|
-
const wrappingPatternIds = useMemo(() => {
|
|
6335
|
-
// On the top level, the node is not defined. If the root blockId is not the default string,
|
|
6336
|
-
// we assume that it is the entry ID of the experience/ pattern to properly detect circular dependencies
|
|
6337
|
-
if (!node && tree.root.data.blockId && tree.root.data.blockId !== ROOT_ID) {
|
|
6338
|
-
return new Set([tree.root.data.blockId, ...parentWrappingPatternIds]);
|
|
6339
|
-
}
|
|
6340
|
-
if (isRootAssembly && node?.data.blockId) {
|
|
6341
|
-
return new Set([node.data.blockId, ...parentWrappingPatternIds]);
|
|
6342
|
-
}
|
|
6343
|
-
return parentWrappingPatternIds;
|
|
6344
|
-
}, [isRootAssembly, node, parentWrappingPatternIds, tree.root.data.blockId]);
|
|
6345
|
-
// To avoid a circular dependency, we create the recursive rendering function here and trickle it down
|
|
6346
|
-
const renderDropzone = useCallback((node, props) => {
|
|
6347
|
-
return (React.createElement(Dropzone, { zoneId: node.data.id, entityStore: entityStore, node: node, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds, areEntitiesFetched: areEntitiesFetched, ...props }));
|
|
6348
|
-
}, [wrappingPatternIds, resolveDesignValue, entityStore, areEntitiesFetched]);
|
|
6349
|
-
const renderClonedDropzone = useCallback((node, props) => {
|
|
6350
|
-
return (React.createElement(DropzoneClone, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
6351
|
-
}, [resolveDesignValue, wrappingPatternIds, entityStore, areEntitiesFetched]);
|
|
6352
|
-
const isDropzoneEnabled = useMemo(() => {
|
|
6353
|
-
const isColumns = node?.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id;
|
|
6354
|
-
const isDraggingSingleColumn = draggedNode?.data.blockId === CONTENTFUL_COMPONENTS$1.singleColumn.id;
|
|
6355
|
-
const isParentOfDraggedNode = node?.data.id === draggedNode?.parentId;
|
|
6356
|
-
// If dragging a single column, only enable the dropzone of the parent
|
|
6357
|
-
// columns component
|
|
6358
|
-
if (isDraggingSingleColumn && isColumns && isParentOfDraggedNode) {
|
|
6359
|
-
return true;
|
|
6360
|
-
}
|
|
6361
|
-
// If dragging a single column, disable dropzones for any component besides
|
|
6362
|
-
// the parent of the dragged single column
|
|
6363
|
-
if (isDraggingSingleColumn && !isParentOfDraggedNode) {
|
|
6364
|
-
return false;
|
|
6365
|
-
}
|
|
6366
|
-
// Disable dropzone for Columns component
|
|
6367
|
-
if (isColumns) {
|
|
6368
|
-
return false;
|
|
6369
4822
|
}
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
}
|
|
6379
|
-
// Enable dropzone for the hovered zone only
|
|
6380
|
-
return isHoveringZone;
|
|
6381
|
-
}, [isAssembly, isHoveringZone, isRootZone, isDraggingNewComponent, draggedNode, node]);
|
|
6382
|
-
if (!resolveDesignValue) {
|
|
6383
|
-
return null;
|
|
4823
|
+
nodeToCoordinatesMap[node.data.id] = {
|
|
4824
|
+
coordinates: {
|
|
4825
|
+
x: rect.x + window.scrollX,
|
|
4826
|
+
y: rect.y + window.scrollY,
|
|
4827
|
+
width: rect.width,
|
|
4828
|
+
height: rect.height,
|
|
4829
|
+
},
|
|
4830
|
+
};
|
|
6384
4831
|
}
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
const
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
return (
|
|
6395
|
-
|
|
6396
|
-
|
|
4832
|
+
node.children.forEach((child) => collectNodeCoordinates(child, nodeToCoordinatesMap));
|
|
4833
|
+
};
|
|
4834
|
+
const waitForAllImagesToBeLoaded = () => {
|
|
4835
|
+
// If the document contains an image, wait for this image to be loaded before collecting & sending all geometry data.
|
|
4836
|
+
const allImageNodes = document.querySelectorAll('img');
|
|
4837
|
+
return Promise.all(Array.from(allImageNodes).map((imageNode) => {
|
|
4838
|
+
if (imageNode.complete) {
|
|
4839
|
+
return Promise.resolve();
|
|
4840
|
+
}
|
|
4841
|
+
return new Promise((resolve, reject) => {
|
|
4842
|
+
const handleImageLoad = (event) => {
|
|
4843
|
+
imageNode.removeEventListener('load', handleImageLoad);
|
|
4844
|
+
imageNode.removeEventListener('error', handleImageLoad);
|
|
4845
|
+
if (event.type === 'error') {
|
|
4846
|
+
console.warn('Image failed to load:', imageNode);
|
|
4847
|
+
reject();
|
|
4848
|
+
}
|
|
4849
|
+
else {
|
|
4850
|
+
resolve();
|
|
6397
4851
|
}
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
[styles$1.isDestination]: isDestination && !isAssembly,
|
|
6403
|
-
[styles$1.isRoot]: isRootZone,
|
|
6404
|
-
[styles$1.isEmptyZone]: !content.length,
|
|
6405
|
-
[styles$1.isSlot]: Boolean(slotId),
|
|
6406
|
-
[styles$1.fullHeight]: isPatternWrapperComponentFullHeight,
|
|
6407
|
-
[styles$1.fullWidth]: isPatternWrapperComponentFullWidth,
|
|
6408
|
-
}) },
|
|
6409
|
-
isEmptyCanvas ? (React.createElement(EmptyContainer, { isDragging: isRootZone && userIsDragging })) : (content
|
|
6410
|
-
.filter((node) => node.data.slotId === slotId)
|
|
6411
|
-
.map((item, i) => (React.createElement(EditorBlock, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, placeholder: {
|
|
6412
|
-
isDraggingOver: snapshot?.isDraggingOver,
|
|
6413
|
-
totalIndexes: content.length,
|
|
6414
|
-
elementIndex: i,
|
|
6415
|
-
dropzoneElementId: zoneId,
|
|
6416
|
-
direction,
|
|
6417
|
-
}, index: i, zoneId: zoneId, key: item.data.id, userIsDragging: userIsDragging, draggingNewComponent: isDraggingNewComponent, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds })))),
|
|
6418
|
-
provided?.placeholder,
|
|
6419
|
-
dragProps?.ToolTipAndPlaceholder));
|
|
4852
|
+
};
|
|
4853
|
+
imageNode.addEventListener('load', handleImageLoad);
|
|
4854
|
+
imageNode.addEventListener('error', handleImageLoad);
|
|
4855
|
+
});
|
|
6420
4856
|
}));
|
|
6421
|
-
}
|
|
4857
|
+
};
|
|
6422
4858
|
|
|
6423
|
-
const
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
6430
|
-
const containerRef = useRef(null);
|
|
6431
|
-
const { resolveDesignValue } = useBreakpoints(breakpoints);
|
|
6432
|
-
const [containerStyles, setContainerStyles] = useState({});
|
|
6433
|
-
const tree = useTreeStore((state) => state.tree);
|
|
6434
|
-
const handleMouseOver = useCallback(() => {
|
|
6435
|
-
// Remove hover state set by UI when mouse is over canvas
|
|
6436
|
-
setHoveredComponentId();
|
|
6437
|
-
// Remove hover styling from components in the layers tab
|
|
6438
|
-
sendMessage(OUTGOING_EVENTS.NewHoveredElement, {});
|
|
6439
|
-
}, [setHoveredComponentId]);
|
|
6440
|
-
const handleClickOutside = useCallback((e) => {
|
|
6441
|
-
const element = e.target;
|
|
6442
|
-
const isRoot = element.getAttribute('data-ctfl-zone-id') === ROOT_ID;
|
|
6443
|
-
const clickedOnCanvas = element.closest(`[data-ctfl-root]`);
|
|
6444
|
-
if (clickedOnCanvas && !isRoot) {
|
|
6445
|
-
return;
|
|
6446
|
-
}
|
|
6447
|
-
sendMessage(OUTGOING_EVENTS.OutsideCanvasClick, {
|
|
6448
|
-
outsideCanvasClick: true,
|
|
6449
|
-
});
|
|
6450
|
-
sendMessage(OUTGOING_EVENTS.ComponentSelected, {
|
|
6451
|
-
nodeId: '',
|
|
6452
|
-
});
|
|
6453
|
-
setSelectedNodeId('');
|
|
6454
|
-
}, [setSelectedNodeId]);
|
|
6455
|
-
const handleResizeCanvas = useCallback(() => {
|
|
6456
|
-
const parentElement = containerRef.current?.parentElement;
|
|
6457
|
-
if (!parentElement) {
|
|
6458
|
-
return;
|
|
6459
|
-
}
|
|
6460
|
-
let siblingHeight = 0;
|
|
6461
|
-
for (const child of parentElement.children) {
|
|
6462
|
-
if (!child.hasAttribute('data-ctfl-root')) {
|
|
6463
|
-
siblingHeight += child.getBoundingClientRect().height;
|
|
6464
|
-
}
|
|
6465
|
-
}
|
|
6466
|
-
if (!siblingHeight) {
|
|
6467
|
-
/**
|
|
6468
|
-
* DRAGGABLE_HEIGHT is subtracted here due to an uninteded scrolling effect
|
|
6469
|
-
* when dragging a new component onto the canvas
|
|
6470
|
-
*
|
|
6471
|
-
* The DRAGGABLE_HEIGHT is then added as margin bottom to offset this value
|
|
6472
|
-
* so that visually there is no difference to the user.
|
|
6473
|
-
*/
|
|
6474
|
-
setContainerStyles({
|
|
6475
|
-
minHeight: `${window.innerHeight - DRAGGABLE_HEIGHT}px`,
|
|
6476
|
-
});
|
|
6477
|
-
return;
|
|
6478
|
-
}
|
|
6479
|
-
setContainerStyles({
|
|
6480
|
-
minHeight: `${window.innerHeight - siblingHeight}px`,
|
|
4859
|
+
const useCanvasGeometryUpdates = ({ tree }) => {
|
|
4860
|
+
const debouncedUpdateGeometry = useMemo(() => debounce((tree, sourceEvent) => {
|
|
4861
|
+
// When the DOM changed, we still need to wait for the next frame to ensure that
|
|
4862
|
+
// rendering is complete (e.g. this is required when deleting a node).
|
|
4863
|
+
window.requestAnimationFrame(() => {
|
|
4864
|
+
sendCanvasGeometryUpdatedMessage(tree, sourceEvent);
|
|
6481
4865
|
});
|
|
6482
|
-
|
|
6483
|
-
|
|
4866
|
+
}, 100, {
|
|
4867
|
+
leading: true,
|
|
4868
|
+
// To be sure, we recalculate it at the end of the frame again. Though, we couldn't
|
|
4869
|
+
// yet show the need for this. So we might be able to drop this later to boost performance.
|
|
4870
|
+
trailing: true,
|
|
4871
|
+
}), []);
|
|
4872
|
+
// Store tree in a ref to avoid the need to deactivate & reactivate the mutation observer
|
|
4873
|
+
// when the tree changes. This is important to avoid missing out on some mutation events.
|
|
4874
|
+
const treeRef = useRef(tree);
|
|
6484
4875
|
useEffect(() => {
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
4876
|
+
treeRef.current = tree;
|
|
4877
|
+
}, [tree]);
|
|
4878
|
+
// Handling window resize events
|
|
6488
4879
|
useEffect(() => {
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
4880
|
+
const resizeEventListener = () => debouncedUpdateGeometry(treeRef.current, 'resize');
|
|
4881
|
+
window.addEventListener('resize', resizeEventListener);
|
|
4882
|
+
return () => window.removeEventListener('resize', resizeEventListener);
|
|
4883
|
+
}, [debouncedUpdateGeometry]);
|
|
4884
|
+
// Handling DOM mutations
|
|
6494
4885
|
useEffect(() => {
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
4886
|
+
const observer = new MutationObserver(() => debouncedUpdateGeometry(treeRef.current, 'mutation'));
|
|
4887
|
+
observer.observe(document.documentElement, {
|
|
4888
|
+
childList: true,
|
|
4889
|
+
subtree: true,
|
|
4890
|
+
attributes: true,
|
|
4891
|
+
});
|
|
4892
|
+
return () => observer.disconnect();
|
|
4893
|
+
}, [debouncedUpdateGeometry]);
|
|
4894
|
+
};
|
|
4895
|
+
|
|
4896
|
+
const RootRenderer = ({ inMemoryEntitiesStore }) => {
|
|
4897
|
+
useEditorSubscriber(inMemoryEntitiesStore);
|
|
4898
|
+
const tree = useTreeStore((state) => state.tree);
|
|
4899
|
+
useCanvasGeometryUpdates({ tree });
|
|
4900
|
+
const breakpoints = useTreeStore((state) => state.breakpoints);
|
|
4901
|
+
const { resolveDesignValue } = useBreakpoints(breakpoints);
|
|
4902
|
+
// If the root blockId is defined but not the default string, it is the entry ID
|
|
4903
|
+
// of the experience/ pattern to properly detect circular dependencies.
|
|
4904
|
+
const rootBlockId = tree.root.data.blockId ?? ROOT_ID;
|
|
4905
|
+
const wrappingPatternIds = rootBlockId !== ROOT_ID ? new Set([rootBlockId]) : new Set();
|
|
6504
4906
|
const entityStore = inMemoryEntitiesStore((state) => state.entityStore);
|
|
6505
4907
|
const areEntitiesFetched = inMemoryEntitiesStore((state) => state.areEntitiesFetched);
|
|
6506
|
-
return (React.createElement(
|
|
6507
|
-
|
|
6508
|
-
React.createElement("div", { "data-ctfl-root": true, className: styles$3.container, ref: containerRef, style: containerStyles },
|
|
6509
|
-
userIsDragging && React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitbox }),
|
|
6510
|
-
React.createElement(Dropzone, { zoneId: ROOT_ID, resolveDesignValue: resolveDesignValue, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched }),
|
|
6511
|
-
userIsDragging && (React.createElement(React.Fragment, null,
|
|
6512
|
-
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitboxLower }),
|
|
6513
|
-
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.canvasBottomSpacer })))),
|
|
6514
|
-
React.createElement("div", { "data-ctfl-hitboxes": true })));
|
|
4908
|
+
return (React.createElement(React.Fragment, null,
|
|
4909
|
+
React.createElement("div", { "data-ctfl-root": true, className: styles$2.rootContainer }, !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, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched })))))));
|
|
6515
4910
|
};
|
|
6516
4911
|
|
|
6517
4912
|
const useInitializeEditor = (inMemoryEntitiesStore) => {
|
|
@@ -6553,38 +4948,11 @@ const useInitializeEditor = (inMemoryEntitiesStore) => {
|
|
|
6553
4948
|
const VisualEditorRoot = ({ experience, inMemoryEntitiesStore: inMemoryEntitiesStore$1 = inMemoryEntitiesStore, }) => {
|
|
6554
4949
|
const initialized = useInitializeEditor(inMemoryEntitiesStore$1);
|
|
6555
4950
|
const setHyperLinkPattern = useEditorStore((state) => state.setHyperLinkPattern);
|
|
6556
|
-
const setMousePosition = useDraggedItemStore((state) => state.setMousePosition);
|
|
6557
|
-
const setHoveringZone = useZoneStore((state) => state.setHoveringZone);
|
|
6558
4951
|
useEffect(() => {
|
|
6559
4952
|
if (experience?.hyperlinkPattern) {
|
|
6560
4953
|
setHyperLinkPattern(experience.hyperlinkPattern);
|
|
6561
4954
|
}
|
|
6562
4955
|
}, [experience?.hyperlinkPattern, setHyperLinkPattern]);
|
|
6563
|
-
useEffect(() => {
|
|
6564
|
-
const onMouseMove = (e) => {
|
|
6565
|
-
setMousePosition(e.clientX, e.clientY);
|
|
6566
|
-
const target = e.target;
|
|
6567
|
-
const zoneId = target.closest(`[${CTFL_ZONE_ID}]`)?.getAttribute(CTFL_ZONE_ID);
|
|
6568
|
-
if (zoneId) {
|
|
6569
|
-
setHoveringZone(zoneId);
|
|
6570
|
-
}
|
|
6571
|
-
if (!SimulateDnD$1.isDragging) {
|
|
6572
|
-
return;
|
|
6573
|
-
}
|
|
6574
|
-
if (target.id === NEW_COMPONENT_ID) {
|
|
6575
|
-
return;
|
|
6576
|
-
}
|
|
6577
|
-
SimulateDnD$1.updateDrag(e.clientX, e.clientY);
|
|
6578
|
-
sendMessage(OUTGOING_EVENTS.MouseMove, {
|
|
6579
|
-
clientX: e.pageX - window.scrollX,
|
|
6580
|
-
clientY: e.pageY - window.scrollY,
|
|
6581
|
-
});
|
|
6582
|
-
};
|
|
6583
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
6584
|
-
return () => {
|
|
6585
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
6586
|
-
};
|
|
6587
|
-
}, [setHoveringZone, setMousePosition]);
|
|
6588
4956
|
if (!initialized)
|
|
6589
4957
|
return null;
|
|
6590
4958
|
return React.createElement(RootRenderer, { inMemoryEntitiesStore: inMemoryEntitiesStore$1 });
|