@elementor/editor-canvas 4.0.0-682 → 4.0.0-beta5

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.
Files changed (29) hide show
  1. package/dist/index.d.mts +4 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.js +260 -79
  4. package/dist/index.mjs +261 -80
  5. package/package.json +19 -18
  6. package/src/components/__tests__/style-renderer.test.tsx +4 -0
  7. package/src/hooks/__tests__/use-style-items.test.ts +119 -0
  8. package/src/hooks/use-style-items.ts +39 -15
  9. package/src/init-settings-transformers.ts +2 -0
  10. package/src/legacy/create-nested-templated-element-type.ts +15 -2
  11. package/src/legacy/create-templated-element-type.ts +8 -0
  12. package/src/legacy/replacements/base.ts +4 -0
  13. package/src/legacy/replacements/inline-editing/canvas-inline-editor.tsx +49 -27
  14. package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +16 -10
  15. package/src/legacy/replacements/inline-editing/inline-editing-utils.ts +12 -1
  16. package/src/legacy/replacements/manager.ts +13 -0
  17. package/src/legacy/types.ts +4 -0
  18. package/src/mcp/canvas-mcp.ts +5 -7
  19. package/src/mcp/resources/breakpoints-resource.ts +11 -4
  20. package/src/mcp/resources/document-structure-resource.ts +18 -13
  21. package/src/mcp/tools/build-composition/tool.ts +5 -1
  22. package/src/mcp/utils/__tests__/get-composition-target-container.test.ts +59 -0
  23. package/src/mcp/utils/get-composition-target-container.ts +15 -0
  24. package/src/renderers/__tests__/create-styles-renderer.test.ts +117 -0
  25. package/src/renderers/create-styles-renderer.ts +13 -3
  26. package/src/transformers/shared/__tests__/svg-src-transformer.test.ts +184 -0
  27. package/src/transformers/shared/svg-src-transformer.ts +87 -0
  28. package/src/transformers/styles/__tests__/size-transformer.test.ts +24 -0
  29. package/src/transformers/styles/size-transformer.ts +3 -0
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ module.exports = __toCommonJS(index_exports);
59
59
  var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
60
60
  var BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
61
61
  var initBreakpointsResource = (reg) => {
62
- const { mcpServer, sendResourceUpdated } = reg;
62
+ const { resource, sendResourceUpdated } = reg;
63
63
  const getBreakpointsList = () => {
64
64
  const { breakpoints } = window.elementor?.config?.responsive || {};
65
65
  if (!breakpoints) {
@@ -83,9 +83,16 @@ var initBreakpointsResource = (reg) => {
83
83
  }
84
84
  ]
85
85
  });
