@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.
Files changed (52) hide show
  1. package/dist/index.d.mts +3 -1
  2. package/dist/index.d.ts +3 -1
  3. package/dist/index.js +535 -393
  4. package/dist/index.mjs +516 -370
  5. package/package.json +20 -20
  6. package/src/__tests__/flex-transformer.test.ts +11 -11
  7. package/src/__tests__/prop-types.ts +11 -0
  8. package/src/init-settings-transformers.ts +4 -0
  9. package/src/init-style-transformers.ts +2 -2
  10. package/src/init.tsx +5 -4
  11. package/src/legacy/__tests__/create-templated-element-type.test.ts +50 -0
  12. package/src/legacy/__tests__/list-type.test.ts +89 -0
  13. package/src/legacy/create-nested-templated-element-type.ts +3 -1
  14. package/src/legacy/create-templated-element-type.ts +5 -2
  15. package/src/legacy/list-type.ts +63 -0
  16. package/src/legacy/replacements/inline-editing/__tests__/inline-editing-eligibility.test.ts +7 -7
  17. package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +22 -9
  18. package/src/legacy/replacements/inline-editing/inline-editing-eligibility.ts +12 -3
  19. package/src/legacy/tabs-model-extensions.ts +2 -5
  20. package/src/legacy/twig-rendering-utils.ts +11 -2
  21. package/src/legacy/types.ts +4 -0
  22. package/src/mcp/canvas-mcp.ts +2 -4
  23. package/src/mcp/mcp-description.ts +18 -30
  24. package/src/mcp/resources/__tests__/available-widgets-resource.test.ts +22 -13
  25. package/src/mcp/resources/__tests__/dynamic-tags-resource.test.ts +22 -30
  26. package/src/mcp/resources/__tests__/widgets-schema-resource.test.ts +11 -6
  27. package/src/mcp/resources/available-widgets-resource.ts +13 -10
  28. package/src/mcp/resources/dynamic-tags-resource.ts +6 -15
  29. package/src/mcp/resources/widgets-schema-resource.ts +8 -5
  30. package/src/mcp/tools/configure-element/__tests__/tool.test.ts +130 -0
  31. package/src/mcp/tools/configure-element/prompt.ts +3 -6
  32. package/src/mcp/tools/configure-element/schema.ts +6 -0
  33. package/src/mcp/tools/configure-element/tool.ts +11 -1
  34. package/src/mcp/tools/get-page-structure/tool.ts +73 -0
  35. package/src/mcp/utils/__tests__/do-update-element-property.test.ts +27 -1
  36. package/src/mcp/utils/do-update-element-property.ts +18 -6
  37. package/src/mcp/utils/get-mcp-error-message.ts +16 -0
  38. package/src/renderers/__tests__/compute-html-tag.test.ts +55 -0
  39. package/src/renderers/__tests__/create-dom-renderer.test.ts +60 -0
  40. package/src/renderers/__tests__/fixtures/html-tag-computer-cases.json +87 -0
  41. package/src/renderers/compute-html-tag.ts +73 -0
  42. package/src/renderers/create-dom-renderer.ts +13 -22
  43. package/src/transformers/settings/escaped-html-transformer.ts +6 -0
  44. package/src/transformers/shared/__tests__/icon-transformer.test.ts +199 -0
  45. package/src/transformers/shared/icon-transformer.ts +231 -0
  46. package/src/transformers/shared/process-svg-content.ts +26 -0
  47. package/src/transformers/shared/svg-src-transformer.ts +1 -26
  48. package/src/transformers/styles/flex-transformer.ts +11 -32
  49. package/src/utils/__tests__/sanitize-escaped-html.test.ts +105 -0
  50. package/src/utils/sanitize-escaped-html.ts +32 -0
  51. package/src/mcp/tools/build-composition/tool.ts +0 -133
  52. package/src/mcp/tools/get-element-config/tool.ts +0 -114
package/dist/index.js CHANGED
@@ -81,10 +81,10 @@ var BEST_PRACTICES_FULL_URI = `${CANVAS_SERVER_NAME}_${BEST_PRACTICES_URI}`;
81
81
  var MCP_PROXY_URL = "elementor/v1/mcp-proxy";
82
82
  var listWidgetTypes = async () => {
83
83
  const { data } = await (0, import_http_client.httpService)().post(MCP_PROXY_URL, {
84
- tool: "list-widgets",
85
- input: {}
84
+ tool: "list-widget-schemas",
85
+ input: { summary: true }
86
86
  });
87
- return (data.data ?? []).map((widget) => widget.type);
87
+ return (data.data?.widgets ?? []).map((widget) => widget.type);
88
88
  };
