@elementor/editor-canvas 4.3.0-951 → 4.3.0-953

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.mjs CHANGED
@@ -384,12 +384,8 @@ import {
384
384
  windowEvent as windowEvent2
385
385
  } from "@elementor/editor-v1-adapters";
386
386
 
387
- // src/components/grid-outline/grid-outline-overlay.tsx
388
- import * as React6 from "react";
389
- import { useSelectedElementSettings } from "@elementor/editor-elements";
390
- import { booleanPropTypeUtil } from "@elementor/editor-props";
391
- import { Box as Box2 } from "@elementor/ui";
392
- import { FloatingPortal as FloatingPortal2 } from "@floating-ui/react";
387
+ // src/components/grid-outline/grid-empty-cell-positioner.tsx
388
+ import { useEffect as useEffect5 } from "react";
393
389
 
394
390
  // src/hooks/use-element-rect.ts
395
391
  import { useEffect as useEffect2, useState } from "react";
@@ -454,49 +450,8 @@ function useMutationsListener({ element, onChange }) {
454
450
  }, [element, onChange]);
455
451
  }
456
452
 
457
- // src/hooks/use-floating-on-element.ts
458
- import { useEffect as useEffect3, useState as useState2 } from "react";
459
- import { autoUpdate, offset, size, useFloating } from "@floating-ui/react";
460
- function useFloatingOnElement({ element, isSelected }) {
461
- const [isOpen, setIsOpen] = useState2(false);
462
- const sizeModifier = 2;
463
- const { refs, floatingStyles, context } = useFloating({
464
- // Must be controlled for interactions (like hover) to work.
465
- open: isOpen || isSelected,
466
- onOpenChange: setIsOpen,
467
- whileElementsMounted: autoUpdate,
468
- middleware: [
469
- // Match the floating element's size to the reference element.
470
- size(() => {
471
- return {
472
- apply({ elements, rects }) {
473
- Object.assign(elements.floating.style, {
474
- width: `${rects.reference.width + sizeModifier}px`,
475
- height: `${rects.reference.height + sizeModifier}px`
476
- });
477
- }
478
- };
479
- }),
480
- // Center the floating element on the reference element.
481
- offset(({ rects }) => -rects.reference.height / 2 - rects.floating.height / 2)
482
- ]
483
- });
484
- useEffect3(() => {
485
- refs.setReference(element);
486
- }, [element, refs]);
487
- return {
488
- isVisible: isOpen || isSelected,
489
- context,
490
- floating: {
491
- setRef: refs.setFloating,
492
- ref: refs.floating,
493
- styles: floatingStyles
494
- }
495
- };
496
- }
497
-
498
453
  // src/hooks/use-grid-tracks.ts
499
- import { useEffect as useEffect5, useState as useState4 } from "react";
454
+ import { useEffect as useEffect4, useState as useState3 } from "react";
500
455
  import { ELEMENT_STYLE_CHANGE_EVENT } from "@elementor/editor-elements";
501
456
  import { __privateUseListenTo as useListenTo, windowEvent } from "@elementor/editor-v1-adapters";
502
457
 
@@ -583,10 +538,10 @@ function toPx(value) {
583
538
  }
584
539
 
585
540
  // src/hooks/use-grid-children.ts
