@elementor/editor-canvas 4.1.0-beta1 → 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.d.mts CHANGED
@@ -319,8 +319,8 @@ type ImportedGlobalStylesPayload = {
319
319
  data: StyleVariables;
320
320
  };
321
321
  global_classes?: {
322
- items: StyleDefinitionsMap;
323
- order: StyleDefinitionID[];
322
+ added_items: StyleDefinitionsMap;
323
+ added_items_order: StyleDefinitionID[];
324
324
  };
325
325
  };
326
326
 
package/dist/index.d.ts CHANGED
@@ -319,8 +319,8 @@ type ImportedGlobalStylesPayload = {
319
319
  data: StyleVariables;
320
320
  };
321
321
  global_classes?: {
322
- items: StyleDefinitionsMap;
323
- order: StyleDefinitionID[];
322
+ added_items: StyleDefinitionsMap;
323
+ added_items_order: StyleDefinitionID[];
324
324
  };
325
325
  };
326
326
 
package/dist/index.js CHANGED
@@ -3987,6 +3987,15 @@ var doUpdateElementProperty = (params) => {
3987
3987
  }
3988
3988
  const propKey = elementPropSchema[propertyName].key;
3989
3989
  const value = resolvePropValue(propertyValue, propKey);
3990
+ const { valid, jsonSchema } = import_editor_props6.Schema.validatePropValue(elementPropSchema[propertyName], propertyValue);
3991
+ if (!valid) {
3992
+ throw new Error(
3993
+ `Invalid PropValue for elementId: ${elementId}. PropKey: ${propKey}, PropValue: ${JSON.stringify(
3994
+ propertyValue
3995
+ )}
3996
+ Expected Schema: ${jsonSchema}`
3997
+ );
3998
+ }
3990
3999
  (0, import_editor_elements11.updateElementSettings)({
3991
4000
  id: elementId,
3992
4001
  props: {
@@ -4566,24 +4575,32 @@ var initBuildCompositionsTool = (reg) => {
4566
4575
  compositionBuilder.setElementConfig(elementConfig);
4567
4576
  compositionBuilder.setStylesConfig(stylesConfig);
4568
4577
  compositionBuilder.setCustomCSS(customCSS);
4569
- const { invalidStyles, rootContainers: generatedRootContainers } = await compositionBuilder.build(targetContainer);
4578
+ const {
4579
+ invalidStyles,
4580
+ configErrors,
4581
+ rootContainers: generatedRootContainers
4582
+ } = await compositionBuilder.build(targetContainer);
4570
4583
  rootContainers.push(...generatedRootContainers);
4571
4584
  generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
4572
- Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
4573
- const customCss = {
4574
- value: rawCssRules.join(";\n")
4575
- };
4576
- doUpdateElementProperty({
4577
- elementId,
4578
- propertyName: "_styles",
4579
- propertyValue: {
4580
- _styles: {
4581
- custom_css: customCss
4582
- }
4583
- },
4584
- elementType: "widget"
4585
+ if (configErrors.length) {
4586
+ errors.push(...configErrors.map((msg) => new Error(msg)));
4587
+ } else {
4588
+ Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
4589
+ const customCss = {
4590
+ value: rawCssRules.join(";\n")
4591
+ };
4592
+ doUpdateElementProperty({
4593
+ elementId,
4594
+ propertyName: "_styles",
4595
+ propertyValue: {
4596
+ _styles: {
4597
+ custom_css: customCss
4598
+ }
4599
+ },
4600
+ elementType: "widget"
4601
+ });
4585
4602
  });
4586
- });
4603
+ }
4587
4604
  } catch (error) {
4588
4605
  errors.push(error);
4589
4606
  }
@@ -4772,6 +4789,13 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
4772
4789
  configureElementToolPrompt.instruction(
4773
4790
  "The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects."
4774
4791
  );
4792
+ configureElementToolPrompt.instruction(`
4793
+ V4 only: If MCP fails, give manual steps using V4 UI.
4794
+
4795
+ V4 Editor structure:
4796
+ Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
4797
+ NO Advanced tab. Never mention Advanced tab.
4798
+ `);
4775
4799
  return configureElementToolPrompt.prompt();
4776
4800
  };
