@elementor/editor-canvas 4.3.0-1004 → 4.3.0-1006

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.js CHANGED
@@ -2548,13 +2548,13 @@ function initStyleTransformers() {
2548
2548
  "layout-direction",
2549
2549
  createMultiPropsTransformer(["row", "column"], ({ propKey, key }) => `${key}-${propKey}`)
2550
2550
  ).register("flex", flexTransformer).register(
2551
- "border-width",
2551
+ "border-width-v2",
2552
2552
  createMultiPropsTransformer(
2553
2553
  ["block-start", "block-end", "inline-start", "inline-end"],
2554
2554
  ({ key }) => `border-${key}-width`
2555
2555
  )
2556
2556
  ).register(
2557
- "border-radius",
2557
+ "border-radius-v2",
2558
2558
  createMultiPropsTransformer(
2559
2559
  ["start-start", "start-end", "end-start", "end-end"],
2560
2560
  ({ key }) => `border-${key}-radius`
@@ -4725,6 +4725,20 @@ var LOCAL_STYLE_META = {
4725
4725
  breakpoint: "desktop",
4726
4726
  state: null
4727
4727
  };
4728
+ var UnsupportedPropertyError = class extends Error {
4729
+ elementType;
4730
+ propertyName;
4731
+ constructor(elementType, propertyName, availableProperties) {
4732
+ super(
4733
+ `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${availableProperties.join(
4734
+ ", "
4735
+ )}`
4736
+ );
4737
+ this.name = "UnsupportedPropertyError";
4738
+ this.elementType = elementType;
4739
+ this.propertyName = propertyName;
4740
+ }
4741
+ };
4728
4742
  function resolvePropValue(value, forceKey) {
4729
4743
  const Utils = window.elementorV2.editorVariables.Utils;
4730
4744
  return import_editor_props6.Schema.adjustLlmPropValueSchema(value, {
@@ -4830,12 +4844,7 @@ var doUpdateElementProperty = (params) => {
4830
4844
  throw new Error(`No prop schema found for element type: ${elementType}`);
4831
4845
  }
4832
4846
  if (!elementPropSchema[propertyName]) {
4833
- const propertyNames = Object.keys(elementPropSchema);
4834
- throw new Error(
4835
- `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${propertyNames.join(
4836
- ", "
4837
- )}`
4838
- );
4847
+ throw new UnsupportedPropertyError(elementType, propertyName, Object.keys(elementPropSchema));
4839
4848
  }
4840
4849
  const propKey = elementPropSchema[propertyName].key;
4841
4850
  const value = resolvePropValue(propertyValue, propKey);
@@ -4965,12 +4974,12 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
4965
4974
  V4 only: If MCP fails, give manual steps using V4 UI.
4966
4975
 
4967
4976
  V4 Editor structure:
4968
- Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
4977
+ Panel tabs: General (\u2192 Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
4969
4978
  NO Advanced tab. Never mention Advanced tab.
4979
+ Note: \`link\` is valid only when the element's PropType schema (which you must already have) includes a \`link\` property. Sending \`link\` to a widget whose schema lacks it is skipped and reported in the response \`warnings\` (other changes still apply) and the link is lost.
4970
4980
  `);
4971
4981
  return configureElementToolPrompt.prompt();
4972
4982
  };
4973
- var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
4974
4983
 
4975
4984
  // src/mcp/tools/configure-element/schema.ts
4976
4985
  var import_schema2 = require("@elementor/schema");
@@ -4994,7 +5003,10 @@ var inputSchema = {
4994
5003
  var outputSchema = {
4995
5004
  success: import_schema2.z.boolean().describe(
4996
5005
  "Whether the configuration change was successful, only if propertyName and propertyValue are provided"
4997
- )
5006
+ ),
5007
+ warnings: import_schema2.z.string().describe(
5008
+ 'Non-fatal notices. Present when some props were skipped because they are not in the element schema (e.g. a "link" on a widget with no link prop). Other changes were still applied.'
5009
+ ).optional()
4998
5010
  };
4999
5011
 
5000
5012
  // src/mcp/tools/configure-element/tool.ts
@@ -5044,6 +5056,7 @@ var initConfigureElementTool = (reg) => {
5044
5056
  }
5045
5057
  const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5046
5058
  const toUpdate = Object.entries(propertiesToUpdate);
5059
+ const skippedProps = [];
5047
5060
  for (const [propertyName, propertyValue] of toUpdate) {
5048
5061
  if (!import_editor_props7.Schema.isPropKeyConfigurable(propertyName)) {
5049
5062
  throw new Error(`Not allowed to update ${propertyName}`);
@@ -5056,6 +5069,10 @@ var initConfigureElementTool = (reg) => {
5056
5069
  propertyValue
5057
5070
  });
5058
5071
  } catch (error) {
5072
+ if (error instanceof UnsupportedPropertyError) {
5073
+ skippedProps.push(error.propertyName);
5074
+ continue;
5075
+ }
5059
5076
  const errorMessage = createUpdateErrorMessage({
5060
5077
  propertyName,
5061
5078
  elementId,
@@ -5068,7 +5085,10 @@ var initConfigureElementTool = (reg) => {
5068
5085
  }
5069
5086
  await applyStyleFromCss({ elementId, elementType, style });
5070
5087
  return {
5071
- success: true
5088
+ success: true,
5089
+ warnings: skippedProps.length ? `Skipped unsupported props (not in the "${elementType}" schema; other changes were applied): ${skippedProps.join(
5090
+ ", "
5091
+ )}.` : void 0
5072
5092
  };
5073
5093
  }
5074
5094
  });
package/dist/index.mjs CHANGED
@@ -2500,13 +2500,13 @@ function initStyleTransformers() {
2500
2500
  "layout-direction",
2501
2501
  createMultiPropsTransformer(["row", "column"], ({ propKey, key }) => `${key}-${propKey}`)
2502
2502
  ).register("flex", flexTransformer).register(
2503
- "border-width",
2503
+ "border-width-v2",
2504
2504
  createMultiPropsTransformer(
2505
2505
  ["block-start", "block-end", "inline-start", "inline-end"],
2506
2506
  ({ key }) => `border-${key}-width`
2507
2507
  )
2508
2508
  ).register(
2509
- "border-radius",
2509
+ "border-radius-v2",
2510
2510
  createMultiPropsTransformer(
2511
2511
  ["start-start", "start-end", "end-start", "end-end"],
2512
2512
  ({ key }) => `border-${key}-radius`
@@ -4697,6 +4697,20 @@ var LOCAL_STYLE_META = {
4697
4697
  breakpoint: "desktop",
4698
4698
  state: null
4699
4699
  };
4700
+ var UnsupportedPropertyError = class extends Error {
4701
+ elementType;
4702
+ propertyName;
4703
+ constructor(elementType, propertyName, availableProperties) {
4704
+ super(
4705
+ `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${availableProperties.join(
4706
+ ", "
4707
+ )}`
4708
+ );
4709
+ this.name = "UnsupportedPropertyError";
4710
+ this.elementType = elementType;
4711
+ this.propertyName = propertyName;
4712
+ }
4713
+ };
4700
4714
  function resolvePropValue(value, forceKey) {
4701
4715
  const Utils = window.elementorV2.editorVariables.Utils;
4702
4716
  return Schema.adjustLlmPropValueSchema(value, {
@@ -4802,12 +4816,7 @@ var doUpdateElementProperty = (params) => {
4802
4816
  throw new Error(`No prop schema found for element type: ${elementType}`);
4803
4817
  }
4804
4818
  if (!elementPropSchema[propertyName]) {
4805
- const propertyNames = Object.keys(elementPropSchema);
4806
- throw new Error(
4807
- `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${propertyNames.join(
4808
- ", "
4809
- )}`
4810
- );
4819
+ throw new UnsupportedPropertyError(elementType, propertyName, Object.keys(elementPropSchema));
4811
4820
  }
4812
4821
  const propKey = elementPropSchema[propertyName].key;
4813
4822
  const value = resolvePropValue(propertyValue, propKey);
@@ -4937,12 +4946,12 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
4937
4946
  V4 only: If MCP fails, give manual steps using V4 UI.
4938
4947
 
4939
4948
  V4 Editor structure:
4940
- Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
4949
+ Panel tabs: General (\u2192 Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
4941
4950
  NO Advanced tab. Never mention Advanced tab.
4951
+ Note: \`link\` is valid only when the element's PropType schema (which you must already have) includes a \`link\` property. Sending \`link\` to a widget whose schema lacks it is skipped and reported in the response \`warnings\` (other changes still apply) and the link is lost.
4942
4952
  `);
4943
4953
  return configureElementToolPrompt.prompt();
4944
4954
  };
4945
- var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
4946
4955
 
4947
4956
  // src/mcp/tools/configure-element/schema.ts
4948
4957
  import { z as z2 } from "@elementor/schema";
@@ -4966,7 +4975,10 @@ var inputSchema = {
4966
4975
  var outputSchema = {
4967
4976
  success: z2.boolean().describe(
4968
4977
  "Whether the configuration change was successful, only if propertyName and propertyValue are provided"
4969
- )
4978
+ ),
4979
+ warnings: z2.string().describe(
4980
+ 'Non-fatal notices. Present when some props were skipped because they are not in the element schema (e.g. a "link" on a widget with no link prop). Other changes were still applied.'
4981
+ ).optional()
4970
4982
  };
4971
4983
 
4972
4984
  // src/mcp/tools/configure-element/tool.ts
@@ -5016,6 +5028,7 @@ var initConfigureElementTool = (reg) => {
5016
5028
  }
5017
5029
  const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5018
5030
  const toUpdate = Object.entries(propertiesToUpdate);
5031
+ const skippedProps = [];
5019
5032
  for (const [propertyName, propertyValue] of toUpdate) {
5020
5033
  if (!Schema2.isPropKeyConfigurable(propertyName)) {
5021
5034
  throw new Error(`Not allowed to update ${propertyName}`);
@@ -5028,6 +5041,10 @@ var initConfigureElementTool = (reg) => {
5028
5041
  propertyValue
5029
5042
  });
5030
5043
  } catch (error) {
5044
+ if (error instanceof UnsupportedPropertyError) {
5045
+ skippedProps.push(error.propertyName);
5046
+ continue;
5047
+ }
5031
5048
  const errorMessage = createUpdateErrorMessage({
5032
5049
  propertyName,
5033
5050
  elementId,
@@ -5040,7 +5057,10 @@ var initConfigureElementTool = (reg) => {
5040
5057
  }
5041
5058
  await applyStyleFromCss({ elementId, elementType, style });
5042
5059
  return {
5043
- success: true
5060
+ success: true,
5061
+ warnings: skippedProps.length ? `Skipped unsupported props (not in the "${elementType}" schema; other changes were applied): ${skippedProps.join(
5062
+ ", "
5063
+ )}.` : void 0
5044
5064
  };
5045
5065
  }
5046
5066
  });
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.3.0-1004",
4
+ "version": "4.3.0-1006",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.3.0-1004",
41
- "@elementor/editor-controls": "4.3.0-1004",
42
- "@elementor/editor-documents": "4.3.0-1004",
43
- "@elementor/editor-elements": "4.3.0-1004",
44
- "@elementor/editor-interactions": "4.3.0-1004",
45
- "@elementor/editor-mcp": "4.3.0-1004",
46
- "@elementor/editor-notifications": "4.3.0-1004",
47
- "@elementor/editor-props": "4.3.0-1004",
48
- "@elementor/editor-responsive": "4.3.0-1004",
49
- "@elementor/editor-styles": "4.3.0-1004",
50
- "@elementor/editor-styles-repository": "4.3.0-1004",
51
- "@elementor/editor-ui": "4.3.0-1004",
52
- "@elementor/editor-v1-adapters": "4.3.0-1004",
53
- "@elementor/events": "4.3.0-1004",
54
- "@elementor/http-client": "4.3.0-1004",
55
- "@elementor/schema": "4.3.0-1004",
56
- "@elementor/twing": "4.3.0-1004",
40
+ "@elementor/editor": "4.3.0-1006",
41
+ "@elementor/editor-controls": "4.3.0-1006",
42
+ "@elementor/editor-documents": "4.3.0-1006",
43
+ "@elementor/editor-elements": "4.3.0-1006",
44
+ "@elementor/editor-interactions": "4.3.0-1006",
45
+ "@elementor/editor-mcp": "4.3.0-1006",
46
+ "@elementor/editor-notifications": "4.3.0-1006",
47
+ "@elementor/editor-props": "4.3.0-1006",
48
+ "@elementor/editor-responsive": "4.3.0-1006",
49
+ "@elementor/editor-styles": "4.3.0-1006",
50
+ "@elementor/editor-styles-repository": "4.3.0-1006",
51
+ "@elementor/editor-ui": "4.3.0-1006",
52
+ "@elementor/editor-v1-adapters": "4.3.0-1006",
53
+ "@elementor/events": "4.3.0-1006",
54
+ "@elementor/http-client": "4.3.0-1006",
55
+ "@elementor/schema": "4.3.0-1006",
56
+ "@elementor/twing": "4.3.0-1006",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.3.0-1004",
59
- "@elementor/wp-media": "4.3.0-1004",
58
+ "@elementor/utils": "4.3.0-1006",
59
+ "@elementor/wp-media": "4.3.0-1006",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -80,14 +80,14 @@ export function initStyleTransformers() {
80
80
  )
81
81
  .register( 'flex', flexTransformer )
82
82
  .register(
83
- 'border-width',
83
+ 'border-width-v2',
84
84
  createMultiPropsTransformer(
85
85
  [ 'block-start', 'block-end', 'inline-start', 'inline-end' ],
86
86
  ( { key } ) => `border-${ key }-width`
87
87
  )
88
88
  )
89
89
  .register(
90
- 'border-radius',
90
+ 'border-radius-v2',
91
91
  createMultiPropsTransformer(
92
92
  [ 'start-start', 'start-end', 'end-start', 'end-end' ],
93
93
  ( { key } ) => `border-${ key }-radius`
@@ -0,0 +1,130 @@
1
+ import { getContainer, getWidgetsCache } from '@elementor/editor-elements';
2
+
3
+ import { doUpdateElementProperty, UnsupportedPropertyError } from '../../../utils/do-update-element-property';
4
+ import { initConfigureElementTool } from '../tool';
5
+
6
+ jest.mock( '@elementor/editor-elements', () => ( {
7
+ getContainer: jest.fn(),
8
+ getWidgetsCache: jest.fn(),
9
+ } ) );
10
+
11
+ jest.mock( '@elementor/editor-mcp', () => ( {
12
+ dispatchMcpStylesAppliedEvent: jest.fn(),
13
+ } ) );
14
+
15
+ jest.mock( '@elementor/editor-props', () => ( {
16
+ Schema: { isPropKeyConfigurable: () => true },
17
+ } ) );
18
+
19
+ jest.mock( '../prompt', () => ( {
20
+ CONFIGURE_ELEMENT_GUIDE_URI: 'configure-element-guide-uri',
21
+ generatePrompt: () => '',
22
+ } ) );
23
+
24
+ jest.mock( '../../../resources/widgets-schema-resource', () => ( {
25
+ WIDGET_SCHEMA_URI: 'elementor://widgets/schema/{widgetType}',
26
+ } ) );
27
+
28
+ jest.mock( '../../../resources/dynamic-tags-resource', () => ( {
29
+ DYNAMIC_TAGS_URI: 'elementor://dynamic-tags',
30
+ } ) );
31
+
32
+ jest.mock( '../../../utils/resolve-canonical-prop-name', () => ( {
33
+ resolveCanonicalPropKeys: ( _elementType: string, props: Record< string, unknown > ) => props,
34
+ } ) );
35
+
36
+ jest.mock( '../../../utils/convert-css-to-atomic', () => ( {
37
+ convertCssToAtomic: jest.fn().mockResolvedValue( { props: {}, customCss: '' } ),
38
+ } ) );
39
+
40
+ jest.mock( '../../../utils/do-update-element-property', () => ( {
41
+ ...jest.requireActual( '../../../utils/do-update-element-property' ),
42
+ doUpdateElementProperty: jest.fn(),
43
+ } ) );
44
+
45
+ const ELEMENT_ID = 'el-1';
46
+ const ELEMENT_TYPE = 'e-youtube';
47
+
48
+ type Handler = ( params: {
49
+ elementId: string;
50
+ elementType: string;
51
+ propertiesToChange: Record< string, unknown >;
52
+ style: Record< string, string | null >;
53
+ } ) => Promise< { success: boolean; warnings?: string } >;
54
+
55
+ const getHandler = (): Handler => {
56
+ const addTool = jest.fn();
57
+ initConfigureElementTool( { addTool, resource: jest.fn() } as never );
58
+ return addTool.mock.calls[ 0 ][ 0 ].handler;
59
+ };
60
+
61
+ describe( 'configure-element handler unsupported props', () => {
62
+ beforeEach( () => {
63
+ jest.mocked( getWidgetsCache ).mockReturnValue( {
64
+ [ ELEMENT_TYPE ]: { atomic_props_schema: { title: { key: 'title' } } },
65
+ } as never );
66
+ jest.mocked( getContainer ).mockReturnValue( {
67
+ settings: { get: () => ELEMENT_TYPE },
68
+ } as never );
69
+ jest.mocked( doUpdateElementProperty ).mockReset();
70
+ } );
71
+
72
+ it( 'skips an unsupported prop, reports it in warnings, and still applies supported props', async () => {
73
+ // Arrange
74
+ jest.mocked( doUpdateElementProperty ).mockImplementation( ( { propertyName } ) => {
75
+ if ( 'link' === propertyName ) {
76
+ throw new UnsupportedPropertyError( ELEMENT_TYPE, 'link', [ 'title' ] );
77
+ }
78
+ } );
79
+ const handler = getHandler();
80
+
81
+ // Act
82
+ const result = await handler( {
83
+ elementId: ELEMENT_ID,
84
+ elementType: ELEMENT_TYPE,
85
+ propertiesToChange: { title: { $$type: 'string', value: 'Hi' }, link: { $$type: 'link', value: {} } },
86
+ style: {},
87
+ } );
88
+
89
+ // Assert
90
+ expect( result.success ).toBe( true );
91
+ expect( result.warnings ).toContain( 'link' );
92
+ expect( doUpdateElementProperty ).toHaveBeenCalledTimes( 2 );
93
+ } );
94
+
95
+ it( 'returns no warnings when every prop is supported', async () => {
96
+ // Arrange
97
+ jest.mocked( doUpdateElementProperty ).mockImplementation( () => undefined );
98
+ const handler = getHandler();
99
+
100
+ // Act
101
+ const result = await handler( {
102
+ elementId: ELEMENT_ID,
103
+ elementType: ELEMENT_TYPE,
104
+ propertiesToChange: { title: { $$type: 'string', value: 'Hi' } },
105
+ style: {},
106
+ } );
107
+
108
+ // Assert
109
+ expect( result.success ).toBe( true );
110
+ expect( result.warnings ).toBeUndefined();
111
+ } );
112
+
113
+ it( 'rethrows non-UnsupportedPropertyError failures', async () => {
114
+ // Arrange
115
+ jest.mocked( doUpdateElementProperty ).mockImplementation( () => {
116
+ throw new Error( 'Invalid PropValue' );
117
+ } );
118
+ const handler = getHandler();
119
+
120
+ // Act & Assert
121
+ await expect(
122
+ handler( {
123
+ elementId: ELEMENT_ID,
124
+ elementType: ELEMENT_TYPE,
125
+ propertiesToChange: { title: { $$type: 'string', value: 'Hi' } },
126
+ style: {},
127
+ } )
128
+ ).rejects.toThrow( /Invalid PropValue/ );
129
+ } );
130
+ } );
@@ -117,11 +117,10 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
117
117
  V4 only: If MCP fails, give manual steps using V4 UI.
118
118
 
119
119
  V4 Editor structure:
120
- Panel tabs: General (→ Settings section: ID, Tag, Link), Style, Interactions.
120
+ Panel tabs: General (→ Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
121
121
  NO Advanced tab. Never mention Advanced tab.
122
+ Note: \`link\` is valid only when the element's PropType schema (which you must already have) includes a \`link\` property. Sending \`link\` to a widget whose schema lacks it is skipped and reported in the response \`warnings\` (other changes still apply) and the link is lost.
122
123
  ` );
123
124
 
124
125
  return configureElementToolPrompt.prompt();
125
126
  };
126
-
127
- export const CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
@@ -36,4 +36,10 @@ export const outputSchema = {
36
36
  .describe(
37
37
  'Whether the configuration change was successful, only if propertyName and propertyValue are provided'
38
38
  ),
39
+ warnings: z
40
+ .string()
41
+ .describe(
42
+ 'Non-fatal notices. Present when some props were skipped because they are not in the element schema (e.g. a "link" on a widget with no link prop). Other changes were still applied.'
43
+ )
44
+ .optional(),
39
45
  };
@@ -6,7 +6,7 @@ import { type PropValue, Schema } from '@elementor/editor-props';
6
6
  import { DYNAMIC_TAGS_URI } from '../../resources/dynamic-tags-resource';
7
7
  import { WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
8
8
  import { convertCssToAtomic } from '../../utils/convert-css-to-atomic';
9
- import { doUpdateElementProperty } from '../../utils/do-update-element-property';
9
+ import { doUpdateElementProperty, UnsupportedPropertyError } from '../../utils/do-update-element-property';
10
10
  import { resolveCanonicalPropKeys } from '../../utils/resolve-canonical-prop-name';
11
11
  import { CONFIGURE_ELEMENT_GUIDE_URI, generatePrompt } from './prompt';
12
12
  import { inputSchema as schema, outputSchema } from './schema';
@@ -61,6 +61,7 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
61
61
  }
62
62
  const propertiesToUpdate = resolveCanonicalPropKeys( elementType, propertiesToChange );
63
63
  const toUpdate = Object.entries( propertiesToUpdate );
64
+ const skippedProps: string[] = [];
64
65
  for ( const [ propertyName, propertyValue ] of toUpdate as [ string, PropValue ][] ) {
65
66
  if ( ! Schema.isPropKeyConfigurable( propertyName ) ) {
66
67
  throw new Error( `Not allowed to update ${ propertyName }` );
@@ -73,6 +74,10 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
73
74
  propertyValue,
74
75
  } );
75
76
  } catch ( error ) {
77
+ if ( error instanceof UnsupportedPropertyError ) {
78
+ skippedProps.push( error.propertyName );
79
+ continue;
80
+ }
76
81
  const errorMessage = createUpdateErrorMessage( {
77
82
  propertyName,
78
83
  elementId,
@@ -86,6 +91,11 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
86
91
  await applyStyleFromCss( { elementId, elementType, style } );
87
92
  return {
88
93
  success: true,
94
+ warnings: skippedProps.length
95
+ ? `Skipped unsupported props (not in the "${ elementType }" schema; other changes were applied): ${ skippedProps.join(
96
+ ', '
97
+ ) }.`
98
+ : undefined,
89
99
  };
90
100
  },
91
101
  } );
@@ -8,7 +8,7 @@ import { Schema } from '@elementor/editor-props';
8
8
  import { getStylesSchema, getVariantByMeta } from '@elementor/editor-styles';
9
9
  import { __privateRunCommandSync } from '@elementor/editor-v1-adapters';
10
10
 
11
- import { doUpdateElementProperty } from '../do-update-element-property';
11
+ import { doUpdateElementProperty, UnsupportedPropertyError } from '../do-update-element-property';
12
12
 
13
13
  jest.mock( '@elementor/editor-elements', () => ( {
14
14
  createElementStyle: jest.fn(),
@@ -108,6 +108,32 @@ describe( 'doUpdateElementProperty', () => {
108
108
  expect( __privateRunCommandSync ).not.toHaveBeenCalled();
109
109
  } );
110
110
 
111
+ it( 'throws UnsupportedPropertyError when the property is not in the element schema', () => {
112
+ // Arrange
113
+ const propertyName = 'link';
114
+
115
+ // Act
116
+ let thrown: unknown;
117
+ try {
118
+ doUpdateElementProperty( {
119
+ elementId: ELEMENT_ID,
120
+ elementType: ELEMENT_TYPE,
121
+ propertyName,
122
+ propertyValue: { $$type: 'link', value: {} },
123
+ } );
124
+ } catch ( error ) {
125
+ thrown = error;
126
+ }
127
+
128
+ // Assert
129
+ expect( thrown ).toBeInstanceOf( UnsupportedPropertyError );
130
+ expect( ( thrown as UnsupportedPropertyError ).propertyName ).toBe( propertyName );
131
+ expect( ( thrown as UnsupportedPropertyError ).elementType ).toBe( ELEMENT_TYPE );
132
+ expect( ( thrown as Error ).message ).toContain( 'does not exist on element type' );
133
+ expect( Schema.validatePropValue ).not.toHaveBeenCalled();
134
+ expect( updateElementSettings ).not.toHaveBeenCalled();
135
+ } );
136
+
111
137
  it( 'updates settings when Schema.validatePropValue reports valid PropValue', () => {
112
138
  // Arrange
113
139
  const propertyValue = 'resolved-title';
@@ -21,6 +21,23 @@ const LOCAL_STYLE_META = {
21
21
  breakpoint: 'desktop',
22
22
  state: null,
23
23
  } as const;
24
+
25
+ export class UnsupportedPropertyError extends Error {
26
+ public readonly elementType: string;
27
+ public readonly propertyName: string;
28
+
29
+ constructor( elementType: string, propertyName: string, availableProperties: string[] ) {
30
+ super(
31
+ `Property "${ propertyName }" does not exist on element type "${ elementType }". Available properties are: ${ availableProperties.join(
32
+ ', '
33
+ ) }`
34
+ );
35
+ this.name = 'UnsupportedPropertyError';
36
+ this.elementType = elementType;
37
+ this.propertyName = propertyName;
38
+ }
39
+ }
40
+
24
41
  type CustomCssWriteMode = 'replace' | 'merge-with-stored';
25
42
  type OwnParams = {
26
43
  elementId: string;
@@ -151,12 +168,7 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
151
168
  throw new Error( `No prop schema found for element type: ${ elementType }` );
152
169
  }
153
170
  if ( ! elementPropSchema[ propertyName ] ) {
154
- const propertyNames = Object.keys( elementPropSchema );
155
- throw new Error(
156
- `Property "${ propertyName }" does not exist on element type "${ elementType }". Available properties are: ${ propertyNames.join(
157
- ', '
158
- ) }`
159
- );
171
+ throw new UnsupportedPropertyError( elementType, propertyName, Object.keys( elementPropSchema ) );
160
172
  }
161
173
  const propKey = elementPropSchema[ propertyName ].key;
162
174
  const value = resolvePropValue( propertyValue, propKey );