@elementor/editor-canvas 4.0.0-621 → 4.0.0-manual

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.mjs CHANGED
@@ -59,7 +59,13 @@ Prefer using "em" and "rem" values for text-related sizes, padding and spacing.
59
59
  This flexboxes are by default "flex" with "stretch" alignment. To ensure proper layout, define the "justify-content" and "align-items" as in the schema.
60
60
 
61
61
  When applicable for styles, apply style PropValues using the ${STYLE_SCHEMA_URI}.
62
- The css string must follow standard CSS syntax, with properties and values separated by semicolons, no selectors, or nesting rules allowed.`
62
+ The css string must follow standard CSS syntax, with properties and values separated by semicolons, no selectors, or nesting rules allowed.
63
+
64
+ ** CRITICAL - VARIABLES **
65
+ When using global variables, ensure that the variables are defined in the ${"elementor://global-variables"} resource.
66
+ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
67
+
68
+ `
63
69
  }
64
70
  ]
65
71
  };
@@ -3197,6 +3203,7 @@ var validateInput = {
3197
3203
  var CompositionBuilder = class _CompositionBuilder {
3198
3204
  elementConfig = {};
3199
3205
  elementStylesConfig = {};
3206
+ elementCusomCSS = {};
3200
3207
  rootContainers = [];
3201
3208
  containerElements = [];
3202
3209
  api = {
@@ -3220,11 +3227,12 @@ var CompositionBuilder = class _CompositionBuilder {
3220
3227
  });
3221
3228
  }
3222
3229
  constructor(opts) {
3223
- const { api = {}, elementConfig = {}, stylesConfig = {}, xml } = opts;
3230
+ const { api = {}, elementConfig = {}, stylesConfig = {}, customCSS = {}, xml } = opts;
3224
3231
  this.xml = xml;
3225
3232
  Object.assign(this.api, api);
3226
3233
  this.setElementConfig(elementConfig);
3227
3234
  this.setStylesConfig(stylesConfig);
3235
+ this.setCustomCSS(customCSS);
3228
3236
  }
3229
3237
  setElementConfig(config) {
3230
3238
  this.elementConfig = config;
@@ -3232,6 +3240,9 @@ var CompositionBuilder = class _CompositionBuilder {
3232
3240
  setStylesConfig(config) {
3233
3241
  this.elementStylesConfig = config;
3234
3242
  }
3243
+ setCustomCSS(config) {
3244
+ this.elementCusomCSS = config;
3245
+ }
3235
3246
  getXML() {
3236
3247
  return this.xml;
3237
3248
  }
@@ -3247,7 +3258,10 @@ var CompositionBuilder = class _CompositionBuilder {
3247
3258
  container: targetContainer,
3248
3259
  model: {
3249
3260
  elType: elementTag,
3250
- id: generateElementId()
3261
+ id: generateElementId(),
3262
+ editor_settings: {
3263
+ title: node.getAttribute("configuration-id") ?? void 0
3264
+ }
3251
3265
  },
3252
3266
  options: { useHistory: false }
3253
3267
  }) : this.api.createElement({
@@ -3255,7 +3269,10 @@ var CompositionBuilder = class _CompositionBuilder {
3255
3269
  model: {
3256
3270
  elType: "widget",
3257
3271
  widgetType: elementTag,
3258
- id: generateElementId()
3272
+ id: generateElementId(),
3273
+ editor_settings: {
3274
+ title: node.getAttribute("configuration-id") ?? void 0
3275
+ }
3259
3276
  },
3260
3277
  options: { useHistory: false }
3261
3278
  });
@@ -3296,9 +3313,9 @@ var CompositionBuilder = class _CompositionBuilder {
3296
3313
  applyStyles() {
3297
3314
  const errors = [];
3298
3315
  const invalidStyles = {};
3299
- const validStylesPropValues = {};
3300
3316
  for (const [styleId, styleConfig] of Object.entries(this.elementStylesConfig)) {
3301
3317
  const { element, node } = this.matchNodeByConfigId(styleId);
3318
+ const validStylesPropValues = {};
3302
3319
  for (const [styleName, stylePropValue] of Object.entries(styleConfig)) {
3303
3320
  const { valid, errors: validationErrors } = validateInput.validateStyles({
3304
3321
  [styleName]: stylePropValue
@@ -3312,14 +3329,30 @@ var CompositionBuilder = class _CompositionBuilder {
3312
3329
  } else {
3313
3330
  validStylesPropValues[styleName] = stylePropValue;
3314
3331
  }
3332
+ }
3333
+ if (Object.keys(validStylesPropValues).length === 0) {
3334
+ continue;
3335
+ }
3336
+ try {
3315
3337
  this.api.doUpdateElementProperty({
3316
3338
  elementId: element.id,
3317
3339
  propertyName: "_styles",
3318
3340
  propertyValue: validStylesPropValues,
3319
3341
  elementType: node.tagName
3320
3342
  });
3343
+ } catch (error) {
3344
+ errors.push(String(error));
3321
3345
  }
3322
3346
  }
3347
+ for (const [customCSSId, customCSS] of Object.entries(this.elementCusomCSS)) {
3348
+ const { element, node } = this.matchNodeByConfigId(customCSSId);
3349
+ this.api.doUpdateElementProperty({
3350
+ elementId: element.id,
3351
+ propertyName: "_styles",
3352
+ propertyValue: { custom_css: customCSS },
3353
+ elementType: node.tagName
3354
+ });
3355
+ }
3323
3356
  return {
3324
3357
  errors,
3325
3358
  invalidStyles
@@ -3381,162 +3414,141 @@ import { toolPrompts } from "@elementor/editor-mcp";
3381
3414
  var generatePrompt = () => {
3382
3415
  const buildCompositionsToolPrompt = toolPrompts("build-compositions");
3383
3416
  buildCompositionsToolPrompt.description(`
3384
- # REQUIRED RESOURCES (Read before use)
3385
- 1. [${WIDGET_SCHEMA_URI}] - Widget types, configuration schemas, and PropType definitions
3386
- 2. [${STYLE_SCHEMA_URI}] - Common styles schema shared by all widgets
3387
- 3. [elementor://global-classes] - Existing global classes (check FIRST to reuse)
3388
-
3389
- # THREE-PHASE WORKFLOW (MANDATORY)
3390
-
3391
- ## Phase 1: Create Global Classes
3392
- 1. Analyze requirements \u2192 identify reusable patterns (typography, colors, spacing)
3393
- 2. Check [elementor://global-classes] for existing classes
3394
- 3. Use "create-global-class" tool for NEW reusable styles BEFORE building
3395
-
3396
- ## Phase 2: Build Composition (THIS TOOL)
3397
- 4. Build valid XML with minimal inline styles (layout/positioning only)
3398
- 5. Avoid duplicating styles that should be global classes
3399
-
3400
- ## Phase 3: Apply Classes
3401
- 6. Use "apply-global-class" tool to apply global classes to elements
3402
-
3403
- # CORE INSTRUCTIONS
3404
-
3405
- **Structure:**
3406
- - Build valid XML using allowed widget tags (e.g., \`<e-button configuration-id="btn1"></e-button>\`)
3407
- - Containers only: "e-flexbox", "e-div-block", "e-tabs"
3408
- - Every element MUST have unique "configuration-id" attribute
3417
+ # RESOURCES (Read before use)
3418
+ - [elementor://global-classes] - Check FIRST for reusable classes
3419
+ - [elementor://global-variables] - ONLY use variables defined here
3420
+
3421
+ # WORKFLOW
3422
+ 1. Check/create global classes via "create-global-class" tool
3423
+ 2. Build composition (THIS TOOL) - minimal inline styles
3424
+ 3. Apply classes via "apply-global-class" tool
3425
+
3426
+ # XML STRUCTURE
3427
+ - Use widget tags: \`<e-button configuration-id="btn1"></e-button>\`
3428
+ - Containers: "e-flexbox", "e-div-block", "e-tabs"
3429
+ - Every element needs unique "configuration-id"
3409
3430
  - No attributes, classes, IDs, or text nodes in XML
3410
3431
 
3411
- **Configuration:**
3412
- - Map each configuration-id to elementConfig (widget props) and stylesConfig (styles)
3413
- - Follow exact PropType schemas from resources above
3414
- - All PropValues need \`$$type\` property matching schema
3415
- - Keep stylesConfig MINIMAL - layout only, NOT reusable styles
3416
-
3417
- **Validation:**
3418
- - Parse XML before submission
3419
- - Match all PropValues to schema (\`$$type\` required)
3420
- - NO LINKS in any configuration
3421
- - Retry on errors up to 10x, reading error messages carefully
3422
-
3423
- # DESIGN QUALITY: AVOID AI SLOP
3424
-
3425
- **Problem:** LLMs default to generic patterns (purple gradients, #333 grays, 24px headings, uniform spacing)
3426
- **Solution:** Make intentional, distinctive choices. When unsure, choose bold over safe.
3427
-
3428
- ## Typography Rules
3429
- \u274C AVOID: Inter/Roboto/Arial, small ratios (1.5x), medium weights (500-700)
3430
- \u2705 USE: 3x+ size ratios, extreme weight contrasts (100/200 vs 800/900), tight headlines (1.1 line-height)
3431
-
3432
- ## Color Rules
3433
- \u274C AVOID: Purple gradients, pure grays (#333/#666/#999), even distribution
3434
- \u2705 USE: ONE dominant color (60-70%), 1-2 accent colors (10-15%), tinted neutrals (warm/cool grays)
3435
-
3436
- ## Spacing Rules
3437
- \u274C AVOID: Uniform spacing (all 16px/24px), cramped layouts, centered everything
3438
- \u2705 USE: Generous spacing (80-120px sections), dramatic variation (12px/48px/96px), asymmetric layouts
3439
-
3440
- ## Background Rules
3441
- \u274C AVOID: Solid white/gray, single colors
3442
- \u2705 USE: Layered gradients (2-3 layers), subtle patterns, alternating light/dark sections
3443
-
3444
- ## Visual Hierarchy
3445
- 1. **Primary** (1 element): Largest, highest contrast, most space
3446
- 2. **Secondary** (2-3 elements): 40-60% of primary size
3447
- 3. **Tertiary** (rest): Minimal weight, muted
3448
-
3449
- **Contrast techniques:** 3x size differences, 300+ weight differences, color hierarchy (brand \u2192 neutral \u2192 muted)
3450
-
3451
- # DESIGN CONSTRAINTS (NEVER VIOLATE)
3452
-
3453
- **Typography:**
3454
- - NEVER use Inter, Roboto, Arial, Helvetica as primary display fonts
3455
- - NEVER use font-size ratios < 2.5x between headlines and body
3456
- - NEVER use font-weight 500-700 for headlines (go lighter or heavier)
3457
-
3458
- **Color:**
3459
- - PREFER not to use pure grays - use tinted neutrals (#2d2622, #faf8f6, not #333/#f5f5f5)
3460
- - NEVER distribute colors evenly - commit to ONE dominant
3461
- - NEVER use more than 3 core colors - except for info/alert/badges
3462
-
3463
- **Spacing:**
3464
- - NEVER use uniform spacing
3465
- - NEVER use < 4rem (64px) padding for major sections
3466
- - NEVER center everything
3467
- - PRIORITIZE rem based values over pixel based
3468
-
3469
- **Background:**
3470
- - NEVER use solid #ffffff or #f5f5f5 without texture/gradients
3471
- - ALWAYS layer 2+ gradient/color elements
3472
-
3473
- # WIDGET NOTES
3474
- - Check \`llm_guidance\` property in widget schemas for context
3475
- - Avoid SVG widgets (require content upload tools) - when must, prior to execution ensure assets uploaded
3476
- - Apply style schema to containers for layout control
3477
-
3478
- # PARAMETERS (ALL MANDATORY)
3432
+ # CONFIGURATION
3433
+ - Map configuration-id \u2192 elementConfig (props) + stylesConfig (layout only)
3434
+ - All PropValues require \`$$type\` matching schema
3435
+ - NO LINKS in configuration
3436
+ - Retry on errors up to 10x
3437
+
3438
+ Note about configuration ids: These names are visible to the end-user, make sure they make sense, related and relevant.
3439
+
3440
+ # DESIGN PHILOSOPHY: CONTEXT-DRIVEN CREATIVITY
3441
+
3442
+ **Use the user's context aggressively.** Business type, brand personality, target audience, and purpose should drive every design decision. A law firm needs gravitas; a children's app needs playfulness. Don't default to generic.
3443
+
3444
+ ## SIZING: DEFAULT IS NO SIZE (CRITICAL)
3445
+
3446
+ **DO NOT specify height or width unless you have a specific visual reason.**
3447
+
3448
+ Flexbox and CSS already handle sizing automatically:
3449
+ - Containers grow to fit their content
3450
+ - Flex children distribute space via flex properties, not width/height
3451
+ - Text elements size to their content
3452
+
3453
+ WHEN TO SPECIFY SIZE:
3454
+ - min-height on ROOT section for viewport-spanning hero (use min-height, NOT height)
3455
+ - max-width for contained content areas (e.g., max-width: 60rem)
3456
+ - Explicit aspect ratios for media containers
3457
+
3458
+ NEVER SPECIFY:
3459
+ - height on nested containers (causes overflow)
3460
+ - width on flex children (use flex-basis or gap instead)
3461
+ - 100vh on anything except root-level sections
3462
+ - Any size "just to be safe" - if unsure, OMIT IT
3463
+
3464
+ vh units are VIEWPORT-relative. Nested 100vh inside 100vh = 200vh overflow.
3465
+
3466
+ GOOD: \`<e-flexbox>content naturally sizes</e-flexbox>\`
3467
+ BAD: \`<e-flexbox style="height:100vh"><e-div-block style="height:100vh">overflow</e-div-block></e-flexbox>\`
3468
+
3469
+ ## Layout Variety (Break the Template)
3470
+ - AVOID: Full-width 100vh hero \u2192 three columns \u2192 testimonials \u2192 CTA (every AI does this)
3471
+ - VARY heights: Use auto-height sections with generous padding (6rem+). Let content breathe
3472
+ - VARY widths: Not everything spans full width. Use contained sections (max-width: 960px) mixed with edge-to-edge
3473
+ - ASYMMETRIC grids: 2:1, 1:3, offset layouts. Avoid equal column widths
3474
+ - Negative space as design element: Large margins create focus and sophistication
3475
+ - Break alignment intentionally: Offset headings, overlapping elements, broken grids
3476
+
3477
+ ## Visual Depth & Effects
3478
+ - Layer elements: Overlapping cards, text over images, floating elements
3479
+ - Subtle shadows with color tint (not pure black): \`box-shadow: 0 20px 60px rgba(<brand-color-here>, 0.15)\`
3480
+ - Gradient overlays on images for text readability
3481
+ - Border radius variation: Mix sharp (0) and soft (1rem+) corners purposefully
3482
+ - Backdrop blur for glassmorphism where appropriate
3483
+ - Micro-interactions via CSS: hover transforms, transitions (0.3s ease)
3484
+
3485
+ ## Typography with Character
3486
+ - Display fonts for headlines (from user's brand or contextually appropriate)
3487
+ - Size contrast: 4rem+ headlines vs 1rem body. Make hierarchy unmistakable
3488
+ - Letter-spacing: Tight for large headlines (-0.02em), loose for small caps (0.1em)
3489
+ - Line-height: Tight for headlines (1.1), generous for body (1.6-1.8)
3490
+ - Text decoration: Underlines, highlights, gradient text for emphasis
3491
+
3492
+ ## Color with Purpose
3493
+ - Extract palette from user context (brand colors, industry norms, mood)
3494
+ - 60-30-10 rule: dominant, secondary, accent
3495
+ - Tinted neutrals over pure grays: warm (#faf8f5, #2d2a26) or cool (#f5f7fa, #1e2430)
3496
+ - Color blocking: Large colored sections create visual rhythm
3497
+ - Gradient directions: Diagonal (135deg, 225deg) feel more dynamic than vertical
3498
+
3499
+ ## Spacing Strategy
3500
+ - Section padding: 6rem-10rem vertical, creating breathing room
3501
+ - Rhythm variation: Tight groups (2rem) with generous gaps between (6rem)
3502
+ - Use rem/em exclusively for responsive scaling
3503
+ - Generous padding on CTAs: min 1rem 2.5rem
3504
+
3505
+ # HARD CONSTRAINTS
3506
+ - Variables ONLY from [elementor://global-variables] (others throw errors)
3507
+ - Avoid SVG widgets unless assets are pre-uploaded
3508
+ - Check \`llm_guidance\` in widget schemas
3509
+
3510
+ # PARAMETERS
3479
3511
  - **xmlStructure**: Valid XML with configuration-id attributes
3480
- - **elementConfig**: Record of configuration-id \u2192 widget PropValues
3481
- - **stylesConfig**: Record of configuration-id \u2192 style PropValues (layout only)
3512
+ - **elementConfig**: configuration-id \u2192 widget PropValues
3513
+ - **stylesConfig**: configuration-id \u2192 style PropValues (layout only)
3514
+ - **customCSS**: configuration-id \u2192 CSS rules (no selectors, semicolon-separated)
3482
3515
  `);
3483
3516
  buildCompositionsToolPrompt.example(`
3484
- A Heading and a button inside a flexbox
3517
+ Section with heading + button (NO explicit heights - content sizes naturally):
3485
3518
  {
3486
- xmlStructure: "<e-flexbox configuration-id="flex1"><e-heading configuration-id="heading1"></e-heading><e-button configuration-id="button1"></e-button></e-flexbox>"
3519
+ xmlStructure: "<e-flexbox configuration-id="Main Section"><e-heading configuration-id="Section Title"></e-heading><e-button configuration-id="Call to Action"></e-button></e-flexbox>",
3487
3520
  elementConfig: {
3488
- "flex1": {
3489
- "tag": {
3490
- "$$type": "string",
3491
- "value": "section"
3492
- },
3521
+ "section1": { "tag": { "$$type": "string", "value": "section" } }
3522
+ },
3523
+ customCSS: {
3524
+ "Section Title": "padding: 6rem 4rem; background: linear-gradient(135deg, #faf8f5 0%, #f0ebe4 100%);"
3493
3525
  },
3494
3526
  stylesConfig: {
3495
- "heading1": {
3496
- "font-size": {
3497
- "$$type": "size",
3498
- "value": {
3499
- "size": { "$$type": "number", "value": 24 },
3500
- "unit": { "$$type": "string", "value": "px" }
3501
- }
3502
- },
3503
- "color": {
3504
- "$$type": "color",
3505
- "value": { "$$type": "string", "value": "#333" }
3506
- }
3527
+ "Section Title": {
3528
+ "font-size": { "$$type": "size", "value": { "size": { "$$type": "number", "value": 3.5 }, "unit": { "$$type": "string", "value": "rem" } } },
3529
+ "color": { "$$type": "color", "value": { "$$type": "string", "value": "#2d2a26" } }
3507
3530
  }
3508
- },
3531
+ }
3509
3532
  }
3533
+ Note: No height/width specified on any element - flexbox handles layout automatically.
3510
3534
  `);
3511
3535
  buildCompositionsToolPrompt.parameter(
3512
3536
  "xmlStructure",
3513
- `**MANDATORY** A valid XML structure representing the composition to be built, using custom elementor tags, styling and configuration PropValues.`
3514
- );
3515
- buildCompositionsToolPrompt.parameter(
3516
- "elementConfig",
3517
- `**MANDATORY** A record mapping configuration IDs to their corresponding configuration objects, defining the PropValues for each element created.`
3537
+ `Valid XML structure with custom elementor tags and configuration-id attributes.`
3518
3538
  );
3539
+ buildCompositionsToolPrompt.parameter("elementConfig", `Record mapping configuration IDs to widget PropValues.`);
3519
3540
  buildCompositionsToolPrompt.parameter(
3520
3541
  "stylesConfig",
3521
- `**MANDATORY** A record mapping style PropTypes to their corresponding style configuration objects, defining the PropValues for styles to be applied to elements.`
3522
- );
3523
- buildCompositionsToolPrompt.instruction(
3524
- `You will be provided the XML structure with element IDs. These IDs represent the actual elementor widgets created on the page/post.
3525
- You should use these IDs as reference for further configuration, styling or changing elements later on.`
3542
+ `Record mapping configuration IDs to style PropValues (layout/positioning only).`
3526
3543
  );
3527
3544
  buildCompositionsToolPrompt.instruction(
3528
- `**CRITICAL WORKFLOW REMINDER**:
3529
- 1. FIRST: Create reusable global classes for typography, colors, spacing patterns using "create-global-class" tool
3530
- 2. SECOND: Use THIS tool with minimal inline styles (only layout & unique properties)
3531
- 3. THIRD: Apply global classes to elements using "apply-global-class" tool
3532
-
3533
- This ensures maximum reusability and consistency across your design system. ALWAYS check [elementor://global-classes] for existing classes before creating new ones.`
3545
+ `Element IDs in the returned XML represent actual widgets. Use these IDs for subsequent styling or configuration changes.`
3534
3546
  );
3535
3547
  return buildCompositionsToolPrompt.prompt();
3536
3548
  };
3537
3549
 
3538
3550
  // src/mcp/tools/build-composition/schema.ts
3539
- import { z } from "@elementor/schema";
3551
+ import { zod as z } from "@elementor/editor-mcp";
3540
3552
  var inputSchema = {
3541
3553
  xmlStructure: z.string().describe("The XML structure representing the composition to be built"),
3542
3554
  elementConfig: z.record(
@@ -3554,7 +3566,11 @@ var inputSchema = {
3554
3566
  )
3555
3567
  ).describe(
3556
3568
  `A record mapping element IDs to their styles configuration objects. Use the actual styles schema from [${STYLE_SCHEMA_URI}].`
3557
- ).default({})
3569
+ ).default({}),
3570
+ customCSS: z.record(
3571
+ z.string().describe("The configuration id"),
3572
+ z.string().describe("The custom CSS for the element. MANDATORY")
3573
+ ).describe("A record mapping element IDs to their custom CSS.").default({})
3558
3574
  };
3559
3575
  var outputSchema = {
3560
3576
  errors: z.string().describe("Error message if the composition building failed").optional(),
@@ -3583,7 +3599,7 @@ var initBuildCompositionsTool = (reg) => {
3583
3599
  hints: [{ name: "claude-sonnet-4-5" }]
3584
3600
  },
3585
3601
  handler: async (params) => {
3586
- const { xmlStructure, elementConfig, stylesConfig } = params;
3602
+ const { xmlStructure, elementConfig, stylesConfig, customCSS } = params;
3587
3603
  let generatedXML = "";
3588
3604
  const errors = [];
3589
3605
  const rootContainers = [];
@@ -3595,17 +3611,18 @@ var initBuildCompositionsTool = (reg) => {
3595
3611
  });
3596
3612
  compositionBuilder.setElementConfig(elementConfig);
3597
3613
  compositionBuilder.setStylesConfig(stylesConfig);
3614
+ compositionBuilder.setCustomCSS(customCSS);
3598
3615
  const {
3599
3616
  configErrors,
3600
3617
  invalidStyles,
3601
3618
  rootContainers: generatedRootContainers
3602
3619
  } = compositionBuilder.build(documentContainer);
3620
+ rootContainers.push(...generatedRootContainers);
3603
3621
  generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
3604
3622
  if (configErrors.length) {
3605
3623
  errors.push(...configErrors.map((e) => new Error(e)));
3606
3624
  throw new Error("Configuration errors occurred during composition building.");
3607
3625
  }
3608
- rootContainers.push(...generatedRootContainers);
3609
3626
  Object.entries(invalidStyles).forEach(([elementId, rawCssRules]) => {
3610
3627
  const customCss = {
3611
3628
  value: rawCssRules.join(";\n")
@@ -3654,10 +3671,7 @@ var initBuildCompositionsTool = (reg) => {
3654
3671
 
3655
3672
  ${errorMessages.join(
3656
3673
  "\n\n"
3657
- )}
3658
-
3659
- "Missing $$type" errors indicate that the configuration objects are invalid. Try again and apply **ALL** object entries with correct $$type.
3660
- Now that you have these errors, fix them and try again. Errors regarding configuration objects, please check against the PropType schemas`;
3674
+ )}`;
3661
3675
  throw new Error(errorText);
3662
3676
  }
3663
3677
  return {
@@ -3986,7 +4000,14 @@ var initGetElementConfigTool = (reg) => {
3986
4000
  var initCanvasMcp = (reg) => {
3987
4001
  const { setMCPDescription } = reg;
3988
4002
  setMCPDescription(
3989
- 'Everything related to creative design, layout, styling and building the pages, specifically element of type "widget"'
4003
+ `Everything related to creative design, layout, styling and building the pages, specifically element of type "widget".
4004
+ # Canvas workflow for new compositions
4005
+ - Check existing global variables
4006
+ - Check existing global classes
4007
+ - Create missing global variables
4008
+ - Create reusable global classes
4009
+ - Build valid XML with minimal inline styles (layout/positioning only)
4010
+ - Apply global classes to elements`
3990
4011
  );
3991
4012
  initWidgetsSchemaResource(reg);
3992
4013
  initDocumentStructureResource(reg);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.0.0-621",
4
+ "version": "4.0.0-manual",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,24 +37,24 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.0.0-621",
41
- "@elementor/editor-controls": "4.0.0-621",
42
- "@elementor/editor-documents": "4.0.0-621",
43
- "@elementor/editor-elements": "4.0.0-621",
44
- "@elementor/editor-interactions": "4.0.0-621",
45
- "@elementor/editor-mcp": "4.0.0-621",
46
- "@elementor/editor-notifications": "4.0.0-621",
47
- "@elementor/editor-props": "4.0.0-621",
48
- "@elementor/editor-responsive": "4.0.0-621",
49
- "@elementor/editor-styles": "4.0.0-621",
50
- "@elementor/editor-styles-repository": "4.0.0-621",
51
- "@elementor/editor-ui": "4.0.0-621",
52
- "@elementor/editor-v1-adapters": "4.0.0-621",
53
- "@elementor/schema": "4.0.0-621",
54
- "@elementor/twing": "4.0.0-621",
40
+ "@elementor/editor": "4.0.0-manual",
41
+ "@elementor/editor-controls": "4.0.0-manual",
42
+ "@elementor/editor-documents": "4.0.0-manual",
43
+ "@elementor/editor-elements": "4.0.0-manual",
44
+ "@elementor/editor-interactions": "4.0.0-manual",
45
+ "@elementor/editor-mcp": "4.0.0-manual",
46
+ "@elementor/editor-notifications": "4.0.0-manual",
47
+ "@elementor/editor-props": "4.0.0-manual",
48
+ "@elementor/editor-responsive": "4.0.0-manual",
49
+ "@elementor/editor-styles": "4.0.0-manual",
50
+ "@elementor/editor-styles-repository": "4.0.0-manual",
51
+ "@elementor/editor-ui": "4.0.0-manual",
52
+ "@elementor/editor-v1-adapters": "4.0.0-manual",
53
+ "@elementor/schema": "4.0.0-manual",
54
+ "@elementor/twing": "4.0.0-manual",
55
55
  "@elementor/ui": "1.36.17",
56
- "@elementor/utils": "4.0.0-621",
57
- "@elementor/wp-media": "4.0.0-621",
56
+ "@elementor/utils": "4.0.0-manual",
57
+ "@elementor/wp-media": "4.0.0-manual",
58
58
  "@floating-ui/react": "^0.27.5",
59
59
  "@wordpress/i18n": "^5.13.0"
60
60
  },
@@ -26,11 +26,13 @@ type CtorOptions = {
26
26
  api?: Partial< API >;
27
27
  elementConfig?: AnyConfig;
28
28
  stylesConfig?: AnyConfig;
29
+ customCSS?: Record< string, string >;
29
30
  };
30
31
 
31
32
  export class CompositionBuilder {
32
33
  private elementConfig: Record< string, Record< string, AnyValue > > = {};
33
34
  private elementStylesConfig: Record< string, Record< string, AnyValue > > = {};
35
+ private elementCusomCSS: Record< string, string > = {};
34
36
  private rootContainers: V1Element[] = [];
35
37
  private containerElements: string[] = [];
36
38
  private api: API = {
@@ -56,11 +58,12 @@ export class CompositionBuilder {
56
58
  }
57
59
 
58
60
  constructor( opts: CtorOptions ) {
59
- const { api = {}, elementConfig = {}, stylesConfig = {}, xml } = opts;
61
+ const { api = {}, elementConfig = {}, stylesConfig = {}, customCSS = {}, xml } = opts;
60
62
  this.xml = xml;
61
63
  Object.assign( this.api, api );
62
64
  this.setElementConfig( elementConfig );
63
65
  this.setStylesConfig( stylesConfig );
66
+ this.setCustomCSS( customCSS );
64
67
  }
65
68
 
66
69
  setElementConfig( config: Record< string, Record< string, AnyValue > > ) {
@@ -71,6 +74,10 @@ export class CompositionBuilder {
71
74
  this.elementStylesConfig = config;
72
75
  }
73
76
 
77
+ setCustomCSS( config: Record< string, string > ) {
78
+ this.elementCusomCSS = config;
79
+ }
80
+
74
81
  getXML() {
75
82
  return this.xml;
76
83
  }
@@ -92,6 +99,9 @@ export class CompositionBuilder {
92
99
  model: {
93
100
  elType: elementTag,
94
101
  id: generateElementId(),
102
+ editor_settings: {
103
+ title: node.getAttribute( 'configuration-id' ) ?? undefined,
104
+ },
95
105
  },
96
106
  options: { useHistory: false },
97
107
  } )
@@ -101,6 +111,9 @@ export class CompositionBuilder {
101
111
  elType: 'widget',
102
112
  widgetType: elementTag,
103
113
  id: generateElementId(),
114
+ editor_settings: {
115
+ title: node.getAttribute( 'configuration-id' ) ?? undefined,
116
+ },
104
117
  },
105
118
  options: { useHistory: false },
106
119
  } );
@@ -144,9 +157,9 @@ export class CompositionBuilder {
144
157
  applyStyles() {
145
158
  const errors: string[] = [];
146
159
  const invalidStyles: Record< string, string[] > = {};
147
- const validStylesPropValues: Record< string, AnyValue > = {};
148
160
  for ( const [ styleId, styleConfig ] of Object.entries( this.elementStylesConfig ) ) {
149
161
  const { element, node } = this.matchNodeByConfigId( styleId );
162
+ const validStylesPropValues: Record< string, AnyValue > = {};
150
163
  for ( const [ styleName, stylePropValue ] of Object.entries( styleConfig ) ) {
151
164
  const { valid, errors: validationErrors } = validateInput.validateStyles( {
152
165
  [ styleName ]: stylePropValue,
@@ -160,14 +173,30 @@ export class CompositionBuilder {
160
173
  } else {
161
174
  validStylesPropValues[ styleName ] = stylePropValue;
162
175
  }
176
+ }
177
+ if ( Object.keys( validStylesPropValues ).length === 0 ) {
178
+ continue;
179
+ }
180
+ try {
163
181
  this.api.doUpdateElementProperty( {
164
182
  elementId: element.id,
165
183
  propertyName: '_styles',
166
184
  propertyValue: validStylesPropValues,
167
185
  elementType: node.tagName,
168
186
  } );
187
+ } catch ( error ) {
188
+ errors.push( String( error ) );
169
189
  }
170
190
  }
191
+ for ( const [ customCSSId, customCSS ] of Object.entries( this.elementCusomCSS ) ) {
192
+ const { element, node } = this.matchNodeByConfigId( customCSSId );
193
+ this.api.doUpdateElementProperty( {
194
+ elementId: element.id,
195
+ propertyName: '_styles',
196
+ propertyValue: { custom_css: customCSS },
197
+ elementType: node.tagName,
198
+ } );
199
+ }
171
200
  return {
172
201
  errors,
173
202
  invalidStyles,
@@ -10,7 +10,14 @@ import { initGetElementConfigTool } from './tools/get-element-config/tool';
10
10
  export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
11
11
  const { setMCPDescription } = reg;
12
12
  setMCPDescription(
13
- 'Everything related to creative design, layout, styling and building the pages, specifically element of type "widget"'
13
+ `Everything related to creative design, layout, styling and building the pages, specifically element of type "widget".
14
+ # Canvas workflow for new compositions
15
+ - Check existing global variables
16
+ - Check existing global classes
17
+ - Create missing global variables
18
+ - Create reusable global classes
19
+ - Build valid XML with minimal inline styles (layout/positioning only)
20
+ - Apply global classes to elements`
14
21
  );
15
22
  initWidgetsSchemaResource( reg );
16
23
  initDocumentStructureResource( reg );