@elementor/editor-canvas 4.2.0-937 → 4.2.0-939

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
@@ -4198,7 +4198,7 @@ function extractElementData(element) {
4198
4198
  widgetType: model.widgetType || void 0,
4199
4199
  version: resolveElementVersion(element)
4200
4200
  };
4201
- const title = model.title || element.model?.editor_settings?.title;
4201
+ const title = model.title || element.model?.editor_settings?.title || element.model.getTitle?.();
4202
4202
  if (title) {
4203
4203
  result.title = title;
4204
4204
  }
@@ -4626,13 +4626,13 @@ function getElementDisplayName(container) {
4626
4626
 
4627
4627
  // src/mcp/tools/build-composition/tool.ts
4628
4628
  var import_editor_documents3 = require("@elementor/editor-documents");
4629
- var import_editor_elements15 = require("@elementor/editor-elements");
4629
+ var import_editor_elements16 = require("@elementor/editor-elements");
4630
4630
 
4631
4631
  // src/composition-builder/composition-builder.ts
4632
- var import_editor_elements14 = require("@elementor/editor-elements");
4632
+ var import_editor_elements15 = require("@elementor/editor-elements");
4633
4633
 
4634
4634
  // src/mcp/utils/do-update-element-property.ts
4635
- var import_editor_elements13 = require("@elementor/editor-elements");
4635
+ var import_editor_elements14 = require("@elementor/editor-elements");
4636
4636
  var import_editor_props8 = require("@elementor/editor-props");
4637
4637
  var import_editor_styles4 = require("@elementor/editor-styles");
4638
4638
  var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
@@ -4651,6 +4651,58 @@ var readStoredCustomCssText = (raw) => {
4651
4651
  }
4652
4652
  };
4653
4653
 
