@elementor/editor-canvas 4.2.0-938 → 4.2.0-940
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 +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +187 -95
- package/dist/index.mjs +127 -35
- package/package.json +19 -19
- package/src/hooks/__tests__/use-style-prop-resolver.test.ts +35 -26
- package/src/hooks/use-style-prop-resolver.ts +3 -6
- package/src/init-style-transformers.ts +2 -0
- package/src/mcp/resources/document-structure-resource.ts +4 -1
- package/src/mcp/tools/configure-element/tool.ts +17 -4
- package/src/mcp/utils/__tests__/do-update-element-property.test.ts +43 -0
- package/src/mcp/utils/__tests__/resolve-canonical-prop-name.test.ts +111 -0
- package/src/mcp/utils/do-update-element-property.ts +6 -1
- package/src/mcp/utils/resolve-canonical-prop-name.ts +71 -0
- package/src/renderers/__tests__/create-props-resolver.test.ts +12 -2
- package/src/renderers/__tests__/create-styles-renderer.test.ts +30 -0
- package/src/renderers/__tests__/enqueue-font-from-style-prop.test.ts +29 -0
- package/src/renderers/create-props-resolver.ts +2 -2
- package/src/renderers/create-styles-renderer.ts +1 -1
- package/src/renderers/enqueue-font-from-style-prop.ts +34 -0
- package/src/transformers/styles/__tests__/font-family-transformer.test.ts +20 -0
- package/src/transformers/styles/font-family-transformer.ts +18 -0
package/dist/index.mjs
CHANGED
|
@@ -1396,7 +1396,7 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
|
|
|
1396
1396
|
Object.entries(schema2).map(async ([key, type]) => {
|
|
1397
1397
|
const value = props[key] ?? type.default;
|
|
1398
1398
|
const transformed = await transform({ value, key, type, signal, renderContext });
|
|
1399
|
-
onPropResolve?.({ key, value: transformed });
|
|
1399
|
+
onPropResolve?.({ key, value: transformed, propValue: value, propType: type });
|
|
1400
1400
|
if (isMultiProps(transformed)) {
|
|
1401
1401
|
return getMultiPropsValue(transformed);
|
|
1402
1402
|
}
|
|
@@ -1466,6 +1466,27 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
|
|
|
1466
1466
|
return resolve;
|
|
1467
1467
|
}
|
|
1468
1468
|
|
|
1469
|
+
// src/renderers/enqueue-font-from-style-prop.ts
|
|
1470
|
+
import { getPropSchemaFromCache, isTransformable as isTransformable2 } from "@elementor/editor-props";
|
|
1471
|
+
var maybeEnqueueFontFromStyleProp = (propType, propValue, enqueue) => {
|
|
1472
|
+
if (!isTransformable2(propValue) || propValue.disabled) {
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
const typeKey = propType.kind === "union" ? propValue.$$type : propType.key;
|
|
1476
|
+
const propTypeUtil = getPropSchemaFromCache(typeKey);
|
|
1477
|
+
if (!propTypeUtil || !("getEnqueueFontFamily" in propTypeUtil) || typeof propTypeUtil.getEnqueueFontFamily !== "function") {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
const stored = propValue.value;
|
|
1481
|
+
if (typeof stored !== "string") {
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
const font = propTypeUtil.getEnqueueFontFamily(stored);
|
|
1485
|
+
if (font) {
|
|
1486
|
+
enqueue(font);
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1469
1490
|
// src/transformers/create-transformers-registry.ts
|
|
1470
1491
|
function createTransformersRegistry() {
|
|
1471
1492
|
const transformers = {};
|
|
@@ -1498,11 +1519,8 @@ function useStylePropResolver() {
|
|
|
1498
1519
|
return createPropsResolver({
|
|
1499
1520
|
transformers: styleTransformersRegistry,
|
|
1500
1521
|
schema: getStylesSchema(),
|
|
1501
|
-
onPropResolve: ({
|
|
1502
|
-
|
|
1503
|
-
return;
|
|
1504
|
-
}
|
|
1505
|
-
enqueueFont(value);
|
|
1522
|
+
onPropResolve: ({ propValue, propType }) => {
|
|
1523
|
+
maybeEnqueueFontFromStyleProp(propType, propValue, enqueueFont);
|
|
1506
1524
|
}
|
|
1507
1525
|
});
|
|
1508
1526
|
}, []);
|
|
@@ -2432,6 +2450,18 @@ var flexTransformer = createTransformer((value) => {
|
|
|
2432
2450
|
return null;
|
|
2433
2451
|
});
|
|
2434
2452
|
|
|
2453
|
+
// src/transformers/styles/font-family-transformer.ts
|
|
2454
|
+
var fontFamilyTransformer = createTransformer((value) => {
|
|
2455
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
2456
|
+
return null;
|
|
2457
|
+
}
|
|
2458
|
+
const trimmed = value.trim();
|
|
2459
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
2460
|
+
return trimmed;
|
|
2461
|
+
}
|
|
2462
|
+
return `"${trimmed}"`;
|
|
2463
|
+
});
|
|
2464
|
+
|
|
2435
2465
|
// src/transformers/styles/grid-track-renderer.ts
|
|
2436
2466
|
var GRID_TRACK_PROPERTIES = /* @__PURE__ */ new Set(["grid-template-columns", "grid-template-rows"]);
|
|
2437
2467
|
var isGridTrackProperty = (cssProperty) => GRID_TRACK_PROPERTIES.has(cssProperty);
|
|
@@ -2583,7 +2613,7 @@ var mapToTransitionString = (value, allowedProperties) => {
|
|
|
2583
2613
|
|
|
2584
2614
|
// src/init-style-transformers.ts
|
|
2585
2615
|
function initStyleTransformers() {
|
|
2586
|
-
styleTransformersRegistry.register("size", sizeTransformer).register("grid-track-size", gridTrackSizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
|
|
2616
|
+
styleTransformersRegistry.register("font-family", fontFamilyTransformer).register("size", sizeTransformer).register("grid-track-size", gridTrackSizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
|
|
2587
2617
|
"dimensions",
|
|
2588
2618
|
createMultiPropsTransformer(
|
|
2589
2619
|
["block-start", "block-end", "inline-start", "inline-end"],
|
|
@@ -4164,7 +4194,7 @@ function extractElementData(element) {
|
|
|
4164
4194
|
widgetType: model.widgetType || void 0,
|
|
4165
4195
|
version: resolveElementVersion(element)
|
|
4166
4196
|
};
|
|
4167
|
-
const title = model.title || element.model?.editor_settings?.title;
|
|
4197
|
+
const title = model.title || element.model?.editor_settings?.title || element.model.getTitle?.();
|
|
4168
4198
|
if (title) {
|
|
4169
4199
|
result.title = title;
|
|
4170
4200
|
}
|
|
@@ -4599,7 +4629,7 @@ import {
|
|
|
4599
4629
|
createElement as createElement13,
|
|
4600
4630
|
deleteElement as deleteElement2,
|
|
4601
4631
|
getContainer as getContainer5,
|
|
4602
|
-
getWidgetsCache as
|
|
4632
|
+
getWidgetsCache as getWidgetsCache9
|
|
4603
4633
|
} from "@elementor/editor-elements";
|
|
4604
4634
|
|
|
4605
4635
|
// src/composition-builder/composition-builder.ts
|
|
@@ -4608,18 +4638,18 @@ import {
|
|
|
4608
4638
|
deleteElement,
|
|
4609
4639
|
generateElementId as generateElementId2,
|
|
4610
4640
|
getContainer as getContainer4,
|
|
4611
|
-
getWidgetsCache as
|
|
4641
|
+
getWidgetsCache as getWidgetsCache8
|
|
4612
4642
|
} from "@elementor/editor-elements";
|
|
4613
4643
|
|
|
4614
4644
|
// src/mcp/utils/do-update-element-property.ts
|
|
4615
4645
|
import {
|
|
4616
4646
|
createElementStyle,
|
|
4617
4647
|
getElementStyles,
|
|
4618
|
-
getWidgetsCache as
|
|
4648
|
+
getWidgetsCache as getWidgetsCache7,
|
|
4619
4649
|
updateElementSettings,
|
|
4620
4650
|
updateElementStyle
|
|
4621
4651
|
} from "@elementor/editor-elements";
|
|
4622
|
-
import { getPropSchemaFromCache, Schema as Schema3 } from "@elementor/editor-props";
|
|
4652
|
+
import { getPropSchemaFromCache as getPropSchemaFromCache2, Schema as Schema3 } from "@elementor/editor-props";
|
|
4623
4653
|
import { getStylesSchema as getStylesSchema2, getVariantByMeta } from "@elementor/editor-styles";
|
|
4624
4654
|
import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
|
|
4625
4655
|
|
|
@@ -4637,6 +4667,58 @@ var readStoredCustomCssText = (raw) => {
|
|
|
4637
4667
|
}
|
|
4638
4668
|
};
|
|
4639
4669
|
|
|
4670
|
+
// src/mcp/utils/resolve-canonical-prop-name.ts
|
|
4671
|
+
import { getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
|
|
4672
|
+
function buildAliasToCanonicalMap(schema2) {
|
|
4673
|
+
const aliasToCanonical = {};
|
|
4674
|
+
for (const [canonical, propType] of Object.entries(schema2)) {
|
|
4675
|
+
const aliases = propType.meta?.aliases;
|
|
4676
|
+
if (!Array.isArray(aliases)) {
|
|
4677
|
+
continue;
|
|
4678
|
+
}
|
|
4679
|
+
for (const alias of aliases) {
|
|
4680
|
+
if (typeof alias === "string" && alias) {
|
|
4681
|
+
aliasToCanonical[alias] = canonical;
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
return aliasToCanonical;
|
|
4686
|
+
}
|
|
4687
|
+
function resolveCanonicalPropName(elementType, propertyName) {
|
|
4688
|
+
const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
|
|
4689
|
+
if (!schema2 || schema2[propertyName]) {
|
|
4690
|
+
return propertyName;
|
|
4691
|
+
}
|
|
4692
|
+
return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
|
|
4693
|
+
}
|
|
4694
|
+
function resolveCanonicalPropKeys(elementType, props) {
|
|
4695
|
+
const schema2 = getWidgetsCache6()?.[elementType]?.atomic_props_schema;
|
|
4696
|
+
if (!schema2) {
|
|
4697
|
+
return { ...props };
|
|
4698
|
+
}
|
|
4699
|
+
const aliasToCanonical = buildAliasToCanonicalMap(schema2);
|
|
4700
|
+
const resolved = {};
|
|
4701
|
+
for (const [key, value] of Object.entries(props)) {
|
|
4702
|
+
if (schema2[key]) {
|
|
4703
|
+
resolved[key] = value;
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4706
|
+
for (const [key, value] of Object.entries(props)) {
|
|
4707
|
+
if (schema2[key]) {
|
|
4708
|
+
continue;
|
|
4709
|
+
}
|
|
4710
|
+
const canonical = aliasToCanonical[key];
|
|
4711
|
+
if (!canonical) {
|
|
4712
|
+
resolved[key] = value;
|
|
4713
|
+
continue;
|
|
4714
|
+
}
|
|
4715
|
+
if (!Object.prototype.hasOwnProperty.call(resolved, canonical)) {
|
|
4716
|
+
resolved[canonical] = value;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
return resolved;
|
|
4720
|
+
}
|
|
4721
|
+
|
|
4640
4722
|
// src/mcp/utils/do-update-element-property.ts
|
|
4641
4723
|
var LOCAL_STYLE_META = {
|
|
4642
4724
|
breakpoint: "desktop",
|
|
@@ -4653,7 +4735,8 @@ function resolvePropValue(value, forceKey) {
|
|
|
4653
4735
|
});
|
|
4654
4736
|
}
|
|
4655
4737
|
var doUpdateElementProperty = (params) => {
|
|
4656
|
-
const { elementId,
|
|
4738
|
+
const { elementId, propertyValue, elementType, customCssWriteMode = "replace" } = params;
|
|
4739
|
+
const propertyName = params.propertyName === "_styles" ? params.propertyName : resolveCanonicalPropName(elementType, params.propertyName);
|
|
4657
4740
|
if (propertyName === "_styles") {
|
|
4658
4741
|
const elementStyles = getElementStyles(elementId) || {};
|
|
4659
4742
|
const propertyMapValue = propertyValue;
|
|
@@ -4702,7 +4785,7 @@ var doUpdateElementProperty = (params) => {
|
|
|
4702
4785
|
}
|
|
4703
4786
|
if (propertyRawSchema.kind === "plain") {
|
|
4704
4787
|
if (typeof propertyMapValue[stylePropName] !== "object") {
|
|
4705
|
-
const propUtil =
|
|
4788
|
+
const propUtil = getPropSchemaFromCache2(propertyRawSchema.key);
|
|
4706
4789
|
if (propUtil) {
|
|
4707
4790
|
const plainValue = propUtil.create(propertyMapValue[stylePropName]);
|
|
4708
4791
|
propertyMapValue[stylePropName] = plainValue;
|
|
@@ -4741,7 +4824,7 @@ var doUpdateElementProperty = (params) => {
|
|
|
4741
4824
|
}
|
|
4742
4825
|
return;
|
|
4743
4826
|
}
|
|
4744
|
-
const elementPropSchema =
|
|
4827
|
+
const elementPropSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
|
|
4745
4828
|
if (!elementPropSchema) {
|
|
4746
4829
|
throw new Error(`No prop schema found for element type: ${elementType}`);
|
|
4747
4830
|
}
|
|
@@ -4824,7 +4907,7 @@ var CompositionBuilder = class _CompositionBuilder {
|
|
|
4824
4907
|
api = {
|
|
4825
4908
|
createElement: createElement12,
|
|
4826
4909
|
deleteElement,
|
|
4827
|
-
getWidgetsCache:
|
|
4910
|
+
getWidgetsCache: getWidgetsCache8,
|
|
4828
4911
|
generateElementId: generateElementId2,
|
|
4829
4912
|
getContainer: getContainer4,
|
|
4830
4913
|
doUpdateElementProperty
|
|
@@ -5346,7 +5429,7 @@ var initBuildCompositionsTool = (reg) => {
|
|
|
5346
5429
|
const { xmlStructure, elementConfig, stylesConfig } = adaptLeafRootParams({
|
|
5347
5430
|
...rawParams,
|
|
5348
5431
|
stylesConfig: convertedStyles,
|
|
5349
|
-
widgetsCache:
|
|
5432
|
+
widgetsCache: getWidgetsCache9() ?? {}
|
|
5350
5433
|
});
|
|
5351
5434
|
let generatedXML = "";
|
|
5352
5435
|
const errors = [];
|
|
@@ -5358,7 +5441,7 @@ var initBuildCompositionsTool = (reg) => {
|
|
|
5358
5441
|
const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
|
|
5359
5442
|
createElement: createElement13,
|
|
5360
5443
|
deleteElement: deleteElement2,
|
|
5361
|
-
getWidgetsCache:
|
|
5444
|
+
getWidgetsCache: getWidgetsCache9
|
|
5362
5445
|
});
|
|
5363
5446
|
compositionBuilder.setElementConfig(elementConfig);
|
|
5364
5447
|
compositionBuilder.setStylesConfig(stylesConfig);
|
|
@@ -5443,7 +5526,7 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
|
|
|
5443
5526
|
if (doc.querySelector("parsererror")) {
|
|
5444
5527
|
throw new Error("Failed to parse XML string: " + doc);
|
|
5445
5528
|
}
|
|
5446
|
-
const widgetsCache =
|
|
5529
|
+
const widgetsCache = getWidgetsCache9() ?? {};
|
|
5447
5530
|
for (const node of doc.querySelectorAll("*")) {
|
|
5448
5531
|
const type = node.tagName;
|
|
5449
5532
|
const widgetData = widgetsCache[type];
|
|
@@ -5460,10 +5543,10 @@ function assertCompositionXmlUsesV4WidgetsOnly(xmlStructure) {
|
|
|
5460
5543
|
}
|
|
5461
5544
|
|
|
5462
5545
|
// src/mcp/tools/configure-element/tool.ts
|
|
5463
|
-
import { getWidgetsCache as
|
|
5546
|
+
import { getContainer as getContainer6, getWidgetsCache as getWidgetsCache11 } from "@elementor/editor-elements";
|
|
5464
5547
|
|
|
5465
5548
|
// src/mcp/utils/validate-input.ts
|
|
5466
|
-
import { getWidgetsCache as
|
|
5549
|
+
import { getWidgetsCache as getWidgetsCache10 } from "@elementor/editor-elements";
|
|
5467
5550
|
import { Schema as Schema4 } from "@elementor/editor-props";
|
|
5468
5551
|
import { getStylesSchema as getStylesSchema3 } from "@elementor/editor-styles";
|
|
5469
5552
|
var _widgetsSchema = null;
|
|
@@ -5471,7 +5554,7 @@ var validateInput = {
|
|
|
5471
5554
|
get widgetsSchema() {
|
|
5472
5555
|
if (!_widgetsSchema) {
|
|
5473
5556
|
const schema2 = {};
|
|
5474
|
-
const cache =
|
|
5557
|
+
const cache = getWidgetsCache10();
|
|
5475
5558
|
if (!cache) {
|
|
5476
5559
|
return {};
|
|
5477
5560
|
}
|
|
@@ -5712,19 +5795,28 @@ var initConfigureElementTool = (reg) => {
|
|
|
5712
5795
|
{ description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
|
|
5713
5796
|
],
|
|
5714
5797
|
handler: async ({ elementId, propertiesToChange, elementType, style }) => {
|
|
5715
|
-
const widgetData =
|
|
5798
|
+
const widgetData = getWidgetsCache11()?.[elementType];
|
|
5716
5799
|
if (!widgetData) {
|
|
5717
5800
|
throw new Error(
|
|
5718
5801
|
`Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
|
|
5719
5802
|
);
|
|
5720
5803
|
}
|
|
5804
|
+
const container = getContainer6(elementId);
|
|
5805
|
+
if (!container) {
|
|
5806
|
+
throw new Error(`Element with id ${elementId} not found`);
|
|
5807
|
+
}
|
|
5808
|
+
const isElementTypeMatchingId = container.settings.get("widgetType") === elementType || container.type === elementType;
|
|
5809
|
+
if (!isElementTypeMatchingId) {
|
|
5810
|
+
throw new Error(`Element with ID ${elementId} is not of type ${elementType}`);
|
|
5811
|
+
}
|
|
5721
5812
|
if (!widgetData.atomic_props_schema) {
|
|
5722
5813
|
throw new Error(
|
|
5723
5814
|
`This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
|
|
5724
5815
|
);
|
|
5725
5816
|
}
|
|
5726
|
-
const
|
|
5727
|
-
const
|
|
5817
|
+
const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
|
|
5818
|
+
const toUpdate = Object.entries(propertiesToUpdate);
|
|
5819
|
+
const { valid, errors } = validateInput.validatePropSchema(elementType, propertiesToUpdate);
|
|
5728
5820
|
if (!valid) {
|
|
5729
5821
|
const errorMessage = `Failed to configure element "${elementId}" due to invalid properties: ${errors?.join(
|
|
5730
5822
|
"\n- "
|
|
@@ -5804,7 +5896,7 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
|
|
|
5804
5896
|
}
|
|
5805
5897
|
|
|
5806
5898
|
// src/mcp/tools/get-element-config/tool.ts
|
|
5807
|
-
import { getContainer as
|
|
5899
|
+
import { getContainer as getContainer7, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache12 } from "@elementor/editor-elements";
|
|
5808
5900
|
import { Schema as Schema5 } from "@elementor/editor-props";
|
|
5809
5901
|
import { z as z3 } from "@elementor/schema";
|
|
5810
5902
|
var schema = {
|
|
@@ -5839,12 +5931,12 @@ var initGetElementConfigTool = (reg) => {
|
|
|
5839
5931
|
schema,
|
|
5840
5932
|
outputSchema: outputSchema3,
|
|
5841
5933
|
handler: async ({ elementId }) => {
|
|
5842
|
-
const element =
|
|
5934
|
+
const element = getContainer7(elementId);
|
|
5843
5935
|
if (!element) {
|
|
5844
5936
|
throw new Error(`Element with ID ${elementId} not found.`);
|
|
5845
5937
|
}
|
|
5846
5938
|
const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
|
|
5847
|
-
const widgetData =
|
|
5939
|
+
const widgetData = getWidgetsCache12()?.[elementType];
|
|
5848
5940
|
if (!widgetData) {
|
|
5849
5941
|
throw new Error(
|
|
5850
5942
|
`Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
|
|
@@ -5856,7 +5948,7 @@ var initGetElementConfigTool = (reg) => {
|
|
|
5856
5948
|
);
|
|
5857
5949
|
}
|
|
5858
5950
|
const elementRawSettings = element.settings;
|
|
5859
|
-
const propSchema =
|
|
5951
|
+
const propSchema = getWidgetsCache12()?.[elementType]?.atomic_props_schema;
|
|
5860
5952
|
if (!elementRawSettings || !propSchema) {
|
|
5861
5953
|
throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
|
|
5862
5954
|
}
|
|
@@ -6108,7 +6200,7 @@ function shouldBlock(sourceElements, targetElements) {
|
|
|
6108
6200
|
}
|
|
6109
6201
|
|
|
6110
6202
|
// src/style-commands/paste-style.ts
|
|
6111
|
-
import { getContainer as
|
|
6203
|
+
import { getContainer as getContainer8, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
|
|
6112
6204
|
import { classesPropTypeUtil } from "@elementor/editor-props";
|
|
6113
6205
|
import {
|
|
6114
6206
|
__privateListenTo as listenTo5,
|
|
@@ -6117,7 +6209,7 @@ import {
|
|
|
6117
6209
|
} from "@elementor/editor-v1-adapters";
|
|
6118
6210
|
|
|
6119
6211
|
// src/utils/command-utils.ts
|
|
6120
|
-
import { getElementLabel as getElementLabel2, getWidgetsCache as
|
|
6212
|
+
import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache13 } from "@elementor/editor-elements";
|
|
6121
6213
|
import { CLASSES_PROP_KEY } from "@elementor/editor-props";
|
|
6122
6214
|
import { __ as __5 } from "@wordpress/i18n";
|
|
6123
6215
|
function hasAtomicWidgets(args) {
|
|
@@ -6142,7 +6234,7 @@ function getClassesProp(container) {
|
|
|
6142
6234
|
}
|
|
6143
6235
|
function getContainerSchema(container) {
|
|
6144
6236
|
const type = container?.model.get("widgetType") || container?.model.get("elType");
|
|
6145
|
-
const widgetsCache =
|
|
6237
|
+
const widgetsCache = getWidgetsCache13();
|
|
6146
6238
|
const elementType = widgetsCache?.[type];
|
|
6147
6239
|
return elementType?.atomic_props_schema ?? null;
|
|
6148
6240
|
}
|
|
@@ -6261,7 +6353,7 @@ function pasteStyles(args, pasteLocalStyle) {
|
|
|
6261
6353
|
}
|
|
6262
6354
|
const clipboardElements = getClipboardElements(storageKey);
|
|
6263
6355
|
const [clipboardElement] = clipboardElements ?? [];
|
|
6264
|
-
const clipboardContainer =
|
|
6356
|
+
const clipboardContainer = getContainer8(clipboardElement.id);
|
|
6265
6357
|
if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
|
|
6266
6358
|
return;
|
|
6267
6359
|
}
|
|
@@ -6538,10 +6630,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
|
|
|
6538
6630
|
}
|
|
6539
6631
|
|
|
6540
6632
|
// src/utils/after-render.ts
|
|
6541
|
-
import { getContainer as
|
|
6633
|
+
import { getContainer as getContainer9 } from "@elementor/editor-elements";
|
|
6542
6634
|
function doAfterRender(elementIds, callback) {
|
|
6543
6635
|
const pending = elementIds.map((elementId) => {
|
|
6544
|
-
const view =
|
|
6636
|
+
const view = getContainer9(elementId)?.view;
|
|
6545
6637
|
if (!view || !hasDoAfterRender(view)) {
|
|
6546
6638
|
return void 0;
|
|
6547
6639
|
}
|
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-
|
|
4
|
+
"version": "4.2.0-940",
|
|
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-
|
|
40
|
+
"@elementor/editor": "4.2.0-940",
|
|
41
41
|
"dompurify": "^3.2.6",
|
|
42
|
-
"@elementor/editor-controls": "4.2.0-
|
|
43
|
-
"@elementor/editor-documents": "4.2.0-
|
|
44
|
-
"@elementor/editor-elements": "4.2.0-
|
|
45
|
-
"@elementor/editor-interactions": "4.2.0-
|
|
46
|
-
"@elementor/editor-mcp": "4.2.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.2.0-
|
|
48
|
-
"@elementor/editor-props": "4.2.0-
|
|
49
|
-
"@elementor/editor-responsive": "4.2.0-
|
|
50
|
-
"@elementor/editor-styles": "4.2.0-
|
|
51
|
-
"@elementor/editor-styles-repository": "4.2.0-
|
|
52
|
-
"@elementor/editor-ui": "4.2.0-
|
|
53
|
-
"@elementor/editor-v1-adapters": "4.2.0-
|
|
54
|
-
"@elementor/http-client": "4.2.0-
|
|
55
|
-
"@elementor/schema": "4.2.0-
|
|
56
|
-
"@elementor/twing": "4.2.0-
|
|
42
|
+
"@elementor/editor-controls": "4.2.0-940",
|
|
43
|
+
"@elementor/editor-documents": "4.2.0-940",
|
|
44
|
+
"@elementor/editor-elements": "4.2.0-940",
|
|
45
|
+
"@elementor/editor-interactions": "4.2.0-940",
|
|
46
|
+
"@elementor/editor-mcp": "4.2.0-940",
|
|
47
|
+
"@elementor/editor-notifications": "4.2.0-940",
|
|
48
|
+
"@elementor/editor-props": "4.2.0-940",
|
|
49
|
+
"@elementor/editor-responsive": "4.2.0-940",
|
|
50
|
+
"@elementor/editor-styles": "4.2.0-940",
|
|
51
|
+
"@elementor/editor-styles-repository": "4.2.0-940",
|
|
52
|
+
"@elementor/editor-ui": "4.2.0-940",
|
|
53
|
+
"@elementor/editor-v1-adapters": "4.2.0-940",
|
|
54
|
+
"@elementor/http-client": "4.2.0-940",
|
|
55
|
+
"@elementor/schema": "4.2.0-940",
|
|
56
|
+
"@elementor/twing": "4.2.0-940",
|
|
57
57
|
"@elementor/ui": "1.37.5",
|
|
58
|
-
"@elementor/utils": "4.2.0-
|
|
59
|
-
"@elementor/wp-media": "4.2.0-
|
|
58
|
+
"@elementor/utils": "4.2.0-940",
|
|
59
|
+
"@elementor/wp-media": "4.2.0-940",
|
|
60
60
|
"@floating-ui/react": "^0.27.5",
|
|
61
61
|
"@wordpress/i18n": "^5.13.0"
|
|
62
62
|
},
|
|
@@ -1,51 +1,60 @@
|
|
|
1
1
|
import { createMockPropType } from 'test-utils';
|
|
2
|
-
import {
|
|
2
|
+
import { fontFamilyPropTypeUtil } from '@elementor/editor-props';
|
|
3
|
+
import { type BreakpointsMap } from '@elementor/editor-responsive';
|
|
3
4
|
import { getStylesSchema } from '@elementor/editor-styles';
|
|
4
5
|
import { enqueueFont } from '@elementor/editor-v1-adapters';
|
|
5
|
-
import {
|
|
6
|
+
import { renderHook } from '@testing-library/react';
|
|
6
7
|
|
|
7
8
|
import { initStyleTransformers } from '../../init-style-transformers';
|
|
9
|
+
import { createStylesRenderer } from '../../renderers/create-styles-renderer';
|
|
8
10
|
import { useStylePropResolver } from '../use-style-prop-resolver';
|
|
9
11
|
|
|
10
12
|
jest.mock( '@elementor/editor-v1-adapters' );
|
|
11
|
-
jest.mock( '@elementor/editor-styles' )
|
|
13
|
+
jest.mock( '@elementor/editor-styles', () => ( {
|
|
14
|
+
...jest.requireActual( '@elementor/editor-styles' ),
|
|
15
|
+
getStylesSchema: jest.fn(),
|
|
16
|
+
} ) );
|
|
12
17
|
|
|
13
18
|
describe( 'useStylePropResolver', () => {
|
|
14
|
-
it( 'should
|
|
19
|
+
it( 'should enqueue fonts from stored props when rendering styles', async () => {
|
|
15
20
|
// Arrange.
|
|
16
21
|
initStyleTransformers();
|
|
17
22
|
|
|
18
23
|
jest.mocked( getStylesSchema ).mockReturnValue( {
|
|
19
|
-
'font-family': createMockPropType( { key: '
|
|
20
|
-
|
|
24
|
+
'font-family': createMockPropType( { key: 'font-family', kind: 'plain' } ),
|
|
25
|
+
color: createMockPropType( { key: 'string', kind: 'plain' } ),
|
|
21
26
|
} );
|
|
22
27
|
|
|
23
28
|
const { result } = renderHook( useStylePropResolver );
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
resolve( {
|
|
30
|
-
props: {
|
|
31
|
-
'another-prop': stringPropTypeUtil.create( 'value' ),
|
|
32
|
-
},
|
|
33
|
-
} )
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// Assert.
|
|
37
|
-
expect( enqueueFont ).not.toHaveBeenCalled();
|
|
30
|
+
const view = createStylesRenderer( {
|
|
31
|
+
resolve: result.current,
|
|
32
|
+
breakpoints: {} as BreakpointsMap,
|
|
33
|
+
} );
|
|
38
34
|
|
|
39
35
|
// Act.
|
|
40
|
-
await
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
await view( {
|
|
37
|
+
styles: [
|
|
38
|
+
{
|
|
39
|
+
id: 'test-style',
|
|
40
|
+
type: 'class',
|
|
41
|
+
cssName: 'test-style',
|
|
42
|
+
label: 'Test style',
|
|
43
|
+
variants: [
|
|
44
|
+
{
|
|
45
|
+
meta: { breakpoint: null, state: null },
|
|
46
|
+
props: {
|
|
47
|
+
'font-family': fontFamilyPropTypeUtil.create( 'Open Sans' ),
|
|
48
|
+
},
|
|
49
|
+
custom_css: null,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
44
52
|
},
|
|
45
|
-
|
|
46
|
-
);
|
|
53
|
+
],
|
|
54
|
+
} );
|
|
47
55
|
|
|
48
56
|
// Assert.
|
|
49
|
-
expect( enqueueFont ).toHaveBeenCalledWith( '
|
|
57
|
+
expect( enqueueFont ).toHaveBeenCalledWith( 'Open Sans' );
|
|
58
|
+
expect( enqueueFont ).toHaveBeenCalledTimes( 1 );
|
|
50
59
|
} );
|
|
51
60
|
} );
|
|
@@ -3,6 +3,7 @@ import { getStylesSchema } from '@elementor/editor-styles';
|
|
|
3
3
|
import { enqueueFont } from '@elementor/editor-v1-adapters';
|
|
4
4
|
|
|
5
5
|
import { createPropsResolver } from '../renderers/create-props-resolver';
|
|
6
|
+
import { maybeEnqueueFontFromStyleProp } from '../renderers/enqueue-font-from-style-prop';
|
|
6
7
|
import { styleTransformersRegistry } from '../style-transformers-registry';
|
|
7
8
|
|
|
8
9
|
export function useStylePropResolver() {
|
|
@@ -10,12 +11,8 @@ export function useStylePropResolver() {
|
|
|
10
11
|
return createPropsResolver( {
|
|
11
12
|
transformers: styleTransformersRegistry,
|
|
12
13
|
schema: getStylesSchema(),
|
|
13
|
-
onPropResolve: ( {
|
|
14
|
-
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
enqueueFont( value );
|
|
14
|
+
onPropResolve: ( { propValue, propType } ) => {
|
|
15
|
+
maybeEnqueueFontFromStyleProp( propType, propValue, enqueueFont );
|
|
19
16
|
},
|
|
20
17
|
} );
|
|
21
18
|
}, [] );
|
|
@@ -13,6 +13,7 @@ import { createCombineArrayTransformer } from './transformers/styles/create-comb
|
|
|
13
13
|
import { createMultiPropsTransformer } from './transformers/styles/create-multi-props-transformer';
|
|
14
14
|
import { filterTransformer } from './transformers/styles/filter-transformer';
|
|
15
15
|
import { flexTransformer } from './transformers/styles/flex-transformer';
|
|
16
|
+
import { fontFamilyTransformer } from './transformers/styles/font-family-transformer';
|
|
16
17
|
import { gridTrackSizeTransformer } from './transformers/styles/grid-track-size-transformer';
|
|
17
18
|
import { perspectiveOriginTransformer } from './transformers/styles/perspective-origin-transformer';
|
|
18
19
|
import { positionTransformer } from './transformers/styles/position-transformer';
|
|
@@ -30,6 +31,7 @@ import { transitionTransformer } from './transformers/styles/transition-transfor
|
|
|
30
31
|
|
|
31
32
|
export function initStyleTransformers() {
|
|
32
33
|
styleTransformersRegistry
|
|
34
|
+
.register( 'font-family', fontFamilyTransformer )
|
|
33
35
|
.register( 'size', sizeTransformer )
|
|
34
36
|
.register( 'grid-track-size', gridTrackSizeTransformer )
|
|
35
37
|
.register( 'shadow', shadowTransformer )
|
|
@@ -136,7 +136,10 @@ function extractElementData( element: UnknownVersionElementInstanceData ): Recor
|
|
|
136
136
|
version: resolveElementVersion( element ),
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
-
const 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
|
|
51
|
-
const
|
|
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( {
|