@elementor/editor-canvas 4.1.0-manual → 4.2.0-839

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 (41) hide show
  1. package/dist/index.d.mts +22 -4
  2. package/dist/index.d.ts +22 -4
  3. package/dist/index.js +773 -137
  4. package/dist/index.mjs +730 -86
  5. package/package.json +18 -18
  6. package/src/__tests__/settings-props-resolver.test.ts +3 -0
  7. package/src/composition-builder/composition-builder.ts +5 -5
  8. package/src/form-structure/utils.ts +4 -0
  9. package/src/hooks/__tests__/use-style-items.test.ts +55 -0
  10. package/src/hooks/use-style-items.ts +12 -14
  11. package/src/index.ts +2 -0
  12. package/src/init-settings-transformers.ts +4 -0
  13. package/src/init-style-transformers.ts +2 -0
  14. package/src/legacy/create-nested-templated-element-type.ts +11 -2
  15. package/src/legacy/create-pending-element.ts +74 -0
  16. package/src/legacy/create-templated-element-type.ts +2 -2
  17. package/src/legacy/types.ts +9 -1
  18. package/src/mcp/canvas-mcp.ts +8 -0
  19. package/src/mcp/resources/available-widgets-resource.ts +67 -0
  20. package/src/mcp/resources/document-structure-resource.ts +51 -36
  21. package/src/mcp/resources/editor-state-resource.ts +122 -0
  22. package/src/mcp/resources/general-context-resource.ts +99 -0
  23. package/src/mcp/resources/selected-element-resource.ts +217 -0
  24. package/src/mcp/resources/widgets-schema-resource.ts +74 -14
  25. package/src/mcp/tools/build-composition/prompt.ts +6 -0
  26. package/src/mcp/tools/build-composition/tool.ts +26 -0
  27. package/src/mcp/tools/configure-element/prompt.ts +6 -6
  28. package/src/mcp/tools/configure-element/schema.ts +1 -1
  29. package/src/mcp/tools/configure-element/tool.ts +12 -0
  30. package/src/mcp/tools/get-element-config/tool.ts +13 -3
  31. package/src/mcp/utils/do-update-element-property.ts +1 -1
  32. package/src/mcp/utils/element-data-util.ts +46 -0
  33. package/src/mcp/utils/validate-input.ts +1 -1
  34. package/src/sync/global-styles-imported-event.ts +8 -0
  35. package/src/transformers/settings/date-range-transformer.ts +12 -0
  36. package/src/transformers/settings/time-range-transformer.ts +12 -0
  37. package/src/transformers/shared/image-src-transformer.ts +2 -0
  38. package/src/transformers/shared/image-transformer.ts +4 -1
  39. package/src/transformers/styles/span-transformer.ts +5 -0
  40. package/src/utils/after-render.ts +26 -0
  41. package/src/mcp/utils/generate-available-tags.ts +0 -23
package/dist/index.mjs CHANGED
@@ -45,12 +45,81 @@ var initBreakpointsResource = (reg) => {
45
45
  };
46
46
 
47
47
  // src/mcp/resources/widgets-schema-resource.ts
48
- import { getWidgetsCache } from "@elementor/editor-elements";
48
+ import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
49
49
  import { ResourceTemplate } from "@elementor/editor-mcp";
50
50
  import {
51
51
  Schema
52
52
  } from "@elementor/editor-props";
53
53
  import { getStylesSchema } from "@elementor/editor-styles";
54
+
55
+ // src/mcp/utils/element-data-util.ts
56
+ import { getWidgetsCache } from "@elementor/editor-elements";
57
+ function hasV3Controls(controls) {
58
+ return typeof controls === "object" && controls !== null && Object.keys(controls).length > 0;
59
+ }
60
+ function isWidgetAvailableForLLM(config) {
61
+ if (!config) {
62
+ return false;
63
+ }
64
+ if (config.meta?.llm_support === false) {
65
+ return false;
66
+ }
67
+ if (config.atomic_props_schema) {
68
+ return true;
69
+ }
70
+ return hasV3Controls(config.controls);
71
+ }
72
+ function getWidgetVersion(config) {
73
+ return config?.atomic_props_schema ? "v4" : "v3";
74
+ }
75
+ function getAvailableWidgets() {
76
+ const cache = getWidgetsCache() ?? {};
77
+ return Object.keys(cache).filter((widgetType) => isWidgetAvailableForLLM(cache[widgetType])).sort().map((widgetType) => {
78
+ const config = cache[widgetType];
79
+ const description = typeof config?.meta?.description === "string" ? config.meta.description : void 0;
80
+ return {
81
+ type: widgetType,
82
+ version: getWidgetVersion(config),
83
+ ...description && { description }
84
+ };
85
+ });
86
+ }
87
+
88
+ // src/mcp/resources/widgets-schema-resource.ts
89
+ var V3_LAYOUT_CONTROL_TYPES = /* @__PURE__ */ new Set(["section", "tab", "tabs"]);
90
+ function extractV3ControlsMetadata(controls) {
91
+ if (!hasV3Controls(controls)) {
92
+ return {};
93
+ }
94
+ const result = {};
95
+ for (const [controlKey, raw] of Object.entries(controls)) {
96
+ if (!raw || typeof raw !== "object") {
97
+ continue;
98
+ }
99
+ const control = raw;
100
+ const controlType = typeof control.type === "string" ? control.type : void 0;
101
+ if (controlType && V3_LAYOUT_CONTROL_TYPES.has(controlType)) {
102
+ continue;
103
+ }
104
+ const entry = {};
105
+ if (Object.prototype.hasOwnProperty.call(control, "default")) {
106
+ entry.default = control.default;
107
+ }
108
+ if (controlType) {
109
+ entry.type = controlType;
110
+ }
111
+ if (Object.prototype.hasOwnProperty.call(control, "options") && control.options !== void 0) {
112
+ const options = control.options;
113
+ if (options && typeof options === "object" && !Array.isArray(options)) {
114
+ entry.options = Object.keys(options);
115
+ } else {
116
+ entry.options = options;
117
+ }
118
+ }
119
+ result[controlKey] = entry;
120
+ }
121
+ return result;
122
+ }
54
123
  var WIDGET_SCHEMA_URI = "elementor://widgets/schema/{widgetType}";
55
124
  var STYLE_SCHEMA_URI = "elementor://styles/schema/{category}";
56
125
  var BEST_PRACTICES_URI = "elementor://styles/best-practices";
@@ -98,7 +167,7 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
98
167
  }
99
168
  }),
100
169
  {
101
- description: "Common styles schema for the specified category"
170
+ description: "Common styles schema for the specified category (applicable for V4 elements only)"
102
171
  },