4777
4801
  var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
package/dist/index.mjs CHANGED
@@ -3982,6 +3982,15 @@ var doUpdateElementProperty = (params) => {
3982
3982
  }
3983
3983
  const propKey = elementPropSchema[propertyName].key;
3984
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
+ }
3985
3994
  updateElementSettings({
3986
3995
  id: elementId,
3987
3996
  props: {
@@ -4561,24 +4570,32 @@ var initBuildCompositionsTool = (reg) => {
4561
4570
  compositionBuilder.setElementConfig(elementConfig);
4562
4571
  compositionBuilder.setStylesConfig(stylesConfig);
4563
4572
  compositionBuilder.setCustomCSS(customCSS);
4564
- const { invalidStyles, rootContainers: generatedRootContainers } = await compositionBuilder.build(targetContainer);
4573
+ const {
4574
+ invalidStyles,
4575
+ configErrors,
4576
+ rootContainers: generatedRootContainers
4577
+ } = await compositionBuilder.build(targetContainer);
4565
4578
  rootContainers.push(...generatedRootContainers);
4566
4579
  generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
4567
- Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
4568
- const customCss = {
4569
- value: rawCssRules.join(";\n")
4570
- };
4571
- doUpdateElementProperty({
4572
- elementId,
4573
- propertyName: "_styles",
4574
- propertyValue: {
4575
- _styles: {
4576
- custom_css: customCss
4577
- }
4578
- },
4579
- 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
+ });
4580
4597
  });
4581
- });
4598
+ }
4582
4599
  } catch (error) {
4583
4600
  errors.push(error);
4584
4601
  }
@@ -4767,6 +4784,13 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
4767
4784
  configureElementToolPrompt.instruction(
4768
4785
  "The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects."
4769
4786
  );
4787
+ configureElementToolPrompt.instruction(`
4788
+ V4 only: If MCP fails, give manual steps using V4 UI.
4789
+
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
+ `);
4770
4794
  return configureElementToolPrompt.prompt();
4771
4795
  };
4772
4796
  var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
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-beta1",
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-beta1",
40
+ "@elementor/editor": "4.1.0-beta2",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.1.0-beta1",
43
- "@elementor/editor-documents": "4.1.0-beta1",
44
- "@elementor/editor-elements": "4.1.0-beta1",
45
- "@elementor/editor-interactions": "4.1.0-beta1",
46
- "@elementor/editor-mcp": "4.1.0-beta1",
47
- "@elementor/editor-notifications": "4.1.0-beta1",
48
- "@elementor/editor-props": "4.1.0-beta1",
49
- "@elementor/editor-responsive": "4.1.0-beta1",
50
- "@elementor/editor-styles": "4.1.0-beta1",
51
- "@elementor/editor-styles-repository": "4.1.0-beta1",
52
- "@elementor/editor-ui": "4.1.0-beta1",
53
- "@elementor/editor-v1-adapters": "4.1.0-beta1",
54
- "@elementor/schema": "4.1.0-beta1",
55
- "@elementor/twing": "4.1.0-beta1",
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-beta1",
58
- "@elementor/wp-media": "4.1.0-beta1",
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
  },
@@ -68,27 +68,34 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
68
68
  compositionBuilder.setStylesConfig( stylesConfig );
69
69
  compositionBuilder.setCustomCSS( customCSS );
70
70
 
71
- const { invalidStyles, rootContainers: generatedRootContainers } =
72
- await compositionBuilder.build( targetContainer );
71
+ const {
72
+ invalidStyles,
73
+ configErrors,
74
+ rootContainers: generatedRootContainers,
75
+ } = await compositionBuilder.build( targetContainer );
73
76
 
74
77
  rootContainers.push( ...generatedRootContainers );
75
78
  generatedXML = new XMLSerializer().serializeToString( compositionBuilder.getXML() );
76
79
 
77
- Object.entries( invalidStyles ).forEach( ( [ elementId, rawCssRules ] ) => {
78
- const customCss = {
79
- value: rawCssRules.join( ';\n' ),
80
- };
81
- doUpdateElementProperty( {
82
- elementId,
83
- propertyName: '_styles',
84
- propertyValue: {
85
- _styles: {
86
- 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
+ },
87
94
  },
88
- },
89
- elementType: 'widget',
95
+ elementType: 'widget',
96
+ } );
90
97
  } );
