@elementor/editor-canvas 4.2.0-beta1 → 4.3.0-1000

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 (45) hide show
  1. package/dist/index.d.mts +1 -1
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +484 -1282
  4. package/dist/index.mjs +350 -1161
  5. package/package.json +22 -22
  6. package/src/__tests__/parse-xml.ts +2 -0
  7. package/src/components/__tests__/elements-overlays.test.tsx +7 -0
  8. package/src/components/elements-overlays.tsx +13 -10
  9. package/src/components/grid-outline/__tests__/grid-outline-overlay.test.tsx +13 -15
  10. package/src/components/grid-outline/grid-outline-overlay.tsx +3 -4
  11. package/src/components/outline-overlay.tsx +9 -2
  12. package/src/form-structure/__tests__/form-structure-utils.test.ts +218 -0
  13. package/src/form-structure/enforce-form-ancestor-commands.ts +11 -4
  14. package/src/form-structure/utils.ts +47 -0
  15. package/src/index.ts +1 -1
  16. package/src/legacy/__tests__/init-legacy-views.test.ts +1 -1
  17. package/src/mcp/canvas-mcp.ts +4 -2
  18. package/src/mcp/resources/__tests__/available-widgets-resource.test.ts +76 -0
  19. package/src/mcp/resources/__tests__/dynamic-tags-resource.test.ts +27 -37
  20. package/src/mcp/resources/__tests__/widgets-schema-resource.test.ts +79 -76
  21. package/src/mcp/resources/available-widgets-resource.ts +31 -40
  22. package/src/mcp/resources/best-practices-resource.ts +34 -0
  23. package/src/mcp/resources/dynamic-tags-resource.ts +28 -29
  24. package/src/mcp/resources/widgets-schema-resource.ts +34 -177
  25. package/src/mcp/tools/build-composition/tool.ts +108 -212
  26. package/src/sync/element-added-event.ts +8 -0
  27. package/src/types/element-overlay.ts +2 -0
  28. package/src/utils/__tests__/grid-outline-utils.test.ts +39 -0
  29. package/src/utils/__tests__/outline-offset-utils.test.ts +39 -0
  30. package/src/utils/grid-outline-utils.ts +13 -2
  31. package/src/utils/outline-offset-utils.ts +11 -0
  32. package/src/composition-builder/__tests__/composition-builder.test.ts +0 -352
  33. package/src/composition-builder/composition-builder.ts +0 -338
  34. package/src/composition-builder/utils/__tests__/required-children-enforcer.test.ts +0 -79
  35. package/src/composition-builder/utils/__tests__/required-default-child-tags.test.ts +0 -35
  36. package/src/composition-builder/utils/required-children-enforcer.ts +0 -56
  37. package/src/composition-builder/utils/required-default-child-tags.ts +0 -22
  38. package/src/mcp/resources/best-practices.ts +0 -159
  39. package/src/mcp/resources/build-llm-guidance.ts +0 -110
  40. package/src/mcp/tools/build-composition/__tests__/xml-leaf-wrapper.test.ts +0 -117
  41. package/src/mcp/tools/build-composition/prompt.ts +0 -167
  42. package/src/mcp/tools/build-composition/schema.ts +0 -42
  43. package/src/mcp/tools/build-composition/xml-leaf-wrapper.ts +0 -68
  44. package/src/mcp/utils/__tests__/get-composition-target-container.test.ts +0 -59
  45. package/src/mcp/utils/get-composition-target-container.ts +0 -15
package/dist/index.mjs CHANGED
@@ -2,205 +2,37 @@
2
2
  import { v1ReadyEvent } from "@elementor/editor-v1-adapters";
3
3
 
4
4
  // src/mcp/resources/widgets-schema-resource.ts
5
- import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
6
5
  import { ResourceTemplate } from "@elementor/editor-mcp";
7
- import {
8
- Schema
9
- } from "@elementor/editor-props";
10
-
11
- // src/mcp/utils/element-data-util.ts
12
- import { getWidgetsCache } from "@elementor/editor-elements";
13
- function hasV3Controls(controls) {
14
- return typeof controls === "object" && controls !== null && Object.keys(controls).length > 0;
15
- }
16
- function isWidgetAvailableForLLM(config) {
17
- if (!config) {
18
- return false;
19
- }
20
- if (config.meta?.llm_support === false) {
21
- return false;
22
- }
23
- if (config.title === "Component") {
24
- return false;
25
- }
26
- if (config.atomic_props_schema) {
27
- return true;
28
- }
29
- return hasV3Controls(config.controls);
30
- }
31
- function getWidgetVersion(config) {
32
- return config?.atomic_props_schema ? "v4" : "v3";
33
- }
34
- function getAvailableWidgets() {
35
- const cache = getWidgetsCache() ?? {};
36
- return Object.keys(cache).filter((widgetType) => isWidgetAvailableForLLM(cache[widgetType])).sort().map((widgetType) => {
37
- const config = cache[widgetType];
38
- const description = typeof config?.meta?.description === "string" ? config.meta.description : void 0;
39
- return {
40
- type: widgetType,
41
- version: getWidgetVersion(config),
42
- ...description && { description }
43
- };
44
- });
45
- }
46
-
47
- // src/composition-builder/utils/required-default-child-tags.ts
48
- function getRequiredDefaultChildTemplates(elementConfig) {
49
- const defaultChildren = elementConfig?.default_children;
50
- if (!Array.isArray(defaultChildren)) {
51
- return [];
52
- }
53
- return defaultChildren.filter((child) => child?.meta?.required ?? false);
54
- }
55
- function getRequiredDefaultChildTypes(elementConfig) {
56
- return getRequiredDefaultChildTemplates(elementConfig).map((child) => child.widgetType ?? child.elType ?? "").filter((type) => Boolean(type));
57
- }
58
-
59
- // src/mcp/resources/build-llm-guidance.ts
60
- var DEFAULT_STYLES_INSTRUCTION = "These are the default styles applied to the widget. Override only when necessary.";
61
- var DEFAULT_SETTINGS_INSTRUCTION = "These are the default settings applied to the widget. Omit them from elementConfig unless the user explicitly asks to change them.";
62
- var BASE_SETTING_PROP_HINT = "Has a widget default \u2014 omit unless user explicitly requests a change. See llm_guidance.default_settings.";
63
- function mergeInstructions(existing, additional) {
64
- if (typeof existing === "string" && existing.length > 0) {
65
- return `${existing} ${additional}`;
66
- }
67
- return additional;
68
- }
69
- function enrichPropertiesWithBaseSettingsHints(properties, baseSettingsKeys) {
70
- if (!baseSettingsKeys.length) {
71
- return properties;
72
- }
73
- const enriched = { ...properties };
74
- for (const key of baseSettingsKeys) {
75
- const propSchema = enriched[key];
76
- if (!propSchema) {
77
- continue;
78
- }
79
- enriched[key] = {
80
- ...propSchema,
81
- description: propSchema.description ? `${propSchema.description} ${BASE_SETTING_PROP_HINT}` : BASE_SETTING_PROP_HINT
82
- };
83
- }
84
- return enriched;
85
- }
86
- function buildLlmGuidance(widgetData, widgetType, allWidgets) {
87
- const defaultStyles = {};
88
- const baseStyleSchema = widgetData?.base_styles;
89
- if (baseStyleSchema) {
90
- Object.values(baseStyleSchema).forEach((stylePropType) => {
91
- stylePropType.variants.forEach((variant) => {
92
- Object.assign(defaultStyles, variant.props);
93
- });
94
- });
95
- }
96
- const baseSettings = widgetData?.base_settings ?? {};
97
- const hasDefaultStyles = Object.keys(defaultStyles).length > 0;
98
- const hasDefaultSettings = Object.keys(baseSettings).length > 0;
99
- const llmGuidance = {
100
- can_have_children: !!widgetData?.meta?.is_container
101
- };
102
- if (hasDefaultStyles) {
103
- llmGuidance.instructions = DEFAULT_STYLES_INSTRUCTION;
104
- llmGuidance.default_styles = defaultStyles;
105
- }
106
- if (hasDefaultSettings) {
107
- llmGuidance.instructions = mergeInstructions(llmGuidance.instructions, DEFAULT_SETTINGS_INSTRUCTION);
108
- llmGuidance.default_settings = baseSettings;
109
- }
110
- const allowedChildTypes = widgetData.allowed_child_types;
111
- const allowedParents = Object.entries(allWidgets).filter(([, parentConfig]) => parentConfig.allowed_child_types?.includes(widgetType)).map(([parentType]) => parentType);
112
- if (allowedChildTypes?.length || allowedParents.length) {
113
- llmGuidance.nesting = {
114
- ...allowedChildTypes?.length ? { allowed_child_types: allowedChildTypes } : {},
115
- ...allowedParents.length ? { allowed_parents: allowedParents } : {}
116
- };
117
- }
118
- const requiredDirectChildTags = getRequiredDefaultChildTypes(widgetData);
119
- if (requiredDirectChildTags.length) {
120
- llmGuidance.required_direct_children = requiredDirectChildTags;
121
- }
122
- return llmGuidance;
123
- }
124
-
125
- // src/mcp/resources/widgets-schema-resource.ts
126
- var V3_LAYOUT_CONTROL_TYPES = /* @__PURE__ */ new Set(["section", "tab", "tabs"]);
127
- function extractV3ControlsMetadata(controls) {
128
- if (!hasV3Controls(controls)) {
129
- return {};
130
- }
131
- const result = {};
132
- for (const [controlKey, raw] of Object.entries(controls)) {
133
- if (!raw || typeof raw !== "object") {
134
- continue;
135
- }
136
- const control = raw;
137
- const controlType = typeof control.type === "string" ? control.type : void 0;
138
- if (controlType && V3_LAYOUT_CONTROL_TYPES.has(controlType)) {
139
- continue;
140
- }
141
- const entry = {};
142
- if (Object.prototype.hasOwnProperty.call(control, "default")) {
143
- entry.default = control.default;
144
- }
145
- if (controlType) {
146
- entry.type = controlType;
147
- }
148
- if (Object.prototype.hasOwnProperty.call(control, "options") && control.options !== void 0) {
149
- const options = control.options;
150
- if (options && typeof options === "object" && !Array.isArray(options)) {
151
- entry.options = Object.keys(options);
152
- } else {
153
- entry.options = options;
154
- }
155
- }
156
- result[controlKey] = entry;
157
- }
158
- return result;
159
- }
6
+ import { httpService } from "@elementor/http-client";
160
7
  var CANVAS_SERVER_NAME = "editor-canvas";
161
8
  var WIDGET_SCHEMA_URI = "elementor://widgets/schema/{widgetType}";
162
9
  var WIDGET_SCHEMA_FULL_URI = `${CANVAS_SERVER_NAME}_${WIDGET_SCHEMA_URI}`;
163
- var BEST_PRACTICES_URI = "elementor://styles/best-practices";
10
+ var BEST_PRACTICES_URI = "elementor://style/best-practices";
164
11
  var BEST_PRACTICES_FULL_URI = `${CANVAS_SERVER_NAME}_${BEST_PRACTICES_URI}`;
