@elementor/editor-canvas 3.35.0-470 → 3.35.0-472
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 +459 -511
- package/dist/index.mjs +448 -496
- package/package.json +18 -18
- package/src/composition-builder/composition-builder.ts +233 -0
- package/src/mcp/mcp-description.ts +99 -108
- package/src/mcp/resources/widgets-schema-resource.ts +1 -1
- package/src/mcp/tools/build-composition/prompt.ts +104 -280
- package/src/mcp/tools/build-composition/schema.ts +0 -1
- package/src/mcp/tools/build-composition/tool.ts +49 -125
- package/src/mcp/utils/do-update-element-property.ts +12 -3
- package/src/mcp/utils/validate-input.ts +9 -2
|
@@ -6,285 +6,104 @@ export const generatePrompt = () => {
|
|
|
6
6
|
const buildCompositionsToolPrompt = toolPrompts( 'build-compositions' );
|
|
7
7
|
|
|
8
8
|
buildCompositionsToolPrompt.description( `
|
|
9
|
-
#
|
|
10
|
-
1. [${ WIDGET_SCHEMA_URI }]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
**Implementation:**
|
|
109
|
-
/* Intentional color system example */
|
|
110
|
-
--brand-primary: #d84315; /* Dominant: Deep orange */
|
|
111
|
-
--brand-accent: #00bfa5; /* Accent: Teal (complementary) */
|
|
112
|
-
--neutral-dark: #2d2622; /* Warm dark brown, not #333 */
|
|
113
|
-
--neutral-light: #faf8f6; /* Warm off-white, not pure white */
|
|
114
|
-
--background: linear-gradient(135deg, #faf8f6 0%, #f0ebe6 100%); /* Subtle warmth */
|
|
115
|
-
|
|
116
|
-
## 3. Spatial Design & White Space
|
|
117
|
-
|
|
118
|
-
**Avoid Distributional Defaults:**
|
|
119
|
-
- NO uniform spacing (everything 16px or 24px)
|
|
120
|
-
- NO cramped layouts that maximize content density
|
|
121
|
-
- NO default container widths (1200px, 1440px)
|
|
122
|
-
|
|
123
|
-
**Intentional Alternatives:**
|
|
124
|
-
- **Breathing Room**: Use generous white space as a design element (80-120px vertical spacing between sections)
|
|
125
|
-
- **Asymmetric Spacing**: Vary padding dramatically (small: 12px, medium: 48px, large: 96px)
|
|
126
|
-
- **Content Width Strategy**:
|
|
127
|
-
- Reading content: max 65-75 characters (600-700px)
|
|
128
|
-
- Hero sections: asymmetric layouts, not centered blocks
|
|
129
|
-
- Cards/components: vary sizes intentionally, not uniform grids
|
|
130
|
-
|
|
131
|
-
**Implementation:**
|
|
132
|
-
/* Intentional spacing scale */
|
|
133
|
-
--space-xs: 0.5rem; /* 8px */
|
|
134
|
-
--space-sm: 1rem; /* 16px */
|
|
135
|
-
--space-md: 3rem; /* 48px */
|
|
136
|
-
--space-lg: 6rem; /* 96px */
|
|
137
|
-
--space-xl: 10rem; /* 160px */
|
|
138
|
-
|
|
139
|
-
/* Use in combinations: */
|
|
140
|
-
padding: var(--space-lg) var(--space-md); /* Not uniform padding */
|
|
141
|
-
margin-bottom: var(--space-xl); /* Generous section breaks */
|
|
142
|
-
|
|
143
|
-
## 4. Backgrounds & Atmospheric Depth
|
|
144
|
-
|
|
145
|
-
**Avoid Distributional Defaults:**
|
|
146
|
-
- NO solid white or light gray backgrounds
|
|
147
|
-
- NO single-color backgrounds
|
|
148
|
-
- NO generic gradient overlays
|
|
149
|
-
|
|
150
|
-
**Intentional Alternatives:**
|
|
151
|
-
- **Layered Gradients**: Combine 2-3 subtle gradients for depth
|
|
152
|
-
- **Geometric Patterns**: SVG patterns, mesh gradients, or subtle noise textures
|
|
153
|
-
- **Strategic Contrast**: Alternate between light and dark sections for rhythm
|
|
154
|
-
|
|
155
|
-
**Implementation:**
|
|
156
|
-
/* Intentional background example */
|
|
157
|
-
background:
|
|
158
|
-
radial-gradient(circle at 20% 30%, rgba(216, 67, 21, 0.08) 0%, transparent 50%),
|
|
159
|
-
radial-gradient(circle at 80% 70%, rgba(0, 191, 165, 0.06) 0%, transparent 50%),
|
|
160
|
-
linear-gradient(135deg, #faf8f6 0%, #f0ebe6 100%);
|
|
161
|
-
|
|
162
|
-
## 5. Visual Hierarchy Principles
|
|
163
|
-
|
|
164
|
-
**Clear Priority System:**
|
|
165
|
-
1. **Primary Focus (1 element)**: Largest, highest contrast, most visual weight
|
|
166
|
-
2. **Secondary Elements (2-3 elements)**: 40-60% of primary size, reduced contrast
|
|
167
|
-
3. **Tertiary/Support (everything else)**: Minimal visual weight, muted colors
|
|
168
|
-
|
|
169
|
-
**Contrast Techniques:**
|
|
170
|
-
- Size: 3x+ differences between hierarchy levels
|
|
171
|
-
- Weight: 300+ difference in font-weight values
|
|
172
|
-
- Color: Primary gets brand color, secondary gets neutral, tertiary gets muted
|
|
173
|
-
- Space: Primary gets 2x+ surrounding white space vs. secondary
|
|
174
|
-
|
|
175
|
-
## 6. EXAMPLES - Intentional vs. Generic Design
|
|
176
|
-
|
|
177
|
-
### ❌ GENERIC (Distributional Convergence)
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
"xmlStructure": "<e-flexbox configuration-id=\"flex1\"><e-heading configuration-id=\"heading1\"></e-heading><e-button configuration-id=\"button1\"></e-button></e-flexbox>",
|
|
181
|
-
"elementConfig": {
|
|
182
|
-
"heading1": {
|
|
183
|
-
"title": { "$$type": "string", "value": "Welcome to Our Site" }
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
"stylesConfig": {
|
|
187
|
-
"heading1": {
|
|
188
|
-
"font-size": {
|
|
189
|
-
"$$type": "size",
|
|
190
|
-
"value": {
|
|
191
|
-
"size": { "$$type": "number", "value": 24 },
|
|
192
|
-
"unit": { "$$type": "string", "value": "px" }
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
**Why Generic**: 24px default size, #333 safe gray, 600 weight (middle-ground), purple gradient (AI cliché), uniform 12/24px padding
|
|
200
|
-
|
|
201
|
-
### ✅ INTENTIONAL (Resisting Convergence)
|
|
202
|
-
{
|
|
203
|
-
"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>",
|
|
204
|
-
"elementConfig": {
|
|
205
|
-
"hero-title": {
|
|
206
|
-
"title": { "$$type": "string", "value": "Transform Your Workflow" }
|
|
207
|
-
},
|
|
208
|
-
"hero-subtitle": {
|
|
209
|
-
"content": { "$$type": "string", "value": "Built for teams who refuse to compromise on quality" }
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
"stylesConfig": {
|
|
213
|
-
"hero-section": {
|
|
214
|
-
"display": { "$$type": "string", "value": "flex" },
|
|
215
|
-
"flex-direction": { "$$type": "string", "value": "column" },
|
|
216
|
-
"align-items": { "$$type": "string", "value": "flex-start" },
|
|
217
|
-
"background": {
|
|
218
|
-
"$$type": "color",
|
|
219
|
-
"value": "#f0ebe6",
|
|
220
|
-
"$intention": "background: #f0ebe6",
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
"hero-title": {
|
|
224
|
-
"font-size": {
|
|
225
|
-
"$$type": "size",
|
|
226
|
-
"value": {
|
|
227
|
-
"size": { "$$type": "number", "value": 72 },
|
|
228
|
-
"unit": { "$$type": "string", "value": "px" }
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
**Why Intentional**:
|
|
237
|
-
- Typography: 4.5rem headline (3.6x body), weight 900 vs 200 contrast, tight leading
|
|
238
|
-
- Color: Warm orange primary (#d84315), warm neutrals (#2d2622, #5a534d) NOT #333/#666
|
|
239
|
-
- Spacing: 10rem vertical padding (generous), 3rem gap, asymmetric alignment
|
|
240
|
-
- Background: Layered gradients with subtle brand color accent
|
|
241
|
-
|
|
242
|
-
# CONSTRAINTS
|
|
243
|
-
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.
|
|
244
|
-
If a "$$type" is missing, update the invalid object, if the XML has parsing errors, fix it, etc. and RETRY.
|
|
245
|
-
VALIDATE the XML structure before delivering it as the final result.
|
|
246
|
-
VALIDATE the JSON structure used in the "configuration" attributes for each element before delivering the final result. The configuration must MATCH the PropValue schemas.
|
|
247
|
-
NO LINKS ALLOWED. Never apply links to elements, even if they appear in the PropType schema.
|
|
248
|
-
elementConfig values must align with the widget's PropType schema, available at the resource [${ WIDGET_SCHEMA_URI }].
|
|
249
|
-
stylesConfig values must align with the common styles PropType schema, available at the resource [${ STYLE_SCHEMA_URI }].
|
|
250
|
-
|
|
251
|
-
# DESIGN QUALITY CONSTRAINTS
|
|
252
|
-
|
|
253
|
-
**Typography Constraints:**
|
|
254
|
-
- NEVER use Inter, Roboto, Arial, or Helvetica as primary display fonts
|
|
255
|
-
- NEVER use font-size ratios smaller than 2.5x between headlines and body
|
|
256
|
-
- NEVER use font-weight values between 500-700 for headlines (go lighter or heavier)
|
|
257
|
-
|
|
258
|
-
**Color Constraints:**
|
|
259
|
-
- NEVER use purple gradients or blue-purple color schemes
|
|
260
|
-
- NEVER use pure grays (#333, #666, #999) - use tinted neutrals instead
|
|
261
|
-
- NEVER distribute colors evenly - commit to ONE dominant color
|
|
262
|
-
- NEVER use more than 3 core colors (1 dominant, 1-2 accents)
|
|
263
|
-
|
|
264
|
-
**Spacing Constraints:**
|
|
265
|
-
- NEVER use uniform spacing across all elements
|
|
266
|
-
- NEVER use section padding less than 4rem (64px) for hero/major sections
|
|
267
|
-
- NEVER center everything - use asymmetric layouts for visual interest
|
|
268
|
-
|
|
269
|
-
**Background Constraints:**
|
|
270
|
-
- NEVER use solid white (#ffffff) or light gray (#f5f5f5) backgrounds without texture/gradients
|
|
271
|
-
- ALWAYS layer at least 2 gradient or color elements for atmospheric depth
|
|
272
|
-
|
|
273
|
-
# Parameters
|
|
274
|
-
All parameters are MANDATORY.
|
|
275
|
-
- xmlStructure
|
|
276
|
-
- elementConfig
|
|
277
|
-
- stylesConfig
|
|
278
|
-
|
|
279
|
-
If unsure about the configuration of a specific property, read the schema resources carefully.
|
|
280
|
-
|
|
281
|
-
# About our widgets
|
|
282
|
-
Most widgets are self-explanatory by their name. Here is some additional information.
|
|
283
|
-
Check for available llm_guidance property in the widget's schema.
|
|
284
|
-
SVG elements are bound to internal content upload. Avoid usage, unless you have tools to upload SVG content.
|
|
285
|
-
When working with containers, do not forget to apply style schema for controlling the layout.
|
|
286
|
-
|
|
287
|
-
|
|
9
|
+
# REQUIRED RESOURCES (Read before use)
|
|
10
|
+
1. [${ WIDGET_SCHEMA_URI }] - Widget types, configuration schemas, and PropType definitions
|
|
11
|
+
2. [${ STYLE_SCHEMA_URI }] - Common styles schema shared by all widgets
|
|
12
|
+
3. [elementor://global-classes] - Existing global classes (check FIRST to reuse)
|
|
13
|
+
|
|
14
|
+
# THREE-PHASE WORKFLOW (MANDATORY)
|
|
15
|
+
|
|
16
|
+
## Phase 1: Create Global Classes
|
|
17
|
+
1. Analyze requirements → identify reusable patterns (typography, colors, spacing)
|
|
18
|
+
2. Check [elementor://global-classes] for existing classes
|
|
19
|
+
3. Use "create-global-class" tool for NEW reusable styles BEFORE building
|
|
20
|
+
|
|
21
|
+
## Phase 2: Build Composition (THIS TOOL)
|
|
22
|
+
4. Build valid XML with minimal inline styles (layout/positioning only)
|
|
23
|
+
5. Avoid duplicating styles that should be global classes
|
|
24
|
+
|
|
25
|
+
## Phase 3: Apply Classes
|
|
26
|
+
6. Use "apply-global-class" tool to apply global classes to elements
|
|
27
|
+
|
|
28
|
+
# CORE INSTRUCTIONS
|
|
29
|
+
|
|
30
|
+
**Structure:**
|
|
31
|
+
- Build valid XML using allowed widget tags (e.g., \`<e-button configuration-id="btn1"></e-button>\`)
|
|
32
|
+
- Containers only: "e-flexbox", "e-div-block", "e-tabs"
|
|
33
|
+
- Every element MUST have unique "configuration-id" attribute
|
|
34
|
+
- No attributes, classes, IDs, or text nodes in XML
|
|
35
|
+
|
|
36
|
+
**Configuration:**
|
|
37
|
+
- Map each configuration-id to elementConfig (widget props) and stylesConfig (styles)
|
|
38
|
+
- Follow exact PropType schemas from resources above
|
|
39
|
+
- All PropValues need \`$$type\` property matching schema
|
|
40
|
+
- Keep stylesConfig MINIMAL - layout only, NOT reusable styles
|
|
41
|
+
|
|
42
|
+
**Validation:**
|
|
43
|
+
- Parse XML before submission
|
|
44
|
+
- Match all PropValues to schema (\`$$type\` required)
|
|
45
|
+
- NO LINKS in any configuration
|
|
46
|
+
- Retry on errors up to 10x, reading error messages carefully
|
|
47
|
+
|
|
48
|
+
# DESIGN QUALITY: AVOID AI SLOP
|
|
49
|
+
|
|
50
|
+
**Problem:** LLMs default to generic patterns (purple gradients, #333 grays, 24px headings, uniform spacing)
|
|
51
|
+
**Solution:** Make intentional, distinctive choices. When unsure, choose bold over safe.
|
|
52
|
+
|
|
53
|
+
## Typography Rules
|
|
54
|
+
❌ AVOID: Inter/Roboto/Arial, small ratios (1.5x), medium weights (500-700)
|
|
55
|
+
✅ USE: 3x+ size ratios, extreme weight contrasts (100/200 vs 800/900), tight headlines (1.1 line-height)
|
|
56
|
+
|
|
57
|
+
## Color Rules
|
|
58
|
+
❌ AVOID: Purple gradients, pure grays (#333/#666/#999), even distribution
|
|
59
|
+
✅ USE: ONE dominant color (60-70%), 1-2 accent colors (10-15%), tinted neutrals (warm/cool grays)
|
|
60
|
+
|
|
61
|
+
## Spacing Rules
|
|
62
|
+
❌ AVOID: Uniform spacing (all 16px/24px), cramped layouts, centered everything
|
|
63
|
+
✅ USE: Generous spacing (80-120px sections), dramatic variation (12px/48px/96px), asymmetric layouts
|
|
64
|
+
|
|
65
|
+
## Background Rules
|
|
66
|
+
❌ AVOID: Solid white/gray, single colors
|
|
67
|
+
✅ USE: Layered gradients (2-3 layers), subtle patterns, alternating light/dark sections
|
|
68
|
+
|
|
69
|
+
## Visual Hierarchy
|
|
70
|
+
1. **Primary** (1 element): Largest, highest contrast, most space
|
|
71
|
+
2. **Secondary** (2-3 elements): 40-60% of primary size
|
|
72
|
+
3. **Tertiary** (rest): Minimal weight, muted
|
|
73
|
+
|
|
74
|
+
**Contrast techniques:** 3x size differences, 300+ weight differences, color hierarchy (brand → neutral → muted)
|
|
75
|
+
|
|
76
|
+
# DESIGN CONSTRAINTS (NEVER VIOLATE)
|
|
77
|
+
|
|
78
|
+
**Typography:**
|
|
79
|
+
- NEVER use Inter, Roboto, Arial, Helvetica as primary display fonts
|
|
80
|
+
- NEVER use font-size ratios < 2.5x between headlines and body
|
|
81
|
+
- NEVER use font-weight 500-700 for headlines (go lighter or heavier)
|
|
82
|
+
|
|
83
|
+
**Color:**
|
|
84
|
+
- PREFER not to use pure grays - use tinted neutrals (#2d2622, #faf8f6, not #333/#f5f5f5)
|
|
85
|
+
- NEVER distribute colors evenly - commit to ONE dominant
|
|
86
|
+
- NEVER use more than 3 core colors - except for info/alert/badges
|
|
87
|
+
|
|
88
|
+
**Spacing:**
|
|
89
|
+
- NEVER use uniform spacing
|
|
90
|
+
- NEVER use < 4rem (64px) padding for major sections
|
|
91
|
+
- NEVER center everything
|
|
92
|
+
- PRIORITIZE rem based values over pixel based
|
|
93
|
+
|
|
94
|
+
**Background:**
|
|
95
|
+
- NEVER use solid #ffffff or #f5f5f5 without texture/gradients
|
|
96
|
+
- ALWAYS layer 2+ gradient/color elements
|
|
97
|
+
|
|
98
|
+
# WIDGET NOTES
|
|
99
|
+
- Check \`llm_guidance\` property in widget schemas for context
|
|
100
|
+
- Avoid SVG widgets (require content upload tools) - when must, prior to execution ensure assets uploaded
|
|
101
|
+
- Apply style schema to containers for layout control
|
|
102
|
+
|
|
103
|
+
# PARAMETERS (ALL MANDATORY)
|
|
104
|
+
- **xmlStructure**: Valid XML with configuration-id attributes
|
|
105
|
+
- **elementConfig**: Record of configuration-id → widget PropValues
|
|
106
|
+
- **stylesConfig**: Record of configuration-id → style PropValues (layout only)
|
|
288
107
|
` );
|
|
289
108
|
|
|
290
109
|
buildCompositionsToolPrompt.example( `
|
|
@@ -337,7 +156,12 @@ You should use these IDs as reference for further configuration, styling or chan
|
|
|
337
156
|
);
|
|
338
157
|
|
|
339
158
|
buildCompositionsToolPrompt.instruction(
|
|
340
|
-
|
|
159
|
+
`**CRITICAL WORKFLOW REMINDER**:
|
|
160
|
+
1. FIRST: Create reusable global classes for typography, colors, spacing patterns using "create-global-class" tool
|
|
161
|
+
2. SECOND: Use THIS tool with minimal inline styles (only layout & unique properties)
|
|
162
|
+
3. THIRD: Apply global classes to elements using "apply-global-class" tool
|
|
163
|
+
|
|
164
|
+
This ensures maximum reusability and consistency across your design system. ALWAYS check [elementor://global-classes] for existing classes before creating new ones.`
|
|
341
165
|
);
|
|
342
166
|
|
|
343
167
|
return buildCompositionsToolPrompt.prompt();
|
|
@@ -35,5 +35,4 @@ export const outputSchema = {
|
|
|
35
35
|
'The built XML structure as a string. Must use this XML after completion of building the composition, it contains real IDs.'
|
|
36
36
|
)
|
|
37
37
|
.optional(),
|
|
38
|
-
llmInstructions: z.string().describe( 'Instructions for what to do next, Important to follow these instructions!' ),
|
|
39
38
|
};
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createElement,
|
|
3
3
|
deleteElement,
|
|
4
|
-
generateElementId,
|
|
5
4
|
getContainer,
|
|
6
5
|
getWidgetsCache,
|
|
7
6
|
type V1Element,
|
|
8
7
|
} from '@elementor/editor-elements';
|
|
9
8
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
10
9
|
|
|
10
|
+
import { CompositionBuilder } from '../../../composition-builder/composition-builder';
|
|
11
11
|
import { BEST_PRACTICES_URI, STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
12
12
|
import { doUpdateElementProperty } from '../../utils/do-update-element-property';
|
|
13
|
-
import { validateInput } from '../../utils/validate-input';
|
|
14
13
|
import { generatePrompt } from './prompt';
|
|
15
14
|
import { inputSchema as schema, outputSchema } from './schema';
|
|
16
15
|
|
|
@@ -23,129 +22,59 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
23
22
|
schema,
|
|
24
23
|
requiredResources: [
|
|
25
24
|
{ description: 'Widgets schema', uri: WIDGET_SCHEMA_URI },
|
|
26
|
-
{ description: 'Global Classes', uri: 'elementor://global-classes' },
|
|
27
25
|
{ description: 'Styles schema', uri: STYLE_SCHEMA_URI },
|
|
26
|
+
{ description: 'Global Classes', uri: 'elementor://global-classes' },
|
|
28
27
|
{ description: 'Global Variables', uri: 'elementor://global-variables' },
|
|
29
28
|
{ description: 'Styles best practices', uri: BEST_PRACTICES_URI },
|
|
30
29
|
],
|
|
31
30
|
outputSchema,
|
|
32
31
|
modelPreferences: {
|
|
33
32
|
hints: [ { name: 'claude-sonnet-4-5' } ],
|
|
34
|
-
intelligencePriority: 0.95,
|
|
35
|
-
speedPriority: 0.5,
|
|
36
33
|
},
|
|
37
34
|
handler: async ( params ) => {
|
|
38
|
-
let xml: Document | null = null;
|
|
39
35
|
const { xmlStructure, elementConfig, stylesConfig } = params;
|
|
36
|
+
let generatedXML: string = '';
|
|
40
37
|
const errors: Error[] = [];
|
|
41
|
-
const softErrors: Error[] = [];
|
|
42
38
|
const rootContainers: V1Element[] = [];
|
|
43
|
-
const widgetsCache = getWidgetsCache() || {};
|
|
44
39
|
const documentContainer = getContainer( 'document' ) as unknown as V1Element;
|
|
45
40
|
try {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
const compositionBuilder = CompositionBuilder.fromXMLString( xmlStructure, {
|
|
42
|
+
createElement,
|
|
43
|
+
getWidgetsCache,
|
|
44
|
+
} );
|
|
45
|
+
compositionBuilder.setElementConfig( elementConfig );
|
|
46
|
+
compositionBuilder.setStylesConfig( stylesConfig );
|
|
52
47
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.filter( ( widget ) => widget.meta?.is_container )
|
|
65
|
-
.map( ( widget ) => widget.elType );
|
|
66
|
-
const isContainer = CONTAINER_ELEMENTS.includes( elementTag );
|
|
67
|
-
const parentElType = containerElement.model.get( 'elType' );
|
|
68
|
-
let targetContainerId =
|
|
69
|
-
parentElType === 'e-tabs'
|
|
70
|
-
? containerElement.children?.[ 1 ].children?.[ childIndex ]?.id ||
|
|
71
|
-
containerElement.children?.[ 1 ].id
|
|
72
|
-
: containerElement.id;
|
|
73
|
-
if ( ! targetContainerId ) {
|
|
74
|
-
targetContainerId = containerElement.id;
|
|
75
|
-
}
|
|
76
|
-
const newElement = isContainer
|
|
77
|
-
? createElement( {
|
|
78
|
-
containerId: targetContainerId,
|
|
79
|
-
model: {
|
|
80
|
-
elType: elementTag,
|
|
81
|
-
id: generateElementId(),
|
|
82
|
-
},
|
|
83
|
-
options: { useHistory: false },
|
|
84
|
-
} )
|
|
85
|
-
: createElement( {
|
|
86
|
-
containerId: targetContainerId,
|
|
87
|
-
model: {
|
|
88
|
-
elType: 'widget',
|
|
89
|
-
widgetType: elementTag,
|
|
90
|
-
id: generateElementId(),
|
|
91
|
-
},
|
|
92
|
-
options: { useHistory: false },
|
|
93
|
-
} );
|
|
94
|
-
if ( containerElement === documentContainer ) {
|
|
95
|
-
rootContainers.push( newElement );
|
|
96
|
-
}
|
|
97
|
-
node.setAttribute( 'id', newElement.id );
|
|
98
|
-
const configId = node.getAttribute( 'configuration-id' ) || '';
|
|
99
|
-
try {
|
|
100
|
-
const configObject = elementConfig[ configId ] || {};
|
|
101
|
-
const styleObject = stylesConfig[ configId ] || {};
|
|
102
|
-
const { errors: propsValidationErrors } = validateInput.validatePropSchema(
|
|
103
|
-
elementTag,
|
|
104
|
-
configObject
|
|
105
|
-
);
|
|
106
|
-
errors.push( ...( propsValidationErrors || [] ).map( ( msg ) => new Error( msg ) ) );
|
|
107
|
-
const { errors: stylesValidationErrors } = validateInput.validateStyles( styleObject );
|
|
108
|
-
errors.push( ...( stylesValidationErrors || [] ).map( ( msg ) => new Error( msg ) ) );
|
|
109
|
-
|
|
110
|
-
if ( propsValidationErrors?.length || stylesValidationErrors?.length ) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
configObject._styles = styleObject || {};
|
|
114
|
-
for ( const [ propertyName, propertyValue ] of Object.entries( configObject ) ) {
|
|
115
|
-
try {
|
|
116
|
-
doUpdateElementProperty( {
|
|
117
|
-
elementId: newElement.id,
|
|
118
|
-
propertyName,
|
|
119
|
-
propertyValue,
|
|
120
|
-
elementType: elementTag,
|
|
121
|
-
} );
|
|
122
|
-
} catch ( error ) {
|
|
123
|
-
softErrors.push( error as Error );
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if ( isContainer ) {
|
|
127
|
-
let currentChild = 0;
|
|
128
|
-
for ( const child of node.children ) {
|
|
129
|
-
iterate( child, newElement, currentChild );
|
|
130
|
-
currentChild++;
|
|
131
|
-
}
|
|
132
|
-
} else {
|
|
133
|
-
node.innerHTML = '';
|
|
134
|
-
node.removeAttribute( 'configuration' );
|
|
135
|
-
}
|
|
136
|
-
} finally {
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
let currentChild = 0;
|
|
141
|
-
for await ( const childNode of children ) {
|
|
142
|
-
await iterate( childNode, documentContainer, currentChild );
|
|
143
|
-
currentChild++;
|
|
144
|
-
try {
|
|
145
|
-
} catch ( error ) {
|
|
146
|
-
errors.push( error as Error );
|
|
147
|
-
}
|
|
48
|
+
const {
|
|
49
|
+
configErrors,
|
|
50
|
+
invalidStyles,
|
|
51
|
+
rootContainers: generatedRootContainers,
|
|
52
|
+
} = compositionBuilder.build( documentContainer );
|
|
53
|
+
|
|
54
|
+
generatedXML = new XMLSerializer().serializeToString( compositionBuilder.getXML() );
|
|
55
|
+
|
|
56
|
+
if ( configErrors.length ) {
|
|
57
|
+
errors.push( ...configErrors.map( ( e ) => new Error( e ) ) );
|
|
58
|
+
throw new Error( 'Configuration errors occurred during composition building.' );
|
|
148
59
|
}
|
|
60
|
+
|
|
61
|
+
rootContainers.push( ...generatedRootContainers );
|
|
62
|
+
|
|
63
|
+
Object.entries( invalidStyles ).forEach( ( [ elementId, rawCssRules ] ) => {
|
|
64
|
+
const customCss = {
|
|
65
|
+
value: rawCssRules.join( ';\n' ),
|
|
66
|
+
};
|
|
67
|
+
doUpdateElementProperty( {
|
|
68
|
+
elementId,
|
|
69
|
+
propertyName: '_styles',
|
|
70
|
+
propertyValue: {
|
|
71
|
+
_styles: {
|
|
72
|
+
custom_css: customCss,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
elementType: 'widget',
|
|
76
|
+
} );
|
|
77
|
+
} );
|
|
149
78
|
} catch ( error ) {
|
|
150
79
|
errors.push( error as Error );
|
|
151
80
|
}
|
|
@@ -187,26 +116,21 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
187
116
|
) }\n\n"Missing $$type" errors indicate that the configuration objects are invalid. Try again and apply **ALL** object entries with correct $$type.\nNow that you have these errors, fix them and try again. Errors regarding configuration objects, please check against the PropType schemas`;
|
|
188
117
|
throw new Error( errorText );
|
|
189
118
|
}
|
|
190
|
-
if ( ! xml ) {
|
|
191
|
-
throw new Error( 'XML structure is null after parsing.' );
|
|
192
|
-
}
|
|
193
119
|
return {
|
|
194
|
-
xmlStructure:
|
|
120
|
+
xmlStructure: generatedXML,
|
|
195
121
|
errors: errors?.length
|
|
196
122
|
? errors.map( ( e ) => ( typeof e === 'string' ? e : e.message ) ).join( '\n\n' )
|
|
197
123
|
: undefined,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- Use "apply-global-class" tool as there may be global styles ready to be applied to elements.
|
|
209
|
-
- Use "configure-element" tool to further configure elements as needed, including styles.
|
|
124
|
+
llm_instructions: `The composition was built successfully with element IDs embedded in the XML.
|
|
125
|
+
|
|
126
|
+
**CRITICAL NEXT STEPS** (Follow in order):
|
|
127
|
+
1. **Apply Global Classes**: Use "apply-global-class" tool to apply the global classes you created BEFORE building this composition
|
|
128
|
+
- Check the created element IDs in the returned XML
|
|
129
|
+
- Apply semantic classes (heading-primary, button-cta, etc.) to appropriate elements
|
|
130
|
+
|
|
131
|
+
2. **Fine-tune if needed**: Use "configure-element" tool only for element-specific adjustments that don't warrant global classes
|
|
132
|
+
|
|
133
|
+
Remember: Global classes ensure design consistency and reusability. Don't skip applying them!
|
|
210
134
|
`,
|
|
211
135
|
};
|
|
212
136
|
},
|