91
- } );
98
+ }
92
99
  } catch ( error ) {
93
100
  errors.push( error as Error );
94
101
  }
@@ -117,6 +117,14 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
117
117
  'The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects.'
118
118
  );
119
119
 
120
+ configureElementToolPrompt.instruction( `
121
+ V4 only: If MCP fails, give manual steps using V4 UI.
122
+
123
+ V4 Editor structure:
124
+ Panel tabs: General (→ Settings section: ID, Tag, Link), Style, Interactions.
125
+ NO Advanced tab. Never mention Advanced tab.
126
+ ` );
127
+
120
128
  return configureElementToolPrompt.prompt();
121
129
  };
122
130
 
@@ -0,0 +1,135 @@
1
+ import { getWidgetsCache, updateElementSettings } from '@elementor/editor-elements';
2
+ import { Schema } from '@elementor/editor-props';
3
+ import { __privateRunCommandSync } from '@elementor/editor-v1-adapters';
4
+
5
+ import { doUpdateElementProperty } from '../do-update-element-property';
6
+
7
+ jest.mock( '@elementor/editor-elements', () => ( {
8
+ createElementStyle: jest.fn(),
9
+ getElementStyles: jest.fn(),
10
+ getWidgetsCache: jest.fn(),
11
+ updateElementSettings: jest.fn(),
12
+ updateElementStyle: jest.fn(),
13
+ } ) );
14
+
15
+ jest.mock( '@elementor/editor-props', () => ( {
16
+ getPropSchemaFromCache: jest.fn(),
17
+ Schema: {
18
+ adjustLlmPropValueSchema: jest.fn( ( value: unknown ) => value ),
19
+ validatePropValue: jest.fn(),
20
+ },
21
+ } ) );
22
+
23
+ jest.mock( '@elementor/editor-styles', () => ( {
24
+ getStylesSchema: jest.fn( () => ( {} ) ),
25
+ } ) );
26
+
27
+ jest.mock( '@elementor/editor-v1-adapters', () => ( {
28
+ __privateRunCommandSync: jest.fn(),
29
+ } ) );
30
+
31
+ const ELEMENT_ID = 'test-element-id';
32
+ const ELEMENT_TYPE = 'atomic-heading';
33
+ const EXPECTED_JSON_SCHEMA_SNIPPET = '{"type":"object"}';
34
+ const PROPERTY_NAME = 'title';
35
+ const PROP_SCHEMA_ENTRY = { key: 'titlePropKey' };
36
+
37
+ const widgetsCacheFixture = {
38
+ [ ELEMENT_TYPE ]: {
39
+ atomic_props_schema: {
40
+ [ PROPERTY_NAME ]: PROP_SCHEMA_ENTRY,
41
+ },
42
+ },
43
+ };
44
+
45
+ describe( 'doUpdateElementProperty', () => {
46
+ beforeEach( () => {
47
+ Object.assign( window, {
48
+ elementorV2: {
49
+ editorVariables: {
50
+ Utils: {
51
+ globalVariablesLLMResolvers: [],
52
+ },
53
+ },
54
+ },
55
+ } );
56
+ // @ts-ignore: Mock values for test
57
+ jest.mocked( getWidgetsCache ).mockReturnValue( widgetsCacheFixture );
58
+ // @ts-ignore: Mock values for test
59
+ jest.mocked( Schema.adjustLlmPropValueSchema ).mockImplementation( ( value: unknown ) => value );
60
+ jest.mocked( Schema.validatePropValue ).mockReset();
61
+ } );
62
+
63
+ afterEach( () => {
64
+ jest.clearAllMocks();
65
+ } );
66
+
67
+ it( 'throws when Schema.validatePropValue reports invalid PropValue and does not persist', () => {
68
+ // Arrange
69
+ const propertyValue = { invalid: true };
70
+ jest.mocked( Schema.validatePropValue ).mockReturnValue( {
71
+ jsonSchema: EXPECTED_JSON_SCHEMA_SNIPPET,
72
+ valid: false,
73
+ errorMessages: 'error',
74
+ errors: [],
75
+ } );
76
+
77
+ // Act
78
+ let thrown: unknown;
79
+ try {
80
+ doUpdateElementProperty( {
81
+ elementId: ELEMENT_ID,
82
+ elementType: ELEMENT_TYPE,
83
+ propertyName: PROPERTY_NAME,
84
+ propertyValue,
85
+ } );
86
+ } catch ( error ) {
87
+ thrown = error;
88
+ }
89
+
90
+ // Assert
91
+ expect( thrown ).toBeInstanceOf( Error );
92
+ expect( ( thrown as Error ).message ).toMatch( /Invalid PropValue/ );
93
+ expect( ( thrown as Error ).message ).toContain( ELEMENT_ID );
94
+ expect( ( thrown as Error ).message ).toContain( PROP_SCHEMA_ENTRY.key );
95
+ expect( ( thrown as Error ).message ).toContain( EXPECTED_JSON_SCHEMA_SNIPPET );
96
+ expect( Schema.validatePropValue ).toHaveBeenCalledWith( PROP_SCHEMA_ENTRY, propertyValue );
97
+ expect( updateElementSettings ).not.toHaveBeenCalled();
98
+ expect( __privateRunCommandSync ).not.toHaveBeenCalled();
99
+ } );
100
+
101
+ it( 'updates settings when Schema.validatePropValue reports valid PropValue', () => {
102
+ // Arrange
103
+ const propertyValue = 'resolved-title';
104
+ jest.mocked( Schema.validatePropValue ).mockReturnValue( {
105
+ jsonSchema: EXPECTED_JSON_SCHEMA_SNIPPET,
106
+ valid: true,
107
+ errorMessages: [],
108
+ errors: [],
109
+ } );
110
+
111
+ // Act
112
+ doUpdateElementProperty( {
113
+ elementId: ELEMENT_ID,
114
+ elementType: ELEMENT_TYPE,
115
+ propertyName: PROPERTY_NAME,
116
+ propertyValue,
117
+ } );
118
+
119
+ // Assert
120
+ expect( Schema.validatePropValue ).toHaveBeenCalledWith( PROP_SCHEMA_ENTRY, propertyValue );
121
+ expect( updateElementSettings ).toHaveBeenCalledTimes( 1 );
122
+ expect( updateElementSettings ).toHaveBeenCalledWith( {
123
+ id: ELEMENT_ID,
124
+ props: {
125
+ [ PROPERTY_NAME ]: propertyValue,
126
+ },
127
+ withHistory: false,
128
+ } );
129
+ expect( __privateRunCommandSync ).toHaveBeenCalledWith(
130
+ 'document/save/set-is-modified',
131
+ { status: true },
132
+ { internal: true }
133
+ );
134
+ } );
135
+ } );
@@ -129,6 +129,14 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
129
129
  }
130
130
  const propKey = elementPropSchema[ propertyName ].key;
131
131
  const value = resolvePropValue( propertyValue, propKey );
132
+ const { valid, jsonSchema } = Schema.validatePropValue( elementPropSchema[ propertyName ], propertyValue );
133
+ if ( ! valid ) {
134
+ throw new Error(
135
+ `Invalid PropValue for elementId: ${ elementId }. PropKey: ${ propKey }, PropValue: ${ JSON.stringify(
136
+ propertyValue
137
+ ) }\nExpected Schema: ${ jsonSchema }`
138
+ );
139
+ }
132
140
  updateElementSettings( {
133
141
  id: elementId,
134
142
  props: {
@@ -4,5 +4,5 @@ export const GLOBAL_STYLES_IMPORTED_EVENT = 'elementor/global-styles/imported';
4
4
 
5
5
  export type ImportedGlobalStylesPayload = {
6
6
  global_variables?: { data: StyleVariables };
7
- global_classes?: { items: StyleDefinitionsMap; order: StyleDefinitionID[] };
7
+ global_classes?: { added_items: StyleDefinitionsMap; added_items_order: StyleDefinitionID[] };
8
8
  };