@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 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 = ({ element, isSelected, id, isGlobal = false }) => {
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.offsetHeight <= 1;
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
- if (!isWithinForm(args.container)) {
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 = ({ element, isSelected, id, isGlobal = false }) => {
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.offsetHeight <= 1;
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
- if (!isWithinForm(args.container)) {
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-975",
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-975",
41
- "@elementor/editor-controls": "4.3.0-975",
42
- "@elementor/editor-documents": "4.3.0-975",
43
- "@elementor/editor-elements": "4.3.0-975",
44
- "@elementor/editor-interactions": "4.3.0-975",
45
- "@elementor/editor-mcp": "4.3.0-975",
46
- "@elementor/editor-notifications": "4.3.0-975",
47
- "@elementor/editor-props": "4.3.0-975",
48
- "@elementor/editor-responsive": "4.3.0-975",
49
- "@elementor/editor-styles": "4.3.0-975",
50
- "@elementor/editor-styles-repository": "4.3.0-975",
51
- "@elementor/editor-ui": "4.3.0-975",
52
- "@elementor/editor-v1-adapters": "4.3.0-975",
53
- "@elementor/events": "4.3.0-975",
54
- "@elementor/http-client": "4.3.0-975",
55
- "@elementor/schema": "4.3.0-975",
56
- "@elementor/twing": "4.3.0-975",
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-975",
59
- "@elementor/wp-media": "4.3.0-975",
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 = ( { element, isSelected, id, isGlobal = false }: Props ): React.ReactElement | false => {
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.offsetHeight <= 1;
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
- if ( ! isWithinForm( args.container ) ) {
51
+ const containers = args.containers ?? [ args.container ];
52
+
53
+ if ( containers.some( ( container ) => ! isWithinForm( container ) ) ) {
52
54
  handleBlockedFormField();
53
55
 
54
56
  return true;
@@ -7,6 +7,7 @@ type Model = {
7
7
 
8
8
  export type CreateArgs = {
9
9
  container?: V1Element;
10
+ containers?: V1Element[];
10
11
  model?: Model;
11
12
  };
12
13
 
@@ -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
+ }