@elementor/editor-canvas 4.3.0-999 → 4.3.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +535 -393
- package/dist/index.mjs +516 -370
- package/package.json +20 -20
- package/src/__tests__/flex-transformer.test.ts +11 -11
- package/src/__tests__/prop-types.ts +11 -0
- 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 -4
- 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 +199 -0
- package/src/transformers/shared/icon-transformer.ts +231 -0
- package/src/transformers/shared/process-svg-content.ts +26 -0
- package/src/transformers/shared/svg-src-transformer.ts +1 -26
- package/src/transformers/styles/flex-transformer.ts +11 -32
- 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/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,172 @@ 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
|
+
aliases: 2,
|
|
2088
|
+
unicode: 3,
|
|
2089
|
+
path: 4
|
|
2090
|
+
};
|
|
2091
|
+
var fontAwesomeJsonCache = /* @__PURE__ */ new Map();
|
|
2092
|
+
var iconTransformer = createTransformer(async (value, { signal }) => {
|
|
2093
|
+
const iconValue = typeof value.value === "string" ? value.value : null;
|
|
2094
|
+
const library = typeof value.library === "string" ? value.library : null;
|
|
2095
|
+
if (!iconValue || !library) {
|
|
2096
|
+
return { html: null, url: null };
|
|
2097
|
+
}
|
|
2098
|
+
const iconName = getFontAwesomeIconName(iconValue);
|
|
2099
|
+
const jsonFileName = getFontAwesomeJsonFileName(library);
|
|
2100
|
+
if (!iconName || !jsonFileName) {
|
|
2101
|
+
return { html: null, url: null };
|
|
2102
|
+
}
|
|
2103
|
+
const icons = await fetchFontAwesomeIcons(jsonFileName, signal);
|
|
2104
|
+
const iconData = icons?.[iconName];
|
|
2105
|
+
if (!iconData) {
|
|
2106
|
+
return { html: null, url: null };
|
|
2107
|
+
}
|
|
2108
|
+
const svgText = buildFontAwesomeSvg(iconData);
|
|
2109
|
+
if (!svgText) {
|
|
2110
|
+
return { html: null, url: null };
|
|
2111
|
+
}
|
|
2112
|
+
const html = processIconSvgContent(svgText);
|
|
2113
|
+
return { html, url: null };
|
|
2114
|
+
});
|
|
2115
|
+
function getFontAwesomeIconName(iconValue) {
|
|
2116
|
+
const match = iconValue.match(/^fa\S*\s+fa-(.+)$/);
|
|
2117
|
+
return match?.[1] ?? null;
|
|
2118
|
+
}
|
|
2119
|
+
function getFontAwesomeJsonFileName(library) {
|
|
2120
|
+
const fileName = library.replace(/^fa-/, "");
|
|
2121
|
+
const config = getFontAwesome7EditorConfig();
|
|
2122
|
+
if (!config?.jsonFiles.includes(fileName)) {
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
return fileName;
|
|
2126
|
+
}
|
|
2127
|
+
function getFontAwesome7EditorConfig() {
|
|
2128
|
+
const config = window.elementorCommon?.config?.fontAwesome?.v7;
|
|
2129
|
+
if (!config || !Array.isArray(config.jsonFiles) || typeof config.jsonBaseUrl !== "string" || config.jsonBaseUrl === "") {
|
|
2130
|
+
return null;
|
|
2131
|
+
}
|
|
2132
|
+
return {
|
|
2133
|
+
jsonFiles: config.jsonFiles,
|
|
2134
|
+
jsonBaseUrl: config.jsonBaseUrl
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2137
|
+
async function fetchFontAwesomeIcons(jsonFileName, signal) {
|
|
2138
|
+
const cached = fontAwesomeJsonCache.get(jsonFileName);
|
|
2139
|
+
if (cached) {
|
|
2140
|
+
return cached;
|
|
2141
|
+
}
|
|
2142
|
+
const icons = await loadFontAwesomeIcons(jsonFileName, signal);
|
|
2143
|
+
if (icons) {
|
|
2144
|
+
fontAwesomeJsonCache.set(jsonFileName, icons);
|
|
2145
|
+
}
|
|
2146
|
+
return icons;
|
|
2147
|
+
}
|
|
2148
|
+
async function loadFontAwesomeIcons(jsonFileName, signal) {
|
|
2149
|
+
const config = getFontAwesome7EditorConfig();
|
|
2150
|
+
if (!config?.jsonFiles.includes(jsonFileName)) {
|
|
2151
|
+
return null;
|
|
2152
|
+
}
|
|
2153
|
+
try {
|
|
2154
|
+
const response = await fetch(`${config.jsonBaseUrl}${jsonFileName}.json`, {
|
|
2155
|
+
signal
|
|
2156
|
+
});
|
|
2157
|
+
if (!response.ok) {
|
|
2158
|
+
return null;
|
|
2159
|
+
}
|
|
2160
|
+
const data = await response.json();
|
|
2161
|
+
const icons = data.icons;
|
|
2162
|
+
if (!icons || typeof icons !== "object") {
|
|
2163
|
+
return null;
|
|
2164
|
+
}
|
|
2165
|
+
return indexFontAwesomeIcons(icons);
|
|
2166
|
+
} catch {
|
|
2167
|
+
return null;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
function indexFontAwesomeIcons(icons) {
|
|
2171
|
+
const index = {};
|
|
2172
|
+
for (const [name, iconData] of Object.entries(icons)) {
|
|
2173
|
+
if (!isValidIconTuple(iconData)) {
|
|
2174
|
+
continue;
|
|
2175
|
+
}
|
|
2176
|
+
index[name] = iconData;
|
|
2177
|
+
for (const alias of iconData[FONT_AWESOME_JSON.aliases]) {
|
|
2178
|
+
if (typeof alias === "string" && alias !== "" && !index[alias]) {
|
|
2179
|
+
index[alias] = iconData;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
return index;
|
|
2184
|
+
}
|
|
2185
|
+
function isValidIconTuple(iconData) {
|
|
2186
|
+
return Array.isArray(iconData) && iconData.length >= 5 && typeof iconData[FONT_AWESOME_JSON.width] === "number" && typeof iconData[FONT_AWESOME_JSON.height] === "number" && Array.isArray(iconData[FONT_AWESOME_JSON.aliases]);
|
|
2187
|
+
}
|
|
2188
|
+
function buildFontAwesomeSvg(iconData) {
|
|
2189
|
+
const width = iconData[FONT_AWESOME_JSON.width];
|
|
2190
|
+
const height = iconData[FONT_AWESOME_JSON.height];
|
|
2191
|
+
const paths = normalizePaths(iconData[FONT_AWESOME_JSON.path]);
|
|
2192
|
+
if (paths.length === 0) {
|
|
2193
|
+
return null;
|
|
2194
|
+
}
|
|
2195
|
+
const pathMarkup = paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
|
|
2196
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">${pathMarkup}</svg>`;
|
|
2197
|
+
}
|
|
2198
|
+
function normalizePaths(pathData) {
|
|
2199
|
+
if (typeof pathData === "string" && pathData !== "") {
|
|
2200
|
+
return [pathData];
|
|
2201
|
+
}
|
|
2202
|
+
if (!Array.isArray(pathData)) {
|
|
2203
|
+
return [];
|
|
2204
|
+
}
|
|
2205
|
+
return pathData.filter((path) => typeof path === "string" && path !== "");
|
|
2206
|
+
}
|
|
2207
|
+
function escapeSvgPath(path) {
|
|
2208
|
+
return path.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2209
|
+
}
|
|
2210
|
+
function processIconSvgContent(svgText) {
|
|
2211
|
+
const html = processSvgContent(svgText);
|
|
2212
|
+
if (!html) {
|
|
2213
|
+
return null;
|
|
2214
|
+
}
|
|
2215
|
+
const parser = new DOMParser();
|
|
2216
|
+
const doc = parser.parseFromString(html, "image/svg+xml");
|
|
2217
|
+
const svgElement = doc.querySelector("svg");
|
|
2218
|
+
if (!svgElement) {
|
|
2219
|
+
return null;
|
|
2220
|
+
}
|
|
2221
|
+
svgElement.setAttribute("aria-hidden", "true");
|
|
2222
|
+
svgElement.style.setProperty("width", "100%");
|
|
2223
|
+
svgElement.style.setProperty("height", "100%");
|
|
2224
|
+
svgElement.style.setProperty("overflow", "visible");
|
|
2225
|
+
return svgElement.outerHTML;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2028
2228
|
// src/transformers/shared/image-src-transformer.ts
|
|
2029
2229
|
var imageSrcTransformer = createTransformer((value) => ({
|
|
2030
2230
|
id: value.id ?? null,
|
|
@@ -2066,26 +2266,7 @@ var plainTransformer = createTransformer((value) => {
|
|
|
2066
2266
|
});
|
|
2067
2267
|
|
|
2068
2268
|
// src/transformers/shared/svg-src-transformer.ts
|
|
2069
|
-
import DOMPurify from "dompurify";
|
|
2070
2269
|
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
2270
|
async function fetchSvgContent(url, signal) {
|
|
2090
2271
|
try {
|
|
2091
2272
|
const response = await fetch(url, { signal });
|
|
@@ -2141,7 +2322,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
|
|
|
2141
2322
|
|
|
2142
2323
|
// src/init-settings-transformers.ts
|
|
2143
2324
|
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);
|
|
2325
|
+
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
2326
|
}
|
|
2146
2327
|
|
|
2147
2328
|
// src/transformers/styles/background-color-overlay-transformer.ts
|
|
@@ -2287,6 +2468,10 @@ var mapToFilterFunctionString = (value) => {
|
|
|
2287
2468
|
};
|
|
2288
2469
|
|
|
2289
2470
|
// src/transformers/styles/flex-transformer.ts
|
|
2471
|
+
var DEFAULT_FLEX_GROW = 0;
|
|
2472
|
+
var DEFAULT_FLEX_SHRINK = 1;
|
|
2473
|
+
var DEFAULT_FLEX_BASIS = "auto";
|
|
2474
|
+
var formatBasis = (basis) => typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis;
|
|
2290
2475
|
var flexTransformer = createTransformer((value) => {
|
|
2291
2476
|
const grow = value.flexGrow;
|
|
2292
2477
|
const shrink = value.flexShrink;
|
|
@@ -2297,28 +2482,10 @@ var flexTransformer = createTransformer((value) => {
|
|
|
2297
2482
|
if (!hasGrow && !hasShrink && !hasBasis) {
|
|
2298
2483
|
return null;
|
|
2299
2484
|
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
return `${grow} ${shrink}`;
|
|
2305
|
-
}
|
|
2306
|
-
if (hasGrow && !hasShrink && hasBasis) {
|
|
2307
|
-
return `${grow} 1 ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
|
|
2308
|
-
}
|
|
2309
|
-
if (!hasGrow && hasShrink && hasBasis) {
|
|
2310
|
-
return `0 ${shrink} ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
|
|
2311
|
-
}
|
|
2312
|
-
if (hasGrow && !hasShrink && !hasBasis) {
|
|
2313
|
-
return `${grow}`;
|
|
2314
|
-
}
|
|
2315
|
-
if (!hasGrow && hasShrink && !hasBasis) {
|
|
2316
|
-
return `0 ${shrink}`;
|
|
2317
|
-
}
|
|
2318
|
-
if (!hasGrow && !hasShrink && hasBasis) {
|
|
2319
|
-
return `0 1 ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
|
|
2320
|
-
}
|
|
2321
|
-
return null;
|
|
2485
|
+
const growOut = hasGrow ? grow : DEFAULT_FLEX_GROW;
|
|
2486
|
+
const shrinkOut = hasShrink ? shrink : DEFAULT_FLEX_SHRINK;
|
|
2487
|
+
const basisOut = hasBasis ? formatBasis(basis) : DEFAULT_FLEX_BASIS;
|
|
2488
|
+
return `${growOut} ${shrinkOut} ${basisOut}`;
|
|
2322
2489
|
});
|
|
2323
2490
|
|
|
2324
2491
|
// src/transformers/styles/font-family-transformer.ts
|
|
@@ -2418,11 +2585,11 @@ function getVal2(val) {
|
|
|
2418
2585
|
var transformOriginTransformer = createTransformer((value) => {
|
|
2419
2586
|
const x = getVal2(value.x);
|
|
2420
2587
|
const y = getVal2(value.y);
|
|
2421
|
-
const
|
|
2422
|
-
if (x === DEFAULT_XY && y === DEFAULT_XY &&
|
|
2588
|
+
const z3 = getVal2(value.z);
|
|
2589
|
+
if (x === DEFAULT_XY && y === DEFAULT_XY && z3 === DEFAULT_Z) {
|
|
2423
2590
|
return null;
|
|
2424
2591
|
}
|
|
2425
|
-
return `${x} ${y} ${
|
|
2592
|
+
return `${x} ${y} ${z3}`;
|
|
2426
2593
|
});
|
|
2427
2594
|
|
|
2428
2595
|
// src/transformers/styles/transform-rotate-transformer.ts
|
|
@@ -2500,13 +2667,13 @@ function initStyleTransformers() {
|
|
|
2500
2667
|
"layout-direction",
|
|
2501
2668
|
createMultiPropsTransformer(["row", "column"], ({ propKey, key }) => `${key}-${propKey}`)
|
|
2502
2669
|
).register("flex", flexTransformer).register(
|
|
2503
|
-
"border-width",
|
|
2670
|
+
"border-width-v2",
|
|
2504
2671
|
createMultiPropsTransformer(
|
|
2505
2672
|
["block-start", "block-end", "inline-start", "inline-end"],
|
|
2506
2673
|
({ key }) => `border-${key}-width`
|
|
2507
2674
|
)
|
|
2508
2675
|
).register(
|
|
2509
|
-
"border-radius",
|
|
2676
|
+
"border-radius-v2",
|
|
2510
2677
|
createMultiPropsTransformer(
|
|
2511
2678
|
["start-start", "start-end", "end-start", "end-end"],
|
|
2512
2679
|
({ key }) => `border-${key}-radius`
|
|
@@ -2530,28 +2697,13 @@ function createDomRenderer() {
|
|
|
2530
2697
|
render: environment.render
|
|
2531
2698
|
};
|
|
2532
2699
|
}
|
|
2700
|
+
function getAllowedHtmlWrapperTags2() {
|
|
2701
|
+
return window.elementorCommon?.config?.allowedHTMLWrapperTags ?? [];
|
|
2702
|
+
}
|
|
2533
2703
|
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";
|
|
2704
|
+
const allowedTags = getAllowedHtmlWrapperTags2();
|
|
2705
|
+
const normalizedTag = value?.toLowerCase?.() ?? "";
|
|
2706
|
+
return allowedTags.includes(normalizedTag) ? value : "div";
|
|
2555
2707
|
}
|
|
2556
2708
|
function escapeURL(value) {
|
|
2557
2709
|
const allowedProtocols = ["http:", "https:", "mailto:", "tel:"];
|
|
@@ -2646,6 +2798,52 @@ function createElementViewClassDeclaration() {
|
|
|
2646
2798
|
// src/legacy/create-nested-templated-element-type.ts
|
|
2647
2799
|
import { ELEMENT_STYLE_CHANGE_EVENT as ELEMENT_STYLE_CHANGE_EVENT2 } from "@elementor/editor-elements";
|
|
2648
2800
|
|
|
2801
|
+
// src/renderers/compute-html-tag.ts
|
|
2802
|
+
var DEFAULT_LINK_TAG = "a";
|
|
2803
|
+
function computeHtmlTag(settings, defaultTag, options = {}) {
|
|
2804
|
+
const followLink = options.followLink ?? true;
|
|
2805
|
+
if (followLink && settingsHaveActiveLink(settings)) {
|
|
2806
|
+
const link = settings.link;
|
|
2807
|
+
return extractLinkHtmlTag(isRecord(link) ? link : {});
|
|
2808
|
+
}
|
|
2809
|
+
const settingsTag = extractHtmlTagValue(settings.tag);
|
|
2810
|
+
if (null !== settingsTag && "" !== settingsTag) {
|
|
2811
|
+
return settingsTag;
|
|
2812
|
+
}
|
|
2813
|
+
return defaultTag;
|
|
2814
|
+
}
|
|
2815
|
+
function settingsHaveActiveLink(settings) {
|
|
2816
|
+
const link = settings.link;
|
|
2817
|
+
if (!isRecord(link)) {
|
|
2818
|
+
return false;
|
|
2819
|
+
}
|
|
2820
|
+
const href = extractHtmlTagValue(link.href);
|
|
2821
|
+
if (null !== href && "" !== href) {
|
|
2822
|
+
return true;
|
|
2823
|
+
}
|
|
2824
|
+
const attributes = link.attributes;
|
|
2825
|
+
return typeof attributes === "string" && "" !== attributes;
|
|
2826
|
+
}
|
|
2827
|
+
function extractLinkHtmlTag(link) {
|
|
2828
|
+
const tag = extractHtmlTagValue(link.tag);
|
|
2829
|
+
if (null !== tag && "" !== tag) {
|
|
2830
|
+
return tag;
|
|
2831
|
+
}
|
|
2832
|
+
return DEFAULT_LINK_TAG;
|
|
2833
|
+
}
|
|
2834
|
+
function extractHtmlTagValue(value) {
|
|
2835
|
+
if (isRecord(value) && typeof value.value === "string") {
|
|
2836
|
+
return value.value;
|
|
2837
|
+
}
|
|
2838
|
+
if (typeof value === "string") {
|
|
2839
|
+
return value;
|
|
2840
|
+
}
|
|
2841
|
+
return null;
|
|
2842
|
+
}
|
|
2843
|
+
function isRecord(value) {
|
|
2844
|
+
return typeof value === "object" && null !== value && !Array.isArray(value);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2649
2847
|
// src/legacy/create-pending-element.ts
|
|
2650
2848
|
import {
|
|
2651
2849
|
addModelToParent,
|
|
@@ -2711,7 +2909,13 @@ function setupTwigRenderer({ renderer, element }) {
|
|
|
2711
2909
|
transformers: settingsTransformersRegistry,
|
|
2712
2910
|
schema: element.atomic_props_schema
|
|
2713
2911
|
});
|
|
2714
|
-
return {
|
|
2912
|
+
return {
|
|
2913
|
+
templateKey,
|
|
2914
|
+
baseStylesDictionary,
|
|
2915
|
+
resolveProps,
|
|
2916
|
+
defaultHtmlTag: element.default_html_tag ?? "div",
|
|
2917
|
+
htmlTagFollowsLink: element.html_tag_follows_link ?? true
|
|
2918
|
+
};
|
|
2715
2919
|
}
|
|
2716
2920
|
function createBeforeRender(view) {
|
|
2717
2921
|
view._ensureViewIsIntact();
|
|
@@ -2751,7 +2955,7 @@ function createTemplatedElementView({
|
|
|
2751
2955
|
element
|
|
2752
2956
|
}) {
|
|
2753
2957
|
const BaseView = createElementViewClassDeclaration();
|
|
2754
|
-
const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
|
|
2958
|
+
const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
|
|
2755
2959
|
type,
|
|
2756
2960
|
renderer,
|
|
2757
2961
|
element
|
|
@@ -2821,6 +3025,7 @@ function createTemplatedElementView({
|
|
|
2821
3025
|
interaction_id: this.getInteractionId(),
|
|
2822
3026
|
type,
|
|
2823
3027
|
settings,
|
|
3028
|
+
tag: computeHtmlTag(settings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
|
|
2824
3029
|
base_styles: baseStylesDictionary,
|
|
2825
3030
|
...this.getResolverRenderContext?.() ?? {}
|
|
2826
3031
|
};
|
|
@@ -2910,7 +3115,7 @@ function createNestedTemplatedElementView({
|
|
|
2910
3115
|
element
|
|
2911
3116
|
}) {
|
|
2912
3117
|
const legacyWindow = window;
|
|
2913
|
-
const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
|
|
3118
|
+
const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
|
|
2914
3119
|
type,
|
|
2915
3120
|
renderer,
|
|
2916
3121
|
element
|
|
@@ -2985,6 +3190,7 @@ function createNestedTemplatedElementView({
|
|
|
2985
3190
|
interaction_id: this.getInteractionId(),
|
|
2986
3191
|
type,
|
|
2987
3192
|
settings: resolvedSettings,
|
|
3193
|
+
tag: computeHtmlTag(resolvedSettings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
|
|
2988
3194
|
base_styles: baseStylesDictionary,
|
|
2989
3195
|
editor_attributes: buildEditorAttributes(model),
|
|
2990
3196
|
editor_classes: buildEditorClasses(model),
|
|
@@ -3208,8 +3414,8 @@ import { createRoot } from "react-dom/client";
|
|
|
3208
3414
|
import * as React11 from "react";
|
|
3209
3415
|
import { getContainer as getContainer2, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
|
|
3210
3416
|
import {
|
|
3417
|
+
escapedHtmlPropTypeUtil as escapedHtmlPropTypeUtil2,
|
|
3211
3418
|
htmlV3PropTypeUtil as htmlV3PropTypeUtil2,
|
|
3212
|
-
parseHtmlChildren,
|
|
3213
3419
|
stringPropTypeUtil as stringPropTypeUtil2
|
|
3214
3420
|
} from "@elementor/editor-props";
|
|
3215
3421
|
import { __privateRunCommandSync as runCommandSync, getCurrentEditMode, undoable } from "@elementor/editor-v1-adapters";
|
|
@@ -3488,11 +3694,15 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
|
|
|
3488
3694
|
};
|
|
3489
3695
|
|
|
3490
3696
|
// src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
|
|
3491
|
-
import {
|
|
3697
|
+
import {
|
|
3698
|
+
escapedHtmlPropTypeUtil,
|
|
3699
|
+
htmlV3PropTypeUtil,
|
|
3700
|
+
stringPropTypeUtil
|
|
3701
|
+
} from "@elementor/editor-props";
|
|
3492
3702
|
var hasKey = (propType) => {
|
|
3493
3703
|
return "key" in propType;
|
|
3494
3704
|
};
|
|
3495
|
-
var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([htmlV3PropTypeUtil.key, stringPropTypeUtil.key]);
|
|
3705
|
+
var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([escapedHtmlPropTypeUtil.key, htmlV3PropTypeUtil.key, stringPropTypeUtil.key]);
|
|
3496
3706
|
var isCoreTextPropTypeKey = (key) => {
|
|
3497
3707
|
return TEXT_PROP_TYPE_KEYS.has(key);
|
|
3498
3708
|
};
|
|
@@ -3512,7 +3722,7 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
|
|
|
3512
3722
|
if (rawValue === null || rawValue === void 0) {
|
|
3513
3723
|
return isAllowedBySchema(propTypeFromSchema);
|
|
3514
3724
|
}
|
|
3515
|
-
return htmlV3PropTypeUtil.isValid(rawValue) || stringPropTypeUtil.isValid(rawValue);
|
|
3725
|
+
return escapedHtmlPropTypeUtil.isValid(rawValue) || htmlV3PropTypeUtil.isValid(rawValue) || stringPropTypeUtil.isValid(rawValue);
|
|
3516
3726
|
};
|
|
3517
3727
|
|
|
3518
3728
|
// src/legacy/replacements/inline-editing/inline-editing-elements.tsx
|
|
@@ -3597,17 +3807,26 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
3597
3807
|
}
|
|
3598
3808
|
getExtractedContentValue() {
|
|
3599
3809
|
const propValue = this.getInlineEditablePropValue();
|
|
3810
|
+
if (escapedHtmlPropTypeUtil2.isValid(propValue)) {
|
|
3811
|
+
return escapedHtmlPropTypeUtil2.extract(propValue) ?? "";
|
|
3812
|
+
}
|
|
3600
3813
|
const extracted = htmlV3PropTypeUtil2.extract(propValue);
|
|
3601
3814
|
return stringPropTypeUtil2.extract(extracted?.content ?? null) ?? "";
|
|
3602
3815
|
}
|
|
3816
|
+
createContentPropValue(value) {
|
|
3817
|
+
const content = value || "";
|
|
3818
|
+
const propTypeKey = this.getInlineEditablePropTypeKey();
|
|
3819
|
+
if (propTypeKey === htmlV3PropTypeUtil2.key) {
|
|
3820
|
+
return htmlV3PropTypeUtil2.create({
|
|
3821
|
+
content: stringPropTypeUtil2.create(content),
|
|
3822
|
+
children: []
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
return escapedHtmlPropTypeUtil2.create(content);
|
|
3826
|
+
}
|
|
3603
3827
|
setContentValue(value) {
|
|
3604
3828
|
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
|
-
});
|
|
3829
|
+
const valueToSave = this.createContentPropValue(value);
|
|
3611
3830
|
undoable(
|
|
3612
3831
|
{
|
|
3613
3832
|
do: () => {
|
|
@@ -3636,7 +3855,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
3636
3855
|
return null;
|
|
3637
3856
|
}
|
|
3638
3857
|
if (propType.kind === "union") {
|
|
3639
|
-
const textKeys = [htmlV3PropTypeUtil2.key, stringPropTypeUtil2.key];
|
|
3858
|
+
const textKeys = [escapedHtmlPropTypeUtil2.key, htmlV3PropTypeUtil2.key, stringPropTypeUtil2.key];
|
|
3640
3859
|
for (const key of textKeys) {
|
|
3641
3860
|
if (propType.prop_types[key]) {
|
|
3642
3861
|
return key;
|
|
@@ -3891,8 +4110,54 @@ function createNestedTemplatedType(type, renderer, element) {
|
|
|
3891
4110
|
});
|
|
3892
4111
|
}
|
|
3893
4112
|
|
|
4113
|
+
// src/legacy/list-type.ts
|
|
4114
|
+
var LIST_TYPE = "e-list";
|
|
4115
|
+
function initListType() {
|
|
4116
|
+
registerElementType(
|
|
4117
|
+
LIST_TYPE,
|
|
4118
|
+
(options) => createListType(options)
|
|
4119
|
+
);
|
|
4120
|
+
}
|
|
4121
|
+
function createListType(options) {
|
|
4122
|
+
const BaseType = createNestedTemplatedElementType(options);
|
|
4123
|
+
let ListView = null;
|
|
4124
|
+
return class extends BaseType {
|
|
4125
|
+
getView() {
|
|
4126
|
+
if (!ListView) {
|
|
4127
|
+
ListView = createListView(options);
|
|
4128
|
+
}
|
|
4129
|
+
return ListView;
|
|
4130
|
+
}
|
|
4131
|
+
};
|
|
4132
|
+
}
|
|
4133
|
+
function createListView(options) {
|
|
4134
|
+
const BaseView = createNestedTemplatedElementView(options);
|
|
4135
|
+
return BaseView.extend({
|
|
4136
|
+
getRenderContext() {
|
|
4137
|
+
const parentContext = this._parent?.getRenderContext?.();
|
|
4138
|
+
const settings = this.model.get("settings");
|
|
4139
|
+
const showMarkersProp = settings?.get?.("show_markers");
|
|
4140
|
+
const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
|
|
4141
|
+
return {
|
|
4142
|
+
...parentContext,
|
|
4143
|
+
show_markers: showMarkers
|
|
4144
|
+
};
|
|
4145
|
+
},
|
|
4146
|
+
getResolverRenderContext() {
|
|
4147
|
+
const parentContext = this._parent?.getResolverRenderContext?.();
|
|
4148
|
+
const settings = this.model.get("settings");
|
|
4149
|
+
const showMarkersProp = settings?.get?.("show_markers");
|
|
4150
|
+
const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
|
|
4151
|
+
return {
|
|
4152
|
+
...parentContext,
|
|
4153
|
+
show_markers: showMarkers
|
|
4154
|
+
};
|
|
4155
|
+
}
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4158
|
+
|
|
3894
4159
|
// src/legacy/tabs-model-extensions.ts
|
|
3895
|
-
import {
|
|
4160
|
+
import { escapedHtmlPropTypeUtil as escapedHtmlPropTypeUtil3 } from "@elementor/editor-props";
|
|
3896
4161
|
var tabModelExtensions = {
|
|
3897
4162
|
modifyDefaultChildren(elements) {
|
|
3898
4163
|
if (!Array.isArray(elements) || elements.length === 0) {
|
|
@@ -3908,10 +4173,7 @@ var tabModelExtensions = {
|
|
|
3908
4173
|
...paragraphElement,
|
|
3909
4174
|
settings: {
|
|
3910
4175
|
...paragraphElement.settings,
|
|
3911
|
-
paragraph:
|
|
3912
|
-
content: stringPropTypeUtil3.create(`Tab ${position}`),
|
|
3913
|
-
children: []
|
|
3914
|
-
})
|
|
4176
|
+
paragraph: escapedHtmlPropTypeUtil3.create(`Tab ${position}`)
|
|
3915
4177
|
}
|
|
3916
4178
|
};
|
|
3917
4179
|
return [updatedParagraph, ...elements.slice(1)];
|
|
@@ -3922,22 +4184,22 @@ function initTabsModelExtensions() {
|
|
|
3922
4184
|
}
|
|
3923
4185
|
|
|
3924
4186
|
// src/mcp/canvas-mcp.ts
|
|
3925
|
-
import { Schema as
|
|
4187
|
+
import { Schema as Schema3 } from "@elementor/editor-props";
|
|
3926
4188
|
|
|
3927
4189
|
// src/mcp/resources/available-widgets-resource.ts
|
|
3928
4190
|
import { httpService as httpService3 } from "@elementor/http-client";
|
|
3929
4191
|
var MCP_PROXY_URL2 = "elementor/v1/mcp-proxy";
|
|
3930
4192
|
var AVAILABLE_WIDGETS_URI = "elementor://context/available-widgets";
|
|
3931
4193
|
var AVAILABLE_WIDGETS_URI_V4 = "elementor://context/available-widgets/v4";
|
|
3932
|
-
var fetchWidgets = async (
|
|
4194
|
+
var fetchWidgets = async () => {
|
|
3933
4195
|
const { data } = await httpService3().post(MCP_PROXY_URL2, {
|
|
3934
|
-
tool: "list-
|
|
3935
|
-
input:
|
|
4196
|
+
tool: "list-widget-schemas",
|
|
4197
|
+
input: { summary: true }
|
|
3936
4198
|
});
|
|
3937
|
-
return data.data ?? [];
|
|
4199
|
+
return data.data?.widgets ?? [];
|
|
3938
4200
|
};
|
|
3939
|
-
var buildContents = async (uri
|
|
3940
|
-
const widgets = await fetchWidgets(
|
|
4201
|
+
var buildContents = async (uri) => {
|
|
4202
|
+
const widgets = await fetchWidgets();
|
|
3941
4203
|
return {
|
|
3942
4204
|
contents: [
|
|
3943
4205
|
{
|
|
@@ -3956,13 +4218,13 @@ var initAvailableWidgetsResource = (reg) => {
|
|
|
3956
4218
|
{
|
|
3957
4219
|
description: "All registered v4 version widgets"
|
|
3958
4220
|
},
|
|
3959
|
-
async () => buildContents(AVAILABLE_WIDGETS_URI_V4
|
|
4221
|
+
async () => buildContents(AVAILABLE_WIDGETS_URI_V4)
|
|
3960
4222
|
);
|
|
3961
4223
|
resource(
|
|
3962
4224
|
"available-widgets",
|
|
3963
4225
|
AVAILABLE_WIDGETS_URI,
|
|
3964
4226
|
{
|
|
3965
|
-
description: "All registered widget types with
|
|
4227
|
+
description: "All registered v4 widget types with description."
|
|
3966
4228
|
},
|
|
3967
4229
|
async () => buildContents(AVAILABLE_WIDGETS_URI)
|
|
3968
4230
|
);
|
|
@@ -4097,11 +4359,10 @@ import { httpService as httpService5 } from "@elementor/http-client";
|
|
|
4097
4359
|
var DYNAMIC_TAGS_URI = "elementor://dynamic-tags";
|
|
4098
4360
|
var MCP_PROXY_URL4 = "elementor/v1/mcp-proxy";
|
|
4099
4361
|
var fetchDynamicTags = async () => {
|
|
4100
|
-
const { data } = await httpService5().
|
|
4101
|
-
|
|
4102
|
-
input: {}
|
|
4362
|
+
const { data } = await httpService5().get(MCP_PROXY_URL4, {
|
|
4363
|
+
params: { uri: DYNAMIC_TAGS_URI }
|
|
4103
4364
|
});
|
|
4104
|
-
return data.data ?? [];
|
|
4365
|
+
return data.data ?? "[]";
|
|
4105
4366
|
};
|
|
4106
4367
|
var initDynamicTagsResource = (reg) => {
|
|
4107
4368
|
const { resource } = reg;
|
|
@@ -4113,13 +4374,12 @@ var initDynamicTagsResource = (reg) => {
|
|
|
4113
4374
|
mimeType: "application/json"
|
|
4114
4375
|
},
|
|
4115
4376
|
async (uri) => {
|
|
4116
|
-
const tags = await fetchDynamicTags();
|
|
4117
4377
|
return {
|
|
4118
4378
|
contents: [
|
|
4119
4379
|
{
|
|
4120
4380
|
uri: uri.href,
|
|
4121
4381
|
mimeType: "application/json",
|
|
4122
|
-
text:
|
|
4382
|
+
text: await fetchDynamicTags()
|
|
4123
4383
|
}
|
|
4124
4384
|
]
|
|
4125
4385
|
};
|
|
@@ -4445,99 +4705,8 @@ function getElementDisplayName(container) {
|
|
|
4445
4705
|
}
|
|
4446
4706
|
}
|
|
4447
4707
|
|
|
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
4708
|
// src/mcp/tools/configure-element/tool.ts
|
|
4540
|
-
import { getContainer as
|
|
4709
|
+
import { getContainer as getContainer4, getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
|
|
4541
4710
|
import { dispatchMcpStylesAppliedEvent } from "@elementor/editor-mcp";
|
|
4542
4711
|
import { Schema as Schema2 } from "@elementor/editor-props";
|
|
4543
4712
|
|
|
@@ -4569,9 +4738,9 @@ var readStoredCustomCssText = (raw) => {
|
|
|
4569
4738
|
|
|
4570
4739
|
// src/mcp/utils/resolve-canonical-prop-name.ts
|
|
4571
4740
|
import { getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
|
|
4572
|
-
function buildAliasToCanonicalMap(
|
|
4741
|
+
function buildAliasToCanonicalMap(schema) {
|
|
4573
4742
|
const aliasToCanonical = {};
|
|
4574
|
-
for (const [canonical, propType] of Object.entries(
|
|
4743
|
+
for (const [canonical, propType] of Object.entries(schema)) {
|
|
4575
4744
|
const aliases = propType.meta?.aliases;
|
|
4576
4745
|
if (!Array.isArray(aliases)) {
|
|
4577
4746
|
continue;
|
|
@@ -4585,26 +4754,26 @@ function buildAliasToCanonicalMap(schema2) {
|
|
|
4585
4754
|
return aliasToCanonical;
|
|
4586
4755
|
}
|
|
4587
4756
|
function resolveCanonicalPropName(elementType, propertyName) {
|
|
4588
|
-
const
|
|
4589
|
-
if (!
|
|
4757
|
+
const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
|
|
4758
|
+
if (!schema || schema[propertyName]) {
|
|
4590
4759
|
return propertyName;
|
|
4591
4760
|
}
|
|
4592
|
-
return buildAliasToCanonicalMap(
|
|
4761
|
+
return buildAliasToCanonicalMap(schema)[propertyName] ?? propertyName;
|
|
4593
4762
|
}
|
|
4594
4763
|
function resolveCanonicalPropKeys(elementType, props) {
|
|
4595
|
-
const
|
|
4596
|
-
if (!
|
|
4764
|
+
const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
|
|
4765
|
+
if (!schema) {
|
|
4597
4766
|
return { ...props };
|
|
4598
4767
|
}
|
|
4599
|
-
const aliasToCanonical = buildAliasToCanonicalMap(
|
|
4768
|
+
const aliasToCanonical = buildAliasToCanonicalMap(schema);
|
|
4600
4769
|
const resolved = {};
|
|
4601
4770
|
for (const [key, value] of Object.entries(props)) {
|
|
4602
|
-
if (
|
|
4771
|
+
if (schema[key]) {
|
|
4603
4772
|
resolved[key] = value;
|
|
4604
4773
|
}
|
|
4605
4774
|
}
|
|
4606
4775
|
for (const [key, value] of Object.entries(props)) {
|
|
4607
|
-
if (
|
|
4776
|
+
if (schema[key]) {
|
|
4608
4777
|
continue;
|
|
4609
4778
|
}
|
|
4610
4779
|
const canonical = aliasToCanonical[key];
|
|
@@ -4652,9 +4821,9 @@ var dynamicTagLLMResolver = (value) => {
|
|
|
4652
4821
|
}
|
|
4653
4822
|
};
|
|
4654
4823
|
};
|
|
4655
|
-
var buildStrictSettings = (
|
|
4824
|
+
var buildStrictSettings = (schema, provided) => {
|
|
4656
4825
|
const settings = {};
|
|
4657
|
-
for (const [key, propType] of Object.entries(
|
|
4826
|
+
for (const [key, propType] of Object.entries(schema)) {
|
|
4658
4827
|
if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
|
|
4659
4828
|
continue;
|
|
4660
4829
|
}
|
|
@@ -4686,6 +4855,20 @@ var LOCAL_STYLE_META = {
|
|
|
4686
4855
|
breakpoint: "desktop",
|
|
4687
4856
|
state: null
|
|
4688
4857
|
};
|
|
4858
|
+
var UnsupportedPropertyError = class extends Error {
|
|
4859
|
+
elementType;
|
|
4860
|
+
propertyName;
|
|
4861
|
+
constructor(elementType, propertyName, availableProperties) {
|
|
4862
|
+
super(
|
|
4863
|
+
`Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${availableProperties.join(
|
|
4864
|
+
", "
|
|
4865
|
+
)}`
|
|
4866
|
+
);
|
|
4867
|
+
this.name = "UnsupportedPropertyError";
|
|
4868
|
+
this.elementType = elementType;
|
|
4869
|
+
this.propertyName = propertyName;
|
|
4870
|
+
}
|
|
4871
|
+
};
|
|
4689
4872
|
function resolvePropValue(value, forceKey) {
|
|
4690
4873
|
const Utils = window.elementorV2.editorVariables.Utils;
|
|
4691
4874
|
return Schema.adjustLlmPropValueSchema(value, {
|
|
@@ -4791,12 +4974,7 @@ var doUpdateElementProperty = (params) => {
|
|
|
4791
4974
|
throw new Error(`No prop schema found for element type: ${elementType}`);
|
|
4792
4975
|
}
|
|
4793
4976
|
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
|
-
);
|
|
4977
|
+
throw new UnsupportedPropertyError(elementType, propertyName, Object.keys(elementPropSchema));
|
|
4800
4978
|
}
|
|
4801
4979
|
const propKey = elementPropSchema[propertyName].key;
|
|
4802
4980
|
const value = resolvePropValue(propertyValue, propKey);
|
|
@@ -4866,8 +5044,6 @@ For all non-primitive entries in \`propertiesToChange\`, provide the schema \`ke
|
|
|
4866
5044
|
|
|
4867
5045
|
Use the EXACT PropType schema given, and ALWAYS include the \`key\` from the schema for every property you are changing in \`propertiesToChange\`.
|
|
4868
5046
|
|
|
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
5047
|
# Dynamic tags
|
|
4872
5048
|
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
5049
|
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 +5070,7 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
|
|
|
4894
5070
|
);
|
|
4895
5071
|
configureElementToolPrompt.parameter(
|
|
4896
5072
|
"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.'
|
|
5073
|
+
'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
5074
|
);
|
|
4899
5075
|
configureElementToolPrompt.example(`
|
|
4900
5076
|
\`\`\`json
|
|
@@ -4926,36 +5102,39 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
|
|
|
4926
5102
|
V4 only: If MCP fails, give manual steps using V4 UI.
|
|
4927
5103
|
|
|
4928
5104
|
V4 Editor structure:
|
|
4929
|
-
Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
|
|
5105
|
+
Panel tabs: General (\u2192 Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
|
|
4930
5106
|
NO Advanced tab. Never mention Advanced tab.
|
|
5107
|
+
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
5108
|
`);
|
|
4932
5109
|
return configureElementToolPrompt.prompt();
|
|
4933
5110
|
};
|
|
4934
|
-
var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
|
|
4935
5111
|
|
|
4936
5112
|
// src/mcp/tools/configure-element/schema.ts
|
|
4937
|
-
import { z
|
|
5113
|
+
import { z } from "@elementor/schema";
|
|
4938
5114
|
var inputSchema = {
|
|
4939
|
-
propertiesToChange:
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
5115
|
+
propertiesToChange: z.record(
|
|
5116
|
+
z.string().describe("The property name."),
|
|
5117
|
+
z.any().describe(`PropValue, refer to [${WIDGET_SCHEMA_URI}] by correct type, as appears in elementType`),
|
|
5118
|
+
z.any()
|
|
4943
5119
|
).describe("An object record containing property names and their new values to be set on the element"),
|
|
4944
|
-
style:
|
|
4945
|
-
|
|
4946
|
-
|
|
5120
|
+
style: z.record(
|
|
5121
|
+
z.string().describe('A CSS property name, e.g. "color", "margin-top".'),
|
|
5122
|
+
z.string().nullable().describe(
|
|
4947
5123
|
'A CSS value, e.g. "red", "10px", "1px solid #000". Use null to reset the property to its default.'
|
|
4948
5124
|
)
|
|
4949
5125
|
).describe(
|
|
4950
5126
|
"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
5127
|
).default({}),
|
|
4952
|
-
elementType:
|
|
4953
|
-
elementId:
|
|
5128
|
+
elementType: z.string().describe("The type of the element to retrieve the schema"),
|
|
5129
|
+
elementId: z.string().describe("The unique id of the element to configure")
|
|
4954
5130
|
};
|
|
4955
5131
|
var outputSchema = {
|
|
4956
|
-
success:
|
|
5132
|
+
success: z.boolean().describe(
|
|
4957
5133
|
"Whether the configuration change was successful, only if propertyName and propertyValue are provided"
|
|
4958
|
-
)
|
|
5134
|
+
),
|
|
5135
|
+
warnings: z.string().describe(
|
|
5136
|
+
'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.'
|
|
5137
|
+
).optional()
|
|
4959
5138
|
};
|
|
4960
5139
|
|
|
4961
5140
|
// src/mcp/tools/configure-element/tool.ts
|
|
@@ -4990,7 +5169,7 @@ var initConfigureElementTool = (reg) => {
|
|
|
4990
5169
|
`Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
|
|
4991
5170
|
);
|
|
4992
5171
|
}
|
|
4993
|
-
const container =
|
|
5172
|
+
const container = getContainer4(elementId);
|
|
4994
5173
|
if (!container) {
|
|
4995
5174
|
throw new Error(`Element with id ${elementId} not found`);
|
|
4996
5175
|
}
|
|
@@ -5005,6 +5184,7 @@ var initConfigureElementTool = (reg) => {
|
|
|
5005
5184
|
}
|
|
5006
5185
|
const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
|
|
5007
5186
|
const toUpdate = Object.entries(propertiesToUpdate);
|
|
5187
|
+
const skippedProps = [];
|
|
5008
5188
|
for (const [propertyName, propertyValue] of toUpdate) {
|
|
5009
5189
|
if (!Schema2.isPropKeyConfigurable(propertyName)) {
|
|
5010
5190
|
throw new Error(`Not allowed to update ${propertyName}`);
|
|
@@ -5017,6 +5197,10 @@ var initConfigureElementTool = (reg) => {
|
|
|
5017
5197
|
propertyValue
|
|
5018
5198
|
});
|
|
5019
5199
|
} catch (error) {
|
|
5200
|
+
if (error instanceof UnsupportedPropertyError) {
|
|
5201
|
+
skippedProps.push(error.propertyName);
|
|
5202
|
+
continue;
|
|
5203
|
+
}
|
|
5020
5204
|
const errorMessage = createUpdateErrorMessage({
|
|
5021
5205
|
propertyName,
|
|
5022
5206
|
elementId,
|
|
@@ -5029,7 +5213,10 @@ var initConfigureElementTool = (reg) => {
|
|
|
5029
5213
|
}
|
|
5030
5214
|
await applyStyleFromCss({ elementId, elementType, style });
|
|
5031
5215
|
return {
|
|
5032
|
-
success: true
|
|
5216
|
+
success: true,
|
|
5217
|
+
warnings: skippedProps.length ? `Skipped unsupported props (not in the "${elementType}" schema; other changes were applied): ${skippedProps.join(
|
|
5218
|
+
", "
|
|
5219
|
+
)}.` : void 0
|
|
5033
5220
|
};
|
|
5034
5221
|
}
|
|
5035
5222
|
});
|
|
@@ -5081,102 +5268,74 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
|
|
|
5081
5268
|
}`;
|
|
5082
5269
|
}
|
|
5083
5270
|
|
|
5084
|
-
// src/mcp/tools/get-
|
|
5085
|
-
import {
|
|
5086
|
-
import {
|
|
5087
|
-
import { z as
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
};
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
}
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
|
|
5108
|
-
childElements: structuredElements(child)
|
|
5109
|
-
};
|
|
5110
|
-
});
|
|
5111
|
-
};
|
|
5112
|
-
var initGetElementConfigTool = (reg) => {
|
|
5271
|
+
// src/mcp/tools/get-page-structure/tool.ts
|
|
5272
|
+
import { getCurrentDocument } from "@elementor/editor-documents";
|
|
5273
|
+
import { httpService as httpService6 } from "@elementor/http-client";
|
|
5274
|
+
import { z as z2 } from "@elementor/schema";
|
|
5275
|
+
|
|
5276
|
+
// src/mcp/utils/get-mcp-error-message.ts
|
|
5277
|
+
import { AxiosError } from "@elementor/http-client";
|
|
5278
|
+
function getMcpErrorMessage(error, toolName) {
|
|
5279
|
+
if (error instanceof AxiosError) {
|
|
5280
|
+
const data = error.response?.data;
|
|
5281
|
+
if (data?.message) {
|
|
5282
|
+
return data.code ? `${data.code}: ${data.message}` : data.message;
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
if (error instanceof Error) {
|
|
5286
|
+
return error.message;
|
|
5287
|
+
}
|
|
5288
|
+
return `${toolName} failed with an unknown error.`;
|
|
5289
|
+
}
|
|
5290
|
+
|
|
5291
|
+
// src/mcp/tools/get-page-structure/tool.ts
|
|
5292
|
+
var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
|
|
5293
|
+
var initGetPageStructureTool = (reg) => {
|
|
5113
5294
|
const { addTool } = reg;
|
|
5114
5295
|
addTool({
|
|
5115
|
-
name: "get-
|
|
5116
|
-
description: "
|
|
5117
|
-
schema
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
);
|
|
5135
|
-
}
|
|
5136
|
-
const elementRawSettings = element.settings;
|
|
5137
|
-
const propSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
|
|
5138
|
-
if (!elementRawSettings || !propSchema) {
|
|
5139
|
-
throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
|
|
5296
|
+
name: "get-page-structure",
|
|
5297
|
+
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.",
|
|
5298
|
+
schema: {
|
|
5299
|
+
postId: z2.number().optional().describe(
|
|
5300
|
+
"WordPress post ID of the Elementor document. If omitted, uses the currently open document."
|
|
5301
|
+
),
|
|
5302
|
+
elementId: z2.string().optional().describe("If provided, returns only the subtree rooted at that element id."),
|
|
5303
|
+
includeContent: z2.boolean().optional().describe(
|
|
5304
|
+
"If true, includes each node's settings and styles (same shape build-composition accepts as input). Requires elementId."
|
|
5305
|
+
)
|
|
5306
|
+
},
|
|
5307
|
+
outputSchema: {
|
|
5308
|
+
elements: z2.array(z2.any()).describe(
|
|
5309
|
+
"Skeleton of Elementor elements (id, elType, widgetType, title, nested elements). When includeContent is true, each node also includes settings and styles."
|
|
5310
|
+
)
|
|
5311
|
+
},
|
|
5312
|
+
handler: async ({ postId, elementId, includeContent }) => {
|
|
5313
|
+
const resolvedPostId = postId ?? getCurrentDocument()?.id;
|
|
5314
|
+
if (!resolvedPostId) {
|
|
5315
|
+
throw new Error("No post ID provided and no active document found.");
|
|
5140
5316
|
}
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
if (localStyle) {
|
|
5149
|
-
const defaultVariant = localStyle.variants.find(
|
|
5150
|
-
(variant) => variant.meta.breakpoint === "desktop" && !variant.meta.state
|
|
5151
|
-
);
|
|
5152
|
-
if (defaultVariant) {
|
|
5153
|
-
const styleProps = defaultVariant.props || {};
|
|
5154
|
-
Object.keys(styleProps).forEach((stylePropName) => {
|
|
5155
|
-
if (typeof styleProps[stylePropName] !== "undefined") {
|
|
5156
|
-
stylePropValues[stylePropName] = structuredClone(styleProps[stylePropName]);
|
|
5157
|
-
}
|
|
5158
|
-
});
|
|
5159
|
-
if (defaultVariant.custom_css) {
|
|
5160
|
-
stylePropValues.custom_css = atob(defaultVariant.custom_css.raw);
|
|
5317
|
+
try {
|
|
5318
|
+
const { data } = await httpService6().post(MCP_PROXY_URL5, {
|
|
5319
|
+
tool: "get-page-structure",
|
|
5320
|
+
input: {
|
|
5321
|
+
post_id: resolvedPostId,
|
|
5322
|
+
...elementId ? { element_id: elementId } : {},
|
|
5323
|
+
...includeContent ? { include_content: true } : {}
|
|
5161
5324
|
}
|
|
5162
|
-
}
|
|
5325
|
+
});
|
|
5326
|
+
return {
|
|
5327
|
+
elements: data.data.elements
|
|
5328
|
+
};
|
|
5329
|
+
} catch (error) {
|
|
5330
|
+
throw new Error(getMcpErrorMessage(error, "get-page-structure"));
|
|
5163
5331
|
}
|
|
5164
|
-
return {
|
|
5165
|
-
properties: {
|
|
5166
|
-
...propValues
|
|
5167
|
-
},
|
|
5168
|
-
style: {
|
|
5169
|
-
...stylePropValues
|
|
5170
|
-
},
|
|
5171
|
-
childElements: structuredElements(element)
|
|
5172
|
-
};
|
|
5173
5332
|
}
|
|
5174
5333
|
});
|
|
5175
5334
|
};
|
|
5176
5335
|
|
|
5177
5336
|
// src/mcp/canvas-mcp.ts
|
|
5178
5337
|
var initCanvasMcp = (reg) => {
|
|
5179
|
-
|
|
5338
|
+
Schema3.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
|
|
5180
5339
|
initWidgetsSchemaResource(reg);
|
|
5181
5340
|
initAvailableWidgetsResource(reg);
|
|
5182
5341
|
initDocumentStructureResource(reg);
|
|
@@ -5185,16 +5344,15 @@ var initCanvasMcp = (reg) => {
|
|
|
5185
5344
|
initEditorStateResource(reg);
|
|
5186
5345
|
initGeneralContextResource(reg);
|
|
5187
5346
|
initBestPracticesResource(reg);
|
|
5188
|
-
initGetElementConfigTool(reg);
|
|
5189
5347
|
initConfigureElementTool(reg);
|
|
5190
|
-
|
|
5348
|
+
initGetPageStructureTool(reg);
|
|
5191
5349
|
initBreakpointsResource(reg);
|
|
5192
5350
|
};
|
|
5193
5351
|
|
|
5194
5352
|
// src/mcp/mcp-description.ts
|
|
5195
5353
|
var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
|
|
5196
5354
|
var mcpDescription = `Elementor Canvas MCP
|
|
5197
|
-
This MCP enables
|
|
5355
|
+
This MCP enables configuration and styling of existing V4 elements on the Elementor canvas using the configure-element tool.
|
|
5198
5356
|
|
|
5199
5357
|
# Core Concepts
|
|
5200
5358
|
|
|
@@ -5213,66 +5371,54 @@ The \`$$type\` defines how Elementor interprets the value. Providing the correct
|
|
|
5213
5371
|
- **Global Classes**: Reusable style sets that can be applied to elements (\`elementor://global-classes\`)
|
|
5214
5372
|
- **Widget Schemas**: Configuration options for each widget type (\`${WIDGET_SCHEMA_URI}\`)
|
|
5215
5373
|
|
|
5216
|
-
#
|
|
5374
|
+
# Configuring Elements with configure-element
|
|
5217
5375
|
|
|
5218
|
-
The \`
|
|
5376
|
+
The \`configure-element\` tool updates settings and styles on existing V4 elements. Read the configure-element guide resource before use.
|
|
5219
5377
|
|
|
5220
5378
|
## Complete Workflow
|
|
5221
5379
|
|
|
5222
5380
|
### 1. Parse User Requirements
|
|
5223
|
-
Understand what needs to
|
|
5381
|
+
Understand what needs to change: content, settings, or styling on existing elements.
|
|
5224
5382
|
|
|
5225
5383
|
### 2. Check Global Resources FIRST
|
|
5226
|
-
Always check existing resources before
|
|
5384
|
+
Always check existing resources before styling:
|
|
5227
5385
|
- List \`elementor://global-variables\` for available variables (colors, sizes, fonts)
|
|
5228
5386
|
- List \`elementor://global-classes\` for available style sets
|
|
5229
5387
|
- **Always prefer using existing global resources over creating inline styles**
|
|
5230
5388
|
|
|
5231
5389
|
### 3. Retrieve Widget Schemas
|
|
5232
|
-
For each
|
|
5390
|
+
For each element you will configure:
|
|
5233
5391
|
- List \`${WIDGET_SCHEMA_URI}\` to see available widgets
|
|
5234
5392
|
- Retrieve configuration schema from \`${ELEMENT_SCHEMA_URI}\` for each widget
|
|
5235
|
-
- Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\`
|
|
5393
|
+
- Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\`
|
|
5236
5394
|
|
|
5237
|
-
### 4.
|
|
5238
|
-
|
|
5239
|
-
- Each element must have a unique \`configuration-id\` attribute
|
|
5240
|
-
- No text nodes, classes, or IDs in XML - structure only
|
|
5241
|
-
- Example:
|
|
5242
|
-
\`\`\`xml
|
|
5243
|
-
<e-container configuration-id="container-1">
|
|
5244
|
-
<e-heading configuration-id="heading-1" />
|
|
5245
|
-
<e-text configuration-id="text-1" />
|
|
5246
|
-
</e-container>
|
|
5247
|
-
\`\`\`
|
|
5395
|
+
### 4. Get Current Element State
|
|
5396
|
+
Use page structure and element configuration resources to find element IDs and current values.
|
|
5248
5397
|
|
|
5249
|
-
### 5. Create
|
|
5250
|
-
Map
|
|
5398
|
+
### 5. Create propertiesToChange
|
|
5399
|
+
Map property names to PropValues using the widget schema:
|
|
5251
5400
|
- Use correct \`$$type\` matching the widget's schema
|
|
5252
5401
|
- Use global variables in PropValues where applicable
|
|
5253
5402
|
- Example:
|
|
5254
5403
|
\`\`\`json
|
|
5255
5404
|
{
|
|
5256
|
-
"
|
|
5257
|
-
|
|
5258
|
-
"tag": { "$$type": "string", "value": "h1" }
|
|
5259
|
-
}
|
|
5405
|
+
"text": { "$$type": "string", "value": "Welcome" },
|
|
5406
|
+
"tag": { "$$type": "string", "value": "h1" }
|
|
5260
5407
|
}
|
|
5261
5408
|
\`\`\`
|
|
5262
5409
|
|
|
5263
5410
|
### 6. Create style
|
|
5264
|
-
|
|
5411
|
+
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.
|
|
5265
5412
|
- Example:
|
|
5266
5413
|
\`\`\`json
|
|
5267
5414
|
{
|
|
5268
|
-
"
|
|
5269
|
-
|
|
5415
|
+
"color": "#1a1a1a",
|
|
5416
|
+
"font-size": "2rem"
|
|
5270
5417
|
}
|
|
5271
5418
|
\`\`\`
|
|
5272
5419
|
|
|
5273
|
-
### 7. Execute
|
|
5274
|
-
Call the tool with
|
|
5275
|
-
At the response you will also find llm_instructions for you to do afterwards, read and follow them!
|
|
5420
|
+
### 7. Execute configure-element
|
|
5421
|
+
Call the tool with elementId, elementType, propertiesToChange, and style as needed.
|
|
5276
5422
|
|
|
5277
5423
|
## Key Points
|
|
5278
5424
|
|
|
@@ -5387,7 +5533,7 @@ function shouldBlock(sourceElements, targetElements) {
|
|
|
5387
5533
|
}
|
|
5388
5534
|
|
|
5389
5535
|
// src/style-commands/paste-style.ts
|
|
5390
|
-
import { getContainer as
|
|
5536
|
+
import { getContainer as getContainer5, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
|
|
5391
5537
|
import { classesPropTypeUtil } from "@elementor/editor-props";
|
|
5392
5538
|
import {
|
|
5393
5539
|
__privateListenTo as listenTo5,
|
|
@@ -5396,7 +5542,7 @@ import {
|
|
|
5396
5542
|
} from "@elementor/editor-v1-adapters";
|
|
5397
5543
|
|
|
5398
5544
|
// src/utils/command-utils.ts
|
|
5399
|
-
import { getElementLabel as getElementLabel2, getWidgetsCache as
|
|
5545
|
+
import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
|
|
5400
5546
|
import { CLASSES_PROP_KEY } from "@elementor/editor-props";
|
|
5401
5547
|
import { __ as __5 } from "@wordpress/i18n";
|
|
5402
5548
|
function hasAtomicWidgets(args) {
|
|
@@ -5421,7 +5567,7 @@ function getClassesProp(container) {
|
|
|
5421
5567
|
}
|
|
5422
5568
|
function getContainerSchema(container) {
|
|
5423
5569
|
const type = container?.model.get("widgetType") || container?.model.get("elType");
|
|
5424
|
-
const widgetsCache =
|
|
5570
|
+
const widgetsCache = getWidgetsCache7();
|
|
5425
5571
|
const elementType = widgetsCache?.[type];
|
|
5426
5572
|
return elementType?.atomic_props_schema ?? null;
|
|
5427
5573
|
}
|
|
@@ -5441,7 +5587,7 @@ function getTitleForContainers(containers) {
|
|
|
5441
5587
|
import {
|
|
5442
5588
|
createElementStyle as createElementStyle2,
|
|
5443
5589
|
deleteElementStyle,
|
|
5444
|
-
getElementStyles as
|
|
5590
|
+
getElementStyles as getElementStyles2,
|
|
5445
5591
|
updateElementStyle as updateElementStyle2
|
|
5446
5592
|
} from "@elementor/editor-elements";
|
|
5447
5593
|
import { ELEMENTS_STYLES_RESERVED_LABEL } from "@elementor/editor-styles-repository";
|
|
@@ -5456,7 +5602,7 @@ var undoablePasteElementStyle = () => undoable2(
|
|
|
5456
5602
|
if (!classesProp) {
|
|
5457
5603
|
return null;
|
|
5458
5604
|
}
|
|
5459
|
-
const originalStyles =
|
|
5605
|
+
const originalStyles = getElementStyles2(container.id);
|
|
5460
5606
|
const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
|
|
5461
5607
|
const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
|
|
5462
5608
|
const revertData = {
|
|
@@ -5540,7 +5686,7 @@ function pasteStyles(args, pasteLocalStyle) {
|
|
|
5540
5686
|
}
|
|
5541
5687
|
const clipboardElements = getClipboardElements(storageKey);
|
|
5542
5688
|
const [clipboardElement] = clipboardElements ?? [];
|
|
5543
|
-
const clipboardContainer =
|
|
5689
|
+
const clipboardContainer = getContainer5(clipboardElement.id);
|
|
5544
5690
|
if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
|
|
5545
5691
|
return;
|
|
5546
5692
|
}
|
|
@@ -5586,7 +5732,7 @@ import {
|
|
|
5586
5732
|
} from "@elementor/editor-v1-adapters";
|
|
5587
5733
|
|
|
5588
5734
|
// src/style-commands/undoable-actions/reset-element-style.ts
|
|
5589
|
-
import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as
|
|
5735
|
+
import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles3 } from "@elementor/editor-elements";
|
|
5590
5736
|
import { ELEMENTS_STYLES_RESERVED_LABEL as ELEMENTS_STYLES_RESERVED_LABEL2 } from "@elementor/editor-styles-repository";
|
|
5591
5737
|
import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
|
|
5592
5738
|
import { __ as __7 } from "@wordpress/i18n";
|
|
@@ -5595,7 +5741,7 @@ var undoableResetElementStyle = () => undoable3(
|
|
|
5595
5741
|
do: ({ containers }) => {
|
|
5596
5742
|
return containers.map((container) => {
|
|
5597
5743
|
const elementId = container.model.get("id");
|
|
5598
|
-
const containerStyles =
|
|
5744
|
+
const containerStyles = getElementStyles3(elementId);
|
|
5599
5745
|
Object.keys(containerStyles ?? {}).forEach(
|
|
5600
5746
|
(styleId) => deleteElementStyle2(elementId, styleId)
|
|
5601
5747
|
);
|
|
@@ -5687,15 +5833,15 @@ function init() {
|
|
|
5687
5833
|
initCanvasMcp(
|
|
5688
5834
|
getMCPByDomain("canvas", {
|
|
5689
5835
|
instructions: `Everything related to V4 ( Atomic ) canvas.
|
|
5690
|
-
# Canvas workflow
|
|
5691
|
-
- Configure
|
|
5692
|
-
-
|
|
5693
|
-
- Get and retrieve element configuration values
|
|
5836
|
+
# Canvas workflow
|
|
5837
|
+
- Configure element settings and styles with configure-element
|
|
5838
|
+
- Get page structure and element configuration values
|
|
5694
5839
|
`,
|
|
5695
5840
|
docs: mcpDescription
|
|
5696
5841
|
})
|
|
5697
5842
|
);
|
|
5698
5843
|
initTabsModelExtensions();
|
|
5844
|
+
initListType();
|
|
5699
5845
|
}
|
|
5700
5846
|
|
|
5701
5847
|
// src/sync/drag-element-from-panel.ts
|
|
@@ -5817,10 +5963,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
|
|
|
5817
5963
|
}
|
|
5818
5964
|
|
|
5819
5965
|
// src/utils/after-render.ts
|
|
5820
|
-
import { getContainer as
|
|
5966
|
+
import { getContainer as getContainer6 } from "@elementor/editor-elements";
|
|
5821
5967
|
function doAfterRender(elementIds, callback) {
|
|
5822
5968
|
const pending = elementIds.map((elementId) => {
|
|
5823
|
-
const view =
|
|
5969
|
+
const view = getContainer6(elementId)?.view;
|
|
5824
5970
|
if (!view || !hasDoAfterRender(view)) {
|
|
5825
5971
|
return void 0;
|
|
5826
5972
|
}
|