4654
+ // src/mcp/utils/resolve-canonical-prop-name.ts
4655
+ var import_editor_elements13 = require("@elementor/editor-elements");
4656
+ function buildAliasToCanonicalMap(schema2) {
4657
+ const aliasToCanonical = {};
4658
+ for (const [canonical, propType] of Object.entries(schema2)) {
4659
+ const aliases = propType.meta?.aliases;
4660
+ if (!Array.isArray(aliases)) {
4661
+ continue;
4662
+ }
4663
+ for (const alias of aliases) {
4664
+ if (typeof alias === "string" && alias) {
4665
+ aliasToCanonical[alias] = canonical;
4666
+ }
4667
+ }
4668
+ }
4669
+ return aliasToCanonical;
4670
+ }
4671
+ function resolveCanonicalPropName(elementType, propertyName) {
4672
+ const schema2 = (0, import_editor_elements13.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4673
+ if (!schema2 || schema2[propertyName]) {
4674
+ return propertyName;
4675
+ }
4676
+ return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4677
+ }
4678
+ function resolveCanonicalPropKeys(elementType, props) {
4679
+ const schema2 = (0, import_editor_elements13.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4680
+ if (!schema2) {
4681
+ return { ...props };
4682
+ }
4683
+ const aliasToCanonical = buildAliasToCanonicalMap(schema2);
4684
+ const resolved = {};
4685
+ for (const [key, value] of Object.entries(props)) {
4686
+ if (schema2[key]) {
4687
+ resolved[key] = value;
4688
+ }
4689
+ }
4690
+ for (const [key, value] of Object.entries(props)) {
4691
+ if (schema2[key]) {
4692
+ continue;
4693
+ }
4694
+ const canonical = aliasToCanonical[key];
4695
+ if (!canonical) {
4696
+ resolved[key] = value;
4697
+ continue;
4698
+ }
4699
+ if (!Object.prototype.hasOwnProperty.call(resolved, canonical)) {
4700
+ resolved[canonical] = value;
4701
+ }
4702
+ }
4703
+ return resolved;
4704
+ }
4705
+
4654
4706
  // src/mcp/utils/do-update-element-property.ts
4655
4707
  var LOCAL_STYLE_META = {
4656
4708
  breakpoint: "desktop",
@@ -4667,9 +4719,10 @@ function resolvePropValue(value, forceKey) {
4667
4719
  });
4668
4720
  }
4669
4721
  var doUpdateElementProperty = (params) => {
4670
- const { elementId, propertyName, propertyValue, elementType, customCssWriteMode = "replace" } = params;
4722
+ const { elementId, propertyValue, elementType, customCssWriteMode = "replace" } = params;
4723
+ const propertyName = params.propertyName === "_styles" ? params.propertyName : resolveCanonicalPropName(elementType, params.propertyName);
4671
4724
  if (propertyName === "_styles") {
4672
- const elementStyles = (0, import_editor_elements13.getElementStyles)(elementId) || {};
4725
+ const elementStyles = (0, import_editor_elements14.getElementStyles)(elementId) || {};
4673
4726
  const propertyMapValue = propertyValue;
4674
4727
  const styleSchema = (0, import_editor_styles4.getStylesSchema)();
4675
4728
  const transformedStyleValues = Object.fromEntries(
@@ -4726,7 +4779,7 @@ var doUpdateElementProperty = (params) => {
4726
4779
  });
4727
4780
  delete transformedStyleValues.custom_css;
4728
4781
  if (!localStyle) {
4729
- (0, import_editor_elements13.createElementStyle)({
4782
+ (0, import_editor_elements14.createElementStyle)({
4730
4783
  elementId,
4731
4784
  ...typeof customCss !== "undefined" ? { custom_css: customCss } : {},
4732
4785
  classesProp: "classes",
@@ -4740,7 +4793,7 @@ var doUpdateElementProperty = (params) => {
4740
4793
  }
4741
4794
  });
4742
4795
  } else {
4743
- (0, import_editor_elements13.updateElementStyle)({
4796
+ (0, import_editor_elements14.updateElementStyle)({
4744
4797
  elementId,
4745
4798
  styleId: localStyle.id,
4746
4799
  meta: {
@@ -4755,7 +4808,7 @@ var doUpdateElementProperty = (params) => {
4755
4808
  }
4756
4809
  return;
4757
4810
  }
4758
- const elementPropSchema = (0, import_editor_elements13.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4811
+ const elementPropSchema = (0, import_editor_elements14.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4759
4812
  if (!elementPropSchema) {
4760
4813
  throw new Error(`No prop schema found for element type: ${elementType}`);
4761
4814
  }
@@ -4778,7 +4831,7 @@ var doUpdateElementProperty = (params) => {
4778
4831
  Expected Schema: ${jsonSchema}`
4779
4832
  );
4780
4833
  }
4781
- (0, import_editor_elements13.updateElementSettings)({
4834
+ (0, import_editor_elements14.updateElementSettings)({
4782
4835
  id: elementId,
4783
4836
  props: {
4784
4837
  [propertyName]: value
@@ -4836,11 +4889,11 @@ var CompositionBuilder = class _CompositionBuilder {
4836
4889
  elementCustomCSS = {};
4837
4890
  rootContainers = [];
4838
4891
  api = {
4839
- createElement: import_editor_elements14.createElement,
4840
- deleteElement: import_editor_elements14.deleteElement,
4841
- getWidgetsCache: import_editor_elements14.getWidgetsCache,
4842
- generateElementId: import_editor_elements14.generateElementId,
4843
- getContainer: import_editor_elements14.getContainer,
4892
+ createElement: import_editor_elements15.createElement,
4893
+ deleteElement: import_editor_elements15.deleteElement,
4894
+ getWidgetsCache: import_editor_elements15.getWidgetsCache,
4895
+ generateElementId: import_editor_elements15.generateElementId,
4896
+ getContainer: import_editor_elements15.getContainer,
4844
4897
  doUpdateElementProperty
4845
4898
  };
4846
4899
  xml;
@@ -5360,19 +5413,19 @@ var initBuildCompositionsTool = (reg) => {
5360
5413
  const { xmlStructure, elementConfig, stylesConfig } = adaptLeafRootParams({
5361
5414
  ...rawParams,
5362
5415
  stylesConfig: convertedStyles,
5363
- widgetsCache: (0, import_editor_elements15.getWidgetsCache)() ?? {}
5416
+ widgetsCache: (0, import_editor_elements16.getWidgetsCache)() ?? {}
5364
5417
  });
5365
5418
  let generatedXML = "";
5366
5419
  const errors = [];
5367
5420
  const rootContainers = [];
5368
- const documentContainer = (0, import_editor_elements15.getContainer)("document");
5421
+ const documentContainer = (0, import_editor_elements16.getContainer)("document");
5369
5422
  const currentDocument = (0, import_editor_documents3.getCurrentDocument)();
5370
5423
  const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
5371
5424
  try {
5372
5425
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
5373
- createElement: import_editor_elements15.createElement,
5374
- deleteElement: import_editor_elements15.deleteElement,
5375
- getWidgetsCache: import_editor_elements15.getWidgetsCache
5426
+ createElement: import_editor_elements16.createElement,
5427
+ deleteElement: import_editor_elements16.deleteElement,
5428
+ getWidgetsCache: import_editor_elements16.getWidgetsCache
5376
5429
  });
5377
5430
  compositionBuilder.setElementConfig(elementConfig);
5378
5431
  compositionBuilder.setStylesConfig(stylesConfig);
@@ -5388,7 +5441,7 @@ var initBuildCompositionsTool = (reg) => {
5388
5441
  }
5389
5442
  if (errors.length) {
5390
5443
  rootContainers.forEach((rootContainer) => {
5391
- (0, import_editor_elements15.deleteElement)({
5444
+ (0, import_editor_elements16.deleteElement)({
5392
5445
  container: rootContainer,
5393
5446
  options: { useHistory: false }
5394
5447
  });
@@ -5457,7 +5510,7 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
5457
5510
  if (doc.querySelector("parsererror")) {
5458
5511
  throw new Error("Failed to parse XML string: " + doc);
5459
5512
  }
5460
- const widgetsCache = (0, import_editor_elements15.getWidgetsCache)() ?? {};
5513
+ const widgetsCache = (0, import_editor_elements16.getWidgetsCache)() ?? {};
5461
5514
  for (const node of doc.querySelectorAll("*")) {
5462
5515
  const type = node.tagName;
5463
5516
  const widgetData = widgetsCache[type];
@@ -5474,10 +5527,10 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
5474
5527
  }
5475
5528
 
5476
5529
  // src/mcp/tools/configure-element/tool.ts
5477
- var import_editor_elements17 = require("@elementor/editor-elements");
5530
+ var import_editor_elements18 = require("@elementor/editor-elements");
5478
5531
 
5479
5532
  // src/mcp/utils/validate-input.ts
5480
- var import_editor_elements16 = require("@elementor/editor-elements");
5533
+ var import_editor_elements17 = require("@elementor/editor-elements");
5481
5534
  var import_editor_props9 = require("@elementor/editor-props");
5482
5535
  var import_editor_styles5 = require("@elementor/editor-styles");
5483
5536
  var _widgetsSchema = null;
@@ -5485,7 +5538,7 @@ var validateInput = {
5485
5538
  get widgetsSchema() {
5486
5539
  if (!_widgetsSchema) {
5487
5540
  const schema2 = {};
5488
- const cache = (0, import_editor_elements16.getWidgetsCache)();
5541
+ const cache = (0, import_editor_elements17.getWidgetsCache)();
5489
5542
  if (!cache) {
5490
5543
  return {};
5491
5544
  }
@@ -5726,19 +5779,28 @@ var initConfigureElementTool = (reg) => {
5726
5779
  { description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
5727
5780
  ],
5728
5781
  handler: async ({ elementId, propertiesToChange, elementType, style }) => {
5729
- const widgetData = (0, import_editor_elements17.getWidgetsCache)()?.[elementType];
5782
+ const widgetData = (0, import_editor_elements18.getWidgetsCache)()?.[elementType];
5730
5783
  if (!widgetData) {
5731
5784
  throw new Error(
5732
5785
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5733
5786
  );
5734
5787
  }
5788
+ const container = (0, import_editor_elements18.getContainer)(elementId);
5789
+ if (!container) {
5790
+ throw new Error(`Element with id ${elementId} not found`);
5791
+ }
5792
+ const isElementTypeMatchingId = container.settings.get("widgetType") === elementType || container.type === elementType;
5793
+ if (!isElementTypeMatchingId) {
5794
+ throw new Error(`Element with ID ${elementId} is not of type ${elementType}`);
5795
+ }
5735
5796
  if (!widgetData.atomic_props_schema) {
5736
5797
  throw new Error(
5737
5798
  `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
5738
5799
  );
5739
5800
  }
5740
- const toUpdate = Object.entries(propertiesToChange);
5741
- const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToChange);
5801
+ const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5802
+ const toUpdate = Object.entries(propertiesToUpdate);
5803
+ const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToUpdate);
5742
5804
  if (!valid) {
5743
5805
  const errorMessage = `Failed to configure element "${elementId}" due to invalid properties: ${errors?.join(
5744
5806
  "\n- "
@@ -5818,7 +5880,7 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5818
5880
  }
5819
5881
 
5820
5882
  // src/mcp/tools/get-element-config/tool.ts
5821
- var import_editor_elements18 = require("@elementor/editor-elements");
5883
+ var import_editor_elements19 = require("@elementor/editor-elements");
5822
5884
  var import_editor_props10 = require("@elementor/editor-props");
5823
5885
  var import_schema5 = require("@elementor/schema");
5824
5886
  var schema = {
@@ -5853,12 +5915,12 @@ var initGetElementConfigTool = (reg) => {
5853
5915
  schema,
5854
5916
  outputSchema: outputSchema3,
5855
5917
  handler: async ({ elementId }) => {
5856
- const element = (0, import_editor_elements18.getContainer)(elementId);
5918
+ const element = (0, import_editor_elements19.getContainer)(elementId);
5857
5919
  if (!element) {
5858
5920
  throw new Error(`Element with ID ${elementId} not found.`);
5859
5921
  }
5860
5922
  const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5861
- const widgetData = (0, import_editor_elements18.getWidgetsCache)()?.[elementType];
5923
+ const widgetData = (0, import_editor_elements19.getWidgetsCache)()?.[elementType];
5862
5924
  if (!widgetData) {
5863
5925
  throw new Error(
5864
5926
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
@@ -5870,7 +5932,7 @@ var initGetElementConfigTool = (reg) => {
5870
5932
  );
5871
5933
  }
5872
5934
  const elementRawSettings = element.settings;
5873
- const propSchema = (0, import_editor_elements18.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
5935
+ const propSchema = (0, import_editor_elements19.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
5874
5936
  if (!elementRawSettings || !propSchema) {
5875
5937
  throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5876
5938
  }
@@ -5879,7 +5941,7 @@ var initGetElementConfigTool = (reg) => {
5879
5941
  import_editor_props10.Schema.configurableKeys(propSchema).forEach((key) => {
5880
5942
  propValues[key] = structuredClone(elementRawSettings.get(key));
5881
5943
  });
5882
- const elementStyles = (0, import_editor_elements18.getElementStyles)(elementId) || {};
5944
+ const elementStyles = (0, import_editor_elements19.getElementStyles)(elementId) || {};
5883
5945
  const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
5884
5946
  if (localStyle) {
5885
5947
  const defaultVariant = localStyle.variants.find(
@@ -6035,7 +6097,7 @@ Note: The "size" property controls image resolution/loading, not visual size. Se
6035
6097
  `;
6036
6098
 
6037
6099
  // src/prevent-link-in-link-commands.ts
6038
- var import_editor_elements19 = require("@elementor/editor-elements");
6100
+ var import_editor_elements20 = require("@elementor/editor-elements");
6039
6101
  var import_editor_notifications3 = require("@elementor/editor-notifications");
6040
6102
  var import_editor_v1_adapters22 = require("@elementor/editor-v1-adapters");
6041
6103
  var import_i18n4 = require("@wordpress/i18n");
@@ -6106,24 +6168,24 @@ function shouldBlock(sourceElements, targetElements) {
6106
6168
  return false;
6107
6169
  }
6108
6170
  const isSourceContainsAnAnchor = sourceElements.some((src) => {
6109
- return src?.id ? (0, import_editor_elements19.isElementAnchored)(src.id) || !!(0, import_editor_elements19.getAnchoredDescendantId)(src.id) : false;
6171
+ return src?.id ? (0, import_editor_elements20.isElementAnchored)(src.id) || !!(0, import_editor_elements20.getAnchoredDescendantId)(src.id) : false;
6110
6172
  });
6111
6173
  if (!isSourceContainsAnAnchor) {
6112
6174
  return false;
6113
6175
  }
6114
6176
  const isTargetContainsAnAnchor = targetElements.some((target) => {
6115
- return target?.id ? (0, import_editor_elements19.isElementAnchored)(target.id) || !!(0, import_editor_elements19.getAnchoredAncestorId)(target.id) : false;
6177
+ return target?.id ? (0, import_editor_elements20.isElementAnchored)(target.id) || !!(0, import_editor_elements20.getAnchoredAncestorId)(target.id) : false;
6116
6178
  });
6117
6179
  return isTargetContainsAnAnchor;
6118
6180
  }
6119
6181
 
6120
6182
  // src/style-commands/paste-style.ts
6121
- var import_editor_elements22 = require("@elementor/editor-elements");
6183
+ var import_editor_elements23 = require("@elementor/editor-elements");
6122
6184
  var import_editor_props13 = require("@elementor/editor-props");
6123
6185
  var import_editor_v1_adapters24 = require("@elementor/editor-v1-adapters");
6124
6186
 
6125
6187
  // src/utils/command-utils.ts
6126
- var import_editor_elements20 = require("@elementor/editor-elements");
6188
+ var import_editor_elements21 = require("@elementor/editor-elements");
6127
6189
  var import_editor_props12 = require("@elementor/editor-props");
6128
6190
  var import_i18n5 = require("@wordpress/i18n");
6129
6191
  function hasAtomicWidgets(args) {
@@ -6148,7 +6210,7 @@ function getClassesProp(container) {
6148
6210
  }
6149
6211
  function getContainerSchema(container) {
6150
6212
  const type = container?.model.get("widgetType") || container?.model.get("elType");
6151
- const widgetsCache = (0, import_editor_elements20.getWidgetsCache)();
6213
+ const widgetsCache = (0, import_editor_elements21.getWidgetsCache)();
6152
6214
  const elementType = widgetsCache?.[type];
6153
6215
  return elementType?.atomic_props_schema ?? null;
6154
6216
  }
@@ -6161,11 +6223,11 @@ function getClipboardElements(storageKey = "clipboard") {
6161
6223
  }
6162
6224
  }
6163
6225
  function getTitleForContainers(containers) {
6164
- return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements20.getElementLabel)(containers[0].id);
6226
+ return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements21.getElementLabel)(containers[0].id);
6165
6227
  }
6166
6228
 
6167
6229
  // src/style-commands/undoable-actions/paste-element-style.ts
6168
- var import_editor_elements21 = require("@elementor/editor-elements");
6230
+ var import_editor_elements22 = require("@elementor/editor-elements");
6169
6231
  var import_editor_styles_repository4 = require("@elementor/editor-styles-repository");
6170
6232
  var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
6171
6233
  var import_i18n6 = require("@wordpress/i18n");
@@ -6178,7 +6240,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
6178
6240
  if (!classesProp) {
6179
6241
  return null;
6180
6242
  }
6181
- const originalStyles = (0, import_editor_elements21.getElementStyles)(container.id);
6243
+ const originalStyles = (0, import_editor_elements22.getElementStyles)(container.id);
6182
6244
  const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
6183
6245
  const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
6184
6246
  const revertData = {
@@ -6187,7 +6249,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
6187
6249
  };
6188
6250
  if (styleId) {
6189
6251
  newStyle.variants.forEach(({ meta, props, custom_css: customCss }) => {
6190
- (0, import_editor_elements21.updateElementStyle)({
6252
+ (0, import_editor_elements22.updateElementStyle)({
6191
6253
  elementId,
6192
6254
  styleId,
6193
6255
  meta,
@@ -6198,7 +6260,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
6198
6260
  } else {
6199
6261
  const [firstVariant] = newStyle.variants;
6200
6262
  const additionalVariants = newStyle.variants.slice(1);
6201
- revertData.styleId = (0, import_editor_elements21.createElementStyle)({
6263
+ revertData.styleId = (0, import_editor_elements22.createElementStyle)({
6202
6264
  elementId,
6203
6265
  classesProp,
6204
6266
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -6216,7 +6278,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
6216
6278
  return;
6217
6279
  }
6218
6280
  if (!revertData.originalStyle) {
6219
- (0, import_editor_elements21.deleteElementStyle)(container.id, revertData.styleId);
6281
+ (0, import_editor_elements22.deleteElementStyle)(container.id, revertData.styleId);
6220
6282
  return;
6221
6283
  }
6222
6284
  const classesProp = getClassesProp(container);
@@ -6225,7 +6287,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
6225
6287
  }
6226
6288
  const [firstVariant] = revertData.originalStyle.variants;
6227
6289
  const additionalVariants = revertData.originalStyle.variants.slice(1);
6228
- (0, import_editor_elements21.createElementStyle)({
6290
+ (0, import_editor_elements22.createElementStyle)({
6229
6291
  elementId: container.id,
6230
6292
  classesProp,
6231
6293
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -6262,7 +6324,7 @@ function pasteStyles(args, pasteLocalStyle) {
6262
6324
  }
6263
6325
  const clipboardElements = getClipboardElements(storageKey);
6264
6326
  const [clipboardElement] = clipboardElements ?? [];
6265
- const clipboardContainer = (0, import_editor_elements22.getContainer)(clipboardElement.id);
6327
+ const clipboardContainer = (0, import_editor_elements23.getContainer)(clipboardElement.id);
6266
6328
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
6267
6329
  return;
6268
6330
  }
@@ -6281,7 +6343,7 @@ function getClassesWithoutLocalStyle(clipboardContainer, style) {
6281
6343
  if (!classesProp) {
6282
6344
  return [];
6283
6345
  }
6284
- const classesSetting = (0, import_editor_elements22.getElementSetting)(clipboardContainer.id, classesProp);
6346
+ const classesSetting = (0, import_editor_elements23.getElementSetting)(clipboardContainer.id, classesProp);
6285
6347
  return classesSetting?.value.filter((styleId) => styleId !== style?.id) ?? [];
6286
6348
  }
6287
6349
  function pasteClasses(containers, classes) {
@@ -6290,10 +6352,10 @@ function pasteClasses(containers, classes) {
6290
6352
  if (!classesProp) {
6291
6353
  return;
6292
6354
  }
6293
- const classesSetting = (0, import_editor_elements22.getElementSetting)(container.id, classesProp);
6355
+ const classesSetting = (0, import_editor_elements23.getElementSetting)(container.id, classesProp);
6294
6356
  const currentClasses = import_editor_props13.classesPropTypeUtil.extract(classesSetting) ?? [];
6295
6357
  const newClasses = import_editor_props13.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
6296
- (0, import_editor_elements22.updateElementSettings)({
6358
+ (0, import_editor_elements23.updateElementSettings)({
6297
6359
  id: container.id,
6298
6360
  props: { [classesProp]: newClasses }
6299
6361
  });
@@ -6304,7 +6366,7 @@ function pasteClasses(containers, classes) {
6304
6366
  var import_editor_v1_adapters26 = require("@elementor/editor-v1-adapters");
6305
6367
 
6306
6368
  // src/style-commands/undoable-actions/reset-element-style.ts
6307
- var import_editor_elements23 = require("@elementor/editor-elements");
6369
+ var import_editor_elements24 = require("@elementor/editor-elements");
6308
6370
  var import_editor_styles_repository5 = require("@elementor/editor-styles-repository");
6309
6371
  var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
6310
6372
  var import_i18n7 = require("@wordpress/i18n");
@@ -6313,9 +6375,9 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters25.undoable)(
6313
6375
  do: ({ containers }) => {
6314
6376
  return containers.map((container) => {
6315
6377
  const elementId = container.model.get("id");
6316
- const containerStyles = (0, import_editor_elements23.getElementStyles)(elementId);
6378
+ const containerStyles = (0, import_editor_elements24.getElementStyles)(elementId);
6317
6379
  Object.keys(containerStyles ?? {}).forEach(
6318
- (styleId) => (0, import_editor_elements23.deleteElementStyle)(elementId, styleId)
6380
+ (styleId) => (0, import_editor_elements24.deleteElementStyle)(elementId, styleId)
6319
6381
  );
6320
6382
  return containerStyles;
6321
6383
  });
@@ -6331,7 +6393,7 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters25.undoable)(
6331
6393
  Object.entries(containerStyles ?? {}).forEach(([styleId, style]) => {
6332
6394
  const [firstVariant] = style.variants;
6333
6395
  const additionalVariants = style.variants.slice(1);
6334
- (0, import_editor_elements23.createElementStyle)({
6396
+ (0, import_editor_elements24.createElementStyle)({
6335
6397
  elementId,
6336
6398
  classesProp,
6337
6399
  styleId,
@@ -6531,10 +6593,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
6531
6593
  }
6532
6594
 
6533
6595
  // src/utils/after-render.ts
6534
- var import_editor_elements24 = require("@elementor/editor-elements");
6596
+ var import_editor_elements25 = require("@elementor/editor-elements");
6535
6597
  function doAfterRender(elementIds, callback) {
6536
6598
  const pending = elementIds.map((elementId) => {
6537
- const view = (0, import_editor_elements24.getContainer)(elementId)?.view;
6599
+ const view = (0, import_editor_elements25.getContainer)(elementId)?.view;
6538
6600
  if (!view || !hasDoAfterRender(view)) {
6539
6601
  return void 0;
6540
6602
  }
package/dist/index.mjs CHANGED
@@ -4164,7 +4164,7 @@ function extractElementData(element) {
4164
4164
  widgetType: model.widgetType || void 0,
4165
4165
  version: resolveElementVersion(element)
4166
4166
  };
4167
- const title = model.title || element.model?.editor_settings?.title;
4167
+ const title = model.title || element.model?.editor_settings?.title || element.model.getTitle?.();
4168
4168
  if (title) {
4169
4169
  result.title = title;
4170
4170
  }
@@ -4599,7 +4599,7 @@ import {
4599
4599
  createElement as createElement13,
4600
4600
  deleteElement as deleteElement2,
4601
4601
  getContainer as getContainer5,
4602
- getWidgetsCache as getWidgetsCache8
4602
+ getWidgetsCache as getWidgetsCache9
4603
4603
  } from "@elementor/editor-elements";
4604
4604
 
4605
4605
  // src/composition-builder/composition-builder.ts
@@ -4608,14 +4608,14 @@ import {
4608
4608
  deleteElement,
4609
4609
  generateElementId as generateElementId2,
4610
4610
  getContainer as getContainer4,
4611
- getWidgetsCache as getWidgetsCache7
4611
+ getWidgetsCache as getWidgetsCache8
4612
4612
  } from "@elementor/editor-elements";
4613
4613
 
4614
4614
  // src/mcp/utils/do-update-element-property.ts
4615
4615
  import {
4616
4616
  createElementStyle,
4617
4617
  getElementStyles,
4618
- getWidgetsCache as getWidgetsCache6,
4618
+ getWidgetsCache as getWidgetsCache7,
4619
4619
  updateElementSettings,
4620
4620
  updateElementStyle
4621
4621
  } from "@elementor/editor-elements";
@@ -4637,6 +4637,58 @@ var readStoredCustomCssText = (raw) => {
4637
4637
  }
4638
4638
  };
4639
4639
 
4640
+ // src/mcp/utils/resolve-canonical-prop-name.ts
4641
+ import { getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
4642
+ function buildAliasToCanonicalMap(schema2) {
4643
+ const aliasToCanonical = {};
4644
+ for (const [canonical, propType] of Object.entries(schema2)) {
4645
+ const aliases = propType.meta?.aliases;
4646
+ if (!Array.isArray(aliases)) {
4647
+ continue;
4648
+ }
4649
+ for (const alias of aliases) {
4650
+ if (typeof alias === "string" && alias) {
4651
+ aliasToCanonical[alias] = canonical;
4652
+ }
4653
+ }
4654
+ }
4655
+ return aliasToCanonical;
4656
+ }
4657
+ function resolveCanonicalPropName(elementType, propertyName) {
4658
+ const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
4659
+ if (!schema2 || schema2[propertyName]) {
4660
+ return propertyName;
4661
+ }
4662
+ return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4663
+ }
4664
+ function resolveCanonicalPropKeys(elementType, props) {
4665
+ const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
4666
+ if (!schema2) {
4667
+ return { ...props };
4668
+ }
4669
+ const aliasToCanonical = buildAliasToCanonicalMap(schema2);
4670
+ const resolved = {};
4671
+ for (const [key, value] of Object.entries(props)) {
4672
+ if (schema2[key]) {
4673
+ resolved[key] = value;
4674
+ }
4675
+ }
4676
+ for (const [key, value] of Object.entries(props)) {
4677
+ if (schema2[key]) {
4678
+ continue;
4679
+ }
4680
+ const canonical = aliasToCanonical[key];
4681
+ if (!canonical) {
4682
+ resolved[key] = value;
4683
+ continue;
4684
+ }
4685
+ if (!Object.prototype.hasOwnProperty.call(resolved, canonical)) {
4686
+ resolved[canonical] = value;
4687
+ }
4688
+ }
4689
+ return resolved;
4690
+ }
4691
+
4640
4692
  // src/mcp/utils/do-update-element-property.ts
4641
4693
  var LOCAL_STYLE_META = {
4642
4694
  breakpoint: "desktop",
@@ -4653,7 +4705,8 @@ function resolvePropValue(value, forceKey) {
4653
4705
  });
4654
4706
  }
4655
4707
  var doUpdateElementProperty = (params) => {
4656
- const { elementId, propertyName, propertyValue, elementType, customCssWriteMode = "replace" } = params;
4708
+ const { elementId, propertyValue, elementType, customCssWriteMode = "replace" } = params;
4709
+ const propertyName = params.propertyName === "_styles" ? params.propertyName : resolveCanonicalPropName(elementType, params.propertyName);
4657
4710
  if (propertyName === "_styles") {
4658
4711
  const elementStyles = getElementStyles(elementId) || {};
4659
4712
  const propertyMapValue = propertyValue;
@@ -4741,7 +4794,7 @@ var doUpdateElementProperty = (params) => {
4741
4794
  }
4742
4795
  return;
4743
4796
  }
4744
- const elementPropSchema = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
4797
+ const elementPropSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
4745
4798
  if (!elementPropSchema) {
4746
4799
  throw new Error(`No prop schema found for element type: ${elementType}`);
4747
4800
  }
@@ -4824,7 +4877,7 @@ var CompositionBuilder = class _CompositionBuilder {
4824
4877
  api = {
4825
4878
  createElement: createElement12,
4826
4879
  deleteElement,
4827
- getWidgetsCache: getWidgetsCache7,
4880
+ getWidgetsCache: getWidgetsCache8,
4828
4881
  generateElementId: generateElementId2,
4829
4882
  getContainer: getContainer4,
4830
4883
  doUpdateElementProperty
@@ -5346,7 +5399,7 @@ var initBuildCompositionsTool = (reg) => {
5346
5399
  const { xmlStructure, elementConfig, stylesConfig } = adaptLeafRootParams({
5347
5400
  ...rawParams,
5348
5401
  stylesConfig: convertedStyles,
5349
- widgetsCache: getWidgetsCache8() ?? {}
5402
+ widgetsCache: getWidgetsCache9() ?? {}
5350
5403
  });
5351
5404
  let generatedXML = "";
5352
5405
  const errors = [];
@@ -5358,7 +5411,7 @@ var initBuildCompositionsTool = (reg) => {
5358
5411
  const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
5359
5412
  createElement: createElement13,
5360
5413
  deleteElement: deleteElement2,
5361
- getWidgetsCache: getWidgetsCache8
5414
+ getWidgetsCache: getWidgetsCache9
5362
5415
  });
5363
5416
  compositionBuilder.setElementConfig(elementConfig);
5364
5417
  compositionBuilder.setStylesConfig(stylesConfig);
@@ -5443,7 +5496,7 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
5443
5496
  if (doc.querySelector("parsererror")) {
5444
5497
  throw new Error("Failed to parse XML string: " + doc);
5445
5498
  }
5446
- const widgetsCache = getWidgetsCache8() ?? {};
5499
+ const widgetsCache = getWidgetsCache9() ?? {};
5447
5500
  for (const node of doc.querySelectorAll("*")) {
5448
5501
  const type = node.tagName;
5449
5502
  const widgetData = widgetsCache[type];
@@ -5460,10 +5513,10 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
5460
5513
  }
5461
5514
 
5462
5515
  // src/mcp/tools/configure-element/tool.ts
5463
- import { getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
5516
+ import { getContainer as getContainer6, getWidgetsCache as getWidgetsCache11 } from "@elementor/editor-elements";
5464
5517
 
5465
5518
  // src/mcp/utils/validate-input.ts
5466
- import { getWidgetsCache as getWidgetsCache9 } from "@elementor/editor-elements";
5519
+ import { getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
5467
5520
  import { Schema as Schema4 } from "@elementor/editor-props";
5468
5521
  import { getStylesSchema as getStylesSchema3 } from "@elementor/editor-styles";
5469
5522
  var _widgetsSchema = null;
@@ -5471,7 +5524,7 @@ var validateInput = {
5471
5524
  get widgetsSchema() {
5472
5525
  if (!_widgetsSchema) {
5473
5526
  const schema2 = {};
5474
- const cache = getWidgetsCache9();
5527
+ const cache = getWidgetsCache10();
5475
5528
  if (!cache) {
5476
5529
  return {};
5477
5530
  }
@@ -5712,19 +5765,28 @@ var initConfigureElementTool = (reg) => {
5712
5765
  { description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
5713
5766
  ],
5714
5767
  handler: async ({ elementId, propertiesToChange, elementType, style }) => {
5715
- const widgetData = getWidgetsCache10()?.[elementType];
5768
+ const widgetData = getWidgetsCache11()?.[elementType];
5716
5769
  if (!widgetData) {
5717
5770
  throw new Error(
5718
5771
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5719
5772
  );
5720
5773
  }
5774
+ const container = getContainer6(elementId);
5775
+ if (!container) {
5776
+ throw new Error(`Element with id ${elementId} not found`);
5777
+ }
5778
+ const isElementTypeMatchingId = container.settings.get("widgetType") === elementType || container.type === elementType;
5779
+ if (!isElementTypeMatchingId) {
5780
+ throw new Error(`Element with ID ${elementId} is not of type ${elementType}`);
5781
+ }
5721
5782
  if (!widgetData.atomic_props_schema) {
5722
5783
  throw new Error(
5723
5784
  `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
5724
5785
  );
5725
5786
  }
5726
- const toUpdate = Object.entries(propertiesToChange);
5727
- const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToChange);
5787
+ const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5788
+ const toUpdate = Object.entries(propertiesToUpdate);
5789
+ const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToUpdate);
5728
5790
  if (!valid) {
5729
5791
  const errorMessage = `Failed to configure element "${elementId}" due to invalid properties: ${errors?.join(
5730
5792
  "\n- "
@@ -5804,7 +5866,7 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5804
5866
  }
5805
5867
 
5806
5868
  // src/mcp/tools/get-element-config/tool.ts
5807
- import { getContainer as getContainer6, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache11 } from "@elementor/editor-elements";
5869
+ import { getContainer as getContainer7, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache12 } from "@elementor/editor-elements";
5808
5870
  import { Schema as Schema5 } from "@elementor/editor-props";
5809
5871
  import { z as z3 } from "@elementor/schema";
5810
5872
  var schema = {
@@ -5839,12 +5901,12 @@ var initGetElementConfigTool = (reg) => {
5839
5901
  schema,
5840
5902
  outputSchema: outputSchema3,
5841
5903
  handler: async ({ elementId }) => {
5842
- const element = getContainer6(elementId);
5904
+ const element = getContainer7(elementId);
5843
5905
  if (!element) {
5844
5906
  throw new Error(`Element with ID ${elementId} not found.`);
5845
5907
  }
5846
5908
  const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5847
- const widgetData = getWidgetsCache11()?.[elementType];
5909
+ const widgetData = getWidgetsCache12()?.[elementType];
5848
5910
  if (!widgetData) {
5849
5911
  throw new Error(
5850
5912
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
@@ -5856,7 +5918,7 @@ var initGetElementConfigTool = (reg) => {
5856
5918
  );
5857
5919
  }
5858
5920
  const elementRawSettings = element.settings;
5859
- const propSchema = getWidgetsCache11()?.[elementType]?.atomic_props_schema;
5921
+ const propSchema = getWidgetsCache12()?.[elementType]?.atomic_props_schema;
5860
5922
  if (!elementRawSettings || !propSchema) {
5861
5923
  throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5862
5924
  }
@@ -6108,7 +6170,7 @@ function shouldBlock(sourceElements, targetElements) {
6108
6170
  }
6109
6171
 
6110
6172
  // src/style-commands/paste-style.ts
6111
- import { getContainer as getContainer7, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
6173
+ import { getContainer as getContainer8, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
6112
6174
  import { classesPropTypeUtil } from "@elementor/editor-props";
6113
6175
  import {
6114
6176
  __privateListenTo as listenTo5,
@@ -6117,7 +6179,7 @@ import {
6117
6179
  } from "@elementor/editor-v1-adapters";
6118
6180
 
6119
6181
  // src/utils/command-utils.ts
6120
- import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache12 } from "@elementor/editor-elements";
6182
+ import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache13 } from "@elementor/editor-elements";
6121
6183
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
6122
6184
  import { __ as __5 } from "@wordpress/i18n";
6123
6185
  function hasAtomicWidgets(args) {
@@ -6142,7 +6204,7 @@ function getClassesProp(container) {
6142
6204
  }
6143
6205
  function getContainerSchema(container) {
6144
6206
  const type = container?.model.get("widgetType") || container?.model.get("elType");
6145
- const widgetsCache = getWidgetsCache12();
6207
+ const widgetsCache = getWidgetsCache13();
6146
6208
  const elementType = widgetsCache?.[type];
6147
6209
  return elementType?.atomic_props_schema ?? null;
6148
6210
  }
@@ -6261,7 +6323,7 @@ function pasteStyles(args, pasteLocalStyle) {
6261
6323
  }
6262
6324
  const clipboardElements = getClipboardElements(storageKey);
6263
6325
  const [clipboardElement] = clipboardElements ?? [];
6264
- const clipboardContainer = getContainer7(clipboardElement.id);
6326
+ const clipboardContainer = getContainer8(clipboardElement.id);
6265
6327
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
6266
6328
  return;
6267
6329
  }
@@ -6538,10 +6600,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
6538
6600
  }
6539
6601
 
6540
6602
  // src/utils/after-render.ts
6541
- import { getContainer as getContainer8 } from "@elementor/editor-elements";
6603
+ import { getContainer as getContainer9 } from "@elementor/editor-elements";
6542
6604
  function doAfterRender(elementIds, callback) {
6543
6605
  const pending = elementIds.map((elementId) => {
6544
- const view = getContainer8(elementId)?.view;
6606
+ const view = getContainer9(elementId)?.view;
6545
6607
  if (!view || !hasDoAfterRender(view)) {
6546
6608
  return void 0;
6547
6609
  }
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.2.0-937",
4
+ "version": "4.2.0-939",
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.2.0-937",
40
+ "@elementor/editor": "4.2.0-939",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.2.0-937",
43
- "@elementor/editor-documents": "4.2.0-937",
44
- "@elementor/editor-elements": "4.2.0-937",
45
- "@elementor/editor-interactions": "4.2.0-937",
46
- "@elementor/editor-mcp": "4.2.0-937",
47
- "@elementor/editor-notifications": "4.2.0-937",
48
- "@elementor/editor-props": "4.2.0-937",
49
- "@elementor/editor-responsive": "4.2.0-937",
50
- "@elementor/editor-styles": "4.2.0-937",
51
- "@elementor/editor-styles-repository": "4.2.0-937",
52
- "@elementor/editor-ui": "4.2.0-937",
53
- "@elementor/editor-v1-adapters": "4.2.0-937",
54
- "@elementor/http-client": "4.2.0-937",
55
- "@elementor/schema": "4.2.0-937",
56
- "@elementor/twing": "4.2.0-937",
42
+ "@elementor/editor-controls": "4.2.0-939",
43
+ "@elementor/editor-documents": "4.2.0-939",
44
+ "@elementor/editor-elements": "4.2.0-939",
45
+ "@elementor/editor-interactions": "4.2.0-939",
46
+ "@elementor/editor-mcp": "4.2.0-939",
47
+ "@elementor/editor-notifications": "4.2.0-939",
48
+ "@elementor/editor-props": "4.2.0-939",
49
+ "@elementor/editor-responsive": "4.2.0-939",
50
+ "@elementor/editor-styles": "4.2.0-939",
51
+ "@elementor/editor-styles-repository": "4.2.0-939",
52
+ "@elementor/editor-ui": "4.2.0-939",
53
+ "@elementor/editor-v1-adapters": "4.2.0-939",
54
+ "@elementor/http-client": "4.2.0-939",
55
+ "@elementor/schema": "4.2.0-939",
56
+ "@elementor/twing": "4.2.0-939",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.2.0-937",
59
- "@elementor/wp-media": "4.2.0-937",
58
+ "@elementor/utils": "4.2.0-939",
59
+ "@elementor/wp-media": "4.2.0-939",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0"
62
62
  },
@@ -136,7 +136,10 @@ function extractElementData( element: UnknownVersionElementInstanceData ): Recor
136
136
  version: resolveElementVersion( element ),
137
137
  };
138
138
 
139
- const title = model.title || element.model?.editor_settings?.title;
139
+ const title =
140
+ model.title ||
141
+ element.model?.editor_settings?.title ||
142
+ ( element.model as unknown as Record< string, CallableFunction > ).getTitle?.();
140
143
 
141
144
  if ( title ) {
142
145
  result.title = title;
@@ -1,10 +1,12 @@
1
- import { getWidgetsCache } from '@elementor/editor-elements';
1
+ import { getContainer, getWidgetsCache } from '@elementor/editor-elements';
2
2
  import { type MCPRegistryEntry } from '@elementor/editor-mcp';
3
+ import { type PropValue } from '@elementor/editor-props';
3
4
 
4
5
  import { DYNAMIC_TAGS_URI } from '../../resources/dynamic-tags-resource';
5
6
  import { WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
6
7
  import { convertCssToAtomic } from '../../utils/convert-css-to-atomic';
7
8
  import { doUpdateElementProperty } from '../../utils/do-update-element-property';
9
+ import { resolveCanonicalPropKeys } from '../../utils/resolve-canonical-prop-name';
8
10
  import { validateInput } from '../../utils/validate-input';
9
11
  import { CONFIGURE_ELEMENT_GUIDE_URI, generatePrompt } from './prompt';
10
12
  import { inputSchema as schema, outputSchema } from './schema';
@@ -42,20 +44,31 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
42
44
  `Unknown element type: ${ elementType }. Check the available-widgets resource for valid types.`
43
45
  );
44
46
  }
47
+ const container = getContainer( elementId );
48
+ if ( ! container ) {
49
+ throw new Error( `Element with id ${ elementId } not found` );
50
+ }
51
+ const isElementTypeMatchingId =
52
+ container.settings.get( 'widgetType' ) === elementType ||
53
+ ( container as Record< string, unknown > ).type === elementType;
54
+ if ( ! isElementTypeMatchingId ) {
55
+ throw new Error( `Element with ID ${ elementId } is not of type ${ elementType }` );
56
+ }
45
57
  if ( ! widgetData.atomic_props_schema ) {
46
58
  throw new Error(
47
59
  `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${ elementType }`
48
60
  );
49
61
  }
50
- const toUpdate = Object.entries( propertiesToChange );
51
- const { valid, errors } = validateInput.validatePropSchema( elementType, propertiesToChange );
62
+ const propertiesToUpdate = resolveCanonicalPropKeys( elementType, propertiesToChange );
63
+ const toUpdate = Object.entries( propertiesToUpdate );
64
+ const { valid, errors } = validateInput.validatePropSchema( elementType, propertiesToUpdate );
52
65
  if ( ! valid ) {
53
66
  const errorMessage = `Failed to configure element "${ elementId }" due to invalid properties: ${ errors?.join(
54
67
  '\n- '
55
68
  ) }`;
56
69
  throw new Error( errorMessage );
57
70
  }
58
- for ( const [ propertyName, propertyValue ] of toUpdate ) {
71
+ for ( const [ propertyName, propertyValue ] of toUpdate as [ string, PropValue ][] ) {
59
72
  try {
60
73
  doUpdateElementProperty( {
61
74
  elementId,
@@ -143,6 +143,49 @@ describe( 'doUpdateElementProperty', () => {
143
143
  );
144
144
  } );
145
145
 
146
+ it( 'persists canonical prop key when an alias property name is used', () => {
147
+ // Arrange
148
+ const propertyValue = 'resolved-title';
149
+ jest.mocked( getWidgetsCache ).mockReturnValue( {
150
+ [ ELEMENT_TYPE ]: {
151
+ atomic_props_schema: {
152
+ // @ts-ignore: Mock type
153
+ [ PROPERTY_NAME ]: {
154
+ ...PROP_SCHEMA_ENTRY,
155
+ meta: { aliases: [ 'text' ] },
156
+ },
157
+ },
158
+ },
159
+ } );
160
+ jest.mocked( Schema.validatePropValue ).mockReturnValue( {
161
+ jsonSchema: EXPECTED_JSON_SCHEMA_SNIPPET,
162
+ valid: true,
163
+ errorMessages: [],
164
+ errors: [],
165
+ } );
166
+
167
+ // Act
168
+ doUpdateElementProperty( {
169
+ elementId: ELEMENT_ID,
170
+ elementType: ELEMENT_TYPE,
171
+ propertyName: 'text',
172
+ propertyValue,
173
+ } );
174
+
175
+ // Assert
176
+ expect( Schema.validatePropValue ).toHaveBeenCalledWith(
177
+ expect.objectContaining( PROP_SCHEMA_ENTRY ),
178
+ propertyValue
179
+ );
180
+ expect( updateElementSettings ).toHaveBeenCalledWith( {
181
+ id: ELEMENT_ID,
182
+ props: {
183
+ [ PROPERTY_NAME ]: propertyValue,
184
+ },
185
+ withHistory: false,
186
+ } );
187
+ } );
188
+
146
189
  it( 'replaces existing local style custom_css by default', () => {
147
190
  // Arrange
148
191
  jest.mocked( getElementStyles ).mockReturnValue( {
@@ -0,0 +1,111 @@
1
+ import { getWidgetsCache } from '@elementor/editor-elements';
2
+
3
+ import { resolveCanonicalPropKeys, resolveCanonicalPropName } from '../resolve-canonical-prop-name';
4
+
5
+ jest.mock( '@elementor/editor-elements', () => ( {
6
+ getWidgetsCache: jest.fn(),
7
+ } ) );
8
+
9
+ const ELEMENT_TYPE = 'e-paragraph';
10
+
11
+ const widgetsCacheFixture = {
12
+ [ ELEMENT_TYPE ]: {
13
+ atomic_props_schema: {
14
+ paragraph: {
15
+ key: 'html-v3',
16
+ meta: {
17
+ aliases: [ 'text', 'content' ],
18
+ },
19
+ },
20
+ tag: {
21
+ key: 'string',
22
+ },
23
+ },
24
+ },
25
+ };
26
+
27
+ describe( 'resolveCanonicalPropName', () => {
28
+ beforeEach( () => {
29
+ // @ts-ignore: Mock values for test
30
+ jest.mocked( getWidgetsCache ).mockReturnValue( widgetsCacheFixture );
31
+ } );
32
+
33
+ it( 'returns canonical property names unchanged', () => {
34
+ // Act
35
+ const resolved = resolveCanonicalPropName( ELEMENT_TYPE, 'paragraph' );
36
+
37
+ // Assert
38
+ expect( resolved ).toBe( 'paragraph' );
39
+ } );
40
+
41
+ it( 'resolves alias property names to canonical keys', () => {
42
+ // Act
43
+ const resolved = resolveCanonicalPropName( ELEMENT_TYPE, 'text' );
44
+
45
+ // Assert
46
+ expect( resolved ).toBe( 'paragraph' );
47
+ } );
48
+
49
+ it( 'returns unknown property names unchanged', () => {
50
+ // Act
51
+ const resolved = resolveCanonicalPropName( ELEMENT_TYPE, 'unknown' );
52
+
53
+ // Assert
54
+ expect( resolved ).toBe( 'unknown' );
55
+ } );
56
+
57
+ it( 'returns property names unchanged when element type has no schema', () => {
58
+ // Arrange
59
+ jest.mocked( getWidgetsCache ).mockReturnValue( null );
60
+
61
+ // Act
62
+ const resolved = resolveCanonicalPropName( 'missing-widget', 'text' );
63
+
64
+ // Assert
65
+ expect( resolved ).toBe( 'text' );
66
+ } );
67
+ } );
68
+
69
+ describe( 'resolveCanonicalPropKeys', () => {
70
+ beforeEach( () => {
71
+ // @ts-ignore: Mock values for test
72
+ jest.mocked( getWidgetsCache ).mockReturnValue( widgetsCacheFixture );
73
+ } );
74
+
75
+ it( 'rewrites alias keys to canonical keys', () => {
76
+ // Act
77
+ const resolved = resolveCanonicalPropKeys( ELEMENT_TYPE, {
78
+ text: 'hello',
79
+ } );
80
+
81
+ // Assert
82
+ expect( resolved ).toEqual( {
83
+ paragraph: 'hello',
84
+ } );
85
+ } );
86
+
87
+ it( 'prefers canonical keys when alias and canonical are both provided', () => {
88
+ // Act
89
+ const resolved = resolveCanonicalPropKeys( ELEMENT_TYPE, {
90
+ paragraph: 'canonical',
91
+ text: 'alias',
92
+ } );
93
+
94
+ // Assert
95
+ expect( resolved ).toEqual( {
96
+ paragraph: 'canonical',
97
+ } );
98
+ } );
99
+
100
+ it( 'passes unknown keys through for downstream validation', () => {
101
+ // Act
102
+ const resolved = resolveCanonicalPropKeys( ELEMENT_TYPE, {
103
+ unknown: 'value',
104
+ } );
105
+
106
+ // Assert
107
+ expect( resolved ).toEqual( {
108
+ unknown: 'value',
109
+ } );
110
+ } );
111
+ } );
@@ -12,6 +12,7 @@ import { type Utils as IUtils } from '@elementor/editor-variables';
12
12
  import { type z } from '@elementor/schema';
13
13
 
14
14
  import { mergeCustomCssText, readStoredCustomCssText } from './merge-custom-css';
15
+ import { resolveCanonicalPropName } from './resolve-canonical-prop-name';
15
16
  import { DYNAMIC_PROP_TYPE_KEY, dynamicTagLLMResolver } from './resolve-dynamic-tag';
16
17
 
17
18
  // TODO: see https://elementor.atlassian.net/browse/ED-22513 for better cross-module access
@@ -47,7 +48,11 @@ export function resolvePropValue( value: unknown, forceKey?: string ): PropValue
47
48
  * Also, it supports updating styles "on-the-way" by checking for "_styles" property with PropValue bag that fits the common style schema.
48
49
  */
49
50
  export const doUpdateElementProperty = ( params: OwnParams ) => {
50
- const { elementId, propertyName, propertyValue, elementType, customCssWriteMode = 'replace' } = params;
51
+ const { elementId, propertyValue, elementType, customCssWriteMode = 'replace' } = params;
52
+ const propertyName =
53
+ params.propertyName === '_styles'
54
+ ? params.propertyName
55
+ : resolveCanonicalPropName( elementType, params.propertyName );
51
56
  if ( propertyName === '_styles' ) {
52
57
  const elementStyles = getElementStyles( elementId ) || {};
53
58
  const propertyMapValue = propertyValue as Record< string, PropValue >;
@@ -0,0 +1,71 @@
1
+ import { getWidgetsCache } from '@elementor/editor-elements';
2
+ import { type PropsSchema } from '@elementor/editor-props';
3
+
4
+ function buildAliasToCanonicalMap( schema: PropsSchema ): Record< string, string > {
5
+ const aliasToCanonical: Record< string, string > = {};
6
+
7
+ for ( const [ canonical, propType ] of Object.entries( schema ) ) {
8
+ const aliases = propType.meta?.aliases;
9
+
10
+ if ( ! Array.isArray( aliases ) ) {
11
+ continue;
12
+ }
13
+
14
+ for ( const alias of aliases ) {
15
+ if ( typeof alias === 'string' && alias ) {
16
+ aliasToCanonical[ alias ] = canonical;
17
+ }
18
+ }
19
+ }
20
+
21
+ return aliasToCanonical;
22
+ }
23
+
24
+ export function resolveCanonicalPropName( elementType: string, propertyName: string ): string {
25
+ const schema = getWidgetsCache()?.[ elementType ]?.atomic_props_schema;
26
+
27
+ if ( ! schema || schema[ propertyName ] ) {
28
+ return propertyName;
29
+ }
30
+
31
+ return buildAliasToCanonicalMap( schema )[ propertyName ] ?? propertyName;
32
+ }
33
+
34
+ export function resolveCanonicalPropKeys(
35
+ elementType: string,
36
+ props: Record< string, unknown >
37
+ ): Record< string, unknown > {
38
+ const schema = getWidgetsCache()?.[ elementType ]?.atomic_props_schema;
39
+
40
+ if ( ! schema ) {
41
+ return { ...props };
42
+ }
43
+
44
+ const aliasToCanonical = buildAliasToCanonicalMap( schema );
45
+ const resolved: Record< string, unknown > = {};
46
+
47
+ for ( const [ key, value ] of Object.entries( props ) ) {
48
+ if ( schema[ key ] ) {
49
+ resolved[ key ] = value;
50
+ }
51
+ }
52
+
53
+ for ( const [ key, value ] of Object.entries( props ) ) {
54
+ if ( schema[ key ] ) {
55
+ continue;
56
+ }
57
+
58
+ const canonical = aliasToCanonical[ key ];
59
+
60
+ if ( ! canonical ) {
61
+ resolved[ key ] = value;
62
+ continue;
63
+ }
64
+
65
+ if ( ! Object.prototype.hasOwnProperty.call( resolved, canonical ) ) {
66
+ resolved[ canonical ] = value;
67
+ }
68
+ }
69
+
70
+ return resolved;
71
+ }