@elementor/editor-canvas 4.1.0-838 → 4.1.0-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -64,6 +64,9 @@ function isWidgetAvailableForLLM(config) {
64
64
  if (config.meta?.llm_support === false) {
65
65
  return false;
66
66
  }
67
+ if (config.title === "Component") {
68
+ return false;
69
+ }
67
70
  if (config.atomic_props_schema) {
68
71
  return true;
69
72
  }
@@ -3853,7 +3856,7 @@ function getElementDisplayName(container) {
3853
3856
  import { getCurrentDocument } from "@elementor/editor-documents";
3854
3857
  import {
3855
3858
  createElement as createElement8,
3856
- deleteElement,
3859
+ deleteElement as deleteElement2,
3857
3860
  getContainer as getContainer5,
3858
3861
  getWidgetsCache as getWidgetsCache9
3859
3862
  } from "@elementor/editor-elements";
@@ -3861,6 +3864,7 @@ import {
3861
3864
  // src/composition-builder/composition-builder.ts
3862
3865
  import {
3863
3866
  createElement as createElement7,
3867
+ deleteElement,
3864
3868
  generateElementId as generateElementId2,
3865
3869
  getContainer as getContainer4,
3866
3870
  getWidgetsCache as getWidgetsCache8
@@ -3876,6 +3880,7 @@ import {
3876
3880
  } from "@elementor/editor-elements";
3877
3881
  import { getPropSchemaFromCache, Schema as Schema2 } from "@elementor/editor-props";
3878
3882
  import { getStylesSchema as getStylesSchema3 } from "@elementor/editor-styles";
3883
+ import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
3879
3884
  function resolvePropValue(value, forceKey) {
3880
3885
  const Utils = window.elementorV2.editorVariables.Utils;
3881
3886
  return Schema2.adjustLlmPropValueSchema(value, {
@@ -3977,6 +3982,15 @@ var doUpdateElementProperty = (params) => {
3977
3982
  }
3978
3983
  const propKey = elementPropSchema[propertyName].key;
3979
3984
  const value = resolvePropValue(propertyValue, propKey);
3985
+ const { valid, jsonSchema } = Schema2.validatePropValue(elementPropSchema[propertyName], propertyValue);
3986
+ if (!valid) {
3987
+ throw new Error(
3988
+ `Invalid PropValue for elementId: ${elementId}. PropKey: ${propKey}, PropValue: ${JSON.stringify(
3989
+ propertyValue
3990
+ )}
3991
+ Expected Schema: ${jsonSchema}`
3992
+ );
3993
+ }
3980
3994
  updateElementSettings({
3981
3995
  id: elementId,
3982
3996
  props: {
@@ -3984,6 +3998,7 @@ var doUpdateElementProperty = (params) => {
3984
3998
  },
3985
3999
  withHistory: false
3986
4000
  });
4001
+ runCommandSync2("document/save/set-is-modified", { status: true }, { internal: true });
3987
4002
  };
3988
4003
 
3989
4004
  // src/mcp/utils/validate-input.ts
@@ -4079,6 +4094,7 @@ var CompositionBuilder = class _CompositionBuilder {
4079
4094
  rootContainers = [];
4080
4095
  api = {
4081
4096
  createElement: createElement7,
4097
+ deleteElement,
4082
4098
  getWidgetsCache: getWidgetsCache8,
4083
4099
  generateElementId: generateElementId2,
4084
4100
  getContainer: getContainer4,
@@ -4129,7 +4145,8 @@ var CompositionBuilder = class _CompositionBuilder {
4129
4145
  elements: children,
4130
4146
  editor_settings: {
4131
4147
  title: node.getAttribute("configuration-id") ?? void 0
4132
- }
4148
+ },
4149
+ elType: "widget"
4133
4150
  };
4134
4151
  if (isWidget) {
4135
4152
  return { ...base, elType: "widget", widgetType: elementTag };
@@ -4161,12 +4178,6 @@ var CompositionBuilder = class _CompositionBuilder {
4161
4178
  }
4162
4179
  return errors;
4163
4180
  }
4164
- findSchemaForNode(node) {
4165
- const widgetsCache = this.api.getWidgetsCache() || {};
4166
- const widgetType = node.tagName;
4167
- const widgetData = widgetsCache[widgetType]?.atomic_props_schema;
4168
- return widgetData || null;
4169
- }
4170
4181
  matchNodeByConfigId(configId) {
4171
4182
  const node = this.xml.querySelector(`[configuration-id="${configId}"]`);
4172
4183
  if (!node) {
@@ -4288,13 +4299,24 @@ ${childTypeErrors.join("\n")}`);
4288
4299
  const children = Array.from(this.xml.children);
4289
4300
  for (const childNode of children) {
4290
4301
  const modelTree = this.buildModelTree(childNode, widgetsCache);
4291
- const newElement = this.api.createElement({
4292
- container: rootContainer,
4293
- model: modelTree,
4294
- options: { useHistory: false }
4295
- });
4296
- this.rootContainers.push(newElement);
4297
- await this.awaitViewRender(newElement);
4302
+ try {
4303
+ const newElement = this.api.createElement({
4304
+ container: rootContainer,
4305
+ model: modelTree,
4306
+ options: { useHistory: false }
4307
+ });
4308
+ this.rootContainers.push(newElement);
4309
+ await this.awaitViewRender(newElement);
4310
+ } catch (e) {
4311
+ const attemptToRestoreInvalidContainer = this.api.getContainer(modelTree.id);
4312
+ if (attemptToRestoreInvalidContainer) {
4313
+ this.api.deleteElement({
4314
+ container: attemptToRestoreInvalidContainer,
4315
+ options: { useHistory: false }
4316
+ });
4317
+ }
4318
+ throw e;
4319
+ }
4298
4320
  }
4299
4321
  const { configErrors, styleErrors, invalidStyles } = await this.applyProperties();
4300
4322
  return {
@@ -4318,6 +4340,7 @@ function getCompositionTargetContainer(documentContainer, documentType) {
4318
4340
 
4319
4341
  // src/mcp/tools/build-composition/prompt.ts
4320
4342
  import { toolPrompts } from "@elementor/editor-mcp";
4343
+ var BUILD_COMPOSITIONS_GUIDE_URI = "elementor://canvas/tools/build-compositions-guide";
4321
4344
  var generatePrompt = () => {
4322
4345
  const buildCompositionsToolPrompt = toolPrompts("build-compositions");
4323
4346
  buildCompositionsToolPrompt.description(`
@@ -4499,12 +4522,25 @@ var outputSchema = {
4499
4522
 
4500
4523
  // src/mcp/tools/build-composition/tool.ts
4501
4524
  var initBuildCompositionsTool = (reg) => {
4502
- const { addTool } = reg;
4525
+ const { addTool, resource } = reg;
4526
+ resource(
4527
+ "build-compositions-guide",
4528
+ BUILD_COMPOSITIONS_GUIDE_URI,
4529
+ {
4530
+ title: "Build Compositions Guide",
4531
+ description: "Detailed guide for using the build-compositions tool",
4532
+ mimeType: "text/plain"
4533
+ },
4534
+ async (uri) => ({
4535
+ contents: [{ uri: uri.href, mimeType: "text/plain", text: generatePrompt() }]
4536
+ })
4537
+ );
4503
4538
  addTool({
4504
4539
  name: "build-compositions",
4505
- description: generatePrompt(),
4540
+ description: "Build V4 element compositions on the Elementor canvas. Read the guide resource before use.",
4506
4541
  schema: inputSchema,
4507
4542
  requiredResources: [
4543
+ { description: "Build compositions guide", uri: BUILD_COMPOSITIONS_GUIDE_URI },
4508
4544
  { description: "Widgets schema", uri: WIDGET_SCHEMA_URI },
4509
4545
  { description: "Styles schema", uri: STYLE_SCHEMA_URI },
4510
4546
  { description: "Global Classes", uri: "elementor://global-classes" },
@@ -4528,35 +4564,44 @@ var initBuildCompositionsTool = (reg) => {
4528
4564
  try {
4529
4565
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
4530
4566
  createElement: createElement8,
4567
+ deleteElement: deleteElement2,
4531
4568
  getWidgetsCache: getWidgetsCache9
4532
4569
  });
4533
4570
  compositionBuilder.setElementConfig(elementConfig);
4534
4571
  compositionBuilder.setStylesConfig(stylesConfig);
4535
4572
  compositionBuilder.setCustomCSS(customCSS);
4536
- const { invalidStyles, rootContainers: generatedRootContainers } = await compositionBuilder.build(targetContainer);
4573
+ const {
4574
+ invalidStyles,
4575
+ configErrors,
4576
+ rootContainers: generatedRootContainers
4577
+ } = await compositionBuilder.build(targetContainer);
4537
4578
  rootContainers.push(...generatedRootContainers);
4538
4579
  generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
4539
- Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
4540
- const customCss = {
4541
- value: rawCssRules.join(";\n")
4542
- };
4543
- doUpdateElementProperty({
4544
- elementId,
4545
- propertyName: "_styles",
4546
- propertyValue: {
4547
- _styles: {
4548
- custom_css: customCss
4549
- }
4550
- },
4551
- elementType: "widget"
4580
+ if (configErrors.length) {
4581
+ errors.push(...configErrors.map((msg) => new Error(msg)));
4582
+ } else {
4583
+ Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
4584
+ const customCss = {
4585
+ value: rawCssRules.join(";\n")
4586
+ };
4587
+ doUpdateElementProperty({
4588
+ elementId,
4589
+ propertyName: "_styles",
4590
+ propertyValue: {
4591
+ _styles: {
4592
+ custom_css: customCss
4593
+ }
4594
+ },
4595
+ elementType: "widget"
4596
+ });
4552
4597
  });
4553
- });
4598
+ }
4554
4599
  } catch (error) {
4555
4600
  errors.push(error);
4556
4601
  }
4557
4602
  if (errors.length) {
4558
4603
  rootContainers.forEach((rootContainer) => {
4559
- deleteElement({
4604
+ deleteElement2({
4560
4605
  container: rootContainer,
4561
4606
  options: { useHistory: false }
4562
4607
  });
@@ -4632,7 +4677,12 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
4632
4677
  import { getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
4633
4678
 
4634
4679
  // src/mcp/tools/configure-element/prompt.ts
4635
- var configureElementToolPrompt = `Configure an existing element on the page.
4680
+ import { toolPrompts as toolPrompts2 } from "@elementor/editor-mcp";
4681
+ var CONFIGURE_ELEMENT_GUIDE_URI = "elementor://canvas/tools/configure-element-guide";
4682
+ var generatePrompt2 = () => {
4683
+ const configureElementToolPrompt = toolPrompts2("configure-element");
4684
+ configureElementToolPrompt.description(`
4685
+ Configure an existing element on the page.
4636
4686
 
4637
4687
  # **CRITICAL - REQUIRED INFORMATION (Must read before using this tool)**
4638
4688
  1. [${WIDGET_SCHEMA_URI}]
@@ -4647,12 +4697,6 @@ Before using this tool, check the definitions of the elements PropTypes at the r
4647
4697
  All widgets share a common _style property for styling, which uses the common styles schema.
4648
4698
  Retrieve and check the common styles schema at the resource list "styles-schema" at editor-canvas__elementor://styles/schema/{category}
4649
4699
 
4650
- # Parameters
4651
- - propertiesToChange: An object containing the properties to change, with their new values. MANDATORY. When updating a style only, provide an empty object.
4652
- - stylePropertiesToChange: An object containing the style properties to change, with their new values. OPTIONAL
4653
- - elementId: The ID of the element to configure. MANDATORY
4654
- - elementType: The type of the element to configure (i.e. e-heading, e-button). MANDATORY
4655
-
4656
4700
  # When to use this tool
4657
4701
  When a user requires to change anything in an element, such as updating text, colors, sizes, or other configurable properties.
4658
4702
  This tool handles elements of type "widget".
@@ -4681,7 +4725,7 @@ You can use multiple property changes at once by providing multiple entries in t
4681
4725
  Some properties are nested, use the root property name, then objects with nested values inside, as the complete schema suggests.
4682
4726
 
4683
4727
  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.
4728
+ Make sure you have the "styles-schema" resources available to retrieve the common styles schema.
4685
4729
 
4686
4730
  # How to configure elements
4687
4731
  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.
@@ -4689,8 +4733,21 @@ For styleProperties, use the style schema provided, as it also uses the PropType
4689
4733
  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.
4690
4734
 
4691
4735
  Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property from the original configuration for every property you are changing.
4692
-
4693
- # Example
4736
+ `);
4737
+ configureElementToolPrompt.parameter("elementId", "The ID of the element to configure. MANDATORY.");
4738
+ configureElementToolPrompt.parameter(
4739
+ "elementType",
4740
+ "The type of the element to configure (i.e. e-heading, e-button). MANDATORY."
4741
+ );
4742
+ configureElementToolPrompt.parameter(
4743
+ "propertiesToChange",
4744
+ "An object containing the properties to change, with their new values. MANDATORY. When updating a style only, provide an empty object."
4745
+ );
4746
+ configureElementToolPrompt.parameter(
4747
+ "stylePropertiesToChange",
4748
+ "An object containing the style properties to change, with their new values. OPTIONAL."
4749
+ );
4750
+ configureElementToolPrompt.example(`
4694
4751
  \`\`\`json
4695
4752
  {
4696
4753
  propertiesToChange: {
@@ -4706,7 +4763,7 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
4706
4763
  },
4707
4764
  stylePropertiesToChange: {
4708
4765
  'line-height': {
4709
- $$type: 'size', // MANDATORY do not forget to include the correct $$type for every property
4766
+ $$type: 'size',
4710
4767
  value: {
4711
4768
  size: {
4712
4769
  $$type: 'number',
@@ -4723,11 +4780,20 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
4723
4780
  elementType: 'element-type'
4724
4781
  };
4725
4782
  \`\`\`
4783
+ `);
4784
+ configureElementToolPrompt.instruction(
4785
+ "The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects."
4786
+ );
4787
+ configureElementToolPrompt.instruction(`
4788
+ V4 only: If MCP fails, give manual steps using V4 UI.
4726
4789
 
4727
- <IMPORTANT>
4728
- The $$type property is MANDATORY for every value, it is required to parse the value and apply application-level effects.
4729
- </IMPORTANT>
4730
- `;
4790
+ V4 Editor structure:
4791
+ Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
4792
+ NO Advanced tab. Never mention Advanced tab.
4793
+ `);
4794
+ return configureElementToolPrompt.prompt();
4795
+ };
4796
+ var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
4731
4797
 
4732
4798
  // src/mcp/tools/configure-element/schema.ts
4733
4799
  import { z as z2 } from "@elementor/schema";
@@ -4753,15 +4819,28 @@ var outputSchema2 = {
4753
4819
 
4754
4820
  // src/mcp/tools/configure-element/tool.ts
4755
4821
  var initConfigureElementTool = (reg) => {
4756
- const { addTool } = reg;
4822
+ const { addTool, resource } = reg;
4823
+ resource(
4824
+ "configure-element-guide",
4825
+ CONFIGURE_ELEMENT_GUIDE_URI,
4826
+ {
4827
+ title: "Configure Element Guide",
4828
+ description: "Detailed guide for using the configure-element tool",
4829
+ mimeType: "text/plain"
4830
+ },
4831
+ async (uri) => ({
4832
+ contents: [{ uri: uri.href, mimeType: "text/plain", text: generatePrompt2() }]
4833
+ })
4834
+ );
4757
4835
  addTool({
4758
4836
  name: "configure-element",
4759
- description: configureElementToolPrompt,
4837
+ description: "Configure an existing V4 element's properties and styles. Read the guide resource before use.",
4760
4838
  schema: inputSchema2,
4761
4839
  outputSchema: outputSchema2,
4762
4840
  requiredResources: [
4763
4841
  { description: "Widgets schema", uri: WIDGET_SCHEMA_URI },
4764
- { description: "Styles schema", uri: STYLE_SCHEMA_URI }
4842
+ { description: "Styles schema", uri: STYLE_SCHEMA_URI },
4843
+ { description: "Configure element guide", uri: CONFIGURE_ELEMENT_GUIDE_URI }
4765
4844
  ],
4766
4845
  modelPreferences: {
4767
4846
  hints: [{ name: "claude-sonnet-4-5" }],
@@ -4959,15 +5038,6 @@ var initGetElementConfigTool = (reg) => {
4959
5038
 
4960
5039
  // src/mcp/canvas-mcp.ts
4961
5040
  var initCanvasMcp = (reg) => {
4962
- const { setMCPDescription } = reg;
4963
- setMCPDescription(
4964
- `Everything related to V4 ( Atomic ) canvas.
4965
- # Canvas workflow for new compositions
4966
- - Configure elements settings and styles
4967
- - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
4968
- - Get and retrieve element configuration values
4969
- `
4970
- );
4971
5041
  initWidgetsSchemaResource(reg);
4972
5042
  initAvailableWidgetsResource(reg);
4973
5043
  initDocumentStructureResource(reg);
@@ -5479,7 +5549,13 @@ function init() {
5479
5549
  });
5480
5550
  initCanvasMcp(
5481
5551
  getMCPByDomain("canvas", {
5482
- instructions: mcpDescription
5552
+ instructions: `Everything related to V4 ( Atomic ) canvas.
5553
+ # Canvas workflow for new compositions
5554
+ - Configure elements settings and styles
5555
+ - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
5556
+ - Get and retrieve element configuration values
5557
+ `,
5558
+ docs: mcpDescription
5483
5559
  })
5484
5560
  );
5485
5561
  initTabsModelExtensions();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.1.0-838",
4
+ "version": "4.1.0-beta2",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,25 +37,25 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.1.0-838",
40
+ "@elementor/editor": "4.1.0-beta2",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.1.0-838",
43
- "@elementor/editor-documents": "4.1.0-838",
44
- "@elementor/editor-elements": "4.1.0-838",
45
- "@elementor/editor-interactions": "4.1.0-838",
46
- "@elementor/editor-mcp": "4.1.0-838",
47
- "@elementor/editor-notifications": "4.1.0-838",
48
- "@elementor/editor-props": "4.1.0-838",
49
- "@elementor/editor-responsive": "4.1.0-838",
50
- "@elementor/editor-styles": "4.1.0-838",
51
- "@elementor/editor-styles-repository": "4.1.0-838",
52
- "@elementor/editor-ui": "4.1.0-838",
53
- "@elementor/editor-v1-adapters": "4.1.0-838",
54
- "@elementor/schema": "4.1.0-838",
55
- "@elementor/twing": "4.1.0-838",
42
+ "@elementor/editor-controls": "4.1.0-beta2",
43
+ "@elementor/editor-documents": "4.1.0-beta2",
44
+ "@elementor/editor-elements": "4.1.0-beta2",
45
+ "@elementor/editor-interactions": "4.1.0-beta2",
46
+ "@elementor/editor-mcp": "4.1.0-beta2",
47
+ "@elementor/editor-notifications": "4.1.0-beta2",
48
+ "@elementor/editor-props": "4.1.0-beta2",
49
+ "@elementor/editor-responsive": "4.1.0-beta2",
50
+ "@elementor/editor-styles": "4.1.0-beta2",
51
+ "@elementor/editor-styles-repository": "4.1.0-beta2",
52
+ "@elementor/editor-ui": "4.1.0-beta2",
53
+ "@elementor/editor-v1-adapters": "4.1.0-beta2",
54
+ "@elementor/schema": "4.1.0-beta2",
55
+ "@elementor/twing": "4.1.0-beta2",
56
56
  "@elementor/ui": "1.37.5",
57
- "@elementor/utils": "4.1.0-838",
58
- "@elementor/wp-media": "4.1.0-838",
57
+ "@elementor/utils": "4.1.0-beta2",
58
+ "@elementor/wp-media": "4.1.0-beta2",
59
59
  "@floating-ui/react": "^0.27.5",
60
60
  "@wordpress/i18n": "^5.13.0"
61
61
  },
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  createElement,
3
3
  type CreateElementParams,
4
+ deleteElement,
4
5
  generateElementId,
5
6
  getContainer,
6
7
  getWidgetsCache,
7
8
  type V1Element,
8
9
  type V1ElementConfig,
10
+ type V1ElementModelProps,
9
11
  } from '@elementor/editor-elements';
10
12
  import { type z } from '@elementor/schema';
11
13
 
@@ -17,6 +19,7 @@ type AnyConfig = Record< string, Record< string, AnyValue > >;
17
19
 
18
20
  type API = {
19
21
  createElement: typeof createElement;
22
+ deleteElement: typeof deleteElement;
20
23
  getWidgetsCache: typeof getWidgetsCache;
21
24
  generateElementId: typeof generateElementId;
22
25
  getContainer: typeof getContainer;
@@ -38,6 +41,7 @@ export class CompositionBuilder {
38
41
  private rootContainers: V1Element[] = [];
39
42
  private api: API = {
40
43
  createElement,
44
+ deleteElement,
41
45
  getWidgetsCache,
42
46
  generateElementId,
43
47
  getContainer,
@@ -94,15 +98,26 @@ export class CompositionBuilder {
94
98
 
95
99
  node.setAttribute( 'id', id );
96
100
 
97
- const base = {
101
+ const base: V1ElementModelProps = {
98
102
  id,
99
103
  skipDefaultChildren: true,
100
- elements: children,
104
+ elements: children as V1ElementModelProps[ 'elements' ],
101
105
  editor_settings: {
102
106
  title: node.getAttribute( 'configuration-id' ) ?? undefined,
103
107
  },
108
+ elType: 'widget',
104
109
  };
105
110
 
111
+ // TODO: Restore this code once components are working in compositions
112
+ // if ( elementTag === 'e-component' ) {
113
+ // // apply component id before applying values
114
+ // const elementConfig = this.elementConfig[ String( node.getAttribute( 'configuration-id' ) ) ];
115
+ // if ( elementConfig ) {
116
+ // base.settings = base.settings || {};
117
+ // base.settings.component_instance = elementConfig.component_instance;
118
+ // }
119
+ // }
120
+
106
121
  if ( isWidget ) {
107
122
  return { ...base, elType: 'widget' as const, widgetType: elementTag };
108
123
  }
@@ -142,13 +157,6 @@ export class CompositionBuilder {
142
157
  return errors;
143
158
  }
144
159
 
145
- private findSchemaForNode( node: Element ) {
146
- const widgetsCache = this.api.getWidgetsCache() || {};
147
- const widgetType = node.tagName;
148
- const widgetData = widgetsCache[ widgetType ]?.atomic_props_schema;
149
- return widgetData || null;
150
- }
151
-
152
160
  private matchNodeByConfigId( configId: string ) {
153
161
  const node = this.xml.querySelector( `[configuration-id="${ configId }"]` );
154
162
  if ( ! node ) {
@@ -282,15 +290,24 @@ export class CompositionBuilder {
282
290
  for ( const childNode of children ) {
283
291
  const modelTree = this.buildModelTree( childNode, widgetsCache );
284
292
 
285
- const newElement = this.api.createElement( {
286
- container: rootContainer,
287
- model: modelTree as CreateElementParams[ 'model' ],
288
- options: { useHistory: false },
289
- } );
290
-
291
- this.rootContainers.push( newElement );
292
-
293
- await this.awaitViewRender( newElement );
293
+ try {
294
+ const newElement = this.api.createElement( {
295
+ container: rootContainer,
296
+ model: modelTree as CreateElementParams[ 'model' ],
297
+ options: { useHistory: false },
298
+ } );
299
+ this.rootContainers.push( newElement );
300
+ await this.awaitViewRender( newElement );
301
+ } catch ( e: unknown ) {
302
+ const attemptToRestoreInvalidContainer = this.api.getContainer( modelTree.id as string );
303
+ if ( attemptToRestoreInvalidContainer ) {
304
+ this.api.deleteElement( {
305
+ container: attemptToRestoreInvalidContainer,
306
+ options: { useHistory: false },
307
+ } );
308
+ }
309
+ throw e;
310
+ }
294
311
  }
295
312
 
296
313
  const { configErrors, styleErrors, invalidStyles } = await this.applyProperties();
package/src/init.tsx CHANGED
@@ -53,7 +53,13 @@ export function init() {
53
53
 
54
54
  initCanvasMcp(
55
55
  getMCPByDomain( 'canvas', {
56
- instructions: mcpDescription,
56
+ instructions: `Everything related to V4 ( Atomic ) canvas.
57
+ # Canvas workflow for new compositions
58
+ - Configure elements settings and styles
59
+ - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
60
+ - Get and retrieve element configuration values
61
+ `,
62
+ docs: mcpDescription,
57
63
  } )
58
64
  );
59
65
 
@@ -12,15 +12,6 @@ import { initConfigureElementTool } from './tools/configure-element/tool';
12
12
  import { initGetElementConfigTool } from './tools/get-element-config/tool';
13
13
 
14
14
  export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
15
- const { setMCPDescription } = reg;
16
- setMCPDescription(
17
- `Everything related to V4 ( Atomic ) canvas.
18
- # Canvas workflow for new compositions
19
- - Configure elements settings and styles
20
- - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
21
- - Get and retrieve element configuration values
22
- `
23
- );
24
15
  initWidgetsSchemaResource( reg );
25
16
  initAvailableWidgetsResource( reg );
26
17
  initDocumentStructureResource( reg );
@@ -2,6 +2,8 @@ import { toolPrompts } from '@elementor/editor-mcp';
2
2
 
3
3
  import { AVAILABLE_WIDGETS_URI } from '../../resources/available-widgets-resource';
4
4
 
5
+ export const BUILD_COMPOSITIONS_GUIDE_URI = 'elementor://canvas/tools/build-compositions-guide';
6
+
5
7
  export const generatePrompt = () => {
6
8
  const buildCompositionsToolPrompt = toolPrompts( 'build-compositions' );
7
9
 
@@ -13,17 +13,31 @@ import { AVAILABLE_WIDGETS_URI_V4 } from '../../resources/available-widgets-reso
13
13
  import { BEST_PRACTICES_URI, STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
14
14
  import { doUpdateElementProperty } from '../../utils/do-update-element-property';
15
15
  import { getCompositionTargetContainer } from '../../utils/get-composition-target-container';
16
- import { generatePrompt } from './prompt';
16
+ import { BUILD_COMPOSITIONS_GUIDE_URI, generatePrompt } from './prompt';
17
17
  import { inputSchema as schema, outputSchema } from './schema';
18
18
 
19
19
  export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
20
- const { addTool } = reg;
20
+ const { addTool, resource } = reg;
21
+
22
+ resource(
23
+ 'build-compositions-guide',
24
+ BUILD_COMPOSITIONS_GUIDE_URI,
25
+ {
26
+ title: 'Build Compositions Guide',
27
+ description: 'Detailed guide for using the build-compositions tool',
28
+ mimeType: 'text/plain',
29
+ },
30
+ async ( uri: URL ) => ( {
31
+ contents: [ { uri: uri.href, mimeType: 'text/plain', text: generatePrompt() } ],
32
+ } )
33
+ );
21
34
 
22
35
  addTool( {
23
36
  name: 'build-compositions',
24
- description: generatePrompt(),
37
+ description: 'Build V4 element compositions on the Elementor canvas. Read the guide resource before use.',
25
38
  schema,
26
39
  requiredResources: [
40
+ { description: 'Build compositions guide', uri: BUILD_COMPOSITIONS_GUIDE_URI },
27
41
  { description: 'Widgets schema', uri: WIDGET_SCHEMA_URI },
28
42
  { description: 'Styles schema', uri: STYLE_SCHEMA_URI },
29
43
  { description: 'Global Classes', uri: 'elementor://global-classes' },
@@ -47,33 +61,41 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
47
61
  try {
48
62
  const compositionBuilder = CompositionBuilder.fromXMLString( xmlStructure, {
49
63
  createElement,
64
+ deleteElement,
50
65
  getWidgetsCache,
51
66
  } );
52
67
  compositionBuilder.setElementConfig( elementConfig );
53
68
  compositionBuilder.setStylesConfig( stylesConfig );
54
69
  compositionBuilder.setCustomCSS( customCSS );
55
70
 
56
- const { invalidStyles, rootContainers: generatedRootContainers } =
57
- await compositionBuilder.build( targetContainer );
71
+ const {
72
+ invalidStyles,
73
+ configErrors,
74
+ rootContainers: generatedRootContainers,
75
+ } = await compositionBuilder.build( targetContainer );
58
76
 
59
77
  rootContainers.push( ...generatedRootContainers );
60
78
  generatedXML = new XMLSerializer().serializeToString( compositionBuilder.getXML() );
61
79
 
62
- Object.entries( invalidStyles ).forEach( ( [ elementId, rawCssRules ] ) => {
63
- const customCss = {
64
- value: rawCssRules.join( ';\n' ),
65
- };
66
- doUpdateElementProperty( {
67
- elementId,
68
- propertyName: '_styles',
69
- propertyValue: {
70
- _styles: {
71
- custom_css: customCss,
80
+ if ( configErrors.length ) {
81
+ errors.push( ...configErrors.map( ( msg ) => new Error( msg ) ) );
82
+ } else {
83
+ Object.entries( invalidStyles ).forEach( ( [ elementId, rawCssRules ] ) => {
84
+ const customCss = {
85
+ value: rawCssRules.join( ';\n' ),
86
+ };
87
+ doUpdateElementProperty( {
88
+ elementId,
89
+ propertyName: '_styles',
90
+ propertyValue: {
91
+ _styles: {
92
+ custom_css: customCss,
93
+ },
72
94
  },
73
- },
74
- elementType: 'widget',
95
+ elementType: 'widget',
96
+ } );
75
97
  } );
76
- } );
98
+ }
77
99
  } catch ( error ) {
78
100
  errors.push( error as Error );
79
101
  }