@elementor/editor-canvas 4.3.0-975 → 4.3.0-977
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 +26 -7
- package/dist/index.mjs +26 -7
- package/package.json +20 -20
- package/src/components/elements-overlays.tsx +7 -4
- package/src/components/outline-overlay.tsx +9 -2
- package/src/form-structure/enforce-form-ancestor-commands.ts +3 -1
- package/src/form-structure/utils.ts +1 -0
- package/src/types/element-overlay.ts +2 -0
- package/src/utils/__tests__/outline-offset-utils.test.ts +39 -0
- package/src/utils/outline-offset-utils.ts +11 -0
package/dist/index.js
CHANGED
|
@@ -943,6 +943,16 @@ var useHasOverlapping = () => {
|
|
|
943
943
|
return hasOverlapping;
|
|
944
944
|
};
|
|
945
945
|
|
|
946
|
+
// src/utils/outline-offset-utils.ts
|
|
947
|
+
var THIN_ELEMENT_MAX_HEIGHT_PX = 1;
|
|
948
|
+
var SMALLER_OUTLINE_OFFSET_WIDGET_TYPES = /* @__PURE__ */ new Set(["e-form-input"]);
|
|
949
|
+
function shouldUseSmallerOutlineOffset(element, widgetType) {
|
|
950
|
+
if (element.offsetHeight <= THIN_ELEMENT_MAX_HEIGHT_PX) {
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
return widgetType !== void 0 && SMALLER_OUTLINE_OFFSET_WIDGET_TYPES.has(widgetType);
|
|
954
|
+
}
|
|
955
|
+
|
|
946
956
|
// src/components/outline-overlay.tsx
|
|
947
957
|
var CANVAS_WRAPPER_ID = "elementor-preview-responsive-wrapper";
|
|
948
958
|
var OverlayBox = (0, import_ui.styled)(import_ui.Box, {
|
|
@@ -954,12 +964,18 @@ var OverlayBox = (0, import_ui.styled)(import_ui.Box, {
|
|
|
954
964
|
pointerEvents: "none"
|
|
955
965
|
})
|
|
956
966
|
);
|
|
957
|
-
var OutlineOverlay = ({
|
|
967
|
+
var OutlineOverlay = ({
|
|
968
|
+
element,
|
|
969
|
+
isSelected,
|
|
970
|
+
id,
|
|
971
|
+
isGlobal = false,
|
|
972
|
+
widgetType
|
|
973
|
+
}) => {
|
|
958
974
|
const { context, floating, isVisible } = useFloatingOnElement({ element, isSelected });
|
|
959
975
|
const { getFloatingProps, getReferenceProps } = (0, import_react9.useInteractions)([(0, import_react9.useHover)(context)]);
|
|
960
976
|
const hasOverlapping = useHasOverlapping();
|
|
961
977
|
useBindReactPropsToElement(element, getReferenceProps);
|
|
962
|
-
const isSmallerOffset = element
|
|
978
|
+
const isSmallerOffset = shouldUseSmallerOutlineOffset(element, widgetType);
|
|
963
979
|
return isVisible && !hasOverlapping && /* @__PURE__ */ React.createElement(import_react9.FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React.createElement(
|
|
964
980
|
OverlayBox,
|
|
965
981
|
{
|
|
@@ -1167,17 +1183,18 @@ function ElementsOverlays() {
|
|
|
1167
1183
|
if (!isActive) {
|
|
1168
1184
|
return null;
|
|
1169
1185
|
}
|
|
1170
|
-
return elements.map(({ id, domElement, isGlobal }) => {
|
|
1186
|
+
return elements.map(({ id, domElement, isGlobal, widgetType }) => {
|
|
1171
1187
|
const isSelected = selected.element?.id === id;
|
|
1172
1188
|
return overlayRegistry.map(
|
|
1173
|
-
({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected }) && /* @__PURE__ */ React7.createElement(
|
|
1189
|
+
({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected, widgetType }) && /* @__PURE__ */ React7.createElement(
|
|
1174
1190
|
Overlay,
|
|
1175
1191
|
{
|
|
1176
1192
|
key: `${id}-${index}`,
|
|
1177
1193
|
id,
|
|
1178
1194
|
element: domElement,
|
|
1179
1195
|
isSelected,
|
|
1180
|
-
isGlobal
|
|
1196
|
+
isGlobal,
|
|
1197
|
+
widgetType
|
|
1181
1198
|
}
|
|
1182
1199
|
)
|
|
1183
1200
|
);
|
|
@@ -1190,7 +1207,8 @@ function useElementsDom() {
|
|
|
1190
1207
|
return (0, import_editor_elements5.getElements)().filter((el) => isV4Element(el.view?.el?.dataset)).map((element) => ({
|
|
1191
1208
|
id: element.id,
|
|
1192
1209
|
domElement: element.view?.getDomElement?.()?.get?.(0),
|
|
1193
|
-
isGlobal: element.model.get("isGlobal") ?? false
|
|
1210
|
+
isGlobal: element.model.get("isGlobal") ?? false,
|
|
1211
|
+
widgetType: element.model.get("widgetType")
|
|
1194
1212
|
})).filter((item) => !!item.domElement);
|
|
1195
1213
|
}
|
|
1196
1214
|
);
|
|
@@ -2029,7 +2047,8 @@ function blockFormFieldCreate(args) {
|
|
|
2029
2047
|
if (!elementType || !FORM_FIELD_ELEMENT_TYPES.has(elementType)) {
|
|
2030
2048
|
return false;
|
|
2031
2049
|
}
|
|
2032
|
-
|
|
2050
|
+
const containers = args.containers ?? [args.container];
|
|
2051
|
+
if (containers.some((container) => !isWithinForm(container))) {
|
|
2033
2052
|
handleBlockedFormField();
|
|
2034
2053
|
return true;
|
|
2035
2054
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -881,6 +881,16 @@ var useHasOverlapping = () => {
|
|
|
881
881
|
return hasOverlapping;
|
|
882
882
|
};
|
|
883
883
|
|
|
884
|
+
// src/utils/outline-offset-utils.ts
|
|
885
|
+
var THIN_ELEMENT_MAX_HEIGHT_PX = 1;
|
|
886
|
+
var SMALLER_OUTLINE_OFFSET_WIDGET_TYPES = /* @__PURE__ */ new Set(["e-form-input"]);
|
|
887
|
+
function shouldUseSmallerOutlineOffset(element, widgetType) {
|
|
888
|
+
if (element.offsetHeight <= THIN_ELEMENT_MAX_HEIGHT_PX) {
|
|
889
|
+
return true;
|
|
890
|
+
}
|
|
891
|
+
return widgetType !== void 0 && SMALLER_OUTLINE_OFFSET_WIDGET_TYPES.has(widgetType);
|
|
892
|
+
}
|
|
893
|
+
|
|
884
894
|
// src/components/outline-overlay.tsx
|
|
885
895
|
var CANVAS_WRAPPER_ID = "elementor-preview-responsive-wrapper";
|
|
886
896
|
var OverlayBox = styled(Box, {
|
|
@@ -892,12 +902,18 @@ var OverlayBox = styled(Box, {
|
|
|
892
902
|
pointerEvents: "none"
|
|
893
903
|
})
|
|
894
904
|
);
|
|
895
|
-
var OutlineOverlay = ({
|
|
905
|
+
var OutlineOverlay = ({
|
|
906
|
+
element,
|
|
907
|
+
isSelected,
|
|
908
|
+
id,
|
|
909
|
+
isGlobal = false,
|
|
910
|
+
widgetType
|
|
911
|
+
}) => {
|
|
896
912
|
const { context, floating, isVisible } = useFloatingOnElement({ element, isSelected });
|
|
897
913
|
const { getFloatingProps, getReferenceProps } = useInteractions([useHover(context)]);
|
|
898
914
|
const hasOverlapping = useHasOverlapping();
|
|
899
915
|
useBindReactPropsToElement(element, getReferenceProps);
|
|
900
|
-
const isSmallerOffset = element
|
|
916
|
+
const isSmallerOffset = shouldUseSmallerOutlineOffset(element, widgetType);
|
|
901
917
|
return isVisible && !hasOverlapping && /* @__PURE__ */ React.createElement(FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React.createElement(
|
|
902
918
|
OverlayBox,
|
|
903
919
|
{
|
|
@@ -1105,17 +1121,18 @@ function ElementsOverlays() {
|
|
|
1105
1121
|
if (!isActive) {
|
|
1106
1122
|
return null;
|
|
1107
1123
|
}
|
|
1108
|
-
return elements.map(({ id, domElement, isGlobal }) => {
|
|
1124
|
+
return elements.map(({ id, domElement, isGlobal, widgetType }) => {
|
|
1109
1125
|
const isSelected = selected.element?.id === id;
|
|
1110
1126
|
return overlayRegistry.map(
|
|
1111
|
-
({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected }) && /* @__PURE__ */ React7.createElement(
|
|
1127
|
+
({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected, widgetType }) && /* @__PURE__ */ React7.createElement(
|
|
1112
1128
|
Overlay,
|
|
1113
1129
|
{
|
|
1114
1130
|
key: `${id}-${index}`,
|
|
1115
1131
|
id,
|
|
1116
1132
|
element: domElement,
|
|
1117
1133
|
isSelected,
|
|
1118
|
-
isGlobal
|
|
1134
|
+
isGlobal,
|
|
1135
|
+
widgetType
|
|
1119
1136
|
}
|
|
1120
1137
|
)
|
|
1121
1138
|
);
|
|
@@ -1128,7 +1145,8 @@ function useElementsDom() {
|
|
|
1128
1145
|
return getElements().filter((el) => isV4Element(el.view?.el?.dataset)).map((element) => ({
|
|
1129
1146
|
id: element.id,
|
|
1130
1147
|
domElement: element.view?.getDomElement?.()?.get?.(0),
|
|
1131
|
-
isGlobal: element.model.get("isGlobal") ?? false
|
|
1148
|
+
isGlobal: element.model.get("isGlobal") ?? false,
|
|
1149
|
+
widgetType: element.model.get("widgetType")
|
|
1132
1150
|
})).filter((item) => !!item.domElement);
|
|
1133
1151
|
}
|
|
1134
1152
|
);
|
|
@@ -1983,7 +2001,8 @@ function blockFormFieldCreate(args) {
|
|
|
1983
2001
|
if (!elementType || !FORM_FIELD_ELEMENT_TYPES.has(elementType)) {
|
|
1984
2002
|
return false;
|
|
1985
2003
|
}
|
|
1986
|
-
|
|
2004
|
+
const containers = args.containers ?? [args.container];
|
|
2005
|
+
if (containers.some((container) => !isWithinForm(container))) {
|
|
1987
2006
|
handleBlockedFormField();
|
|
1988
2007
|
return true;
|
|
1989
2008
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-canvas",
|
|
3
3
|
"description": "Elementor Editor Canvas",
|
|
4
|
-
"version": "4.3.0-
|
|
4
|
+
"version": "4.3.0-977",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,26 +37,26 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor": "4.3.0-
|
|
41
|
-
"@elementor/editor-controls": "4.3.0-
|
|
42
|
-
"@elementor/editor-documents": "4.3.0-
|
|
43
|
-
"@elementor/editor-elements": "4.3.0-
|
|
44
|
-
"@elementor/editor-interactions": "4.3.0-
|
|
45
|
-
"@elementor/editor-mcp": "4.3.0-
|
|
46
|
-
"@elementor/editor-notifications": "4.3.0-
|
|
47
|
-
"@elementor/editor-props": "4.3.0-
|
|
48
|
-
"@elementor/editor-responsive": "4.3.0-
|
|
49
|
-
"@elementor/editor-styles": "4.3.0-
|
|
50
|
-
"@elementor/editor-styles-repository": "4.3.0-
|
|
51
|
-
"@elementor/editor-ui": "4.3.0-
|
|
52
|
-
"@elementor/editor-v1-adapters": "4.3.0-
|
|
53
|
-
"@elementor/events": "4.3.0-
|
|
54
|
-
"@elementor/http-client": "4.3.0-
|
|
55
|
-
"@elementor/schema": "4.3.0-
|
|
56
|
-
"@elementor/twing": "4.3.0-
|
|
40
|
+
"@elementor/editor": "4.3.0-977",
|
|
41
|
+
"@elementor/editor-controls": "4.3.0-977",
|
|
42
|
+
"@elementor/editor-documents": "4.3.0-977",
|
|
43
|
+
"@elementor/editor-elements": "4.3.0-977",
|
|
44
|
+
"@elementor/editor-interactions": "4.3.0-977",
|
|
45
|
+
"@elementor/editor-mcp": "4.3.0-977",
|
|
46
|
+
"@elementor/editor-notifications": "4.3.0-977",
|
|
47
|
+
"@elementor/editor-props": "4.3.0-977",
|
|
48
|
+
"@elementor/editor-responsive": "4.3.0-977",
|
|
49
|
+
"@elementor/editor-styles": "4.3.0-977",
|
|
50
|
+
"@elementor/editor-styles-repository": "4.3.0-977",
|
|
51
|
+
"@elementor/editor-ui": "4.3.0-977",
|
|
52
|
+
"@elementor/editor-v1-adapters": "4.3.0-977",
|
|
53
|
+
"@elementor/events": "4.3.0-977",
|
|
54
|
+
"@elementor/http-client": "4.3.0-977",
|
|
55
|
+
"@elementor/schema": "4.3.0-977",
|
|
56
|
+
"@elementor/twing": "4.3.0-977",
|
|
57
57
|
"@elementor/ui": "1.37.5",
|
|
58
|
-
"@elementor/utils": "4.3.0-
|
|
59
|
-
"@elementor/wp-media": "4.3.0-
|
|
58
|
+
"@elementor/utils": "4.3.0-977",
|
|
59
|
+
"@elementor/wp-media": "4.3.0-977",
|
|
60
60
|
"@floating-ui/react": "^0.27.5",
|
|
61
61
|
"@wordpress/i18n": "^5.13.0",
|
|
62
62
|
"dompurify": "^3.2.6"
|
|
@@ -45,18 +45,19 @@ export function ElementsOverlays() {
|
|
|
45
45
|
return null;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
return elements.map( ( { id, domElement, isGlobal } ) => {
|
|
48
|
+
return elements.map( ( { id, domElement, isGlobal, widgetType } ) => {
|
|
49
49
|
const isSelected = selected.element?.id === id;
|
|
50
50
|
|
|
51
51
|
return overlayRegistry.map(
|
|
52
52
|
( { shouldRender, component: Overlay }, index ) =>
|
|
53
|
-
shouldRender( { id, element: domElement, isSelected } ) && (
|
|
53
|
+
shouldRender( { id, element: domElement, isSelected, widgetType } ) && (
|
|
54
54
|
<Overlay
|
|
55
55
|
key={ `${ id }-${ index }` }
|
|
56
56
|
id={ id }
|
|
57
57
|
element={ domElement }
|
|
58
58
|
isSelected={ isSelected }
|
|
59
59
|
isGlobal={ isGlobal }
|
|
60
|
+
widgetType={ widgetType }
|
|
60
61
|
/>
|
|
61
62
|
)
|
|
62
63
|
);
|
|
@@ -67,18 +68,20 @@ type ElementData = {
|
|
|
67
68
|
id: string;
|
|
68
69
|
domElement: HTMLElement;
|
|
69
70
|
isGlobal: boolean;
|
|
71
|
+
widgetType: string | undefined;
|
|
70
72
|
};
|
|
71
73
|
|
|
72
|
-
function useElementsDom() {
|
|
74
|
+
function useElementsDom(): ElementData[] {
|
|
73
75
|
return useListenTo(
|
|
74
76
|
[ windowEvent( 'elementor/editor/element-rendered' ), windowEvent( 'elementor/editor/element-destroyed' ) ],
|
|
75
|
-
() => {
|
|
77
|
+
(): ElementData[] => {
|
|
76
78
|
return getElements()
|
|
77
79
|
.filter( ( el ) => isV4Element( el.view?.el?.dataset ) )
|
|
78
80
|
.map( ( element ) => ( {
|
|
79
81
|
id: element.id,
|
|
80
82
|
domElement: element.view?.getDomElement?.()?.get?.( 0 ),
|
|
81
83
|
isGlobal: element.model.get( 'isGlobal' ) ?? false,
|
|
84
|
+
widgetType: element.model.get( 'widgetType' ),
|
|
82
85
|
} ) )
|
|
83
86
|
.filter( ( item ): item is ElementData => !! item.domElement );
|
|
84
87
|
}
|
|
@@ -6,6 +6,7 @@ import { useBindReactPropsToElement } from '../hooks/use-bind-react-props-to-ele
|
|
|
6
6
|
import { useFloatingOnElement } from '../hooks/use-floating-on-element';
|
|
7
7
|
import { useHasOverlapping } from '../hooks/use-has-overlapping';
|
|
8
8
|
import type { ElementOverlayProps } from '../types/element-overlay';
|
|
9
|
+
import { shouldUseSmallerOutlineOffset } from '../utils/outline-offset-utils';
|
|
9
10
|
|
|
10
11
|
export const CANVAS_WRAPPER_ID = 'elementor-preview-responsive-wrapper';
|
|
11
12
|
|
|
@@ -25,13 +26,19 @@ const OverlayBox = styled( Box, {
|
|
|
25
26
|
} )
|
|
26
27
|
);
|
|
27
28
|
|
|
28
|
-
export const OutlineOverlay = ( {
|
|
29
|
+
export const OutlineOverlay = ( {
|
|
30
|
+
element,
|
|
31
|
+
isSelected,
|
|
32
|
+
id,
|
|
33
|
+
isGlobal = false,
|
|
34
|
+
widgetType,
|
|
35
|
+
}: Props ): React.ReactElement | false => {
|
|
29
36
|
const { context, floating, isVisible } = useFloatingOnElement( { element, isSelected } );
|
|
30
37
|
const { getFloatingProps, getReferenceProps } = useInteractions( [ useHover( context ) ] );
|
|
31
38
|
const hasOverlapping = useHasOverlapping();
|
|
32
39
|
|
|
33
40
|
useBindReactPropsToElement( element, getReferenceProps );
|
|
34
|
-
const isSmallerOffset = element
|
|
41
|
+
const isSmallerOffset = shouldUseSmallerOutlineOffset( element, widgetType );
|
|
35
42
|
|
|
36
43
|
return (
|
|
37
44
|
isVisible &&
|
|
@@ -48,7 +48,9 @@ function blockFormFieldCreate( args: CreateArgs ): boolean {
|
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
const containers = args.containers ?? [ args.container ];
|
|
52
|
+
|
|
53
|
+
if ( containers.some( ( container ) => ! isWithinForm( container ) ) ) {
|
|
52
54
|
handleBlockedFormField();
|
|
53
55
|
|
|
54
56
|
return true;
|
|
@@ -5,12 +5,14 @@ export type ElementOverlayProps = {
|
|
|
5
5
|
id: string;
|
|
6
6
|
isSelected: boolean;
|
|
7
7
|
isGlobal?: boolean;
|
|
8
|
+
widgetType?: string;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export type OverlayFilterArgs = {
|
|
11
12
|
id: string;
|
|
12
13
|
element: HTMLElement;
|
|
13
14
|
isSelected: boolean;
|
|
15
|
+
widgetType?: string;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export type ElementOverlayConfig = {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { shouldUseSmallerOutlineOffset, THIN_ELEMENT_MAX_HEIGHT_PX } from '../outline-offset-utils';
|
|
2
|
+
|
|
3
|
+
describe( 'shouldUseSmallerOutlineOffset', () => {
|
|
4
|
+
it( 'returns true for thin elements like dividers', () => {
|
|
5
|
+
// Arrange.
|
|
6
|
+
const element = document.createElement( 'hr' );
|
|
7
|
+
Object.defineProperty( element, 'offsetHeight', { value: THIN_ELEMENT_MAX_HEIGHT_PX } );
|
|
8
|
+
|
|
9
|
+
// Act.
|
|
10
|
+
const result = shouldUseSmallerOutlineOffset( element );
|
|
11
|
+
|
|
12
|
+
// Assert.
|
|
13
|
+
expect( result ).toBe( true );
|
|
14
|
+
} );
|
|
15
|
+
|
|
16
|
+
it( 'returns true for atomic form input widgets', () => {
|
|
17
|
+
// Arrange.
|
|
18
|
+
const element = document.createElement( 'input' );
|
|
19
|
+
Object.defineProperty( element, 'offsetHeight', { value: 36 } );
|
|
20
|
+
|
|
21
|
+
// Act.
|
|
22
|
+
const result = shouldUseSmallerOutlineOffset( element, 'e-form-input' );
|
|
23
|
+
|
|
24
|
+
// Assert.
|
|
25
|
+
expect( result ).toBe( true );
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
it( 'returns false for other atomic widgets', () => {
|
|
29
|
+
// Arrange.
|
|
30
|
+
const element = document.createElement( 'div' );
|
|
31
|
+
Object.defineProperty( element, 'offsetHeight', { value: 100 } );
|
|
32
|
+
|
|
33
|
+
// Act.
|
|
34
|
+
const result = shouldUseSmallerOutlineOffset( element, 'e-heading' );
|
|
35
|
+
|
|
36
|
+
// Assert.
|
|
37
|
+
expect( result ).toBe( false );
|
|
38
|
+
} );
|
|
39
|
+
} );
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const THIN_ELEMENT_MAX_HEIGHT_PX = 1;
|
|
2
|
+
|
|
3
|
+
export const SMALLER_OUTLINE_OFFSET_WIDGET_TYPES = new Set( [ 'e-form-input' ] );
|
|
4
|
+
|
|
5
|
+
export function shouldUseSmallerOutlineOffset( element: HTMLElement, widgetType?: string ): boolean {
|
|
6
|
+
if ( element.offsetHeight <= THIN_ELEMENT_MAX_HEIGHT_PX ) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return widgetType !== undefined && SMALLER_OUTLINE_OFFSET_WIDGET_TYPES.has( widgetType );
|
|
11
|
+
}
|