89
89
  var fetchWidgetSchema = async (widgetType) => {
90
90
  const { data } = await (0, import_http_client.httpService)().post(MCP_PROXY_URL, {
@@ -116,13 +116,13 @@ var initWidgetsSchemaResource = (reg) => {
116
116
  if (!widgetType) {
117
117
  throw new Error("No widget type provided.");
118
118
  }
119
- const schema2 = await fetchWidgetSchema(widgetType);
119
+ const schema = await fetchWidgetSchema(widgetType);
120
120
  return {
121
121
  contents: [
122
122
  {
123
123
  uri: uri.toString(),
124
124
  mimeType: "application/json",
125
- text: JSON.stringify(schema2)
125
+ text: JSON.stringify(schema)
126
126
  }
127
127
  ]
128
128
  };
@@ -1310,10 +1310,10 @@ var getMultiPropsValue = (multiProps) => {
1310
1310
  // src/renderers/create-props-resolver.ts
1311
1311
  var TRANSFORM_DEPTH_LIMIT = 3;
1312
1312
  function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
1313
- async function resolve({ props, schema: schema2, signal, renderContext }) {
1314
- schema2 = schema2 ?? initialSchema;
1313
+ async function resolve({ props, schema, signal, renderContext }) {
1314
+ schema = schema ?? initialSchema;
1315
1315
  const promises = Promise.all(
1316
- Object.entries(schema2).map(async ([key, type]) => {
1316
+ Object.entries(schema).map(async ([key, type]) => {
1317
1317
  const value = props[key] ?? type.default;
1318
1318
  const transformed = await transform({ value, key, type, signal, renderContext });
1319
1319
  onPropResolve?.({ key, value: transformed, propValue: value, propType: type });
@@ -2037,6 +2037,40 @@ var dateTimeTransformer = createTransformer((values) => {
2037
2037
  }).join(" ");
2038
2038
  });
2039
2039
 
2040
+ // src/utils/sanitize-escaped-html.ts
2041
+ var import_dompurify = __toESM(require("dompurify"));
2042
+ var ALLOWED_NON_OPERATIONAL_ATTRS = [
2043
+ "href",
2044
+ "target",
2045
+ "class",
2046
+ "id",
2047
+ "style",
2048
+ "title",
2049
+ "lang",
2050
+ "dir",
2051
+ "role"
2052
+ ];
2053
+ function getAllowedHtmlWrapperTags() {
2054
+ return window.elementorCommon?.config?.allowedHTMLWrapperTags ?? [];
2055
+ }
2056
+ function sanitizeEscapedHtml(value) {
2057
+ if (!value) {
2058
+ return "";
2059
+ }
2060
+ const allowedTags = [...getAllowedHtmlWrapperTags()];
2061
+ return import_dompurify.default.sanitize(value, {
2062
+ ALLOWED_TAGS: allowedTags,
2063
+ ALLOWED_ATTR: [...ALLOWED_NON_OPERATIONAL_ATTRS],
2064
+ ALLOW_DATA_ATTR: true,
2065
+ ALLOW_ARIA_ATTR: true
2066
+ });
2067
+ }
2068
+
2069
+ // src/transformers/settings/escaped-html-transformer.ts
2070
+ var escapedHtmlTransformer = createTransformer((value) => {
2071
+ return sanitizeEscapedHtml(value);
2072
+ });
2073
+
2040
2074
  // src/transformers/settings/html-v2-transformer.ts
2041
2075
  var htmlV2Transformer = createTransformer((value) => {
2042
2076
  return value?.content ?? "";
@@ -2073,6 +2107,172 @@ var timeRangeTransformer = createTransformer((value) => {
2073
2107
  };
2074
2108
  });
2075
2109
 
2110
+ // src/transformers/shared/process-svg-content.ts
2111
+ var import_dompurify2 = __toESM(require("dompurify"));
2112
+ var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
2113
+ function processSvgContent(svgText) {
2114
+ const sanitized = import_dompurify2.default.sanitize(svgText, {
2115
+ USE_PROFILES: { svg: true, svgFilters: true }
2116
+ });
2117
+ const parser = new DOMParser();
2118
+ const doc = parser.parseFromString(sanitized, "image/svg+xml");
2119
+ const svgElement = doc.querySelector("svg");
2120
+ if (!svgElement) {
2121
+ return null;
2122
+ }
2123
+ svgElement.setAttribute("fill", "currentColor");
2124
+ const existingStyle = svgElement.getAttribute("style") ?? "";
2125
+ const trimmed = existingStyle.trim();
2126
+ const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
2127
+ svgElement.setAttribute("style", merged);
2128
+ return svgElement.outerHTML;
2129
+ }
2130
+
2131
+ // src/transformers/shared/icon-transformer.ts
2132
+ var FONT_AWESOME_JSON = {
2133
+ width: 0,
2134
+ height: 1,
2135
+ aliases: 2,
2136
+ unicode: 3,
2137
+ path: 4
2138
+ };
2139
+ var fontAwesomeJsonCache = /* @__PURE__ */ new Map();
2140
+ var iconTransformer = createTransformer(async (value, { signal }) => {
2141
+ const iconValue = typeof value.value === "string" ? value.value : null;
2142
+ const library = typeof value.library === "string" ? value.library : null;
2143
+ if (!iconValue || !library) {
2144
+ return { html: null, url: null };
2145
+ }
2146
+ const iconName = getFontAwesomeIconName(iconValue);
2147
+ const jsonFileName = getFontAwesomeJsonFileName(library);
2148
+ if (!iconName || !jsonFileName) {
2149
+ return { html: null, url: null };
2150
+ }
2151
+ const icons = await fetchFontAwesomeIcons(jsonFileName, signal);
2152
+ const iconData = icons?.[iconName];
2153
+ if (!iconData) {
2154
+ return { html: null, url: null };
2155
+ }
2156
+ const svgText = buildFontAwesomeSvg(iconData);
2157
+ if (!svgText) {
2158
+ return { html: null, url: null };
2159
+ }
2160
+ const html = processIconSvgContent(svgText);
2161
+ return { html, url: null };
2162
+ });
2163
+ function getFontAwesomeIconName(iconValue) {
2164
+ const match = iconValue.match(/^fa\S*\s+fa-(.+)$/);
2165
+ return match?.[1] ?? null;
2166
+ }
2167
+ function getFontAwesomeJsonFileName(library) {
2168
+ const fileName = library.replace(/^fa-/, "");
2169
+ const config = getFontAwesome7EditorConfig();
2170
+ if (!config?.jsonFiles.includes(fileName)) {
2171
+ return null;
2172
+ }
2173
+ return fileName;
2174
+ }
2175
+ function getFontAwesome7EditorConfig() {
2176
+ const config = window.elementorCommon?.config?.fontAwesome?.v7;
2177
+ if (!config || !Array.isArray(config.jsonFiles) || typeof config.jsonBaseUrl !== "string" || config.jsonBaseUrl === "") {
2178
+ return null;
2179
+ }
2180
+ return {
2181
+ jsonFiles: config.jsonFiles,
2182
+ jsonBaseUrl: config.jsonBaseUrl
2183
+ };
2184
+ }
2185
+ async function fetchFontAwesomeIcons(jsonFileName, signal) {
2186
+ const cached = fontAwesomeJsonCache.get(jsonFileName);
2187
+ if (cached) {
2188
+ return cached;
2189
+ }
2190
+ const icons = await loadFontAwesomeIcons(jsonFileName, signal);
2191
+ if (icons) {
2192
+ fontAwesomeJsonCache.set(jsonFileName, icons);
2193
+ }
2194
+ return icons;
2195
+ }
2196
+ async function loadFontAwesomeIcons(jsonFileName, signal) {
2197
+ const config = getFontAwesome7EditorConfig();
2198
+ if (!config?.jsonFiles.includes(jsonFileName)) {
2199
+ return null;
2200
+ }
2201
+ try {
2202
+ const response = await fetch(`${config.jsonBaseUrl}${jsonFileName}.json`, {
2203
+ signal
2204
+ });
2205
+ if (!response.ok) {
2206
+ return null;
2207
+ }
2208
+ const data = await response.json();
2209
+ const icons = data.icons;
2210
+ if (!icons || typeof icons !== "object") {
2211
+ return null;
2212
+ }
2213
+ return indexFontAwesomeIcons(icons);
2214
+ } catch {
2215
+ return null;
2216
+ }
2217
+ }
2218
+ function indexFontAwesomeIcons(icons) {
2219
+ const index = {};
2220
+ for (const [name, iconData] of Object.entries(icons)) {
2221
+ if (!isValidIconTuple(iconData)) {
2222
+ continue;
2223
+ }
2224
+ index[name] = iconData;
2225
+ for (const alias of iconData[FONT_AWESOME_JSON.aliases]) {
2226
+ if (typeof alias === "string" && alias !== "" && !index[alias]) {
2227
+ index[alias] = iconData;
2228
+ }
2229
+ }
2230
+ }
2231
+ return index;
2232
+ }
2233
+ function isValidIconTuple(iconData) {
2234
+ 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]);
2235
+ }
2236
+ function buildFontAwesomeSvg(iconData) {
2237
+ const width = iconData[FONT_AWESOME_JSON.width];
2238
+ const height = iconData[FONT_AWESOME_JSON.height];
2239
+ const paths = normalizePaths(iconData[FONT_AWESOME_JSON.path]);
2240
+ if (paths.length === 0) {
2241
+ return null;
2242
+ }
2243
+ const pathMarkup = paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
2244
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">${pathMarkup}</svg>`;
2245
+ }
2246
+ function normalizePaths(pathData) {
2247
+ if (typeof pathData === "string" && pathData !== "") {
2248
+ return [pathData];
2249
+ }
2250
+ if (!Array.isArray(pathData)) {
2251
+ return [];
2252
+ }
2253
+ return pathData.filter((path) => typeof path === "string" && path !== "");
2254
+ }
2255
+ function escapeSvgPath(path) {
2256
+ return path.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2257
+ }
2258
+ function processIconSvgContent(svgText) {
2259
+ const html = processSvgContent(svgText);
2260
+ if (!html) {
2261
+ return null;
2262
+ }
2263
+ const parser = new DOMParser();
2264
+ const doc = parser.parseFromString(html, "image/svg+xml");
2265
+ const svgElement = doc.querySelector("svg");
2266
+ if (!svgElement) {
2267
+ return null;
2268
+ }
2269
+ svgElement.setAttribute("aria-hidden", "true");
2270
+ svgElement.style.setProperty("width", "100%");
2271
+ svgElement.style.setProperty("height", "100%");
2272
+ svgElement.style.setProperty("overflow", "visible");
2273
+ return svgElement.outerHTML;
2274
+ }
2275
+
2076
2276
  // src/transformers/shared/image-src-transformer.ts
2077
2277
  var imageSrcTransformer = createTransformer((value) => ({
2078
2278
  id: value.id ?? null,
@@ -2114,26 +2314,7 @@ var plainTransformer = createTransformer((value) => {
2114
2314
  });
2115
2315
 
2116
2316
  // src/transformers/shared/svg-src-transformer.ts
2117
- var import_dompurify = __toESM(require("dompurify"));
2118
2317
  var import_wp_media2 = require("@elementor/wp-media");
2119
- var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
2120
- function processSvgContent(svgText) {
2121
- const sanitized = import_dompurify.default.sanitize(svgText, {
2122
- USE_PROFILES: { svg: true, svgFilters: true }
2123
- });
2124
- const parser = new DOMParser();
2125
- const doc = parser.parseFromString(sanitized, "image/svg+xml");
2126
- const svgElement = doc.querySelector("svg");
2127
- if (!svgElement) {
2128
- return null;
2129
- }
2130
- svgElement.setAttribute("fill", "currentColor");
2131
- const existingStyle = svgElement.getAttribute("style") ?? "";
2132
- const trimmed = existingStyle.trim();
2133
- const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
2134
- svgElement.setAttribute("style", merged);
2135
- return svgElement.outerHTML;
2136
- }
2137
2318
  async function fetchSvgContent(url, signal) {
2138
2319
  try {
2139
2320
  const response = await fetch(url, { signal });
@@ -2189,7 +2370,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
2189
2370
 
2190
2371
  // src/init-settings-transformers.ts
2191
2372
  function initSettingsTransformers() {
2192
- 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);
2373
+ 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);
2193
2374
  }
2194
2375
 
2195
2376
  // src/transformers/styles/background-color-overlay-transformer.ts
@@ -2335,6 +2516,10 @@ var mapToFilterFunctionString = (value) => {
2335
2516
  };
2336
2517
 
2337
2518
  // src/transformers/styles/flex-transformer.ts
2519
+ var DEFAULT_FLEX_GROW = 0;
2520
+ var DEFAULT_FLEX_SHRINK = 1;
2521
+ var DEFAULT_FLEX_BASIS = "auto";
2522
+ var formatBasis = (basis) => typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis;
2338
2523
  var flexTransformer = createTransformer((value) => {
2339
2524
  const grow = value.flexGrow;
2340
2525
  const shrink = value.flexShrink;
@@ -2345,28 +2530,10 @@ var flexTransformer = createTransformer((value) => {
2345
2530
  if (!hasGrow && !hasShrink && !hasBasis) {
2346
2531
  return null;
2347
2532
  }
2348
- if (hasGrow && hasShrink && hasBasis) {
2349
- return `${grow} ${shrink} ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
2350
- }
2351
- if (hasGrow && hasShrink && !hasBasis) {
2352
- return `${grow} ${shrink}`;
2353
- }
2354
- if (hasGrow && !hasShrink && hasBasis) {
2355
- return `${grow} 1 ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
2356
- }
2357
- if (!hasGrow && hasShrink && hasBasis) {
2358
- return `0 ${shrink} ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
2359
- }
2360
- if (hasGrow && !hasShrink && !hasBasis) {
2361
- return `${grow}`;
2362
- }
2363
- if (!hasGrow && hasShrink && !hasBasis) {
2364
- return `0 ${shrink}`;
2365
- }
2366
- if (!hasGrow && !hasShrink && hasBasis) {
2367
- return `0 1 ${typeof basis === "object" && basis.size !== void 0 ? `${basis.size}${basis.unit || ""}` : basis}`;
2368
- }
2369
- return null;
2533
+ const growOut = hasGrow ? grow : DEFAULT_FLEX_GROW;
2534
+ const shrinkOut = hasShrink ? shrink : DEFAULT_FLEX_SHRINK;
2535
+ const basisOut = hasBasis ? formatBasis(basis) : DEFAULT_FLEX_BASIS;
2536
+ return `${growOut} ${shrinkOut} ${basisOut}`;
2370
2537
  });
2371
2538
 
2372
2539
  // src/transformers/styles/font-family-transformer.ts
@@ -2466,11 +2633,11 @@ function getVal2(val) {
2466
2633
  var transformOriginTransformer = createTransformer((value) => {
2467
2634
  const x = getVal2(value.x);
2468
2635
  const y = getVal2(value.y);
2469
- const z4 = getVal2(value.z);
2470
- if (x === DEFAULT_XY && y === DEFAULT_XY && z4 === DEFAULT_Z) {
2636
+ const z3 = getVal2(value.z);
2637
+ if (x === DEFAULT_XY && y === DEFAULT_XY && z3 === DEFAULT_Z) {
2471
2638
  return null;
2472
2639
  }
2473
- return `${x} ${y} ${z4}`;
2640
+ return `${x} ${y} ${z3}`;
2474
2641
  });
2475
2642
 
2476
2643
  // src/transformers/styles/transform-rotate-transformer.ts
@@ -2548,13 +2715,13 @@ function initStyleTransformers() {
2548
2715
  "layout-direction",
2549
2716
  createMultiPropsTransformer(["row", "column"], ({ propKey, key }) => `${key}-${propKey}`)
2550
2717
  ).register("flex", flexTransformer).register(
2551
- "border-width",
2718
+ "border-width-v2",
2552
2719
  createMultiPropsTransformer(
2553
2720
  ["block-start", "block-end", "inline-start", "inline-end"],
2554
2721
  ({ key }) => `border-${key}-width`
2555
2722
  )
2556
2723
  ).register(
2557
- "border-radius",
2724
+ "border-radius-v2",
2558
2725
  createMultiPropsTransformer(
2559
2726
  ["start-start", "start-end", "end-start", "end-end"],
2560
2727
  ({ key }) => `border-${key}-radius`
@@ -2578,28 +2745,13 @@ function createDomRenderer() {
2578
2745
  render: environment.render
2579
2746
  };
2580
2747
  }
2748
+ function getAllowedHtmlWrapperTags2() {
2749
+ return window.elementorCommon?.config?.allowedHTMLWrapperTags ?? [];
2750
+ }
2581
2751
  function escapeHtmlTag(value) {
2582
- const allowedTags = [
2583
- "a",
2584
- "article",
2585
- "aside",
2586
- "button",
2587
- "div",
2588
- "footer",
2589
- "h1",
2590
- "h2",
2591
- "h3",
2592
- "h4",
2593
- "h5",
2594
- "h6",
2595
- "header",
2596
- "main",
2597
- "nav",
2598
- "p",
2599
- "section",
2600
- "span"
2601
- ];
2602
- return allowedTags.includes(value) ? value : "div";
2752
+ const allowedTags = getAllowedHtmlWrapperTags2();
2753
+ const normalizedTag = value?.toLowerCase?.() ?? "";
2754
+ return allowedTags.includes(normalizedTag) ? value : "div";
2603
2755
  }
2604
2756
  function escapeURL(value) {
2605
2757
  const allowedProtocols = ["http:", "https:", "mailto:", "tel:"];
@@ -2694,6 +2846,52 @@ function createElementViewClassDeclaration() {
2694
2846
  // src/legacy/create-nested-templated-element-type.ts
2695
2847
  var import_editor_elements6 = require("@elementor/editor-elements");
2696
2848
 
2849
+ // src/renderers/compute-html-tag.ts
2850
+ var DEFAULT_LINK_TAG = "a";
2851
+ function computeHtmlTag(settings, defaultTag, options = {}) {
2852
+ const followLink = options.followLink ?? true;
2853
+ if (followLink && settingsHaveActiveLink(settings)) {
2854
+ const link = settings.link;
2855
+ return extractLinkHtmlTag(isRecord(link) ? link : {});
2856
+ }
2857
+ const settingsTag = extractHtmlTagValue(settings.tag);
2858
+ if (null !== settingsTag && "" !== settingsTag) {
2859
+ return settingsTag;
2860
+ }
2861
+ return defaultTag;
2862
+ }
2863
+ function settingsHaveActiveLink(settings) {
2864
+ const link = settings.link;
2865
+ if (!isRecord(link)) {
2866
+ return false;
2867
+ }
2868
+ const href = extractHtmlTagValue(link.href);
2869
+ if (null !== href && "" !== href) {
2870
+ return true;
2871
+ }
2872
+ const attributes = link.attributes;
2873
+ return typeof attributes === "string" && "" !== attributes;
2874
+ }
2875
+ function extractLinkHtmlTag(link) {
2876
+ const tag = extractHtmlTagValue(link.tag);
2877
+ if (null !== tag && "" !== tag) {
2878
+ return tag;
2879
+ }
2880
+ return DEFAULT_LINK_TAG;
2881
+ }
2882
+ function extractHtmlTagValue(value) {
2883
+ if (isRecord(value) && typeof value.value === "string") {
2884
+ return value.value;
2885
+ }
2886
+ if (typeof value === "string") {
2887
+ return value;
2888
+ }
2889
+ return null;
2890
+ }
2891
+ function isRecord(value) {
2892
+ return typeof value === "object" && null !== value && !Array.isArray(value);
2893
+ }
2894
+
2697
2895
  // src/legacy/create-pending-element.ts
2698
2896
  var import_editor_elements5 = require("@elementor/editor-elements");
2699
2897
  function createPendingElement(wrapperView, data, options = {}) {
@@ -2754,7 +2952,13 @@ function setupTwigRenderer({ renderer, element }) {
2754
2952
  transformers: settingsTransformersRegistry,
2755
2953
  schema: element.atomic_props_schema
2756
2954
  });
2757
- return { templateKey, baseStylesDictionary, resolveProps };
2955
+ return {
2956
+ templateKey,
2957
+ baseStylesDictionary,
2958
+ resolveProps,
2959
+ defaultHtmlTag: element.default_html_tag ?? "div",
2960
+ htmlTagFollowsLink: element.html_tag_follows_link ?? true
2961
+ };
2758
2962
  }
2759
2963
  function createBeforeRender(view) {
2760
2964
  view._ensureViewIsIntact();
@@ -2794,7 +2998,7 @@ function createTemplatedElementView({
2794
2998
  element
2795
2999
  }) {
2796
3000
  const BaseView = createElementViewClassDeclaration();
2797
- const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
3001
+ const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
2798
3002
  type,
2799
3003
  renderer,
2800
3004
  element
@@ -2864,6 +3068,7 @@ function createTemplatedElementView({
2864
3068
  interaction_id: this.getInteractionId(),
2865
3069
  type,
2866
3070
  settings,
3071
+ tag: computeHtmlTag(settings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
2867
3072
  base_styles: baseStylesDictionary,
2868
3073
  ...this.getResolverRenderContext?.() ?? {}
2869
3074
  };
@@ -2953,7 +3158,7 @@ function createNestedTemplatedElementView({
2953
3158
  element
2954
3159
  }) {
2955
3160
  const legacyWindow = window;
2956
- const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer({
3161
+ const { templateKey, baseStylesDictionary, resolveProps, defaultHtmlTag, htmlTagFollowsLink } = setupTwigRenderer({
2957
3162
  type,
2958
3163
  renderer,
2959
3164
  element
@@ -3028,6 +3233,7 @@ function createNestedTemplatedElementView({
3028
3233
  interaction_id: this.getInteractionId(),
3029
3234
  type,
3030
3235
  settings: resolvedSettings,
3236
+ tag: computeHtmlTag(resolvedSettings, defaultHtmlTag, { followLink: htmlTagFollowsLink }),
3031
3237
  base_styles: baseStylesDictionary,
3032
3238
  editor_attributes: buildEditorAttributes(model),
3033
3239
  editor_classes: buildEditorClasses(model),
@@ -3531,7 +3737,7 @@ var import_editor_props3 = require("@elementor/editor-props");
3531
3737
  var hasKey = (propType) => {
3532
3738
  return "key" in propType;
3533
3739
  };
3534
- var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([import_editor_props3.htmlV3PropTypeUtil.key, import_editor_props3.stringPropTypeUtil.key]);
3740
+ var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([import_editor_props3.escapedHtmlPropTypeUtil.key, import_editor_props3.htmlV3PropTypeUtil.key, import_editor_props3.stringPropTypeUtil.key]);
3535
3741
  var isCoreTextPropTypeKey = (key) => {
3536
3742
  return TEXT_PROP_TYPE_KEYS.has(key);
3537
3743
  };
@@ -3551,7 +3757,7 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
3551
3757
  if (rawValue === null || rawValue === void 0) {
3552
3758
  return isAllowedBySchema(propTypeFromSchema);
3553
3759
  }
3554
- return import_editor_props3.htmlV3PropTypeUtil.isValid(rawValue) || import_editor_props3.stringPropTypeUtil.isValid(rawValue);
3760
+ return import_editor_props3.escapedHtmlPropTypeUtil.isValid(rawValue) || import_editor_props3.htmlV3PropTypeUtil.isValid(rawValue) || import_editor_props3.stringPropTypeUtil.isValid(rawValue);
3555
3761
  };
3556
3762
 
3557
3763
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
@@ -3636,17 +3842,26 @@ var InlineEditingReplacement = class extends ReplacementBase {
3636
3842
  }
3637
3843
  getExtractedContentValue() {
3638
3844
  const propValue = this.getInlineEditablePropValue();
3845
+ if (import_editor_props4.escapedHtmlPropTypeUtil.isValid(propValue)) {
3846
+ return import_editor_props4.escapedHtmlPropTypeUtil.extract(propValue) ?? "";
3847
+ }
3639
3848
  const extracted = import_editor_props4.htmlV3PropTypeUtil.extract(propValue);
3640
3849
  return import_editor_props4.stringPropTypeUtil.extract(extracted?.content ?? null) ?? "";
3641
3850
  }
3851
+ createContentPropValue(value) {
3852
+ const content = value || "";
3853
+ const propTypeKey = this.getInlineEditablePropTypeKey();
3854
+ if (propTypeKey === import_editor_props4.htmlV3PropTypeUtil.key) {
3855
+ return import_editor_props4.htmlV3PropTypeUtil.create({
3856
+ content: import_editor_props4.stringPropTypeUtil.create(content),
3857
+ children: []
3858
+ });
3859
+ }
3860
+ return import_editor_props4.escapedHtmlPropTypeUtil.create(content);
3861
+ }
3642
3862
  setContentValue(value) {
3643
3863
  const settingKey = this.getInlineEditablePropertyName();
3644
- const html = value || "";
3645
- const parsed = (0, import_editor_props4.parseHtmlChildren)(html);
3646
- const valueToSave = import_editor_props4.htmlV3PropTypeUtil.create({
3647
- content: parsed.content ? import_editor_props4.stringPropTypeUtil.create(parsed.content) : null,
3648
- children: parsed.children
3649
- });
3864
+ const valueToSave = this.createContentPropValue(value);
3650
3865
  (0, import_editor_v1_adapters13.undoable)(
3651
3866
  {
3652
3867
  do: () => {
@@ -3675,7 +3890,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3675
3890
  return null;
3676
3891
  }
3677
3892
  if (propType.kind === "union") {
3678
- const textKeys = [import_editor_props4.htmlV3PropTypeUtil.key, import_editor_props4.stringPropTypeUtil.key];
3893
+ const textKeys = [import_editor_props4.escapedHtmlPropTypeUtil.key, import_editor_props4.htmlV3PropTypeUtil.key, import_editor_props4.stringPropTypeUtil.key];
3679
3894
  for (const key of textKeys) {
3680
3895
  if (propType.prop_types[key]) {
3681
3896
  return key;
@@ -3930,6 +4145,52 @@ function createNestedTemplatedType(type, renderer, element) {
3930
4145
  });
3931
4146
  }
3932
4147
 
4148
+ // src/legacy/list-type.ts
4149
+ var LIST_TYPE = "e-list";
4150
+ function initListType() {
4151
+ registerElementType(
4152
+ LIST_TYPE,
4153
+ (options) => createListType(options)
4154
+ );
4155
+ }
4156
+ function createListType(options) {
4157
+ const BaseType = createNestedTemplatedElementType(options);
4158
+ let ListView = null;
4159
+ return class extends BaseType {
4160
+ getView() {
4161
+ if (!ListView) {
4162
+ ListView = createListView(options);
4163
+ }
4164
+ return ListView;
4165
+ }
4166
+ };
4167
+ }
4168
+ function createListView(options) {
4169
+ const BaseView = createNestedTemplatedElementView(options);
4170
+ return BaseView.extend({
4171
+ getRenderContext() {
4172
+ const parentContext = this._parent?.getRenderContext?.();
4173
+ const settings = this.model.get("settings");
4174
+ const showMarkersProp = settings?.get?.("show_markers");
4175
+ const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
4176
+ return {
4177
+ ...parentContext,
4178
+ show_markers: showMarkers
4179
+ };
4180
+ },
4181
+ getResolverRenderContext() {
4182
+ const parentContext = this._parent?.getResolverRenderContext?.();
4183
+ const settings = this.model.get("settings");
4184
+ const showMarkersProp = settings?.get?.("show_markers");
4185
+ const showMarkers = showMarkersProp?.value ?? showMarkersProp ?? true;
4186
+ return {
4187
+ ...parentContext,
4188
+ show_markers: showMarkers
4189
+ };
4190
+ }
4191
+ });
4192
+ }
4193
+
3933
4194
  // src/legacy/tabs-model-extensions.ts
3934
4195
  var import_editor_props5 = require("@elementor/editor-props");
3935
4196
  var tabModelExtensions = {
@@ -3947,10 +4208,7 @@ var tabModelExtensions = {
3947
4208
  ...paragraphElement,
3948
4209
  settings: {
3949
4210
  ...paragraphElement.settings,
3950
- paragraph: import_editor_props5.htmlV3PropTypeUtil.create({
3951
- content: import_editor_props5.stringPropTypeUtil.create(`Tab ${position}`),
3952
- children: []
3953
- })
4211
+ paragraph: import_editor_props5.escapedHtmlPropTypeUtil.create(`Tab ${position}`)
3954
4212
  }
3955
4213
  };
3956
4214
  return [updatedParagraph, ...elements.slice(1)];
@@ -3961,22 +4219,22 @@ function initTabsModelExtensions() {
3961
4219
  }
3962
4220
 
3963
4221
  // src/mcp/canvas-mcp.ts
3964
- var import_editor_props9 = require("@elementor/editor-props");
4222
+ var import_editor_props8 = require("@elementor/editor-props");
3965
4223
 
3966
4224
  // src/mcp/resources/available-widgets-resource.ts
3967
4225
  var import_http_client3 = require("@elementor/http-client");
3968
4226
  var MCP_PROXY_URL2 = "elementor/v1/mcp-proxy";
3969
4227
  var AVAILABLE_WIDGETS_URI = "elementor://context/available-widgets";
3970
4228
  var AVAILABLE_WIDGETS_URI_V4 = "elementor://context/available-widgets/v4";
3971
- var fetchWidgets = async (version) => {
4229
+ var fetchWidgets = async () => {
3972
4230
  const { data } = await (0, import_http_client3.httpService)().post(MCP_PROXY_URL2, {
3973
- tool: "list-widgets",
3974
- input: version ? { version } : {}
4231
+ tool: "list-widget-schemas",
4232
+ input: { summary: true }
3975
4233
  });
3976
- return data.data ?? [];
4234
+ return data.data?.widgets ?? [];
3977
4235
  };
3978
- var buildContents = async (uri, version) => {
3979
- const widgets = await fetchWidgets(version);
4236
+ var buildContents = async (uri) => {
4237
+ const widgets = await fetchWidgets();
3980
4238
  return {
3981
4239
  contents: [
3982
4240
  {
@@ -3995,13 +4253,13 @@ var initAvailableWidgetsResource = (reg) => {
3995
4253
  {
3996
4254
  description: "All registered v4 version widgets"
3997
4255
  },
3998
- async () => buildContents(AVAILABLE_WIDGETS_URI_V4, "v4")
4256
+ async () => buildContents(AVAILABLE_WIDGETS_URI_V4)
3999
4257
  );
4000
4258
  resource(
4001
4259
  "available-widgets",
4002
4260
  AVAILABLE_WIDGETS_URI,
4003
4261
  {
4004
- description: "All registered widget types with v3/v4 version metadata and description."
4262
+ description: "All registered v4 widget types with description."
4005
4263
  },
4006
4264
  async () => buildContents(AVAILABLE_WIDGETS_URI)
4007
4265
  );
@@ -4134,11 +4392,10 @@ var import_http_client5 = require("@elementor/http-client");
4134
4392
  var DYNAMIC_TAGS_URI = "elementor://dynamic-tags";
4135
4393
  var MCP_PROXY_URL4 = "elementor/v1/mcp-proxy";
4136
4394
  var fetchDynamicTags = async () => {
4137
- const { data } = await (0, import_http_client5.httpService)().post(MCP_PROXY_URL4, {
4138
- tool: "list-dynamic-tags",
4139
- input: {}
4395
+ const { data } = await (0, import_http_client5.httpService)().get(MCP_PROXY_URL4, {
4396
+ params: { uri: DYNAMIC_TAGS_URI }
4140
4397
  });
4141
- return data.data ?? [];
4398
+ return data.data ?? "[]";
4142
4399
  };
4143
4400
  var initDynamicTagsResource = (reg) => {
4144
4401
  const { resource } = reg;
@@ -4150,13 +4407,12 @@ var initDynamicTagsResource = (reg) => {
4150
4407
  mimeType: "application/json"
4151
4408
  },
4152
4409
  async (uri) => {
4153
- const tags = await fetchDynamicTags();
4154
4410
  return {
4155
4411
  contents: [
4156
4412
  {
4157
4413
  uri: uri.href,
4158
4414
  mimeType: "application/json",
4159
- text: JSON.stringify(tags)
4415
+ text: await fetchDynamicTags()
4160
4416
  }
4161
4417
  ]
4162
4418
  };
@@ -4479,104 +4735,13 @@ function getElementDisplayName(container) {
4479
4735
  }
4480
4736
  }
4481
4737
 
4482
- // src/mcp/tools/build-composition/tool.ts
4483
- var import_editor_documents2 = require("@elementor/editor-documents");
4484
- var import_editor_elements11 = require("@elementor/editor-elements");
4485
- var import_http_client6 = require("@elementor/http-client");
4486
- var import_schema = require("@elementor/schema");
4487
- var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
4488
- var initBuildCompositionTool = (reg) => {
4489
- const { addTool } = reg;
4490
- addTool({
4491
- name: "build-composition",
4492
- 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.",
4493
- schema: {
4494
- xmlStructure: import_schema.z.string().describe(
4495
- '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.'
4496
- ),
4497
- elementConfig: import_schema.z.record(
4498
- import_schema.z.string().describe("configuration-id"),
4499
- import_schema.z.record(import_schema.z.string().describe("property name"), import_schema.z.any().describe("PropValue"))
4500
- ).optional().describe("Map configuration-id \u2192 widget PropValues ($$type + value)."),
4501
- style: import_schema.z.record(
4502
- import_schema.z.string().describe("configuration-id"),
4503
- import_schema.z.record(import_schema.z.string().describe("CSS property name"), import_schema.z.string().describe("CSS value"))
4504
- ).optional().describe(
4505
- "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."
4506
- ),
4507
- parentId: import_schema.z.string().optional().describe("ID of the parent container. Omit or pass 'document' to insert at document root."),
4508
- dryRun: import_schema.z.boolean().optional().describe("If true, validate and return the resolved tree without persisting.")
4509
- },
4510
- outputSchema: {
4511
- rootElementIds: import_schema.z.array(import_schema.z.string()),
4512
- previewUrl: import_schema.z.string(),
4513
- version: import_schema.z.string(),
4514
- resolvedXml: import_schema.z.string(),
4515
- llmInstructions: import_schema.z.string(),
4516
- warnings: import_schema.z.array(import_schema.z.string()).optional()
4517
- },
4518
- handler: async ({ xmlStructure, elementConfig, style, parentId, dryRun }) => {
4519
- const document2 = (0, import_editor_documents2.getCurrentDocument)();
4520
- if (!document2?.id) {
4521
- throw new Error("No active document found.");
4522
- }
4523
- try {
4524
- const { data } = await (0, import_http_client6.httpService)().post(MCP_PROXY_URL5, {
4525
- tool: "build-composition",
4526
- input: {
4527
- post_id: document2.id,
4528
- xml_structure: xmlStructure,
4529
- element_config: elementConfig ?? {},
4530
- style: style ?? {},
4531
- parent_id: parentId ?? "document",
4532
- dry_run: dryRun ?? false
4533
- }
4534
- });
4535
- if (!dryRun) {
4536
- await (0, import_editor_documents2.reloadCurrentDocument)();
4537
- const [firstRootId] = data.data.root_element_ids;
4538
- if (firstRootId) {
4539
- (0, import_editor_elements11.selectElement)(firstRootId);
4540
- (0, import_editor_elements11.getContainer)(firstRootId)?.view?.el?.scrollIntoView({
4541
- behavior: "smooth",
4542
- block: "center"
4543
- });
4544
- }
4545
- }
4546
- return {
4547
- rootElementIds: data.data.root_element_ids,
4548
- previewUrl: data.data.preview_url,
4549
- version: data.data.version,
4550
- resolvedXml: data.data.resolved_xml,
4551
- llmInstructions: data.data.llm_instructions,
4552
- warnings: data.data.warnings
4553
- };
4554
- } catch (error) {
4555
- throw new Error(getErrorMessage(error));
4556
- }
4557
- }
4558
- });
4559
- };
4560
- function getErrorMessage(error) {
4561
- if (error instanceof import_http_client6.AxiosError) {
4562
- const data = error.response?.data;
4563
- if (data?.message) {
4564
- return data.code ? `${data.code}: ${data.message}` : data.message;
4565
- }
4566
- }
4567
- if (error instanceof Error) {
4568
- return error.message;
4569
- }
4570
- return "build-composition failed with an unknown error.";
4571
- }
4572
-
4573
4738
  // src/mcp/tools/configure-element/tool.ts
4574
- var import_editor_elements14 = require("@elementor/editor-elements");
4739
+ var import_editor_elements13 = require("@elementor/editor-elements");
4575
4740
  var import_editor_mcp3 = require("@elementor/editor-mcp");
4576
4741
  var import_editor_props7 = require("@elementor/editor-props");
4577
4742
 
4578
4743
  // src/mcp/utils/do-update-element-property.ts
4579
- var import_editor_elements13 = require("@elementor/editor-elements");
4744
+ var import_editor_elements12 = require("@elementor/editor-elements");
4580
4745
  var import_editor_props6 = require("@elementor/editor-props");
4581
4746
  var import_editor_styles4 = require("@elementor/editor-styles");
4582
4747
  var import_editor_v1_adapters20 = require("@elementor/editor-v1-adapters");
@@ -4596,10 +4761,10 @@ var readStoredCustomCssText = (raw) => {
4596
4761
  };
4597
4762
 
4598
4763
  // src/mcp/utils/resolve-canonical-prop-name.ts
4599
- var import_editor_elements12 = require("@elementor/editor-elements");
4600
- function buildAliasToCanonicalMap(schema2) {
4764
+ var import_editor_elements11 = require("@elementor/editor-elements");
4765
+ function buildAliasToCanonicalMap(schema) {
4601
4766
  const aliasToCanonical = {};
4602
- for (const [canonical, propType] of Object.entries(schema2)) {
4767
+ for (const [canonical, propType] of Object.entries(schema)) {
4603
4768
  const aliases = propType.meta?.aliases;
4604
4769
  if (!Array.isArray(aliases)) {
4605
4770
  continue;
@@ -4613,26 +4778,26 @@ function buildAliasToCanonicalMap(schema2) {
4613
4778
  return aliasToCanonical;
4614
4779
  }
4615
4780
  function resolveCanonicalPropName(elementType, propertyName) {
4616
- const schema2 = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4617
- if (!schema2 || schema2[propertyName]) {
4781
+ const schema = (0, import_editor_elements11.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4782
+ if (!schema || schema[propertyName]) {
4618
4783
  return propertyName;
4619
4784
  }
4620
- return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4785
+ return buildAliasToCanonicalMap(schema)[propertyName] ?? propertyName;
4621
4786
  }
4622
4787
  function resolveCanonicalPropKeys(elementType, props) {
4623
- const schema2 = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4624
- if (!schema2) {
4788
+ const schema = (0, import_editor_elements11.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4789
+ if (!schema) {
4625
4790
  return { ...props };
4626
4791
  }
4627
- const aliasToCanonical = buildAliasToCanonicalMap(schema2);
4792
+ const aliasToCanonical = buildAliasToCanonicalMap(schema);
4628
4793
  const resolved = {};
4629
4794
  for (const [key, value] of Object.entries(props)) {
4630
- if (schema2[key]) {
4795
+ if (schema[key]) {
4631
4796
  resolved[key] = value;
4632
4797
  }
4633
4798
  }
4634
4799
  for (const [key, value] of Object.entries(props)) {
4635
- if (schema2[key]) {
4800
+ if (schema[key]) {
4636
4801
  continue;
4637
4802
  }
4638
4803
  const canonical = aliasToCanonical[key];
@@ -4680,9 +4845,9 @@ var dynamicTagLLMResolver = (value) => {
4680
4845
  }
4681
4846
  };
4682
4847
  };
4683
- var buildStrictSettings = (schema2, provided) => {
4848
+ var buildStrictSettings = (schema, provided) => {
4684
4849
  const settings = {};
4685
- for (const [key, propType] of Object.entries(schema2)) {
4850
+ for (const [key, propType] of Object.entries(schema)) {
4686
4851
  if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
4687
4852
  continue;
4688
4853
  }
@@ -4714,6 +4879,20 @@ var LOCAL_STYLE_META = {
4714
4879
  breakpoint: "desktop",
4715
4880
  state: null
4716
4881
  };
4882
+ var UnsupportedPropertyError = class extends Error {
4883
+ elementType;
4884
+ propertyName;
4885
+ constructor(elementType, propertyName, availableProperties) {
4886
+ super(
4887
+ `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${availableProperties.join(
4888
+ ", "
4889
+ )}`
4890
+ );
4891
+ this.name = "UnsupportedPropertyError";
4892
+ this.elementType = elementType;
4893
+ this.propertyName = propertyName;
4894
+ }
4895
+ };
4717
4896
  function resolvePropValue(value, forceKey) {
4718
4897
  const Utils = window.elementorV2.editorVariables.Utils;
4719
4898
  return import_editor_props6.Schema.adjustLlmPropValueSchema(value, {
@@ -4728,7 +4907,7 @@ var doUpdateElementProperty = (params) => {
4728
4907
  const { elementId, propertyValue, elementType, customCssWriteMode = "replace" } = params;
4729
4908
  const propertyName = params.propertyName === "_styles" ? params.propertyName : resolveCanonicalPropName(elementType, params.propertyName);
4730
4909
  if (propertyName === "_styles") {
4731
- const elementStyles = (0, import_editor_elements13.getElementStyles)(elementId) || {};
4910
+ const elementStyles = (0, import_editor_elements12.getElementStyles)(elementId) || {};
4732
4911
  const propertyMapValue = propertyValue;
4733
4912
  const styleSchema = (0, import_editor_styles4.getStylesSchema)();
4734
4913
  const transformedStyleValues = Object.fromEntries(
@@ -4785,7 +4964,7 @@ var doUpdateElementProperty = (params) => {
4785
4964
  });
4786
4965
  delete transformedStyleValues.custom_css;
4787
4966
  if (!localStyle) {
4788
- (0, import_editor_elements13.createElementStyle)({
4967
+ (0, import_editor_elements12.createElementStyle)({
4789
4968
  elementId,
4790
4969
  ...typeof customCss !== "undefined" ? { custom_css: customCss } : {},
4791
4970
  classesProp: "classes",
@@ -4799,7 +4978,7 @@ var doUpdateElementProperty = (params) => {
4799
4978
  }
4800
4979
  });
4801
4980
  } else {
4802
- (0, import_editor_elements13.updateElementStyle)({
4981
+ (0, import_editor_elements12.updateElementStyle)({
4803
4982
  elementId,
4804
4983
  styleId: localStyle.id,
4805
4984
  meta: {
@@ -4814,17 +4993,12 @@ var doUpdateElementProperty = (params) => {
4814
4993
  }
4815
4994
  return;
4816
4995
  }
4817
- const elementPropSchema = (0, import_editor_elements13.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4996
+ const elementPropSchema = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4818
4997
  if (!elementPropSchema) {
4819
4998
  throw new Error(`No prop schema found for element type: ${elementType}`);
4820
4999
  }
4821
5000
  if (!elementPropSchema[propertyName]) {
4822
- const propertyNames = Object.keys(elementPropSchema);
4823
- throw new Error(
4824
- `Property "${propertyName}" does not exist on element type "${elementType}". Available properties are: ${propertyNames.join(
4825
- ", "
4826
- )}`
4827
- );
5001
+ throw new UnsupportedPropertyError(elementType, propertyName, Object.keys(elementPropSchema));
4828
5002
  }
4829
5003
  const propKey = elementPropSchema[propertyName].key;
4830
5004
  const value = resolvePropValue(propertyValue, propKey);
@@ -4837,7 +5011,7 @@ var doUpdateElementProperty = (params) => {
4837
5011
  Expected Schema: ${jsonSchema}`
4838
5012
  );
4839
5013
  }
4840
- (0, import_editor_elements13.updateElementSettings)({
5014
+ (0, import_editor_elements12.updateElementSettings)({
4841
5015
  id: elementId,
4842
5016
  props: {
4843
5017
  [propertyName]: value
@@ -4894,8 +5068,6 @@ For all non-primitive entries in \`propertiesToChange\`, provide the schema \`ke
4894
5068
 
4895
5069
  Use the EXACT PropType schema given, and ALWAYS include the \`key\` from the schema for every property you are changing in \`propertiesToChange\`.
4896
5070
 
4897
- Check \`llm_guidance.default_settings\` in the widget schema \u2014 include a key in \`propertiesToChange\` only when the user explicitly asks to change it.
4898
-
4899
5071
  # Dynamic tags
4900
5072
  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.
4901
5073
  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.
@@ -4922,7 +5094,7 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
4922
5094
  );
4923
5095
  configureElementToolPrompt.parameter(
4924
5096
  "style",
4925
- '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.'
5097
+ '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.'
4926
5098
  );
4927
5099
  configureElementToolPrompt.example(`
4928
5100
  \`\`\`json
@@ -4954,36 +5126,39 @@ Do NOT send "group" (it is resolved automatically). Use { "settings": {} } only
4954
5126
  V4 only: If MCP fails, give manual steps using V4 UI.
4955
5127
 
4956
5128
  V4 Editor structure:
4957
- Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
5129
+ Panel tabs: General (\u2192 Settings section: ID, Tag, and Link where the widget supports it), Style, Interactions.
4958
5130
  NO Advanced tab. Never mention Advanced tab.
5131
+ 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.
4959
5132
  `);
4960
5133
  return configureElementToolPrompt.prompt();
4961
5134
  };
4962
- var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt();
4963
5135
 
4964
5136
  // src/mcp/tools/configure-element/schema.ts
4965
- var import_schema2 = require("@elementor/schema");
5137
+ var import_schema = require("@elementor/schema");
4966
5138
  var inputSchema = {
4967
- propertiesToChange: import_schema2.z.record(
4968
- import_schema2.z.string().describe("The property name."),
4969
- import_schema2.z.any().describe(`PropValue, refer to [${WIDGET_SCHEMA_URI}] by correct type, as appears in elementType`),
4970
- import_schema2.z.any()
5139
+ propertiesToChange: import_schema.z.record(
5140
+ import_schema.z.string().describe("The property name."),
5141
+ import_schema.z.any().describe(`PropValue, refer to [${WIDGET_SCHEMA_URI}] by correct type, as appears in elementType`),
5142
+ import_schema.z.any()
4971
5143
  ).describe("An object record containing property names and their new values to be set on the element"),
4972
- style: import_schema2.z.record(
4973
- import_schema2.z.string().describe('A CSS property name, e.g. "color", "margin-top".'),
4974
- import_schema2.z.string().nullable().describe(
5144
+ style: import_schema.z.record(
5145
+ import_schema.z.string().describe('A CSS property name, e.g. "color", "margin-top".'),
5146
+ import_schema.z.string().nullable().describe(
4975
5147
  'A CSS value, e.g. "red", "10px", "1px solid #000". Use null to reset the property to its default.'
4976
5148
  )
4977
5149
  ).describe(
4978
5150
  "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."
4979
5151
  ).default({}),
4980
- elementType: import_schema2.z.string().describe("The type of the element to retrieve the schema"),
4981
- elementId: import_schema2.z.string().describe("The unique id of the element to configure")
5152
+ elementType: import_schema.z.string().describe("The type of the element to retrieve the schema"),
5153
+ elementId: import_schema.z.string().describe("The unique id of the element to configure")
4982
5154
  };
4983
5155
  var outputSchema = {
4984
- success: import_schema2.z.boolean().describe(
5156
+ success: import_schema.z.boolean().describe(
4985
5157
  "Whether the configuration change was successful, only if propertyName and propertyValue are provided"
4986
- )
5158
+ ),
5159
+ warnings: import_schema.z.string().describe(
5160
+ '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.'
5161
+ ).optional()
4987
5162
  };
4988
5163
 
4989
5164
  // src/mcp/tools/configure-element/tool.ts
@@ -5012,13 +5187,13 @@ var initConfigureElementTool = (reg) => {
5012
5187
  { description: "Dynamic tags catalog", uri: DYNAMIC_TAGS_URI }
5013
5188
  ],
5014
5189
  handler: async ({ elementId, propertiesToChange, elementType, style }) => {
5015
- const widgetData = (0, import_editor_elements14.getWidgetsCache)()?.[elementType];
5190
+ const widgetData = (0, import_editor_elements13.getWidgetsCache)()?.[elementType];
5016
5191
  if (!widgetData) {
5017
5192
  throw new Error(
5018
5193
  `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5019
5194
  );
5020
5195
  }
5021
- const container = (0, import_editor_elements14.getContainer)(elementId);
5196
+ const container = (0, import_editor_elements13.getContainer)(elementId);
5022
5197
  if (!container) {
5023
5198
  throw new Error(`Element with id ${elementId} not found`);
5024
5199
  }
@@ -5033,6 +5208,7 @@ var initConfigureElementTool = (reg) => {
5033
5208
  }
5034
5209
  const propertiesToUpdate = resolveCanonicalPropKeys(elementType, propertiesToChange);
5035
5210
  const toUpdate = Object.entries(propertiesToUpdate);
5211
+ const skippedProps = [];
5036
5212
  for (const [propertyName, propertyValue] of toUpdate) {
5037
5213
  if (!import_editor_props7.Schema.isPropKeyConfigurable(propertyName)) {
5038
5214
  throw new Error(`Not allowed to update ${propertyName}`);
@@ -5045,6 +5221,10 @@ var initConfigureElementTool = (reg) => {
5045
5221
  propertyValue
5046
5222
  });
5047
5223
  } catch (error) {
5224
+ if (error instanceof UnsupportedPropertyError) {
5225
+ skippedProps.push(error.propertyName);
5226
+ continue;
5227
+ }
5048
5228
  const errorMessage = createUpdateErrorMessage({
5049
5229
  propertyName,
5050
5230
  elementId,
@@ -5057,7 +5237,10 @@ var initConfigureElementTool = (reg) => {
5057
5237
  }
5058
5238
  await applyStyleFromCss({ elementId, elementType, style });
5059
5239
  return {
5060
- success: true
5240
+ success: true,
5241
+ warnings: skippedProps.length ? `Skipped unsupported props (not in the "${elementType}" schema; other changes were applied): ${skippedProps.join(
5242
+ ", "
5243
+ )}.` : void 0
5061
5244
  };
5062
5245
  }
5063
5246
  });
@@ -5109,102 +5292,74 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5109
5292
  }`;
5110
5293
  }
5111
5294
 
5112
- // src/mcp/tools/get-element-config/tool.ts
5113
- var import_editor_elements15 = require("@elementor/editor-elements");
5114
- var import_editor_props8 = require("@elementor/editor-props");
5115
- var import_schema4 = require("@elementor/schema");
5116
- var schema = {
5117
- elementId: import_schema4.z.string()
5118
- };
5119
- var outputSchema2 = {
5120
- properties: import_schema4.z.record(import_schema4.z.string(), import_schema4.z.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
5121
- style: import_schema4.z.record(import_schema4.z.string(), import_schema4.z.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
5122
- childElements: import_schema4.z.array(
5123
- import_schema4.z.object({
5124
- id: import_schema4.z.string(),
5125
- elementType: import_schema4.z.string(),
5126
- childElements: import_schema4.z.array(import_schema4.z.any()).describe("An array of child element IDs, when applicable, same structure recursively")
5127
- })
5128
- ).describe("An array of child element IDs, when applicable, with recursive structure")
5129
- };
5130
- var structuredElements = (element) => {
5131
- const children = element.children || [];
5132
- return children.map((child) => {
5133
- return {
5134
- id: child.id,
5135
- elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
5136
- childElements: structuredElements(child)
5137
- };
5138
- });
5139
- };
5140
- var initGetElementConfigTool = (reg) => {
5295
+ // src/mcp/tools/get-page-structure/tool.ts
5296
+ var import_editor_documents2 = require("@elementor/editor-documents");
5297
+ var import_http_client7 = require("@elementor/http-client");
5298
+ var import_schema3 = require("@elementor/schema");
5299
+
5300
+ // src/mcp/utils/get-mcp-error-message.ts
5301
+ var import_http_client6 = require("@elementor/http-client");
5302
+ function getMcpErrorMessage(error, toolName) {
5303
+ if (error instanceof import_http_client6.AxiosError) {
5304
+ const data = error.response?.data;
5305
+ if (data?.message) {
5306
+ return data.code ? `${data.code}: ${data.message}` : data.message;
5307
+ }
5308
+ }
5309
+ if (error instanceof Error) {
5310
+ return error.message;
5311
+ }
5312
+ return `${toolName} failed with an unknown error.`;
5313
+ }
5314
+
5315
+ // src/mcp/tools/get-page-structure/tool.ts
5316
+ var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
5317
+ var initGetPageStructureTool = (reg) => {
5141
5318
  const { addTool } = reg;
5142
5319
  addTool({
5143
- name: "get-element-configuration-values",
5144
- description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
5145
- schema,
5146
- outputSchema: outputSchema2,
5147
- handler: async ({ elementId }) => {
5148
- const element = (0, import_editor_elements15.getContainer)(elementId);
5149
- if (!element) {
5150
- throw new Error(`Element with ID ${elementId} not found.`);
5151
- }
5152
- const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5153
- const widgetData = (0, import_editor_elements15.getWidgetsCache)()?.[elementType];
5154
- if (!widgetData) {
5155
- throw new Error(
5156
- `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5157
- );
5158
- }
5159
- if (!widgetData.atomic_props_schema) {
5160
- throw new Error(
5161
- `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
5162
- );
5163
- }
5164
- const elementRawSettings = element.settings;
5165
- const propSchema = (0, import_editor_elements15.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
5166
- if (!elementRawSettings || !propSchema) {
5167
- throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5320
+ name: "get-page-structure",
5321
+ 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.",
5322
+ schema: {
5323
+ postId: import_schema3.z.number().optional().describe(
5324
+ "WordPress post ID of the Elementor document. If omitted, uses the currently open document."
5325
+ ),
5326
+ elementId: import_schema3.z.string().optional().describe("If provided, returns only the subtree rooted at that element id."),
5327
+ includeContent: import_schema3.z.boolean().optional().describe(
5328
+ "If true, includes each node's settings and styles (same shape build-composition accepts as input). Requires elementId."
5329
+ )
5330
+ },
5331
+ outputSchema: {
5332
+ elements: import_schema3.z.array(import_schema3.z.any()).describe(
5333
+ "Skeleton of Elementor elements (id, elType, widgetType, title, nested elements). When includeContent is true, each node also includes settings and styles."
5334
+ )
5335
+ },
5336
+ handler: async ({ postId, elementId, includeContent }) => {
5337
+ const resolvedPostId = postId ?? (0, import_editor_documents2.getCurrentDocument)()?.id;
5338
+ if (!resolvedPostId) {
5339
+ throw new Error("No post ID provided and no active document found.");
5168
5340
  }
5169
- const propValues = {};
5170
- const stylePropValues = {};
5171
- import_editor_props8.Schema.configurableKeys(propSchema).forEach((key) => {
5172
- propValues[key] = structuredClone(elementRawSettings.get(key));
5173
- });
5174
- const elementStyles = (0, import_editor_elements15.getElementStyles)(elementId) || {};
5175
- const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
5176
- if (localStyle) {
5177
- const defaultVariant = localStyle.variants.find(
5178
- (variant) => variant.meta.breakpoint === "desktop" && !variant.meta.state
5179
- );
5180
- if (defaultVariant) {
5181
- const styleProps = defaultVariant.props || {};
5182
- Object.keys(styleProps).forEach((stylePropName) => {
5183
- if (typeof styleProps[stylePropName] !== "undefined") {
5184
- stylePropValues[stylePropName] = structuredClone(styleProps[stylePropName]);
5185
- }
5186
- });
5187
- if (defaultVariant.custom_css) {
5188
- stylePropValues.custom_css = atob(defaultVariant.custom_css.raw);
5341
+ try {
5342
+ const { data } = await (0, import_http_client7.httpService)().post(MCP_PROXY_URL5, {
5343
+ tool: "get-page-structure",
5344
+ input: {
5345
+ post_id: resolvedPostId,
5346
+ ...elementId ? { element_id: elementId } : {},
5347
+ ...includeContent ? { include_content: true } : {}
5189
5348
  }
5190
- }
5349
+ });
5350
+ return {
5351
+ elements: data.data.elements
5352
+ };
5353
+ } catch (error) {
5354
+ throw new Error(getMcpErrorMessage(error, "get-page-structure"));
5191
5355
  }
5192
- return {
5193
- properties: {
5194
- ...propValues
5195
- },
5196
- style: {
5197
- ...stylePropValues
5198
- },
5199
- childElements: structuredElements(element)
5200
- };
5201
5356
  }
5202
5357
  });
5203
5358
  };
5204
5359
 
5205
5360
  // src/mcp/canvas-mcp.ts
5206
5361
  var initCanvasMcp = (reg) => {
5207
- import_editor_props9.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5362
+ import_editor_props8.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5208
5363
  initWidgetsSchemaResource(reg);
5209
5364
  initAvailableWidgetsResource(reg);
5210
5365
  initDocumentStructureResource(reg);
@@ -5213,16 +5368,15 @@ var initCanvasMcp = (reg) => {
5213
5368
  initEditorStateResource(reg);
5214
5369
  initGeneralContextResource(reg);
5215
5370
  initBestPracticesResource(reg);
5216
- initGetElementConfigTool(reg);
5217
5371
  initConfigureElementTool(reg);
5218
- initBuildCompositionTool(reg);
5372
+ initGetPageStructureTool(reg);
5219
5373
  initBreakpointsResource(reg);
5220
5374
  };
5221
5375
 
5222
5376
  // src/mcp/mcp-description.ts
5223
5377
  var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
5224
5378
  var mcpDescription = `Elementor Canvas MCP
5225
- This MCP enables creation, configuration, and styling of elements on the Elementor canvas using the build_composition tool.
5379
+ This MCP enables configuration and styling of existing V4 elements on the Elementor canvas using the configure-element tool.
5226
5380
 
5227
5381
  # Core Concepts
5228
5382
 
@@ -5241,66 +5395,54 @@ The \`$$type\` defines how Elementor interprets the value. Providing the correct
5241
5395
  - **Global Classes**: Reusable style sets that can be applied to elements (\`elementor://global-classes\`)
5242
5396
  - **Widget Schemas**: Configuration options for each widget type (\`${WIDGET_SCHEMA_URI}\`)
5243
5397
 
5244
- # Building Compositions with build_composition
5398
+ # Configuring Elements with configure-element
5245
5399
 
5246
- The \`build_composition\` tool is the primary way to create elements. It accepts structure (XML), configuration, and styling in a single operation.
5400
+ The \`configure-element\` tool updates settings and styles on existing V4 elements. Read the configure-element guide resource before use.
5247
5401
 
5248
5402
  ## Complete Workflow
5249
5403
 
5250
5404
  ### 1. Parse User Requirements
5251
- Understand what needs to be built: structure, content, and styling.
5405
+ Understand what needs to change: content, settings, or styling on existing elements.
5252
5406
 
5253
5407
  ### 2. Check Global Resources FIRST
5254
- Always check existing resources before building:
5408
+ Always check existing resources before styling:
5255
5409
  - List \`elementor://global-variables\` for available variables (colors, sizes, fonts)
5256
5410
  - List \`elementor://global-classes\` for available style sets
5257
5411
  - **Always prefer using existing global resources over creating inline styles**
5258
5412
 
5259
5413
  ### 3. Retrieve Widget Schemas
5260
- For each widget you'll use:
5414
+ For each element you will configure:
5261
5415
  - List \`${WIDGET_SCHEMA_URI}\` to see available widgets
5262
5416
  - Retrieve configuration schema from \`${ELEMENT_SCHEMA_URI}\` for each widget
5263
- - Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\` (omit default_settings from elementConfig unless the user asks to change them)
5417
+ - Check the \`llm_guidance\` property for container nesting, \`default_styles\`, and \`default_settings\`
5264
5418
 
5265
- ### 4. Build XML Structure
5266
- Create valid XML with configuration-ids:
5267
- - Each element must have a unique \`configuration-id\` attribute
5268
- - No text nodes, classes, or IDs in XML - structure only
5269
- - Example:
5270
- \`\`\`xml
5271
- <e-container configuration-id="container-1">
5272
- <e-heading configuration-id="heading-1" />
5273
- <e-text configuration-id="text-1" />
5274
- </e-container>
5275
- \`\`\`
5419
+ ### 4. Get Current Element State
5420
+ Use page structure and element configuration resources to find element IDs and current values.
5276
5421
 
5277
- ### 5. Create elementConfig
5278
- Map each configuration-id to its widget properties using PropValues:
5422
+ ### 5. Create propertiesToChange
5423
+ Map property names to PropValues using the widget schema:
5279
5424
  - Use correct \`$$type\` matching the widget's schema
5280
5425
  - Use global variables in PropValues where applicable
5281
5426
  - Example:
5282
5427
  \`\`\`json
5283
5428
  {
5284
- "heading-1": {
5285
- "text": { "$$type": "string", "value": "Welcome" },
5286
- "tag": { "$$type": "string", "value": "h1" }
5287
- }
5429
+ "text": { "$$type": "string", "value": "Welcome" },
5430
+ "tag": { "$$type": "string", "value": "h1" }
5288
5431
  }
5289
5432
  \`\`\`
5290
5433
 
5291
5434
  ### 6. Create style
5292
- Map each configuration-id to raw CSS declarations (property \u2192 value strings). The server converts them to native styles and stores any unconvertible declarations as the element custom CSS.
5435
+ 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.
5293
5436
  - Example:
5294
5437
  \`\`\`json
5295
5438
  {
5296
- "heading-1": "color: #1a1a1a; font-size: 2rem;"
5297
- }
5439
+ "color": "#1a1a1a",
5440
+ "font-size": "2rem"
5298
5441
  }
5299
5442
  \`\`\`
5300
5443
 
5301
- ### 7. Execute build_composition
5302
- Call the tool with your XML structure, elementConfig, and style. The response will contain the created element IDs.
5303
- At the response you will also find llm_instructions for you to do afterwards, read and follow them!
5444
+ ### 7. Execute configure-element
5445
+ Call the tool with elementId, elementType, propertiesToChange, and style as needed.
5304
5446
 
5305
5447
  ## Key Points
5306
5448
 
@@ -5328,7 +5470,7 @@ Note: The "size" property controls image resolution/loading, not visual size. Se
5328
5470
  `;
5329
5471
 
5330
5472
  // src/prevent-link-in-link-commands.ts
5331
- var import_editor_elements16 = require("@elementor/editor-elements");
5473
+ var import_editor_elements14 = require("@elementor/editor-elements");
5332
5474
  var import_editor_notifications3 = require("@elementor/editor-notifications");
5333
5475
  var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
5334
5476
  var import_i18n4 = require("@wordpress/i18n");
@@ -5399,25 +5541,25 @@ function shouldBlock(sourceElements, targetElements) {
5399
5541
  return false;
5400
5542
  }
5401
5543
  const isSourceContainsAnAnchor = sourceElements.some((src) => {
5402
- return src?.id ? (0, import_editor_elements16.isElementAnchored)(src.id) || !!(0, import_editor_elements16.getAnchoredDescendantId)(src.id) : false;
5544
+ return src?.id ? (0, import_editor_elements14.isElementAnchored)(src.id) || !!(0, import_editor_elements14.getAnchoredDescendantId)(src.id) : false;
5403
5545
  });
5404
5546
  if (!isSourceContainsAnAnchor) {
5405
5547
  return false;
5406
5548
  }
5407
5549
  const isTargetContainsAnAnchor = targetElements.some((target) => {
5408
- return target?.id ? (0, import_editor_elements16.isElementAnchored)(target.id) || !!(0, import_editor_elements16.getAnchoredAncestorId)(target.id) : false;
5550
+ return target?.id ? (0, import_editor_elements14.isElementAnchored)(target.id) || !!(0, import_editor_elements14.getAnchoredAncestorId)(target.id) : false;
5409
5551
  });
5410
5552
  return isTargetContainsAnAnchor;
5411
5553
  }
5412
5554
 
5413
5555
  // src/style-commands/paste-style.ts
5414
- var import_editor_elements19 = require("@elementor/editor-elements");
5415
- var import_editor_props11 = require("@elementor/editor-props");
5556
+ var import_editor_elements17 = require("@elementor/editor-elements");
5557
+ var import_editor_props10 = require("@elementor/editor-props");
5416
5558
  var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
5417
5559
 
5418
5560
  // src/utils/command-utils.ts
5419
- var import_editor_elements17 = require("@elementor/editor-elements");
5420
- var import_editor_props10 = require("@elementor/editor-props");
5561
+ var import_editor_elements15 = require("@elementor/editor-elements");
5562
+ var import_editor_props9 = require("@elementor/editor-props");
5421
5563
  var import_i18n5 = require("@wordpress/i18n");
5422
5564
  function hasAtomicWidgets(args) {
5423
5565
  const { containers = [args.container] } = args;
@@ -5435,13 +5577,13 @@ function getClassesProp(container) {
5435
5577
  return null;
5436
5578
  }
5437
5579
  const [propKey] = Object.entries(propsSchema).find(
5438
- ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props10.CLASSES_PROP_KEY
5580
+ ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props9.CLASSES_PROP_KEY
5439
5581
  ) ?? [];
5440
5582
  return propKey ?? null;
5441
5583
  }
5442
5584
  function getContainerSchema(container) {
5443
5585
  const type = container?.model.get("widgetType") || container?.model.get("elType");
5444
- const widgetsCache = (0, import_editor_elements17.getWidgetsCache)();
5586
+ const widgetsCache = (0, import_editor_elements15.getWidgetsCache)();
5445
5587
  const elementType = widgetsCache?.[type];
5446
5588
  return elementType?.atomic_props_schema ?? null;
5447
5589
  }
@@ -5454,11 +5596,11 @@ function getClipboardElements(storageKey = "clipboard") {
5454
5596
  }
5455
5597
  }
5456
5598
  function getTitleForContainers(containers) {
5457
- return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements17.getElementLabel)(containers[0].id);
5599
+ return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements15.getElementLabel)(containers[0].id);
5458
5600
  }
5459
5601
 
5460
5602
  // src/style-commands/undoable-actions/paste-element-style.ts
5461
- var import_editor_elements18 = require("@elementor/editor-elements");
5603
+ var import_editor_elements16 = require("@elementor/editor-elements");
5462
5604
  var import_editor_styles_repository4 = require("@elementor/editor-styles-repository");
5463
5605
  var import_editor_v1_adapters22 = require("@elementor/editor-v1-adapters");
5464
5606
  var import_i18n6 = require("@wordpress/i18n");
@@ -5471,7 +5613,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5471
5613
  if (!classesProp) {
5472
5614
  return null;
5473
5615
  }
5474
- const originalStyles = (0, import_editor_elements18.getElementStyles)(container.id);
5616
+ const originalStyles = (0, import_editor_elements16.getElementStyles)(container.id);
5475
5617
  const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
5476
5618
  const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
5477
5619
  const revertData = {
@@ -5480,7 +5622,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5480
5622
  };
5481
5623
  if (styleId) {
5482
5624
  newStyle.variants.forEach(({ meta, props, custom_css: customCss }) => {
5483
- (0, import_editor_elements18.updateElementStyle)({
5625
+ (0, import_editor_elements16.updateElementStyle)({
5484
5626
  elementId,
5485
5627
  styleId,
5486
5628
  meta,
@@ -5491,7 +5633,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5491
5633
  } else {
5492
5634
  const [firstVariant] = newStyle.variants;
5493
5635
  const additionalVariants = newStyle.variants.slice(1);
5494
- revertData.styleId = (0, import_editor_elements18.createElementStyle)({
5636
+ revertData.styleId = (0, import_editor_elements16.createElementStyle)({
5495
5637
  elementId,
5496
5638
  classesProp,
5497
5639
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -5509,7 +5651,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5509
5651
  return;
5510
5652
  }
5511
5653
  if (!revertData.originalStyle) {
5512
- (0, import_editor_elements18.deleteElementStyle)(container.id, revertData.styleId);
5654
+ (0, import_editor_elements16.deleteElementStyle)(container.id, revertData.styleId);
5513
5655
  return;
5514
5656
  }
5515
5657
  const classesProp = getClassesProp(container);
@@ -5518,7 +5660,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5518
5660
  }
5519
5661
  const [firstVariant] = revertData.originalStyle.variants;
5520
5662
  const additionalVariants = revertData.originalStyle.variants.slice(1);
5521
- (0, import_editor_elements18.createElementStyle)({
5663
+ (0, import_editor_elements16.createElementStyle)({
5522
5664
  elementId: container.id,
5523
5665
  classesProp,
5524
5666
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -5555,7 +5697,7 @@ function pasteStyles(args, pasteLocalStyle) {
5555
5697
  }
5556
5698
  const clipboardElements = getClipboardElements(storageKey);
5557
5699
  const [clipboardElement] = clipboardElements ?? [];
5558
- const clipboardContainer = (0, import_editor_elements19.getContainer)(clipboardElement.id);
5700
+ const clipboardContainer = (0, import_editor_elements17.getContainer)(clipboardElement.id);
5559
5701
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
5560
5702
  return;
5561
5703
  }
@@ -5574,7 +5716,7 @@ function getClassesWithoutLocalStyle(clipboardContainer, style) {
5574
5716
  if (!classesProp) {
5575
5717
  return [];
5576
5718
  }
5577
- const classesSetting = (0, import_editor_elements19.getElementSetting)(clipboardContainer.id, classesProp);
5719
+ const classesSetting = (0, import_editor_elements17.getElementSetting)(clipboardContainer.id, classesProp);
5578
5720
  return classesSetting?.value.filter((styleId) => styleId !== style?.id) ?? [];
5579
5721
  }
5580
5722
  function pasteClasses(containers, classes) {
@@ -5583,10 +5725,10 @@ function pasteClasses(containers, classes) {
5583
5725
  if (!classesProp) {
5584
5726
  return;
5585
5727
  }
5586
- const classesSetting = (0, import_editor_elements19.getElementSetting)(container.id, classesProp);
5587
- const currentClasses = import_editor_props11.classesPropTypeUtil.extract(classesSetting) ?? [];
5588
- const newClasses = import_editor_props11.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
5589
- (0, import_editor_elements19.updateElementSettings)({
5728
+ const classesSetting = (0, import_editor_elements17.getElementSetting)(container.id, classesProp);
5729
+ const currentClasses = import_editor_props10.classesPropTypeUtil.extract(classesSetting) ?? [];
5730
+ const newClasses = import_editor_props10.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
5731
+ (0, import_editor_elements17.updateElementSettings)({
5590
5732
  id: container.id,
5591
5733
  props: { [classesProp]: newClasses }
5592
5734
  });
@@ -5597,7 +5739,7 @@ function pasteClasses(containers, classes) {
5597
5739
  var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
5598
5740
 
5599
5741
  // src/style-commands/undoable-actions/reset-element-style.ts
5600
- var import_editor_elements20 = require("@elementor/editor-elements");
5742
+ var import_editor_elements18 = require("@elementor/editor-elements");
5601
5743
  var import_editor_styles_repository5 = require("@elementor/editor-styles-repository");
5602
5744
  var import_editor_v1_adapters24 = require("@elementor/editor-v1-adapters");
5603
5745
  var import_i18n7 = require("@wordpress/i18n");
@@ -5606,9 +5748,9 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters24.undoable)(
5606
5748
  do: ({ containers }) => {
5607
5749
  return containers.map((container) => {
5608
5750
  const elementId = container.model.get("id");
5609
- const containerStyles = (0, import_editor_elements20.getElementStyles)(elementId);
5751
+ const containerStyles = (0, import_editor_elements18.getElementStyles)(elementId);
5610
5752
  Object.keys(containerStyles ?? {}).forEach(
5611
- (styleId) => (0, import_editor_elements20.deleteElementStyle)(elementId, styleId)
5753
+ (styleId) => (0, import_editor_elements18.deleteElementStyle)(elementId, styleId)
5612
5754
  );
5613
5755
  return containerStyles;
5614
5756
  });
@@ -5624,7 +5766,7 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters24.undoable)(
5624
5766
  Object.entries(containerStyles ?? {}).forEach(([styleId, style]) => {
5625
5767
  const [firstVariant] = style.variants;
5626
5768
  const additionalVariants = style.variants.slice(1);
5627
- (0, import_editor_elements20.createElementStyle)({
5769
+ (0, import_editor_elements18.createElementStyle)({
5628
5770
  elementId,
5629
5771
  classesProp,
5630
5772
  styleId,
@@ -5698,15 +5840,15 @@ function init() {
5698
5840
  initCanvasMcp(
5699
5841
  (0, import_editor_mcp4.getMCPByDomain)("canvas", {
5700
5842
  instructions: `Everything related to V4 ( Atomic ) canvas.
5701
- # Canvas workflow for new compositions
5702
- - Configure elements settings and styles
5703
- - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
5704
- - Get and retrieve element configuration values
5843
+ # Canvas workflow
5844
+ - Configure element settings and styles with configure-element
5845
+ - Get page structure and element configuration values
5705
5846
  `,
5706
5847
  docs: mcpDescription
5707
5848
  })
5708
5849
  );
5709
5850
  initTabsModelExtensions();
5851
+ initListType();
5710
5852
  }
5711
5853
 
5712
5854
  // src/sync/drag-element-from-panel.ts
@@ -5824,10 +5966,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
5824
5966
  }
5825
5967
 
5826
5968
  // src/utils/after-render.ts
5827
- var import_editor_elements21 = require("@elementor/editor-elements");
5969
+ var import_editor_elements19 = require("@elementor/editor-elements");
5828
5970
  function doAfterRender(elementIds, callback) {
5829
5971
  const pending = elementIds.map((elementId) => {
5830
- const view = (0, import_editor_elements21.getContainer)(elementId)?.view;
5972
+ const view = (0, import_editor_elements19.getContainer)(elementId)?.view;
5831
5973
  if (!view || !hasDoAfterRender(view)) {
5832
5974
  return void 0;
5833
5975
  }