@elementor/editor-canvas 3.33.0-271 → 3.33.0-273
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 +747 -21
- package/dist/index.mjs +755 -15
- package/package.json +17 -15
- package/src/init.tsx +9 -0
- package/src/mcp/canvas-mcp.ts +15 -0
- package/src/mcp/mcp-description.ts +33 -0
- package/src/mcp/resources/widgets-schema-resource.ts +154 -0
- package/src/mcp/tools/build-composition/prompt.ts +119 -0
- package/src/mcp/tools/build-composition/schema.ts +27 -0
- package/src/mcp/tools/build-composition/tool.ts +158 -0
- package/src/mcp/tools/configure-element/prompt.ts +92 -0
- package/src/mcp/tools/configure-element/schema.ts +25 -0
- package/src/mcp/tools/configure-element/tool.ts +67 -0
- package/src/mcp/utils/do-update-element-property.ts +115 -0
- package/src/mcp/utils/generate-available-tags.ts +23 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-canvas",
|
|
3
3
|
"description": "Elementor Editor Canvas",
|
|
4
|
-
"version": "3.33.0-
|
|
4
|
+
"version": "3.33.0-273",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,21 +37,23 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor": "3.33.0-
|
|
41
|
-
"@elementor/editor-controls": "3.33.0-
|
|
42
|
-
"@elementor/editor-documents": "3.33.0-
|
|
43
|
-
"@elementor/editor-elements": "3.33.0-
|
|
44
|
-
"@elementor/editor-interactions": "3.33.0-
|
|
45
|
-
"@elementor/editor-notifications": "3.33.0-
|
|
46
|
-
"@elementor/editor-props": "3.33.0-
|
|
47
|
-
"@elementor/editor-responsive": "3.33.0-
|
|
48
|
-
"@elementor/editor-styles": "3.33.0-
|
|
49
|
-
"@elementor/editor-styles-repository": "3.33.0-
|
|
50
|
-
"@elementor/editor-v1-adapters": "3.33.0-
|
|
51
|
-
"@elementor/
|
|
40
|
+
"@elementor/editor": "3.33.0-273",
|
|
41
|
+
"@elementor/editor-controls": "3.33.0-273",
|
|
42
|
+
"@elementor/editor-documents": "3.33.0-273",
|
|
43
|
+
"@elementor/editor-elements": "3.33.0-273",
|
|
44
|
+
"@elementor/editor-interactions": "3.33.0-273",
|
|
45
|
+
"@elementor/editor-notifications": "3.33.0-273",
|
|
46
|
+
"@elementor/editor-props": "3.33.0-273",
|
|
47
|
+
"@elementor/editor-responsive": "3.33.0-273",
|
|
48
|
+
"@elementor/editor-styles": "3.33.0-273",
|
|
49
|
+
"@elementor/editor-styles-repository": "3.33.0-273",
|
|
50
|
+
"@elementor/editor-v1-adapters": "3.33.0-273",
|
|
51
|
+
"@elementor/editor-mcp": "3.33.0-273",
|
|
52
|
+
"@elementor/schema": "3.33.0-273",
|
|
53
|
+
"@elementor/twing": "3.33.0-273",
|
|
52
54
|
"@elementor/ui": "1.36.17",
|
|
53
|
-
"@elementor/utils": "3.33.0-
|
|
54
|
-
"@elementor/wp-media": "3.33.0-
|
|
55
|
+
"@elementor/utils": "3.33.0-273",
|
|
56
|
+
"@elementor/wp-media": "3.33.0-273",
|
|
55
57
|
"@floating-ui/react": "^0.27.5",
|
|
56
58
|
"@wordpress/i18n": "^5.13.0"
|
|
57
59
|
},
|
package/src/init.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { injectIntoLogic, injectIntoTop } from '@elementor/editor';
|
|
2
2
|
import { init as initInteractionsRepository } from '@elementor/editor-interactions';
|
|
3
|
+
import { getMCPByDomain } from '@elementor/editor-mcp';
|
|
3
4
|
|
|
4
5
|
import { ClassesRename } from './components/classes-rename';
|
|
5
6
|
import { ElementsOverlays } from './components/elements-overlays';
|
|
@@ -8,6 +9,8 @@ import { StyleRenderer } from './components/style-renderer';
|
|
|
8
9
|
import { initSettingsTransformers } from './init-settings-transformers';
|
|
9
10
|
import { initStyleTransformers } from './init-style-transformers';
|
|
10
11
|
import { initLegacyViews } from './legacy/init-legacy-views';
|
|
12
|
+
import { initCanvasMcp } from './mcp/canvas-mcp';
|
|
13
|
+
import { mcpDescription } from './mcp/mcp-description';
|
|
11
14
|
import { initLinkInLinkPrevention } from './prevent-link-in-link-commands';
|
|
12
15
|
import { initStyleCommands } from './style-commands/init-style-commands';
|
|
13
16
|
|
|
@@ -42,4 +45,10 @@ export function init() {
|
|
|
42
45
|
id: 'classes-rename',
|
|
43
46
|
component: ClassesRename,
|
|
44
47
|
} );
|
|
48
|
+
|
|
49
|
+
initCanvasMcp(
|
|
50
|
+
getMCPByDomain( 'canvas', {
|
|
51
|
+
instructions: mcpDescription,
|
|
52
|
+
} )
|
|
53
|
+
);
|
|
45
54
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
|
+
|
|
3
|
+
import { initWidgetsSchemaResource } from './resources/widgets-schema-resource';
|
|
4
|
+
import { initBuildCompositionsTool } from './tools/build-composition/tool';
|
|
5
|
+
import { initConfigureElementTool } from './tools/configure-element/tool';
|
|
6
|
+
|
|
7
|
+
export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
|
|
8
|
+
const { setMCPDescription } = reg;
|
|
9
|
+
setMCPDescription(
|
|
10
|
+
'Everything related to creative design, layout, styling and building the pages, specifically element of type "widget"'
|
|
11
|
+
);
|
|
12
|
+
initWidgetsSchemaResource( reg );
|
|
13
|
+
initBuildCompositionsTool( reg );
|
|
14
|
+
initConfigureElementTool( reg );
|
|
15
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from './resources/widgets-schema-resource';
|
|
2
|
+
|
|
3
|
+
export const mcpDescription = `Canvas MCP - Working with widgets and styles: how to use the PropType schemas and generate PropValue structures
|
|
4
|
+
|
|
5
|
+
# Elementor's PropValue configuration system
|
|
6
|
+
|
|
7
|
+
Every widget in Elementor has a set of properties that can be configured. These properties are defined using a strict schema, which specifies the type and structure of each property's value.
|
|
8
|
+
All values are wrapped in a special structure called a "PropValue", which includes data and additional information about the type of the value.
|
|
9
|
+
|
|
10
|
+
To correctly configure a widget's properties, you must follow the PropType schema defined for that widget. This schema outlines the expected structure and types for each property, ensuring that the values you provide are valid and can be properly interpreted by Elementor.
|
|
11
|
+
Every widget has it's own PropType schema, retreivable from the resource [${ WIDGET_SCHEMA_URI }].
|
|
12
|
+
ALL WIDGETS share a common _styles property with a uniform styles schema, retreivable from the resource [${ STYLE_SCHEMA_URI }].
|
|
13
|
+
The style schema is grouped by categories, such as "typography", "background", "border", etc.
|
|
14
|
+
|
|
15
|
+
All array types that can receive union types, are typed as mixed array, which means that each item in the array can be of any of the allowed types defined in the PropType schema.
|
|
16
|
+
Example: the "background" can have a background-overlay property, which can contain multiple overlays, such as color, gradient, image, etc. Each item in the array must follow the PropType schema for each overlay type.
|
|
17
|
+
All _style properties are OPTIONAL. When a _style is defined, we MERGE the values with existing styles, so only the properties you define will be changed, and the rest will remain as is.
|
|
18
|
+
|
|
19
|
+
When applicable for styles, use the "custom_css" property for free-form CSS styling. This property accepts a string of CSS rules that will be applied directly to the element.
|
|
20
|
+
The css string must follow standard CSS syntax, with properties and values separated by semicolons, no selectors, or nesting rules allowed.
|
|
21
|
+
|
|
22
|
+
Additionaly, some PropTypes have metadata information (meta property) that can help in understaind the PropType usage, such as description or other useful information.
|
|
23
|
+
|
|
24
|
+
# Note about null values
|
|
25
|
+
If a PropValue's value is null, omit the entire PropValue object.
|
|
26
|
+
|
|
27
|
+
Example of "image" PropValue structure:
|
|
28
|
+
|
|
29
|
+
PropValue structure:
|
|
30
|
+
{$$type:'image',value:{src:{$$type:'image-src',value:{url:{$$type:'url',value:'https://example.com/image.jpg'}}},size:{$$type:'string',value:'full'}}}
|
|
31
|
+
|
|
32
|
+
Example of
|
|
33
|
+
`;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { getWidgetsCache } from '@elementor/editor-elements';
|
|
2
|
+
import { type MCPRegistryEntry, ResourceTemplate } from '@elementor/editor-mcp';
|
|
3
|
+
import {
|
|
4
|
+
type ArrayPropType,
|
|
5
|
+
type ObjectPropType,
|
|
6
|
+
type PropType,
|
|
7
|
+
Schema,
|
|
8
|
+
type TransformablePropType,
|
|
9
|
+
type UnionPropType,
|
|
10
|
+
} from '@elementor/editor-props';
|
|
11
|
+
import { getStylesSchema } from '@elementor/editor-styles';
|
|
12
|
+
|
|
13
|
+
export const WIDGET_SCHEMA_URI = 'elementor://widgets/schema/{widgetType}';
|
|
14
|
+
export const STYLE_SCHEMA_URI = 'elementor://styles/schema/{category}';
|
|
15
|
+
|
|
16
|
+
export const initWidgetsSchemaResource = ( reg: MCPRegistryEntry ) => {
|
|
17
|
+
const { mcpServer } = reg;
|
|
18
|
+
|
|
19
|
+
mcpServer.resource(
|
|
20
|
+
'styles-schema',
|
|
21
|
+
new ResourceTemplate( STYLE_SCHEMA_URI, {
|
|
22
|
+
list: () => {
|
|
23
|
+
const categories = [ ...Object.keys( getStylesSchema() ), 'custom_css' ];
|
|
24
|
+
return {
|
|
25
|
+
resources: categories.map( ( category ) => ( {
|
|
26
|
+
uri: `elementor://styles/schema/${ category }`,
|
|
27
|
+
name: 'Style schema for ' + category,
|
|
28
|
+
} ) ),
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
} ),
|
|
32
|
+
{
|
|
33
|
+
description: 'Common styles schema for the specified category',
|
|
34
|
+
},
|
|
35
|
+
async ( uri, variables ) => {
|
|
36
|
+
const category = typeof variables.category === 'string' ? variables.category : variables.category?.[ 0 ];
|
|
37
|
+
if ( category === 'custom_css' ) {
|
|
38
|
+
return {
|
|
39
|
+
contents: [
|
|
40
|
+
{
|
|
41
|
+
uri: uri.toString(),
|
|
42
|
+
text: 'Free style inline CSS string of properties and their values. Applicable for a single element, only the properties and values are accepted.',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const stylesSchema = getStylesSchema()[ category ];
|
|
48
|
+
if ( ! stylesSchema ) {
|
|
49
|
+
throw new Error( `No styles schema found for category: ${ category }` );
|
|
50
|
+
}
|
|
51
|
+
const cleanedupPropSchema = cleanupPropType( stylesSchema );
|
|
52
|
+
const asJson = Schema.propTypeToJsonSchema( cleanedupPropSchema as PropType );
|
|
53
|
+
return {
|
|
54
|
+
contents: [
|
|
55
|
+
{
|
|
56
|
+
uri: uri.toString(),
|
|
57
|
+
text: JSON.stringify( asJson ),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
mcpServer.resource(
|
|
65
|
+
'widget-schema-by-type',
|
|
66
|
+
new ResourceTemplate( WIDGET_SCHEMA_URI, {
|
|
67
|
+
list: () => {
|
|
68
|
+
const cache = getWidgetsCache() || {};
|
|
69
|
+
const availableWidgets = Object.keys( cache || {} ).filter(
|
|
70
|
+
( widgetType ) => cache[ widgetType ]?.atomic_props_schema
|
|
71
|
+
);
|
|
72
|
+
return {
|
|
73
|
+
resources: availableWidgets.map( ( widgetType ) => ( {
|
|
74
|
+
uri: `elementor://widgets/schema/${ widgetType }`,
|
|
75
|
+
name: 'Widget schema for ' + widgetType,
|
|
76
|
+
} ) ),
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
} ),
|
|
80
|
+
{
|
|
81
|
+
description: 'PropType schema for the specified widget type',
|
|
82
|
+
},
|
|
83
|
+
async ( uri, variables ) => {
|
|
84
|
+
const widgetType =
|
|
85
|
+
typeof variables.widgetType === 'string' ? variables.widgetType : variables.widgetType?.[ 0 ];
|
|
86
|
+
const propSchema = getWidgetsCache()?.[ widgetType ]?.atomic_props_schema;
|
|
87
|
+
if ( ! propSchema ) {
|
|
88
|
+
throw new Error( `No prop schema found for element type: ${ widgetType }` );
|
|
89
|
+
}
|
|
90
|
+
const cleanedupPropSchema = cleanupPropSchema( propSchema );
|
|
91
|
+
const asJson = Object.fromEntries(
|
|
92
|
+
Object.entries( cleanedupPropSchema ).map( ( [ key, propType ] ) => [
|
|
93
|
+
key,
|
|
94
|
+
Schema.propTypeToJsonSchema( propType ),
|
|
95
|
+
] )
|
|
96
|
+
);
|
|
97
|
+
delete asJson.classes;
|
|
98
|
+
delete asJson._cssid;
|
|
99
|
+
delete asJson.attributes;
|
|
100
|
+
return {
|
|
101
|
+
contents: [
|
|
102
|
+
{
|
|
103
|
+
uri: uri.toString(),
|
|
104
|
+
text: JSON.stringify( asJson ),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
function cleanupPropSchema( propSchema: Record< string, PropType > ): Record< string, PropType > {
|
|
113
|
+
const result: Record< string, Partial< PropType > > = {};
|
|
114
|
+
Object.keys( propSchema ).forEach( ( propName ) => {
|
|
115
|
+
result[ propName ] = cleanupPropType( propSchema[ propName ] );
|
|
116
|
+
} );
|
|
117
|
+
return result as Record< string, PropType >;
|
|
118
|
+
}
|
|
119
|
+
function cleanupPropType( propType: PropType & { key?: string } ): Partial< PropType > {
|
|
120
|
+
const result: Partial< PropType > = {};
|
|
121
|
+
Object.keys( propType ).forEach( ( property ) => {
|
|
122
|
+
switch ( property ) {
|
|
123
|
+
case 'key':
|
|
124
|
+
case 'kind':
|
|
125
|
+
( result as Record< string, unknown > )[ property ] = propType[ property ];
|
|
126
|
+
break;
|
|
127
|
+
case 'meta':
|
|
128
|
+
case 'settings':
|
|
129
|
+
{
|
|
130
|
+
if ( Object.keys( propType[ property ] || {} ).length > 0 ) {
|
|
131
|
+
( result as Record< string, unknown > )[ property ] = propType[ property ];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
} );
|
|
137
|
+
if ( result.kind === 'plain' ) {
|
|
138
|
+
Object.defineProperty( result, 'kind', { value: 'string' } );
|
|
139
|
+
} else if ( result.kind === 'array' ) {
|
|
140
|
+
result.item_prop_type = cleanupPropType( ( propType as ArrayPropType ).item_prop_type ) as PropType;
|
|
141
|
+
} else if ( result.kind === 'object' ) {
|
|
142
|
+
const shape = ( propType as ObjectPropType ).shape as Record< string, PropType >;
|
|
143
|
+
const cleanedShape = cleanupPropSchema( shape );
|
|
144
|
+
result.shape = cleanedShape;
|
|
145
|
+
} else if ( result.kind === 'union' ) {
|
|
146
|
+
const propTypes = ( propType as UnionPropType ).prop_types;
|
|
147
|
+
const cleanedPropTypes: Record< string, Partial< PropType > > = {};
|
|
148
|
+
Object.keys( propTypes ).forEach( ( key ) => {
|
|
149
|
+
cleanedPropTypes[ key ] = cleanupPropType( propTypes[ key ] );
|
|
150
|
+
} );
|
|
151
|
+
result.prop_types = cleanedPropTypes as Record< string, TransformablePropType >;
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { toolPrompts } from '@elementor/editor-mcp';
|
|
2
|
+
|
|
3
|
+
import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
4
|
+
|
|
5
|
+
const CUSTOM_CSS_URI = STYLE_SCHEMA_URI.replace( '{category}', 'custom_css' );
|
|
6
|
+
|
|
7
|
+
export const generatePrompt = () => {
|
|
8
|
+
const buildCompositionsToolPrompt = toolPrompts( 'build-compositions' );
|
|
9
|
+
|
|
10
|
+
buildCompositionsToolPrompt.description( `
|
|
11
|
+
Build entire elementor widget comositions representing complex structures of nested elements.
|
|
12
|
+
|
|
13
|
+
# When to use this tool
|
|
14
|
+
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.
|
|
15
|
+
Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
|
|
16
|
+
|
|
17
|
+
# **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
|
|
18
|
+
1. [${ WIDGET_SCHEMA_URI }]
|
|
19
|
+
Required to understand which widgets are available, and what are their configuration schemas.
|
|
20
|
+
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.
|
|
21
|
+
2. [${ CUSTOM_CSS_URI }]
|
|
22
|
+
Required to understand the styles schema for the widgets. All widgets share the same styles schema.
|
|
23
|
+
USE ONLY THE "custom_css" CATEGORY FROM THE STYLES SCHEMA FOR STYLING THE ELEMENTS with this tool.
|
|
24
|
+
3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
|
|
25
|
+
|
|
26
|
+
# Instructions
|
|
27
|
+
1. Understand the user requirements carefully.
|
|
28
|
+
2. Build a valid XML structure using only the allowed custom tags provided. For example, if you
|
|
29
|
+
use the "e-button" element, it would be represented as <e-button></e-button> in the XML structure.
|
|
30
|
+
3. Plan the configuration for each element according to the user requirements, using the configuration schema provided for each custom tag.
|
|
31
|
+
Every widget type has it's own configuration schema, retreivable from the resource [${ WIDGET_SCHEMA_URI }].
|
|
32
|
+
PropValues must follow the exact PropType schema provided in the resource.
|
|
33
|
+
4. For every element, provide a "configuration-id" attribute. For example:
|
|
34
|
+
\`<e-flexbox configuration-id="flex1"><e-heading configuration-id="heading2"></e-heading></e-flexbox>\`
|
|
35
|
+
In the elementConfig property, provide the actual configuration object for each configuration-id used in the XML structure.
|
|
36
|
+
In the stylesConfig property, provide the actual styles configuration object for each configuration-id used in the XML structure.
|
|
37
|
+
For easy execution, USE ONLY "custom_css" category from the styles schema resource to apply styles.
|
|
38
|
+
5. Ensure the XML structure is valid and parsable.
|
|
39
|
+
6. Do not add any attribute nodes, classes, id's, and no text nodes allowed, for inline styles prefer USE the [${ CUSTOM_CSS_URI }] resource for custom_css.
|
|
40
|
+
7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-div-block" and "e-flexbox".
|
|
41
|
+
8. Make sure that non-container elements do NOT have any nested elements.
|
|
42
|
+
9. Unsless the user specifically requires structure only, BE EXPRESSIVE AND VISUALLY CREATIVE AS POSSIBLE IN APPLYING STYLE CONFIGURATION.
|
|
43
|
+
In the case of doubt, prefer adding more styles to make the composition visually appealing.
|
|
44
|
+
|
|
45
|
+
# Additional Guidelines
|
|
46
|
+
- Most users expect the structure to be well designed and visually appealing.
|
|
47
|
+
- Use layout properties, ensure "white space" design approach is followed, and make sure the composition is visually balanced.
|
|
48
|
+
- Use appropriate spacing, alignment, and sizing to create a harmonious layout.
|
|
49
|
+
- Consider the visual hierarchy of elements to guide the user's attention effectively.
|
|
50
|
+
- You are encouraged to use colors, typography, and other style properties to enhance the visual appeal, as long as they are part of the configuration schema for the elements used.
|
|
51
|
+
- Always aim for a clean and professional look that aligns with modern design principles.
|
|
52
|
+
- When you are required to create placeholder texts, use texts that have a length that fits the goal. When long texts are required, use longer placeholder texts. When the user specifies exact texts, use the exact texts.
|
|
53
|
+
- Image size does not affect the actual size on the screen, only which quality to use. If you use images, specifically add _styles PropValues to define the image sizes.
|
|
54
|
+
|
|
55
|
+
# CONSTRAINTS
|
|
56
|
+
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.
|
|
57
|
+
If a "$$type" is missing, update the invalid object, if the XML has parsing errors, fix it, etc. and RETRY.
|
|
58
|
+
VALIDATE the XML structure before delivering it as the final result.
|
|
59
|
+
VALIDATE the JSON structure used in the "configuration" attributes for each element before delivering the final result. The configuration must MATCH the PropValue schemas.
|
|
60
|
+
NO LINKS ALLOWED. Never apply links to elements, even if they appear in the PropType schema.
|
|
61
|
+
elementConfig values must align with the widget's PropType schema, available at the resource [${ WIDGET_SCHEMA_URI }].
|
|
62
|
+
stylesConfig values must align with the common styles PropType schema, available at the resource [${ STYLE_SCHEMA_URI }].
|
|
63
|
+
|
|
64
|
+
# Parameters
|
|
65
|
+
All parameters are MANDATORY.
|
|
66
|
+
- xmlStructure
|
|
67
|
+
- elementConfig
|
|
68
|
+
- stylesConfig
|
|
69
|
+
|
|
70
|
+
If unsure about the configuration of a specific property, read the schema resources carefully.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
` );
|
|
74
|
+
|
|
75
|
+
buildCompositionsToolPrompt.example( `
|
|
76
|
+
A Heading and a button inside a flexbox
|
|
77
|
+
{
|
|
78
|
+
xmlStructure: "<e-flexbox configuration-id="flex1"><e-heading configuration-id="heading1"></e-heading><e-button configuration-id="button1"></e-button></e-flexbox>"
|
|
79
|
+
elementConfig: {
|
|
80
|
+
"flex1": {
|
|
81
|
+
"tag": {
|
|
82
|
+
"$$type": "string",
|
|
83
|
+
"value": "section"
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
styleConfig: {
|
|
87
|
+
"heading1": {
|
|
88
|
+
"custom_css": "font-size: 24px; color: #333;"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
` );
|
|
93
|
+
|
|
94
|
+
buildCompositionsToolPrompt.parameter(
|
|
95
|
+
'xmlStructure',
|
|
96
|
+
`**MANDATORY** A valid XML structure representing the composition to be built, using custom elementor tags, styling and configuration PropValues.`
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
buildCompositionsToolPrompt.parameter(
|
|
100
|
+
'elementConfig',
|
|
101
|
+
`**MANDATORY** A record mapping configuration IDs to their corresponding configuration objects, defining the PropValues for each element created.`
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
buildCompositionsToolPrompt.parameter(
|
|
105
|
+
'styleConfig',
|
|
106
|
+
`**MANDATORY** A record mapping style PropTypes to their corresponding style configuration objects, defining the PropValues for styles to be applied to elements.`
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
buildCompositionsToolPrompt.instruction(
|
|
110
|
+
`You will be provided the XML structure with element IDs. These IDs represent the actual elementor widgets created on the page/post.
|
|
111
|
+
You should use these IDs as reference for further configuration, styling or changing elements later on.`
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
buildCompositionsToolPrompt.instruction(
|
|
115
|
+
`If you have global styles/classes available in the project, 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.`
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return buildCompositionsToolPrompt.prompt();
|
|
119
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from '@elementor/schema';
|
|
2
|
+
|
|
3
|
+
export const inputSchema = {
|
|
4
|
+
xmlStructure: z.string().describe( 'The XML structure representing the composition to be built' ),
|
|
5
|
+
elementConfig: z
|
|
6
|
+
.record(
|
|
7
|
+
z.string().describe( 'The configuration id' ),
|
|
8
|
+
z.record( z.string().describe( 'property name' ), z.any().describe( 'The PropValue for the property' ) )
|
|
9
|
+
)
|
|
10
|
+
.describe( 'A record mapping element IDs to their configuration objects. REQUIRED' ),
|
|
11
|
+
stylesConfig: z
|
|
12
|
+
.record(
|
|
13
|
+
z.string().describe( 'The configuration id' ),
|
|
14
|
+
z.record(
|
|
15
|
+
z.string().describe( '_styles property name' ),
|
|
16
|
+
z.any().describe( 'The PropValue for the style property. MANDATORY' )
|
|
17
|
+
)
|
|
18
|
+
)
|
|
19
|
+
.describe( 'A record mapping element IDs to their styles configuration objects.' )
|
|
20
|
+
.default( {} ),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const outputSchema = {
|
|
24
|
+
errors: z.string().describe( 'Error message if the composition building failed' ).optional(),
|
|
25
|
+
xmlStructure: z.string().describe( 'The built XML structure as a string' ).optional(),
|
|
26
|
+
llmInstructions: z.string().describe( 'Instructions used to further actions for you' ).optional(),
|
|
27
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createElement,
|
|
3
|
+
deleteElement,
|
|
4
|
+
generateElementId,
|
|
5
|
+
getContainer,
|
|
6
|
+
getWidgetsCache,
|
|
7
|
+
type V1Element,
|
|
8
|
+
} from '@elementor/editor-elements';
|
|
9
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
10
|
+
import { type PropValue } from '@elementor/editor-props';
|
|
11
|
+
|
|
12
|
+
import { doUpdateElementProperty } from '../../utils/do-update-element-property';
|
|
13
|
+
import { generatePrompt } from './prompt';
|
|
14
|
+
import { inputSchema as schema, outputSchema } from './schema';
|
|
15
|
+
|
|
16
|
+
export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
17
|
+
const { addTool } = reg;
|
|
18
|
+
|
|
19
|
+
addTool( {
|
|
20
|
+
name: 'build-compositions',
|
|
21
|
+
description: generatePrompt(),
|
|
22
|
+
schema,
|
|
23
|
+
outputSchema,
|
|
24
|
+
handler: async ( params ) => {
|
|
25
|
+
let xml: Document | null = null;
|
|
26
|
+
const { xmlStructure, elementConfig, stylesConfig } = params;
|
|
27
|
+
const errors: Error[] = [];
|
|
28
|
+
const softErrors: Error[] = [];
|
|
29
|
+
const widgetsCache = getWidgetsCache() || {};
|
|
30
|
+
const documentContainer = getContainer( 'document' ) as unknown as V1Element;
|
|
31
|
+
const rootContainer = createElement( {
|
|
32
|
+
containerId: documentContainer.id,
|
|
33
|
+
model: {
|
|
34
|
+
elType: 'container',
|
|
35
|
+
id: generateElementId(),
|
|
36
|
+
},
|
|
37
|
+
options: { useHistory: false },
|
|
38
|
+
} );
|
|
39
|
+
try {
|
|
40
|
+
const parser = new DOMParser();
|
|
41
|
+
xml = parser.parseFromString( xmlStructure, 'application/xml' );
|
|
42
|
+
const errorNode = xml.querySelector( 'parsererror' );
|
|
43
|
+
if ( errorNode ) {
|
|
44
|
+
throw new Error( 'Failed to parse XML structure: ' + errorNode.textContent );
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const children = Array.from( xml.children );
|
|
48
|
+
const iterate = ( node: Element, containerElement: V1Element ) => {
|
|
49
|
+
const elementTag = node.tagName;
|
|
50
|
+
if ( ! widgetsCache[ elementTag ] ) {
|
|
51
|
+
errors.push( new Error( `Unknown widget type: ${ elementTag }` ) );
|
|
52
|
+
}
|
|
53
|
+
const isContainer = elementTag === 'e-flexbox' || elementTag === 'e-div-block';
|
|
54
|
+
const newElement = isContainer
|
|
55
|
+
? createElement( {
|
|
56
|
+
containerId: containerElement.id,
|
|
57
|
+
model: {
|
|
58
|
+
elType: elementTag,
|
|
59
|
+
id: generateElementId(),
|
|
60
|
+
},
|
|
61
|
+
options: { useHistory: false },
|
|
62
|
+
} )
|
|
63
|
+
: createElement( {
|
|
64
|
+
containerId: containerElement.id,
|
|
65
|
+
model: {
|
|
66
|
+
elType: 'widget',
|
|
67
|
+
widgetType: elementTag,
|
|
68
|
+
id: generateElementId(),
|
|
69
|
+
},
|
|
70
|
+
options: { useHistory: false },
|
|
71
|
+
} );
|
|
72
|
+
node.setAttribute( 'id', newElement.id );
|
|
73
|
+
const configId = node.getAttribute( 'configuration-id' ) || '';
|
|
74
|
+
try {
|
|
75
|
+
const configObject = elementConfig[ configId ] || {};
|
|
76
|
+
const styleObject = stylesConfig[ configId ] || {};
|
|
77
|
+
configObject._styles = styleObject;
|
|
78
|
+
for ( const [ propertyName, propertyValue ] of Object.entries( configObject ) ) {
|
|
79
|
+
// validate property existance
|
|
80
|
+
const widgetSchema = widgetsCache[ elementTag ];
|
|
81
|
+
if ( ! widgetSchema?.atomic_props_schema?.[ propertyName ] && propertyName !== '_styles' ) {
|
|
82
|
+
softErrors.push(
|
|
83
|
+
new Error(
|
|
84
|
+
`Property "${ propertyName }" does not exist on element type "${ elementTag }".`
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
doUpdateElementProperty( {
|
|
91
|
+
elementId: newElement.id,
|
|
92
|
+
propertyName,
|
|
93
|
+
propertyValue: propertyValue as unknown as PropValue,
|
|
94
|
+
elementType: elementTag,
|
|
95
|
+
} );
|
|
96
|
+
} catch ( error ) {
|
|
97
|
+
softErrors.push( error as Error );
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if ( isContainer ) {
|
|
101
|
+
for ( const child of node.children ) {
|
|
102
|
+
iterate( child, newElement );
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
node.innerHTML = '';
|
|
106
|
+
node.removeAttribute( 'configuration' );
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
for ( const childNode of children ) {
|
|
113
|
+
iterate( childNode, rootContainer );
|
|
114
|
+
try {
|
|
115
|
+
} catch ( error ) {
|
|
116
|
+
errors.push( error as Error );
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch ( error ) {
|
|
120
|
+
errors.push( error as Error );
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if ( errors.length ) {
|
|
124
|
+
deleteElement( {
|
|
125
|
+
elementId: rootContainer.id,
|
|
126
|
+
options: { useHistory: false },
|
|
127
|
+
} );
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if ( errors.length > 0 ) {
|
|
131
|
+
const errorText = `Failed to build composition with the following errors:\n\n
|
|
132
|
+
${ errors.map( ( e ) => ( typeof e === 'string' ? e : e.message ) ).join( '\n\n' ) }
|
|
133
|
+
"Missing $$type" errors indicate that the configuration objects are invalid. Try again and apply **ALL** object entries with correct $$type.
|
|
134
|
+
Now that you have these errors, fix them and try again. Errors regarding configuration objects, please check again the PropType schemas`;
|
|
135
|
+
throw new Error( errorText );
|
|
136
|
+
}
|
|
137
|
+
if ( ! xml ) {
|
|
138
|
+
throw new Error( 'XML structure is null after parsing.' );
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
xmlStructure: new XMLSerializer().serializeToString( xml ),
|
|
142
|
+
llmInstructions:
|
|
143
|
+
( softErrors.length
|
|
144
|
+
? `The composition was built successfully, but there were some issues with the provided configurations:
|
|
145
|
+
|
|
146
|
+
${ softErrors.map( ( e ) => `- ${ e.message }` ).join( '\n' ) }
|
|
147
|
+
|
|
148
|
+
Please use confiugure-element tool to fix these issues. Now that you have information about these issues, use the configure-element tool to fix them!`
|
|
149
|
+
: '' ) +
|
|
150
|
+
`
|
|
151
|
+
Next Steps:
|
|
152
|
+
- Use "apply-global-class" tool as there may be global styles ready to be applied to elements.
|
|
153
|
+
- Use "configure-element" tool to further configure elements as needed, including styles.
|
|
154
|
+
`,
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
} );
|
|
158
|
+
};
|