86
- mcpServer.resource("breakpoints ", BREAKPOINTS_SCHEMA_URI, () => {
87
- return buildResourceResponse();
88
- });
86
+ resource(
87
+ "breakpoints ",
88
+ BREAKPOINTS_SCHEMA_URI,
89
+ {
90
+ description: "Breakpoints list."
91
+ },
92
+ () => {
93
+ return buildResourceResponse();
94
+ }
95
+ );
89
96
  window.addEventListener((0, import_editor_v1_adapters.v1ReadyEvent)().name, () => {
90
97
  sendResourceUpdated({
91
98
  uri: BREAKPOINTS_SCHEMA_URI,
@@ -833,14 +840,22 @@ var UnknownStyleStateError = (0, import_utils2.createError)({
833
840
  var SELECTORS_MAP = {
834
841
  class: "."
835
842
  };
843
+ var DEFAULT_BREAKPOINT = "desktop";
844
+ var DEFAULT_STATE = "normal";
845
+ function getStyleUniqueKey(style) {
846
+ const breakpoint = style.variants[0]?.meta?.breakpoint ?? DEFAULT_BREAKPOINT;
847
+ const state = style.variants[0]?.meta?.state ?? DEFAULT_STATE;
848
+ return `${style.id}-${breakpoint}-${state}`;
849
+ }
836
850
  function createStylesRenderer({ resolve, breakpoints, selectorPrefix = "" }) {
837
851
  return async ({ styles, signal }) => {
838
- const seenIds = /* @__PURE__ */ new Set();
852
+ const seenKeys = /* @__PURE__ */ new Set();
839
853
  const uniqueStyles = styles.filter((style) => {
840
- if (seenIds.has(style.id)) {
854
+ const key = getStyleUniqueKey(style);
855
+ if (seenKeys.has(key)) {
841
856
  return false;
842
857
  }
843
- seenIds.add(style.id);
858
+ seenKeys.add(key);
844
859
  return true;
845
860
  });
846
861
  const stylesCssPromises = uniqueStyles.map(async (style) => {
@@ -929,22 +944,30 @@ function useStyleItems() {
929
944
  const [styleItems, setStyleItems] = (0, import_react10.useState)({});
930
945
  const styleItemsCacheRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
931
946
  const providerAndSubscribers = (0, import_react10.useMemo)(() => {
932
- return import_editor_styles_repository2.stylesRepository.getProviders().map((provider) => {
933
- const providerKey = provider.getKey();
947
+ const createEmptyCache = () => {
948
+ return { orderedIds: [], itemsById: /* @__PURE__ */ new Map() };
949
+ };
950
+ const getCache = (provider) => {
951
+ const providerKey = safeGetKey(provider);
952
+ if (!providerKey) {
953
+ return createEmptyCache();
954
+ }
934
955
  if (!styleItemsCacheRef.current.has(providerKey)) {
935
- styleItemsCacheRef.current.set(providerKey, { orderedIds: [], itemsById: /* @__PURE__ */ new Map() });
956
+ styleItemsCacheRef.current.set(providerKey, createEmptyCache());
936
957
  }
937
- const cache = styleItemsCacheRef.current.get(providerKey);
938
- return {
958
+ return styleItemsCacheRef.current.get(providerKey);
959
+ };
960
+ return import_editor_styles_repository2.stylesRepository.getProviders().map(
961
+ (provider) => ({
939
962
  provider,
940
963
  subscriber: createProviderSubscriber2({
941
964
  provider,
942
965
  renderStyles,
943
966
  setStyleItems,
944
- cache
967
+ getCache: () => getCache(provider)
945
968
  })
946
- };
947
- });
969
+ })
970
+ );
948
971
  }, [renderStyles]);
949
972
  (0, import_react10.useEffect)(() => {
950
973
  const unsubscribes = providerAndSubscribers.map(
@@ -984,15 +1007,23 @@ function stateSorter({ state: stateA }, { state: stateB }) {
984
1007
  function createBreakpointSorter(breakpointsOrder) {
985
1008
  return ({ breakpoint: breakpointA }, { breakpoint: breakpointB }) => breakpointsOrder.indexOf(breakpointA) - breakpointsOrder.indexOf(breakpointB);
986
1009
  }
987
- function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cache }) {
1010
+ function safeGetKey(provider) {
1011
+ try {
1012
+ return provider.getKey();
1013
+ } catch {
1014
+ return null;
1015
+ }
1016
+ }
1017
+ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, getCache }) {
988
1018
  return abortPreviousRuns(
989
1019
  (abortController, previous, current) => signalizedProcess(abortController.signal).then((_, signal) => {
1020
+ const cache = getCache();
990
1021
  const hasDiffInfo = current !== void 0 && previous !== void 0;
991
1022
  const hasCache = cache.orderedIds.length > 0;
992
1023
  if (hasDiffInfo && hasCache) {
993
- return updateItems(previous, current, signal);
1024
+ return updateItems(cache, previous, current, signal);
994
1025
  }
995
- return createItems(signal);
1026
+ return createItems(cache, signal);
996
1027
  }).then((items) => {
997
1028
  setStyleItems((prev) => ({
998
1029
  ...prev,
@@ -1000,7 +1031,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
1000
1031
  }));
1001
1032
  }).execute()
1002
1033
  );
1003
- async function updateItems(previous, current, signal) {
1034
+ async function updateItems(cache, previous, current, signal) {
1004
1035
  const changedIds = getChangedStyleIds(previous, current);
1005
1036
  cache.orderedIds = provider.actions.all().map((style) => style.id).reverse();
1006
1037
  if (changedIds.length > 0) {
@@ -1015,7 +1046,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
1015
1046
  }
1016
1047
  return getOrderedItems(cache);
1017
1048
  }
1018
- async function createItems(signal) {
1049
+ async function createItems(cache, signal) {
1019
1050
  const allStyles = provider.actions.all();
1020
1051
  const styles = [...allStyles].reverse().map((style) => {
1021
1052
  return {
@@ -1025,7 +1056,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
1025
1056
  });
1026
1057
  return renderStyles({ styles: breakToBreakpoints(styles), signal }).then((rendered) => {
1027
1058
  rebuildCache(cache, allStyles, rendered);
1028
- return rendered;
1059
+ return getOrderedItems(cache);
1029
1060
  });
1030
1061
  }
1031
1062
  function breakToBreakpoints(styles) {
@@ -1410,14 +1441,74 @@ var plainTransformer = createTransformer((value) => {
1410
1441
  return value;
1411
1442
  });
1412
1443
 
1413
- // src/transformers/shared/video-src-transformer.ts
1444
+ // src/transformers/shared/svg-src-transformer.ts
1445
+ var import_dompurify = __toESM(require("dompurify"));
1414
1446
  var import_wp_media2 = require("@elementor/wp-media");
1447
+ var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
1448
+ function processSvgContent(svgText) {
1449
+ const sanitized = import_dompurify.default.sanitize(svgText, {
1450
+ USE_PROFILES: { svg: true, svgFilters: true }
1451
+ });
1452
+ const parser = new DOMParser();
1453
+ const doc = parser.parseFromString(sanitized, "image/svg+xml");
1454
+ const svgElement = doc.querySelector("svg");
1455
+ if (!svgElement) {
1456
+ return null;
1457
+ }
1458
+ svgElement.setAttribute("fill", "currentColor");
1459
+ const existingStyle = svgElement.getAttribute("style") ?? "";
1460
+ const trimmed = existingStyle.trim();
1461
+ const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
1462
+ svgElement.setAttribute("style", merged);
1463
+ return svgElement.outerHTML;
1464
+ }
1465
+ async function fetchSvgContent(url, signal) {
1466
+ try {
1467
+ const response = await fetch(url, { signal });
1468
+ if (!response.ok) {
1469
+ return null;
1470
+ }
1471
+ const contentType = response.headers.get("content-type") ?? "";
1472
+ const isSvg = contentType.includes("svg") || contentType.includes("xml") || url.endsWith(".svg");
1473
+ if (!isSvg) {
1474
+ return null;
1475
+ }
1476
+ return await response.text();
1477
+ } catch {
1478
+ return null;
1479
+ }
1480
+ }
1481
+ function resolveSvgSrcId(id) {
1482
+ if (typeof id !== "number" || id <= 0) {
1483
+ return null;
1484
+ }
1485
+ return id;
1486
+ }
1487
+ var svgSrcTransformer = createTransformer(async (value, { signal }) => {
1488
+ const id = resolveSvgSrcId(value.id);
1489
+ const urlFromValue = typeof value.url === "string" ? value.url : null;
1490
+ let url = urlFromValue;
1491
+ if (id && !urlFromValue) {
1492
+ const attachment = await (0, import_wp_media2.getMediaAttachment)({ id });
1493
+ url = attachment?.url ?? null;
1494
+ }
1495
+ const resolvedUrl = typeof url === "string" ? url : null;
1496
+ if (!resolvedUrl) {
1497
+ return { html: null, url: null };
1498
+ }
1499
+ const svgText = await fetchSvgContent(resolvedUrl, signal);
1500
+ const html = svgText ? processSvgContent(svgText) : null;
1501
+ return { html, url: resolvedUrl };
1502
+ });
1503
+
1504
+ // src/transformers/shared/video-src-transformer.ts
1505
+ var import_wp_media3 = require("@elementor/wp-media");
1415
1506
  var videoSrcTransformer = createTransformer(async (value) => {
1416
1507
  const { id, url } = value;
1417
1508
  if (!id) {
1418
1509
  return { id: null, url };
1419
1510
  }
1420
- const attachment = await (0, import_wp_media2.getMediaAttachment)({ id });
1511
+ const attachment = await (0, import_wp_media3.getMediaAttachment)({ id });
1421
1512
  return {
1422
1513
  id,
1423
1514
  url: attachment?.url ?? url
@@ -1426,7 +1517,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
1426
1517
 
1427
1518
  // src/init-settings-transformers.ts
1428
1519
  function initSettingsTransformers() {
1429
- settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).registerFallback(plainTransformer);
1520
+ settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("svg-src", svgSrcTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).registerFallback(plainTransformer);
1430
1521
  }
1431
1522
 
1432
1523
  // src/transformers/styles/background-color-overlay-transformer.ts
@@ -1625,6 +1716,9 @@ var shadowTransformer = createTransformer((value) => {
1625
1716
 
1626
1717
  // src/transformers/styles/size-transformer.ts
1627
1718
  var sizeTransformer = createTransformer((value) => {
1719
+ if (value.unit === "auto") {
1720
+ return "auto";
1721
+ }
1628
1722
  return value.unit === "custom" ? value.size : `${value.size}${value.unit}`;
1629
1723
  });
1630
1724
 
@@ -2008,6 +2102,7 @@ function createTemplatedElementView({
2008
2102
  this._lastResolvedSettingsHash = settingsHash;
2009
2103
  const context = {
2010
2104
  id: this.model.get("id"),
2105
+ interaction_id: this.getInteractionId(),
2011
2106
  type,
2012
2107
  settings,
2013
2108
  base_styles: baseStylesDictionary
@@ -2042,6 +2137,11 @@ function createTemplatedElementView({
2042
2137
  _openEditingPanel(options) {
2043
2138
  this._doAfterRender(() => super._openEditingPanel(options));
2044
2139
  }
2140
+ getInteractionId() {
2141
+ const originId = this.model.get("originId");
2142
+ const id = this.model.get("id");
2143
+ return originId ?? id;
2144
+ }
2045
2145
  };
2046
2146
  }
2047
2147
 
@@ -2074,10 +2174,11 @@ function createNestedTemplatedElementType({
2074
2174
  }
2075
2175
  function buildEditorAttributes(model) {
2076
2176
  const id = model.get("id");
2177
+ const originId = model.get("originId");
2077
2178
  const cid = model.cid ?? "";
2078
2179
  const attrs = {
2079
2180
  "data-model-cid": cid,
2080
- "data-interaction-id": id,
2181
+ "data-interaction-id": originId ?? id,
2081
2182
  "x-ignore": "true"
2082
2183
  };
2083
2184
  return Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ");
@@ -2111,6 +2212,9 @@ function createNestedTemplatedElementView({
2111
2212
  invalidateRenderCache() {
2112
2213
  this._lastResolvedSettingsHash = null;
2113
2214
  },
2215
+ renderOnChange() {
2216
+ this.render();
2217
+ },
2114
2218
  render() {
2115
2219
  this._abortController?.abort();
2116
2220
  this._abortController = new AbortController();
@@ -2154,6 +2258,7 @@ function createNestedTemplatedElementView({
2154
2258
  this._lastResolvedSettingsHash = settingsHash;
2155
2259
  const context = {
2156
2260
  id: model.get("id"),
2261
+ interaction_id: this.getInteractionId(),
2157
2262
  type,
2158
2263
  settings,
2159
2264
  base_styles: baseStylesDictionary,
@@ -2283,13 +2388,20 @@ function createNestedTemplatedElementView({
2283
2388
  },
2284
2389
  _openEditingPanel(options) {
2285
2390
  this._doAfterRender(() => parentOpenEditingPanel.call(this, options));
2391
+ },
2392
+ getInteractionId() {
2393
+ const originId = this.model.get("originId");
2394
+ const id = this.model.get("id");
2395
+ return originId ?? id;
2286
2396
  }
2287
2397
  });
2288
2398
  }
2289
2399
 
2400
+ // src/legacy/replacements/manager.ts
2401
+ var import_client = require("react-dom/client");
2402
+
2290
2403
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2291
2404
  var React6 = __toESM(require("react"));
2292
- var import_client = require("react-dom/client");
2293
2405
  var import_editor_elements5 = require("@elementor/editor-elements");
2294
2406
  var import_editor_props4 = require("@elementor/editor-props");
2295
2407
  var import_editor_v1_adapters11 = require("@elementor/editor-v1-adapters");
@@ -2308,6 +2420,8 @@ var ReplacementBase = class {
2308
2420
  type;
2309
2421
  id;
2310
2422
  refreshView;
2423
+ reactRoot;
2424
+ reactContainer;
2311
2425
  constructor(settings) {
2312
2426
  this.getSetting = settings.getSetting;
2313
2427
  this.setSetting = settings.setSetting;
@@ -2315,6 +2429,8 @@ var ReplacementBase = class {
2315
2429
  this.type = settings.type;
2316
2430
  this.id = settings.id;
2317
2431
  this.refreshView = settings.refreshView;
2432
+ this.reactRoot = settings.reactRoot;
2433
+ this.reactContainer = settings.reactContainer;
2318
2434
  }
2319
2435
  static getTypes() {
2320
2436
  return null;
@@ -2365,7 +2481,8 @@ var INLINE_EDITING_PROPERTY_PER_TYPE = {
2365
2481
  "e-button": "text",
2366
2482
  "e-form-label": "text",
2367
2483
  "e-heading": "title",
2368
- "e-paragraph": "paragraph"
2484
+ "e-paragraph": "paragraph",
2485
+ "e-form-submit-button": "text"
2369
2486
  };
2370
2487
  var getInlineEditorElement = (elementWrapper, expectedTag) => {
2371
2488
  return !expectedTag ? null : elementWrapper.querySelector(expectedTag);
@@ -2383,6 +2500,11 @@ var useOnClickOutsideIframe = (handleUnmount) => {
2383
2500
  };
2384
2501
  var useRenderToolbar = (ownerDocument, id) => {
2385
2502
  const [anchor, setAnchor] = (0, import_react11.useState)(null);
2503
+ (0, import_react11.useEffect)(() => {
2504
+ if (!anchor) {
2505
+ removeToolbarAnchor(ownerDocument, id);
2506
+ }
2507
+ }, [anchor, ownerDocument, id]);
2386
2508
  const onSelectionEnd = (view) => {
2387
2509
  const hasSelection = !view.state.selection.empty;
2388
2510
  removeToolbarAnchor(ownerDocument, id);
@@ -2392,7 +2514,10 @@ var useRenderToolbar = (ownerDocument, id) => {
2392
2514
  setAnchor(null);
2393
2515
  }
2394
2516
  };
2395
- return { onSelectionEnd, anchor };
2517
+ const clearAnchor = (0, import_react11.useCallback)(() => {
2518
+ setAnchor(null);
2519
+ }, []);
2520
+ return { onSelectionEnd, anchor, clearAnchor };
2396
2521
  };
2397
2522
  var createAnchorBasedOnSelection = (ownerDocument, id) => {
2398
2523
  const frameWindow = ownerDocument.defaultView;
@@ -2459,46 +2584,59 @@ var horizontalShifterMiddleware = {
2459
2584
  };
2460
2585
 
2461
2586
  // src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
2462
- var EDITOR_WRAPPER_SELECTOR = "inline-editor-wrapper";
2463
2587
  var CanvasInlineEditor = ({
2464
2588
  elementClasses,
2465
2589
  initialValue,
2466
2590
  expectedTag,
2467
2591
  rootElement,
2592
+ contentElement,
2468
2593
  id,
2469
2594
  setValue,
2470
- ...props
2595
+ requestDestroy
2471
2596
  }) => {
2597
+ const [active, setActive] = (0, import_react12.useState)(true);
2472
2598
  const [editor, setEditor] = (0, import_react12.useState)(null);
2473
- const { onSelectionEnd, anchor: toolbarAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
2474
- const onBlur = () => {
2475
- removeToolbarAnchor(rootElement.ownerDocument, id);
2476
- props.onBlur();
2477
- };
2478
- useOnClickOutsideIframe(onBlur);
2479
- return /* @__PURE__ */ React5.createElement(import_ui4.ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement("style", null, `
2480
- .ProseMirror > * {
2481
- height: 100%;
2482
- }
2483
- .${EDITOR_WRAPPER_SELECTOR} .ProseMirror > button[contenteditable="true"] {
2484
- height: auto;
2485
- cursor: text;
2486
- }
2487
- `), /* @__PURE__ */ React5.createElement(
2599
+ const { onSelectionEnd, anchor: toolbarAnchor, clearAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
2600
+ (0, import_react12.useEffect)(() => {
2601
+ if (!active) {
2602
+ clearAnchor();
2603
+ requestDestroy();
2604
+ }
2605
+ }, [active, clearAnchor, requestDestroy]);
2606
+ const dismiss = (0, import_react12.useCallback)(() => {
2607
+ setEditor(null);
2608
+ setActive(false);
2609
+ }, []);
2610
+ useOnClickOutsideIframe(dismiss);
2611
+ (0, import_react12.useEffect)(() => {
2612
+ const ownerDocument = contentElement.ownerDocument;
2613
+ const handleClickAway = (event) => {
2614
+ if (contentElement.contains(event.target)) {
2615
+ return;
2616
+ }
2617
+ dismiss();
2618
+ };
2619
+ ownerDocument.addEventListener("mousedown", handleClickAway);
2620
+ return () => ownerDocument.removeEventListener("mousedown", handleClickAway);
2621
+ }, [contentElement, dismiss]);
2622
+ if (!active) {
2623
+ return null;
2624
+ }
2625
+ return /* @__PURE__ */ React5.createElement(import_ui4.ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement(
2488
2626
  import_editor_controls2.InlineEditor,
2489
2627
  {
2490
2628
  onEditorCreate: setEditor,
2629
+ mountElement: contentElement,
2491
2630
  editorProps: {
2492
2631
  attributes: {
2493
- style: "outline: none;overflow-wrap: normal;height:100%"
2632
+ style: "outline: none; display: inherit; justify-content: inherit; align-items: inherit; flex-direction: inherit; text-align: inherit;"
2494
2633
  }
2495
2634
  },
2496
2635
  elementClasses,
2497
2636
  value: initialValue,
2498
2637
  setValue,
2499
- onBlur,
2638
+ onBlur: dismiss,
2500
2639
  autofocus: true,
2501
- expectedTag,
2502
2640
  onSelectionEnd
2503
2641
  }
2504
2642
  ), toolbarAnchor && editor && /* @__PURE__ */ React5.createElement(InlineEditingToolbar, { anchor: toolbarAnchor, editor, id }));
@@ -2527,7 +2665,18 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
2527
2665
  refs.setReference(anchor);
2528
2666
  return () => refs.setReference(null);
2529
2667
  }, [anchor, refs]);
2530
- return /* @__PURE__ */ React5.createElement(import_react13.FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(import_ui4.Box, { ref: refs.setFloating, role: "presentation", style: { ...floatingStyles, pointerEvents: "none" } }, /* @__PURE__ */ React5.createElement(import_editor_controls2.InlineEditorToolbar, { editor, elementId: id })));
2668
+ return /* @__PURE__ */ React5.createElement(import_react13.FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(
2669
+ import_ui4.Box,
2670
+ {
2671
+ ref: refs.setFloating,
2672
+ role: "presentation",
2673
+ style: {
2674
+ ...floatingStyles,
2675
+ pointerEvents: "none"
2676
+ }
2677
+ },
2678
+ /* @__PURE__ */ React5.createElement(import_editor_controls2.InlineEditorToolbar, { editor, elementId: id })
2679
+ ));
2531
2680
  };
2532
2681
 
2533
2682
  // src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
@@ -2561,8 +2710,8 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
2561
2710
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2562
2711
  var HISTORY_DEBOUNCE_WAIT = 800;
2563
2712
  var InlineEditingReplacement = class extends ReplacementBase {
2564
- inlineEditorRoot = null;
2565
2713
  handlerAttached = false;
2714
+ editing = false;
2566
2715
  getReplacementKey() {
2567
2716
  return "inline-editing";
2568
2717
  }
@@ -2570,7 +2719,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
2570
2719
  return Object.keys(INLINE_EDITING_PROPERTY_PER_TYPE);
2571
2720
  }
2572
2721
  isEditingModeActive() {
2573
- return !!this.inlineEditorRoot;
2722
+ return this.editing;
2574
2723
  }
2575
2724
  shouldRenderReplacement() {
2576
2725
  return this.isInlineEditingEligible() && (0, import_editor_v1_adapters11.getCurrentEditMode)() === "edit";
@@ -2613,8 +2762,8 @@ var InlineEditingReplacement = class extends ReplacementBase {
2613
2762
  resetInlineEditorRoot() {
2614
2763
  this.element.removeEventListener("click", this.handleRenderInlineEditor);
2615
2764
  this.handlerAttached = false;
2616
- this.inlineEditorRoot?.unmount?.();
2617
- this.inlineEditorRoot = null;
2765
+ this.reactRoot.render(null);
2766
+ this.editing = false;
2618
2767
  }
2619
2768
  unmountInlineEditor() {
2620
2769
  this.resetInlineEditorRoot();
@@ -2725,12 +2874,16 @@ var InlineEditingReplacement = class extends ReplacementBase {
2725
2874
  if (this.isEditingModeActive()) {
2726
2875
  this.resetInlineEditorRoot();
2727
2876
  }
2728
- const elementClasses = this.element.children?.[0]?.classList.toString() ?? "";
2877
+ const contentElement = this.element.children?.[0];
2878
+ if (!contentElement) {
2879
+ return;
2880
+ }
2881
+ const elementClasses = contentElement.classList.toString();
2729
2882
  const propValue = this.getExtractedContentValue();
2730
2883
  const expectedTag = this.getExpectedTag();
2731
- this.element.innerHTML = "";
2732
- this.inlineEditorRoot = (0, import_client.createRoot)(this.element);
2733
- this.inlineEditorRoot.render(
2884
+ contentElement.innerHTML = "";
2885
+ this.editing = true;
2886
+ this.reactRoot.render(
2734
2887
  /* @__PURE__ */ React6.createElement(
2735
2888
  CanvasInlineEditor,
2736
2889
  {
@@ -2738,9 +2891,10 @@ var InlineEditingReplacement = class extends ReplacementBase {
2738
2891
  initialValue: propValue,
2739
2892
  expectedTag,
2740
2893
  rootElement: this.element,
2894
+ contentElement,
2741
2895
  id: this.id,
2742
2896
  setValue: this.setContentValue.bind(this),
2743
- onBlur: this.unmountInlineEditor.bind(this)
2897
+ requestDestroy: this.unmountInlineEditor.bind(this)
2744
2898
  }
2745
2899
  )
2746
2900
  );
@@ -2769,16 +2923,24 @@ var createViewWithReplacements = (options) => {
2769
2923
  return class extends TemplatedView {
2770
2924
  #replacement = null;
2771
2925
  #config;
2926
+ #reactContainer;
2927
+ #reactRoot;
2772
2928
  constructor(...args) {
2773
2929
  super(...args);
2774
2930
  const settings = this.model.get("settings");
2931
+ this.#reactContainer = this.el.ownerDocument.createElement("div");
2932
+ this.#reactContainer.style.display = "none";
2933
+ this.el.ownerDocument.body.appendChild(this.#reactContainer);
2934
+ this.#reactRoot = (0, import_client.createRoot)(this.#reactContainer);
2775
2935
  this.#config = {
2776
2936
  getSetting: settings.get.bind(settings),
2777
2937
  setSetting: settings.set.bind(settings),
2778
2938
  element: this.el,
2779
2939
  type: this?.model?.get("widgetType") ?? this.container?.model?.get("elType") ?? null,
2780
2940
  id: this?.model?.get("id") ?? null,
2781
- refreshView: this.refreshView.bind(this)
2941
+ refreshView: this.refreshView.bind(this),
2942
+ reactRoot: this.#reactRoot,
2943
+ reactContainer: this.#reactContainer
2782
2944
  };
2783
2945
  }
2784
2946
  refreshView() {
@@ -2799,6 +2961,8 @@ var createViewWithReplacements = (options) => {
2799
2961
  }
2800
2962
  onDestroy() {
2801
2963
  this.#triggerAltMethod("onDestroy");
2964
+ this.#reactRoot.unmount();
2965
+ this.#reactContainer.remove();
2802
2966
  }
2803
2967
  _afterRender() {
2804
2968
  this.#triggerAltMethod("_afterRender");
@@ -2937,7 +3101,7 @@ function initTabsModelExtensions() {
2937
3101
  var import_editor_v1_adapters13 = require("@elementor/editor-v1-adapters");
2938
3102
  var DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
2939
3103
  var initDocumentStructureResource = (reg) => {
2940
- const { mcpServer, sendResourceUpdated } = reg;
3104
+ const { resource, sendResourceUpdated } = reg;
2941
3105
  let currentDocumentStructure = null;
2942
3106
  const updateDocumentStructure = () => {
2943
3107
  const structure = getDocumentStructure();
@@ -2959,17 +3123,23 @@ var initDocumentStructureResource = (reg) => {
2959
3123
  updateDocumentStructure
2960
3124
  );
2961
3125
  updateDocumentStructure();
2962
- mcpServer.resource("document-structure", DOCUMENT_STRUCTURE_URI, async () => {
2963
- const structure = getDocumentStructure();
2964
- return {
2965
- contents: [
2966
- {
2967
- uri: DOCUMENT_STRUCTURE_URI,
2968
- text: JSON.stringify(structure, null, 2)
2969
- }
2970
- ]
2971
- };
2972
- });
3126
+ resource(
3127
+ "document-structure",
3128
+ DOCUMENT_STRUCTURE_URI,
3129
+ {
3130
+ description: "Document structure."
3131
+ },
3132
+ async () => {
3133
+ return {
3134
+ contents: [
3135
+ {
3136
+ uri: DOCUMENT_STRUCTURE_URI,
3137
+ text: JSON.stringify(getDocumentStructure(), null, 2)
3138
+ }
3139
+ ]
3140
+ };
3141
+ }
3142
+ );
2973
3143
  };
2974
3144
  function getDocumentStructure() {
2975
3145
  const extendedWindow = window;
@@ -3009,6 +3179,7 @@ function extractElementData(element) {
3009
3179
  }
3010
3180
 
3011
3181
  // src/mcp/tools/build-composition/tool.ts
3182
+ var import_editor_documents3 = require("@elementor/editor-documents");
3012
3183
  var import_editor_elements10 = require("@elementor/editor-elements");
3013
3184
 
3014
3185
  // src/composition-builder/composition-builder.ts
@@ -3423,6 +3594,16 @@ var CompositionBuilder = class _CompositionBuilder {
3423
3594
  }
3424
3595
  };
3425
3596
 
3597
+ // src/mcp/utils/get-composition-target-container.ts
3598
+ var import_editor_documents2 = require("@elementor/editor-documents");
3599
+ function getCompositionTargetContainer(documentContainer, documentType) {
3600
+ const firstChild = documentContainer.children?.[0];
3601
+ if (documentType === import_editor_documents2.COMPONENT_DOCUMENT_TYPE && firstChild) {
3602
+ return firstChild;
3603
+ }
3604
+ return documentContainer;
3605
+ }
3606
+
3426
3607
  // src/mcp/tools/build-composition/prompt.ts
3427
3608
  var import_editor_mcp2 = require("@elementor/editor-mcp");
3428
3609
  var generatePrompt = () => {
@@ -3618,6 +3799,8 @@ var initBuildCompositionsTool = (reg) => {
3618
3799
  const errors = [];
3619
3800
  const rootContainers = [];
3620
3801
  const documentContainer = (0, import_editor_elements10.getContainer)("document");
3802
+ const currentDocument = (0, import_editor_documents3.getCurrentDocument)();
3803
+ const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
3621
3804
  try {
3622
3805
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
3623
3806
  createElement: import_editor_elements10.createElement,
@@ -3630,7 +3813,7 @@ var initBuildCompositionsTool = (reg) => {
3630
3813
  configErrors,
3631
3814
  invalidStyles,
3632
3815
  rootContainers: generatedRootContainers
3633
- } = compositionBuilder.build(documentContainer);
3816
+ } = compositionBuilder.build(targetContainer);
3634
3817
  rootContainers.push(...generatedRootContainers);
3635
3818
  generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
3636
3819
  if (configErrors.length) {
@@ -4014,14 +4197,12 @@ var initGetElementConfigTool = (reg) => {
4014
4197
  var initCanvasMcp = (reg) => {
4015
4198
  const { setMCPDescription } = reg;
4016
4199
  setMCPDescription(
4017
- `Everything related to creative design, layout, styling and building the pages, specifically element of type "widget".
4200
+ `Everything related to V4 ( Atomic ) canvas.
4018
4201
  # Canvas workflow for new compositions
4019
- - Check existing global variables
4020
- - Check existing global classes
4021
- - Create missing global variables
4022
- - Create reusable global classes
4023
- - Build valid XML with minimal inline styles (layout/positioning only)
4024
- - Apply global classes to elements`
4202
+ - Configure elements settings and styles
4203
+ - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
4204
+ - Get and retrieve element configuration values
4205
+ `
4025
4206
  );
4026
4207
  initWidgetsSchemaResource(reg);
4027
4208
  initDocumentStructureResource(reg);