103
172
  async (uri, variables) => {
104
173
  const category = typeof variables.category === "string" ? variables.category : variables.category?.[0];
@@ -124,9 +193,9 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
124
193
  "widget-schema-by-type",
125
194
  new ResourceTemplate(WIDGET_SCHEMA_URI, {
126
195
  list: () => {
127
- const cache = getWidgetsCache() || {};
128
- const availableWidgets = Object.keys(cache || {}).filter(
129
- (widgetType) => cache[widgetType]?.atomic_props_schema && cache[widgetType].meta?.llm_support !== false
196
+ const cache = getWidgetsCache2() || {};
197
+ const availableWidgets = Object.keys(cache).filter(
198
+ (widgetType) => isWidgetAvailableForLLM(cache[widgetType])
130
199
  );
131
200
  return {
132
201
  resources: availableWidgets.map((widgetType) => ({
@@ -141,20 +210,34 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
141
210
  },
142
211
  async (uri, variables) => {
143
212
  const widgetType = typeof variables.widgetType === "string" ? variables.widgetType : variables.widgetType?.[0];
144
- const widgetData = getWidgetsCache()?.[widgetType];
145
- const propSchema = widgetData?.atomic_props_schema;
146
- if (!propSchema || !widgetData) {
213
+ const widgetData = getWidgetsCache2()?.[widgetType];
214
+ if (!widgetData) {
147
215
  throw new Error(`No prop schema found for element type: ${widgetType}`);
148
216
  }
217
+ const propSchema = widgetData.atomic_props_schema;
218
+ if (!propSchema) {
219
+ if (!hasV3Controls(widgetData.controls)) {
220
+ throw new Error(`No prop schema found for element type: ${widgetType}`);
221
+ }
222
+ const controlMetadata = extractV3ControlsMetadata(widgetData.controls);
223
+ return {
224
+ contents: [
225
+ {
226
+ uri: uri.toString(),
227
+ mimeType: "application/json",
228
+ text: JSON.stringify({
229
+ widget_version: "v3",
230
+ message: "This widget exists in the editor but has no atomic props schema (V4). Use control_metadata as non-authoritative hints from legacy controls.",
231
+ fields_note: "All settings are optional; there is no JSON schema for this widget type.",
232
+ properties: controlMetadata
233
+ })
234
+ }
235
+ ]
236
+ };
237
+ }
149
238
  const asJson = Object.fromEntries(
150
- Object.entries(propSchema).map(([key, propType]) => [
151
- key,
152
- Schema.propTypeToJsonSchema(propType)
153
- ])
239
+ Object.entries(propSchema).filter(([key, propType]) => Schema.isPropKeyConfigurable(key, propType)).map(([key, propType]) => [key, Schema.propTypeToJsonSchema(propType)])
154
240
  );
155
- Schema.nonConfigurablePropKeys.forEach((key) => {
156
- delete asJson[key];
157
- });
158
241
  const description = typeof widgetData?.meta?.description === "string" ? widgetData.meta.description : void 0;
159
242
  const defaultStyles = {};
160
243
  const baseStyleSchema = widgetData?.base_styles;
@@ -174,7 +257,7 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
174
257
  llmGuidance.default_styles = defaultStyles;
175
258
  }
176
259
  const allowedChildTypes = widgetData.allowed_child_types;
177
- const allWidgets = getWidgetsCache() || {};
260
+ const allWidgets = getWidgetsCache2() || {};
178
261
  const allowedParents = Object.entries(allWidgets).filter(([, parentConfig]) => parentConfig.allowed_child_types?.includes(widgetType)).map(([parentType]) => parentType);
179
262
  if (allowedChildTypes?.length || allowedParents.length) {
180
263
  llmGuidance.nesting = {
@@ -1049,8 +1132,9 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, getC
1049
1132
  ...style,
1050
1133
  cssName: provider.actions.resolveCssName(style.id)
1051
1134
  }));
1052
- return renderStyles({ styles: breakToBreakpoints(changedStyles), signal }).then((rendered) => {
1053
- updateCacheItems(cache, rendered);
1135
+ const breakpointSplit = breakToBreakpoints(changedStyles);
1136
+ return renderStyles({ styles: breakpointSplit, signal }).then((rendered) => {
1137
+ updateCacheItems(cache, changedIds, rendered);
1054
1138
  return getOrderedItems(cache);
1055
1139
  });
1056
1140
  }
@@ -1107,19 +1191,14 @@ function getChangedStyleIds(previous, current) {
1107
1191
  function getOrderedItems(cache) {
1108
1192
  return cache.orderedIds.map((id) => cache.itemsById.get(id)).filter((items) => items !== void 0).flat();
1109
1193
  }
1110
- function updateCacheItems(cache, changedItems) {
1194
+ function updateCacheItems(cache, changedIds, changedItems) {
1195
+ for (const id of changedIds) {
1196
+ cache.itemsById.delete(id);
1197
+ }
1111
1198
  for (const item of changedItems) {
1112
- const existing = cache.itemsById.get(item.id);
1113
- if (existing) {
1114
- const idx = existing.findIndex((e) => e.breakpoint === item.breakpoint && e.state === item.state);
1115
- if (idx >= 0) {
1116
- existing[idx] = item;
1117
- } else {
1118
- existing.push(item);
1119
- }
1120
- } else {
1121
- cache.itemsById.set(item.id, [item]);
1122
- }
1199
+ const existing = cache.itemsById.get(item.id) || [];
1200
+ existing.push(item);
1201
+ cache.itemsById.set(item.id, existing);
1123
1202
  }
1124
1203
  }
1125
1204
  function rebuildCache(cache, allStyles, items) {
@@ -1178,7 +1257,11 @@ var FORM_FIELD_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1178
1257
  "e-form-label",
1179
1258
  "e-form-checkbox",
1180
1259
  "e-form-submit-button",
1181
- "e-form-select"
1260
+ "e-form-select",
1261
+ "e-form-radio-button",
1262
+ "e-form-file-upload",
1263
+ "e-form-date-picker",
1264
+ "e-form-time-picker"
1182
1265
  ]);
1183
1266
  function getArgsElementType(args) {
1184
1267
  return args.model?.widgetType || args.model?.elType;
@@ -1393,6 +1476,17 @@ function createClassesTransformer() {
1393
1476
  });
1394
1477
  }
1395
1478
 
1479
+ // src/transformers/settings/date-range-transformer.ts
1480
+ var dateRangeTransformer = createTransformer((value) => {
1481
+ if (!value || Object.keys(value).length === 0) {
1482
+ return null;
1483
+ }
1484
+ return {
1485
+ min: value.min || null,
1486
+ max: value.max || null
1487
+ };
1488
+ });
1489
+
1396
1490
  // src/transformers/settings/date-time-transformer.ts
1397
1491
  var dateTimeTransformer = createTransformer((values) => {
1398
1492
  return values.map((value) => {
@@ -1427,10 +1521,22 @@ var queryTransformer = createTransformer(({ id }) => {
1427
1521
  return id ?? null;
1428
1522
  });
1429
1523
 
1524
+ // src/transformers/settings/time-range-transformer.ts
1525
+ var timeRangeTransformer = createTransformer((value) => {
1526
+ if (!value || Object.keys(value).length === 0) {
1527
+ return null;
1528
+ }
1529
+ return {
1530
+ min: value.min || null,
1531
+ max: value.max || null
1532
+ };
1533
+ });
1534
+
1430
1535
  // src/transformers/shared/image-src-transformer.ts
1431
1536
  var imageSrcTransformer = createTransformer((value) => ({
1432
1537
  id: value.id ?? null,
1433
- url: value.url ?? null
1538
+ url: value.url ?? null,
1539
+ alt: value.alt ?? null
1434
1540
  }));
1435
1541
 
1436
1542
  // src/transformers/shared/image-transformer.ts
@@ -1438,7 +1544,7 @@ import { getMediaAttachment } from "@elementor/wp-media";
1438
1544
  var imageTransformer = createTransformer(async (value) => {
1439
1545
  const { src, size: size2 } = value;
1440
1546
  if (!src?.id) {
1441
- return src?.url ? { src: src.url } : null;
1547
+ return src?.url ? { src: src.url, alt: src.alt ?? "" } : null;
1442
1548
  }
1443
1549
  const attachment = await getMediaAttachment({ id: src.id });
1444
1550
  const sizedAttachment = attachment?.sizes?.[size2 ?? ""];
@@ -1446,14 +1552,16 @@ var imageTransformer = createTransformer(async (value) => {
1446
1552
  return {
1447
1553
  src: sizedAttachment.url,
1448
1554
  height: sizedAttachment.height,
1449
- width: sizedAttachment.width
1555
+ width: sizedAttachment.width,
1556
+ alt: attachment.alt
1450
1557
  };
1451
1558
  }
1452
1559
  if (attachment) {
1453
1560
  return {
1454
1561
  src: attachment.url,
1455
1562
  height: attachment.height,
1456
- width: attachment.width
1563
+ width: attachment.width,
1564
+ alt: attachment.alt
1457
1565
  };
1458
1566
  }
1459
1567
  return null;
@@ -1540,7 +1648,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
1540
1648
 
1541
1649
  // src/init-settings-transformers.ts
1542
1650
  function initSettingsTransformers() {
1543
- 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);
1651
+ 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).register("date-range", dateRangeTransformer).register("time-range", timeRangeTransformer).registerFallback(plainTransformer);
1544
1652
  }
1545
1653
 
1546
1654
  // src/transformers/styles/background-color-overlay-transformer.ts
@@ -1745,6 +1853,11 @@ var sizeTransformer = createTransformer((value) => {
1745
1853
  return value.unit === "custom" ? value.size : `${value.size}${value.unit}`;
1746
1854
  });
1747
1855
 
1856
+ // src/transformers/styles/span-transformer.ts
1857
+ var spanTransformer = createTransformer((value) => {
1858
+ return value || 0 === value ? "span " + value : null;
1859
+ });
1860
+
1748
1861
  // src/transformers/styles/stroke-transformer.ts
1749
1862
  var strokeTransformer = createTransformer((value) => {
1750
1863
  const parsed = {
@@ -1851,7 +1964,7 @@ function initStyleTransformers() {
1851
1964
  ["block-start", "block-end", "inline-start", "inline-end"],
1852
1965
  ({ propKey, key }) => `${propKey}-${key}`
1853
1966
  )
1854
- ).register("filter", filterTransformer).register("backdrop-filter", filterTransformer).register("box-shadow", createCombineArrayTransformer(",")).register("background", backgroundTransformer).register("background-overlay", backgroundOverlayTransformer).register("background-color-overlay", backgroundColorOverlayTransformer).register("background-image-overlay", backgroundImageOverlayTransformer).register("background-gradient-overlay", backgroundGradientOverlayTransformer).register("gradient-color-stop", createCombineArrayTransformer(",")).register("color-stop", colorStopTransformer).register("background-image-position-offset", positionTransformer).register("background-image-size-scale", backgroundImageSizeScaleTransformer).register("image-src", imageSrcTransformer).register("image", imageTransformer).register("object-position", positionTransformer).register("transform-origin", transformOriginTransformer).register("perspective-origin", perspectiveOriginTransformer).register("transform-move", transformMoveTransformer).register("transform-scale", transformScaleTransformer).register("transform-rotate", transformRotateTransformer).register("transform-skew", transformSkewTransformer).register("transform-functions", transformFunctionsTransformer).register(
1967
+ ).register("filter", filterTransformer).register("backdrop-filter", filterTransformer).register("box-shadow", createCombineArrayTransformer(",")).register("background", backgroundTransformer).register("background-overlay", backgroundOverlayTransformer).register("background-color-overlay", backgroundColorOverlayTransformer).register("background-image-overlay", backgroundImageOverlayTransformer).register("background-gradient-overlay", backgroundGradientOverlayTransformer).register("gradient-color-stop", createCombineArrayTransformer(",")).register("color-stop", colorStopTransformer).register("background-image-position-offset", positionTransformer).register("background-image-size-scale", backgroundImageSizeScaleTransformer).register("image-src", imageSrcTransformer).register("image", imageTransformer).register("object-position", positionTransformer).register("span", spanTransformer).register("transform-origin", transformOriginTransformer).register("perspective-origin", perspectiveOriginTransformer).register("transform-move", transformMoveTransformer).register("transform-scale", transformScaleTransformer).register("transform-rotate", transformRotateTransformer).register("transform-skew", transformSkewTransformer).register("transform-functions", transformFunctionsTransformer).register(
1855
1968
  "transform",
1856
1969
  createMultiPropsTransformer(
1857
1970
  ["transform-functions", "transform-origin", "perspective", "perspective-origin"],
@@ -1876,7 +1989,7 @@ function initStyleTransformers() {
1876
1989
  }
1877
1990
 
1878
1991
  // src/legacy/init-legacy-views.ts
1879
- import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
1992
+ import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
1880
1993
  import { __privateListenTo, v1ReadyEvent as v1ReadyEvent2 } from "@elementor/editor-v1-adapters";
1881
1994
 
1882
1995
  // src/renderers/create-dom-renderer.ts
@@ -2007,6 +2120,60 @@ function createElementViewClassDeclaration() {
2007
2120
  // src/legacy/create-nested-templated-element-type.ts
2008
2121
  import { ELEMENT_STYLE_CHANGE_EVENT } from "@elementor/editor-elements";
2009
2122
 
2123
+ // src/legacy/create-pending-element.ts
2124
+ import {
2125
+ addModelToParent,
2126
+ findModelInDocument,
2127
+ generateElementId,
2128
+ getContainer
2129
+ } from "@elementor/editor-elements";
2130
+ function createPendingElement(wrapperView, data, options = {}) {
2131
+ const parentContainer = wrapperView.getContainer();
2132
+ const model = { ...data };
2133
+ if (!model.id) {
2134
+ model.id = generateElementId();
2135
+ }
2136
+ if (!model.elements) {
2137
+ model.elements = [];
2138
+ }
2139
+ const added = addModelToParent(parentContainer.id, model, options);
2140
+ if (!added) {
2141
+ return void 0;
2142
+ }
2143
+ const childId = model.id;
2144
+ const childModel = findModelInDocument(childId);
2145
+ if (!childModel) {
2146
+ return void 0;
2147
+ }
2148
+ const pendingContainer = {
2149
+ id: childId,
2150
+ settings: { get: () => ({}), set: () => ({}), toJSON: () => ({}) },
2151
+ parent: parentContainer,
2152
+ model: childModel,
2153
+ view: void 0,
2154
+ lookup() {
2155
+ return getContainer(childId) ?? pendingContainer;
2156
+ }
2157
+ };
2158
+ wrapperView.once("render", () => {
2159
+ wrapperView.model?.trigger?.("navigator:add", childModel, options);
2160
+ });
2161
+ if (options.edit !== false) {
2162
+ selectChildWhenWrapperRenders(wrapperView, childId);
2163
+ }
2164
+ return { getContainer: () => pendingContainer };
2165
+ }
2166
+ function selectChildWhenWrapperRenders(wrapperView, childId) {
2167
+ wrapperView.once("render", () => {
2168
+ const childContainer = getContainer(childId);
2169
+ if (childContainer?.model?.trigger) {
2170
+ childContainer.model.trigger("request:edit");
2171
+ return;
2172
+ }
2173
+ wrapperView.model?.trigger?.("request:edit");
2174
+ });
2175
+ }
2176
+
2010
2177
  // src/legacy/twig-rendering-utils.ts
2011
2178
  function setupTwigRenderer({ renderer, element }) {
2012
2179
  const templateKey = element.twig_main_template;
@@ -2224,6 +2391,7 @@ function createNestedTemplatedElementView({
2224
2391
  const AtomicElementBaseView = legacyWindow.elementor.modules.elements.views.createAtomicElementBase(type);
2225
2392
  const parentRenderChildren = AtomicElementBaseView.prototype._renderChildren;
2226
2393
  const parentOpenEditingPanel = AtomicElementBaseView.prototype._openEditingPanel;
2394
+ const parentAddElement = AtomicElementBaseView.prototype.addElement;
2227
2395
  return AtomicElementBaseView.extend({
2228
2396
  _abortController: null,
2229
2397
  _lastResolvedSettingsHash: null,
@@ -2331,7 +2499,6 @@ function createNestedTemplatedElementView({
2331
2499
  Array.from(newEl.attributes).forEach((attr) => {
2332
2500
  targetEl.setAttribute(attr.name, attr.value);
2333
2501
  });
2334
- targetEl.setAttribute("draggable", "true");
2335
2502
  targetEl.innerHTML = overlayHTML + newEl.innerHTML;
2336
2503
  if (needsTagSwap) {
2337
2504
  oldEl.replaceWith(targetEl);
@@ -2423,6 +2590,12 @@ function createNestedTemplatedElementView({
2423
2590
  _openEditingPanel(options) {
2424
2591
  this._doAfterRender(() => parentOpenEditingPanel.call(this, options));
2425
2592
  },
2593
+ addElement(data, options) {
2594
+ if (this.isRendered) {
2595
+ return parentAddElement.call(this, data, options);
2596
+ }
2597
+ return createPendingElement(this, data, options);
2598
+ },
2426
2599
  getInteractionId() {
2427
2600
  const originId = this.model.get("originId");
2428
2601
  const id = this.model.get("id");
@@ -2499,7 +2672,7 @@ import { createRoot } from "react-dom/client";
2499
2672
 
2500
2673
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2501
2674
  import * as React6 from "react";
2502
- import { getContainer, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
2675
+ import { getContainer as getContainer2, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
2503
2676
  import {
2504
2677
  htmlV3PropTypeUtil as htmlV3PropTypeUtil2,
2505
2678
  parseHtmlChildren,
@@ -2946,7 +3119,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
2946
3119
  runCommandSync(
2947
3120
  "document/elements/set-settings",
2948
3121
  {
2949
- container: getContainer(this.id),
3122
+ container: getContainer2(this.id),
2950
3123
  settings: {
2951
3124
  [key]: value
2952
3125
  }
@@ -3121,7 +3294,7 @@ function registerElementType(type, elementTypeGenerator) {
3121
3294
  }
3122
3295
  function initLegacyViews() {
3123
3296
  __privateListenTo(v1ReadyEvent2(), () => {
3124
- const widgetsCache = getWidgetsCache2() ?? {};
3297
+ const widgetsCache = getWidgetsCache3() ?? {};
3125
3298
  const legacyWindow = window;
3126
3299
  const renderer = createDomRenderer();
3127
3300
  registerProPromotionTypes(widgetsCache);
@@ -3207,7 +3380,67 @@ function initTabsModelExtensions() {
3207
3380
  registerModelExtensions("e-tab", tabModelExtensions);
3208
3381
  }
3209
3382
 
3383
+ // src/mcp/resources/available-widgets-resource.ts
3384
+ import { v1ReadyEvent as v1ReadyEvent3 } from "@elementor/editor-v1-adapters";
3385
+ var AVAILABLE_WIDGETS_URI = "elementor://context/available-widgets";
3386
+ var AVAILABLE_WIDGETS_URI_V4 = "elementor://context/available-widgets/v4";
3387
+ var initAvailableWidgetsResource = (reg) => {
3388
+ const { resource, sendResourceUpdated } = reg;
3389
+ const buildContents = (uri, filterFunction = () => true) => {
3390
+ const widgets = getAvailableWidgets().filter(filterFunction);
3391
+ return {
3392
+ contents: [
3393
+ {
3394
+ uri,
3395
+ mimeType: "application/json",
3396
+ text: JSON.stringify(widgets, null, 2)
3397
+ }
3398
+ ]
3399
+ };
3400
+ };
3401
+ const notifyResourcesUpdated = () => {
3402
+ sendResourceUpdated({
3403
+ uri: AVAILABLE_WIDGETS_URI,
3404
+ ...buildContents(AVAILABLE_WIDGETS_URI)
3405
+ });
3406
+ sendResourceUpdated({
3407
+ uri: AVAILABLE_WIDGETS_URI_V4,
3408
+ ...buildContents(AVAILABLE_WIDGETS_URI_V4, (w) => w.version === "v4")
3409
+ });
3410
+ };
3411
+ resource(
3412
+ "available-widgets-v4",
3413
+ AVAILABLE_WIDGETS_URI_V4,
3414
+ {
3415
+ description: "All registered v4 version widgets"
3416
+ },
3417
+ async () => buildContents(AVAILABLE_WIDGETS_URI_V4, (w) => w.version === "v4")
3418
+ );
3419
+ resource(
3420
+ "available-widgets",
3421
+ AVAILABLE_WIDGETS_URI,
3422
+ {
3423
+ description: "All registered widget types with v3/v4 version metadata and description."
3424
+ },
3425
+ async () => buildContents(AVAILABLE_WIDGETS_URI)
3426
+ );
3427
+ const eventName = v1ReadyEvent3().name;
3428
+ const onV1Ready = () => {
3429
+ const widgets = getAvailableWidgets();
3430
+ if (widgets.length === 0) {
3431
+ return;
3432
+ }
3433
+ window.removeEventListener(eventName, onV1Ready);
3434
+ notifyResourcesUpdated();
3435
+ };
3436
+ window.addEventListener(eventName, onV1Ready);
3437
+ onV1Ready();
3438
+ };
3439
+
3210
3440
  // src/mcp/resources/document-structure-resource.ts
3441
+ import {
3442
+ getWidgetsCache as getWidgetsCache4
3443
+ } from "@elementor/editor-elements";
3211
3444
  import { __privateListenTo as listenTo, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
3212
3445
  var DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
3213
3446
  var initDocumentStructureResource = (reg) => {
@@ -3228,7 +3461,8 @@ var initDocumentStructureResource = (reg) => {
3228
3461
  commandEndEvent4("document/elements/move"),
3229
3462
  commandEndEvent4("document/elements/copy"),
3230
3463
  commandEndEvent4("document/elements/paste"),
3231
- commandEndEvent4("editor/documents/attach-preview")
3464
+ commandEndEvent4("editor/documents/attach-preview"),
3465
+ commandEndEvent4("editor/documents/switch")
3232
3466
  ],
3233
3467
  updateDocumentStructure
3234
3468
  );
@@ -3258,9 +3492,7 @@ function getDocumentStructure() {
3258
3492
  return { error: "No active document found" };
3259
3493
  }
3260
3494
  const containers = document2.container?.children || [];
3261
- const elements = containers.map(
3262
- (container) => extractElementData(container)
3263
- );
3495
+ const elements = containers.map((container) => extractElementData(container));
3264
3496
  return {
3265
3497
  documentId: document2.id,
3266
3498
  documentType: document2.config.type,
@@ -3268,6 +3500,16 @@ function getDocumentStructure() {
3268
3500
  elements: elements.filter((el) => el !== null)
3269
3501
  };
3270
3502
  }
3503
+ function resolveElementVersion(element) {
3504
+ if (element.model?.config?.atomic) {
3505
+ return "v4";
3506
+ }
3507
+ const widgetType = element.model?.attributes?.widgetType;
3508
+ if (widgetType && getWidgetsCache4()?.[widgetType]?.atomic_props_schema) {
3509
+ return "v4";
3510
+ }
3511
+ return "v3";
3512
+ }
3271
3513
  function extractElementData(element) {
3272
3514
  if (!element || !element.model) {
3273
3515
  return null;
@@ -3276,7 +3518,8 @@ function extractElementData(element) {
3276
3518
  const result = {
3277
3519
  id: model.id,
3278
3520
  elType: model.elType,
3279
- widgetType: model.widgetType || void 0
3521
+ widgetType: model.widgetType || void 0,
3522
+ version: resolveElementVersion(element)
3280
3523
  };
3281
3524
  const title = model.title || element.model?.editor_settings?.title;
3282
3525
  if (title) {
@@ -3288,28 +3531,346 @@ function extractElementData(element) {
3288
3531
  return result;
3289
3532
  }
3290
3533
 
3534
+ // src/mcp/resources/editor-state-resource.ts
3535
+ import { __privateListenTo as listenTo2, commandEndEvent as commandEndEvent5 } from "@elementor/editor-v1-adapters";
3536
+ var CURRENTLY_VIEWED_SCREEN = "The user is currently viewing the Elementor editor";
3537
+ var PAGE_CONTENT_CHARACTER_LIMIT = 500;
3538
+ var PREVIEW_TEXT_NODE_MIN_LENGTH = 2;
3539
+ var EDITOR_STATE_URI = "elementor://context/editor-state";
3540
+ var initEditorStateResource = (reg) => {
3541
+ const { resource, sendResourceUpdated } = reg;
3542
+ let lastSerializedState = "";
3543
+ const buildState = () => ({
3544
+ currentlyViewedScreen: CURRENTLY_VIEWED_SCREEN,
3545
+ pageContent: getPageContentFromPreview(),
3546
+ pageTitle: getPageTitle()
3547
+ });
3548
+ const notifyIfChanged = () => {
3549
+ const serialized = JSON.stringify(buildState());
3550
+ if (serialized === lastSerializedState) {
3551
+ return;
3552
+ }
3553
+ lastSerializedState = serialized;
3554
+ sendResourceUpdated({ uri: EDITOR_STATE_URI });
3555
+ };
3556
+ listenTo2(
3557
+ [commandEndEvent5("editor/documents/switch"), commandEndEvent5("editor/documents/attach-preview")],
3558
+ notifyIfChanged
3559
+ );
3560
+ lastSerializedState = JSON.stringify(buildState());
3561
+ resource(
3562
+ "editor-state",
3563
+ EDITOR_STATE_URI,
3564
+ {
3565
+ description: "Editor page title, preview text snapshot, and viewed screen label."
3566
+ },
3567
+ async () => {
3568
+ return {
3569
+ contents: [
3570
+ {
3571
+ uri: EDITOR_STATE_URI,
3572
+ text: JSON.stringify(buildState(), null, 2)
3573
+ }
3574
+ ]
3575
+ };
3576
+ }
3577
+ );
3578
+ };
3579
+ function getPageContentFromPreview() {
3580
+ try {
3581
+ const root = window.elementor?.$previewContents?.[0];
3582
+ if (!root) {
3583
+ return null;
3584
+ }
3585
+ const content = [];
3586
+ const clone = root.cloneNode(true);
3587
+ clone.querySelectorAll(".elementor-editor-element-settings, #elementor-add-new-section").forEach((el) => {
3588
+ el.remove();
3589
+ });
3590
+ const walk = (node, insideElementorElement = false) => {
3591
+ const isInside = node.classList?.contains("elementor-element") || insideElementorElement;
3592
+ if (node.nodeType === Node.TEXT_NODE && isInside) {
3593
+ const text2 = node.textContent?.trim().replace(/\s+/g, " ");
3594
+ if (text2 && text2.length > PREVIEW_TEXT_NODE_MIN_LENGTH) {
3595
+ content.push(text2);
3596
+ }
3597
+ } else {
3598
+ node.childNodes.forEach((child) => {
3599
+ walk(child, isInside);
3600
+ });
3601
+ }
3602
+ };
3603
+ walk(clone);
3604
+ const text = content.join(" ");
3605
+ if (text.length > PAGE_CONTENT_CHARACTER_LIMIT) {
3606
+ return text.slice(0, PAGE_CONTENT_CHARACTER_LIMIT) + "...";
3607
+ }
3608
+ return text;
3609
+ } catch {
3610
+ return null;
3611
+ }
3612
+ }
3613
+ function getPageTitle() {
3614
+ try {
3615
+ const extendedWindow = window;
3616
+ const currentDocument = extendedWindow.elementor?.documents?.getCurrent?.();
3617
+ const postTitle = currentDocument?.config?.settings?.post_title;
3618
+ if (postTitle) {
3619
+ return postTitle;
3620
+ }
3621
+ let title = document.title || "Page";
3622
+ title = title.split(/\s*[‹»|–—-]\s*/)[0];
3623
+ const trimmed = title.trim();
3624
+ return trimmed || "Page";
3625
+ } catch {
3626
+ return "Page";
3627
+ }
3628
+ }
3629
+
3630
+ // src/mcp/resources/general-context-resource.ts
3631
+ import { __privateListenTo as listenTo3, commandEndEvent as commandEndEvent6 } from "@elementor/editor-v1-adapters";
3632
+ var GENERAL_CONTEXT_URI = "elementor://context/general";
3633
+ var initGeneralContextResource = (reg) => {
3634
+ const { resource, sendResourceUpdated } = reg;
3635
+ let lastSerializedPayload = null;
3636
+ const getPageTitle2 = () => {
3637
+ const extendedWindow = window;
3638
+ const title = extendedWindow.elementor?.documents?.getCurrent?.()?.config?.settings?.post_title;
3639
+ if (!title?.trim()) {
3640
+ return null;
3641
+ }
3642
+ return title;
3643
+ };
3644
+ const buildPayload = () => {
3645
+ const extendedWindow = window;
3646
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
3647
+ const postParam = new URLSearchParams(location.search).get("post");
3648
+ const parsedPostId = postParam ? Number(postParam) : null;
3649
+ const postId = parsedPostId !== null && Number.isFinite(parsedPostId) ? parsedPostId : null;
3650
+ const pageTitle = getPageTitle2();
3651
+ const urlObject = new URL(window.location.href);
3652
+ const pageUrl = urlObject.pathname + urlObject.search;
3653
+ const pageName = pageTitle || "Elementor Editor";
3654
+ const plugins = extendedWindow.angieConfig?.plugins;
3655
+ return {
3656
+ timezone,
3657
+ postId,
3658
+ currentPage: {
3659
+ pageName,
3660
+ pageTitle,
3661
+ pageUrl
3662
+ },
3663
+ ...plugins && { plugins }
3664
+ };
3665
+ };
3666
+ const pushUpdateIfChanged = () => {
3667
+ const serialized = JSON.stringify(buildPayload());
3668
+ if (serialized === lastSerializedPayload) {
3669
+ return;
3670
+ }
3671
+ lastSerializedPayload = serialized;
3672
+ sendResourceUpdated({ uri: GENERAL_CONTEXT_URI });
3673
+ };
3674
+ resource(
3675
+ "general-context",
3676
+ GENERAL_CONTEXT_URI,
3677
+ {
3678
+ description: "General context: timezone, post id, and current page."
3679
+ },
3680
+ async () => {
3681
+ return {
3682
+ contents: [
3683
+ {
3684
+ uri: GENERAL_CONTEXT_URI,
3685
+ mimeType: "application/json",
3686
+ text: JSON.stringify(buildPayload(), null, 2)
3687
+ }
3688
+ ]
3689
+ };
3690
+ }
3691
+ );
3692
+ listenTo3(
3693
+ [
3694
+ commandEndEvent6("editor/documents/switch"),
3695
+ commandEndEvent6("editor/documents/attach-preview"),
3696
+ commandEndEvent6("document/elements/settings")
3697
+ ],
3698
+ pushUpdateIfChanged
3699
+ );
3700
+ pushUpdateIfChanged();
3701
+ };
3702
+
3703
+ // src/mcp/resources/selected-element-resource.ts
3704
+ import { getContainer as getContainer3, getSelectedElements, getWidgetsCache as getWidgetsCache5 } from "@elementor/editor-elements";
3705
+ import {
3706
+ __privateListenTo as listenTo4,
3707
+ commandEndEvent as commandEndEvent7
3708
+ } from "@elementor/editor-v1-adapters";
3709
+ var SELECTED_ELEMENT_URI = "elementor://context/selected-element";
3710
+ var initSelectedElementResource = (reg) => {
3711
+ const { resource, sendResourceUpdated } = reg;
3712
+ let currentPayloadText = null;
3713
+ const publishIfChanged = (payload) => {
3714
+ const nextText = JSON.stringify(payload);
3715
+ if (nextText !== currentPayloadText) {
3716
+ currentPayloadText = nextText;
3717
+ sendResourceUpdated({ uri: SELECTED_ELEMENT_URI });
3718
+ }
3719
+ };
3720
+ const onCommand = (e) => {
3721
+ if (e.type !== "command") {
3722
+ return;
3723
+ }
3724
+ const commandEvent = e;
3725
+ if (commandEvent.command === "document/elements/deselect-all") {
3726
+ publishIfChanged(createEmptySelectedElementPayload());
3727
+ return;
3728
+ }
3729
+ if (commandEvent.command !== "document/elements/select" && commandEvent.command !== "document/elements/settings") {
3730
+ return;
3731
+ }
3732
+ const { container } = commandEvent.args || {};
3733
+ if (container?.id) {
3734
+ publishIfChanged(buildPayloadFromContainer(container));
3735
+ return;
3736
+ }
3737
+ publishIfChanged(readSelectionFromEditor());
3738
+ };
3739
+ listenTo4(
3740
+ [
3741
+ commandEndEvent7("document/elements/select"),
3742
+ commandEndEvent7("document/elements/deselect-all"),
3743
+ commandEndEvent7("document/elements/settings")
3744
+ ],
3745
+ onCommand
3746
+ );
3747
+ publishIfChanged(readSelectionFromEditor());
3748
+ resource(
3749
+ "selected-element",
3750
+ SELECTED_ELEMENT_URI,
3751
+ {
3752
+ description: "Currently selected Elementor element context."
3753
+ },
3754
+ async () => {
3755
+ return {
3756
+ contents: [
3757
+ {
3758
+ uri: SELECTED_ELEMENT_URI,
3759
+ text: JSON.stringify(readSelectionFromEditor(), null, 2)
3760
+ }
3761
+ ]
3762
+ };
3763
+ }
3764
+ );
3765
+ };
3766
+ function createEmptySelectedElementPayload() {
3767
+ return {
3768
+ elementDisplayName: null,
3769
+ elementType: null,
3770
+ properties: null,
3771
+ selectedElementId: null,
3772
+ selectedParentId: null,
3773
+ version: null,
3774
+ widgetType: null
3775
+ };
3776
+ }
3777
+ function readSelectionFromEditor() {
3778
+ const elements = getSelectedElements();
3779
+ if (elements.length !== 1) {
3780
+ return createEmptySelectedElementPayload();
3781
+ }
3782
+ const container = getContainer3(elements[0].id);
3783
+ return buildPayloadFromContainer(container);
3784
+ }
3785
+ function buildPayloadFromContainer(container) {
3786
+ if (!container?.id) {
3787
+ return createEmptySelectedElementPayload();
3788
+ }
3789
+ const widgetType = container.model.get("widgetType") ?? null;
3790
+ const elementType = container.type ?? "widget";
3791
+ return {
3792
+ elementDisplayName: getElementDisplayName(container),
3793
+ elementType,
3794
+ properties: getElementProperties(container, widgetType),
3795
+ selectedElementId: container.id,
3796
+ selectedParentId: container.parent?.id ?? null,
3797
+ version: resolveElementVersion2(container, widgetType),
3798
+ widgetType
3799
+ };
3800
+ }
3801
+ function resolveElementVersion2(container, widgetType) {
3802
+ if (container.model?.config?.atomic) {
3803
+ return "v4";
3804
+ }
3805
+ if (widgetType && getWidgetsCache5()?.[widgetType]?.atomic_props_schema) {
3806
+ return "v4";
3807
+ }
3808
+ return "v3";
3809
+ }
3810
+ function getElementProperties(container, widgetType) {
3811
+ const settings = container.settings?.toJSON?.();
3812
+ if (!settings || typeof settings !== "object") {
3813
+ return null;
3814
+ }
3815
+ const widgetConfig = widgetType ? getWidgetsCache5()?.[widgetType] : null;
3816
+ const controls = widgetConfig?.controls;
3817
+ const filtered = {};
3818
+ for (const [key, value] of Object.entries(settings)) {
3819
+ if (value === void 0 || value === null || value === "") {
3820
+ continue;
3821
+ }
3822
+ const controlDefault = controls?.[key]?.default;
3823
+ if (controlDefault !== void 0 && JSON.stringify(value) === JSON.stringify(controlDefault)) {
3824
+ continue;
3825
+ }
3826
+ filtered[key] = value;
3827
+ }
3828
+ return Object.keys(filtered).length > 0 ? filtered : null;
3829
+ }
3830
+ function getElementDisplayName(container) {
3831
+ try {
3832
+ if (container.label) {
3833
+ return container.label;
3834
+ }
3835
+ const widgetType = container.model?.get?.("widgetType");
3836
+ if (widgetType) {
3837
+ const capitalizedType = widgetType.charAt(0).toUpperCase() + widgetType.slice(1);
3838
+ return capitalizedType.replace(/-/g, " ");
3839
+ }
3840
+ if (container.type === "container") {
3841
+ return "Container";
3842
+ }
3843
+ if (container.type === "section") {
3844
+ return "Section";
3845
+ }
3846
+ return `Element ${container.id}`;
3847
+ } catch {
3848
+ return `Element ${container.id}`;
3849
+ }
3850
+ }
3851
+
3291
3852
  // src/mcp/tools/build-composition/tool.ts
3292
3853
  import { getCurrentDocument } from "@elementor/editor-documents";
3293
3854
  import {
3294
3855
  createElement as createElement8,
3295
3856
  deleteElement,
3296
- getContainer as getContainer3,
3297
- getWidgetsCache as getWidgetsCache6
3857
+ getContainer as getContainer5,
3858
+ getWidgetsCache as getWidgetsCache9
3298
3859
  } from "@elementor/editor-elements";
3299
3860
 
3300
3861
  // src/composition-builder/composition-builder.ts
3301
3862
  import {
3302
3863
  createElement as createElement7,
3303
- generateElementId,
3304
- getContainer as getContainer2,
3305
- getWidgetsCache as getWidgetsCache5
3864
+ generateElementId as generateElementId2,
3865
+ getContainer as getContainer4,
3866
+ getWidgetsCache as getWidgetsCache8
3306
3867
  } from "@elementor/editor-elements";
3307
3868
 
3308
3869
  // src/mcp/utils/do-update-element-property.ts
3309
3870
  import {
3310
3871
  createElementStyle,
3311
3872
  getElementStyles,
3312
- getWidgetsCache as getWidgetsCache3,
3873
+ getWidgetsCache as getWidgetsCache6,
3313
3874
  updateElementSettings,
3314
3875
  updateElementStyle
3315
3876
  } from "@elementor/editor-elements";
@@ -3402,7 +3963,7 @@ var doUpdateElementProperty = (params) => {
3402
3963
  }
3403
3964
  return;
3404
3965
  }
3405
- const elementPropSchema = getWidgetsCache3()?.[elementType]?.atomic_props_schema;
3966
+ const elementPropSchema = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
3406
3967
  if (!elementPropSchema) {
3407
3968
  throw new Error(`No prop schema found for element type: ${elementType}`);
3408
3969
  }
@@ -3426,7 +3987,7 @@ var doUpdateElementProperty = (params) => {
3426
3987
  };
3427
3988
 
3428
3989
  // src/mcp/utils/validate-input.ts
3429
- import { getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
3990
+ import { getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
3430
3991
  import { Schema as Schema3 } from "@elementor/editor-props";
3431
3992
  import { getStylesSchema as getStylesSchema4 } from "@elementor/editor-styles";
3432
3993
  var _widgetsSchema = null;
@@ -3434,7 +3995,7 @@ var validateInput = {
3434
3995
  get widgetsSchema() {
3435
3996
  if (!_widgetsSchema) {
3436
3997
  const schema2 = {};
3437
- const cache = getWidgetsCache4();
3998
+ const cache = getWidgetsCache7();
3438
3999
  if (!cache) {
3439
4000
  return {};
3440
4001
  }
@@ -3461,7 +4022,7 @@ var validateInput = {
3461
4022
  if (!propSchema) {
3462
4023
  errors.push(`Property "${propName}" is not defined in the schema.`);
3463
4024
  hasInvalidKey = true;
3464
- } else if (!Schema3.isPropKeyConfigurable(propName)) {
4025
+ } else if (!Schema3.isPropKeyConfigurable(propName, propSchema)) {
3465
4026
  errors.push(`Property "${propName}" is not configurable.`);
3466
4027
  } else {
3467
4028
  const { valid } = Schema3.validatePropValue(propSchema, propValue);
@@ -3514,13 +4075,13 @@ var validateInput = {
3514
4075
  var CompositionBuilder = class _CompositionBuilder {
3515
4076
  elementConfig = {};
3516
4077
  elementStylesConfig = {};
3517
- elementCusomCSS = {};
4078
+ elementCustomCSS = {};
3518
4079
  rootContainers = [];
3519
4080
  api = {
3520
4081
  createElement: createElement7,
3521
- getWidgetsCache: getWidgetsCache5,
3522
- generateElementId,
3523
- getContainer: getContainer2,
4082
+ getWidgetsCache: getWidgetsCache8,
4083
+ generateElementId: generateElementId2,
4084
+ getContainer: getContainer4,
3524
4085
  doUpdateElementProperty
3525
4086
  };
3526
4087
  xml;
@@ -3551,7 +4112,7 @@ var CompositionBuilder = class _CompositionBuilder {
3551
4112
  this.elementStylesConfig = config;
3552
4113
  }
3553
4114
  setCustomCSS(config) {
3554
- this.elementCusomCSS = config;
4115
+ this.elementCustomCSS = config;
3555
4116
  }
3556
4117
  getXML() {
3557
4118
  return this.xml;
@@ -3631,7 +4192,7 @@ var CompositionBuilder = class _CompositionBuilder {
3631
4192
  const allConfigIds = /* @__PURE__ */ new Set([
3632
4193
  ...Object.keys(this.elementConfig),
3633
4194
  ...Object.keys(this.elementStylesConfig),
3634
- ...Object.keys(this.elementCusomCSS)
4195
+ ...Object.keys(this.elementCustomCSS)
3635
4196
  ]);
3636
4197
  for (const configId of allConfigIds) {
3637
4198
  let element, node;
@@ -3642,7 +4203,7 @@ var CompositionBuilder = class _CompositionBuilder {
3642
4203
  if (this.elementConfig[configId]) {
3643
4204
  configErrors.push(msg);
3644
4205
  }
3645
- if (this.elementStylesConfig[configId] || this.elementCusomCSS[configId]) {
4206
+ if (this.elementStylesConfig[configId] || this.elementCustomCSS[configId]) {
3646
4207
  styleErrors.push(msg);
3647
4208
  }
3648
4209
  continue;
@@ -3692,7 +4253,7 @@ var CompositionBuilder = class _CompositionBuilder {
3692
4253
  }
3693
4254
  }
3694
4255
  }
3695
- const customCSS = this.elementCusomCSS[configId];
4256
+ const customCSS = this.elementCustomCSS[configId];
3696
4257
  if (customCSS) {
3697
4258
  try {
3698
4259
  this.api.doUpdateElementProperty({
@@ -3763,6 +4324,10 @@ var generatePrompt = () => {
3763
4324
  # RESOURCES (Read before use)
3764
4325
  - [elementor://global-classes] - Check FIRST for reusable classes
3765
4326
  - [elementor://global-variables] - ONLY use variables defined here
4327
+ - [${AVAILABLE_WIDGETS_URI}/v4]
4328
+
4329
+ # TOOL SUPPORT
4330
+ This tool support v4 elements only
3766
4331
 
3767
4332
  # WORKFLOW
3768
4333
  1. Check/create global classes via "create-global-class" tool
@@ -3944,24 +4509,26 @@ var initBuildCompositionsTool = (reg) => {
3944
4509
  { description: "Styles schema", uri: STYLE_SCHEMA_URI },
3945
4510
  { description: "Global Classes", uri: "elementor://global-classes" },
3946
4511
  { description: "Global Variables", uri: "elementor://global-variables" },
3947
- { description: "Styles best practices", uri: BEST_PRACTICES_URI }
4512
+ { description: "Styles best practices", uri: BEST_PRACTICES_URI },
4513
+ { description: "Available widgets for this tool", uri: AVAILABLE_WIDGETS_URI_V4 }
3948
4514
  ],
3949
4515
  outputSchema,
3950
4516
  modelPreferences: {
3951
4517
  hints: [{ name: "claude-sonnet-4-5" }]
3952
4518
  },
3953
4519
  handler: async (params) => {
4520
+ assertCompositionXmlUsesV4WidgetsOnly(params.xmlStructure);
3954
4521
  const { xmlStructure, elementConfig, stylesConfig, customCSS } = params;
3955
4522
  let generatedXML = "";
3956
4523
  const errors = [];
3957
4524
  const rootContainers = [];
3958
- const documentContainer = getContainer3("document");
4525
+ const documentContainer = getContainer5("document");
3959
4526
  const currentDocument = getCurrentDocument();
3960
4527
  const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
3961
4528
  try {
3962
4529
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
3963
4530
  createElement: createElement8,
3964
- getWidgetsCache: getWidgetsCache6
4531
+ getWidgetsCache: getWidgetsCache9
3965
4532
  });
3966
4533
  compositionBuilder.setElementConfig(elementConfig);
3967
4534
  compositionBuilder.setStylesConfig(stylesConfig);
@@ -4038,6 +4605,31 @@ Remember: Global classes ensure design consistency and reusability. Don't skip a
4038
4605
  }
4039
4606
  });
4040
4607
  };
4608
+ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
4609
+ const doc = new DOMParser().parseFromString(xmlStructure, "application/xml");
4610
+ if (doc.querySelector("parsererror")) {
4611
+ throw new Error("Failed to parse XML string: " + doc);
4612
+ }
4613
+ const widgetsCache = getWidgetsCache9() ?? {};
4614
+ for (const node of doc.querySelectorAll("*")) {
4615
+ const type = node.tagName;
4616
+ const widgetData = widgetsCache[type];
4617
+ if (!widgetData) {
4618
+ continue;
4619
+ }
4620
+ if (widgetData.elType !== "widget") {
4621
+ continue;
4622
+ }
4623
+ if (!widgetData.atomic_props_schema) {
4624
+ throw new Error(
4625
+ `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${type}`
4626
+ );
4627
+ }
4628
+ }
4629
+ }
4630
+
4631
+ // src/mcp/tools/configure-element/tool.ts
4632
+ import { getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
4041
4633
 
4042
4634
  // src/mcp/tools/configure-element/prompt.ts
4043
4635
  var configureElementToolPrompt = `Configure an existing element on the page.
@@ -4049,11 +4641,11 @@ var configureElementToolPrompt = `Configure an existing element on the page.
4049
4641
  2. [${STYLE_SCHEMA_URI}]
4050
4642
  Required to understand the styles schema for the widgets. All widgets share the same styles schema, grouped by categories.
4051
4643
  Use this resource to understand which style properties are available for each element, and how to structure the "stylePropertiesToChange" parameter.
4052
- 3. If not sure about the PropValues schema, you can use the "get-element-configuration-values" tool to retreive the current PropValues configuration of the element.
4644
+ 3. If not sure about the PropValues schema, you can use the "get-element-configuration-values" tool to retrieve the current PropValues configuration of the element.
4053
4645
 
4054
4646
  Before using this tool, check the definitions of the elements PropTypes at the resource "widget-schema-by-type" at editor-canvas__elementor://widgets/schema/{widgetType}
4055
4647
  All widgets share a common _style property for styling, which uses the common styles schema.
4056
- Retreive and check the common styles schema at the resource list "styles-schema" at editor-canvas__elementor://styles/schema/{category}
4648
+ Retrieve and check the common styles schema at the resource list "styles-schema" at editor-canvas__elementor://styles/schema/{category}
4057
4649
 
4058
4650
  # Parameters
4059
4651
  - propertiesToChange: An object containing the properties to change, with their new values. MANDATORY. When updating a style only, provide an empty object.
@@ -4082,19 +4674,19 @@ PropValue structure:
4082
4674
  }
4083
4675
 
4084
4676
  <IMPORTANT>
4085
- ALWAYS MAKE SURE you have the PropType schemas for the element you are configuring, and the common-styles schema for styling. If you are not sure, retreive the schema from the resources mentioned above.
4677
+ ALWAYS MAKE SURE you have the PropType schemas for the element you are configuring, and the common-styles schema for styling. If you are not sure, retrieve the schema from the resources mentioned above.
4086
4678
  </IMPORTANT>
4087
4679
 
4088
4680
  You can use multiple property changes at once by providing multiple entries in the propertiesToChange object, including _style alongside non-style props.
4089
4681
  Some properties are nested, use the root property name, then objects with nested values inside, as the complete schema suggests.
4090
4682
 
4091
- Make sure you have the "widget-schema-by-type" resource available to retreive the PropType schema for the element type you are configuring.
4092
- Make sure you have to "styles-schema" resources available to retreive the common styles schema.
4683
+ Make sure you have the "widget-schema-by-type" resource available to retrieve the PropType schema for the element type you are configuring.
4684
+ Make sure you have to "styles-schema" resources available to retrieve the common styles schema.
4093
4685
 
4094
4686
  # How to configure elements
4095
4687
  We use a dedicated PropType Schema for configuring elements, including styles. When you configure an element, you must use the EXACT PropType Value as defined in the schema.
4096
4688
  For styleProperties, use the style schema provided, as it also uses the PropType format.
4097
- For all non-primitive types, provide the key property as defined in the schema as $$type in the generated objecct, as it is MANDATORY for parsing.
4689
+ For all non-primitive types, provide the key property as defined in the schema as $$type in the generated object, as it is MANDATORY for parsing.
4098
4690
 
4099
4691
  Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property from the original configuration for every property you are changing.
4100
4692
 
@@ -4150,7 +4742,7 @@ var inputSchema2 = {
4150
4742
  z2.any().describe(`The style PropValue, refer to [${STYLE_SCHEMA_URI}] how to generate values`),
4151
4743
  z2.any()
4152
4744
  ).describe("An object record containing style property names and their new values to be set on the element").default({}),
4153
- elementType: z2.string().describe("The type of the element to retreive the schema"),
4745
+ elementType: z2.string().describe("The type of the element to retrieve the schema"),
4154
4746
  elementId: z2.string().describe("The unique id of the element to configure")
4155
4747
  };
4156
4748
  var outputSchema2 = {
@@ -4177,6 +4769,17 @@ var initConfigureElementTool = (reg) => {
4177
4769
  speedPriority: 0.7
4178
4770
  },
4179
4771
  handler: ({ elementId, propertiesToChange, elementType, stylePropertiesToChange }) => {
4772
+ const widgetData = getWidgetsCache10()?.[elementType];
4773
+ if (!widgetData) {
4774
+ throw new Error(
4775
+ `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
4776
+ );
4777
+ }
4778
+ if (!widgetData.atomic_props_schema) {
4779
+ throw new Error(
4780
+ `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
4781
+ );
4782
+ }
4180
4783
  const toUpdate = Object.entries(propertiesToChange);
4181
4784
  const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToChange);
4182
4785
  const { valid: stylesValid, errors: stylesErrors } = validateInput.validateStyles(
@@ -4258,7 +4861,7 @@ Check the styles schema at the resource [${STYLE_SCHEMA_URI.replace(
4258
4861
  }
4259
4862
 
4260
4863
  // src/mcp/tools/get-element-config/tool.ts
4261
- import { getContainer as getContainer4, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
4864
+ import { getContainer as getContainer6, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache11 } from "@elementor/editor-elements";
4262
4865
  import { Schema as Schema4 } from "@elementor/editor-props";
4263
4866
  import { z as z3 } from "@elementor/schema";
4264
4867
  var schema = {
@@ -4297,12 +4900,24 @@ var initGetElementConfigTool = (reg) => {
4297
4900
  speedPriority: 0.9
4298
4901
  },
4299
4902
  handler: async ({ elementId }) => {
4300
- const element = getContainer4(elementId);
4903
+ const element = getContainer6(elementId);
4301
4904
  if (!element) {
4302
4905
  throw new Error(`Element with ID ${elementId} not found.`);
4303
4906
  }
4907
+ const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
4908
+ const widgetData = getWidgetsCache11()?.[elementType];
4909
+ if (!widgetData) {
4910
+ throw new Error(
4911
+ `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
4912
+ );
4913
+ }
4914
+ if (!widgetData.atomic_props_schema) {
4915
+ throw new Error(
4916
+ `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
4917
+ );
4918
+ }
4304
4919
  const elementRawSettings = element.settings;
4305
- const propSchema = getWidgetsCache7()?.[element.model.get("widgetType") || element.model.get("elType") || ""]?.atomic_props_schema;
4920
+ const propSchema = getWidgetsCache11()?.[elementType]?.atomic_props_schema;
4306
4921
  if (!elementRawSettings || !propSchema) {
4307
4922
  throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
4308
4923
  }
@@ -4354,7 +4969,11 @@ var initCanvasMcp = (reg) => {
4354
4969
  `
4355
4970
  );
4356
4971
  initWidgetsSchemaResource(reg);
4972
+ initAvailableWidgetsResource(reg);
4357
4973
  initDocumentStructureResource(reg);
4974
+ initSelectedElementResource(reg);
4975
+ initEditorStateResource(reg);
4976
+ initGeneralContextResource(reg);
4358
4977
  initBuildCompositionsTool(reg);
4359
4978
  initGetElementConfigTool(reg);
4360
4979
  initConfigureElementTool(reg);
@@ -4561,16 +5180,16 @@ function shouldBlock(sourceElements, targetElements) {
4561
5180
  }
4562
5181
 
4563
5182
  // src/style-commands/paste-style.ts
4564
- import { getContainer as getContainer5, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
5183
+ import { getContainer as getContainer7, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
4565
5184
  import { classesPropTypeUtil } from "@elementor/editor-props";
4566
5185
  import {
4567
- __privateListenTo as listenTo2,
5186
+ __privateListenTo as listenTo5,
4568
5187
  blockCommand as blockCommand4,
4569
5188
  commandStartEvent
4570
5189
  } from "@elementor/editor-v1-adapters";
4571
5190
 
4572
5191
  // src/utils/command-utils.ts
4573
- import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache8 } from "@elementor/editor-elements";
5192
+ import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache12 } from "@elementor/editor-elements";
4574
5193
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
4575
5194
  import { __ as __5 } from "@wordpress/i18n";
4576
5195
  function hasAtomicWidgets(args) {
@@ -4595,7 +5214,7 @@ function getClassesProp(container) {
4595
5214
  }
4596
5215
  function getContainerSchema(container) {
4597
5216
  const type = container?.model.get("widgetType") || container?.model.get("elType");
4598
- const widgetsCache = getWidgetsCache8();
5217
+ const widgetsCache = getWidgetsCache12();
4599
5218
  const elementType = widgetsCache?.[type];
4600
5219
  return elementType?.atomic_props_schema ?? null;
4601
5220
  }
@@ -4701,7 +5320,7 @@ function initPasteStyleCommand() {
4701
5320
  command: "document/elements/paste-style",
4702
5321
  condition: hasAtomicWidgets
4703
5322
  });
4704
- listenTo2(
5323
+ listenTo5(
4705
5324
  commandStartEvent("document/elements/paste-style"),
4706
5325
  (e) => pasteStyles(e.args, pasteElementStyleCommand)
4707
5326
  );
@@ -4714,7 +5333,7 @@ function pasteStyles(args, pasteLocalStyle) {
4714
5333
  }
4715
5334
  const clipboardElements = getClipboardElements(storageKey);
4716
5335
  const [clipboardElement] = clipboardElements ?? [];
4717
- const clipboardContainer = getContainer5(clipboardElement.id);
5336
+ const clipboardContainer = getContainer7(clipboardElement.id);
4718
5337
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
4719
5338
  return;
4720
5339
  }
@@ -4754,7 +5373,7 @@ function pasteClasses(containers, classes) {
4754
5373
 
4755
5374
  // src/style-commands/reset-style.ts
4756
5375
  import {
4757
- __privateListenTo as listenTo3,
5376
+ __privateListenTo as listenTo6,
4758
5377
  blockCommand as blockCommand5,
4759
5378
  commandStartEvent as commandStartEvent2
4760
5379
  } from "@elementor/editor-v1-adapters";
@@ -4812,7 +5431,7 @@ function initResetStyleCommand() {
4812
5431
  command: "document/elements/reset-style",
4813
5432
  condition: hasAtomicWidgets
4814
5433
  });
4815
- listenTo3(
5434
+ listenTo6(
4816
5435
  commandStartEvent2("document/elements/reset-style"),
4817
5436
  (e) => resetStyles(e.args, resetElementStyles)
4818
5437
  );
@@ -4910,9 +5529,33 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
4910
5529
  });
4911
5530
  return { model: elementModel };
4912
5531
  };
5532
+
5533
+ // src/sync/global-styles-imported-event.ts
5534
+ var GLOBAL_STYLES_IMPORTED_EVENT = "elementor/global-styles/imported";
5535
+
5536
+ // src/utils/after-render.ts
5537
+ import { getContainer as getContainer8 } from "@elementor/editor-elements";
5538
+ function doAfterRender(elementIds, callback) {
5539
+ const pending = elementIds.map((elementId) => {
5540
+ const view = getContainer8(elementId)?.view;
5541
+ if (!view || !hasDoAfterRender(view)) {
5542
+ return void 0;
5543
+ }
5544
+ return new Promise((resolve) => view._doAfterRender(resolve));
5545
+ }).filter(Boolean);
5546
+ if (pending.length > 0) {
5547
+ Promise.all(pending).then(() => callback(elementIds));
5548
+ } else {
5549
+ callback(elementIds);
5550
+ }
5551
+ }
5552
+ function hasDoAfterRender(view) {
5553
+ return typeof view?._doAfterRender === "function";
5554
+ }
4913
5555
  export {
4914
5556
  BREAKPOINTS_SCHEMA_URI,
4915
5557
  DOCUMENT_STRUCTURE_URI,
5558
+ GLOBAL_STYLES_IMPORTED_EVENT,
4916
5559
  STYLE_SCHEMA_URI,
4917
5560
  UnknownStyleStateError,
4918
5561
  UnknownStyleTypeError,
@@ -4924,6 +5567,7 @@ export {
4924
5567
  createTemplatedElementView,
4925
5568
  createTransformer,
4926
5569
  createTransformersRegistry,
5570
+ doAfterRender,
4927
5571
  endDragElementFromPanel,
4928
5572
  init,
4929
5573
  isAtomicWidget,