12
+ var MCP_PROXY_URL = "elementor/v1/mcp-proxy";
13
+ var listWidgetTypes = async () => {
14
+ const { data } = await httpService().post(MCP_PROXY_URL, {
15
+ tool: "list-widgets",
16
+ input: {}
17
+ });
18
+ return (data.data ?? []).map((widget) => widget.type);
19
+ };
20
+ var fetchWidgetSchema = async (widgetType) => {
21
+ const { data } = await httpService().post(MCP_PROXY_URL, {
22
+ tool: "get-widget-schema",
23
+ input: { widget_type: widgetType }
24
+ });
25
+ return data.data ?? {};
26
+ };
165
27
  var initWidgetsSchemaResource = (reg) => {
166
28
  const { resource } = reg;
167
- resource(
168
- "styles-best-practices",
169
- BEST_PRACTICES_URI,
170
- {
171
- description: "Styling best practices"
172
- },
173
- async () => {
174
- return {
175
- contents: [
176
- {
177
- uri: BEST_PRACTICES_URI,
178
- text: `# Styling best practices
179
- Prefer using "em" and "rem" values for text-related sizes, padding and spacing. Use percentages for dynamic sizing relative to parent containers.
180
- This flexboxes are by default "flex" with "stretch" alignment. To ensure proper layout, define the "justify-content" and "align-items" as in the schema.
181
-
182
- Styling is provided as raw CSS. The css string must follow standard CSS syntax, with properties and values separated by semicolons, no selectors, or nesting rules allowed.
183
-
184
- ** CRITICAL - VARIABLES **
185
- When using global variables, ensure that the variables are defined in the ${"elementor://global-variables"} resource.
186
- Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
187
-
188
- `
189
- }
190
- ]
191
- };
192
- }
193
- );
194
29
  resource(
195
30
  "widget-schema-by-type",
196
31
  new ResourceTemplate(WIDGET_SCHEMA_URI, {
197
- list: () => {
198
- const cache = getWidgetsCache2() || {};
199
- const availableWidgets = Object.keys(cache).filter(
200
- (widgetType) => isWidgetAvailableForLLM(cache[widgetType])
201
- );
32
+ list: async () => {
33
+ const widgetTypes = await listWidgetTypes();
202
34
  return {
203
- resources: availableWidgets.map((widgetType) => ({
35
+ resources: widgetTypes.map((widgetType) => ({
204
36
  uri: `elementor://widgets/schema/${widgetType}`,
205
37
  name: "Widget schema for " + widgetType
206
38
  }))
@@ -212,52 +44,16 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
212
44
  },
213
45
  async (uri, variables) => {
214
46
  const widgetType = typeof variables.widgetType === "string" ? variables.widgetType : variables.widgetType?.[0];
215
- const widgetData = getWidgetsCache2()?.[widgetType];
216
- if (!widgetData) {
217
- throw new Error(`No prop schema found for element type: ${widgetType}`);
218
- }
219
- const propSchema = widgetData.atomic_props_schema;
220
- if (!propSchema) {
221
- if (!hasV3Controls(widgetData.controls)) {
222
- throw new Error(`No prop schema found for element type: ${widgetType}`);
223
- }
224
- const controlMetadata = extractV3ControlsMetadata(widgetData.controls);
225
- return {
226
- contents: [
227
- {
228
- uri: uri.toString(),
229
- mimeType: "application/json",
230
- text: JSON.stringify({
231
- widget_version: "v3",
232
- message: "This widget exists in the editor but has no atomic props schema (V4). Use control_metadata as non-authoritative hints from legacy controls.",
233
- fields_note: "All settings are optional; there is no JSON schema for this widget type.",
234
- properties: controlMetadata
235
- })
236
- }
237
- ]
238
- };
47
+ if (!widgetType) {
48
+ throw new Error("No widget type provided.");
239
49
  }
240
- const baseSettingsKeys = Object.keys(widgetData?.base_settings ?? {});
241
- const asJson = enrichPropertiesWithBaseSettingsHints(
242
- Object.fromEntries(
243
- Object.entries(propSchema).filter(([key, propType]) => Schema.isPropKeyConfigurable(key, propType)).map(([key, propType]) => [key, Schema.propTypeToJsonSchema(propType)])
244
- ),
245
- baseSettingsKeys
246
- );
247
- const description = typeof widgetData?.meta?.description === "string" ? widgetData.meta.description : void 0;
248
- const allWidgets = getWidgetsCache2() || {};
249
- const llmGuidance = buildLlmGuidance(widgetData, widgetType, allWidgets);
50
+ const schema2 = await fetchWidgetSchema(widgetType);
250
51
  return {
251
52
  contents: [
252
53
  {
253
54
  uri: uri.toString(),
254
55
  mimeType: "application/json",
255
- text: JSON.stringify({
256
- type: "object",
257
- properties: asJson,
258
- description,
259
- llm_guidance: llmGuidance
260
- })
56
+ text: JSON.stringify(schema2)
261
57
  }
262
58
  ]
263
59
  };
@@ -312,11 +108,11 @@ var initBreakpointsResource = (reg) => {
312
108
  };
313
109
 
314
110
  // src/mcp/utils/convert-css-to-atomic.ts
315
- import { httpService } from "@elementor/http-client";
111
+ import { httpService as httpService2 } from "@elementor/http-client";
316
112
  var CSS_TO_ATOMIC_URL = "elementor/v1/css-to-atomic";
317
113
  var SINGLE_BLOCK_KEY = "default";
318
114
  var convertBlocks = async (blocks) => {
319
- const { data } = await httpService().post(
115
+ const { data } = await httpService2().post(
320
116
  CSS_TO_ATOMIC_URL,
321
117
  { blocks }
322
118
  );
@@ -460,8 +256,8 @@ function toGridTracks(computedStyle) {
460
256
  return {
461
257
  columns: parseTrackList(computedStyle.gridTemplateColumns),
462
258
  rows: parseTrackList(computedStyle.gridTemplateRows),
463
- columnGap: toPx(computedStyle.columnGap),
464
- rowGap: toPx(computedStyle.rowGap),
259
+ columnGap: resolveGapPx(computedStyle.columnGap, computedStyle.width),
260
+ rowGap: resolveGapPx(computedStyle.rowGap, computedStyle.height),
465
261
  padding: {
466
262
  top: toPx(computedStyle.paddingTop),
467
263
  right: toPx(computedStyle.paddingRight),
@@ -536,6 +332,14 @@ function toPx(value) {
536
332
  const parsed = parseFloat(value);
537
333
  return Number.isFinite(parsed) ? parsed : 0;
538
334
  }
335
+ function resolveGapPx(value, referenceSize) {
336
+ if (value.trim().endsWith("%")) {
337
+ const percent = parseFloat(value);
338
+ const reference = parseFloat(referenceSize);
339
+ return Number.isFinite(percent) && Number.isFinite(reference) ? percent / 100 * reference : 0;
340
+ }
341
+ return toPx(value);
342
+ }
539
343
 
540
344
  // src/hooks/use-grid-children.ts
541
345
  import { useEffect as useEffect3, useState as useState2 } from "react";
@@ -807,8 +611,7 @@ var GridEmptyCellPositioner = ({ element }) => {
807
611
 
808
612
  // src/components/grid-outline/grid-outline-overlay.tsx
809
613
  import * as React6 from "react";
810
- import { useSelectedElementSettings } from "@elementor/editor-elements";
811
- import { booleanPropTypeUtil } from "@elementor/editor-props";
614
+ import { useElementEditorSettings } from "@elementor/editor-elements";
812
615
  import { Box as Box2 } from "@elementor/ui";
813
616
  import { FloatingPortal as FloatingPortal2 } from "@floating-ui/react";
814
617
 
@@ -909,6 +712,16 @@ var useHasOverlapping = () => {
909
712
  return hasOverlapping;
910
713
  };
911
714
 
715
+ // src/utils/outline-offset-utils.ts
716
+ var THIN_ELEMENT_MAX_HEIGHT_PX = 1;
717
+ var SMALLER_OUTLINE_OFFSET_WIDGET_TYPES = /* @__PURE__ */ new Set(["e-form-input"]);
718
+ function shouldUseSmallerOutlineOffset(element, widgetType) {
719
+ if (element.offsetHeight <= THIN_ELEMENT_MAX_HEIGHT_PX) {
720
+ return true;
721
+ }
722
+ return widgetType !== void 0 && SMALLER_OUTLINE_OFFSET_WIDGET_TYPES.has(widgetType);
723
+ }
724
+
912
725
  // src/components/outline-overlay.tsx
913
726
  var CANVAS_WRAPPER_ID = "elementor-preview-responsive-wrapper";
914
727
  var OverlayBox = styled(Box, {
@@ -920,12 +733,18 @@ var OverlayBox = styled(Box, {
920
733
  pointerEvents: "none"
921
734
  })
922
735
  );
923
- var OutlineOverlay = ({ element, isSelected, id, isGlobal = false }) => {
736
+ var OutlineOverlay = ({
737
+ element,
738
+ isSelected,
739
+ id,
740
+ isGlobal = false,
741
+ widgetType
742
+ }) => {
924
743
  const { context, floating, isVisible } = useFloatingOnElement({ element, isSelected });
925
744
  const { getFloatingProps, getReferenceProps } = useInteractions([useHover(context)]);
926
745
  const hasOverlapping = useHasOverlapping();
927
746
  useBindReactPropsToElement(element, getReferenceProps);
928
- const isSmallerOffset = element.offsetHeight <= 1;
747
+ const isSmallerOffset = shouldUseSmallerOutlineOffset(element, widgetType);
929
748
  return isVisible && !hasOverlapping && /* @__PURE__ */ React.createElement(FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React.createElement(
930
749
  OverlayBox,
931
750
  {
@@ -1081,8 +900,8 @@ function GridOutline({ element, tracks, width, height }) {
1081
900
 
1082
901
  // src/components/grid-outline/grid-outline-overlay.tsx
1083
902
  var GridOutlineOverlay = ({ element, id, isSelected }) => {
1084
- const { settings } = useSelectedElementSettings();
1085
- const enabled = booleanPropTypeUtil.extract(settings?.grid_outline);
903
+ const settings = useElementEditorSettings(id);
904
+ const enabled = settings?.grid_outline;
1086
905
  const rect = useElementRect(element);
1087
906
  const tracks = useGridTracks(element, rect);
1088
907
  const { floating } = useFloatingOnElement({ element, isSelected });
@@ -1105,9 +924,10 @@ var GridOutlineOverlay = ({ element, id, isSelected }) => {
1105
924
  };
1106
925
 
1107
926
  // src/components/elements-overlays.tsx
927
+ var hasGridStyleDisplay = (element) => {
928
+ return element.computedStyleMap().get("display")?.toString() === "grid";
929
+ };
1108
930
  var ELEMENTS_DATA_ATTR = "atomic";
1109
- var E_GRID_TYPE = "e-grid";
1110
- var isGridElement = (element) => [element.dataset.eType, element.dataset.element_type].includes(E_GRID_TYPE);
1111
931
  var overlayRegistry = [
1112
932
  {
1113
933
  component: OutlineOverlay,
@@ -1115,11 +935,11 @@ var overlayRegistry = [
1115
935
  },
1116
936
  {
1117
937
  component: GridEmptyCellPositioner,
1118
- shouldRender: ({ element }) => isGridElement(element)
938
+ shouldRender: ({ element }) => hasGridStyleDisplay(element)
1119
939
  },
1120
940
  {
1121
941
  component: GridOutlineOverlay,
1122
- shouldRender: ({ element, isSelected }) => isSelected && isGridElement(element)
942
+ shouldRender: ({ isSelected, element }) => isSelected && hasGridStyleDisplay(element)
1123
943
  }
1124
944
  ];
1125
945
  function ElementsOverlays() {
@@ -1132,17 +952,18 @@ function ElementsOverlays() {
1132
952
  if (!isActive) {
1133
953
  return null;
1134
954
  }
1135
- return elements.map(({ id, domElement, isGlobal }) => {
955
+ return elements.map(({ id, domElement, isGlobal, widgetType }) => {
1136
956
  const isSelected = selected.element?.id === id;
1137
957
  return overlayRegistry.map(
1138
- ({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected }) && /* @__PURE__ */ React7.createElement(
958
+ ({ shouldRender, component: Overlay }, index) => shouldRender({ id, element: domElement, isSelected, widgetType }) && /* @__PURE__ */ React7.createElement(
1139
959
  Overlay,
1140
960
  {
1141
961
  key: `${id}-${index}`,
1142
962
  id,
1143
963
  element: domElement,
1144
964
  isSelected,
1145
- isGlobal
965
+ isGlobal,
966
+ widgetType
1146
967
  }
1147
968
  )
1148
969
  );
@@ -1155,7 +976,8 @@ function useElementsDom() {
1155
976
  return getElements().filter((el) => isV4Element(el.view?.el?.dataset)).map((element) => ({
1156
977
  id: element.id,
1157
978
  domElement: element.view?.getDomElement?.()?.get?.(0),
1158
- isGlobal: element.model.get("isGlobal") ?? false
979
+ isGlobal: element.model.get("isGlobal") ?? false,
980
+ widgetType: element.model.get("widgetType")
1159
981
  })).filter((item) => !!item.domElement);
1160
982
  }
1161
983
  );
@@ -2010,7 +1832,8 @@ function blockFormFieldCreate(args) {
2010
1832
  if (!elementType || !FORM_FIELD_ELEMENT_TYPES.has(elementType)) {
2011
1833
  return false;
2012
1834
  }
2013
- if (!isWithinForm(args.container)) {
1835
+ const containers = args.containers ?? [args.container];
1836
+ if (containers.some((container) => !isWithinForm(container))) {
2014
1837
  handleBlockedFormField();
2015
1838
  return true;
2016
1839
  }
@@ -2018,10 +1841,10 @@ function blockFormFieldCreate(args) {
2018
1841
  }
2019
1842
  function blockFormFieldMove(args) {
2020
1843
  const { containers = [args.container], target } = args;
2021
- const hasFormFieldElement = containers.some(
2022
- (container) => container ? hasElementTypes(container, FORM_FIELD_ELEMENT_TYPES) : false
1844
+ const hasLooseFormFields = containers.some(
1845
+ (container) => container ? !hasElementType(container, FORM_ELEMENT_TYPE) && hasElementTypes(container, FORM_FIELD_ELEMENT_TYPES) : false
2023
1846
  );
2024
- if (hasFormFieldElement && !isWithinForm(target) && !movedContainersIncludeAtomicFormRoot(containers)) {
1847
+ if (hasLooseFormFields && !isWithinForm(target) && !movedContainersIncludeAtomicFormRoot(containers)) {
2025
1848
  handleBlockedFormField();
2026
1849
  return true;
2027
1850
  }
@@ -2692,7 +2515,7 @@ function initStyleTransformers() {
2692
2515
  }
2693
2516
 
2694
2517
  // src/legacy/init-legacy-views.ts
2695
- import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
2518
+ import { getWidgetsCache } from "@elementor/editor-elements";
2696
2519
  import { __privateIsReady as isV1Ready, __privateListenTo, v1ReadyEvent as v1ReadyEvent2 } from "@elementor/editor-v1-adapters";
2697
2520
 
2698
2521
  // src/renderers/create-dom-renderer.ts
@@ -4008,7 +3831,7 @@ function registerElementType(type, elementTypeGenerator) {
4008
3831
  }
4009
3832
  function initLegacyViews() {
4010
3833
  __privateListenTo(v1ReadyEvent2(), () => {
4011
- const widgetsCache = getWidgetsCache3() ?? {};
3834
+ const widgetsCache = getWidgetsCache() ?? {};
4012
3835
  const renderer = createDomRenderer();
4013
3836
  registerProPromotionTypes(widgetsCache);
4014
3837
  Object.keys(widgetsCache).forEach((type) => {
@@ -4017,7 +3840,7 @@ function initLegacyViews() {
4017
3840
  });
4018
3841
  }
4019
3842
  function registerElementInLegacyManager(type, renderer) {
4020
- const element = (getWidgetsCache3() ?? {})[type];
3843
+ const element = (getWidgetsCache() ?? {})[type];
4021
3844
  if (!element?.atomic) {
4022
3845
  return;
4023
3846
  }
@@ -4099,43 +3922,41 @@ function initTabsModelExtensions() {
4099
3922
  }
4100
3923
 
4101
3924
  // src/mcp/canvas-mcp.ts
4102
- import { Schema as Schema6 } from "@elementor/editor-props";
3925
+ import { Schema as Schema4 } from "@elementor/editor-props";
4103
3926
 
4104
3927
  // src/mcp/resources/available-widgets-resource.ts
4105
- import { v1ReadyEvent as v1ReadyEvent3 } from "@elementor/editor-v1-adapters";
3928
+ import { httpService as httpService3 } from "@elementor/http-client";
3929
+ var MCP_PROXY_URL2 = "elementor/v1/mcp-proxy";
4106
3930
  var AVAILABLE_WIDGETS_URI = "elementor://context/available-widgets";
4107
3931
  var AVAILABLE_WIDGETS_URI_V4 = "elementor://context/available-widgets/v4";
4108
- var initAvailableWidgetsResource = (reg) => {
4109
- const { resource, sendResourceUpdated } = reg;
4110
- const buildContents = (uri, filterFunction = () => true) => {
4111
- const widgets = getAvailableWidgets().filter(filterFunction);
4112
- return {
4113
- contents: [
4114
- {
4115
- uri,
4116
- mimeType: "application/json",
4117
- text: JSON.stringify(widgets, null, 2)
4118
- }
4119
- ]
4120
- };
4121
- };
4122
- const notifyResourcesUpdated = () => {
4123
- sendResourceUpdated({
4124
- uri: AVAILABLE_WIDGETS_URI,
4125
- ...buildContents(AVAILABLE_WIDGETS_URI)
4126
- });
4127
- sendResourceUpdated({
4128
- uri: AVAILABLE_WIDGETS_URI_V4,
4129
- ...buildContents(AVAILABLE_WIDGETS_URI_V4, (w) => w.version === "v4")
4130
- });
3932
+ var fetchWidgets = async (version) => {
3933
+ const { data } = await httpService3().post(MCP_PROXY_URL2, {
3934
+ tool: "list-widgets",
3935
+ input: version ? { version } : {}
3936
+ });
3937
+ return data.data ?? [];
3938
+ };
3939
+ var buildContents = async (uri, version) => {
3940
+ const widgets = await fetchWidgets(version);
3941
+ return {
3942
+ contents: [
3943
+ {
3944
+ uri,
3945
+ mimeType: "application/json",
3946
+ text: JSON.stringify(widgets, null, 2)
3947
+ }
3948
+ ]
4131
3949
  };
3950
+ };
3951
+ var initAvailableWidgetsResource = (reg) => {
3952
+ const { resource } = reg;
4132
3953
  resource(
4133
3954
  "available-widgets-v4",
4134
3955
  AVAILABLE_WIDGETS_URI_V4,
4135
3956
  {
4136
3957
  description: "All registered v4 version widgets"
4137
3958
  },
4138
- async () => buildContents(AVAILABLE_WIDGETS_URI_V4, (w) => w.version === "v4")
3959
+ async () => buildContents(AVAILABLE_WIDGETS_URI_V4, "v4")
4139
3960
  );
4140
3961
  resource(
4141
3962
  "available-widgets",
@@ -4145,22 +3966,41 @@ var initAvailableWidgetsResource = (reg) => {
4145
3966
  },
4146
3967
  async () => buildContents(AVAILABLE_WIDGETS_URI)
4147
3968
  );
4148
- const eventName = v1ReadyEvent3().name;
4149
- const onV1Ready = () => {
4150
- const widgets = getAvailableWidgets();
4151
- if (widgets.length === 0) {
4152
- return;
3969
+ };
3970
+
3971
+ // src/mcp/resources/best-practices-resource.ts
3972
+ import { httpService as httpService4 } from "@elementor/http-client";
3973
+ var MCP_PROXY_URL3 = "elementor/v1/mcp-proxy";
3974
+ var BEST_PRACTICES_URI2 = "elementor://style/best-practices";
3975
+ var initBestPracticesResource = (reg) => {
3976
+ const { resource } = reg;
3977
+ resource(
3978
+ "style-best-practices",
3979
+ BEST_PRACTICES_URI2,
3980
+ {
3981
+ description: "Design quality guidelines for avoiding generic AI output: typography, color strategy, spacing, motion, and visual hierarchy best practices.",
3982
+ mimeType: "text/markdown"
3983
+ },
3984
+ async (uri) => {
3985
+ const { data } = await httpService4().get(MCP_PROXY_URL3, {
3986
+ params: { uri: uri.href }
3987
+ });
3988
+ return {
3989
+ contents: [
3990
+ {
3991
+ uri: uri.href,
3992
+ mimeType: "text/markdown",
3993
+ text: data.data
3994
+ }
3995
+ ]
3996
+ };
4153
3997
  }
4154
- window.removeEventListener(eventName, onV1Ready);
4155
- notifyResourcesUpdated();
4156
- };
4157
- window.addEventListener(eventName, onV1Ready);
4158
- onV1Ready();
3998
+ );
4159
3999
  };
4160
4000
 
4161
4001
  // src/mcp/resources/document-structure-resource.ts
4162
4002
  import {
4163
- getWidgetsCache as getWidgetsCache4
4003
+ getWidgetsCache as getWidgetsCache2
4164
4004
  } from "@elementor/editor-elements";
4165
4005
  import { __privateListenTo as listenTo, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
4166
4006
  var DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
@@ -4226,7 +4066,7 @@ function resolveElementVersion(element) {
4226
4066
  return "v4";
4227
4067
  }
4228
4068
  const widgetType = element.model?.attributes?.widgetType;
4229
- if (widgetType && getWidgetsCache4()?.[widgetType]?.atomic_props_schema) {
4069
+ if (widgetType && getWidgetsCache2()?.[widgetType]?.atomic_props_schema) {
4230
4070
  return "v4";
4231
4071
  }
4232
4072
  return "v3";
@@ -4253,84 +4093,15 @@ function extractElementData(element) {
4253
4093
  }
4254
4094
 
4255
4095
  // src/mcp/resources/dynamic-tags-resource.ts
4256
- import { Schema as Schema2 } from "@elementor/editor-props";
4257
-
4258
- // src/mcp/utils/resolve-dynamic-tag.ts
4259
- import { getElementorConfig } from "@elementor/editor-v1-adapters";
4260
- var DYNAMIC_PROP_TYPE_KEY = "dynamic";
4261
- var OMITTED_DYNAMIC_SETTING_KEYS = ["fallback"];
4262
- var getAtomicDynamicTags = () => {
4263
- const config = getElementorConfig();
4264
- return config.atomicDynamicTags?.tags ?? {};
4265
- };
4266
- var getDynamicTagNamesByCategories = (categories) => {
4267
- if (!categories.length) {
4268
- return [];
4269
- }
4270
- const wanted = new Set(categories);
4271
- return Object.values(getAtomicDynamicTags()).filter((tag) => tag.categories?.some((category) => wanted.has(category))).map((tag) => tag.name);
4272
- };
4273
- var dynamicTagLLMResolver = (value) => {
4274
- const input = value ?? {};
4275
- const tag = input.name ? getAtomicDynamicTags()[input.name] : void 0;
4276
- if (!tag) {
4277
- return {
4278
- $$type: DYNAMIC_PROP_TYPE_KEY,
4279
- value: { name: input.name ?? "", group: "", settings: {} }
4280
- };
4281
- }
4282
- return {
4283
- $$type: DYNAMIC_PROP_TYPE_KEY,
4284
- value: {
4285
- name: tag.name,
4286
- group: tag.group,
4287
- settings: buildStrictSettings(tag.props_schema ?? {}, input.settings ?? {})
4288
- }
4289
- };
4290
- };
4291
- var buildStrictSettings = (schema2, provided) => {
4292
- const settings = {};
4293
- for (const [key, propType] of Object.entries(schema2)) {
4294
- if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
4295
- continue;
4296
- }
4297
- const resolved = provided[key] !== void 0 ? wrapSettingValue(provided[key], propType) : defaultSettingValue(propType);
4298
- if (resolved !== void 0 && resolved !== null) {
4299
- settings[key] = resolved;
4300
- }
4301
- }
4302
- return settings;
4303
- };
4304
- var wrapSettingValue = (raw, propType) => {
4305
- if (raw !== null && typeof raw === "object") {
4306
- return raw;
4307
- }
4308
- return propType.key ? { $$type: propType.key, value: raw } : raw;
4309
- };
4310
- var defaultSettingValue = (propType) => {
4311
- if (propType.initial_value !== null && propType.initial_value !== void 0) {
4312
- return propType.initial_value;
4313
- }
4314
- if (propType.default !== null && propType.default !== void 0) {
4315
- return wrapSettingValue(propType.default, propType);
4316
- }
4317
- return void 0;
4318
- };
4319
-
4320
- // src/mcp/resources/dynamic-tags-resource.ts
4096
+ import { httpService as httpService5 } from "@elementor/http-client";
4321
4097
  var DYNAMIC_TAGS_URI = "elementor://dynamic-tags";
4322
- var settingsSchema = (propsSchema) => {
4323
- return Object.fromEntries(
4324
- Object.entries(propsSchema ?? {}).filter(([key]) => !OMITTED_DYNAMIC_SETTING_KEYS.includes(key)).map(([key, propType]) => [key, Schema2.propTypeToJsonSchema(propType)])
4325
- );
4326
- };
4327
- var buildDynamicTagsList = () => {
4328
- return Object.values(getAtomicDynamicTags()).map((tag) => ({
4329
- name: tag.name,
4330
- label: tag.label,
4331
- categories: tag.categories,
4332
- settings: settingsSchema(tag.props_schema)
4333
- }));
4098
+ var MCP_PROXY_URL4 = "elementor/v1/mcp-proxy";
4099
+ var fetchDynamicTags = async () => {
4100
+ const { data } = await httpService5().post(MCP_PROXY_URL4, {
4101
+ tool: "list-dynamic-tags",
4102
+ input: {}
4103
+ });
4104
+ return data.data ?? [];
4334
4105
  };
4335
4106
  var initDynamicTagsResource = (reg) => {
4336
4107
  const { resource } = reg;
@@ -4341,15 +4112,18 @@ var initDynamicTagsResource = (reg) => {
4341
4112
  description: `List of available dynamic tags. To bind a property to a dynamic source, set its value to { "$$type": "dynamic", "value": { "name": <tag name>, "settings": { ... } } } using a tag whose name appears in that property's allowed list, and populate "settings" per the tag entry here.`,
4342
4113
  mimeType: "application/json"
4343
4114
  },
4344
- async (uri) => ({
4345
- contents: [
4346
- {
4347
- uri: uri.href,
4348
- mimeType: "application/json",
4349
- text: JSON.stringify(buildDynamicTagsList())
4350
- }
4351
- ]
4352
- })
4115
+ async (uri) => {
4116
+ const tags = await fetchDynamicTags();
4117
+ return {
4118
+ contents: [
4119
+ {
4120
+ uri: uri.href,
4121
+ mimeType: "application/json",
4122
+ text: JSON.stringify(tags)
4123
+ }
4124
+ ]
4125
+ };
4126
+ }
4353
4127
  );
4354
4128
  };
4355
4129
 
@@ -4523,7 +4297,7 @@ var initGeneralContextResource = (reg) => {
4523
4297
  };
4524
4298
 
4525
4299
  // src/mcp/resources/selected-element-resource.ts
4526
- import { getContainer as getContainer3, getSelectedElements, getWidgetsCache as getWidgetsCache5 } from "@elementor/editor-elements";
4300
+ import { getContainer as getContainer3, getSelectedElements, getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
4527
4301
  import {
4528
4302
  __privateListenTo as listenTo4,
4529
4303
  commandEndEvent as commandEndEvent7
@@ -4624,7 +4398,7 @@ function resolveElementVersion2(container, widgetType) {
4624
4398
  if (container.model?.config?.atomic) {
4625
4399
  return "v4";
4626
4400
  }
4627
- if (widgetType && getWidgetsCache5()?.[widgetType]?.atomic_props_schema) {
4401
+ if (widgetType && getWidgetsCache3()?.[widgetType]?.atomic_props_schema) {
4628
4402
  return "v4";
4629
4403
  }
4630
4404
  return "v3";
@@ -4634,7 +4408,7 @@ function getElementProperties(container, widgetType) {
4634
4408
  if (!settings || typeof settings !== "object") {
4635
4409
  return null;
4636
4410
  }
4637
- const widgetConfig = widgetType ? getWidgetsCache5()?.[widgetType] : null;
4411
+ const widgetConfig = widgetType ? getWidgetsCache3()?.[widgetType] : null;
4638
4412
  const controls = widgetConfig?.controls;
4639
4413
  const filtered = {};
4640
4414
  for (const [key, value] of Object.entries(settings)) {
@@ -4672,33 +4446,110 @@ function getElementDisplayName(container) {
4672
4446
  }
4673
4447
 
4674
4448
  // src/mcp/tools/build-composition/tool.ts
4675
- import { getCurrentDocument } from "@elementor/editor-documents";
4676
- import {
4677
- createElement as createElement13,
4678
- deleteElement as deleteElement2,
4679
- getContainer as getContainer5,
4680
- getWidgetsCache as getWidgetsCache9
4681
- } from "@elementor/editor-elements";
4682
- import { dispatchMcpStylesAppliedEvent } from "@elementor/editor-mcp";
4449
+ import { getCurrentDocument, reloadCurrentDocument } from "@elementor/editor-documents";
4450
+ import { getContainer as getContainer4, selectElement } from "@elementor/editor-elements";
4451
+ import { AxiosError, httpService as httpService6 } from "@elementor/http-client";
4452
+ import { z } from "@elementor/schema";
4453
+ var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
4454
+ var initBuildCompositionTool = (reg) => {
4455
+ const { addTool } = reg;
4456
+ addTool({
4457
+ name: "build-composition",
4458
+ description: "Build a V4 element composition on the Elementor canvas via the server-side MCP ability. Pass the raw XML tags directly as xmlStructure \u2014 do NOT wrap the value in <![CDATA[ ... ]]>, code fences, or quotes. The document is saved as a draft. Reload the editor after calling this tool to see the result.",
4459
+ schema: {
4460
+ xmlStructure: z.string().describe(
4461
+ 'Valid XML structure with custom Elementor widget tags. Every element MUST have a unique configuration-id attribute (e.g. <e-heading configuration-id="hero-title"></e-heading>). No attributes, classes, IDs, or text nodes in XML. Pass raw XML \u2014 do not wrap in CDATA.'
4462
+ ),
4463
+ elementConfig: z.record(
4464
+ z.string().describe("configuration-id"),
4465
+ z.record(z.string().describe("property name"), z.any().describe("PropValue"))
4466
+ ).optional().describe("Map configuration-id \u2192 widget PropValues ($$type + value)."),
4467
+ style: z.record(
4468
+ z.string().describe("configuration-id"),
4469
+ z.record(z.string().describe("CSS property name"), z.string().describe("CSS value"))
4470
+ ).optional().describe(
4471
+ "Map configuration-id \u2192 raw CSS declarations (property \u2192 value strings; no selectors). Server converts to native styles; unconvertible declarations become the element custom CSS."
4472
+ ),
4473
+ parentId: z.string().optional().describe("ID of the parent container. Omit or pass 'document' to insert at document root."),
4474
+ dryRun: z.boolean().optional().describe("If true, validate and return the resolved tree without persisting.")
4475
+ },
4476
+ outputSchema: {
4477
+ rootElementIds: z.array(z.string()),
4478
+ previewUrl: z.string(),
4479
+ version: z.string(),
4480
+ resolvedXml: z.string(),
4481
+ llmInstructions: z.string(),
4482
+ warnings: z.array(z.string()).optional()
4483
+ },
4484
+ handler: async ({ xmlStructure, elementConfig, style, parentId, dryRun }) => {
4485
+ const document2 = getCurrentDocument();
4486
+ if (!document2?.id) {
4487
+ throw new Error("No active document found.");
4488
+ }
4489
+ try {
4490
+ const { data } = await httpService6().post(MCP_PROXY_URL5, {
4491
+ tool: "build-composition",
4492
+ input: {
4493
+ post_id: document2.id,
4494
+ xml_structure: xmlStructure,
4495
+ element_config: elementConfig ?? {},
4496
+ style: style ?? {},
4497
+ parent_id: parentId ?? "document",
4498
+ dry_run: dryRun ?? false
4499
+ }
4500
+ });
4501
+ if (!dryRun) {
4502
+ await reloadCurrentDocument();
4503
+ const [firstRootId] = data.data.root_element_ids;
4504
+ if (firstRootId) {
4505
+ selectElement(firstRootId);
4506
+ getContainer4(firstRootId)?.view?.el?.scrollIntoView({
4507
+ behavior: "smooth",
4508
+ block: "center"
4509
+ });
4510
+ }
4511
+ }
4512
+ return {
4513
+ rootElementIds: data.data.root_element_ids,
4514
+ previewUrl: data.data.preview_url,
4515
+ version: data.data.version,
4516
+ resolvedXml: data.data.resolved_xml,
4517
+ llmInstructions: data.data.llm_instructions,
4518
+ warnings: data.data.warnings
4519
+ };
4520
+ } catch (error) {
4521
+ throw new Error(getErrorMessage(error));
4522
+ }
4523
+ }
4524
+ });
4525
+ };
4526
+ function getErrorMessage(error) {
4527
+ if (error instanceof AxiosError) {
4528
+ const data = error.response?.data;
4529
+ if (data?.message) {
4530
+ return data.code ? `${data.code}: ${data.message}` : data.message;
4531
+ }
4532
+ }
4533
+ if (error instanceof Error) {
4534
+ return error.message;
4535
+ }
4536
+ return "build-composition failed with an unknown error.";
4537
+ }
4683
4538
 
4684
- // src/composition-builder/composition-builder.ts
4685
- import {
4686
- createElement as createElement12,
4687
- deleteElement,
4688
- generateElementId as generateElementId2,
4689
- getContainer as getContainer4,
4690
- getWidgetsCache as getWidgetsCache8
4691
- } from "@elementor/editor-elements";
4539
+ // src/mcp/tools/configure-element/tool.ts
4540
+ import { getContainer as getContainer5, getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
4541
+ import { dispatchMcpStylesAppliedEvent } from "@elementor/editor-mcp";
4542
+ import { Schema as Schema2 } from "@elementor/editor-props";
4692
4543
 
4693
4544
  // src/mcp/utils/do-update-element-property.ts
4694
4545
  import {
4695
4546
  createElementStyle,
4696
4547
  getElementStyles,
4697
- getWidgetsCache as getWidgetsCache7,
4548
+ getWidgetsCache as getWidgetsCache5,
4698
4549
  updateElementSettings,
4699
4550
  updateElementStyle
4700
4551
  } from "@elementor/editor-elements";
4701
- import { getPropSchemaFromCache as getPropSchemaFromCache2, Schema as Schema3 } from "@elementor/editor-props";
4552
+ import { getPropSchemaFromCache as getPropSchemaFromCache2, Schema } from "@elementor/editor-props";
4702
4553
  import { getStylesSchema as getStylesSchema2, getVariantByMeta } from "@elementor/editor-styles";
4703
4554
  import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
4704
4555
 
@@ -4717,7 +4568,7 @@ var readStoredCustomCssText = (raw) => {
4717
4568
  };
4718
4569
 
4719
4570
  // src/mcp/utils/resolve-canonical-prop-name.ts
4720
- import { getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
4571
+ import { getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
4721
4572
  function buildAliasToCanonicalMap(schema2) {
4722
4573
  const aliasToCanonical = {};
4723
4574
  for (const [canonical, propType] of Object.entries(schema2)) {
@@ -4734,14 +4585,14 @@ function buildAliasToCanonicalMap(schema2) {
4734
4585
  return aliasToCanonical;
4735
4586
  }
4736
4587
  function resolveCanonicalPropName(elementType, propertyName) {
4737
- const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
4588
+ const schema2 = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4738
4589
  if (!schema2 || schema2[propertyName]) {
4739
4590
  return propertyName;
4740
4591
  }
4741
4592
  return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4742
4593
  }
4743
4594
  function resolveCanonicalPropKeys(elementType, props) {
4744
- const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
4595
+ const schema2 = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4745
4596
  if (!schema2) {
4746
4597
  return { ...props };
4747
4598
  }
@@ -4768,6 +4619,68 @@ function resolveCanonicalPropKeys(elementType, props) {
4768
4619
  return resolved;
4769
4620
  }
4770
4621
 
4622
+ // src/mcp/utils/resolve-dynamic-tag.ts
4623
+ import { getElementorConfig } from "@elementor/editor-v1-adapters";
4624
+ var DYNAMIC_PROP_TYPE_KEY = "dynamic";
4625
+ var OMITTED_DYNAMIC_SETTING_KEYS = ["fallback"];
4626
+ var getAtomicDynamicTags = () => {
4627
+ const config = getElementorConfig();
4628
+ return config.atomicDynamicTags?.tags ?? {};
4629
+ };
4630
+ var getDynamicTagNamesByCategories = (categories) => {
4631
+ if (!categories.length) {
4632
+ return [];
4633
+ }
4634
+ const wanted = new Set(categories);
4635
+ return Object.values(getAtomicDynamicTags()).filter((tag) => tag.categories?.some((category) => wanted.has(category))).map((tag) => tag.name);
4636
+ };
4637
+ var dynamicTagLLMResolver = (value) => {
4638
+ const input = value ?? {};
4639
+ const tag = input.name ? getAtomicDynamicTags()[input.name] : void 0;
4640
+ if (!tag) {
4641
+ return {
4642
+ $$type: DYNAMIC_PROP_TYPE_KEY,
4643
+ value: { name: input.name ?? "", group: "", settings: {} }
4644
+ };
4645
+ }
4646
+ return {
4647
+ $$type: DYNAMIC_PROP_TYPE_KEY,
4648
+ value: {
4649
+ name: tag.name,
4650
+ group: tag.group,
4651
+ settings: buildStrictSettings(tag.props_schema ?? {}, input.settings ?? {})
4652
+ }
4653
+ };
4654
+ };
4655
+ var buildStrictSettings = (schema2, provided) => {
4656
+ const settings = {};
4657
+ for (const [key, propType] of Object.entries(schema2)) {
4658
+ if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
4659
+ continue;
4660
+ }
4661
+ const resolved = provided[key] !== void 0 ? wrapSettingValue(provided[key], propType) : defaultSettingValue(propType);
4662
+ if (resolved !== void 0 && resolved !== null) {
4663
+ settings[key] = resolved;
4664
+ }
4665
+ }
4666
+ return settings;
4667
+ };
4668
+ var wrapSettingValue = (raw, propType) => {
4669
+ if (raw !== null && typeof raw === "object") {
4670
+ return raw;
4671
+ }
4672
+ return propType.key ? { $$type: propType.key, value: raw } : raw;
4673
+ };
4674
+ var defaultSettingValue = (propType) => {
4675
+ if (propType.initial_value !== null && propType.initial_value !== void 0) {
4676
+ return propType.initial_value;
4677
+ }
4678
+ if (propType.default !== null && propType.default !== void 0) {
4679
+ return wrapSettingValue(propType.default, propType);
4680
+ }
4681
+ return void 0;
4682
+ };
4683
+
4771
4684
  // src/mcp/utils/do-update-element-property.ts
4772
4685
  var LOCAL_STYLE_META = {
4773
4686
  breakpoint: "desktop",
@@ -4775,7 +4688,7 @@ var LOCAL_STYLE_META = {
4775
4688
  };
4776
4689
  function resolvePropValue(value, forceKey) {
4777
4690
  const Utils = window.elementorV2.editorVariables.Utils;
4778
- return Schema3.adjustLlmPropValueSchema(value, {
4691
+ return Schema.adjustLlmPropValueSchema(value, {
4779
4692
  forceKey,
4780
4693
  transformers: {
4781
4694
  ...Utils.globalVariablesLLMResolvers,
@@ -4873,7 +4786,7 @@ var doUpdateElementProperty = (params) => {
4873
4786
  }
4874
4787
  return;
4875
4788
  }
4876
- const elementPropSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
4789
+ const elementPropSchema = getWidgetsCache5()?.[elementType]?.atomic_props_schema;
4877
4790
  if (!elementPropSchema) {
4878
4791
  throw new Error(`No prop schema found for element type: ${elementType}`);
4879
4792
  }
@@ -4887,7 +4800,7 @@ var doUpdateElementProperty = (params) => {
4887
4800
  }
4888
4801
  const propKey = elementPropSchema[propertyName].key;
4889
4802
  const value = resolvePropValue(propertyValue, propKey);
4890
- const { valid, jsonSchema } = Schema3.validatePropValue(elementPropSchema[propertyName], propertyValue);
4803
+ const { valid, jsonSchema } = Schema.validatePropValue(elementPropSchema[propertyName], propertyValue);
4891
4804
  if (!valid) {
4892
4805
  throw new Error(
4893
4806
  `Invalid PropValue for elementId: ${elementId}. PropKey: ${propKey}, PropValue: ${JSON.stringify(
@@ -4906,739 +4819,11 @@ Expected Schema: ${jsonSchema}`
4906
4819
  runCommandSync2("document/save/set-is-modified", { status: true }, { internal: true });
4907
4820
  };
4908
4821
 
4909
- // src/composition-builder/utils/required-children-enforcer.ts
4910
- var REQUIRED_CHILD_SCHEMA_HINT = "Use the widget schema resource; under llm_guidance.required_direct_children for V4 widgets.";
4911
- var RequiredChildrenEnforcer = class {
4912
- elementType;
4913
- requiredTemplates;
4914
- constructor(elementType, widgetsCache) {
4915
- this.elementType = elementType;
4916
- this.requiredTemplates = getRequiredDefaultChildTemplates(widgetsCache[elementType]);
4917
- }
4918
- enforce(xml) {
4919
- if (this.requiredTemplates.length === 0) {
4920
- return;
4921
- }
4922
- const errors = [];
4923
- for (const rootNode of Array.from(xml.children)) {
4924
- this.collectMissingRequiredErrors(rootNode, errors);
4925
- }
4926
- if (errors.length) {
4927
- throw new Error(`${errors.join("\n")}
4928
- ${REQUIRED_CHILD_SCHEMA_HINT}`);
4929
- }
4930
- }
4931
- collectMissingRequiredErrors(node, errors) {
4932
- if (node.tagName === this.elementType) {
4933
- const existingChildTags = new Set(Array.from(node.children).map((child) => child.tagName));
4934
- const missingTags = this.requiredTemplates.map((child) => child.widgetType ?? child.elType ?? "").filter((type) => type && !existingChildTags.has(type));
4935
- if (missingTags.length) {
4936
- const configurationId = node.getAttribute("configuration-id");
4937
- const location2 = configurationId ? `<${node.tagName} configuration-id="${configurationId}">` : `<${node.tagName}>`;
4938
- errors.push(
4939
- `${location2} Missing required direct child element tag(s): ${missingTags.join(", ")}.`
4940
- );
4941
- }
4942
- }
4943
- for (const childNode of Array.from(node.children)) {
4944
- this.collectMissingRequiredErrors(childNode, errors);
4945
- }
4946
- }
4947
- };
4948
-
4949
- // src/composition-builder/composition-builder.ts
4950
- var CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = "createElement did not return an element container with a model.";
4951
- var CompositionBuilder = class _CompositionBuilder {
4952
- elementConfig = {};
4953
- elementStylesConfig = {};
4954
- elementCustomCSS = {};
4955
- rootContainers = [];
4956
- api = {
4957
- createElement: createElement12,
4958
- deleteElement,
4959
- getWidgetsCache: getWidgetsCache8,
4960
- generateElementId: generateElementId2,
4961
- getContainer: getContainer4,
4962
- doUpdateElementProperty
4963
- };
4964
- xml;
4965
- static fromXMLString(xmlString, api = {}) {
4966
- const parser = new DOMParser();
4967
- const xmlDoc = parser.parseFromString(xmlString, "application/xml");
4968
- const errorNode = xmlDoc.querySelector("parsererror");
4969
- if (errorNode) {
4970
- throw new Error("Failed to parse XML string: " + errorNode.textContent);
4971
- }
4972
- return new _CompositionBuilder({
4973
- xml: xmlDoc,
4974
- api
4975
- });
4976
- }
4977
- constructor(opts) {
4978
- const { api = {}, elementConfig = {}, stylesConfig = {}, customCSS = {}, xml } = opts;
4979
- this.xml = xml;
4980
- Object.assign(this.api, api);
4981
- this.setElementConfig(elementConfig);
4982
- this.setStylesConfig(stylesConfig);
4983
- this.setCustomCSS(customCSS);
4984
- }
4985
- setElementConfig(config) {
4986
- this.elementConfig = config;
4987
- }
4988
- setStylesConfig(config) {
4989
- this.elementStylesConfig = config;
4990
- }
4991
- setCustomCSS(config) {
4992
- this.elementCustomCSS = config;
4993
- }
4994
- getXML() {
4995
- return this.xml;
4996
- }
4997
- buildModelTree(node, widgetsCache) {
4998
- const elementTag = node.tagName;
4999
- const isWidget = widgetsCache[elementTag]?.elType === "widget";
5000
- const id = this.api.generateElementId();
5001
- const children = Array.from(node.children).map((child) => this.buildModelTree(child, widgetsCache));
5002
- node.setAttribute("id", id);
5003
- const base = {
5004
- id,
5005
- skipDefaultChildren: true,
5006
- elements: children,
5007
- editor_settings: {
5008
- title: node.getAttribute("configuration-id") ?? void 0
5009
- },
5010
- elType: "widget"
5011
- };
5012
- if (isWidget) {
5013
- return { ...base, elType: "widget", widgetType: elementTag };
5014
- }
5015
- return { ...base, elType: elementTag };
5016
- }
5017
- async awaitViewRender(element) {
5018
- const view = element.view;
5019
- if (view?._currentRenderPromise instanceof Promise) {
5020
- await view._currentRenderPromise;
5021
- } else {
5022
- await Promise.resolve();
5023
- }
5024
- }
5025
- validateChildTypes(node, widgetsCache) {
5026
- const errors = [];
5027
- const allowedChildTypes = widgetsCache[node.tagName]?.allowed_child_types;
5028
- if (allowedChildTypes?.length) {
5029
- for (const child of Array.from(node.children)) {
5030
- if (!allowedChildTypes.includes(child.tagName)) {
5031
- errors.push(
5032
- `"${child.tagName}" is not allowed as a child of "${node.tagName}". Allowed: ${allowedChildTypes.join(", ")}`
5033
- );
5034
- }
5035
- }
5036
- }
5037
- for (const child of Array.from(node.children)) {
5038
- errors.push(...this.validateChildTypes(child, widgetsCache));
5039
- }
5040
- return errors;
5041
- }
5042
- matchNodeByConfigId(configId) {
5043
- const node = this.xml.querySelector(`[configuration-id="${configId}"]`);
5044
- if (!node) {
5045
- throw new Error(`Configuration id "${configId}" does not have target node.`);
5046
- }
5047
- const id = node.getAttribute("id");
5048
- if (!id) {
5049
- throw new Error(`Node with configuration id "${configId}" does not have element id.`);
5050
- }
5051
- const element = this.api.getContainer(id);
5052
- if (!element) {
5053
- throw new Error(`Element with id "${id}" not found but should exist.`);
5054
- }
5055
- return {
5056
- element,
5057
- node
5058
- };
5059
- }
5060
- async applyProperties() {
5061
- const configErrors = [];
5062
- const styleErrors = [];
5063
- const allConfigIds = /* @__PURE__ */ new Set([
5064
- ...Object.keys(this.elementConfig),
5065
- ...Object.keys(this.elementStylesConfig),
5066
- ...Object.keys(this.elementCustomCSS)
5067
- ]);
5068
- for (const configId of allConfigIds) {
5069
- let element, node;
5070
- try {
5071
- ({ element, node } = this.matchNodeByConfigId(configId));
5072
- } catch (matchErr) {
5073
- const msg = matchErr.message;
5074
- if (this.elementConfig[configId]) {
5075
- configErrors.push(msg);
5076
- }
5077
- if (this.elementStylesConfig[configId] || this.elementCustomCSS[configId]) {
5078
- styleErrors.push(msg);
5079
- }
5080
- continue;
5081
- }
5082
- const config = this.elementConfig[configId];
5083
- if (config) {
5084
- for (const [propertyName, propertyValue] of Object.entries(config)) {
5085
- try {
5086
- this.api.doUpdateElementProperty({
5087
- elementId: element.id,
5088
- propertyName,
5089
- propertyValue,
5090
- elementType: node.tagName
5091
- });
5092
- } catch (error) {
5093
- configErrors.push(error.message);
5094
- }
5095
- }
5096
- }
5097
- const styleConfig = this.elementStylesConfig[configId];
5098
- const hasInvalidStyles = false;
5099
- if (styleConfig) {
5100
- const validStylesPropValues = {};
5101
- for (const [styleName, stylePropValue] of Object.entries(styleConfig)) {
5102
- if (styleName === "$intention") {
5103
- continue;
5104
- } else {
5105
- validStylesPropValues[styleName] = stylePropValue;
5106
- }
5107
- }
5108
- if (Object.keys(validStylesPropValues).length > 0) {
5109
- try {
5110
- this.api.doUpdateElementProperty({
5111
- elementId: element.id,
5112
- propertyName: "_styles",
5113
- propertyValue: validStylesPropValues,
5114
- elementType: node.tagName
5115
- });
5116
- } catch (error) {
5117
- styleErrors.push(String(error));
5118
- }
5119
- }
5120
- }
5121
- const intentionCss = typeof styleConfig?.$intention === "string" ? styleConfig.$intention.trim() : "";
5122
- const fallbackCss = hasInvalidStyles && intentionCss ? intentionCss : "";
5123
- const mergedCustomCss = mergeCustomCssText(this.elementCustomCSS[configId], fallbackCss);
5124
- if (mergedCustomCss) {
5125
- try {
5126
- this.api.doUpdateElementProperty({
5127
- elementId: element.id,
5128
- propertyName: "_styles",
5129
- propertyValue: { custom_css: mergedCustomCss },
5130
- elementType: node.tagName
5131
- });
5132
- } catch (cssErr) {
5133
- styleErrors.push(String(cssErr));
5134
- }
5135
- }
5136
- await this.awaitViewRender(element);
5137
- }
5138
- return { configErrors, styleErrors };
5139
- }
5140
- async build(rootContainer) {
5141
- const widgetsCache = this.api.getWidgetsCache() || {};
5142
- new Set(this.xml.querySelectorAll("*")).forEach((node) => {
5143
- if (!widgetsCache[node.tagName]) {
5144
- throw new Error(`Unknown widget type: ${node.tagName}`);
5145
- }
5146
- });
5147
- const typesWithRequiredChildren = Object.keys(widgetsCache).filter(
5148
- (elementType) => getRequiredDefaultChildTemplates(widgetsCache[elementType]).length > 0
5149
- );
5150
- typesWithRequiredChildren.forEach((elementType) => {
5151
- new RequiredChildrenEnforcer(elementType, widgetsCache).enforce(this.xml);
5152
- });
5153
- const childTypeErrors = [];
5154
- for (const rootChild of Array.from(this.xml.children)) {
5155
- childTypeErrors.push(...this.validateChildTypes(rootChild, widgetsCache));
5156
- }
5157
- if (childTypeErrors.length) {
5158
- throw new Error(`Invalid element structure:
5159
- ${childTypeErrors.join("\n")}`);
5160
- }
5161
- const children = Array.from(this.xml.children);
5162
- for (const childNode of children) {
5163
- const modelTree = this.buildModelTree(childNode, widgetsCache);
5164
- try {
5165
- const newElement = this.api.createElement({
5166
- container: rootContainer,
5167
- model: modelTree,
5168
- options: { useHistory: false }
5169
- });
5170
- if (!newElement?.model) {
5171
- throw new Error(CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE);
5172
- }
5173
- this.rootContainers.push(newElement);
5174
- await this.awaitViewRender(newElement);
5175
- } catch (e) {
5176
- const attempToRestoreInvalidContainer = this.api.getContainer(modelTree.id);
5177
- if (attempToRestoreInvalidContainer) {
5178
- this.api.deleteElement({ container: attempToRestoreInvalidContainer });
5179
- }
5180
- throw e;
5181
- }
5182
- }
5183
- const { configErrors, styleErrors } = await this.applyProperties();
5184
- if (typeof window !== "undefined") {
5185
- const targetWindow = window.top || window;
5186
- targetWindow.dispatchEvent(
5187
- new CustomEvent("elementor/composition/built", {
5188
- detail: { rootContainers: this.rootContainers.map((c) => c.id) }
5189
- })
5190
- );
5191
- }
5192
- return {
5193
- configErrors,
5194
- styleErrors,
5195
- rootContainers: [...this.rootContainers]
5196
- };
5197
- }
5198
- };
5199
-
5200
- // src/utils/tracking.ts
5201
- import { trackEvent } from "@elementor/events";
5202
- var trackCanvasEvent = (data) => {
5203
- trackEvent(data);
5204
- };
5205
-
5206
- // src/mcp/utils/get-composition-target-container.ts
5207
- import { COMPONENT_DOCUMENT_TYPE } from "@elementor/editor-documents";
5208
- function getCompositionTargetContainer(documentContainer, documentType) {
5209
- const firstChild = documentContainer.children?.[0];
5210
- if (documentType === COMPONENT_DOCUMENT_TYPE && firstChild) {
5211
- return firstChild;
5212
- }
5213
- return documentContainer;
5214
- }
5215
-
5216
- // src/mcp/tools/build-composition/prompt.ts
5217
- import { toolPrompts } from "@elementor/editor-mcp";
5218
- var BUILD_COMPOSITIONS_GUIDE_URI = "elementor://canvas/tools/build-compositions-guide";
5219
- var generatePrompt = () => {
5220
- const buildCompositionsToolPrompt = toolPrompts("build-compositions");
5221
- buildCompositionsToolPrompt.description(`
5222
- # RESOURCES (Read before use)
5223
- - [elementor://global-classes] - Check FIRST for reusable classes
5224
- - [elementor://global-variables] - ONLY use variables defined here
5225
- - [${AVAILABLE_WIDGETS_URI}/v4]
5226
-
5227
- # TOOL SUPPORT
5228
- This tool support v4 elements only
5229
-
5230
- # WORKFLOW
5231
- 1. Check/create global classes via "manage-global-classes" tool
5232
- 2. Build composition (THIS TOOL) - minimal inline styles
5233
- 3. Apply classes via "apply-global-class" tool
5234
-
5235
- # XML STRUCTURE
5236
- - Use widget tags: \`<e-button configuration-id="btn1"></e-button>\`
5237
- - Containers: "e-flexbox", "e-div-block", "e-tabs"
5238
- - Every element needs unique "configuration-id"
5239
- - No attributes, classes, IDs, or text nodes in XML
5240
-
5241
- ## NESTED ELEMENTS
5242
- Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML.
5243
- - Check \`llm_guidance.nesting\` in widget schemas for structure requirements
5244
- - \`llm_guidance.required_direct_children\` lists element types that must appear as direct child tags in XML (from widget defaults)
5245
- - \`allowed_child_types\` lists which element types can be nested inside
5246
- - \`allowed_parents\` lists which element types this element can be placed inside
5247
-
5248
- # CONFIGURATION
5249
- - Map configuration-id \u2192 elementConfig (props) + style (raw CSS declarations)
5250
- - elementConfig PropValues require \`$$type\` matching schema
5251
- - style is raw CSS (property \u2192 value strings); the server converts it to native styles and stores any unconvertible declarations as the element custom CSS
5252
- - NO LINKS in configuration
5253
- - Retry on errors up to 10x
5254
- - Check \`llm_guidance.default_settings\` in widget schemas \u2014 omit only keys listed there from elementConfig unless the user explicitly asks to change them
5255
-
5256
- # DYNAMIC TAGS
5257
- - A value can be made dynamic wherever its schema exposes a \`"$$type": "dynamic"\` variant. This may be the property root OR a NESTED field (e.g. an image's \`src\`, not the whole \`image\`).
5258
- - Put the dynamic object EXACTLY at that node, in place of the static variant. The variant's \`name\` lists the allowed tags; read [${DYNAMIC_TAGS_URI}] for each tag's settings schema.
5259
- - Provide at that node: \`{ "$$type": "dynamic", "value": { "name": "<allowed tag>", "settings": { ... } } }\`
5260
- - Example (image): \`{ "$$type": "image", "value": { "src": { "$$type": "dynamic", "value": { "name": "<image tag>", "settings": { ... } } } } }\`
5261
- - Do NOT send \`group\` (it is resolved automatically). Populate \`settings\` strictly per the tag's schema; use \`{}\` only when it has none.
5262
-
5263
- Note about configuration ids: These names are visible to the end-user, make sure they make sense, related and relevant.
5264
-
5265
- # DESIGN PHILOSOPHY: CONTEXT-DRIVEN CREATIVITY
5266
-
5267
- **Use the user's context aggressively.** Business type, brand personality, target audience, and purpose should drive every design decision. A law firm needs gravitas; a children's app needs playfulness. Don't default to generic.
5268
-
5269
- ## SIZING: DEFAULT IS NO SIZE (CRITICAL)
5270
-
5271
- **DO NOT specify height or width unless you have a specific visual reason.**
5272
-
5273
- Flexbox and CSS already handle sizing automatically:
5274
- - Containers grow to fit their content
5275
- - Flex children distribute space via flex properties, not width/height
5276
- - Text elements size to their content
5277
-
5278
- WHEN TO SPECIFY SIZE:
5279
- - min-height on ROOT section for viewport-spanning hero (use min-height, NOT height)
5280
- - max-width for contained content areas (e.g., max-width: 60rem)
5281
- - Explicit aspect ratios for media containers
5282
-
5283
- NEVER SPECIFY:
5284
- - height on nested containers (causes overflow)
5285
- - width on flex children (use flex-basis or gap instead)
5286
- - 100vh on anything except root-level sections
5287
- - Any size "just to be safe" - if unsure, OMIT IT
5288
-
5289
- vh units are VIEWPORT-relative. Nested 100vh inside 100vh = 200vh overflow.
5290
-
5291
- GOOD: \`<e-flexbox>content naturally sizes</e-flexbox>\`
5292
- BAD: \`<e-flexbox style="height:100vh"><e-div-block style="height:100vh">overflow</e-div-block></e-flexbox>\`
5293
-
5294
- ## Layout Variety (Break the Template)
5295
- - AVOID: Full-width 100vh hero \u2192 three columns \u2192 testimonials \u2192 CTA (every AI does this)
5296
- - VARY heights: Use auto-height sections with generous padding (6rem+). Let content breathe
5297
- - VARY widths: Not everything spans full width. Use contained sections (max-width: 960px) mixed with edge-to-edge
5298
- - ASYMMETRIC grids: 2:1, 1:3, offset layouts. Avoid equal column widths
5299
- - Negative space as design element: Large margins create focus and sophistication
5300
- - Break alignment intentionally: Offset headings, overlapping elements, broken grids
5301
-
5302
- ## Visual Depth & Effects
5303
- - Layer elements: Overlapping cards, text over images, floating elements
5304
- - Subtle shadows with color tint (not pure black): \`box-shadow: 0 20px 60px rgba(<brand-color-here>, 0.15)\`
5305
- - Gradient overlays on images for text readability
5306
- - Border radius variation: Mix sharp (0) and soft (1rem+) corners purposefully
5307
- - Backdrop blur for glassmorphism where appropriate
5308
- - Micro-interactions via CSS: hover transforms, transitions (0.3s ease)
5309
-
5310
- ## Typography with Character
5311
- - Display fonts for headlines (from user's brand or contextually appropriate)
5312
- - Size contrast: 4rem+ headlines vs 1rem body. Make hierarchy unmistakable
5313
- - Letter-spacing: Tight for large headlines (-0.02em), loose for small caps (0.1em)
5314
- - Line-height: Tight for headlines (1.1), generous for body (1.6-1.8)
5315
- - Text decoration: Underlines, highlights, gradient text for emphasis
5316
-
5317
- ## Color with Purpose
5318
- - Extract palette from user context (brand colors, industry norms, mood)
5319
- - 60-30-10 rule: dominant, secondary, accent
5320
- - Tinted neutrals over pure grays: warm (#faf8f5, #2d2a26) or cool (#f5f7fa, #1e2430)
5321
- - Color blocking: Large colored sections create visual rhythm
5322
- - Gradient directions: Diagonal (135deg, 225deg) feel more dynamic than vertical
5323
-
5324
- ## Spacing Strategy
5325
- - Section padding: 6rem-10rem vertical, creating breathing room
5326
- - Rhythm variation: Tight groups (2rem) with generous gaps between (6rem)
5327
- - Use rem/em exclusively for responsive scaling
5328
- - Generous padding on CTAs: min 1rem 2.5rem
5329
-
5330
- # HARD CONSTRAINTS
5331
- - Variables ONLY from [elementor://global-variables] (others throw errors)
5332
- - Avoid SVG widgets unless assets are pre-uploaded
5333
- - Check \`llm_guidance\` in widget schemas (\`default_styles\`, nesting, required children)
5334
-
5335
- # PARAMETERS
5336
- - **xmlStructure**: Valid XML with configuration-id attributes
5337
- - **elementConfig**: configuration-id \u2192 widget PropValues
5338
- - **style**: configuration-id \u2192 raw CSS declarations (property \u2192 value strings; no selectors)
5339
- `);
5340
- buildCompositionsToolPrompt.example(`
5341
- Section with heading + button (NO explicit heights - content sizes naturally):
5342
- {
5343
- xmlStructure: "<e-flexbox configuration-id="Main Section"><e-heading configuration-id="Section Title"></e-heading><e-button configuration-id="Call to Action"></e-button></e-flexbox>",
5344
- elementConfig: {
5345
- "section1": { "tag": { "$$type": "string", "value": "section" } }
5346
- },
5347
- style: {
5348
- "Section Title": {
5349
- "padding": "6rem 4rem",
5350
- "background": "linear-gradient(135deg, #faf8f5 0%, #f0ebe4 100%)",
5351
- "font-size": "3.5rem",
5352
- "color": "#2d2a26"
5353
- }
5354
- }
5355
- }
5356
- Note: No height/width specified on any element - flexbox handles layout automatically.
5357
- `);
5358
- buildCompositionsToolPrompt.parameter(
5359
- "xmlStructure",
5360
- `Valid XML structure with custom elementor tags and configuration-id attributes.`
5361
- );
5362
- buildCompositionsToolPrompt.parameter("elementConfig", `Record mapping configuration IDs to widget PropValues.`);
5363
- buildCompositionsToolPrompt.parameter(
5364
- "style",
5365
- `Record mapping configuration IDs to raw CSS declarations (property \u2192 value strings).`
5366
- );
5367
- buildCompositionsToolPrompt.instruction(
5368
- `Element IDs in the returned XML represent actual widgets. Use these IDs for subsequent styling or configuration changes.`
5369
- );
5370
- return buildCompositionsToolPrompt.prompt();
5371
- };
5372
-
5373
- // src/mcp/tools/build-composition/schema.ts
5374
- import { z } from "@elementor/schema";
5375
- var inputSchema = {
5376
- xmlStructure: z.string().describe("The XML structure representing the composition to be built"),
5377
- elementConfig: z.record(
5378
- z.string().describe("The configuration id"),
5379
- z.record(
5380
- z.string().describe("property name"),
5381
- z.any().describe(`The PropValue for the property, refer to ${WIDGET_SCHEMA_URI}`)
5382
- )
5383
- ).describe("A record mapping element IDs to their configuration objects. REQUIRED"),
5384
- style: z.record(
5385
- z.string().describe("The configuration id"),
5386
- z.record(
5387
- z.string().describe('A CSS property name, e.g. "color", "padding".'),
5388
- z.string().describe('A CSS value, e.g. "6rem 4rem", "#2d2a26".')
5389
- )
5390
- ).describe(
5391
- "A record mapping element configuration IDs to their raw CSS declarations (property\u2192value). Converted to native styles server-side; any declaration that cannot be converted is stored as the element custom CSS."
5392
- ).default({})
5393
- };
5394
- var outputSchema = {
5395
- errors: z.string().describe("Error message if the composition building failed").optional(),
5396
- xmlStructure: z.string().describe(
5397
- "The built XML structure as a string. Must use this XML after completion of building the composition, it contains real IDs."
5398
- ).optional(),
5399
- llm_instructions: z.string().describe("Instructions what to do next, Important to follow these instructions!").optional()
5400
- };
5401
-
5402
- // src/mcp/tools/build-composition/xml-leaf-wrapper.ts
5403
- var DIV_BLOCK_TAG = "e-div-block";
5404
- var ZERO_SPACING = {
5405
- $$type: "size",
5406
- value: {
5407
- size: {
5408
- $$type: "number",
5409
- value: 0
5410
- },
5411
- unit: {
5412
- $$type: "string",
5413
- value: "px"
5414
- }
5415
- }
5416
- };
5417
- function adaptLeafRootParams(params) {
5418
- const doc = new DOMParser().parseFromString(params.xmlStructure, "application/xml");
5419
- const rootElement = doc.documentElement;
5420
- if (!isLeafWidget(rootElement.tagName, params.widgetsCache)) {
5421
- return params;
5422
- }
5423
- const wrapperConfigId = getDivBlockWrapperConfigId(params.widgetsCache);
5424
- return {
5425
- ...params,
5426
- xmlStructure: serializeWrapped(doc, rootElement, wrapperConfigId),
5427
- stylesConfig: {
5428
- ...params.stylesConfig,
5429
- [wrapperConfigId]: {
5430
- margin: ZERO_SPACING,
5431
- padding: ZERO_SPACING,
5432
- ...params.stylesConfig[wrapperConfigId]
5433
- }
5434
- }
5435
- };
5436
- }
5437
- function getDivBlockWrapperConfigId(widgetsCache) {
5438
- return widgetsCache[DIV_BLOCK_TAG]?.title ?? DIV_BLOCK_TAG;
5439
- }
5440
- function isLeafWidget(tagName, widgetsCache) {
5441
- return widgetsCache[tagName]?.elType === "widget";
5442
- }
5443
- function serializeWrapped(doc, rootElement, wrapperConfigId) {
5444
- const wrapper = doc.createElement(DIV_BLOCK_TAG);
5445
- wrapper.setAttribute("configuration-id", wrapperConfigId);
5446
- wrapper.appendChild(rootElement.cloneNode(true));
5447
- const wrappedDoc = new DOMParser().parseFromString(`<${DIV_BLOCK_TAG} />`, "application/xml");
5448
- wrappedDoc.replaceChild(wrapper, wrappedDoc.documentElement);
5449
- return new XMLSerializer().serializeToString(wrappedDoc);
5450
- }
5451
-
5452
- // src/mcp/tools/build-composition/tool.ts
5453
- var ELEMENT_ADDED_EVENT = "elementor/canvas/element-added";
5454
- var initBuildCompositionsTool = (reg) => {
5455
- const { addTool, resource } = reg;
5456
- resource(
5457
- "build-compositions-guide",
5458
- BUILD_COMPOSITIONS_GUIDE_URI,
5459
- {
5460
- title: "Build Compositions Guide",
5461
- description: "Detailed guide for using the build-compositions tool",
5462
- mimeType: "text/plain"
5463
- },
5464
- async (uri) => ({
5465
- contents: [{ uri: uri.href, mimeType: "text/plain", text: generatePrompt() }]
5466
- })
5467
- );
5468
- addTool({
5469
- name: "build-compositions",
5470
- description: "Build V4 element compositions on the Elementor canvas. Read the guide resource before use.",
5471
- schema: inputSchema,
5472
- requiredResources: [
5473
- { description: "Build compositions guide", uri: BUILD_COMPOSITIONS_GUIDE_URI },
5474
- { description: "Widgets schema", uri: WIDGET_SCHEMA_URI },
5475
- { description: "Global Classes", uri: "elementor://global-classes" },
5476
- { description: "Global Variables", uri: "elementor://global-variables" },
5477
- { description: "Styles best practices", uri: BEST_PRACTICES_URI },
5478
- { description: "Available widgets for this tool", uri: AVAILABLE_WIDGETS_URI_V4 },
5479
- { description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
5480
- ],
5481
- outputSchema,
5482
- handler: async (rawParams) => {
5483
- assertCompositionXmlUsesV4WidgetsOnly(rawParams.xmlStructure);
5484
- const { stylesConfig: convertedStyles, customCSS } = await convertCompositionStyles(rawParams.style);
5485
- const { xmlStructure, elementConfig, stylesConfig } = adaptLeafRootParams({
5486
- ...rawParams,
5487
- stylesConfig: convertedStyles,
5488
- widgetsCache: getWidgetsCache9() ?? {}
5489
- });
5490
- let generatedXML = "";
5491
- const errors = [];
5492
- const rootContainers = [];
5493
- const documentContainer = getContainer5("document");
5494
- const currentDocument = getCurrentDocument();
5495
- const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
5496
- try {
5497
- const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
5498
- createElement: createElement13,
5499
- deleteElement: deleteElement2,
5500
- getWidgetsCache: getWidgetsCache9
5501
- });
5502
- compositionBuilder.setElementConfig(elementConfig);
5503
- compositionBuilder.setStylesConfig(stylesConfig);
5504
- compositionBuilder.setCustomCSS(customCSS);
5505
- const { configErrors, rootContainers: generatedRootContainers } = await compositionBuilder.build(targetContainer);
5506
- rootContainers.push(...generatedRootContainers);
5507
- generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
5508
- rootContainers.forEach((container) => {
5509
- const elementData = container.model?.toJSON();
5510
- if (elementData) {
5511
- onElementAdded(elementData);
5512
- }
5513
- });
5514
- Object.values(stylesConfig).forEach((styleValue) => {
5515
- dispatchMcpStylesAppliedEvent({ styleValue });
5516
- });
5517
- if (configErrors.length) {
5518
- errors.push(...configErrors.map((msg) => new Error(msg)));
5519
- }
5520
- } catch (error) {
5521
- errors.push(error);
5522
- }
5523
- if (errors.length) {
5524
- rootContainers.forEach((rootContainer) => {
5525
- deleteElement2({
5526
- container: rootContainer,
5527
- options: { useHistory: false }
5528
- });
5529
- });
5530
- const errorMessages = errors.map((e) => {
5531
- if (typeof e === "string") {
5532
- return e;
5533
- }
5534
- if (e instanceof Error) {
5535
- return e.message || String(e);
5536
- }
5537
- if (typeof e === "object" && e !== null) {
5538
- return JSON.stringify(e);
5539
- }
5540
- return String(e);
5541
- }).filter(
5542
- (msg) => msg && msg.trim() !== "" && msg !== "{}" && msg !== "null" && msg !== "undefined"
5543
- );
5544
- if (errorMessages.length === 0) {
5545
- throw new Error(
5546
- "Failed to build composition: Unknown error occurred. No error details available."
5547
- );
5548
- }
5549
- const errorText = `Failed to build composition with the following errors:
5550
-
5551
- ${errorMessages.join(
5552
- "\n\n"
5553
- )}`;
5554
- throw new Error(errorText);
5555
- }
5556
- return {
5557
- xmlStructure: generatedXML,
5558
- errors: errors?.length ? errors.map((e) => typeof e === "string" ? e : e.message).join("\n\n") : void 0,
5559
- llm_instructions: `The composition was built successfully with element IDs embedded in the XML.
5560
-
5561
- **CRITICAL NEXT STEPS** (Follow in order):
5562
- 1. **Apply Global Classes**: Use "apply-global-class" tool to apply the global classes you created BEFORE building this composition
5563
- - Check the created element IDs in the returned XML
5564
- - Apply semantic classes (heading-primary, button-cta, etc.) to appropriate elements
5565
-
5566
- 2. **Fine-tune if needed**: Use "configure-element" tool only for element-specific adjustments that don't warrant global classes
5567
-
5568
- Remember: Global classes ensure design consistency and reusability. Don't skip applying them!
5569
- `
5570
- };
5571
- }
5572
- });
5573
- };
5574
- async function convertCompositionStyles(style) {
5575
- const stylesConfig = {};
5576
- const customCSS = {};
5577
- if (!style || Object.keys(style).length === 0) {
5578
- return { stylesConfig, customCSS };
5579
- }
5580
- const results = await convertStyleBlocksToAtomic(style);
5581
- for (const [configId, { props, customCss }] of Object.entries(results)) {
5582
- stylesConfig[configId] = props;
5583
- if (customCss) {
5584
- customCSS[configId] = customCss;
5585
- }
5586
- }
5587
- return { stylesConfig, customCSS };
5588
- }
5589
- function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
5590
- const doc = new DOMParser().parseFromString(xmlStructure, "application/xml");
5591
- if (doc.querySelector("parsererror")) {
5592
- throw new Error("Failed to parse XML string: " + doc);
5593
- }
5594
- const widgetsCache = getWidgetsCache9() ?? {};
5595
- for (const node of doc.querySelectorAll("*")) {
5596
- const type = node.tagName;
5597
- const widgetData = widgetsCache[type];
5598
- if (!widgetData) {
5599
- continue;
5600
- }
5601
- if (widgetData.elType !== "widget") {
5602
- continue;
5603
- }
5604
- if (!isWidgetAvailableForLLM(widgetData) || !widgetData.atomic_props_schema) {
5605
- throw new Error(`This tool does not support element type: ${type}`);
5606
- }
5607
- }
5608
- }
5609
- function onElementAdded(element) {
5610
- const elType = element.elType ?? "";
5611
- const widgetType = element.widgetType ?? "";
5612
- const elementName = elType === "widget" ? widgetType : elType;
5613
- trackCanvasEvent({
5614
- eventName: "add_element",
5615
- executed_by: "mcp_tool",
5616
- element_name: elementName,
5617
- element_type: elType,
5618
- widget_type: widgetType
5619
- });
5620
- const event = {
5621
- element,
5622
- executedBy: "mcp_tool"
5623
- };
5624
- window.dispatchEvent(new CustomEvent(ELEMENT_ADDED_EVENT, { detail: event }));
5625
- if (element.elements?.length) {
5626
- element.elements?.forEach((childElement) => {
5627
- onElementAdded(childElement);
5628
- });
5629
- }
5630
- }
5631
-
5632
- // src/mcp/tools/configure-element/tool.ts
5633
- import { getContainer as getContainer6, getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
5634
- import { dispatchMcpStylesAppliedEvent as dispatchMcpStylesAppliedEvent2 } from "@elementor/editor-mcp";
5635
- import { Schema as Schema4 } from "@elementor/editor-props";
5636
-
5637
4822
  // src/mcp/tools/configure-element/prompt.ts
5638
- import { toolPrompts as toolPrompts2 } from "@elementor/editor-mcp";
4823
+ import { toolPrompts } from "@elementor/editor-mcp";
5639
4824
  var CONFIGURE_ELEMENT_GUIDE_URI = "elementor://canvas/tools/configure-element-guide";
5640
- var generatePrompt2 = () => {
5641
- const configureElementToolPrompt = toolPrompts2("configure-element");
4825
+ var generatePrompt = () => {
4826
+ const configureElementToolPrompt = toolPrompts("configure-element");
5642
4827
  configureElementToolPrompt.description(`
5643
4828
  Configure an existing element on the page.
5644
4829
 
@@ -5746,11 +4931,11 @@ NO Advanced tab. Never mention Advanced tab.
5746
4931
  `);
5747
4932
  return configureElementToolPrompt.prompt();
5748
4933
  };
5749
- var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
4934
+ var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
5750
4935
 
5751
4936
  // src/mcp/tools/configure-element/schema.ts
5752
4937
  import { z as z2 } from "@elementor/schema";
5753
- var inputSchema2 = {
4938
+ var inputSchema = {
5754
4939
  propertiesToChange: z2.record(
5755
4940
  z2.string().describe("The property name."),
5756
4941
  z2.any().describe(`PropValue, refer to [${WIDGET_SCHEMA_URI}] by correct type, as appears in elementType`),
@@ -5767,7 +4952,7 @@ var inputSchema2 = {
5767
4952
  elementType: z2.string().describe("The type of the element to retrieve the schema"),
5768
4953
  elementId: z2.string().describe("The unique id of the element to configure")
5769
4954
  };
5770
- var outputSchema2 = {
4955
+ var outputSchema = {
5771
4956
  success: z2.boolean().describe(
5772
4957
  "Whether the configuration change was successful, only if propertyName and propertyValue are provided"
5773
4958
  )
@@ -5785,27 +4970,27 @@ var initConfigureElementTool = (reg) => {
5785
4970
  mimeType: "text/plain"
5786
4971
  },
5787
4972
  async (uri) => ({
5788
- contents: [{ uri: uri.href, mimeType: "text/plain", text: generatePrompt2() }]
4973
+ contents: [{ uri: uri.href, mimeType: "text/plain", text: generatePrompt() }]
5789
4974
  })
5790
4975
  );
5791
4976
  addTool({
5792
4977
  name: "configure-element",
5793
4978
  description: "Configure an existing V4 element's properties and styles. Read the guide resource before use.",
5794
- schema: inputSchema2,
5795
- outputSchema: outputSchema2,
4979
+ schema: inputSchema,
4980
+ outputSchema,
5796
4981
  requiredResources: [
5797
4982
  { description: "Widgets schema", uri: WIDGET_SCHEMA_URI },
5798
4983
  { description: "Configure element guide", uri: CONFIGURE_ELEMENT_GUIDE_URI },
5799
4984
  { description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
5800
4985
  ],
5801
4986
  handler: async ({ elementId, propertiesToChange, elementType, style }) => {
5802
- const widgetData = getWidgetsCache10()?.[elementType];
4987
+ const widgetData = getWidgetsCache6()?.[elementType];
5803
4988
  if (!widgetData) {
5804
4989
  throw new Error(
5805
4990
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5806
4991
  );
5807
4992
  }
5808
- const container = getContainer6(elementId);
4993
+ const container = getContainer5(elementId);
5809
4994
  if (!container) {
5810
4995
  throw new Error(`Element with id ${elementId} not found`);
5811
4996
  }
@@ -5821,7 +5006,7 @@ var initConfigureElementTool = (reg) => {
5821
5006
  const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5822
5007
  const toUpdate = Object.entries(propertiesToUpdate);
5823
5008
  for (const [propertyName, propertyValue] of toUpdate) {
5824
- if (!Schema4.isPropKeyConfigurable(propertyName)) {
5009
+ if (!Schema2.isPropKeyConfigurable(propertyName)) {
5825
5010
  throw new Error(`Not allowed to update ${propertyName}`);
5826
5011
  }
5827
5012
  try {
@@ -5870,7 +5055,7 @@ async function applyStyleFromCss(opts) {
5870
5055
  propertyValue: styleValue,
5871
5056
  customCssWriteMode: "merge-with-stored"
5872
5057
  });
5873
- dispatchMcpStylesAppliedEvent2({ styleValue });
5058
+ dispatchMcpStylesAppliedEvent({ styleValue });
5874
5059
  } catch (error) {
5875
5060
  throw new Error(
5876
5061
  createUpdateErrorMessage({
@@ -5897,13 +5082,13 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5897
5082
  }
5898
5083
 
5899
5084
  // src/mcp/tools/get-element-config/tool.ts
5900
- import { getContainer as getContainer7, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache11 } from "@elementor/editor-elements";
5901
- import { Schema as Schema5 } from "@elementor/editor-props";
5085
+ import { getContainer as getContainer6, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
5086
+ import { Schema as Schema3 } from "@elementor/editor-props";
5902
5087
  import { z as z3 } from "@elementor/schema";
5903
5088
  var schema = {
5904
5089
  elementId: z3.string()
5905
5090
  };
5906
- var outputSchema3 = {
5091
+ var outputSchema2 = {
5907
5092
  properties: z3.record(z3.string(), z3.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
5908
5093
  style: z3.record(z3.string(), z3.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
5909
5094
  childElements: z3.array(
@@ -5930,14 +5115,14 @@ var initGetElementConfigTool = (reg) => {
5930
5115
  name: "get-element-configuration-values",
5931
5116
  description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
5932
5117
  schema,
5933
- outputSchema: outputSchema3,
5118
+ outputSchema: outputSchema2,
5934
5119
  handler: async ({ elementId }) => {
5935
- const element = getContainer7(elementId);
5120
+ const element = getContainer6(elementId);
5936
5121
  if (!element) {
5937
5122
  throw new Error(`Element with ID ${elementId} not found.`);
5938
5123
  }
5939
5124
  const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5940
- const widgetData = getWidgetsCache11()?.[elementType];
5125
+ const widgetData = getWidgetsCache7()?.[elementType];
5941
5126
  if (!widgetData) {
5942
5127
  throw new Error(
5943
5128
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
@@ -5949,13 +5134,13 @@ var initGetElementConfigTool = (reg) => {
5949
5134
  );
5950
5135
  }
5951
5136
  const elementRawSettings = element.settings;
5952
- const propSchema = getWidgetsCache11()?.[elementType]?.atomic_props_schema;
5137
+ const propSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
5953
5138
  if (!elementRawSettings || !propSchema) {
5954
5139
  throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5955
5140
  }
5956
5141
  const propValues = {};
5957
5142
  const stylePropValues = {};
5958
- Schema5.configurableKeys(propSchema).forEach((key) => {
5143
+ Schema3.configurableKeys(propSchema).forEach((key) => {
5959
5144
  propValues[key] = structuredClone(elementRawSettings.get(key));
5960
5145
  });
5961
5146
  const elementStyles = getElementStyles2(elementId) || {};
@@ -5991,7 +5176,7 @@ var initGetElementConfigTool = (reg) => {
5991
5176
 
5992
5177
  // src/mcp/canvas-mcp.ts
5993
5178
  var initCanvasMcp = (reg) => {
5994
- Schema6.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5179
+ Schema4.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5995
5180
  initWidgetsSchemaResource(reg);
5996
5181
  initAvailableWidgetsResource(reg);
5997
5182
  initDocumentStructureResource(reg);
@@ -5999,9 +5184,10 @@ var initCanvasMcp = (reg) => {
5999
5184
  initSelectedElementResource(reg);
6000
5185
  initEditorStateResource(reg);
6001
5186
  initGeneralContextResource(reg);
6002
- initBuildCompositionsTool(reg);
5187
+ initBestPracticesResource(reg);
6003
5188
  initGetElementConfigTool(reg);
6004
5189
  initConfigureElementTool(reg);
5190
+ initBuildCompositionTool(reg);
6005
5191
  initBreakpointsResource(reg);
6006
5192
  };
6007
5193
 
@@ -6201,7 +5387,7 @@ function shouldBlock(sourceElements, targetElements) {
6201
5387
  }
6202
5388
 
6203
5389
  // src/style-commands/paste-style.ts
6204
- import { getContainer as getContainer8, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
5390
+ import { getContainer as getContainer7, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
6205
5391
  import { classesPropTypeUtil } from "@elementor/editor-props";
6206
5392
  import {
6207
5393
  __privateListenTo as listenTo5,
@@ -6210,7 +5396,7 @@ import {
6210
5396
  } from "@elementor/editor-v1-adapters";
6211
5397
 
6212
5398
  // src/utils/command-utils.ts
6213
- import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache12 } from "@elementor/editor-elements";
5399
+ import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache8 } from "@elementor/editor-elements";
6214
5400
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
6215
5401
  import { __ as __5 } from "@wordpress/i18n";
6216
5402
  function hasAtomicWidgets(args) {
@@ -6235,7 +5421,7 @@ function getClassesProp(container) {
6235
5421
  }
6236
5422
  function getContainerSchema(container) {
6237
5423
  const type = container?.model.get("widgetType") || container?.model.get("elType");
6238
- const widgetsCache = getWidgetsCache12();
5424
+ const widgetsCache = getWidgetsCache8();
6239
5425
  const elementType = widgetsCache?.[type];
6240
5426
  return elementType?.atomic_props_schema ?? null;
6241
5427
  }
@@ -6354,7 +5540,7 @@ function pasteStyles(args, pasteLocalStyle) {
6354
5540
  }
6355
5541
  const clipboardElements = getClipboardElements(storageKey);
6356
5542
  const [clipboardElement] = clipboardElements ?? [];
6357
- const clipboardContainer = getContainer8(clipboardElement.id);
5543
+ const clipboardContainer = getContainer7(clipboardElement.id);
6358
5544
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
6359
5545
  return;
6360
5546
  }
@@ -6631,10 +5817,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
6631
5817
  }
6632
5818
 
6633
5819
  // src/utils/after-render.ts
6634
- import { getContainer as getContainer9 } from "@elementor/editor-elements";
5820
+ import { getContainer as getContainer8 } from "@elementor/editor-elements";
6635
5821
  function doAfterRender(elementIds, callback) {
6636
5822
  const pending = elementIds.map((elementId) => {
6637
- const view = getContainer9(elementId)?.view;
5823
+ const view = getContainer8(elementId)?.view;
6638
5824
  if (!view || !hasDoAfterRender(view)) {
6639
5825
  return void 0;
6640
5826
  }
@@ -6649,6 +5835,9 @@ function doAfterRender(elementIds, callback) {
6649
5835
  function hasDoAfterRender(view) {
6650
5836
  return typeof view?._doAfterRender === "function";
6651
5837
  }
5838
+
5839
+ // src/sync/element-added-event.ts
5840
+ var ELEMENT_ADDED_EVENT = "elementor/canvas/element-added";
6652
5841
  export {
6653
5842
  BREAKPOINTS_SCHEMA_FULL_URI,
6654
5843
  BREAKPOINTS_SCHEMA_URI,