@elementor/editor-canvas 4.2.0-898 → 4.2.0-900

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
@@ -356,7 +356,7 @@ var renameClass = (oldClassName, newClassName) => {
356
356
  };
357
357
 
358
358
  // src/components/elements-overlays.tsx
359
- import * as React2 from "react";
359
+ import * as React5 from "react";
360
360
  import { getElements, useSelectedElement } from "@elementor/editor-elements";
361
361
  import {
362
362
  __privateUseIsRouteActive as useIsRouteActive,
@@ -365,50 +365,81 @@ import {
365
365
  windowEvent
366
366
  } from "@elementor/editor-v1-adapters";
367
367
 
368
- // src/components/outline-overlay.tsx
369
- import * as React from "react";
370
- import { Box, styled } from "@elementor/ui";
371
- import { FloatingPortal, useHover, useInteractions } from "@floating-ui/react";
368
+ // src/components/grid-outline/grid-outline-overlay.tsx
369
+ import * as React4 from "react";
370
+ import { useSelectedElementSettings } from "@elementor/editor-elements";
371
+ import { booleanPropTypeUtil } from "@elementor/editor-props";
372
+ import { Box as Box2 } from "@elementor/ui";
373
+ import { FloatingPortal as FloatingPortal2 } from "@floating-ui/react";
372
374
 
373
- // src/hooks/use-bind-react-props-to-element.ts
374
- import { useEffect as useEffect2 } from "react";
375
- function useBindReactPropsToElement(element, getProps) {
375
+ // src/hooks/use-element-rect.ts
376
+ import { useEffect as useEffect2, useState } from "react";
377
+ import { throttle } from "@elementor/utils";
378
+ function useElementRect(element) {
379
+ const [rect, setRect] = useState(new DOMRect(0, 0, 0, 0));
380
+ const onChange = throttle(
381
+ () => {
382
+ setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
383
+ },
384
+ 20,
385
+ true
386
+ );
387
+ useScrollListener({ element, onChange });
388
+ useResizeListener({ element, onChange });
389
+ useMutationsListener({ element, onChange });
390
+ useEffect2(
391
+ () => () => {
392
+ onChange.cancel();
393
+ },
394
+ [onChange]
395
+ );
396
+ return rect;
397
+ }
398
+ function useScrollListener({ element, onChange }) {
376
399
  useEffect2(() => {
377
- const el = element;
378
- const { events, attrs } = groupProps(getProps());
379
- events.forEach(([eventName, listener]) => el.addEventListener(eventName, listener));
380
- attrs.forEach(([attrName, attrValue]) => el.setAttribute(attrName, attrValue));
400
+ if (!element) {
401
+ return;
402
+ }
403
+ const win = element.ownerDocument?.defaultView;
404
+ win?.addEventListener("scroll", onChange, { passive: true });
381
405
  return () => {
382
- events.forEach(([eventName, listener]) => el.removeEventListener(eventName, listener));
383
- attrs.forEach(([attrName]) => el.removeAttribute(attrName));
406
+ win?.removeEventListener("scroll", onChange);
384
407
  };
385
- }, [getProps, element]);
408
+ }, [element, onChange]);
386
409
  }
