@elementor/editor-canvas 4.3.0-998 → 4.3.0-beta1
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 +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +452 -408
- package/dist/index.mjs +434 -386
- package/package.json +20 -20
- package/src/init-settings-transformers.ts +4 -0
- package/src/init-style-transformers.ts +2 -2
- package/src/init.tsx +5 -4
- package/src/legacy/__tests__/create-templated-element-type.test.ts +50 -0
- package/src/legacy/__tests__/list-type.test.ts +89 -0
- package/src/legacy/create-nested-templated-element-type.ts +3 -1
- package/src/legacy/create-templated-element-type.ts +5 -2
- package/src/legacy/list-type.ts +63 -0
- package/src/legacy/replacements/inline-editing/__tests__/inline-editing-eligibility.test.ts +7 -7
- package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +22 -9
- package/src/legacy/replacements/inline-editing/inline-editing-eligibility.ts +12 -3
- package/src/legacy/tabs-model-extensions.ts +2 -5
- package/src/legacy/twig-rendering-utils.ts +11 -2
- package/src/legacy/types.ts +4 -0
- package/src/mcp/canvas-mcp.ts +2 -6
- package/src/mcp/mcp-description.ts +18 -30
- package/src/mcp/resources/__tests__/available-widgets-resource.test.ts +22 -13
- package/src/mcp/resources/__tests__/dynamic-tags-resource.test.ts +22 -30
- package/src/mcp/resources/__tests__/widgets-schema-resource.test.ts +11 -6
- package/src/mcp/resources/available-widgets-resource.ts +13 -10
- package/src/mcp/resources/dynamic-tags-resource.ts +6 -15
- package/src/mcp/resources/widgets-schema-resource.ts +8 -5
- package/src/mcp/tools/configure-element/__tests__/tool.test.ts +130 -0
- package/src/mcp/tools/configure-element/prompt.ts +3 -6
- package/src/mcp/tools/configure-element/schema.ts +6 -0
- package/src/mcp/tools/configure-element/tool.ts +11 -1
- package/src/mcp/tools/get-page-structure/tool.ts +73 -0
- package/src/mcp/utils/__tests__/do-update-element-property.test.ts +27 -1
- package/src/mcp/utils/do-update-element-property.ts +18 -6
- package/src/mcp/utils/get-mcp-error-message.ts +16 -0
- package/src/renderers/__tests__/compute-html-tag.test.ts +55 -0
- package/src/renderers/__tests__/create-dom-renderer.test.ts +60 -0
- package/src/renderers/__tests__/fixtures/html-tag-computer-cases.json +87 -0
- package/src/renderers/compute-html-tag.ts +73 -0
- package/src/renderers/create-dom-renderer.ts +13 -22
- package/src/transformers/settings/escaped-html-transformer.ts +6 -0
- package/src/transformers/shared/__tests__/icon-transformer.test.ts +74 -0
- package/src/transformers/shared/icon-transformer.ts +122 -0
- package/src/transformers/shared/process-svg-content.ts +26 -0
- package/src/transformers/shared/svg-src-transformer.ts +1 -26
- package/src/utils/__tests__/sanitize-escaped-html.test.ts +105 -0
- package/src/utils/sanitize-escaped-html.ts +32 -0
- package/src/mcp/tools/build-composition/tool.ts +0 -133
- package/src/mcp/tools/create-element/tool.ts +0 -61
- package/src/mcp/tools/get-element-config/tool.ts +0 -114
package/dist/index.mjs
CHANGED
|
@@ -12,10 +12,10 @@ var BEST_PRACTICES_FULL_URI = `${CANVAS_SERVER_NAME}_${BEST_PRACTICES_URI}`;
|
|
|
12
12
|
var MCP_PROXY_URL = "elementor/v1/mcp-proxy";
|
|
13
13
|
var listWidgetTypes = async () => {
|
|
14
14
|
const { data } = await httpService().post(MCP_PROXY_URL, {
|
|
15
|
-
tool: "list-
|
|
16
|
-
input: {}
|
|
15
|
+
tool: "list-widget-schemas",
|
|
16
|
+
input: { summary: true }
|
|
17
17
|
});
|
|
18
|
-
return (data.data ?? []).map((widget) => widget.type);
|
|
18
|
+
return (data.data?.widgets ?? []).map((widget) => widget.type);
|
|
19
19
|
};
|
|
20
20
|
var fetchWidgetSchema = async (widgetType) => {
|
|
21
21
|
const { data } = await httpService().post(MCP_PROXY_URL, {
|
|
@@ -47,13 +47,13 @@ var initWidgetsSchemaResource = (reg) => {
|
|
|
47
47
|
if (!widgetType) {
|
|
48
48
|
throw new Error("No widget type provided.");
|
|
49
49
|
}
|
|
50
|
-
const
|
|
50
|
+
const schema = await fetchWidgetSchema(widgetType);
|
|
51
51
|
return {
|
|
52
52
|
contents: [
|
|
53
53
|
{
|
|
54
54
|
uri: uri.toString(),
|
|
55
55
|
mimeType: "application/json",
|
|
56
|
-
text: JSON.stringify(
|
|
56
|
+
text: JSON.stringify(schema)
|
|
57
57
|
}
|
|
58
58
|
]
|
|
59
59
|
};
|
|
@@ -1260,10 +1260,10 @@ var getMultiPropsValue = (multiProps) => {
|
|
|
1260
1260
|
// src/renderers/create-props-resolver.ts
|
|
1261
1261
|
var TRANSFORM_DEPTH_LIMIT = 3;
|
|
1262
1262
|
function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
|
|
1263
|
-
async function resolve({ props, schema
|
|
1264
|
-
|
|
1263
|
+
async function resolve({ props, schema, signal, renderContext }) {
|
|
1264
|
+
schema = schema ?? initialSchema;
|
|
1265
1265
|
const promises = Promise.all(
|
|
1266
|
-
Object.entries(
|
|
1266
|
+
Object.entries(schema).map(async ([key, type]) => {
|
|
1267
1267
|
const value = props[key] ?? type.default;
|
|
1268
1268
|
const transformed = await transform({ value, key, type, signal, renderContext });
|
|
1269
1269
|
onPropResolve?.({ key, value: transformed, propValue: value, propType: type });
|
|
@@ -1989,6 +1989,40 @@ var dateTimeTransformer = createTransformer((values) => {
|
|
|
1989
1989
|
}).join(" ");
|
|
1990
1990
|
});
|
|
1991
1991
|
|
|
1992
|
+
// src/utils/sanitize-escaped-html.ts
|
|
1993
|
+
import DOMPurify from "dompurify";
|
|
1994
|
+
var ALLOWED_NON_OPERATIONAL_ATTRS = [
|
|
1995
|
+
"href",
|
|
1996
|
+
"target",
|
|
1997
|
+
"class",
|
|
1998
|
+
"id",
|
|
1999
|
+
"style",
|
|
2000
|
+
"title",
|
|
2001
|
+
"lang",
|
|
2002
|
+
"dir",
|
|
2003
|
+
"role"
|
|
2004
|
+
];
|
|
2005
|
+
function getAllowedHtmlWrapperTags() {
|
|
2006
|
+
return window.elementorCommon?.config?.allowedHTMLWrapperTags ?? [];
|
|
2007
|
+
}
|
|
2008
|
+
function sanitizeEscapedHtml(value) {
|
|
2009
|
+
if (!value) {
|
|
2010
|
+
return "";
|
|
2011
|
+
}
|
|
2012
|
+
const allowedTags = [...getAllowedHtmlWrapperTags()];
|
|
2013
|
+
return DOMPurify.sanitize(value, {
|
|
2014
|
+
ALLOWED_TAGS: allowedTags,
|
|
2015
|
+
ALLOWED_ATTR: [...ALLOWED_NON_OPERATIONAL_ATTRS],
|
|
2016
|
+
ALLOW_DATA_ATTR: true,
|
|
2017
|
+
ALLOW_ARIA_ATTR: true
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
// src/transformers/settings/escaped-html-transformer.ts
|
|
2022
|
+
var escapedHtmlTransformer = createTransformer((value) => {
|
|
2023
|
+
return sanitizeEscapedHtml(value);
|
|
2024
|
+
});
|
|
2025
|
+
|
|
1992
2026
|
// src/transformers/settings/html-v2-transformer.ts
|
|
1993
2027
|
var htmlV2Transformer = createTransformer((value) => {
|
|
1994
2028
|
return value?.content ?? "";
|
|
@@ -2025,6 +2059,102 @@ var timeRangeTransformer = createTransformer((value) => {
|
|
|
2025
2059
|
};
|
|
2026
2060
|
});
|
|
2027
2061
|
|
|
2062
|
+
// src/transformers/shared/process-svg-content.ts
|
|
2063
|
+
import DOMPurify2 from "dompurify";
|
|
2064
|
+
var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
|
|
2065
|
+
function processSvgContent(svgText) {
|
|
2066
|
+
const sanitized = DOMPurify2.sanitize(svgText, {
|
|
2067
|
+
USE_PROFILES: { svg: true, svgFilters: true }
|
|
2068
|
+
});
|
|
2069
|
+
const parser = new DOMParser();
|
|
2070
|
+
const doc = parser.parseFromString(sanitized, "image/svg+xml");
|
|
2071
|
+
const svgElement = doc.querySelector("svg");
|
|
2072
|
+
if (!svgElement) {
|
|
2073
|
+
return null;
|
|
2074
|
+
}
|
|
2075
|
+
svgElement.setAttribute("fill", "currentColor");
|
|
2076
|
+
const existingStyle = svgElement.getAttribute("style") ?? "";
|
|
2077
|
+
const trimmed = existingStyle.trim();
|
|
2078
|
+
const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
|
|
2079
|
+
svgElement.setAttribute("style", merged);
|
|
2080
|
+
return svgElement.outerHTML;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
// src/transformers/shared/icon-transformer.ts
|
|
2084
|
+
var FONT_AWESOME_JSON = {
|
|
2085
|
+
width: 0,
|
|
2086
|
+
height: 1,
|
|
2087
|
+
path: 4
|
|
2088
|
+
};
|
|
2089
|
+
var fontAwesomeJsonCache = /* @__PURE__ */ new Map();
|
|
2090
|
+
var iconTransformer = createTransformer(async (value, { signal }) => {
|
|
2091
|
+
const iconValue = typeof value.value === "string" ? value.value : null;
|
|
2092
|
+
const library = typeof value.library === "string" ? value.library : null;
|
|
2093
|
+
if (!iconValue || !library) {
|
|
2094
|
+
return { html: null, url: null };
|
|
2095
|
+
}
|
|
2096
|
+
const iconName = getFontAwesomeIconName(iconValue);
|
|
2097
|
+
const jsonFileName = getFontAwesomeJsonFileName(library);
|
|
2098
|
+
if (!iconName || !jsonFileName) {
|
|
2099
|
+
return { html: null, url: null };
|
|
2100
|
+
}
|
|
2101
|
+
const icons = await fetchFontAwesomeIcons(jsonFileName, signal);
|
|
2102
|
+
const iconData = icons?.[iconName];
|
|
2103
|
+
if (!iconData) {
|
|
2104
|
+
return { html: null, url: null };
|
|
2105
|
+
}
|
|
2106
|
+
const svgText = buildFontAwesomeSvg(iconData);
|
|
2107
|
+
const html = processSvgContent(svgText);
|
|
2108
|
+
return { html, url: null };
|
|
2109
|
+
});
|
|
2110
|
+
function getFontAwesomeIconName(iconValue) {
|
|
2111
|
+
const match = iconValue.match(/^fa\S*\s+fa-(.+)$/);
|
|
2112
|
+
return match?.[1] ?? null;
|
|
2113
|
+
}
|
|
2114
|
+
function getFontAwesomeJsonFileName(library) {
|
|
2115
|
+
if (!library.startsWith("fa-")) {
|
|
2116
|
+
return null;
|
|
2117
|
+
}
|
|
2118
|
+
return library.replace(/^fa-/, "");
|
|
2119
|
+
}
|
|
2120
|
+
function getAssetsBaseUrl() {
|
|
2121
|
+
const assetsUrl = window.elementorCommon?.config?.urls?.assets;
|
|
2122
|
+
return typeof assetsUrl === "string" && assetsUrl !== "" ? assetsUrl : null;
|
|
2123
|
+
}
|
|
2124
|
+
async function fetchFontAwesomeIcons(jsonFileName, signal) {
|
|
2125
|
+
const cached = fontAwesomeJsonCache.get(jsonFileName);
|
|
2126
|
+
if (cached) {
|
|
2127
|
+
return cached;
|
|
2128
|
+
}
|
|
2129
|
+
const icons = await loadFontAwesomeIcons(jsonFileName, signal);
|
|
2130
|
+
if (icons) {
|
|
2131
|
+
fontAwesomeJsonCache.set(jsonFileName, icons);
|
|
2132
|
+
}
|
|
2133
|
+
return icons;
|
|
2134
|
+
}
|
|
2135
|
+
async function loadFontAwesomeIcons(jsonFileName, signal) {
|
|
2136
|
+
const assetsUrl = getAssetsBaseUrl();
|
|
2137
|
+
if (!assetsUrl) {
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
const response = await fetch(`${assetsUrl}lib/font-awesome/json/${jsonFileName}.json`, { signal });
|
|
2142
|
+
if (!response.ok) {
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
const data = await response.json();
|
|
2146
|
+
return data.icons ?? null;
|
|
2147
|
+
} catch {
|
|
2148
|
+
return null;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
function buildFontAwesomeSvg(iconData) {
|
|
2152
|
+
const width = iconData[FONT_AWESOME_JSON.width];
|
|
2153
|
+
const height = iconData[FONT_AWESOME_JSON.height];
|
|
2154
|
+
const path = iconData[FONT_AWESOME_JSON.path];
|
|
2155
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}"><path d="${path}"></path></svg>`;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2028
2158
|
// src/transformers/shared/image-src-transformer.ts
|
|
2029
2159
|
var imageSrcTransformer = createTransformer((value) => ({
|
|
2030
2160
|
id: value.id ?? null,
|
|
@@ -2066,26 +2196,7 @@ var plainTransformer = createTransformer((value) => {
|
|
|
2066
2196
|
});
|
|
2067
2197
|
|
|
2068
2198
|
// src/transformers/shared/svg-src-transformer.ts
|
|
2069
|
-
import DOMPurify from "dompurify";
|
|
2070
2199
|
import { getMediaAttachment as getMediaAttachment2 } from "@elementor/wp-media";
|
|
2071
|
-
var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
|
|
2072
|
-
function processSvgContent(svgText) {
|
|
2073
|
-
const sanitized = DOMPurify.sanitize(svgText, {
|
|
2074
|
-
USE_PROFILES: { svg: true, svgFilters: true }
|
|
2075
|
-
});
|
|
2076
|
-
const parser = new DOMParser();
|
|
2077
|
-
const doc = parser.parseFromString(sanitized, "image/svg+xml");
|
|
2078
|
-
const svgElement = doc.querySelector("svg");
|
|
2079
|
-
if (!svgElement) {
|
|
2080
|
-
return null;
|
|
2081
|
-
}
|
|
2082
|
-
svgElement.setAttribute("fill", "currentColor");
|
|
2083
|
-
const existingStyle = svgElement.getAttribute("style") ?? "";
|
|
2084
|
-
const trimmed = existingStyle.trim();
|
|
2085
|
-
const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
|
|
2086
|
-
svgElement.setAttribute("style", merged);
|
|
2087
|
-
return svgElement.outerHTML;
|
|
2088
|
-
}
|
|
2089
2200
|
async function fetchSvgContent(url, signal) {
|
|
2090
2201
|
try {
|
|
2091
2202
|
const response = await fetch(url, { signal });
|
|
@@ -2141,7 +2252,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
|
|
|
2141
2252
|
|
|
2142
2253
|
// src/init-settings-transformers.ts
|
|
2143
2254
|
function initSettingsTransformers() {
|
|
2144
|
-
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("svg-src", svgSrcTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).register("date-range", dateRangeTransformer).register("time-range", timeRangeTransformer).registerFallback(plainTransformer);
|
|
2255
|
+
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("svg-src", svgSrcTransformer).register("icon", iconTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).register("escaped-html", escapedHtmlTransformer).register("date-range", dateRangeTransformer).register("time-range", timeRangeTransformer).registerFallback(plainTransformer);
|
|
2145
2256
|
}
|
|
2146
2257
|
|
|
2147
2258
|
// src/transformers/styles/background-color-overlay-transformer.ts
|
|
@@ -2418,11 +2529,11 @@ function getVal2(val) {
|
|
|
2418
2529
|
var transformOriginTransformer = createTransformer((value) => {
|
|
2419
2530
|
const x = getVal2(value.x);
|
|
2420
2531
|
const y = getVal2(value.y);
|
|
2421
|
-
const
|
|
2422
|
-
if (x === DEFAULT_XY && y === DEFAULT_XY &&
|
|
2532
|
+
const z3 = getVal2(value.z);
|
|
2533
|
+
if (x === DEFAULT_XY && y === DEFAULT_XY && z3 === DEFAULT_Z) {
|
|
2423
2534
|
return null;
|
|
2424
2535
|
}
|
|
2425
|
-
return `${x} ${y} ${
|
|
2536
|
+
return `${x} ${y} ${z3}`;
|
|
2426
2537
|
});
|
|
2427
2538
|
|
|
2428
2539
|
// src/transformers/styles/transform-rotate-transformer.ts
|
|
@@ -2500,13 +2611,13 @@ function initStyleTransformers() {
|
|
|
2500
2611
|
"layout-direction",
|
|
2501
2612
|
createMultiPropsTransformer(["row", "column"], ({ propKey, key }) => `${key}-${propKey}`)
|
|
2502
2613
|
).register("flex", flexTransformer).register(
|
|
2503
|
-
"border-width",
|
|
2614
|
+
"border-width-v2",
|
|
2504
2615
|
createMultiPropsTransformer(
|
|
2505
2616
|
["block-start", "block-end", "inline-start", "inline-end"],
|
|
2506
2617
|
({ key }) => `border-${key}-width`
|
|
2507
2618
|
)
|
|
2508
2619
|
).register(
|
|
2509
|
-
"border-radius",
|
|
2620
|
+
"border-radius-v2",
|
|
2510
2621
|
createMultiPropsTransformer(
|
|
2511
2622
|
["start-start", "start-end", "end-start", "end-end"],
|
|
2512
2623
|
({ key }) => `border-${key}-radius`
|
|
@@ -2530,28 +2641,13 @@ function createDomRenderer() {
|
|
|
2530
2641
|
render: environment.render
|
|
2531
2642
|
};
|
|
2532
2643
|
}
|
|
2644
|
+
function getAllowedHtmlWrapperTags2() {
|
|
2645
|
+
return window.elementorCommon?.config?.allowedHTMLWrapperTags ?? [];
|
|
2646
|
+
}
|
|
2533
2647
|
function escapeHtmlTag(value) {
|
|
2534
|
-
const allowedTags =
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
"aside",
|
|
2538
|
-
"button",
|
|
2539
|
-
"div",
|
|
2540
|
-
"footer",
|
|
2541
|
-
"h1",
|
|
2542
|
-
"h2",
|
|
2543
|
-
"h3",
|
|
2544
|
-
"h4",
|
|
2545
|
-
"h5",
|
|
2546
|
-
"h6",
|
|
2547
|
-
"header",
|
|
2548
|
-
"main",
|
|
2549
|
-
"nav",
|
|
2550
|
-
"p",
|
|
2551
|
-
"section",
|
|
2552
|
-
"span"
|
|
2553
|
-
];
|
|
2554
|
-
return allowedTags.includes(value) ? value : "div";
|
|
2648
|
+
const allowedTags = getAllowedHtmlWrapperTags2();
|
|
2649
|
+
const normalizedTag = value?.toLowerCase?.() ?? "";
|
|
2650
|
+
return allowedTags.includes(normalizedTag) ? value : "div";
|
|
2555
2651
|
}
|
|
2556
2652
|
function escapeURL(value) {
|
|
2557
2653
|
const allowedProtocols = ["http:", "https:", "mailto:", "tel:"];
|
|
@@ -2646,6 +2742,52 @@ function createElementViewClassDeclaration() {
|
|
|
2646
2742
|
// src/legacy/create-nested-templated-element-type.ts
|
|
2647
2743
|
import { ELEMENT_STYLE_CHANGE_EVENT as ELEMENT_STYLE_CHANGE_EVENT2 } from "@elementor/editor-elements";
|
|
2648
2744
|
|
|
2745
|
+
// src/renderers/compute-html-tag.ts
|
|
2746
|
+
var DEFAULT_LINK_TAG = "a";
|
|
2747
|
+
function computeHtmlTag(settings, defaultTag, options = {}) {
|
|
2748
|
+
const followLink = options.followLink ?? true;
|
|
2749
|
+
if (followLink && settingsHaveActiveLink(settings)) {
|
|
2750
|
+
const link = settings.link;
|
|
2751
|
+
return extractLinkHtmlTag(isRecord(link) ? link : {});
|
|
2752
|
+
}
|
|
2753
|
+
const settingsTag = extractHtmlTagValue(settings.tag);
|
|
2754
|
+
if (null !== settingsTag && "" !== settingsTag) {
|
|
2755
|
+
return settingsTag;
|
|
2756
|
+
}
|
|
2757
|
+
return defaultTag;
|
|
2758
|
+
}
|
|
2759
|
+
function settingsHaveActiveLink(settings) {
|
|
2760
|
+
const link = settings.link;
|
|
2761
|
+
if (!isRecord(link)) {
|
|
2762
|
+
return false;
|
|
2763
|
+
}
|
|
2764
|
+
const href = extractHtmlTagValue(link.href);
|
|
2765
|
+
if (null !== href && "" !== href) {
|
|
2766
|
+
return true;
|
|
2767
|
+
}
|
|
2768
|
+
const attributes = link.attributes;
|
|
2769
|
+
return typeof attributes === "string" && "" !== attributes;
|
|
2770
|
+
}
|
|
2771
|
+
function extractLinkHtmlTag(link) {
|
|
2772
|
+
const tag = extractHtmlTagValue(link.tag);
|
|
2773
|
+
if (null !== tag && "" !== tag) {
|
|
2774
|
+
return tag;
|
|
2775
|
+
}
|
|
2776
|
+
return DEFAULT_LINK_TAG;
|
|
2777
|
+
}
|
|
2778
|
+
function extractHtmlTagValue(value) {
|
|
2779
|
+
if (isRecord(value) && typeof value.value === "string") {
|
|
2780
|
+
return value.value;
|
|
2781
|
+
}
|
|
2782
|
+
if (typeof value === "string") {
|
|
2783
|
+
return value;
|
|
2784
|
+
}
|
|
2785
|
+
return null;
|
|
2786
|
+
}
|
|
2787
|
+
function isRecord(value) {
|
|
2788
|
+
return typeof value === "object" && null !== value && !Array.isArray(value);
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2649
2791
|
// src/legacy/create-pending-element.ts
|
|
2650
2792
|
import {
|
|
2651
2793
|
addModelToParent,
|
|
@@ -2711,7 +2853,13 @@ function setupTwigRenderer({ renderer, element }) {
|
|
|
2711
2853
|
transformers: settingsTransformersRegistry,
|
|
2712
2854
|
schema: element.atomic_props_schema
|
|
2713
2855
|
});
|
|
2714
|
-
return {
|
|
2856
|
+
return {
|
|
2857
|
+
templateKey,
|
|
2858
|
+
baseStylesDictionary,
|
|
2859
|
+
resolveProps,
|
|
2860
|
+
defaultHtmlTag: element.default_html_tag ?? "div",
|
|
2861
|
+
htmlTagFollowsLink: element.html_tag_follows_link ?? true
|
|
2862
|
+
};
|
|
2715
2863
|
}
|
|
2716
2864
|
function createBeforeRender(view) {
|
|
2717
2865
|
view._ensureViewIsIntact();
|
|
@@ -2751,7 +2899,7 @@ function createTemplatedElementView({
|
|
|
2751
2899
|
element
|
|
2752
2900
|
}) {
|
|
2753
2901
|
const BaseView = createElementViewClassDeclaration();
|
|
2754
|
-
const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
|
|
2902
|
+
const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
|
|
2755
2903
|
type,
|
|
2756
2904
|
renderer,
|
|
2757
2905
|
element
|
|
@@ -2821,6 +2969,7 @@ function createTemplatedElementView({
|
|
|
2821
2969
|
interaction_id: this.getInteractionId(),
|
|
2822
2970
|
type,
|
|
2823
2971
|
settings,
|
|
2972
|
+
tag: computeHtmlTag(settings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
|
|
2824
2973
|
base_styles: baseStylesDictionary,
|
|
2825
2974
|
...this.getResolverRenderContext?.() ?? {}
|
|
2826
2975
|
};
|
|
@@ -2910,7 +3059,7 @@ function createNestedTemplatedElementView({
|
|
|
2910
3059
|
element
|
|
2911
3060
|
}) {
|
|
2912
3061
|
const legacyWindow = window;
|
|
2913
|
-
const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
|
|
3062
|
+
const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
|
|
2914
3063
|
type,
|
|
2915
3064
|
renderer,
|
|
2916
3065
|
element
|
|
@@ -2985,6 +3134,7 @@ function createNestedTemplatedElementView({
|
|
|
2985
3134
|
interaction_id: this.getInteractionId(),
|
|
2986
3135
|
type,
|
|
2987
3136
|
settings: resolvedSettings,
|
|
3137
|
+
tag: computeHtmlTag(resolvedSettings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
|
|
2988
3138
|
base_styles: baseStylesDictionary,
|
|
2989
3139
|
editor_attributes: buildEditorAttributes(model),
|
|
2990
3140
|
editor_classes: buildEditorClasses(model),
|
|
@@ -3208,8 +3358,8 @@ import { createRoot } from "react-dom/client";
|
|
|
3208
3358
|
import * as React11 from "react";
|
|
3209
3359
|
import { getContainer as getContainer2, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
|
|
3210
3360
|
import {
|
|
3361
|
+
escapedHtmlPropTypeUtil as escapedHtmlPropTypeUtil2,
|
|
3211
3362
|
htmlV3PropTypeUtil as htmlV3PropTypeUtil2,
|
|
3212
|
-
parseHtmlChildren,
|
|
3213
3363
|
stringPropTypeUtil as stringPropTypeUtil2
|
|
3214
3364
|
} from "@elementor/editor-props";
|
|
3215
3365
|
import { __privateRunCommandSync as runCommandSync, getCurrentEditMode, undoable } from "@elementor/editor-v1-adapters";
|
|
@@ -3488,11 +3638,15 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
|
|
|
3488
3638
|
};
|
|
3489
3639
|
|
|
3490
3640
|
// src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
|
|
3491
|
-
import {
|
|
3641
|
+
import {
|
|
3642
|
+
escapedHtmlPropTypeUtil,
|
|
3643
|
+
htmlV3PropTypeUtil,
|
|
3644
|
+
stringPropTypeUtil
|
|
3645
|
+
} from "@elementor/editor-props";
|
|
3492
3646
|
var hasKey = (propType) => {
|
|
3493
3647
|
return "key" in propType;
|
|
3494
3648
|
};
|
|
3495
|
-
var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([htmlV3PropTypeUtil.key, stringPropTypeUtil.key]);
|
|
3649
|
+
var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([escapedHtmlPropTypeUtil.key, htmlV3PropTypeUtil.key, stringPropTypeUtil.key]);
|
|
3496
3650
|
var isCoreTextPropTypeKey = (key) => {
|
|
3497
3651
|
return TEXT_PROP_TYPE_KEYS.has(key);
|
|
3498
3652
|
};
|
|
@@ -3512,7 +3666,7 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
|
|
|
3512
3666
|
if (rawValue === null || rawValue === void 0) {
|
|
3513
3667
|
return isAllowedBySchema(propTypeFromSchema);
|
|
3514
3668
|
}
|
|
3515
|
-
return htmlV3PropTypeUtil.isValid(rawValue) || stringPropTypeUtil.isValid(rawValue);
|
|
3669
|
+
return escapedHtmlPropTypeUtil.isValid(rawValue) || htmlV3PropTypeUtil.isValid(rawValue) || stringPropTypeUtil.isValid(rawValue);
|
|
3516
3670
|
};
|
|
3517
3671
|
|
|
3518
3672
|
// src/legacy/replacements/inline-editing/inline-editing-elements.tsx
|
|
@@ -3597,17 +3751,26 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
3597
3751
|
}
|
|
3598
3752
|
getExtractedContentValue() {
|
|
3599
3753
|
const propValue = this.getInlineEditablePropValue();
|
|
3754
|
+
if (escapedHtmlPropTypeUtil2.isValid(propValue)) {
|
|
3755
|
+
return escapedHtmlPropTypeUtil2.extract(propValue) ?? "";
|
|
3756
|
+
}
|
|
3600
3757
|
const extracted = htmlV3PropTypeUtil2.extract(propValue);
|
|
3601
3758
|
return stringPropTypeUtil2.extract(extracted?.content ?? null) ?? "";
|
|
3602
3759
|
}
|
|
3760
|
+
createContentPropValue(value) {
|
|
3761
|
+
const content = value || "";
|
|
3762
|
+
const propTypeKey = this.getInlineEditablePropTypeKey();
|
|
3763
|
+
if (propTypeKey === htmlV3PropTypeUtil2.key) {
|
|
3764
|
+
return htmlV3PropTypeUtil2.create({
|
|
3765
|
+
content: stringPropTypeUtil2.create(content),
|
|
3766
|
+
children: []
|
|
3767
|
+
});
|
|
3768
|
+
}
|
|
3769
|
+
return escapedHtmlPropTypeUtil2.create(content);
|
|
3770
|
+
}
|
|
3603
3771
|
setContentValue(value) {
|
|
3604
3772
|
const settingKey = this.getInlineEditablePropertyName();
|
|
3605
|
-
const
|
|
3606
|
-
const parsed = parseHtmlChildren(html);
|
|
3607
|
-
const valueToSave = htmlV3PropTypeUtil2.create({
|
|
3608
|
-
content: parsed.content ? stringPropTypeUtil2.create(parsed.content) : null,
|
|
3609
|
-
children: parsed.children
|
|
3610
|
-
});
|
|
3773
|
+
const valueToSave = this.createContentPropValue(value);
|
|
3611
3774
|
undoable(
|
|
3612
3775
|
{
|
|
3613
3776
|
do: () => {
|
|
@@ -3636,7 +3799,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
3636
3799
|
return null;
|
|
3637
3800
|
}
|
|
3638
3801
|
if (propType.kind === "union") {
|
|
3639
|
-
const textKeys = [htmlV3PropTypeUtil2.key, stringPropTypeUtil2.key];
|
|
3802
|
+
const textKeys = [escapedHtmlPropTypeUtil2.key, htmlV3PropTypeUtil2.key, stringPropTypeUtil2.key];
|
|
3640
3803
|
for (const key of textKeys) {
|
|
3641
3804
|
if (propType.prop_types[key]) {
|
|
3642
3805
|
return key;
|
|
@@ -3891,8 +4054,54 @@ function createNestedTemplatedType(type, renderer, element) {
|
|
|
3891
4054
|
});
|
|
3892
4055
|
}
|
|
3893
4056
|
|
|
4057
|
+
// src/legacy/list-type.ts
|
|
4058
|
+
var LIST_TYPE = "e-list";
|
|
4059
|
+
function initListType() {
|
|
4060
|
+
registerElementType(
|
|
4061
|
+
LIST_TYPE,
|
|
4062
|
+
(options) => createListType(options)
|
|
4063
|
+
);
|
|
4064
|
+
}
|
|
4065
|
+
function createListType(options) {
|
|
4066
|
+
const BaseType = createNestedTemplatedElementType(options);
|
|
4067
|
+
let ListView = null;
|
|
4068
|
+
return class extends BaseType {
|
|
4069
|
+
getView() {
|
|
4070
|
+
if (!ListView) {
|
|
4071
|
+
ListView = createListView(options);
|
|
4072
|
+
}
|
|
4073
|
+
return ListView;
|
|
4074
|
+
}
|
|
4075
|
+
};
|
|
4076
|
+
}
|
|
4077
|
+
function createListView(options) {
|
|
4078
|
+
const BaseView = createNestedTemplatedElementView(options);
|
|
4079
|
+
return BaseView.extend({
|
|
4080
|
+
getRenderContext() {
|
|
4081
|
+
const parentContext = this._parent?.getRenderContext?.();
|
|
4082
|
+
const settings = this.model.get("settings");
|
|
4083
|
+
const showMarkersProp = settings?.get?.("show_markers");
|
|
4084
|
+
const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
|
|
4085
|
+
return {
|
|
4086
|
+
...parentContext,
|
|
4087
|
+
show_markers: showMarkers
|
|
4088
|
+
};
|
|
4089
|
+
},
|
|
4090
|
+
getResolverRenderContext() {
|
|
4091
|
+
const parentContext = this._parent?.getResolverRenderContext?.();
|
|
4092
|
+
const settings = this.model.get("settings");
|
|
4093
|
+
const showMarkersProp = settings?.get?.("show_markers");
|
|
4094
|
+
const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
|
|
4095
|
+
return {
|
|
4096
|
+
...parentContext,
|
|
4097
|
+
show_markers: showMarkers
|
|
4098
|
+
};
|
|
4099
|
+
}
|
|
4100
|
+
});
|
|
4101
|
+
}
|
|
4102
|
+
|
|
3894
4103
|
// src/legacy/tabs-model-extensions.ts
|
|
3895
|
-
import {
|
|
4104
|
+
import { escapedHtmlPropTypeUtil as escapedHtmlPropTypeUtil3 } from "@elementor/editor-props";
|
|
3896
4105
|
var tabModelExtensions = {
|
|
3897
4106
|
modifyDefaultChildren(elements) {
|
|
3898
4107
|
if (!Array.isArray(elements) || elements.length === 0) {
|
|
@@ -3908,10 +4117,7 @@ var tabModelExtensions = {
|
|
|
3908
4117
|
...paragraphElement,
|
|
3909
4118
|
settings: {
|
|
3910
4119
|
...paragraphElement.settings,
|
|
3911
|
-
paragraph:
|
|
3912
|
-
content: stringPropTypeUtil3.create(`Tab ${position}`),
|
|
3913
|
-
children: []
|
|
3914
|
-
})
|
|
4120
|
+
paragraph: escapedHtmlPropTypeUtil3.create(`Tab ${position}`)
|
|
3915
4121
|
}
|
|
3916
4122
|
};
|
|
3917
4123
|
return [updatedParagraph, ...elements.slice(1)];
|
|
@@ -3922,22 +4128,22 @@ function initTabsModelExtensions() {
|
|
|
3922
4128
|
}
|
|
3923
4129
|
|
|
3924
4130
|
// src/mcp/canvas-mcp.ts
|
|
3925
|
-
import { Schema as
|
|
4131
|
+
import { Schema as Schema3 } from "@elementor/editor-props";
|
|
3926
4132
|
|
|
3927
4133
|
// src/mcp/resources/available-widgets-resource.ts
|
|
3928
4134
|
import { httpService as httpService3 } from "@elementor/http-client";
|
|
3929
4135
|
var MCP_PROXY_URL2 = "elementor/v1/mcp-proxy";
|
|
3930
4136
|
var AVAILABLE_WIDGETS_URI = "elementor://context/available-widgets";
|
|
3931
4137
|
var AVAILABLE_WIDGETS_URI_V4 = "elementor://context/available-widgets/v4";
|
|
3932
|
-
var fetchWidgets = async (
|
|
4138
|
+
var fetchWidgets = async () => {
|
|
3933
4139
|
const { data } = await httpService3().post(MCP_PROXY_URL2, {
|
|
3934
|
-
tool: "list-
|
|
3935
|
-
input:
|
|
4140
|
+
tool: "list-widget-schemas",
|
|
4141
|
+
input: { summary: true }
|
|
3936
4142
|
});
|
|
3937
|
-
return data.data ?? [];
|
|
4143
|
+
return data.data?.widgets ?? [];
|
|
3938
4144
|
};
|
|
3939
|
-
var buildContents = async (uri
|
|
3940
|
-
const widgets = await fetchWidgets(
|
|
4145
|
+
var buildContents = async (uri) => {
|
|
4146
|
+
const widgets = await fetchWidgets();
|
|
3941
4147
|
return {
|
|
3942
4148
|
contents: [
|
|
3943
4149
|
{
|
|
@@ -3956,13 +4162,13 @@ var initAvailableWidgetsResource = (reg) => {
|
|
|
3956
4162
|
{
|
|
3957
4163
|
description: "All registered v4 version widgets"
|
|
3958
4164
|
},
|
|
3959
|
-
async () => buildContents(AVAILABLE_WIDGETS_URI_V4
|
|
4165
|
+
async () => buildContents(AVAILABLE_WIDGETS_URI_V4)
|
|
3960
4166
|
);
|
|
3961
4167
|
resource(
|
|
3962
4168
|
"available-widgets",
|
|
3963
4169
|
AVAILABLE_WIDGETS_URI,
|
|
3964
4170
|
{
|
|
3965
|
-
description: "All registered widget types with
|
|
4171
|
+
description: "All registered v4 widget types with description."
|
|
3966
4172
|
},
|
|
3967
4173
|
async () => buildContents(AVAILABLE_WIDGETS_URI)
|
|
3968
4174
|
);
|
|
@@ -4097,11 +4303,10 @@ import { httpService as httpService5 } from "@elementor/http-client";
|
|
|
4097
4303
|
var DYNAMIC_TAGS_URI = "elementor://dynamic-tags";
|
|
4098
4304
|
var MCP_PROXY_URL4 = "elementor/v1/mcp-proxy";
|
|
4099
4305
|
var fetchDynamicTags = async () => {
|
|
4100
|
-
const { data } = await httpService5().
|
|
4101
|
-
|
|
4102
|
-
input: {}
|
|
4306
|
+
const { data } = await httpService5().get(MCP_PROXY_URL4, {
|
|
4307
|
+
params: { uri: DYNAMIC_TAGS_URI }
|
|
4103
4308
|
});
|
|
4104
|
-
return data.data ?? [];
|
|
4309
|
+
return data.data ?? "[]";
|
|
4105
4310
|
};
|
|
4106
4311
|
var initDynamicTagsResource = (reg) => {
|
|
4107
4312
|
const { resource } = reg;
|
|
@@ -4113,13 +4318,12 @@ var initDynamicTagsResource = (reg) => {
|
|
|
4113
4318
|
mimeType: "application/json"
|
|
4114
4319
|
},
|
|
4115
4320
|
async (uri) => {
|
|
4116
|
-
const tags = await fetchDynamicTags();
|
|
4117
4321
|
return {
|
|
4118
4322
|
contents: [
|
|
4119
4323
|
{
|
|
4120
4324
|
uri: uri.href,
|
|
4121
4325
|
mimeType: "application/json",
|
|
4122
|
-
text:
|
|
4326
|
+
text: await fetchDynamicTags()
|
|
4123
4327
|
}
|
|
4124
4328
|
]
|
|
4125
4329
|
};
|
|
@@ -4445,99 +4649,8 @@ function getElementDisplayName(container) {
|
|
|
4445
4649
|
}
|
|
4446
4650
|
}
|
|
4447
4651
|
|
|
4448
|
-
// src/mcp/tools/build-composition/tool.ts
|
|
4449
|
-
import { getCurrentDocument, reloadCurrentDocument } from "@elementor/editor-documents";
|
|
4450
|
-
import { getContainer as getContainer4, selectElement } from "@elementor/editor-elements";
|
|
4451
|
-
import { AxiosError, httpService as httpService6 } from "@elementor/http-client";
|
|
4452
|
-
import { z } from "@elementor/schema";
|
|
4453
|
-
var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
|
|
4454
|
-
var initBuildCompositionTool = (reg) => {
|
|
4455
|
-
const { addTool } = reg;
|
|
4456
|
-
addTool({
|
|
4457
|
-
name: "build-composition",
|
|
4458
|
-
description: "Build a V4 element composition on the Elementor canvas via the server-side MCP ability. Pass the raw XML tags directly as xmlStructure \u2014 do NOT wrap the value in <![CDATA[ ... ]]>, code fences, or quotes. The document is saved as a draft. Reload the editor after calling this tool to see the result.",
|
|
4459
|
-
schema: {
|
|
4460
|
-
xmlStructure: z.string().describe(
|
|
4461
|
-
'Valid XML structure with custom Elementor widget tags. Every element MUST have a unique configuration-id attribute (e.g. <e-heading configuration-id="hero-title"></e-heading>). No attributes, classes, IDs, or text nodes in XML. Pass raw XML \u2014 do not wrap in CDATA.'
|
|
4462
|
-
),
|
|
4463
|
-
elementConfig: z.record(
|
|
4464
|
-
z.string().describe("configuration-id"),
|
|
4465
|
-
z.record(z.string().describe("property name"), z.any().describe("PropValue"))
|
|
4466
|
-
).optional().describe("Map configuration-id \u2192 widget PropValues ($$type + value)."),
|
|
4467
|
-
style: z.record(
|
|
4468
|
-
z.string().describe("configuration-id"),
|
|
4469
|
-
z.record(z.string().describe("CSS property name"), z.string().describe("CSS value"))
|
|
4470
|
-
).optional().describe(
|
|
4471
|
-
"Map configuration-id \u2192 raw CSS declarations (property \u2192 value strings; no selectors). Server converts to native styles; unconvertible declarations become the element custom CSS."
|
|
4472
|
-
),
|
|
4473
|
-
parentId: z.string().optional().describe("ID of the parent container. Omit or pass 'document' to insert at document root."),
|
|
4474
|
-
dryRun: z.boolean().optional().describe("If true, validate and return the resolved tree without persisting.")
|
|
4475
|
-
},
|
|
4476
|
-
outputSchema: {
|
|
4477
|
-
rootElementIds: z.array(z.string()),
|
|
4478
|
-
previewUrl: z.string(),
|
|
4479
|
-
version: z.string(),
|
|
4480
|
-
resolvedXml: z.string(),
|
|
4481
|
-
llmInstructions: z.string(),
|
|
4482
|
-
warnings: z.array(z.string()).optional()
|
|
4483
|
-
},
|
|
4484
|
-
handler: async ({ xmlStructure, elementConfig, style, parentId, dryRun }) => {
|
|
4485
|
-
const document2 = getCurrentDocument();
|
|
4486
|
-
if (!document2?.id) {
|
|
4487
|
-
throw new Error("No active document found.");
|
|
4488
|
-
}
|
|
4489
|
-
try {
|
|
4490
|
-
const { data } = await httpService6().post(MCP_PROXY_URL5, {
|
|
4491
|
-
tool: "build-composition",
|
|
4492
|
-
input: {
|
|
4493
|
-
post_id: document2.id,
|
|
4494
|
-
xml_structure: xmlStructure,
|
|
4495
|
-
element_config: elementConfig ?? {},
|
|
4496
|
-
style: style ?? {},
|
|
4497
|
-
parent_id: parentId ?? "document",
|
|
4498
|
-
dry_run: dryRun ?? false
|
|
4499
|
-
}
|
|
4500
|
-
});
|
|
4501
|
-
if (!dryRun) {
|
|
4502
|
-
await reloadCurrentDocument();
|
|
4503
|
-
const [firstRootId] = data.data.root_element_ids;
|
|
4504
|
-
if (firstRootId) {
|
|
4505
|
-
selectElement(firstRootId);
|
|
4506
|
-
getContainer4(firstRootId)?.view?.el?.scrollIntoView({
|
|
4507
|
-
behavior: "smooth",
|
|
4508
|
-
block: "center"
|
|
4509
|
-
});
|
|
4510
|
-
}
|
|
4511
|
-
}
|
|
4512
|
-
return {
|
|
4513
|
-
rootElementIds: data.data.root_element_ids,
|
|
4514
|
-
previewUrl: data.data.preview_url,
|
|
4515
|
-
version: data.data.version,
|
|
4516
|
-
resolvedXml: data.data.resolved_xml,
|
|
4517
|
-
llmInstructions: data.data.llm_instructions,
|
|
4518
|
-
warnings: data.data.warnings
|
|
4519
|
-
};
|
|
4520
|
-
} catch (error) {
|
|
4521
|
-
throw new Error(getErrorMessage(error));
|
|
4522
|
-
}
|
|
4523
|
-
}
|
|
4524
|
-
});
|
|
4525
|
-
};
|
|
4526
|
-
function getErrorMessage(error) {
|
|
4527
|
-
if (error instanceof AxiosError) {
|
|
4528
|
-
const data = error.response?.data;
|
|
4529
|
-
if (data?.message) {
|
|
4530
|
-
return data.code ? `${data.code}: ${data.message}` : data.message;
|
|
4531
|
-
}
|
|
4532
|
-
}
|
|
4533
|
-
if (error instanceof Error) {
|
|
4534
|
-
return error.message;
|
|
4535
|
-
}
|
|
4536
|
-
return "build-composition failed with an unknown error.";
|
|
4537
|
-
}
|
|
4538
|
-
|
|
4539
4652
|
// src/mcp/tools/configure-element/tool.ts
|
|
4540
|
-
import { getContainer as
|
|
4653
|
+
import { getContainer as getContainer4, getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
|
|
4541
4654
|
import { dispatchMcpStylesAppliedEvent } from "@elementor/editor-mcp";
|
|
4542
4655
|
import { Schema as Schema2 } from "@elementor/editor-props";
|
|
4543
4656
|
|
|
@@ -4569,9 +4682,9 @@ var readStoredCustomCssText = (raw) => {
|
|
|
4569
4682
|
|
|
4570
4683
|
// src/mcp/utils/resolve-canonical-prop-name.ts
|
|
4571
4684
|
import { getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
|
|
4572
|
-
function buildAliasToCanonicalMap(
|
|
4685
|
+
function buildAliasToCanonicalMap(schema) {
|
|
4573
4686
|
const aliasToCanonical = {};
|
|
4574
|
-
for (const [canonical, propType] of Object.entries(
|
|
4687
|
+
for (const [canonical, propType] of Object.entries(schema)) {
|
|
4575
4688
|
const aliases = propType.meta?.aliases;
|
|
4576
4689
|
if (!Array.isArray(aliases)) {
|
|
4577
4690
|
continue;
|
|
@@ -4585,26 +4698,26 @@ function buildAliasToCanonicalMap(schema2) {
|
|
|
4585
4698
|
return aliasToCanonical;
|
|
4586
4699
|
}
|
|
4587
4700
|
function resolveCanonicalPropName(elementType, propertyName) {
|
|
4588
|
-
const
|
|
4589
|
-
if (!
|
|
4701
|
+
const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
|
|
4702
|
+
if (!schema || schema[propertyName]) {
|
|
4590
4703
|
return propertyName;
|
|
4591
4704
|
}
|
|
4592
|
-
return buildAliasToCanonicalMap(
|
|
4705
|
+
return buildAliasToCanonicalMap(schema)[propertyName] ?? propertyName;
|
|
4593
4706
|
}
|
|
4594
4707
|
function resolveCanonicalPropKeys(elementType, props) {
|
|
4595
|
-
const
|
|
4596
|
-
if (!
|
|
4708
|
+
const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
|
|
4709
|
+
if (!schema) {
|
|
4597
4710
|
return { ...props };
|
|
4598
4711
|
}
|
|
4599
|
-
const aliasToCanonical = buildAliasToCanonicalMap(
|
|
4712
|
+
const aliasToCanonical = buildAliasToCanonicalMap(schema);
|
|
4600
4713
|
const resolved = {};
|
|
4601
4714
|
for (const [key, value] of Object.entries(props)) {
|
|
4602
|
-
if (
|
|
4715
|
+
if (schema[key]) {
|
|
4603
4716
|
resolved[key] = value;
|
|
4604
4717
|
}
|
|
4605
4718
|
}
|
|
4606
4719
|
for (const [key, value] of Object.entries(props)) {
|
|
4607
|
-
if (
|
|
4720
|
+
if (schema[key]) {
|
|
4608
4721
|
continue;
|
|
4609
4722
|
}
|
|
4610
4723
|
const canonical = aliasToCanonical[key];
|
|
@@ -4652,9 +4765,9 @@ var dynamicTagLLMResolver = (value) => {
|
|
|
4652
4765
|
}
|
|
4653
4766
|
};
|
|
4654
4767
|
};
|
|
4655
|
-
var buildStrictSettings = (
|
|
4768
|
+
var buildStrictSettings = (schema, provided) => {
|
|
4656
4769
|
const settings = {};
|
|
4657
|
-
for (const [key, propType] of Object.entries(
|
|
4770
|
+
for (const [key, propType] of Object.entries(schema)) {
|
|
4658
4771
|
if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
|
|
4659
4772
|
continue;
|
|
4660
4773
|
}
|
|
@@ -4686,6 +4799,20 @@ var LOCAL_STYLE_META = {
|
|
|
4686
4799
|
breakpoint: "desktop",
|
|
4687
4800
|
state: null
|
|
4688
4801
|
};
|
|
4802
|
+
var UnsupportedPropertyError = class extends Error {
|
|
4803
|
+
elementType;
|
|
4804
|
+
propertyName;
|
|
4805
|
+
constructor(elementType, propertyName, availableProperties) {
|
|
4806
|
+
super(
|
|
4807
|
+
`Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${availableProperties.join(
|
|
4808
|
+
", "
|
|
4809
|
+
)}`
|
|
4810
|
+
);
|
|
4811
|
+
this.name = "UnsupportedPropertyError";
|
|
4812
|
+
this.elementType = elementType;
|
|
4813
|
+
this.propertyName = propertyName;
|
|
4814
|
+
}
|
|
4815
|
+
};
|
|
4689
4816
|
function resolvePropValue(value, forceKey) {
|
|
4690
4817
|
const Utils = window.elementorV2.editorVariables.Utils;
|
|
4691
4818
|
return Schema.adjustLlmPropValueSchema(value, {
|
|
@@ -4791,12 +4918,7 @@ var doUpdateElementProperty = (params) => {
|
|
|
4791
4918
|
throw new Error(`No prop schema found for element type: ${elementType}`);
|
|
4792
4919
|
}
|
|
4793
4920
|
if (!elementPropSchema[propertyName]) {
|
|
4794
|
-
|
|
4795
|
-
throw new Error(
|
|
4796
|
-
`Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${propertyNames.join(
|
|
4797
|
-
", "
|
|
4798
|
-
)}`
|
|
4799
|
-
);
|
|
4921
|
+
throw new UnsupportedPropertyError(elementType, propertyName, Object.keys(elementPropSchema));
|
|
4800
4922
|
}
|
|
4801
4923
|
const propKey = elementPropSchema[propertyName].key;
|
|
4802
4924
|
const value = resolvePropValue(propertyValue, propKey);
|
|
@@ -4866,8 +4988,6 @@ For all non-primitive entries in \`propertiesToChange\`, provide the schema \`ke
|
|
|
4866
4988
|
|
|
4867
4989
|
Use the EXACT PropType schema given, and ALWAYS include the \`key\` from the schema for every property you are changing in \`propertiesToChange\`.
|
|
4868
4990
|
|
|
4869
|
-
Check \`llm_guidance.default_settings\` in the widget schema \u2014 include a key in \`propertiesToChange\` only when the user explicitly asks to change it.
|
|
4870
|
-
|
|
4871
4991
|
# Dynamic tags
|
|
4872
4992
|
A value can be made dynamic wherever its schema exposes a variant with "$$type": "dynamic". This may be the property root OR a NESTED field: for example an image is made dynamic on its "src" (the root stays "image"), NOT on the whole "image" value.
|
|
4873
4993
|
Put the dynamic object EXACTLY at the node whose schema offers the "dynamic" variant, in place of the static variant. The variant's "name" enumerates the tags allowed at that node.
|
|
@@ -4894,7 +5014,7 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
|
|
|
4894
5014
|
);
|
|
4895
5015
|
configureElementToolPrompt.parameter(
|
|
4896
5016
|
"style",
|
|
4897
|
-
'A flat map of raw CSS declarations (property \u2192 value), e.g. { "line-height": "1.25rem", "color": "var(--primary-text, #000)" }. Set a value to null to reset that property to its default. OPTIONAL.'
|
|
5017
|
+
'A flat map of raw CSS declarations (property \u2192 value), e.g. { "line-height": "1.25rem", "color": "var(--primary-text, #000)" }. font-family must be a single Google Font name or a var(--label) \u2014 no fallback stacks. Set a value to null to reset that property to its default. OPTIONAL.'
|
|
4898
5018
|
);
|
|
4899
5019
|
configureElementToolPrompt.example(`
|
|
4900
5020
|
\`\`\`json
|
|
@@ -4926,36 +5046,39 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
|
|
|
4926
5046
|
V4 only: If MCP fails, give manual steps using V4 UI.
|
|
4927
5047
|
|
|
4928
5048
|
V4 Editor structure:
|
|
4929
|
-
Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
|
|
5049
|
+
Panel tabs: General (\u2192 Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
|
|
4930
5050
|
NO Advanced tab. Never mention Advanced tab.
|
|
5051
|
+
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.
|
|
4931
5052
|
`);
|
|
4932
5053
|
return configureElementToolPrompt.prompt();
|
|
4933
5054
|
};
|
|
4934
|
-
var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
|
|
4935
5055
|
|
|
4936
5056
|
// src/mcp/tools/configure-element/schema.ts
|
|
4937
|
-
import { z
|
|
5057
|
+
import { z } from "@elementor/schema";
|
|
4938
5058
|
var inputSchema = {
|
|
4939
|
-
propertiesToChange:
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
5059
|
+
propertiesToChange: z.record(
|
|
5060
|
+
z.string().describe("The property name."),
|
|
5061
|
+
z.any().describe(`PropValue, refer to [${WIDGET_SCHEMA_URI}] by correct type, as appears in elementType`),
|
|
5062
|
+
z.any()
|
|
4943
5063
|
).describe("An object record containing property names and their new values to be set on the element"),
|
|
4944
|
-
style:
|
|
4945
|
-
|
|
4946
|
-
|
|
5064
|
+
style: z.record(
|
|
5065
|
+
z.string().describe('A CSS property name, e.g. "color", "margin-top".'),
|
|
5066
|
+
z.string().nullable().describe(
|
|
4947
5067
|
'A CSS value, e.g. "red", "10px", "1px solid #000". Use null to reset the property to its default.'
|
|
4948
5068
|
)
|
|
4949
5069
|
).describe(
|
|
4950
5070
|
"Raw CSS declarations as a flat property\u2192value map. Converted to native styles server-side; any declaration that cannot be converted is stored as the element custom CSS. A null value resets that property to its default."
|
|
4951
5071
|
).default({}),
|
|
4952
|
-
elementType:
|
|
4953
|
-
elementId:
|
|
5072
|
+
elementType: z.string().describe("The type of the element to retrieve the schema"),
|
|
5073
|
+
elementId: z.string().describe("The unique id of the element to configure")
|
|
4954
5074
|
};
|
|
4955
5075
|
var outputSchema = {
|
|
4956
|
-
success:
|
|
5076
|
+
success: z.boolean().describe(
|
|
4957
5077
|
"Whether the configuration change was successful, only if propertyName and propertyValue are provided"
|
|
4958
|
-
)
|
|
5078
|
+
),
|
|
5079
|
+
warnings: z.string().describe(
|
|
5080
|
+
'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.'
|
|
5081
|
+
).optional()
|
|
4959
5082
|
};
|
|
4960
5083
|
|
|
4961
5084
|
// src/mcp/tools/configure-element/tool.ts
|
|
@@ -4990,7 +5113,7 @@ var initConfigureElementTool = (reg) => {
|
|
|
4990
5113
|
`Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
|
|
4991
5114
|
);
|
|
4992
5115
|
}
|
|
4993
|
-
const container =
|
|
5116
|
+
const container = getContainer4(elementId);
|
|
4994
5117
|
if (!container) {
|
|
4995
5118
|
throw new Error(`Element with id ${elementId} not found`);
|
|
4996
5119
|
}
|
|
@@ -5005,6 +5128,7 @@ var initConfigureElementTool = (reg) => {
|
|
|
5005
5128
|
}
|
|
5006
5129
|
const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
|
|
5007
5130
|
const toUpdate = Object.entries(propertiesToUpdate);
|
|
5131
|
+
const skippedProps = [];
|
|
5008
5132
|
for (const [propertyName, propertyValue] of toUpdate) {
|
|
5009
5133
|
if (!Schema2.isPropKeyConfigurable(propertyName)) {
|
|
5010
5134
|
throw new Error(`Not allowed to update ${propertyName}`);
|
|
@@ -5017,6 +5141,10 @@ var initConfigureElementTool = (reg) => {
|
|
|
5017
5141
|
propertyValue
|
|
5018
5142
|
});
|
|
5019
5143
|
} catch (error) {
|
|
5144
|
+
if (error instanceof UnsupportedPropertyError) {
|
|
5145
|
+
skippedProps.push(error.propertyName);
|
|
5146
|
+
continue;
|
|
5147
|
+
}
|
|
5020
5148
|
const errorMessage = createUpdateErrorMessage({
|
|
5021
5149
|
propertyName,
|
|
5022
5150
|
elementId,
|
|
@@ -5029,7 +5157,10 @@ var initConfigureElementTool = (reg) => {
|
|
|
5029
5157
|
}
|
|
5030
5158
|
await applyStyleFromCss({ elementId, elementType, style });
|
|
5031
5159
|
return {
|
|
5032
|
-
success: true
|
|
5160
|
+
success: true,
|
|
5161
|
+
warnings: skippedProps.length ? `Skipped unsupported props (not in the "${elementType}" schema; other changes were applied): ${skippedProps.join(
|
|
5162
|
+
", "
|
|
5163
|
+
)}.` : void 0
|
|
5033
5164
|
};
|
|
5034
5165
|
}
|
|
5035
5166
|
});
|
|
@@ -5081,143 +5212,74 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
|
|
|
5081
5212
|
}`;
|
|
5082
5213
|
}
|
|
5083
5214
|
|
|
5084
|
-
// src/mcp/tools/
|
|
5085
|
-
import { getCurrentDocument
|
|
5086
|
-
import { httpService as
|
|
5087
|
-
import { z as
|
|
5088
|
-
|
|
5089
|
-
|
|
5215
|
+
// src/mcp/tools/get-page-structure/tool.ts
|
|
5216
|
+
import { getCurrentDocument } from "@elementor/editor-documents";
|
|
5217
|
+
import { httpService as httpService6 } from "@elementor/http-client";
|
|
5218
|
+
import { z as z2 } from "@elementor/schema";
|
|
5219
|
+
|
|
5220
|
+
// src/mcp/utils/get-mcp-error-message.ts
|
|
5221
|
+
import { AxiosError } from "@elementor/http-client";
|
|
5222
|
+
function getMcpErrorMessage(error, toolName) {
|
|
5223
|
+
if (error instanceof AxiosError) {
|
|
5224
|
+
const data = error.response?.data;
|
|
5225
|
+
if (data?.message) {
|
|
5226
|
+
return data.code ? `${data.code}: ${data.message}` : data.message;
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
if (error instanceof Error) {
|
|
5230
|
+
return error.message;
|
|
5231
|
+
}
|
|
5232
|
+
return `${toolName} failed with an unknown error.`;
|
|
5233
|
+
}
|
|
5234
|
+
|
|
5235
|
+
// src/mcp/tools/get-page-structure/tool.ts
|
|
5236
|
+
var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
|
|
5237
|
+
var initGetPageStructureTool = (reg) => {
|
|
5090
5238
|
const { addTool } = reg;
|
|
5091
5239
|
addTool({
|
|
5092
|
-
name: "
|
|
5093
|
-
description: "
|
|
5240
|
+
name: "get-page-structure",
|
|
5241
|
+
description: "Returns a lean Elementor element tree skeleton (id, elType, widgetType, title, nested elements) for a post or page. If no postId is provided, uses the currently open document. Optionally scope to a subtree with elementId. Set includeContent=true (requires elementId) to also return each node's settings and styles.",
|
|
5094
5242
|
schema: {
|
|
5095
|
-
|
|
5096
|
-
|
|
5243
|
+
postId: z2.number().optional().describe(
|
|
5244
|
+
"WordPress post ID of the Elementor document. If omitted, uses the currently open document."
|
|
5245
|
+
),
|
|
5246
|
+
elementId: z2.string().optional().describe("If provided, returns only the subtree rooted at that element id."),
|
|
5247
|
+
includeContent: z2.boolean().optional().describe(
|
|
5248
|
+
"If true, includes each node's settings and styles (same shape build-composition accepts as input). Requires elementId."
|
|
5249
|
+
)
|
|
5097
5250
|
},
|
|
5098
5251
|
outputSchema: {
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5252
|
+
elements: z2.array(z2.any()).describe(
|
|
5253
|
+
"Skeleton of Elementor elements (id, elType, widgetType, title, nested elements). When includeContent is true, each node also includes settings and styles."
|
|
5254
|
+
)
|
|
5102
5255
|
},
|
|
5103
|
-
handler: async ({
|
|
5104
|
-
const
|
|
5105
|
-
if (!
|
|
5106
|
-
throw new Error("No active document found.");
|
|
5107
|
-
}
|
|
5108
|
-
const { data } = await httpService7().post(MCP_PROXY_URL6, {
|
|
5109
|
-
tool: "create-element",
|
|
5110
|
-
input: {
|
|
5111
|
-
parent_id: parentId ?? "document",
|
|
5112
|
-
element: { type: elementType },
|
|
5113
|
-
post_id: document2.id
|
|
5114
|
-
}
|
|
5115
|
-
});
|
|
5116
|
-
return {
|
|
5117
|
-
elementId: data.data.element_id,
|
|
5118
|
-
previewUrl: data.data.preview_url,
|
|
5119
|
-
version: data.data.version
|
|
5120
|
-
};
|
|
5121
|
-
}
|
|
5122
|
-
});
|
|
5123
|
-
};
|
|
5124
|
-
|
|
5125
|
-
// src/mcp/tools/get-element-config/tool.ts
|
|
5126
|
-
import { getContainer as getContainer6, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
|
|
5127
|
-
import { Schema as Schema3 } from "@elementor/editor-props";
|
|
5128
|
-
import { z as z4 } from "@elementor/schema";
|
|
5129
|
-
var schema = {
|
|
5130
|
-
elementId: z4.string()
|
|
5131
|
-
};
|
|
5132
|
-
var outputSchema2 = {
|
|
5133
|
-
properties: z4.record(z4.string(), z4.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
|
|
5134
|
-
style: z4.record(z4.string(), z4.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
|
|
5135
|
-
childElements: z4.array(
|
|
5136
|
-
z4.object({
|
|
5137
|
-
id: z4.string(),
|
|
5138
|
-
elementType: z4.string(),
|
|
5139
|
-
childElements: z4.array(z4.any()).describe("An array of child element IDs, when applicable, same structure recursively")
|
|
5140
|
-
})
|
|
5141
|
-
).describe("An array of child element IDs, when applicable, with recursive structure")
|
|
5142
|
-
};
|
|
5143
|
-
var structuredElements = (element) => {
|
|
5144
|
-
const children = element.children || [];
|
|
5145
|
-
return children.map((child) => {
|
|
5146
|
-
return {
|
|
5147
|
-
id: child.id,
|
|
5148
|
-
elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
|
|
5149
|
-
childElements: structuredElements(child)
|
|
5150
|
-
};
|
|
5151
|
-
});
|
|
5152
|
-
};
|
|
5153
|
-
var initGetElementConfigTool = (reg) => {
|
|
5154
|
-
const { addTool } = reg;
|
|
5155
|
-
addTool({
|
|
5156
|
-
name: "get-element-configuration-values",
|
|
5157
|
-
description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
|
|
5158
|
-
schema,
|
|
5159
|
-
outputSchema: outputSchema2,
|
|
5160
|
-
handler: async ({ elementId }) => {
|
|
5161
|
-
const element = getContainer6(elementId);
|
|
5162
|
-
if (!element) {
|
|
5163
|
-
throw new Error(`Element with ID ${elementId} not found.`);
|
|
5164
|
-
}
|
|
5165
|
-
const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
|
|
5166
|
-
const widgetData = getWidgetsCache7()?.[elementType];
|
|
5167
|
-
if (!widgetData) {
|
|
5168
|
-
throw new Error(
|
|
5169
|
-
`Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
|
|
5170
|
-
);
|
|
5256
|
+
handler: async ({ postId, elementId, includeContent }) => {
|
|
5257
|
+
const resolvedPostId = postId ?? getCurrentDocument()?.id;
|
|
5258
|
+
if (!resolvedPostId) {
|
|
5259
|
+
throw new Error("No post ID provided and no active document found.");
|
|
5171
5260
|
}
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
if (!elementRawSettings || !propSchema) {
|
|
5180
|
-
throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
|
|
5181
|
-
}
|
|
5182
|
-
const propValues = {};
|
|
5183
|
-
const stylePropValues = {};
|
|
5184
|
-
Schema3.configurableKeys(propSchema).forEach((key) => {
|
|
5185
|
-
propValues[key] = structuredClone(elementRawSettings.get(key));
|
|
5186
|
-
});
|
|
5187
|
-
const elementStyles = getElementStyles2(elementId) || {};
|
|
5188
|
-
const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
|
|
5189
|
-
if (localStyle) {
|
|
5190
|
-
const defaultVariant = localStyle.variants.find(
|
|
5191
|
-
(variant) => variant.meta.breakpoint === "desktop" && !variant.meta.state
|
|
5192
|
-
);
|
|
5193
|
-
if (defaultVariant) {
|
|
5194
|
-
const styleProps = defaultVariant.props || {};
|
|
5195
|
-
Object.keys(styleProps).forEach((stylePropName) => {
|
|
5196
|
-
if (typeof styleProps[stylePropName] !== "undefined") {
|
|
5197
|
-
stylePropValues[stylePropName] = structuredClone(styleProps[stylePropName]);
|
|
5198
|
-
}
|
|
5199
|
-
});
|
|
5200
|
-
if (defaultVariant.custom_css) {
|
|
5201
|
-
stylePropValues.custom_css = atob(defaultVariant.custom_css.raw);
|
|
5261
|
+
try {
|
|
5262
|
+
const { data } = await httpService6().post(MCP_PROXY_URL5, {
|
|
5263
|
+
tool: "get-page-structure",
|
|
5264
|
+
input: {
|
|
5265
|
+
post_id: resolvedPostId,
|
|
5266
|
+
...elementId ? { element_id: elementId } : {},
|
|
5267
|
+
...includeContent ? { include_content: true } : {}
|
|
5202
5268
|
}
|
|
5203
|
-
}
|
|
5269
|
+
});
|
|
5270
|
+
return {
|
|
5271
|
+
elements: data.data.elements
|
|
5272
|
+
};
|
|
5273
|
+
} catch (error) {
|
|
5274
|
+
throw new Error(getMcpErrorMessage(error, "get-page-structure"));
|
|
5204
5275
|
}
|
|
5205
|
-
return {
|
|
5206
|
-
properties: {
|
|
5207
|
-
...propValues
|
|
5208
|
-
},
|
|
5209
|
-
style: {
|
|
5210
|
-
...stylePropValues
|
|
5211
|
-
},
|
|
5212
|
-
childElements: structuredElements(element)
|
|
5213
|
-
};
|
|
5214
5276
|
}
|
|
5215
5277
|
});
|
|
5216
5278
|
};
|
|
5217
5279
|
|
|
5218
5280
|
// src/mcp/canvas-mcp.ts
|
|
5219
5281
|
var initCanvasMcp = (reg) => {
|
|
5220
|
-
|
|
5282
|
+
Schema3.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
|
|
5221
5283
|
initWidgetsSchemaResource(reg);
|
|
5222
5284
|
initAvailableWidgetsResource(reg);
|
|
5223
5285
|
initDocumentStructureResource(reg);
|
|
@@ -5226,17 +5288,15 @@ var initCanvasMcp = (reg) => {
|
|
|
5226
5288
|
initEditorStateResource(reg);
|
|
5227
5289
|
initGeneralContextResource(reg);
|
|
5228
5290
|
initBestPracticesResource(reg);
|
|
5229
|
-
initGetElementConfigTool(reg);
|
|
5230
5291
|
initConfigureElementTool(reg);
|
|
5231
|
-
|
|
5232
|
-
initBuildCompositionTool(reg);
|
|
5292
|
+
initGetPageStructureTool(reg);
|
|
5233
5293
|
initBreakpointsResource(reg);
|
|
5234
5294
|
};
|
|
5235
5295
|
|
|
5236
5296
|
// src/mcp/mcp-description.ts
|
|
5237
5297
|
var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
|
|
5238
5298
|
var mcpDescription = `Elementor Canvas MCP
|
|
5239
|
-
This MCP enables
|
|
5299
|
+
This MCP enables configuration and styling of existing V4 elements on the Elementor canvas using the configure-element tool.
|
|
5240
5300
|
|
|
5241
5301
|
# Core Concepts
|
|
5242
5302
|
|
|
@@ -5255,66 +5315,54 @@ The \`$$type\` defines how Elementor interprets the value. Providing the correct
|
|
|
5255
5315
|
- **Global Classes**: Reusable style sets that can be applied to elements (\`elementor://global-classes\`)
|
|
5256
5316
|
- **Widget Schemas**: Configuration options for each widget type (\`${WIDGET_SCHEMA_URI}\`)
|
|
5257
5317
|
|
|
5258
|
-
#
|
|
5318
|
+
# Configuring Elements with configure-element
|
|
5259
5319
|
|
|
5260
|
-
The \`
|
|
5320
|
+
The \`configure-element\` tool updates settings and styles on existing V4 elements. Read the configure-element guide resource before use.
|
|
5261
5321
|
|
|
5262
5322
|
## Complete Workflow
|
|
5263
5323
|
|
|
5264
5324
|
### 1. Parse User Requirements
|
|
5265
|
-
Understand what needs to
|
|
5325
|
+
Understand what needs to change: content, settings, or styling on existing elements.
|
|
5266
5326
|
|
|
5267
5327
|
### 2. Check Global Resources FIRST
|
|
5268
|
-
Always check existing resources before
|
|
5328
|
+
Always check existing resources before styling:
|
|
5269
5329
|
- List \`elementor://global-variables\` for available variables (colors, sizes, fonts)
|
|
5270
5330
|
- List \`elementor://global-classes\` for available style sets
|
|
5271
5331
|
- **Always prefer using existing global resources over creating inline styles**
|
|
5272
5332
|
|
|
5273
5333
|
### 3. Retrieve Widget Schemas
|
|
5274
|
-
For each
|
|
5334
|
+
For each element you will configure:
|
|
5275
5335
|
- List \`${WIDGET_SCHEMA_URI}\` to see available widgets
|
|
5276
5336
|
- Retrieve configuration schema from \`${ELEMENT_SCHEMA_URI}\` for each widget
|
|
5277
|
-
- Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\`
|
|
5337
|
+
- Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\`
|
|
5278
5338
|
|
|
5279
|
-
### 4.
|
|
5280
|
-
|
|
5281
|
-
- Each element must have a unique \`configuration-id\` attribute
|
|
5282
|
-
- No text nodes, classes, or IDs in XML - structure only
|
|
5283
|
-
- Example:
|
|
5284
|
-
\`\`\`xml
|
|
5285
|
-
<e-container configuration-id="container-1">
|
|
5286
|
-
<e-heading configuration-id="heading-1" />
|
|
5287
|
-
<e-text configuration-id="text-1" />
|
|
5288
|
-
</e-container>
|
|
5289
|
-
\`\`\`
|
|
5339
|
+
### 4. Get Current Element State
|
|
5340
|
+
Use page structure and element configuration resources to find element IDs and current values.
|
|
5290
5341
|
|
|
5291
|
-
### 5. Create
|
|
5292
|
-
Map
|
|
5342
|
+
### 5. Create propertiesToChange
|
|
5343
|
+
Map property names to PropValues using the widget schema:
|
|
5293
5344
|
- Use correct \`$$type\` matching the widget's schema
|
|
5294
5345
|
- Use global variables in PropValues where applicable
|
|
5295
5346
|
- Example:
|
|
5296
5347
|
\`\`\`json
|
|
5297
5348
|
{
|
|
5298
|
-
"
|
|
5299
|
-
|
|
5300
|
-
"tag": { "$$type": "string", "value": "h1" }
|
|
5301
|
-
}
|
|
5349
|
+
"text": { "$$type": "string", "value": "Welcome" },
|
|
5350
|
+
"tag": { "$$type": "string", "value": "h1" }
|
|
5302
5351
|
}
|
|
5303
5352
|
\`\`\`
|
|
5304
5353
|
|
|
5305
5354
|
### 6. Create style
|
|
5306
|
-
|
|
5355
|
+
Provide raw CSS declarations (property \u2192 value strings). The server converts them to native styles and stores any unconvertible declarations as the element custom CSS.
|
|
5307
5356
|
- Example:
|
|
5308
5357
|
\`\`\`json
|
|
5309
5358
|
{
|
|
5310
|
-
"
|
|
5311
|
-
|
|
5359
|
+
"color": "#1a1a1a",
|
|
5360
|
+
"font-size": "2rem"
|
|
5312
5361
|
}
|
|
5313
5362
|
\`\`\`
|
|
5314
5363
|
|
|
5315
|
-
### 7. Execute
|
|
5316
|
-
Call the tool with
|
|
5317
|
-
At the response you will also find llm_instructions for you to do afterwards, read and follow them!
|
|
5364
|
+
### 7. Execute configure-element
|
|
5365
|
+
Call the tool with elementId, elementType, propertiesToChange, and style as needed.
|
|
5318
5366
|
|
|
5319
5367
|
## Key Points
|
|
5320
5368
|
|
|
@@ -5429,7 +5477,7 @@ function shouldBlock(sourceElements, targetElements) {
|
|
|
5429
5477
|
}
|
|
5430
5478
|
|
|
5431
5479
|
// src/style-commands/paste-style.ts
|
|
5432
|
-
import { getContainer as
|
|
5480
|
+
import { getContainer as getContainer5, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
|
|
5433
5481
|
import { classesPropTypeUtil } from "@elementor/editor-props";
|
|
5434
5482
|
import {
|
|
5435
5483
|
__privateListenTo as listenTo5,
|
|
@@ -5438,7 +5486,7 @@ import {
|
|
|
5438
5486
|
} from "@elementor/editor-v1-adapters";
|
|
5439
5487
|
|
|
5440
5488
|
// src/utils/command-utils.ts
|
|
5441
|
-
import { getElementLabel as getElementLabel2, getWidgetsCache as
|
|
5489
|
+
import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
|
|
5442
5490
|
import { CLASSES_PROP_KEY } from "@elementor/editor-props";
|
|
5443
5491
|
import { __ as __5 } from "@wordpress/i18n";
|
|
5444
5492
|
function hasAtomicWidgets(args) {
|
|
@@ -5463,7 +5511,7 @@ function getClassesProp(container) {
|
|
|
5463
5511
|
}
|
|
5464
5512
|
function getContainerSchema(container) {
|
|
5465
5513
|
const type = container?.model.get("widgetType") || container?.model.get("elType");
|
|
5466
|
-
const widgetsCache =
|
|
5514
|
+
const widgetsCache = getWidgetsCache7();
|
|
5467
5515
|
const elementType = widgetsCache?.[type];
|
|
5468
5516
|
return elementType?.atomic_props_schema ?? null;
|
|
5469
5517
|
}
|
|
@@ -5483,7 +5531,7 @@ function getTitleForContainers(containers) {
|
|
|
5483
5531
|
import {
|
|
5484
5532
|
createElementStyle as createElementStyle2,
|
|
5485
5533
|
deleteElementStyle,
|
|
5486
|
-
getElementStyles as
|
|
5534
|
+
getElementStyles as getElementStyles2,
|
|
5487
5535
|
updateElementStyle as updateElementStyle2
|
|
5488
5536
|
} from "@elementor/editor-elements";
|
|
5489
5537
|
import { ELEMENTS_STYLES_RESERVED_LABEL } from "@elementor/editor-styles-repository";
|
|
@@ -5498,7 +5546,7 @@ var undoablePasteElementStyle = () => undoable2(
|
|
|
5498
5546
|
if (!classesProp) {
|
|
5499
5547
|
return null;
|
|
5500
5548
|
}
|
|
5501
|
-
const originalStyles =
|
|
5549
|
+
const originalStyles = getElementStyles2(container.id);
|
|
5502
5550
|
const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
|
|
5503
5551
|
const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
|
|
5504
5552
|
const revertData = {
|
|
@@ -5582,7 +5630,7 @@ function pasteStyles(args, pasteLocalStyle) {
|
|
|
5582
5630
|
}
|
|
5583
5631
|
const clipboardElements = getClipboardElements(storageKey);
|
|
5584
5632
|
const [clipboardElement] = clipboardElements ?? [];
|
|
5585
|
-
const clipboardContainer =
|
|
5633
|
+
const clipboardContainer = getContainer5(clipboardElement.id);
|
|
5586
5634
|
if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
|
|
5587
5635
|
return;
|
|
5588
5636
|
}
|
|
@@ -5628,7 +5676,7 @@ import {
|
|
|
5628
5676
|
} from "@elementor/editor-v1-adapters";
|
|
5629
5677
|
|
|
5630
5678
|
// src/style-commands/undoable-actions/reset-element-style.ts
|
|
5631
|
-
import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as
|
|
5679
|
+
import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles3 } from "@elementor/editor-elements";
|
|
5632
5680
|
import { ELEMENTS_STYLES_RESERVED_LABEL as ELEMENTS_STYLES_RESERVED_LABEL2 } from "@elementor/editor-styles-repository";
|
|
5633
5681
|
import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
|
|
5634
5682
|
import { __ as __7 } from "@wordpress/i18n";
|
|
@@ -5637,7 +5685,7 @@ var undoableResetElementStyle = () => undoable3(
|
|
|
5637
5685
|
do: ({ containers }) => {
|
|
5638
5686
|
return containers.map((container) => {
|
|
5639
5687
|
const elementId = container.model.get("id");
|
|
5640
|
-
const containerStyles =
|
|
5688
|
+
const containerStyles = getElementStyles3(elementId);
|
|
5641
5689
|
Object.keys(containerStyles ?? {}).forEach(
|
|
5642
5690
|
(styleId) => deleteElementStyle2(elementId, styleId)
|
|
5643
5691
|
);
|
|
@@ -5729,15 +5777,15 @@ function init() {
|
|
|
5729
5777
|
initCanvasMcp(
|
|
5730
5778
|
getMCPByDomain("canvas", {
|
|
5731
5779
|
instructions: `Everything related to V4 ( Atomic ) canvas.
|
|
5732
|
-
# Canvas workflow
|
|
5733
|
-
- Configure
|
|
5734
|
-
-
|
|
5735
|
-
- Get and retrieve element configuration values
|
|
5780
|
+
# Canvas workflow
|
|
5781
|
+
- Configure element settings and styles with configure-element
|
|
5782
|
+
- Get page structure and element configuration values
|
|
5736
5783
|
`,
|
|
5737
5784
|
docs: mcpDescription
|
|
5738
5785
|
})
|
|
5739
5786
|
);
|
|
5740
5787
|
initTabsModelExtensions();
|
|
5788
|
+
initListType();
|
|
5741
5789
|
}
|
|
5742
5790
|
|
|
5743
5791
|
// src/sync/drag-element-from-panel.ts
|
|
@@ -5859,10 +5907,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
|
|
|
5859
5907
|
}
|
|
5860
5908
|
|
|
5861
5909
|
// src/utils/after-render.ts
|
|
5862
|
-
import { getContainer as
|
|
5910
|
+
import { getContainer as getContainer6 } from "@elementor/editor-elements";
|
|
5863
5911
|
function doAfterRender(elementIds, callback) {
|
|
5864
5912
|
const pending = elementIds.map((elementId) => {
|
|
5865
|
-
const view =
|
|
5913
|
+
const view = getContainer6(elementId)?.view;
|
|
5866
5914
|
if (!view || !hasDoAfterRender(view)) {
|
|
5867
5915
|
return void 0;
|
|
5868
5916
|
}
|