@elementor/editor-canvas 3.35.0-469 → 3.35.0-471

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -118,7 +118,7 @@ The css string must follow standard CSS syntax, with properties and values separ
118
118
  "styles-schema",
119
119
  new import_editor_mcp.ResourceTemplate(STYLE_SCHEMA_URI, {
120
120
  list: () => {
121
- const categories = [...Object.keys((0, import_editor_styles.getStylesSchema)())];
121
+ const categories = [...Object.keys((0, import_editor_styles.getStylesSchema)())].filter((category) => category !== "all");
122
122
  return {
123
123
  resources: categories.map((category) => ({
124
124
  uri: `elementor://styles/schema/${category}`,
@@ -2240,6 +2240,9 @@ function extractElementData(element) {
2240
2240
  }
2241
2241
 
2242
2242
  // src/mcp/tools/build-composition/tool.ts
2243
+ var import_editor_elements8 = require("@elementor/editor-elements");
2244
+
2245
+ // src/composition-builder/composition-builder.ts
2243
2246
  var import_editor_elements7 = require("@elementor/editor-elements");
2244
2247
 
2245
2248
  // src/mcp/utils/do-update-element-property.ts
@@ -2247,7 +2250,11 @@ var import_editor_elements5 = require("@elementor/editor-elements");
2247
2250
  var import_editor_props5 = require("@elementor/editor-props");
2248
2251
  var import_editor_styles5 = require("@elementor/editor-styles");
2249
2252
  function resolvePropValue(value, forceKey) {
2250
- return import_editor_props5.Schema.adjustLlmPropValueSchema(value, { forceKey });
2253
+ const Utils = window.elementorV2.editorVariables.Utils;
2254
+ return import_editor_props5.Schema.adjustLlmPropValueSchema(value, {
2255
+ forceKey,
2256
+ transformers: Utils.globalVariablesLLMResolvers
2257
+ });
2251
2258
  }
2252
2259
  var doUpdateElementProperty = (params) => {
2253
2260
  const { elementId, propertyName, propertyValue, elementType } = params;
@@ -2391,9 +2398,14 @@ var validateInput = {
2391
2398
  } else if (!import_editor_props6.Schema.isPropKeyConfigurable(propName)) {
2392
2399
  errors.push(`Property "${propName}" is not configurable.`);
2393
2400
  } else {
2394
- const { valid, jsonSchema } = import_editor_props6.Schema.validatePropValue(propSchema, propValue);
2401
+ const { valid } = import_editor_props6.Schema.validatePropValue(propSchema, propValue);
2395
2402
  if (!valid) {
2396
- errors.push(`Invalid property "${propName}". Expected schema: ${jsonSchema}`);
2403
+ errors.push(
2404
+ `Invalid property "${propName}". Validate input with resource [${STYLE_SCHEMA_URI.replace(
2405
+ "{category}",
2406
+ propName
2407
+ )}]`
2408
+ );
2397
2409
  }
2398
2410
  }
2399
2411
  });
@@ -2432,290 +2444,292 @@ var validateInput = {
2432
2444
  }
2433
2445
  };
2434
2446
 
2435
- // src/mcp/tools/build-composition/prompt.ts
2436
- var import_editor_mcp2 = require("@elementor/editor-mcp");
2437
- var generatePrompt = () => {
2438
- const buildCompositionsToolPrompt = (0, import_editor_mcp2.toolPrompts)("build-compositions");
2439
- buildCompositionsToolPrompt.description(`
2440
- # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
2441
- 1. [${WIDGET_SCHEMA_URI}]
2442
- Required to understand which widgets are available, and what are their configuration schemas.
2443
- Every widgetType (i.e. e-heading, e-button) that is supported has it's own property schema, that you must follow in order to apply property values correctly.
2444
- 2. [${STYLE_SCHEMA_URI}]
2445
- Required to understand the styles schema for the widgets. All widgets share the same styles schema.
2446
- 3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
2447
-
2448
- # DESIGN QUALITY IMPERATIVE
2449
- You are generating designs for real users who expect distinctive, intentional aesthetics - NOT generic AI output.
2450
- **The Core Challenge**: Large language models naturally converge toward statistically common design patterns during generation. This creates predictable, uninspired results that users describe as "AI slop": safe color schemes, default typography hierarchies, minimal contrast, and timid spacing.
2451
- **Your Mission**: Actively resist distributional convergence by making intentional, distinctive design choices across all aesthetic dimensions. Every design decision should have a clear purpose tied to visual hierarchy, brand personality, or user experience goals.
2452
- When in doubt between "safe" and "distinctive," choose distinctive - users can always request refinements, but they cannot salvage generic foundations.
2453
-
2454
- # When to use this tool
2455
- Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2456
- Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2457
-
2458
- # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
2459
- 1. [${WIDGET_SCHEMA_URI}]
2460
- Required to understand which widgets are available, and what are their configuration schemas.
2461
- Every widgetType (i.e. e-heading, e-button) that is supported has it's own property schema, that you must follow in order to apply property values correctly.
2462
- 2. [${STYLE_SCHEMA_URI}]
2463
- Required to understand the styles schema for the widgets. All widgets share the same styles schema.
2464
- 3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
2465
-
2466
- # DESIGN QUALITY IMPERATIVE
2467
- You are generating designs for real users who expect distinctive, intentional aesthetics - NOT generic AI output.
2468
- **The Core Challenge**: Large language models naturally converge toward statistically common design patterns during generation. This creates predictable, uninspired results that users describe as "AI slop": safe color schemes, default typography hierarchies, minimal contrast, and timid spacing.
2469
- **Your Mission**: Actively resist distributional convergence by making intentional, distinctive design choices across all aesthetic dimensions. Every design decision should have a clear purpose tied to visual hierarchy, brand personality, or user experience goals.
2470
- When in doubt between "safe" and "distinctive," choose distinctive - users can always request refinements, but they cannot salvage generic foundations.
2471
-
2472
- # When to use this tool
2473
- Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2474
- Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2475
-
2476
- # Instructions
2477
- 1. Understand the user requirements carefully.
2478
- 2. Build a valid XML structure using only the allowed custom tags provided. For example, if you
2479
- use the "e-button" element, it would be represented as <e-button></e-button> in the XML structure.
2480
- 3. Plan the configuration for each element according to the user requirements, using the configuration schema provided for each custom tag.
2481
- Every widget type has it's own configuration schema, retreivable from the resource [${WIDGET_SCHEMA_URI}].
2482
- PropValues must follow the exact PropType schema provided in the resource.
2483
- 4. For every element, provide a "configuration-id" attribute. For example:
2484
- \`<e-flexbox configuration-id="flex1"><e-heading configuration-id="heading2"></e-heading></e-flexbox>\`
2485
- In the elementConfig property, provide the actual configuration object for each configuration-id used in the XML structure.
2486
- In the stylesConfig property, provide the actual styles configuration object for each configuration-id used in the XML structure.
2487
- 5. Ensure the XML structure is valid and parsable.
2488
- 6. Do not add any attribute nodes, classes, id's, and no text nodes allowed.
2489
- Layout properties, such as margin, padding, align, etc. must be applied using the [${STYLE_SCHEMA_URI}] PropValues.
2490
- 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-tabs", "e-div-block", and "e-flexbox".
2491
- 8. Make sure that non-container elements do NOT have any nested elements.
2492
-
2493
- # DESIGN VECTORS - Concrete Implementation Guidance
2494
-
2495
- ## 1. Typography & Visual Hierarchy
2496
-
2497
- **Avoid Distributional Defaults:**
2498
- - NO generic sans-serifs as primary typefaces (Inter, Roboto, Arial, Helvetica)
2499
- - NO timid size ratios (1.2x, 1.5x scaling)
2500
- - NO uniform font weights (everything at 400 or 600)
2501
-
2502
- **Intentional Alternatives:**
2503
- - **For Technical/Modern**: Consider monospace headlines (JetBrains Mono, SF Mono) paired with clean body text
2504
- - **For Editorial/Elegant**: Consider serif headlines (Playfair Display, Crimson Text) with sans-serif body
2505
- - **For Playful/Creative**: Consider display fonts with character, paired with highly legible body text
2506
-
2507
- **Scale & Contrast Implementation:**
2508
- - Headline-to-body size ratios: 3x minimum (e.g., 48px headline vs 16px body)
2509
- - Use extreme weight contrasts: pair weight-100 or 200 with weight-800 or 900
2510
- - Line height contrasts: tight headlines (1.1) vs. generous body (1.7)
2511
- - Letter spacing: compressed headlines (-0.02em to -0.05em) vs. open small text (0.03em+)
2512
-
2513
- **Hierarchy Mapping:**
2514
- /* Intentional hierarchy example */
2515
- H1: font-size: 3.5rem; font-weight: 900; line-height: 1.1; letter-spacing: -0.03em;
2516
- H2: font-size: 2rem; font-weight: 200; line-height: 1.2;
2517
- Body: font-size: 1rem; font-weight: 400; line-height: 1.7;
2518
- Caption: font-size: 0.75rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
2519
-
2520
- ## 2. Color & Theme Strategy
2521
-
2522
- **Avoid Distributional Defaults:**
2523
- - NO purple gradients or blue-purple color schemes (massively overrepresented in AI output)
2524
- - NO evenly-distributed color palettes (3-4 colors used equally)
2525
- - NO timid pastels or all-neutral schemes
2526
- - NO #333333, #666666, #999999 grays
2527
-
2528
- **Intentional Alternatives:**
2529
- - **Commit to a Dominant Color**: Choose ONE primary brand color that appears in 60-70% of colored elements
2530
- - **Sharp Accent Strategy**: Use 1-2 high-contrast accent colors sparingly (10-15% of colored elements)
2531
- - **Neutrals with Personality**: Replace pure grays with warm (#3d3228, #f5f1ed) or cool (#2a2f3d, #f0f2f5) tinted neutrals
2532
-
2533
- **Color Psychology Mapping:**
2534
- - Energy/Action \u2192 Warm reds, oranges, yellows (NOT purple/blue)
2535
- - Trust/Calm \u2192 Deep teals, forest greens (NOT generic blue)
2536
- - Luxury/Premium \u2192 Deep burgundy, emerald, charcoal with gold accents
2537
- - Playful/Creative \u2192 Unexpected combinations (coral + mint, mustard + navy)
2538
-
2539
- **Implementation:**
2540
- /* Intentional color system example */
2541
- --brand-primary: #d84315; /* Dominant: Deep orange */
2542
- --brand-accent: #00bfa5; /* Accent: Teal (complementary) */
2543
- --neutral-dark: #2d2622; /* Warm dark brown, not #333 */
2544
- --neutral-light: #faf8f6; /* Warm off-white, not pure white */
2545
- --background: linear-gradient(135deg, #faf8f6 0%, #f0ebe6 100%); /* Subtle warmth */
2546
-
2547
- ## 3. Spatial Design & White Space
2548
-
2549
- **Avoid Distributional Defaults:**
2550
- - NO uniform spacing (everything 16px or 24px)
2551
- - NO cramped layouts that maximize content density
2552
- - NO default container widths (1200px, 1440px)
2553
-
2554
- **Intentional Alternatives:**
2555
- - **Breathing Room**: Use generous white space as a design element (80-120px vertical spacing between sections)
2556
- - **Asymmetric Spacing**: Vary padding dramatically (small: 12px, medium: 48px, large: 96px)
2557
- - **Content Width Strategy**:
2558
- - Reading content: max 65-75 characters (600-700px)
2559
- - Hero sections: asymmetric layouts, not centered blocks
2560
- - Cards/components: vary sizes intentionally, not uniform grids
2561
-
2562
- **Implementation:**
2563
- /* Intentional spacing scale */
2564
- --space-xs: 0.5rem; /* 8px */
2565
- --space-sm: 1rem; /* 16px */
2566
- --space-md: 3rem; /* 48px */
2567
- --space-lg: 6rem; /* 96px */
2568
- --space-xl: 10rem; /* 160px */
2569
-
2570
- /* Use in combinations: */
2571
- padding: var(--space-lg) var(--space-md); /* Not uniform padding */
2572
- margin-bottom: var(--space-xl); /* Generous section breaks */
2573
-
2574
- ## 4. Backgrounds & Atmospheric Depth
2575
-
2576
- **Avoid Distributional Defaults:**
2577
- - NO solid white or light gray backgrounds
2578
- - NO single-color backgrounds
2579
- - NO generic gradient overlays
2580
-
2581
- **Intentional Alternatives:**
2582
- - **Layered Gradients**: Combine 2-3 subtle gradients for depth
2583
- - **Geometric Patterns**: SVG patterns, mesh gradients, or subtle noise textures
2584
- - **Strategic Contrast**: Alternate between light and dark sections for rhythm
2585
-
2586
- **Implementation:**
2587
- /* Intentional background example */
2588
- background:
2589
- radial-gradient(circle at 20% 30%, rgba(216, 67, 21, 0.08) 0%, transparent 50%),
2590
- radial-gradient(circle at 80% 70%, rgba(0, 191, 165, 0.06) 0%, transparent 50%),
2591
- linear-gradient(135deg, #faf8f6 0%, #f0ebe6 100%);
2592
-
2593
- ## 5. Visual Hierarchy Principles
2594
-
2595
- **Clear Priority System:**
2596
- 1. **Primary Focus (1 element)**: Largest, highest contrast, most visual weight
2597
- 2. **Secondary Elements (2-3 elements)**: 40-60% of primary size, reduced contrast
2598
- 3. **Tertiary/Support (everything else)**: Minimal visual weight, muted colors
2599
-
2600
- **Contrast Techniques:**
2601
- - Size: 3x+ differences between hierarchy levels
2602
- - Weight: 300+ difference in font-weight values
2603
- - Color: Primary gets brand color, secondary gets neutral, tertiary gets muted
2604
- - Space: Primary gets 2x+ surrounding white space vs. secondary
2605
-
2606
- ## 6. EXAMPLES - Intentional vs. Generic Design
2607
-
2608
- ### \u274C GENERIC (Distributional Convergence)
2609
-
2610
- {
2611
- "xmlStructure": "<e-flexbox configuration-id="flex1"><e-heading configuration-id="heading1"></e-heading><e-button configuration-id="button1"></e-button></e-flexbox>",
2612
- "elementConfig": {
2613
- "heading1": {
2614
- "title": { "$$type": "string", "value": "Welcome to Our Site" }
2615
- }
2616
- },
2617
- "stylesConfig": {
2618
- "heading1": {
2619
- "font-size": {
2620
- "$$type": "size",
2621
- "value": {
2622
- "size": { "$$type": "number", "value": 24 },
2623
- "unit": { "$$type": "string", "value": "px" }
2624
- }
2447
+ // src/composition-builder/composition-builder.ts
2448
+ var CompositionBuilder = class _CompositionBuilder {
2449
+ elementConfig = {};
2450
+ elementStylesConfig = {};
2451
+ rootContainers = [];
2452
+ containerElements = [];
2453
+ api = {
2454
+ createElement: import_editor_elements7.createElement,
2455
+ getWidgetsCache: import_editor_elements7.getWidgetsCache,
2456
+ generateElementId: import_editor_elements7.generateElementId,
2457
+ getContainer: import_editor_elements7.getContainer,
2458
+ doUpdateElementProperty
2459
+ };
2460
+ xml;
2461
+ static fromXMLString(xmlString, api = {}) {
2462
+ const parser = new DOMParser();
2463
+ const xmlDoc = parser.parseFromString(xmlString, "application/xml");
2464
+ const errorNode = xmlDoc.querySelector("parsererror");
2465
+ if (errorNode) {
2466
+ throw new Error("Failed to parse XML string: " + errorNode.textContent);
2467
+ }
2468
+ return new _CompositionBuilder({
2469
+ xml: xmlDoc,
2470
+ api
2471
+ });
2472
+ }
2473
+ constructor(opts) {
2474
+ const { api = {}, elementConfig = {}, stylesConfig = {}, xml } = opts;
2475
+ this.xml = xml;
2476
+ Object.assign(this.api, api);
2477
+ this.setElementConfig(elementConfig);
2478
+ this.setStylesConfig(stylesConfig);
2479
+ }
2480
+ setElementConfig(config) {
2481
+ this.elementConfig = config;
2482
+ }
2483
+ setStylesConfig(config) {
2484
+ this.elementStylesConfig = config;
2485
+ }
2486
+ getXML() {
2487
+ return this.xml;
2488
+ }
2489
+ iterateBuild(node, containerElement, childIndex) {
2490
+ const elementTag = node.tagName;
2491
+ const isContainer = this.containerElements.includes(elementTag);
2492
+ const parentElType = containerElement.model.get("elType");
2493
+ let targetContainerId = parentElType === "e-tabs" ? containerElement.children?.[1].children?.[childIndex]?.id || containerElement.children?.[1].id : containerElement.id;
2494
+ if (!targetContainerId) {
2495
+ targetContainerId = containerElement.id;
2496
+ }
2497
+ const newElement = isContainer ? this.api.createElement({
2498
+ containerId: targetContainerId,
2499
+ model: {
2500
+ elType: elementTag,
2501
+ id: (0, import_editor_elements7.generateElementId)()
2502
+ },
2503
+ options: { useHistory: false }
2504
+ }) : this.api.createElement({
2505
+ containerId: targetContainerId,
2506
+ model: {
2507
+ elType: "widget",
2508
+ widgetType: elementTag,
2509
+ id: (0, import_editor_elements7.generateElementId)()
2625
2510
  },
2511
+ options: { useHistory: false }
2512
+ });
2513
+ if (containerElement.id === "document") {
2514
+ this.rootContainers.push(newElement);
2515
+ }
2516
+ node.setAttribute("id", newElement.id);
2517
+ let currentChild = 0;
2518
+ for (const childNode of Array.from(node.children)) {
2519
+ this.iterateBuild(childNode, newElement, currentChild);
2520
+ currentChild++;
2626
2521
  }
2627
2522
  }
2628
- }
2629
-
2630
- **Why Generic**: 24px default size, #333 safe gray, 600 weight (middle-ground), purple gradient (AI clich\xE9), uniform 12/24px padding
2631
-
2632
- ### \u2705 INTENTIONAL (Resisting Convergence)
2633
- {
2634
- "xmlStructure": "<e-flexbox configuration-id="hero-section"><e-heading configuration-id="hero-title"></e-heading><e-text configuration-id="hero-subtitle"></e-text><e-button configuration-id="hero-cta"></e-button></e-flexbox>",
2635
- "elementConfig": {
2636
- "hero-title": {
2637
- "title": { "$$type": "string", "value": "Transform Your Workflow" }
2638
- },
2639
- "hero-subtitle": {
2640
- "content": { "$$type": "string", "value": "Built for teams who refuse to compromise on quality" }
2523
+ findSchemaForNode(node) {
2524
+ const widgetsCache = this.api.getWidgetsCache() || {};
2525
+ const widgetType = node.tagName;
2526
+ const widgetData = widgetsCache[widgetType]?.atomic_props_schema;
2527
+ return widgetData || null;
2528
+ }
2529
+ matchNodeByConfigId(configId) {
2530
+ const node = this.xml.querySelector(`[configuration-id="${configId}"]`);
2531
+ if (!node) {
2532
+ throw new Error(`Configuration id "${configId}" does not have target node.`);
2641
2533
  }
2642
- },
2643
- "stylesConfig": {
2644
- "hero-section": {
2645
- "display": { "$$type": "string", "value": "flex" },
2646
- "flex-direction": { "$$type": "string", "value": "column" },
2647
- "align-items": { "$$type": "string", "value": "flex-start" },
2648
- "background": {
2649
- "$$type": "color",
2650
- "value": "#f0ebe6",
2651
- "$intention": "background: #f0ebe6",
2534
+ const id = node.getAttribute("id");
2535
+ if (!id) {
2536
+ throw new Error(`Node with configuration id "${configId}" does not have element id.`);
2537
+ }
2538
+ const element = this.api.getContainer(id);
2539
+ if (!element) {
2540
+ throw new Error(`Element with id "${id}" not found but should exist.`);
2541
+ }
2542
+ return {
2543
+ element,
2544
+ node
2545
+ };
2546
+ }
2547
+ applyStyles() {
2548
+ const errors = [];
2549
+ const invalidStyles = {};
2550
+ const validStylesPropValues = {};
2551
+ for (const [styleId, styleConfig] of Object.entries(this.elementStylesConfig)) {
2552
+ const { element, node } = this.matchNodeByConfigId(styleId);
2553
+ for (const [styleName, stylePropValue] of Object.entries(styleConfig)) {
2554
+ const { valid, errors: validationErrors } = validateInput.validateStyles({
2555
+ [styleName]: stylePropValue
2556
+ });
2557
+ if (!valid) {
2558
+ if (styleConfig.$intention) {
2559
+ invalidStyles[element.id] = invalidStyles[element.id] || [];
2560
+ invalidStyles[element.id].push(styleName);
2561
+ }
2562
+ errors.push(...validationErrors || []);
2563
+ } else {
2564
+ validStylesPropValues[styleName] = stylePropValue;
2565
+ }
2566
+ this.api.doUpdateElementProperty({
2567
+ elementId: element.id,
2568
+ propertyName: "_styles",
2569
+ propertyValue: validStylesPropValues,
2570
+ elementType: node.tagName
2571
+ });
2652
2572
  }
2653
- },
2654
- "hero-title": {
2655
- "font-size": {
2656
- "$$type": "size",
2657
- "value": {
2658
- "size": { "$$type": "number", "value": 72 },
2659
- "unit": { "$$type": "string", "value": "px" }
2573
+ }
2574
+ return {
2575
+ errors,
2576
+ invalidStyles
2577
+ };
2578
+ }
2579
+ applyConfigs() {
2580
+ const errors = [];
2581
+ for (const [configId, config] of Object.entries(this.elementConfig)) {
2582
+ const { element, node } = this.matchNodeByConfigId(configId);
2583
+ const propSchema = this.findSchemaForNode(node);
2584
+ const result = validateInput.validateProps(propSchema, config);
2585
+ if (!result.valid && result.errors?.length) {
2586
+ errors.push(...result.errors);
2587
+ } else {
2588
+ for (const [propertyName, propertyValue] of Object.entries(config)) {
2589
+ try {
2590
+ this.api.doUpdateElementProperty({
2591
+ elementId: element.id,
2592
+ propertyName,
2593
+ propertyValue,
2594
+ elementType: node.tagName
2595
+ });
2596
+ } catch (error) {
2597
+ errors.push(error.message);
2660
2598
  }
2661
- },
2599
+ }
2600
+ }
2662
2601
  }
2602
+ return errors;
2663
2603
  }
2664
- }
2665
-
2666
-
2667
- **Why Intentional**:
2668
- - Typography: 4.5rem headline (3.6x body), weight 900 vs 200 contrast, tight leading
2669
- - Color: Warm orange primary (#d84315), warm neutrals (#2d2622, #5a534d) NOT #333/#666
2670
- - Spacing: 10rem vertical padding (generous), 3rem gap, asymmetric alignment
2671
- - Background: Layered gradients with subtle brand color accent
2672
-
2673
- # CONSTRAINTS
2674
- When a tool execution fails, retry up to 10 more times, read the error message carefully, and adjust the XML structure or the configurations accordingly.
2675
- If a "$$type" is missing, update the invalid object, if the XML has parsing errors, fix it, etc. and RETRY.
2676
- VALIDATE the XML structure before delivering it as the final result.
2677
- VALIDATE the JSON structure used in the "configuration" attributes for each element before delivering the final result. The configuration must MATCH the PropValue schemas.
2678
- NO LINKS ALLOWED. Never apply links to elements, even if they appear in the PropType schema.
2679
- elementConfig values must align with the widget's PropType schema, available at the resource [${WIDGET_SCHEMA_URI}].
2680
- stylesConfig values must align with the common styles PropType schema, available at the resource [${STYLE_SCHEMA_URI}].
2681
-
2682
- # DESIGN QUALITY CONSTRAINTS
2683
-
2684
- **Typography Constraints:**
2685
- - NEVER use Inter, Roboto, Arial, or Helvetica as primary display fonts
2686
- - NEVER use font-size ratios smaller than 2.5x between headlines and body
2687
- - NEVER use font-weight values between 500-700 for headlines (go lighter or heavier)
2688
-
2689
- **Color Constraints:**
2690
- - NEVER use purple gradients or blue-purple color schemes
2691
- - NEVER use pure grays (#333, #666, #999) - use tinted neutrals instead
2692
- - NEVER distribute colors evenly - commit to ONE dominant color
2693
- - NEVER use more than 3 core colors (1 dominant, 1-2 accents)
2694
-
2695
- **Spacing Constraints:**
2696
- - NEVER use uniform spacing across all elements
2697
- - NEVER use section padding less than 4rem (64px) for hero/major sections
2698
- - NEVER center everything - use asymmetric layouts for visual interest
2699
-
2700
- **Background Constraints:**
2701
- - NEVER use solid white (#ffffff) or light gray (#f5f5f5) backgrounds without texture/gradients
2702
- - ALWAYS layer at least 2 gradient or color elements for atmospheric depth
2703
-
2704
- # Parameters
2705
- All parameters are MANDATORY.
2706
- - xmlStructure
2707
- - elementConfig
2708
- - stylesConfig
2709
-
2710
- If unsure about the configuration of a specific property, read the schema resources carefully.
2711
-
2712
- # About our widgets
2713
- Most widgets are self-explanatory by their name. Here is some additional information.
2714
- Check for available llm_guidance property in the widget's schema.
2715
- SVG elements are bound to internal content upload. Avoid usage, unless you have tools to upload SVG content.
2716
- When working with containers, do not forget to apply style schema for controlling the layout.
2717
-
2604
+ build(rootContainer) {
2605
+ const widgetsCache = this.api.getWidgetsCache() || {};
2606
+ const CONTAINER_ELEMENTS = Object.values(widgetsCache).filter((widget) => widget.meta?.is_container).map((widget) => widget.elType).filter((x) => typeof x === "string");
2607
+ this.containerElements = CONTAINER_ELEMENTS;
2608
+ new Set(this.xml.querySelectorAll("*")).forEach((node) => {
2609
+ if (!widgetsCache[node.tagName]) {
2610
+ throw new Error(`Unknown widget type: ${node.tagName}`);
2611
+ }
2612
+ });
2613
+ const children = Array.from(this.xml.children);
2614
+ let currentChild = 0;
2615
+ for (const childNode of children) {
2616
+ this.iterateBuild(childNode, rootContainer, currentChild);
2617
+ currentChild++;
2618
+ }
2619
+ const { errors: styleErrors, invalidStyles } = this.applyStyles();
2620
+ const configErrors = this.applyConfigs();
2621
+ return {
2622
+ configErrors,
2623
+ styleErrors,
2624
+ invalidStyles,
2625
+ rootContainers: [...this.rootContainers]
2626
+ };
2627
+ }
2628
+ };
2718
2629
 
2630
+ // src/mcp/tools/build-composition/prompt.ts
2631
+ var import_editor_mcp2 = require("@elementor/editor-mcp");
2632
+ var generatePrompt = () => {
2633
+ const buildCompositionsToolPrompt = (0, import_editor_mcp2.toolPrompts)("build-compositions");
2634
+ buildCompositionsToolPrompt.description(`
2635
+ # REQUIRED RESOURCES (Read before use)
2636
+ 1. [${WIDGET_SCHEMA_URI}] - Widget types, configuration schemas, and PropType definitions
2637
+ 2. [${STYLE_SCHEMA_URI}] - Common styles schema shared by all widgets
2638
+ 3. [elementor://global-classes] - Existing global classes (check FIRST to reuse)
2639
+
2640
+ # THREE-PHASE WORKFLOW (MANDATORY)
2641
+
2642
+ ## Phase 1: Create Global Classes
2643
+ 1. Analyze requirements \u2192 identify reusable patterns (typography, colors, spacing)
2644
+ 2. Check [elementor://global-classes] for existing classes
2645
+ 3. Use "create-global-class" tool for NEW reusable styles BEFORE building
2646
+
2647
+ ## Phase 2: Build Composition (THIS TOOL)
2648
+ 4. Build valid XML with minimal inline styles (layout/positioning only)
2649
+ 5. Avoid duplicating styles that should be global classes
2650
+
2651
+ ## Phase 3: Apply Classes
2652
+ 6. Use "apply-global-class" tool to apply global classes to elements
2653
+
2654
+ # CORE INSTRUCTIONS
2655
+
2656
+ **Structure:**
2657
+ - Build valid XML using allowed widget tags (e.g., \`<e-button configuration-id="btn1"></e-button>\`)
2658
+ - Containers only: "e-flexbox", "e-div-block", "e-tabs"
2659
+ - Every element MUST have unique "configuration-id" attribute
2660
+ - No attributes, classes, IDs, or text nodes in XML
2661
+
2662
+ **Configuration:**
2663
+ - Map each configuration-id to elementConfig (widget props) and stylesConfig (styles)
2664
+ - Follow exact PropType schemas from resources above
2665
+ - All PropValues need \`$$type\` property matching schema
2666
+ - Keep stylesConfig MINIMAL - layout only, NOT reusable styles
2667
+
2668
+ **Validation:**
2669
+ - Parse XML before submission
2670
+ - Match all PropValues to schema (\`$$type\` required)
2671
+ - NO LINKS in any configuration
2672
+ - Retry on errors up to 10x, reading error messages carefully
2673
+
2674
+ # DESIGN QUALITY: AVOID AI SLOP
2675
+
2676
+ **Problem:** LLMs default to generic patterns (purple gradients, #333 grays, 24px headings, uniform spacing)
2677
+ **Solution:** Make intentional, distinctive choices. When unsure, choose bold over safe.
2678
+
2679
+ ## Typography Rules
2680
+ \u274C AVOID: Inter/Roboto/Arial, small ratios (1.5x), medium weights (500-700)
2681
+ \u2705 USE: 3x+ size ratios, extreme weight contrasts (100/200 vs 800/900), tight headlines (1.1 line-height)
2682
+
2683
+ ## Color Rules
2684
+ \u274C AVOID: Purple gradients, pure grays (#333/#666/#999), even distribution
2685
+ \u2705 USE: ONE dominant color (60-70%), 1-2 accent colors (10-15%), tinted neutrals (warm/cool grays)
2686
+
2687
+ ## Spacing Rules
2688
+ \u274C AVOID: Uniform spacing (all 16px/24px), cramped layouts, centered everything
2689
+ \u2705 USE: Generous spacing (80-120px sections), dramatic variation (12px/48px/96px), asymmetric layouts
2690
+
2691
+ ## Background Rules
2692
+ \u274C AVOID: Solid white/gray, single colors
2693
+ \u2705 USE: Layered gradients (2-3 layers), subtle patterns, alternating light/dark sections
2694
+
2695
+ ## Visual Hierarchy
2696
+ 1. **Primary** (1 element): Largest, highest contrast, most space
2697
+ 2. **Secondary** (2-3 elements): 40-60% of primary size
2698
+ 3. **Tertiary** (rest): Minimal weight, muted
2699
+
2700
+ **Contrast techniques:** 3x size differences, 300+ weight differences, color hierarchy (brand \u2192 neutral \u2192 muted)
2701
+
2702
+ # DESIGN CONSTRAINTS (NEVER VIOLATE)
2703
+
2704
+ **Typography:**
2705
+ - NEVER use Inter, Roboto, Arial, Helvetica as primary display fonts
2706
+ - NEVER use font-size ratios < 2.5x between headlines and body
2707
+ - NEVER use font-weight 500-700 for headlines (go lighter or heavier)
2708
+
2709
+ **Color:**
2710
+ - PREFER not to use pure grays - use tinted neutrals (#2d2622, #faf8f6, not #333/#f5f5f5)
2711
+ - NEVER distribute colors evenly - commit to ONE dominant
2712
+ - NEVER use more than 3 core colors - except for info/alert/badges
2713
+
2714
+ **Spacing:**
2715
+ - NEVER use uniform spacing
2716
+ - NEVER use < 4rem (64px) padding for major sections
2717
+ - NEVER center everything
2718
+ - PRIORITIZE rem based values over pixel based
2719
+
2720
+ **Background:**
2721
+ - NEVER use solid #ffffff or #f5f5f5 without texture/gradients
2722
+ - ALWAYS layer 2+ gradient/color elements
2723
+
2724
+ # WIDGET NOTES
2725
+ - Check \`llm_guidance\` property in widget schemas for context
2726
+ - Avoid SVG widgets (require content upload tools) - when must, prior to execution ensure assets uploaded
2727
+ - Apply style schema to containers for layout control
2728
+
2729
+ # PARAMETERS (ALL MANDATORY)
2730
+ - **xmlStructure**: Valid XML with configuration-id attributes
2731
+ - **elementConfig**: Record of configuration-id \u2192 widget PropValues
2732
+ - **stylesConfig**: Record of configuration-id \u2192 style PropValues (layout only)
2719
2733
  `);
2720
2734
  buildCompositionsToolPrompt.example(`
2721
2735
  A Heading and a button inside a flexbox
@@ -2762,7 +2776,12 @@ A Heading and a button inside a flexbox
2762
2776
  You should use these IDs as reference for further configuration, styling or changing elements later on.`
2763
2777
  );
2764
2778
  buildCompositionsToolPrompt.instruction(
2765
- `You must use styles/variables/classes that are available in the project resources, you should prefer using them over inline styles, and you are welcome to execute relevant tools AFTER this tool execution, to apply global classes to the created elements.`
2779
+ `**CRITICAL WORKFLOW REMINDER**:
2780
+ 1. FIRST: Create reusable global classes for typography, colors, spacing patterns using "create-global-class" tool
2781
+ 2. SECOND: Use THIS tool with minimal inline styles (only layout & unique properties)
2782
+ 3. THIRD: Apply global classes to elements using "apply-global-class" tool
2783
+
2784
+ This ensures maximum reusability and consistency across your design system. ALWAYS check [elementor://global-classes] for existing classes before creating new ones.`
2766
2785
  );
2767
2786
  return buildCompositionsToolPrompt.prompt();
2768
2787
  };
@@ -2792,8 +2811,7 @@ var outputSchema = {
2792
2811
  errors: import_schema.z.string().describe("Error message if the composition building failed").optional(),
2793
2812
  xmlStructure: import_schema.z.string().describe(
2794
2813
  "The built XML structure as a string. Must use this XML after completion of building the composition, it contains real IDs."
2795
- ).optional(),
2796
- llmInstructions: import_schema.z.string().describe("Instructions for what to do next, Important to follow these instructions!")
2814
+ ).optional()
2797
2815
  };
2798
2816
 
2799
2817
  // src/mcp/tools/build-composition/tool.ts
@@ -2805,120 +2823,60 @@ var initBuildCompositionsTool = (reg) => {
2805
2823
  schema: inputSchema,
2806
2824
  requiredResources: [
2807
2825
  { description: "Widgets schema", uri: WIDGET_SCHEMA_URI },
2808
- { description: "Global Classes", uri: "elementor://global-classes" },
2809
2826
  { description: "Styles schema", uri: STYLE_SCHEMA_URI },
2827
+ { description: "Global Classes", uri: "elementor://global-classes" },
2810
2828
  { description: "Global Variables", uri: "elementor://global-variables" },
2811
2829
  { description: "Styles best practices", uri: BEST_PRACTICES_URI }
2812
2830
  ],
2813
2831
  outputSchema,
2814
2832
  modelPreferences: {
2815
- hints: [{ name: "claude-sonnet-4-5" }],
2816
- intelligencePriority: 0.95,
2817
- speedPriority: 0.5
2833
+ hints: [{ name: "claude-sonnet-4-5" }]
2818
2834
  },
2819
2835
  handler: async (params) => {
2820
- let xml = null;
2821
2836
  const { xmlStructure, elementConfig, stylesConfig } = params;
2837
+ let generatedXML = "";
2822
2838
  const errors = [];
2823
- const softErrors = [];
2824
2839
  const rootContainers = [];
2825
- const widgetsCache = (0, import_editor_elements7.getWidgetsCache)() || {};
2826
- const documentContainer = (0, import_editor_elements7.getContainer)("document");
2840
+ const documentContainer = (0, import_editor_elements8.getContainer)("document");
2827
2841
  try {
2828
- const parser = new DOMParser();
2829
- xml = parser.parseFromString(xmlStructure, "application/xml");
2830
- const errorNode = xml.querySelector("parsererror");
2831
- if (errorNode) {
2832
- throw new Error("Failed to parse XML structure: " + errorNode.textContent);
2842
+ const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
2843
+ createElement: import_editor_elements8.createElement,
2844
+ getWidgetsCache: import_editor_elements8.getWidgetsCache
2845
+ });
2846
+ compositionBuilder.setElementConfig(elementConfig);
2847
+ compositionBuilder.setStylesConfig(stylesConfig);
2848
+ const {
2849
+ configErrors,
2850
+ invalidStyles,
2851
+ rootContainers: generatedRootContainers
2852
+ } = compositionBuilder.build(documentContainer);
2853
+ generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
2854
+ if (configErrors.length) {
2855
+ errors.push(...configErrors.map((e) => new Error(e)));
2856
+ throw new Error("Configuration errors occurred during composition building.");
2833
2857
  }
2834
- const children = Array.from(xml.children);
2835
- const iterate = async (node, containerElement = documentContainer, childIndex) => {
2836
- const elementTag = node.tagName;
2837
- if (!widgetsCache[elementTag]) {
2838
- errors.push(new Error(`Unknown widget type: ${elementTag}`));
2839
- }
2840
- const CONTAINER_ELEMENTS = Object.values(widgetsCache).filter((widget) => widget.meta?.is_container).map((widget) => widget.elType);
2841
- const isContainer = CONTAINER_ELEMENTS.includes(elementTag);
2842
- const parentElType = containerElement.model.get("elType");
2843
- let targetContainerId = parentElType === "e-tabs" ? containerElement.children?.[1].children?.[childIndex]?.id || containerElement.children?.[1].id : containerElement.id;
2844
- if (!targetContainerId) {
2845
- targetContainerId = containerElement.id;
2846
- }
2847
- const newElement = isContainer ? (0, import_editor_elements7.createElement)({
2848
- containerId: targetContainerId,
2849
- model: {
2850
- elType: elementTag,
2851
- id: (0, import_editor_elements7.generateElementId)()
2852
- },
2853
- options: { useHistory: false }
2854
- }) : (0, import_editor_elements7.createElement)({
2855
- containerId: targetContainerId,
2856
- model: {
2857
- elType: "widget",
2858
- widgetType: elementTag,
2859
- id: (0, import_editor_elements7.generateElementId)()
2858
+ rootContainers.push(...generatedRootContainers);
2859
+ Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
2860
+ const customCss = {
2861
+ value: rawCssRules.join(";\n")
2862
+ };
2863
+ doUpdateElementProperty({
2864
+ elementId,
2865
+ propertyName: "_styles",
2866
+ propertyValue: {
2867
+ _styles: {
2868
+ custom_css: customCss
2869
+ }
2860
2870
  },
2861
- options: { useHistory: false }
2871
+ elementType: "widget"
2862
2872
  });
2863
- if (containerElement === documentContainer) {
2864
- rootContainers.push(newElement);
2865
- }
2866
- node.setAttribute("id", newElement.id);
2867
- const configId = node.getAttribute("configuration-id") || "";
2868
- try {
2869
- const configObject = elementConfig[configId] || {};
2870
- const styleObject = stylesConfig[configId] || {};
2871
- const { errors: propsValidationErrors } = validateInput.validatePropSchema(
2872
- elementTag,
2873
- configObject
2874
- );
2875
- errors.push(...(propsValidationErrors || []).map((msg) => new Error(msg)));
2876
- const { errors: stylesValidationErrors } = validateInput.validateStyles(styleObject);
2877
- errors.push(...(stylesValidationErrors || []).map((msg) => new Error(msg)));
2878
- if (propsValidationErrors?.length || stylesValidationErrors?.length) {
2879
- return;
2880
- }
2881
- configObject._styles = styleObject || {};
2882
- for (const [propertyName, propertyValue] of Object.entries(configObject)) {
2883
- try {
2884
- doUpdateElementProperty({
2885
- elementId: newElement.id,
2886
- propertyName,
2887
- propertyValue,
2888
- elementType: elementTag
2889
- });
2890
- } catch (error) {
2891
- softErrors.push(error);
2892
- }
2893
- }
2894
- if (isContainer) {
2895
- let currentChild2 = 0;
2896
- for (const child of node.children) {
2897
- iterate(child, newElement, currentChild2);
2898
- currentChild2++;
2899
- }
2900
- } else {
2901
- node.innerHTML = "";
2902
- node.removeAttribute("configuration");
2903
- }
2904
- } finally {
2905
- }
2906
- };
2907
- let currentChild = 0;
2908
- for await (const childNode of children) {
2909
- await iterate(childNode, documentContainer, currentChild);
2910
- currentChild++;
2911
- try {
2912
- } catch (error) {
2913
- errors.push(error);
2914
- }
2915
- }
2873
+ });
2916
2874
  } catch (error) {
2917
2875
  errors.push(error);
2918
2876
  }
2919
2877
  if (errors.length) {
2920
2878
  rootContainers.forEach((rootContainer) => {
2921
- (0, import_editor_elements7.deleteElement)({
2879
+ (0, import_editor_elements8.deleteElement)({
2922
2880
  elementId: rootContainer.id,
2923
2881
  options: { useHistory: false }
2924
2882
  });
@@ -2952,20 +2910,19 @@ ${errorMessages.join(
2952
2910
  Now that you have these errors, fix them and try again. Errors regarding configuration objects, please check against the PropType schemas`;
2953
2911
  throw new Error(errorText);
2954
2912
  }
2955
- if (!xml) {
2956
- throw new Error("XML structure is null after parsing.");
2957
- }
2958
2913
  return {
2959
- xmlStructure: new XMLSerializer().serializeToString(xml),
2914
+ xmlStructure: generatedXML,
2960
2915
  errors: errors?.length ? errors.map((e) => typeof e === "string" ? e : e.message).join("\n\n") : void 0,
2961
- llmInstructions: (softErrors.length ? `The composition was built successfully, but there were some issues with the provided configurations:
2916
+ llm_instructions: `The composition was built successfully with element IDs embedded in the XML.
2962
2917
 
2963
- ${softErrors.map((e) => `- ${e.message}`).join("\n")}
2918
+ **CRITICAL NEXT STEPS** (Follow in order):
2919
+ 1. **Apply Global Classes**: Use "apply-global-class" tool to apply the global classes you created BEFORE building this composition
2920
+ - Check the created element IDs in the returned XML
2921
+ - Apply semantic classes (heading-primary, button-cta, etc.) to appropriate elements
2964
2922
 
2965
- Please use configure-element tool to fix these issues. Now that you have information about these issues, use the configure-element tool to fix them!` : "") + `
2966
- Next Steps:
2967
- - Use "apply-global-class" tool as there may be global styles ready to be applied to elements.
2968
- - Use "configure-element" tool to further configure elements as needed, including styles.
2923
+ 2. **Fine-tune if needed**: Use "configure-element" tool only for element-specific adjustments that don't warrant global classes
2924
+
2925
+ Remember: Global classes ensure design consistency and reusability. Don't skip applying them!
2969
2926
  `
2970
2927
  };
2971
2928
  }
@@ -3191,7 +3148,7 @@ Check the styles schema at the resource [${STYLE_SCHEMA_URI.replace(
3191
3148
  }
3192
3149
 
3193
3150
  // src/mcp/tools/get-element-config/tool.ts
3194
- var import_editor_elements8 = require("@elementor/editor-elements");
3151
+ var import_editor_elements9 = require("@elementor/editor-elements");
3195
3152
  var import_editor_props7 = require("@elementor/editor-props");
3196
3153
  var import_schema5 = require("@elementor/schema");
3197
3154
  var schema = {
@@ -3230,12 +3187,12 @@ var initGetElementConfigTool = (reg) => {
3230
3187
  speedPriority: 0.9
3231
3188
  },
3232
3189
  handler: async ({ elementId }) => {
3233
- const element = (0, import_editor_elements8.getContainer)(elementId);
3190
+ const element = (0, import_editor_elements9.getContainer)(elementId);
3234
3191
  if (!element) {
3235
3192
  throw new Error(`Element with ID ${elementId} not found.`);
3236
3193
  }
3237
3194
  const elementRawSettings = element.settings;
3238
- const propSchema = (0, import_editor_elements8.getWidgetsCache)()?.[element.model.get("widgetType") || element.model.get("elType") || ""]?.atomic_props_schema;
3195
+ const propSchema = (0, import_editor_elements9.getWidgetsCache)()?.[element.model.get("widgetType") || element.model.get("elType") || ""]?.atomic_props_schema;
3239
3196
  if (!elementRawSettings || !propSchema) {
3240
3197
  throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
3241
3198
  }
@@ -3244,7 +3201,7 @@ var initGetElementConfigTool = (reg) => {
3244
3201
  import_editor_props7.Schema.configurableKeys(propSchema).forEach((key) => {
3245
3202
  propValues[key] = structuredClone(elementRawSettings.get(key));
3246
3203
  });
3247
- const elementStyles = (0, import_editor_elements8.getElementStyles)(elementId) || {};
3204
+ const elementStyles = (0, import_editor_elements9.getElementStyles)(elementId) || {};
3248
3205
  const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
3249
3206
  if (localStyle) {
3250
3207
  const defaultVariant = localStyle.variants.find(
@@ -3291,127 +3248,118 @@ var initCanvasMcp = (reg) => {
3291
3248
 
3292
3249
  // src/mcp/mcp-description.ts
3293
3250
  var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
3294
- var mcpDescription = `Canvas MCP
3295
- This MCP enables everything related to creation, configuration, and styling of elements on the Elementor canvas.
3251
+ var mcpDescription = `Elementor Canvas MCP
3252
+ This MCP enables creation, configuration, and styling of elements on the Elementor canvas using the build_composition tool.
3296
3253
 
3297
- # Design Systems in Elementor
3298
- - Elementor presents global classes. Each global class is a a set of styles that can be applied to multiple elements. This allows for consistent styling across the design.
3299
- - Elementor also presents global variables, which can be colors, sizes or fonts. These variables can be used in any element's styles, or global classes, allowing for easy updates and consistency across the design.
3300
- - All data is stored in a PropValue structure, which is a wrapper for elementor values. The PropValues are derived from an internal "PropType" schema, which defines the structure and types of the values.
3254
+ # Core Concepts
3255
+
3256
+ ## PropValues Structure
3257
+ All data in Elementor uses PropValues - a typed wrapper for values:
3258
+ \`\`\`json
3259
+ {
3260
+ "$$type": "the-prop-type-schema-kind",
3261
+ "value": "the-actual-value-as-defined-for-the-propType"
3262
+ }
3263
+ \`\`\`
3264
+ The \`$$type\` defines how Elementor interprets the value. Providing the correct \`$$type\` is critical - incorrect types will be rejected.
3265
+
3266
+ ## Design System Resources
3267
+ - **Global Variables**: Reusable colors, sizes, and fonts (\`elementor://global-variables\`)
3268
+ - **Global Classes**: Reusable style sets that can be applied to elements (\`elementor://global-classes\`)
3269
+ - **Widget Schemas**: Configuration options for each widget type (\`${WIDGET_SCHEMA_URI}\`)
3270
+ - **Style Schema**: Common styles shared across all widgets and containers (\`${STYLE_SCHEMA_URI}\`)
3271
+
3272
+ # Building Compositions with build_composition
3273
+
3274
+ The \`build_composition\` tool is the primary way to create elements. It accepts structure (XML), configuration, and styling in a single operation.
3275
+
3276
+ ## Complete Workflow
3277
+
3278
+ ### 1. Parse User Requirements
3279
+ Understand what needs to be built: structure, content, and styling.
3280
+
3281
+ ### 2. Check Global Resources FIRST
3282
+ Always check existing resources before building:
3283
+ - List \`elementor://global-variables\` for available variables (colors, sizes, fonts)
3284
+ - List \`elementor://global-classes\` for available style sets
3285
+ - **Always prefer using existing global resources over creating inline styles**
3286
+
3287
+ ### 3. Retrieve Widget Schemas
3288
+ For each widget you'll use:
3289
+ - List \`${WIDGET_SCHEMA_URI}\` to see available widgets
3290
+ - Retrieve configuration schema from \`${ELEMENT_SCHEMA_URI}\` for each widget
3291
+ - Check the \`llm_guidance\` property to understand if a widget is a container (can have children)
3292
+
3293
+ ### 4. Build XML Structure
3294
+ Create valid XML with configuration-ids:
3295
+ - Each element must have a unique \`configuration-id\` attribute
3296
+ - No text nodes, classes, or IDs in XML - structure only
3297
+ - Example:
3298
+ \`\`\`xml
3299
+ <e-container configuration-id="container-1">
3300
+ <e-heading configuration-id="heading-1" />
3301
+ <e-text configuration-id="text-1" />
3302
+ </e-container>
3303
+ \`\`\`
3301
3304
 
3302
- # PropValues structure and usage
3305
+ ### 5. Create elementConfig
3306
+ Map each configuration-id to its widget properties using PropValues:
3307
+ - Use correct \`$$type\` matching the widget's schema
3308
+ - Use global variables in PropValues where applicable
3309
+ - Example:
3303
3310
  \`\`\`json
3304
3311
  {
3305
- $$type: 'the-prop-type-schema-kind',
3306
- value: 'the-actual-value-as-defined-for-the-propType'
3312
+ "heading-1": {
3313
+ "text": { "$$type": "string", "value": "Welcome" },
3314
+ "tag": { "$$type": "string", "value": "h1" }
3315
+ }
3307
3316
  }
3308
3317
  \`\`\`
3309
- The "value" property can be an object, string, number, boolean, array, etc. The $$type defines the kind of value, and the value is the actual value.
3310
- It is critical to provide the correct $$type for each value, as it defines how Elementor will interpret the value or reject it.
3311
-
3312
- All widgets properties and configuration is built from sets of PropValues, which can be retreived from the resource [${WIDGET_SCHEMA_URI}].
3313
- All styles are SHARED ACCROSS widgets, containers and components, and are defined in a common styles schema, retreivable from the resource [${STYLE_SCHEMA_URI}].
3314
- The style schema also defines the global classes.
3315
-
3316
- To understand the configuration options for an element, refer to the PropType schema for that specific element. For example: "e-heading" configuration schema is available at the resource [${WIDGET_SCHEMA_URI}/e-heading]
3317
-
3318
- # Modifying elements and styles
3319
- When configuring an element, elementor does a MERGE PROPERTIES operation, which means that only the properties you provide will be updated, and the rest will remain as is.
3320
- For deleting a property, the value must be set to null, instead of a PropValue. When adding a configuration, no need to provide the full configuration, only the properties you want to add or update.
3321
- The same rule applies to styles as well and modifications to global classes.
3322
-
3323
- # Building full compositions
3324
- The "build-composition" tool allows creating multiple elements in a single operation.
3325
- The tool accepts both the structure, the styling and the configuration of each element to be created.
3326
-
3327
- - First step: Retreive the available widgets by listing the [${WIDGET_SCHEMA_URI}] dynamic resource.
3328
- - Second step: decide which elements to create, and their configuration and styles.
3329
- Retrieve the used elements configuration schema from the resource [${ELEMENT_SCHEMA_URI}]
3330
- - Third step: define the styles for each element, using the common styles schema from the resource [${STYLE_SCHEMA_URI}]. List the resource to see all available style properties.
3331
-
3332
- ## Workflow for build-compositions tool
3333
- 1. **Parse user requirements** - Undestand what needs to be built (structure, content, styling).
3334
- 2. ** Check global resources FIRST** - Always check before building:
3335
- - List \`elementor://global-classes\` to see if the needed global classes already exist.
3336
- - List \`elementor://global-variables\` to see if the needed global variables already exist.
3337
- - **Preference**: Use existing global classes and variables over creating new inline styles.
3338
- 3. **Retreive widget schemas** - For each widget you will use:
3339
- - List [${WIDGET_SCHEMA_URI}] to see available widgets.
3340
- - Retrieve configuration schema from [${ELEMENT_SCHEMA_URI}] for each widget to understand required properties.
3341
- - Understand if a widget is a container (can have children) by checking the "llm_guidance" property in the widget's schema.
3342
- 4. **Build XML structure** - Create valid XML width configuration-ids:
3343
- - Every element has unique configuration-id attribute
3344
- - No text nodes, classes, IDs in XML.
3345
-
3346
- 5. **Create elementConfig** - For each configuration-id:
3347
- - Use PropValues with corrent \`$$type\` matching the schema.
3348
- - **Use global variables** in PropValues where applicable
3349
-
3350
- 6. **Create stylesConfig** - For each configuration-id:
3351
- - Use style schema PropValues from [${STYLE_SCHEMA_URI}]
3352
- - **Use global variables** for colors, sizes, fonts where applicable
3353
- - **Important**: Global classes are applied AFTER building the composition. Once built, apply classes using the "apply-global-class" tool - after completion of building the composition.
3354
-
3355
- 7. **Validate** - Ensure:
3356
- - XML structure is valid
3357
- - All PropValues have corrent \`$$type\`
3358
- - After building a composition, you can retreive each element configuration using the "get-element-configuration-values" tool to verify correctness, using the IDs returned from the build-composition tool.
3359
-
3360
- ## Key relationships:
3361
- - **XML structure**: Defines the hierarchy of elements/widgets
3362
- - **elementConfig**: Maps configuration-id to widget PropValues
3363
- - **stylesConfig**: Maps configuration-id to style PropValues
3364
-
3365
- ## Using global variables example:
3366
- Existing global variables can be used during composition
3318
+
3319
+ ### 6. Create stylesConfig
3320
+ Map each configuration-id to style PropValues from \`${STYLE_SCHEMA_URI}\`:
3321
+ - Use global variables for colors, sizes, and fonts
3322
+ - Example using global variable:
3367
3323
  \`\`\`json
3368
- { "color": { "$$type": "global-color-variable", "value": "global-variable-id" } }
3324
+ {
3325
+ "heading-1": {
3326
+ "color": { "$$type": "global-color-variable", "value": "primary-color-id" },
3327
+ "font-size": { "$$type": "size", "value": "2rem" }
3328
+ }
3329
+ }
3369
3330
  \`\`\`
3370
3331
 
3371
- # Configuring Elements / Adding Style to Elements
3372
- An element configuration can be retrieved using the "get-element-configuration-values" tool.
3373
- Updating an element requires only the UPDATED properties (including in the styles), as Elementor does a MERGE/PATCH operation.
3332
+ ### 7. Execute build_composition
3333
+ Call the tool with your XML structure, elementConfig, and stylesConfig. The response will contain the created element IDs.
3334
+ At the response you will also find llm_instructions for you to do afterwards, read and follow them!
3374
3335
 
3375
- <note>
3376
- for PropValue with array as value:
3377
- All array types that can receive union types, are typed as mixed array.
3378
- </note>
3336
+ ## Key Points
3379
3337
 
3380
- # Styling best practices
3381
- Prefer using "em" and "rem" values for text-related sizes, padding and spacing. Use percentages for dynamic sizing relative to parent containers.
3382
- This flexboxes are by default "flex" with "stretch" alignment. To ensure proper layout, define the "justify-content" and "align-items" as in the schema.
3338
+ - **PropValue Types**: Arrays that accept union types are typed as mixed arrays
3339
+ - **Visual Sizing**: Widget sizes MUST be defined in stylesConfig. Widget properties like image "size" control resolution, not visual appearance
3340
+ - **Global Variables**: Reference by ID in PropValues (e.g., \`{ "$$type": "global-color-variable", "value": "variable-id" }\`)
3341
+ - **Naming Conventions**: Use meaningful, purpose-based names (e.g., "primary-button", "heading-large"), not value-based names (e.g., "blue-style", "20px-padding")
3383
3342
 
3384
- # Examples:
3385
-
3386
- ## e-image PropValue structure:
3387
- {$$type:'image',value:{src:{$$type:'image-src',value:{url:{$$type:'url',value:'https://example.com/image.jpg'}}},size:{$$type:'string',value:'full'}}}
3388
-
3389
- Widgets' sizes MUST be defined using the style schema. Images, for example, have a "size" property, but it DOES NOT AFFECT THE VISUAL size, but rather the image size/resolution to load.
3390
-
3391
- # Working with Global Classes and Variables
3392
- - To get the list of available global classes, use the resource at uri elementor://global-classes
3393
- - To get the list of available global variables, use the resource at uri elementor://global-variables
3394
- - Before creating a global variable or class, refer to the list and see if it already exists.
3395
- - Naming conventions:
3396
- - Global classes and global variables should have meaningful names that reflect their purpose and usage.
3397
- - Avoid generic names like "style1" or "classA"; instead, use descriptive names like "primary-button" or "heading-level-1".
3398
- - Avoid names that reflect colors or values, use only purpose-based names.
3399
-
3400
- # Advanced operations
3401
- You are encouraged to run multiple times multiple tools to achieve the desired result.
3402
-
3403
- An Example scenario of creating fully styled composition:
3404
- 1. Get the list of availble widgets using dynamic resource [${WIDGET_SCHEMA_URI}]
3405
- 2. For each element to create, retreive its configuration schema from [${WIDGET_SCHEMA_URI}/element-name]
3406
- 3. Get the list of available global classes using the always up-to-date resource
3407
- 4. Get the list of available global variables using the dynamic resource
3408
- 5. Build a composition using the "build-composition" tool, providing the structure, configuration and styles for each element. You may want to style the elements later.
3409
- 6. Check you work: as you have the created IDs from the build-composition response, you can retreive each element configuration using the "get-element-configuration-values" tool.
3410
- 7. If needed, update styles using the "configure-element" tool, providing only the styles or widget's properties to update.
3343
+ ## Example: e-image PropValue Structure
3344
+ \`\`\`json
3345
+ {
3346
+ "$$type": "image",
3347
+ "value": {
3348
+ "src": {
3349
+ "$$type": "image-src",
3350
+ "value": {
3351
+ "url": { "$$type": "url", "value": "https://example.com/image.jpg" }
3352
+ }
3353
+ },
3354
+ "size": { "$$type": "string", "value": "full" }
3355
+ }
3356
+ }
3357
+ \`\`\`
3358
+ Note: The "size" property controls image resolution/loading, not visual size. Set visual dimensions in stylesConfig.
3411
3359
  `;
3412
3360
 
3413
3361
  // src/prevent-link-in-link-commands.ts
3414
- var import_editor_elements9 = require("@elementor/editor-elements");
3362
+ var import_editor_elements10 = require("@elementor/editor-elements");
3415
3363
  var import_editor_notifications = require("@elementor/editor-notifications");
3416
3364
  var import_editor_v1_adapters11 = require("@elementor/editor-v1-adapters");
3417
3365
  var import_i18n2 = require("@wordpress/i18n");
@@ -3482,13 +3430,13 @@ function shouldBlock(sourceElements, targetElements) {
3482
3430
  return false;
3483
3431
  }
3484
3432
  const isSourceContainsAnAnchor = sourceElements.some((src) => {
3485
- return src?.id ? (0, import_editor_elements9.isElementAnchored)(src.id) || !!(0, import_editor_elements9.getAnchoredDescendantId)(src.id) : false;
3433
+ return src?.id ? (0, import_editor_elements10.isElementAnchored)(src.id) || !!(0, import_editor_elements10.getAnchoredDescendantId)(src.id) : false;
3486
3434
  });
3487
3435
  if (!isSourceContainsAnAnchor) {
3488
3436
  return false;
3489
3437
  }
3490
3438
  const isTargetContainsAnAnchor = targetElements.some((target) => {
3491
- return target?.id ? (0, import_editor_elements9.isElementAnchored)(target.id) || !!(0, import_editor_elements9.getAnchoredAncestorId)(target.id) : false;
3439
+ return target?.id ? (0, import_editor_elements10.isElementAnchored)(target.id) || !!(0, import_editor_elements10.getAnchoredAncestorId)(target.id) : false;
3492
3440
  });
3493
3441
  return isTargetContainsAnAnchor;
3494
3442
  }
@@ -3497,13 +3445,13 @@ function shouldBlock(sourceElements, targetElements) {
3497
3445
  var import_editor_v1_adapters13 = require("@elementor/editor-v1-adapters");
3498
3446
 
3499
3447
  // src/style-commands/undoable-actions/paste-element-style.ts
3500
- var import_editor_elements11 = require("@elementor/editor-elements");
3448
+ var import_editor_elements12 = require("@elementor/editor-elements");
3501
3449
  var import_editor_styles_repository4 = require("@elementor/editor-styles-repository");
3502
3450
  var import_editor_v1_adapters12 = require("@elementor/editor-v1-adapters");
3503
3451
  var import_i18n4 = require("@wordpress/i18n");
3504
3452
 
3505
3453
  // src/style-commands/utils.ts
3506
- var import_editor_elements10 = require("@elementor/editor-elements");
3454
+ var import_editor_elements11 = require("@elementor/editor-elements");
3507
3455
  var import_editor_props8 = require("@elementor/editor-props");
3508
3456
  var import_i18n3 = require("@wordpress/i18n");
3509
3457
  function hasAtomicWidgets(args) {
@@ -3528,7 +3476,7 @@ function getClassesProp(container) {
3528
3476
  }
3529
3477
  function getContainerSchema(container) {
3530
3478
  const type = container?.model.get("widgetType") || container?.model.get("elType");
3531
- const widgetsCache = (0, import_editor_elements10.getWidgetsCache)();
3479
+ const widgetsCache = (0, import_editor_elements11.getWidgetsCache)();
3532
3480
  const elementType = widgetsCache?.[type];
3533
3481
  return elementType?.atomic_props_schema ?? null;
3534
3482
  }
@@ -3541,7 +3489,7 @@ function getClipboardElements(storageKey = "clipboard") {
3541
3489
  }
3542
3490
  }
3543
3491
  function getTitleForContainers(containers) {
3544
- return containers.length > 1 ? (0, import_i18n3.__)("Elements", "elementor") : (0, import_editor_elements10.getElementLabel)(containers[0].id);
3492
+ return containers.length > 1 ? (0, import_i18n3.__)("Elements", "elementor") : (0, import_editor_elements11.getElementLabel)(containers[0].id);
3545
3493
  }
3546
3494
 
3547
3495
  // src/style-commands/undoable-actions/paste-element-style.ts
@@ -3554,7 +3502,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters12.undoable)(
3554
3502
  if (!classesProp) {
3555
3503
  return null;
3556
3504
  }
3557
- const originalStyles = (0, import_editor_elements11.getElementStyles)(container.id);
3505
+ const originalStyles = (0, import_editor_elements12.getElementStyles)(container.id);
3558
3506
  const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
3559
3507
  const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
3560
3508
  const revertData = {
@@ -3563,7 +3511,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters12.undoable)(
3563
3511
  };
3564
3512
  if (styleId) {
3565
3513
  newStyle.variants.forEach(({ meta, props, custom_css: customCss }) => {
3566
- (0, import_editor_elements11.updateElementStyle)({
3514
+ (0, import_editor_elements12.updateElementStyle)({
3567
3515
  elementId,
3568
3516
  styleId,
3569
3517
  meta,
@@ -3574,7 +3522,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters12.undoable)(
3574
3522
  } else {
3575
3523
  const [firstVariant] = newStyle.variants;
3576
3524
  const additionalVariants = newStyle.variants.slice(1);
3577
- revertData.styleId = (0, import_editor_elements11.createElementStyle)({
3525
+ revertData.styleId = (0, import_editor_elements12.createElementStyle)({
3578
3526
  elementId,
3579
3527
  classesProp,
3580
3528
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -3592,7 +3540,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters12.undoable)(
3592
3540
  return;
3593
3541
  }
3594
3542
  if (!revertData.originalStyle) {
3595
- (0, import_editor_elements11.deleteElementStyle)(container.id, revertData.styleId);
3543
+ (0, import_editor_elements12.deleteElementStyle)(container.id, revertData.styleId);
3596
3544
  return;
3597
3545
  }
3598
3546
  const classesProp = getClassesProp(container);
@@ -3601,7 +3549,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters12.undoable)(
3601
3549
  }
3602
3550
  const [firstVariant] = revertData.originalStyle.variants;
3603
3551
  const additionalVariants = revertData.originalStyle.variants.slice(1);
3604
- (0, import_editor_elements11.createElementStyle)({
3552
+ (0, import_editor_elements12.createElementStyle)({
3605
3553
  elementId: container.id,
3606
3554
  classesProp,
3607
3555
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -3653,7 +3601,7 @@ function pasteStyles(args, pasteCallback) {
3653
3601
  var import_editor_v1_adapters15 = require("@elementor/editor-v1-adapters");
3654
3602
 
3655
3603
  // src/style-commands/undoable-actions/reset-element-style.ts
3656
- var import_editor_elements12 = require("@elementor/editor-elements");
3604
+ var import_editor_elements13 = require("@elementor/editor-elements");
3657
3605
  var import_editor_styles_repository5 = require("@elementor/editor-styles-repository");
3658
3606
  var import_editor_v1_adapters14 = require("@elementor/editor-v1-adapters");
3659
3607
  var import_i18n5 = require("@wordpress/i18n");
@@ -3662,9 +3610,9 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters14.undoable)(
3662
3610
  do: ({ containers }) => {
3663
3611
  return containers.map((container) => {
3664
3612
  const elementId = container.model.get("id");
3665
- const containerStyles = (0, import_editor_elements12.getElementStyles)(elementId);
3613
+ const containerStyles = (0, import_editor_elements13.getElementStyles)(elementId);
3666
3614
  Object.keys(containerStyles ?? {}).forEach(
3667
- (styleId) => (0, import_editor_elements12.deleteElementStyle)(elementId, styleId)
3615
+ (styleId) => (0, import_editor_elements13.deleteElementStyle)(elementId, styleId)
3668
3616
  );
3669
3617
  return containerStyles;
3670
3618
  });
@@ -3680,7 +3628,7 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters14.undoable)(
3680
3628
  Object.entries(containerStyles ?? {}).forEach(([styleId, style]) => {
3681
3629
  const [firstVariant] = style.variants;
3682
3630
  const additionalVariants = style.variants.slice(1);
3683
- (0, import_editor_elements12.createElementStyle)({
3631
+ (0, import_editor_elements13.createElementStyle)({
3684
3632
  elementId,
3685
3633
  classesProp,
3686
3634
  styleId,