387
- function groupProps(props) {
388
- const eventRegex = /^on(?=[A-Z])/;
389
- return Object.entries(props).reduce(
390
- (acc, [propName, propValue]) => {
391
- if (!eventRegex.test(propName)) {
392
- acc.attrs.push([propName, propValue]);
393
- return acc;
394
- }
395
- const eventName = propName.replace(eventRegex, "").toLowerCase();
396
- const listener = propValue;
397
- acc.events.push([eventName, listener]);
398
- return acc;
399
- },
400
- {
401
- events: [],
402
- attrs: []
410
+ function useResizeListener({ element, onChange }) {
411
+ useEffect2(() => {
412
+ if (!element) {
413
+ return;
403
414
  }
404
- );
415
+ const resizeObserver = new ResizeObserver(onChange);
416
+ resizeObserver.observe(element);
417
+ const win = element.ownerDocument?.defaultView;
418
+ win?.addEventListener("resize", onChange, { passive: true });
419
+ return () => {
420
+ resizeObserver.disconnect();
421
+ win?.removeEventListener("resize", onChange);
422
+ };
423
+ }, [element, onChange]);
424
+ }
425
+ function useMutationsListener({ element, onChange }) {
426
+ useEffect2(() => {
427
+ if (!element) {
428
+ return;
429
+ }
430
+ const mutationObserver = new MutationObserver(onChange);
431
+ mutationObserver.observe(element, { childList: true, subtree: true });
432
+ return () => {
433
+ mutationObserver.disconnect();
434
+ };
435
+ }, [element, onChange]);
405
436
  }
406
437
 
407
438
  // src/hooks/use-floating-on-element.ts
408
- import { useEffect as useEffect3, useState } from "react";
439
+ import { useEffect as useEffect3, useState as useState2 } from "react";
409
440
  import { autoUpdate, offset, size, useFloating } from "@floating-ui/react";
410
441
  function useFloatingOnElement({ element, isSelected }) {
411
- const [isOpen, setIsOpen] = useState(false);
442
+ const [isOpen, setIsOpen] = useState2(false);
412
443
  const sizeModifier = 2;
413
444
  const { refs, floatingStyles, context } = useFloating({
414
445
  // Must be controlled for interactions (like hover) to work.
@@ -445,6 +476,128 @@ function useFloatingOnElement({ element, isSelected }) {
445
476
  };
446
477
  }
447
478
 
479
+ // src/hooks/use-grid-tracks.ts
480
+ import { useMemo } from "react";
481
+
482
+ // src/utils/grid-outline-utils.ts
483
+ function computeOutlineGeometry(tracks, width, height) {
484
+ const { columns, rows, columnGap, rowGap, padding } = tracks;
485
+ return {
486
+ vertical: computeBoundaries(columns, columnGap, padding.left),
487
+ horizontal: computeBoundaries(rows, rowGap, padding.top),
488
+ top: padding.top,
489
+ bottom: height - padding.bottom,
490
+ left: padding.left,
491
+ right: width - padding.right
492
+ };
493
+ }
494
+ function computeBoundaries(sizes, gap, offset2) {
495
+ if (sizes.length === 0) {
496
+ return [];
497
+ }
498
+ const boundaries = [];
499
+ let cursor = offset2;
500
+ for (let i = 0; i < sizes.length; i++) {
501
+ if (i === 0) {
502
+ boundaries.push(cursor);
503
+ }
504
+ cursor += sizes[i];
505
+ boundaries.push(cursor);
506
+ if (i < sizes.length - 1 && gap > 0) {
507
+ cursor += gap;
508
+ boundaries.push(cursor);
509
+ }
510
+ }
511
+ return boundaries;
512
+ }
513
+ function snapToHalfPixel(value) {
514
+ return Math.round(value) + 0.5;
515
+ }
516
+ function parseTrackList(value) {
517
+ if (!value || value === "none") {
518
+ return [];
519
+ }
520
+ return value.trim().split(/\s+/).map(toPx).filter((n) => n > 0);
521
+ }
522
+ function toPx(value) {
523
+ const parsed = parseFloat(value);
524
+ return Number.isFinite(parsed) ? parsed : 0;
525
+ }
526
+
527
+ // src/hooks/use-grid-tracks.ts
528
+ var EMPTY = {
529
+ columns: [],
530
+ rows: [],
531
+ columnGap: 0,
532
+ rowGap: 0,
533
+ padding: { top: 0, right: 0, bottom: 0, left: 0 },
534
+ borderColor: ""
535
+ };
536
+ function useGridTracks(element, rect) {
537
+ return useMemo(() => {
538
+ if (!element) {
539
+ return EMPTY;
540
+ }
541
+ const previewWindow = element.ownerDocument?.defaultView;
542
+ if (!previewWindow) {
543
+ return EMPTY;
544
+ }
545
+ const computedStyle = previewWindow.getComputedStyle(element);
546
+ return {
547
+ columns: parseTrackList(computedStyle.gridTemplateColumns),
548
+ rows: parseTrackList(computedStyle.gridTemplateRows),
549
+ columnGap: toPx(computedStyle.columnGap),
550
+ rowGap: toPx(computedStyle.rowGap),
551
+ padding: {
552
+ top: toPx(computedStyle.paddingTop),
553
+ right: toPx(computedStyle.paddingRight),
554
+ bottom: toPx(computedStyle.paddingBottom),
555
+ left: toPx(computedStyle.paddingLeft)
556
+ },
557
+ borderColor: computedStyle.getPropertyValue("--e-a-border-color-bold").trim()
558
+ };
559
+ }, [element, rect.width, rect.height]);
560
+ }
561
+
562
+ // src/components/outline-overlay.tsx
563
+ import * as React from "react";
564
+ import { Box, styled } from "@elementor/ui";
565
+ import { FloatingPortal, useHover, useInteractions } from "@floating-ui/react";
566
+
567
+ // src/hooks/use-bind-react-props-to-element.ts
568
+ import { useEffect as useEffect4 } from "react";
569
+ function useBindReactPropsToElement(element, getProps) {
570
+ useEffect4(() => {
571
+ const el = element;
572
+ const { events, attrs } = groupProps(getProps());
573
+ events.forEach(([eventName, listener]) => el.addEventListener(eventName, listener));
574
+ attrs.forEach(([attrName, attrValue]) => el.setAttribute(attrName, attrValue));
575
+ return () => {
576
+ events.forEach(([eventName, listener]) => el.removeEventListener(eventName, listener));
577
+ attrs.forEach(([attrName]) => el.removeAttribute(attrName));
578
+ };
579
+ }, [getProps, element]);
580
+ }
581
+ function groupProps(props) {
582
+ const eventRegex = /^on(?=[A-Z])/;
583
+ return Object.entries(props).reduce(
584
+ (acc, [propName, propValue]) => {
585
+ if (!eventRegex.test(propName)) {
586
+ acc.attrs.push([propName, propValue]);
587
+ return acc;
588
+ }
589
+ const eventName = propName.replace(eventRegex, "").toLowerCase();
590
+ const listener = propValue;
591
+ acc.events.push([eventName, listener]);
592
+ return acc;
593
+ },
594
+ {
595
+ events: [],
596
+ attrs: []
597
+ }
598
+ );
599
+ }
600
+
448
601
  // src/hooks/use-has-overlapping.ts
449
602
  var possibleOverlappingSelectors = [".e-off-canvas"];
450
603
  var useHasOverlapping = () => {
@@ -494,12 +647,100 @@ var OutlineOverlay = ({ element, isSelected, id, isGlobal = false }) => {
494
647
  ));
495
648
  };
496
649
 
650
+ // src/components/grid-outline/grid-outline.tsx
651
+ import * as React3 from "react";
652
+
653
+ // src/components/grid-outline/grid-outline-line.tsx
654
+ import * as React2 from "react";
655
+ var FALLBACK_COLOR = "rgba(0, 0, 0, 0.12)";
656
+ var DASH = "2 2";
657
+ function GridOutlineLine({ x1, x2, y1, y2, color }) {
658
+ return /* @__PURE__ */ React2.createElement(
659
+ "line",
660
+ {
661
+ x1,
662
+ x2,
663
+ y1,
664
+ y2,
665
+ stroke: color || FALLBACK_COLOR,
666
+ strokeWidth: 1,
667
+ strokeDasharray: DASH,
668
+ vectorEffect: "non-scaling-stroke"
669
+ }
670
+ );
671
+ }
672
+
673
+ // src/components/grid-outline/grid-outline.tsx
674
+ function GridOutline({ tracks, width, height }) {
675
+ const { vertical, horizontal, top, bottom, left, right } = computeOutlineGeometry(tracks, width, height);
676
+ return /* @__PURE__ */ React3.createElement(
677
+ "svg",
678
+ {
679
+ width,
680
+ height,
681
+ style: { position: "absolute", inset: 0, overflow: "visible" },
682
+ xmlns: "http://www.w3.org/2000/svg"
683
+ },
684
+ vertical.map((x, i) => /* @__PURE__ */ React3.createElement(
685
+ GridOutlineLine,
686
+ {
687
+ key: `v-${i}`,
688
+ x1: snapToHalfPixel(x),
689
+ x2: snapToHalfPixel(x),
690
+ y1: top,
691
+ y2: bottom,
692
+ color: tracks.borderColor
693
+ }
694
+ )),
695
+ horizontal.map((y, i) => /* @__PURE__ */ React3.createElement(
696
+ GridOutlineLine,
697
+ {
698
+ key: `h-${i}`,
699
+ x1: left,
700
+ x2: right,
701
+ y1: snapToHalfPixel(y),
702
+ y2: snapToHalfPixel(y),
703
+ color: tracks.borderColor
704
+ }
705
+ ))
706
+ );
707
+ }
708
+
709
+ // src/components/grid-outline/grid-outline-overlay.tsx
710
+ var GridOutlineOverlay = ({ element, id, isSelected }) => {
711
+ const { settings } = useSelectedElementSettings();
712
+ const enabled = booleanPropTypeUtil.extract(settings?.grid_outline);
713
+ const rect = useElementRect(element);
714
+ const tracks = useGridTracks(element, rect);
715
+ const { floating } = useFloatingOnElement({ element, isSelected });
716
+ if (enabled === false) {
717
+ return null;
718
+ }
719
+ if (tracks.columns.length === 0 && tracks.rows.length === 0) {
720
+ return null;
721
+ }
722
+ return /* @__PURE__ */ React4.createElement(FloatingPortal2, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React4.createElement(
723
+ Box2,
724
+ {
725
+ ref: floating.setRef,
726
+ style: { ...floating.styles, pointerEvents: "none" },
727
+ "data-grid-outline": id,
728
+ role: "presentation"
729
+ },
730
+ /* @__PURE__ */ React4.createElement(GridOutline, { tracks, width: rect.width, height: rect.height })
731
+ ));
732
+ };
733
+
497
734
  // src/components/elements-overlays.tsx
498
735
  var ELEMENTS_DATA_ATTR = "atomic";
499
736
  var overlayRegistry = [
500
737
  {
501
738
  component: OutlineOverlay,
502
739
  shouldRender: () => true
740
+ },
741
+ {
742
+ component: GridOutlineOverlay,
743
+ shouldRender: ({ element, isSelected }) => isSelected && element.dataset.eType === "e-grid"
503
744
  }
504
745
  ];
505
746
  function ElementsOverlays() {
@@ -515,7 +756,7 @@ function ElementsOverlays() {
515
756
  return elements.map(({ id, domElement, isGlobal }) => {
516
757
  const isSelected = selected.element?.id === id;
517
758
  return overlayRegistry.map(
518
- ({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected }) && /* @__PURE__ */ React2.createElement(
759
+ ({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected }) && /* @__PURE__ */ React5.createElement(
519
760
  Overlay,
520
761
  {
521
762
  key: `${id}-${index}`,
@@ -532,7 +773,7 @@ function useElementsDom() {
532
773
  return useListenTo(
533
774
  [windowEvent("elementor/editor/element-rendered"), windowEvent("elementor/editor/element-destroyed")],
534
775
  () => {
535
- return getElements().filter((el) => ELEMENTS_DATA_ATTR in (el.view?.el?.dataset ?? {})).map((element) => ({
776
+ return getElements().filter((el) => isV4Element(el.view?.el?.dataset)).map((element) => ({
536
777
  id: element.id,
537
778
  domElement: element.view?.getDomElement?.()?.get?.(0),
538
779
  isGlobal: element.model.get("isGlobal") ?? false
@@ -540,9 +781,15 @@ function useElementsDom() {
540
781
  }
541
782
  );
542
783
  }
784
+ function isV4Element(dataset) {
785
+ if (!dataset) {
786
+ return false;
787
+ }
788
+ return ELEMENTS_DATA_ATTR in dataset || "eType" in dataset;
789
+ }
543
790
 
544
791
  // src/components/interactions-renderer.tsx
545
- import * as React3 from "react";
792
+ import * as React6 from "react";
546
793
  import {
547
794
  __privateUseListenTo as useListenTo2,
548
795
  commandEndEvent,
@@ -551,15 +798,15 @@ import {
551
798
  import { Portal } from "@elementor/ui";
552
799
 
553
800
  // src/hooks/use-interactions-items.ts
554
- import { useEffect as useEffect5, useMemo, useState as useState2 } from "react";
801
+ import { useEffect as useEffect6, useMemo as useMemo2, useState as useState3 } from "react";
555
802
  import { interactionsRepository } from "@elementor/editor-interactions";
556
803
  import { registerDataHook } from "@elementor/editor-v1-adapters";
557
804
 
558
805
  // src/hooks/use-on-mount.ts
559
- import { useEffect as useEffect4, useRef } from "react";
806
+ import { useEffect as useEffect5, useRef } from "react";
560
807
  function useOnMount(cb) {
561
808
  const mounted = useRef(false);
562
- useEffect4(() => {
809
+ useEffect5(() => {
563
810
  if (!mounted.current) {
564
811
  mounted.current = true;
565
812
  cb();
@@ -569,8 +816,8 @@ function useOnMount(cb) {
569
816
 
570
817
  // src/hooks/use-interactions-items.ts
571
818
  function useInteractionsItems() {
572
- const [interactionItems, setInteractionItems] = useState2({});
573
- const providerAndSubscribers = useMemo(() => {
819
+ const [interactionItems, setInteractionItems] = useState3({});
820
+ const providerAndSubscribers = useMemo2(() => {
574
821
  try {
575
822
  const providers = interactionsRepository.getProviders();
576
823
  const mapped = providers.map((provider) => {
@@ -587,7 +834,7 @@ function useInteractionsItems() {
587
834
  return [];
588
835
  }
589
836
  }, []);
590
- useEffect5(() => {
837
+ useEffect6(() => {
591
838
  if (providerAndSubscribers.length === 0) {
592
839
  return;
593
840
  }
@@ -618,7 +865,7 @@ function useInteractionsItems() {
618
865
  });
619
866
  });
620
867
  });
621
- return useMemo(() => {
868
+ return useMemo2(() => {
622
869
  const result = Object.values(interactionItems).sort(sortByProviderPriority).flatMap(({ items }) => items);
623
870
  return result;
624
871
  }, [interactionItems]);
@@ -648,7 +895,7 @@ function InteractionsRenderer() {
648
895
  return null;
649
896
  }
650
897
  const interactionsData = JSON.stringify(Array.isArray(interactionItems) ? interactionItems : []);
651
- return /* @__PURE__ */ React3.createElement(Portal, { container }, /* @__PURE__ */ React3.createElement(
898
+ return /* @__PURE__ */ React6.createElement(Portal, { container }, /* @__PURE__ */ React6.createElement(
652
899
  "script",
653
900
  {
654
901
  type: "application/json",
@@ -664,7 +911,7 @@ function usePortalContainer() {
664
911
  }
665
912
 
666
913
  // src/components/style-renderer.tsx
667
- import * as React4 from "react";
914
+ import * as React7 from "react";
668
915
  import {
669
916
  __privateUseListenTo as useListenTo4,
670
917
  commandEndEvent as commandEndEvent3,
@@ -724,7 +971,7 @@ function getLinkAttrs(el) {
724
971
  }
725
972
 
726
973
  // src/hooks/use-style-items.ts
727
- import { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef2, useState as useState3 } from "react";
974
+ import { useEffect as useEffect7, useMemo as useMemo5, useRef as useRef2, useState as useState4 } from "react";
728
975
  import { useBreakpoints } from "@elementor/editor-responsive";
729
976
  import { isClassState } from "@elementor/editor-styles";
730
977
  import { stylesRepository as stylesRepository2 } from "@elementor/editor-styles-repository";
@@ -786,7 +1033,7 @@ function signalizedProcess(signal, steps = []) {
786
1033
  }
787
1034
 
788
1035
  // src/hooks/use-style-prop-resolver.ts
789
- import { useMemo as useMemo2 } from "react";
1036
+ import { useMemo as useMemo3 } from "react";
790
1037
  import { getStylesSchema as getStylesSchema2 } from "@elementor/editor-styles";
791
1038
  import { enqueueFont } from "@elementor/editor-v1-adapters";
792
1039
 
@@ -916,7 +1163,7 @@ var styleTransformersRegistry = createTransformersRegistry();
916
1163
 
917
1164
  // src/hooks/use-style-prop-resolver.ts
918
1165
  function useStylePropResolver() {
919
- return useMemo2(() => {
1166
+ return useMemo3(() => {
920
1167
  return createPropsResolver({
921
1168
  transformers: styleTransformersRegistry,
922
1169
  schema: getStylesSchema2(),
@@ -931,7 +1178,7 @@ function useStylePropResolver() {
931
1178
  }
932
1179
 
933
1180
  // src/hooks/use-style-renderer.ts
934
- import { useMemo as useMemo3 } from "react";
1181
+ import { useMemo as useMemo4 } from "react";
935
1182
  import { useBreakpointsMap } from "@elementor/editor-responsive";
936
1183
 
937
1184
  // src/renderers/create-styles-renderer.ts
@@ -1042,7 +1289,7 @@ function customCssToString(customCss) {
1042
1289
  var SELECTOR_PREFIX = ".elementor";
1043
1290
  function useStyleRenderer(resolve) {
1044
1291
  const breakpoints = useBreakpointsMap();
1045
- return useMemo3(() => {
1292
+ return useMemo4(() => {
1046
1293
  return createStylesRenderer({
1047
1294
  selectorPrefix: SELECTOR_PREFIX,
1048
1295
  breakpoints,
@@ -1056,9 +1303,9 @@ function useStyleItems() {
1056
1303
  const resolve = useStylePropResolver();
1057
1304
  const renderStyles = useStyleRenderer(resolve);
1058
1305
  const breakpoints = useBreakpoints();
1059
- const [styleItems, setStyleItems] = useState3({});
1306
+ const [styleItems, setStyleItems] = useState4({});
1060
1307
  const styleItemsCacheRef = useRef2(/* @__PURE__ */ new Map());
1061
- const providerAndSubscribers = useMemo4(() => {
1308
+ const providerAndSubscribers = useMemo5(() => {
1062
1309
  const createEmptyCache = () => {
1063
1310
  return { orderedIds: [], itemsById: /* @__PURE__ */ new Map() };
1064
1311
  };
@@ -1084,7 +1331,7 @@ function useStyleItems() {
1084
1331
  })
1085
1332
  );
1086
1333
  }, [renderStyles]);
1087
- useEffect6(() => {
1334
+ useEffect7(() => {
1088
1335
  const unsubscribes = providerAndSubscribers.map(
1089
1336
  ({ provider, subscriber }) => provider.subscribe(subscriber)
1090
1337
  );
@@ -1099,11 +1346,11 @@ function useStyleItems() {
1099
1346
  await Promise.all(promises);
1100
1347
  });
1101
1348
  });
1102
- const breakpointSorter = useMemo4(
1349
+ const breakpointSorter = useMemo5(
1103
1350
  () => createBreakpointSorter(breakpoints.map((breakpoint) => breakpoint.id)),
1104
1351
  [breakpoints]
1105
1352
  );
1106
- return useMemo4(
1353
+ return useMemo5(
1107
1354
  () => Object.values(styleItems).sort(prioritySorter).flatMap(({ items }) => items).sort(stateSorter).sort(breakpointSorter),
1108
1355
  [styleItems, breakpointSorter]
1109
1356
  );
@@ -1245,7 +1492,7 @@ function StyleRenderer() {
1245
1492
  if (!container) {
1246
1493
  return null;
1247
1494
  }
1248
- return /* @__PURE__ */ React4.createElement(Portal2, { container }, filterUniqueStyleDefinitions(styleItems).map((item) => /* @__PURE__ */ React4.createElement("style", { key: `${item.id}-${item.breakpoint}-${item.state ?? "normal"}` }, item.value)), linksAttrs.map((attrs) => /* @__PURE__ */ React4.createElement("link", { ...attrs, key: attrs.id })));
1495
+ return /* @__PURE__ */ React7.createElement(Portal2, { container }, filterUniqueStyleDefinitions(styleItems).map((item) => /* @__PURE__ */ React7.createElement("style", { key: `${item.id}-${item.breakpoint}-${item.state ?? "normal"}` }, item.value)), linksAttrs.map((attrs) => /* @__PURE__ */ React7.createElement("link", { ...attrs, key: attrs.id })));
1249
1496
  }
1250
1497
  function usePortalContainer2() {
1251
1498
  return useListenTo4(commandEndEvent3("editor/documents/attach-preview"), () => getCanvasIframeDocument4()?.head);
@@ -2718,7 +2965,7 @@ function createPromotionView(BaseView) {
2718
2965
  import { createRoot } from "react-dom/client";
2719
2966
 
2720
2967
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2721
- import * as React6 from "react";
2968
+ import * as React9 from "react";
2722
2969
  import { getContainer as getContainer2, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
2723
2970
  import {
2724
2971
  htmlV3PropTypeUtil as htmlV3PropTypeUtil2,
@@ -2771,14 +3018,14 @@ var ReplacementBase = class {
2771
3018
  };
2772
3019
 
2773
3020
  // src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
2774
- import * as React5 from "react";
2775
- import { useCallback as useCallback2, useEffect as useEffect8, useLayoutEffect, useState as useState5 } from "react";
3021
+ import * as React8 from "react";
3022
+ import { useCallback as useCallback2, useEffect as useEffect9, useLayoutEffect, useState as useState6 } from "react";
2776
3023
  import { InlineEditor, InlineEditorToolbar } from "@elementor/editor-controls";
2777
- import { Box as Box2, ThemeProvider } from "@elementor/ui";
2778
- import { autoUpdate as autoUpdate2, flip, FloatingPortal as FloatingPortal2, useFloating as useFloating2 } from "@floating-ui/react";
3024
+ import { Box as Box3, ThemeProvider } from "@elementor/ui";
3025
+ import { autoUpdate as autoUpdate2, flip, FloatingPortal as FloatingPortal3, useFloating as useFloating2 } from "@floating-ui/react";
2779
3026
 
2780
3027
  // src/legacy/replacements/inline-editing/inline-editing-utils.ts
2781
- import { useCallback, useEffect as useEffect7, useState as useState4 } from "react";
3028
+ import { useCallback, useEffect as useEffect8, useState as useState5 } from "react";
2782
3029
  var TOP_BAR_SELECTOR = "#elementor-editor-wrapper-v2";
2783
3030
  var NAVIGATOR_SELECTOR = "#elementor-navigator";
2784
3031
  var EDITING_PANEL = "#elementor-panel";
@@ -2810,7 +3057,7 @@ var getInlineEditorElement = (elementWrapper, expectedTag) => {
2810
3057
  };
2811
3058
  var useOnClickOutsideIframe = (handleUnmount) => {
2812
3059
  const asyncUnmountInlineEditor = useCallback(() => queueMicrotask(handleUnmount), [handleUnmount]);
2813
- useEffect7(() => {
3060
+ useEffect8(() => {
2814
3061
  EDITOR_ELEMENTS_OUT_OF_IFRAME.forEach(
2815
3062
  (selector) => document?.querySelector(selector)?.addEventListener("mousedown", asyncUnmountInlineEditor)
2816
3063
  );
@@ -2820,8 +3067,8 @@ var useOnClickOutsideIframe = (handleUnmount) => {
2820
3067
  }, []);
2821
3068
  };
2822
3069
  var useRenderToolbar = (ownerDocument, id) => {
2823
- const [anchor, setAnchor] = useState4(null);
2824
- useEffect7(() => {
3070
+ const [anchor, setAnchor] = useState5(null);
3071
+ useEffect8(() => {
2825
3072
  if (!anchor) {
2826
3073
  removeToolbarAnchor(ownerDocument, id);
2827
3074
  }
@@ -2915,10 +3162,10 @@ var CanvasInlineEditor = ({
2915
3162
  setValue,
2916
3163
  requestDestroy
2917
3164
  }) => {
2918
- const [active, setActive] = useState5(true);
2919
- const [editor, setEditor] = useState5(null);
3165
+ const [active, setActive] = useState6(true);
3166
+ const [editor, setEditor] = useState6(null);
2920
3167
  const { onSelectionEnd, anchor: toolbarAnchor, clearAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
2921
- useEffect8(() => {
3168
+ useEffect9(() => {
2922
3169
  if (!active) {
2923
3170
  clearAnchor();
2924
3171
  requestDestroy();
@@ -2929,7 +3176,7 @@ var CanvasInlineEditor = ({
2929
3176
  setActive(false);
2930
3177
  }, []);
2931
3178
  useOnClickOutsideIframe(dismiss);
2932
- useEffect8(() => {
3179
+ useEffect9(() => {
2933
3180
  const ownerDocument = contentElement.ownerDocument;
2934
3181
  const handleClickAway = (event) => {
2935
3182
  if (contentElement.contains(event.target)) {
@@ -2943,7 +3190,7 @@ var CanvasInlineEditor = ({
2943
3190
  if (!active) {
2944
3191
  return null;
2945
3192
  }
2946
- return /* @__PURE__ */ React5.createElement(ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement(
3193
+ return /* @__PURE__ */ React8.createElement(ThemeProvider, null, /* @__PURE__ */ React8.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React8.createElement(
2947
3194
  InlineEditor,
2948
3195
  {
2949
3196
  onEditorCreate: setEditor,
@@ -2960,7 +3207,7 @@ var CanvasInlineEditor = ({
2960
3207
  autofocus: true,
2961
3208
  onSelectionEnd
2962
3209
  }
2963
- ), toolbarAnchor && editor && /* @__PURE__ */ React5.createElement(InlineEditingToolbar, { anchor: toolbarAnchor, editor, id }));
3210
+ ), toolbarAnchor && editor && /* @__PURE__ */ React8.createElement(InlineEditingToolbar, { anchor: toolbarAnchor, editor, id }));
2964
3211
  };
2965
3212
  var InlineEditingOverlay = ({
2966
3213
  expectedTag,
@@ -2968,11 +3215,11 @@ var InlineEditingOverlay = ({
2968
3215
  id
2969
3216
  }) => {
2970
3217
  const inlineEditedElement = getInlineEditorElement(rootElement, expectedTag);
2971
- const [overlayRefElement, setOverlayElement] = useState5(inlineEditedElement);
2972
- useEffect8(() => {
3218
+ const [overlayRefElement, setOverlayElement] = useState6(inlineEditedElement);
3219
+ useEffect9(() => {
2973
3220
  setOverlayElement(getInlineEditorElement(rootElement, expectedTag));
2974
3221
  }, [expectedTag, rootElement]);
2975
- return overlayRefElement ? /* @__PURE__ */ React5.createElement(OutlineOverlay, { element: overlayRefElement, id, isSelected: true }) : null;
3222
+ return overlayRefElement ? /* @__PURE__ */ React8.createElement(OutlineOverlay, { element: overlayRefElement, id, isSelected: true }) : null;
2976
3223
  };
2977
3224
  var InlineEditingToolbar = ({ anchor, editor, id }) => {
2978
3225
  const { refs, floatingStyles } = useFloating2({
@@ -2986,8 +3233,8 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
2986
3233
  refs.setReference(anchor);
2987
3234
  return () => refs.setReference(null);
2988
3235
  }, [anchor, refs]);
2989
- return /* @__PURE__ */ React5.createElement(FloatingPortal2, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(
2990
- Box2,
3236
+ return /* @__PURE__ */ React8.createElement(FloatingPortal3, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React8.createElement(
3237
+ Box3,
2991
3238
  {
2992
3239
  ref: refs.setFloating,
2993
3240
  role: "presentation",
@@ -2996,7 +3243,7 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
2996
3243
  pointerEvents: "none"
2997
3244
  }
2998
3245
  },
2999
- /* @__PURE__ */ React5.createElement(InlineEditorToolbar, { editor, elementId: id })
3246
+ /* @__PURE__ */ React8.createElement(InlineEditorToolbar, { editor, elementId: id })
3000
3247
  ));
3001
3248
  };
3002
3249
 
@@ -3205,7 +3452,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3205
3452
  contentElement.innerHTML = "";
3206
3453
  this.editing = true;
3207
3454
  this.reactRoot.render(
3208
- /* @__PURE__ */ React6.createElement(
3455
+ /* @__PURE__ */ React9.createElement(
3209
3456
  CanvasInlineEditor,
3210
3457
  {
3211
3458
  elementClasses,
@@ -3899,7 +4146,7 @@ function getElementDisplayName(container) {
3899
4146
  // src/mcp/tools/build-composition/tool.ts
3900
4147
  import { getCurrentDocument } from "@elementor/editor-documents";
3901
4148
  import {
3902
- createElement as createElement8,
4149
+ createElement as createElement11,
3903
4150
  deleteElement as deleteElement2,
3904
4151
  getContainer as getContainer5,
3905
4152
  getWidgetsCache as getWidgetsCache9
@@ -3907,7 +4154,7 @@ import {
3907
4154
 
3908
4155
  // src/composition-builder/composition-builder.ts
3909
4156
  import {
3910
- createElement as createElement7,
4157
+ createElement as createElement10,
3911
4158
  deleteElement,
3912
4159
  generateElementId as generateElementId2,
3913
4160
  getContainer as getContainer4,
@@ -4178,7 +4425,7 @@ var CompositionBuilder = class _CompositionBuilder {
4178
4425
  elementCustomCSS = {};
4179
4426
  rootContainers = [];
4180
4427
  api = {
4181
- createElement: createElement7,
4428
+ createElement: createElement10,
4182
4429
  deleteElement,
4183
4430
  getWidgetsCache: getWidgetsCache8,
4184
4431
  generateElementId: generateElementId2,
@@ -4612,6 +4859,56 @@ var outputSchema = {
4612
4859
  llm_instructions: z.string().describe("Instructions what to do next, Important to follow these instructions!").optional()
4613
4860
  };
4614
4861
 
4862
+ // src/mcp/tools/build-composition/xml-leaf-wrapper.ts
4863
+ var DIV_BLOCK_TAG = "e-div-block";
4864
+ var ZERO_SPACING = {
4865
+ $$type: "size",
4866
+ value: {
4867
+ size: {
4868
+ $$type: "number",
4869
+ value: 0
4870
+ },
4871
+ unit: {
4872
+ $$type: "string",
4873
+ value: "px"
4874
+ }
4875
+ }
4876
+ };
4877
+ function adaptLeafRootParams(params) {
4878
+ const doc = new DOMParser().parseFromString(params.xmlStructure, "application/xml");
4879
+ const rootElement = doc.documentElement;
4880
+ if (!isLeafWidget(rootElement.tagName, params.widgetsCache)) {
4881
+ return params;
4882
+ }
4883
+ const wrapperConfigId = getDivBlockWrapperConfigId(params.widgetsCache);
4884
+ return {
4885
+ ...params,
4886
+ xmlStructure: serializeWrapped(doc, rootElement, wrapperConfigId),
4887
+ stylesConfig: {
4888
+ ...params.stylesConfig,
4889
+ [wrapperConfigId]: {
4890
+ margin: ZERO_SPACING,
4891
+ padding: ZERO_SPACING,
4892
+ ...params.stylesConfig[wrapperConfigId]
4893
+ }
4894
+ }
4895
+ };
4896
+ }
4897
+ function getDivBlockWrapperConfigId(widgetsCache) {
4898
+ return widgetsCache[DIV_BLOCK_TAG]?.title ?? DIV_BLOCK_TAG;
4899
+ }
4900
+ function isLeafWidget(tagName, widgetsCache) {
4901
+ return widgetsCache[tagName]?.elType === "widget";
4902
+ }
4903
+ function serializeWrapped(doc, rootElement, wrapperConfigId) {
4904
+ const wrapper = doc.createElement(DIV_BLOCK_TAG);
4905
+ wrapper.setAttribute("configuration-id", wrapperConfigId);
4906
+ wrapper.appendChild(rootElement.cloneNode(true));
4907
+ const wrappedDoc = new DOMParser().parseFromString(`<${DIV_BLOCK_TAG} />`, "application/xml");
4908
+ wrappedDoc.replaceChild(wrapper, wrappedDoc.documentElement);
4909
+ return new XMLSerializer().serializeToString(wrappedDoc);
4910
+ }
4911
+
4615
4912
  // src/mcp/tools/build-composition/tool.ts
4616
4913
  var initBuildCompositionsTool = (reg) => {
4617
4914
  const { addTool, resource } = reg;
@@ -4641,9 +4938,12 @@ var initBuildCompositionsTool = (reg) => {
4641
4938
  { description: "Available widgets for this tool", uri: AVAILABLE_WIDGETS_URI_V4 }
4642
4939
  ],
4643
4940
  outputSchema,
4644
- handler: async (params) => {
4645
- assertCompositionXmlUsesV4WidgetsOnly(params.xmlStructure);
4646
- const { xmlStructure, elementConfig, stylesConfig, customCSS } = params;
4941
+ handler: async (rawParams) => {
4942
+ assertCompositionXmlUsesV4WidgetsOnly(rawParams.xmlStructure);
4943
+ const { xmlStructure, elementConfig, stylesConfig, customCSS } = adaptLeafRootParams({
4944
+ ...rawParams,
4945
+ widgetsCache: getWidgetsCache9() ?? {}
4946
+ });
4647
4947
  let generatedXML = "";
4648
4948
  const errors = [];
4649
4949
  const rootContainers = [];
@@ -4652,7 +4952,7 @@ var initBuildCompositionsTool = (reg) => {
4652
4952
  const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
4653
4953
  try {
4654
4954
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
4655
- createElement: createElement8,
4955
+ createElement: createElement11,
4656
4956
  deleteElement: deleteElement2,
4657
4957
  getWidgetsCache: getWidgetsCache9
4658
4958
  });
@@ -4754,10 +5054,8 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
4754
5054
  if (widgetData.elType !== "widget") {
4755
5055
  continue;
4756
5056
  }
4757
- if (!widgetData.atomic_props_schema) {
4758
- throw new Error(
4759
- `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${type}`
4760
- );
5057
+ if (!isWidgetAvailableForLLM(widgetData) || !widgetData.atomic_props_schema) {
5058
+ throw new Error(`This tool does not support element type: ${type}`);
4761
5059
  }
4762
5060
  }
4763
5061
  }
@@ -5690,72 +5988,7 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
5690
5988
  var GLOBAL_STYLES_IMPORTED_EVENT = "elementor/global-styles/imported";
5691
5989
 
5692
5990
  // src/components/spotlight-backdrop.tsx
5693
- import * as React7 from "react";
5694
-
5695
- // src/hooks/use-element-rect.ts
5696
- import { useEffect as useEffect9, useState as useState6 } from "react";
5697
- import { throttle } from "@elementor/utils";
5698
- function useElementRect(element) {
5699
- const [rect, setRect] = useState6(new DOMRect(0, 0, 0, 0));
5700
- const onChange = throttle(
5701
- () => {
5702
- setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
5703
- },
5704
- 20,
5705
- true
5706
- );
5707
- useScrollListener({ element, onChange });
5708
- useResizeListener({ element, onChange });
5709
- useMutationsListener({ element, onChange });
5710
- useEffect9(
5711
- () => () => {
5712
- onChange.cancel();
5713
- },
5714
- [onChange]
5715
- );
5716
- return rect;
5717
- }
5718
- function useScrollListener({ element, onChange }) {
5719
- useEffect9(() => {
5720
- if (!element) {
5721
- return;
5722
- }
5723
- const win = element.ownerDocument?.defaultView;
5724
- win?.addEventListener("scroll", onChange, { passive: true });
5725
- return () => {
5726
- win?.removeEventListener("scroll", onChange);
5727
- };
5728
- }, [element, onChange]);
5729
- }
5730
- function useResizeListener({ element, onChange }) {
5731
- useEffect9(() => {
5732
- if (!element) {
5733
- return;
5734
- }
5735
- const resizeObserver = new ResizeObserver(onChange);
5736
- resizeObserver.observe(element);
5737
- const win = element.ownerDocument?.defaultView;
5738
- win?.addEventListener("resize", onChange, { passive: true });
5739
- return () => {
5740
- resizeObserver.disconnect();
5741
- win?.removeEventListener("resize", onChange);
5742
- };
5743
- }, [element, onChange]);
5744
- }
5745
- function useMutationsListener({ element, onChange }) {
5746
- useEffect9(() => {
5747
- if (!element) {
5748
- return;
5749
- }
5750
- const mutationObserver = new MutationObserver(onChange);
5751
- mutationObserver.observe(element, { childList: true, subtree: true });
5752
- return () => {
5753
- mutationObserver.disconnect();
5754
- };
5755
- }, [element, onChange]);
5756
- }
5757
-
5758
- // src/components/spotlight-backdrop.tsx
5991
+ import * as React10 from "react";
5759
5992
  function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }) {
5760
5993
  const rect = useElementRect(element);
5761
5994
  const clipPath = element ? getRectClipPath(rect, canvas.defaultView) : void 0;
@@ -5777,7 +6010,7 @@ function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }) {
5777
6010
  onExit();
5778
6011
  }
5779
6012
  };
5780
- return /* @__PURE__ */ React7.createElement(
6013
+ return /* @__PURE__ */ React10.createElement(
5781
6014
  "div",
5782
6015
  {
5783
6016
  style: backdropStyle,