586
- import { useEffect as useEffect4, useState as useState3 } from "react";
541
+ import { useEffect as useEffect3, useState as useState2 } from "react";
587
542
  function useGridChildren(element) {
588
- const [signal, setSignal] = useState3(0);
589
- useEffect4(() => {
543
+ const [signal, setSignal] = useState2(0);
544
+ useEffect3(() => {
590
545
  if (!element) {
591
546
  return;
592
547
  }
@@ -633,13 +588,13 @@ var EMPTY = {
633
588
  };
634
589
  var DEVICE_MODE_CHANGE_EVENT = "elementor/device-mode/change";
635
590
  function useGridTracks(element, rect) {
636
- const [tracks, setTracks] = useState4(EMPTY);
591
+ const [tracks, setTracks] = useState3(EMPTY);
637
592
  const trigger = useListenTo(
638
593
  [windowEvent(ELEMENT_STYLE_CHANGE_EVENT), windowEvent(DEVICE_MODE_CHANGE_EVENT)],
639
594
  () => ({})
640
595
  );
641
596
  const childrenTrigger = useGridChildren(element);
642
- useEffect5(() => {
597
+ useEffect4(() => {
643
598
  const previewWindow = element?.ownerDocument?.defaultView;
644
599
  if (!element || !previewWindow) {
645
600
  setTracks(EMPTY);
@@ -655,98 +610,6 @@ function useGridTracks(element, rect) {
655
610
  return tracks;
656
611
  }
657
612
 
658
- // src/components/outline-overlay.tsx
659
- import * as React from "react";
660
- import { Box, styled } from "@elementor/ui";
661
- import { FloatingPortal, useHover, useInteractions } from "@floating-ui/react";
662
-
663
- // src/hooks/use-bind-react-props-to-element.ts
664
- import { useEffect as useEffect6 } from "react";
665
- function useBindReactPropsToElement(element, getProps) {
666
- useEffect6(() => {
667
- const el = element;
668
- const { events, attrs } = groupProps(getProps());
669
- events.forEach(([eventName, listener]) => el.addEventListener(eventName, listener));
670
- attrs.forEach(([attrName, attrValue]) => el.setAttribute(attrName, attrValue));
671
- return () => {
672
- events.forEach(([eventName, listener]) => el.removeEventListener(eventName, listener));
673
- attrs.forEach(([attrName]) => el.removeAttribute(attrName));
674
- };
675
- }, [getProps, element]);
676
- }
677
- function groupProps(props) {
678
- const eventRegex = /^on(?=[A-Z])/;
679
- return Object.entries(props).reduce(
680
- (acc, [propName, propValue]) => {
681
- if (!eventRegex.test(propName)) {
682
- acc.attrs.push([propName, propValue]);
683
- return acc;
684
- }
685
- const eventName = propName.replace(eventRegex, "").toLowerCase();
686
- const listener = propValue;
687
- acc.events.push([eventName, listener]);
688
- return acc;
689
- },
690
- {
691
- events: [],
692
- attrs: []
693
- }
694
- );
695
- }
696
-
697
- // src/hooks/use-has-overlapping.ts
698
- var possibleOverlappingSelectors = [".e-off-canvas"];
699
- var useHasOverlapping = () => {
700
- const preview = window.elementor?.$preview?.[0];
701
- if (!preview) {
702
- return false;
703
- }
704
- const hasOverlapping = possibleOverlappingSelectors.map((selector) => Array.from(preview?.contentWindow?.document.body.querySelectorAll(selector) ?? [])).flat().some(
705
- (elem) => elem.checkVisibility({
706
- opacityProperty: true,
707
- visibilityProperty: true,
708
- contentVisibilityAuto: true
709
- })
710
- );
711
- return hasOverlapping;
712
- };
713
-
714
- // src/components/outline-overlay.tsx
715
- var CANVAS_WRAPPER_ID = "elementor-preview-responsive-wrapper";
716
- var OverlayBox = styled(Box, {
717
- shouldForwardProp: (prop) => prop !== "isSelected" && prop !== "isSmallerOffset" && prop !== "isGlobal"
718
- })(
719
- ({ theme, isSelected, isSmallerOffset, isGlobal }) => ({
720
- outline: `${isSelected ? "2px" : "1px"} solid ${isGlobal ? theme.palette.global.main : theme.palette.primary.light}`,
721
- outlineOffset: isSelected && !isSmallerOffset ? "-2px" : "-1px",
722
- pointerEvents: "none"
723
- })
724
- );
725
- var OutlineOverlay = ({ element, isSelected, id, isGlobal = false }) => {
726
- const { context, floating, isVisible } = useFloatingOnElement({ element, isSelected });
727
- const { getFloatingProps, getReferenceProps } = useInteractions([useHover(context)]);
728
- const hasOverlapping = useHasOverlapping();
729
- useBindReactPropsToElement(element, getReferenceProps);
730
- const isSmallerOffset = element.offsetHeight <= 1;
731
- return isVisible && !hasOverlapping && /* @__PURE__ */ React.createElement(FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React.createElement(
732
- OverlayBox,
733
- {
734
- ref: floating.setRef,
735
- isSelected,
736
- isGlobal,
737
- style: floating.styles,
738
- "data-element-overlay": id,
739
- role: "presentation",
740
- isSmallerOffset,
741
- ...getFloatingProps()
742
- }
743
- ));
744
- };
745
-
746
- // src/components/grid-outline/grid-outline.tsx
747
- import * as React5 from "react";
748
- import { useMemo } from "react";
749
-
750
613
  // src/utils/find-first-empty-cell.ts
751
614
  function findFirstEmptyCell(element, columnCount, rowCount) {
752
615
  if (!element || columnCount === 0 || rowCount === 0) {
@@ -909,6 +772,179 @@ function scanFirstEmpty(matrix, flowsByColumn) {
909
772
  return null;
910
773
  }
911
774
 
775
+ // src/components/grid-outline/grid-empty-cell-positioner.tsx
776
+ var CSS_VAR_ROW = "--e-grid-empty-cell-row";
777
+ var CSS_VAR_COL = "--e-grid-empty-cell-col";
778
+ var CSS_VAR_VISIBILITY = "--e-grid-empty-cell-visibility";
779
+ var clearGridEmptyCellStyles = (target) => {
780
+ target.style.removeProperty(CSS_VAR_ROW);
781
+ target.style.removeProperty(CSS_VAR_COL);
782
+ target.style.removeProperty(CSS_VAR_VISIBILITY);
783
+ };
784
+ var GridEmptyCellPositioner = ({ element }) => {
785
+ const rect = useElementRect(element);
786
+ const tracks = useGridTracks(element, rect);
787
+ useEffect5(() => {
788
+ if (!element) {
789
+ return;
790
+ }
791
+ const firstEmpty = findFirstEmptyCell(element, tracks.columns.length, tracks.rows.length);
792
+ if (!firstEmpty) {
793
+ element.style.removeProperty(CSS_VAR_ROW);
794
+ element.style.removeProperty(CSS_VAR_COL);
795
+ element.style.setProperty(CSS_VAR_VISIBILITY, "hidden");
796
+ return () => clearGridEmptyCellStyles(element);
797
+ }
798
+ element.style.setProperty(CSS_VAR_ROW, String(firstEmpty.row + 1));
799
+ element.style.setProperty(CSS_VAR_COL, String(firstEmpty.col + 1));
800
+ element.style.setProperty(CSS_VAR_VISIBILITY, "visible");
801
+ return () => {
802
+ clearGridEmptyCellStyles(element);
803
+ };
804
+ }, [element, tracks]);
805
+ return null;
806
+ };
807
+
808
+ // src/components/grid-outline/grid-outline-overlay.tsx
809
+ import * as React6 from "react";
810
+ import { useSelectedElementSettings } from "@elementor/editor-elements";
811
+ import { booleanPropTypeUtil } from "@elementor/editor-props";
812
+ import { Box as Box2 } from "@elementor/ui";
813
+ import { FloatingPortal as FloatingPortal2 } from "@floating-ui/react";
814
+
815
+ // src/hooks/use-floating-on-element.ts
816
+ import { useEffect as useEffect6, useState as useState4 } from "react";
817
+ import { autoUpdate, offset, size, useFloating } from "@floating-ui/react";
818
+ function useFloatingOnElement({ element, isSelected }) {
819
+ const [isOpen, setIsOpen] = useState4(false);
820
+ const sizeModifier = 2;
821
+ const { refs, floatingStyles, context } = useFloating({
822
+ // Must be controlled for interactions (like hover) to work.
823
+ open: isOpen || isSelected,
824
+ onOpenChange: setIsOpen,
825
+ whileElementsMounted: autoUpdate,
826
+ middleware: [
827
+ // Match the floating element's size to the reference element.
828
+ size(() => {
829
+ return {
830
+ apply({ elements, rects }) {
831
+ Object.assign(elements.floating.style, {
832
+ width: `${rects.reference.width + sizeModifier}px`,
833
+ height: `${rects.reference.height + sizeModifier}px`
834
+ });
835
+ }
836
+ };
837
+ }),
838
+ // Center the floating element on the reference element.
839
+ offset(({ rects }) => -rects.reference.height / 2 - rects.floating.height / 2)
840
+ ]
841
+ });
842
+ useEffect6(() => {
843
+ refs.setReference(element);
844
+ }, [element, refs]);
845
+ return {
846
+ isVisible: isOpen || isSelected,
847
+ context,
848
+ floating: {
849
+ setRef: refs.setFloating,
850
+ ref: refs.floating,
851
+ styles: floatingStyles
852
+ }
853
+ };
854
+ }
855
+
856
+ // src/components/outline-overlay.tsx
857
+ import * as React from "react";
858
+ import { Box, styled } from "@elementor/ui";
859
+ import { FloatingPortal, useHover, useInteractions } from "@floating-ui/react";
860
+
861
+ // src/hooks/use-bind-react-props-to-element.ts
862
+ import { useEffect as useEffect7 } from "react";
863
+ function useBindReactPropsToElement(element, getProps) {
864
+ useEffect7(() => {
865
+ const el = element;
866
+ const { events, attrs } = groupProps(getProps());
867
+ events.forEach(([eventName, listener]) => el.addEventListener(eventName, listener));
868
+ attrs.forEach(([attrName, attrValue]) => el.setAttribute(attrName, attrValue));
869
+ return () => {
870
+ events.forEach(([eventName, listener]) => el.removeEventListener(eventName, listener));
871
+ attrs.forEach(([attrName]) => el.removeAttribute(attrName));
872
+ };
873
+ }, [getProps, element]);
874
+ }
875
+ function groupProps(props) {
876
+ const eventRegex = /^on(?=[A-Z])/;
877
+ return Object.entries(props).reduce(
878
+ (acc, [propName, propValue]) => {
879
+ if (!eventRegex.test(propName)) {
880
+ acc.attrs.push([propName, propValue]);
881
+ return acc;
882
+ }
883
+ const eventName = propName.replace(eventRegex, "").toLowerCase();
884
+ const listener = propValue;
885
+ acc.events.push([eventName, listener]);
886
+ return acc;
887
+ },
888
+ {
889
+ events: [],
890
+ attrs: []
891
+ }
892
+ );
893
+ }
894
+
895
+ // src/hooks/use-has-overlapping.ts
896
+ var possibleOverlappingSelectors = [".e-off-canvas"];
897
+ var useHasOverlapping = () => {
898
+ const preview = window.elementor?.$preview?.[0];
899
+ if (!preview) {
900
+ return false;
901
+ }
902
+ const hasOverlapping = possibleOverlappingSelectors.map((selector) => Array.from(preview?.contentWindow?.document.body.querySelectorAll(selector) ?? [])).flat().some(
903
+ (elem) => elem.checkVisibility({
904
+ opacityProperty: true,
905
+ visibilityProperty: true,
906
+ contentVisibilityAuto: true
907
+ })
908
+ );
909
+ return hasOverlapping;
910
+ };
911
+
912
+ // src/components/outline-overlay.tsx
913
+ var CANVAS_WRAPPER_ID = "elementor-preview-responsive-wrapper";
914
+ var OverlayBox = styled(Box, {
915
+ shouldForwardProp: (prop) => prop !== "isSelected" && prop !== "isSmallerOffset" && prop !== "isGlobal"
916
+ })(
917
+ ({ theme, isSelected, isSmallerOffset, isGlobal }) => ({
918
+ outline: `${isSelected ? "2px" : "1px"} solid ${isGlobal ? theme.palette.global.main : theme.palette.primary.light}`,
919
+ outlineOffset: isSelected && !isSmallerOffset ? "-2px" : "-1px",
920
+ pointerEvents: "none"
921
+ })
922
+ );
923
+ var OutlineOverlay = ({ element, isSelected, id, isGlobal = false }) => {
924
+ const { context, floating, isVisible } = useFloatingOnElement({ element, isSelected });
925
+ const { getFloatingProps, getReferenceProps } = useInteractions([useHover(context)]);
926
+ const hasOverlapping = useHasOverlapping();
927
+ useBindReactPropsToElement(element, getReferenceProps);
928
+ const isSmallerOffset = element.offsetHeight <= 1;
929
+ return isVisible && !hasOverlapping && /* @__PURE__ */ React.createElement(FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React.createElement(
930
+ OverlayBox,
931
+ {
932
+ ref: floating.setRef,
933
+ isSelected,
934
+ isGlobal,
935
+ style: floating.styles,
936
+ "data-element-overlay": id,
937
+ role: "presentation",
938
+ isSmallerOffset,
939
+ ...getFloatingProps()
940
+ }
941
+ ));
942
+ };
943
+
944
+ // src/components/grid-outline/grid-outline.tsx
945
+ import * as React5 from "react";
946
+ import { useMemo } from "react";
947
+
912
948
  // src/components/grid-outline/cell.tsx
913
949
  import * as React2 from "react";
914
950
  var FALLBACK_COLOR = "rgba(0, 0, 0, 0.12)";
@@ -1016,6 +1052,13 @@ var renderLines = (tracks, width, height) => {
1016
1052
  ))
1017
1053
  ];
1018
1054
  };
1055
+ var isDragActiveFromDom = (element) => {
1056
+ return Boolean(
1057
+ element?.querySelector(
1058
+ ".e-dragging-over, .elementor-dragging-on-child, .elementor-draggable-over, .elementor-widget-placeholder, .elementor-sortable-placeholder"
1059
+ )
1060
+ );
1061
+ };
1019
1062
  function GridOutline({ element, tracks, width, height }) {
1020
1063
  const cells = useMemo(() => computeCellRects(tracks, width, height), [tracks, width, height]);
1021
1064
  const hasGap = tracks.columnGap > 0 || tracks.rowGap > 0;
@@ -1033,7 +1076,7 @@ function GridOutline({ element, tracks, width, height }) {
1033
1076
  xmlns: "http://www.w3.org/2000/svg"
1034
1077
  },
1035
1078
  hasGap ? renderCells(cells, tracks.borderColor) : renderLines(tracks, width, height)
1036
- ), emptyCellRect && /* @__PURE__ */ React5.createElement(FirstEmptyCell, { rect: emptyCellRect, color: tracks.borderColor }));
1079
+ ), emptyCellRect && !isDragActiveFromDom(element) && /* @__PURE__ */ React5.createElement(FirstEmptyCell, { rect: emptyCellRect, color: tracks.borderColor }));
1037
1080
  }
1038
1081
 
1039
1082
  // src/components/grid-outline/grid-outline-overlay.tsx
@@ -1063,14 +1106,20 @@ var GridOutlineOverlay = ({ element, id, isSelected }) => {
1063
1106
 
1064
1107
  // src/components/elements-overlays.tsx
1065
1108
  var ELEMENTS_DATA_ATTR = "atomic";
1109
+ var E_GRID_TYPE = "e-grid";
1110
+ var isGridElement = (element) => [element.dataset.eType, element.dataset.element_type].includes(E_GRID_TYPE);
1066
1111
  var overlayRegistry = [
1067
1112
  {
1068
1113
  component: OutlineOverlay,
1069
1114
  shouldRender: () => true
1070
1115
  },
1116
+ {
1117
+ component: GridEmptyCellPositioner,
1118
+ shouldRender: ({ element }) => isGridElement(element)
1119
+ },
1071
1120
  {
1072
1121
  component: GridOutlineOverlay,
1073
- shouldRender: ({ element, isSelected }) => isSelected && element.dataset.eType === "e-grid"
1122
+ shouldRender: ({ element, isSelected }) => isSelected && isGridElement(element)
1074
1123
  }
1075
1124
  ];
1076
1125
  function ElementsOverlays() {
@@ -1128,15 +1177,15 @@ import {
1128
1177
  import { Portal } from "@elementor/ui";
1129
1178
 
1130
1179
  // src/hooks/use-interactions-items.ts
1131
- import { useEffect as useEffect8, useMemo as useMemo2, useState as useState5 } from "react";
1180
+ import { useEffect as useEffect9, useMemo as useMemo2, useState as useState5 } from "react";
1132
1181
  import { interactionsRepository } from "@elementor/editor-interactions";
1133
1182
  import { registerDataHook } from "@elementor/editor-v1-adapters";
1134
1183
 
1135
1184
  // src/hooks/use-on-mount.ts
1136
- import { useEffect as useEffect7, useRef } from "react";
1185
+ import { useEffect as useEffect8, useRef } from "react";
1137
1186
  function useOnMount(cb) {
1138
1187
  const mounted = useRef(false);
1139
- useEffect7(() => {
1188
+ useEffect8(() => {
1140
1189
  if (!mounted.current) {
1141
1190
  mounted.current = true;
1142
1191
  cb();
@@ -1164,7 +1213,7 @@ function useInteractionsItems() {
1164
1213
  return [];
1165
1214
  }
1166
1215
  }, []);
1167
- useEffect8(() => {
1216
+ useEffect9(() => {
1168
1217
  if (providerAndSubscribers.length === 0) {
1169
1218
  return;
1170
1219
  }
@@ -1301,7 +1350,7 @@ function getLinkAttrs(el) {
1301
1350
  }
1302
1351
 
1303
1352
  // src/hooks/use-style-items.ts
1304
- import { useEffect as useEffect9, useMemo as useMemo5, useRef as useRef2, useState as useState6 } from "react";
1353
+ import { useEffect as useEffect10, useMemo as useMemo5, useRef as useRef2, useState as useState6 } from "react";
1305
1354
  import { useBreakpoints } from "@elementor/editor-responsive";
1306
1355
  import { isClassState } from "@elementor/editor-styles";
1307
1356
  import { stylesRepository as stylesRepository2 } from "@elementor/editor-styles-repository";
@@ -1679,7 +1728,7 @@ function useStyleItems() {
1679
1728
  })
1680
1729
  );
1681
1730
  }, [renderStyles]);
1682
- useEffect9(() => {
1731
+ useEffect10(() => {
1683
1732
  const unsubscribes = providerAndSubscribers.map(
1684
1733
  ({ provider, subscriber }) => provider.subscribe(subscriber)
1685
1734
  );
@@ -3387,13 +3436,13 @@ var ReplacementBase = class {
3387
3436
 
3388
3437
  // src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
3389
3438
  import * as React10 from "react";
3390
- import { useCallback as useCallback2, useEffect as useEffect11, useLayoutEffect, useState as useState8 } from "react";
3439
+ import { useCallback as useCallback2, useEffect as useEffect12, useLayoutEffect, useState as useState8 } from "react";
3391
3440
  import { InlineEditor, InlineEditorToolbar } from "@elementor/editor-controls";
3392
3441
  import { Box as Box3, ThemeProvider } from "@elementor/ui";
3393
3442
  import { autoUpdate as autoUpdate2, flip, FloatingPortal as FloatingPortal3, useFloating as useFloating2 } from "@floating-ui/react";
3394
3443
 
3395
3444
  // src/legacy/replacements/inline-editing/inline-editing-utils.ts
3396
- import { useCallback, useEffect as useEffect10, useState as useState7 } from "react";
3445
+ import { useCallback, useEffect as useEffect11, useState as useState7 } from "react";
3397
3446
  var TOP_BAR_SELECTOR = "#elementor-editor-wrapper-v2";
3398
3447
  var NAVIGATOR_SELECTOR = "#elementor-navigator";
3399
3448
  var EDITING_PANEL = "#elementor-panel";
@@ -3425,7 +3474,7 @@ var getInlineEditorElement = (elementWrapper, expectedTag) => {
3425
3474
  };
3426
3475
  var useOnClickOutsideIframe = (handleUnmount) => {
3427
3476
  const asyncUnmountInlineEditor = useCallback(() => queueMicrotask(handleUnmount), [handleUnmount]);
3428
- useEffect10(() => {
3477
+ useEffect11(() => {
3429
3478
  EDITOR_ELEMENTS_OUT_OF_IFRAME.forEach(
3430
3479
  (selector) => document?.querySelector(selector)?.addEventListener("mousedown", asyncUnmountInlineEditor)
3431
3480
  );
@@ -3436,7 +3485,7 @@ var useOnClickOutsideIframe = (handleUnmount) => {
3436
3485
  };
3437
3486
  var useRenderToolbar = (ownerDocument, id) => {
3438
3487
  const [anchor, setAnchor] = useState7(null);
3439
- useEffect10(() => {
3488
+ useEffect11(() => {
3440
3489
  if (!anchor) {
3441
3490
  removeToolbarAnchor(ownerDocument, id);
3442
3491
  }
@@ -3533,7 +3582,7 @@ var CanvasInlineEditor = ({
3533
3582
  const [active, setActive] = useState8(true);
3534
3583
  const [editor, setEditor] = useState8(null);
3535
3584
  const { onSelectionEnd, anchor: toolbarAnchor, clearAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
3536
- useEffect11(() => {
3585
+ useEffect12(() => {
3537
3586
  if (!active) {
3538
3587
  clearAnchor();
3539
3588
  requestDestroy();
@@ -3544,7 +3593,7 @@ var CanvasInlineEditor = ({
3544
3593
  setActive(false);
3545
3594
  }, []);
3546
3595
  useOnClickOutsideIframe(dismiss);
3547
- useEffect11(() => {
3596
+ useEffect12(() => {
3548
3597
  const ownerDocument = contentElement.ownerDocument;
3549
3598
  const handleClickAway = (event) => {
3550
3599
  if (contentElement.contains(event.target)) {
@@ -3584,7 +3633,7 @@ var InlineEditingOverlay = ({
3584
3633
  }) => {
3585
3634
  const inlineEditedElement = getInlineEditorElement(rootElement, expectedTag);
3586
3635
  const [overlayRefElement, setOverlayElement] = useState8(inlineEditedElement);
3587
- useEffect11(() => {
3636
+ useEffect12(() => {
3588
3637
  setOverlayElement(getInlineEditorElement(rootElement, expectedTag));
3589
3638
  }, [expectedTag, rootElement]);
3590
3639
  return overlayRefElement ? /* @__PURE__ */ React10.createElement(OutlineOverlay, { element: overlayRefElement, id, isSelected: true }) : null;
@@ -6563,9 +6612,9 @@ function useCanvasDocument() {
6563
6612
  }
6564
6613
 
6565
6614
  // src/hooks/use-escape-on-canvas.ts
6566
- import { useEffect as useEffect12 } from "react";
6615
+ import { useEffect as useEffect13 } from "react";
6567
6616
  function useEscapeOnCanvas(canvasDocument, onEscape) {
6568
- useEffect12(() => {
6617
+ useEffect13(() => {
6569
6618
  if (!canvasDocument) {
6570
6619
  return;
6571
6620
  }
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-951",
4
+ "version": "4.3.0-953",
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-951",
41
- "@elementor/editor-controls": "4.3.0-951",
42
- "@elementor/editor-documents": "4.3.0-951",
43
- "@elementor/editor-elements": "4.3.0-951",
44
- "@elementor/editor-interactions": "4.3.0-951",
45
- "@elementor/editor-mcp": "4.3.0-951",
46
- "@elementor/editor-notifications": "4.3.0-951",
47
- "@elementor/editor-props": "4.3.0-951",
48
- "@elementor/editor-responsive": "4.3.0-951",
49
- "@elementor/editor-styles": "4.3.0-951",
50
- "@elementor/editor-styles-repository": "4.3.0-951",
51
- "@elementor/editor-ui": "4.3.0-951",
52
- "@elementor/editor-v1-adapters": "4.3.0-951",
53
- "@elementor/events": "4.3.0-951",
54
- "@elementor/http-client": "4.3.0-951",
55
- "@elementor/schema": "4.3.0-951",
56
- "@elementor/twing": "4.3.0-951",
40
+ "@elementor/editor": "4.3.0-953",
41
+ "@elementor/editor-controls": "4.3.0-953",
42
+ "@elementor/editor-documents": "4.3.0-953",
43
+ "@elementor/editor-elements": "4.3.0-953",
44
+ "@elementor/editor-interactions": "4.3.0-953",
45
+ "@elementor/editor-mcp": "4.3.0-953",
46
+ "@elementor/editor-notifications": "4.3.0-953",
47
+ "@elementor/editor-props": "4.3.0-953",
48
+ "@elementor/editor-responsive": "4.3.0-953",
49
+ "@elementor/editor-styles": "4.3.0-953",
50
+ "@elementor/editor-styles-repository": "4.3.0-953",
51
+ "@elementor/editor-ui": "4.3.0-953",
52
+ "@elementor/editor-v1-adapters": "4.3.0-953",
53
+ "@elementor/events": "4.3.0-953",
54
+ "@elementor/http-client": "4.3.0-953",
55
+ "@elementor/schema": "4.3.0-953",
56
+ "@elementor/twing": "4.3.0-953",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.3.0-951",
59
- "@elementor/wp-media": "4.3.0-951",
58
+ "@elementor/utils": "4.3.0-953",
59
+ "@elementor/wp-media": "4.3.0-953",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -8,19 +8,27 @@ import {
8
8
  } from '@elementor/editor-v1-adapters';
9
9
 
10
10
  import type { ElementOverlayConfig } from '../types/element-overlay';
11
- import { GridOutlineOverlay } from './grid-outline';
11
+ import { GridEmptyCellPositioner, GridOutlineOverlay } from './grid-outline';
12
12
  import { OutlineOverlay } from './outline-overlay';
13
13
 
14
14
  const ELEMENTS_DATA_ATTR = 'atomic';
15
+ const E_GRID_TYPE = 'e-grid';
16
+
17
+ const isGridElement = ( element: HTMLElement ): boolean =>
18
+ [ element.dataset.eType, element.dataset.element_type ].includes( E_GRID_TYPE );
15
19
 
16
20
  const overlayRegistry: ElementOverlayConfig[] = [
17
21
  {
18
22
  component: OutlineOverlay,
19
23
  shouldRender: () => true,
20
24
  },
25
+ {
26
+ component: GridEmptyCellPositioner,
27
+ shouldRender: ( { element } ) => isGridElement( element ),
28
+ },
21
29
  {
22
30
  component: GridOutlineOverlay,
23
- shouldRender: ( { element, isSelected } ) => isSelected && element.dataset.eType === 'e-grid',
31
+ shouldRender: ( { element, isSelected } ) => isSelected && isGridElement( element ),
24
32
  },
25
33
  ];
26
34
 
@@ -0,0 +1,46 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import { useElementRect } from '../../hooks/use-element-rect';
4
+ import { useGridTracks } from '../../hooks/use-grid-tracks';
5
+ import type { ElementOverlayProps } from '../../types/element-overlay';
6
+ import { findFirstEmptyCell } from '../../utils/find-first-empty-cell';
7
+
8
+ const CSS_VAR_ROW = '--e-grid-empty-cell-row';
9
+ const CSS_VAR_COL = '--e-grid-empty-cell-col';
10
+ const CSS_VAR_VISIBILITY = '--e-grid-empty-cell-visibility';
11
+
12
+ const clearGridEmptyCellStyles = ( target: HTMLElement ): void => {
13
+ target.style.removeProperty( CSS_VAR_ROW );
14
+ target.style.removeProperty( CSS_VAR_COL );
15
+ target.style.removeProperty( CSS_VAR_VISIBILITY );
16
+ };
17
+
18
+ export const GridEmptyCellPositioner = ( { element }: ElementOverlayProps ): null => {
19
+ const rect = useElementRect( element );
20
+ const tracks = useGridTracks( element, rect );
21
+
22
+ useEffect( () => {
23
+ if ( ! element ) {
24
+ return;
25
+ }
26
+
27
+ const firstEmpty = findFirstEmptyCell( element, tracks.columns.length, tracks.rows.length );
28
+
29
+ if ( ! firstEmpty ) {
30
+ element.style.removeProperty( CSS_VAR_ROW );
31
+ element.style.removeProperty( CSS_VAR_COL );
32
+ element.style.setProperty( CSS_VAR_VISIBILITY, 'hidden' );
33
+ return () => clearGridEmptyCellStyles( element );
34
+ }
35
+
36
+ element.style.setProperty( CSS_VAR_ROW, String( firstEmpty.row + 1 ) );
37
+ element.style.setProperty( CSS_VAR_COL, String( firstEmpty.col + 1 ) );
38
+ element.style.setProperty( CSS_VAR_VISIBILITY, 'visible' );
39
+
40
+ return () => {
41
+ clearGridEmptyCellStyles( element );
42
+ };
43
+ }, [ element, tracks ] );
44
+
45
+ return null;
46
+ };