@elementor/editor-canvas 3.35.0-340 → 3.35.0-341
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.d.mts +66 -62
- package/dist/index.d.ts +66 -62
- package/dist/index.js +757 -364
- package/dist/index.mjs +680 -293
- package/package.json +17 -17
- package/src/index.ts +12 -9
- package/src/mcp/canvas-mcp.ts +2 -0
- package/src/mcp/mcp-description.ts +67 -24
- package/src/mcp/resources/breakpoints-resource.ts +47 -0
- package/src/mcp/resources/widgets-schema-resource.ts +10 -7
- package/src/mcp/tools/build-composition/prompt.ts +222 -20
- package/src/mcp/tools/build-composition/schema.ts +7 -4
- package/src/mcp/tools/build-composition/tool.ts +23 -24
- package/src/mcp/tools/configure-element/prompt.ts +23 -20
- package/src/mcp/tools/configure-element/schema.ts +15 -7
- package/src/mcp/tools/configure-element/tool.ts +62 -18
- package/src/mcp/tools/get-element-config/tool.ts +15 -7
- package/src/mcp/utils/do-update-element-property.ts +16 -16
- package/src/mcp/utils/validate-input.ts +100 -0
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
type V1Element,
|
|
8
8
|
} from '@elementor/editor-elements';
|
|
9
9
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
10
|
-
import { type PropValue } from '@elementor/editor-props';
|
|
11
10
|
|
|
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';
|
|
13
14
|
import { generatePrompt } from './prompt';
|
|
14
15
|
import { inputSchema as schema, outputSchema } from './schema';
|
|
15
16
|
|
|
@@ -20,6 +21,13 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
20
21
|
name: 'build-compositions',
|
|
21
22
|
description: generatePrompt(),
|
|
22
23
|
schema,
|
|
24
|
+
requiredResources: [
|
|
25
|
+
{ description: 'Widgets schema', uri: WIDGET_SCHEMA_URI },
|
|
26
|
+
{ description: 'Global Classes', uri: 'elementor://global-classes' },
|
|
27
|
+
{ description: 'Styles schema', uri: STYLE_SCHEMA_URI },
|
|
28
|
+
{ description: 'Global Variables', uri: 'elementor://global-variables' },
|
|
29
|
+
{ description: 'Styles best practices', uri: BEST_PRACTICES_URI },
|
|
30
|
+
],
|
|
23
31
|
outputSchema,
|
|
24
32
|
handler: async ( params ) => {
|
|
25
33
|
let xml: Document | null = null;
|
|
@@ -70,30 +78,24 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
70
78
|
try {
|
|
71
79
|
const configObject = elementConfig[ configId ] || {};
|
|
72
80
|
const styleObject = stylesConfig[ configId ] || {};
|
|
73
|
-
|
|
81
|
+
const { errors: propsValidationErrors } = validateInput.validatePropSchema(
|
|
82
|
+
elementTag,
|
|
83
|
+
configObject
|
|
84
|
+
);
|
|
85
|
+
errors.push( ...( propsValidationErrors || [] ).map( ( msg ) => new Error( msg ) ) );
|
|
86
|
+
const { errors: stylesValidationErrors } = validateInput.validateStyles( styleObject );
|
|
87
|
+
errors.push( ...( stylesValidationErrors || [] ).map( ( msg ) => new Error( msg ) ) );
|
|
88
|
+
|
|
89
|
+
if ( propsValidationErrors?.length || stylesValidationErrors?.length ) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
configObject._styles = styleObject || {};
|
|
74
93
|
for ( const [ propertyName, propertyValue ] of Object.entries( configObject ) ) {
|
|
75
|
-
// validate property existance
|
|
76
|
-
const widgetSchema = widgetsCache[ elementTag ];
|
|
77
|
-
if (
|
|
78
|
-
! widgetSchema?.atomic_props_schema?.[ propertyName ] &&
|
|
79
|
-
propertyName !== '_styles' &&
|
|
80
|
-
propertyName !== 'custom_css'
|
|
81
|
-
) {
|
|
82
|
-
softErrors.push(
|
|
83
|
-
new Error(
|
|
84
|
-
`Property "${ propertyName }" does not exist on element type "${ elementTag }".`
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
94
|
try {
|
|
90
95
|
doUpdateElementProperty( {
|
|
91
96
|
elementId: newElement.id,
|
|
92
97
|
propertyName,
|
|
93
|
-
propertyValue
|
|
94
|
-
propertyName === 'custom_css'
|
|
95
|
-
? { _styles: propertyValue }
|
|
96
|
-
: ( propertyValue as unknown as PropValue ),
|
|
98
|
+
propertyValue,
|
|
97
99
|
elementType: elementTag,
|
|
98
100
|
} );
|
|
99
101
|
} catch ( error ) {
|
|
@@ -130,13 +132,10 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
130
132
|
options: { useHistory: false },
|
|
131
133
|
} );
|
|
132
134
|
} );
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if ( errors.length > 0 ) {
|
|
136
135
|
const errorText = `Failed to build composition with the following errors:\n\n
|
|
137
136
|
${ errors.map( ( e ) => ( typeof e === 'string' ? e : e.message ) ).join( '\n\n' ) }
|
|
138
137
|
"Missing $$type" errors indicate that the configuration objects are invalid. Try again and apply **ALL** object entries with correct $$type.
|
|
139
|
-
Now that you have these errors, fix them and try again. Errors regarding configuration objects, please check
|
|
138
|
+
Now that you have these errors, fix them and try again. Errors regarding configuration objects, please check against the PropType schemas`;
|
|
140
139
|
throw new Error( errorText );
|
|
141
140
|
}
|
|
142
141
|
if ( ! xml ) {
|
|
@@ -5,10 +5,10 @@ export const configureElementToolPrompt = `Configure an existing element on the
|
|
|
5
5
|
# **CRITICAL - REQUIRED INFORMATION (Must read before using this tool)**
|
|
6
6
|
1. [${ WIDGET_SCHEMA_URI }]
|
|
7
7
|
Required to understand which widgets are available, and what are their configuration schemas.
|
|
8
|
-
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
|
|
8
|
+
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 parameter values correctly.
|
|
9
9
|
2. [${ STYLE_SCHEMA_URI }]
|
|
10
10
|
Required to understand the styles schema for the widgets. All widgets share the same styles schema, grouped by categories.
|
|
11
|
-
Use this resource to understand which style properties are available for each element, and how to structure the "
|
|
11
|
+
Use this resource to understand which style properties are available for each element, and how to structure the "stylePropertiesToChange" parameter.
|
|
12
12
|
3. If not sure about the PropValues schema, you can use the "get-element-configuration-values" tool to retreive the current PropValues configuration of the element.
|
|
13
13
|
|
|
14
14
|
Before using this tool, check the definitions of the elements PropTypes at the resource "widget-schema-by-type" at editor-canvas__elementor://widgets/schema/{widgetType}
|
|
@@ -16,16 +16,18 @@ All widgets share a common _style property for styling, which uses the common st
|
|
|
16
16
|
Retreive and check the common styles schema at the resource list "styles-schema" at editor-canvas__elementor://styles/schema/{category}
|
|
17
17
|
|
|
18
18
|
# Parameters
|
|
19
|
-
- propertiesToChange: An object containing the properties to change, with their new values. MANDATORY
|
|
19
|
+
- propertiesToChange: An object containing the properties to change, with their new values. MANDATORY. When updating a style only, provide an empty object.
|
|
20
|
+
- stylePropertiesToChange: An object containing the style properties to change, with their new values. OPTIONAL
|
|
20
21
|
- elementId: The ID of the element to configure. MANDATORY
|
|
21
22
|
- elementType: The type of the element to configure (i.e. e-heading, e-button). MANDATORY
|
|
22
23
|
|
|
23
24
|
# When to use this tool
|
|
24
25
|
When a user requires to change anything in an element, such as updating text, colors, sizes, or other configurable properties.
|
|
25
26
|
This tool handles elements of type "widget".
|
|
26
|
-
This tool handles styling elements, using the
|
|
27
|
+
This tool handles styling elements, using the "stylePropertiesToChange" parameter.
|
|
27
28
|
|
|
28
29
|
The element's schema must be known before using this tool.
|
|
30
|
+
The style schema must be known before using this tool.
|
|
29
31
|
|
|
30
32
|
Attached resource link describing how PropType schema should be parsed as PropValue for this tool.
|
|
31
33
|
|
|
@@ -43,13 +45,13 @@ ALWAYS MAKE SURE you have the PropType schemas for the element you are configuri
|
|
|
43
45
|
|
|
44
46
|
You can use multiple property changes at once by providing multiple entries in the propertiesToChange object, including _style alongside non-style props.
|
|
45
47
|
Some properties are nested, use the root property name, then objects with nested values inside, as the complete schema suggests.
|
|
46
|
-
Nested properties, such as for the _styles, should include a "_styles" property with object containing the definitions to change.
|
|
47
48
|
|
|
48
49
|
Make sure you have the "widget-schema-by-type" resource available to retreive the PropType schema for the element type you are configuring.
|
|
50
|
+
Make sure you have to "styles-schema" resources available to retreive the common styles schema.
|
|
49
51
|
|
|
50
52
|
# How to configure elements
|
|
51
53
|
We use a dedicated PropType Schema for configuring elements, including styles. When you configure an element, you must use the EXACT PropType Value as defined in the schema.
|
|
52
|
-
For
|
|
54
|
+
For styleProperties, use the style schema provided, as it also uses the PropType format.
|
|
53
55
|
For all non-primitive types, provide the key property as defined in the schema as $$type in the generated objecct, as it is MANDATORY for parsing.
|
|
54
56
|
|
|
55
57
|
Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property from the original configuration for every property you are changing.
|
|
@@ -67,23 +69,24 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
|
|
|
67
69
|
$$type: 'boolean',
|
|
68
70
|
value: false
|
|
69
71
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
72
|
+
},
|
|
73
|
+
stylePropertiesToChange: {
|
|
74
|
+
'line-height': {
|
|
75
|
+
$$type: 'size', // MANDATORY do not forget to include the correct $$type for every property
|
|
76
|
+
value: {
|
|
77
|
+
size: {
|
|
78
|
+
$$type: 'number',
|
|
79
|
+
value: 20
|
|
80
|
+
},
|
|
81
|
+
unit: {
|
|
82
|
+
$$type: 'string',
|
|
83
|
+
value: 'px'
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
|
-
}
|
|
87
|
+
},
|
|
88
|
+
elementId: 'element-id',
|
|
89
|
+
elementType: 'element-type'
|
|
87
90
|
};
|
|
88
91
|
\`\`\`
|
|
89
92
|
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { z } from '@elementor/schema';
|
|
2
2
|
|
|
3
|
+
import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
4
|
+
|
|
3
5
|
export const inputSchema = {
|
|
4
6
|
propertiesToChange: z
|
|
5
7
|
.record(
|
|
8
|
+
z.string().describe( 'The property name.' ),
|
|
6
9
|
z
|
|
7
|
-
.
|
|
8
|
-
.describe(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
.any()
|
|
11
|
+
.describe( `PropValue, refer to [${ WIDGET_SCHEMA_URI }] by correct type, as appears in elementType` ),
|
|
12
|
+
z.any()
|
|
13
|
+
)
|
|
14
|
+
.describe( 'An object record containing property names and their new values to be set on the element' ),
|
|
15
|
+
stylePropertiesToChange: z
|
|
16
|
+
.record(
|
|
17
|
+
z.string().describe( 'The style property name' ),
|
|
18
|
+
z.any().describe( `The style PropValue, refer to [${ STYLE_SCHEMA_URI }] how to generate values` ),
|
|
19
|
+
z.any()
|
|
12
20
|
)
|
|
13
|
-
.describe( 'An object record containing property names and their new values to be set on the element' )
|
|
14
|
-
.
|
|
21
|
+
.describe( 'An object record containing style property names and their new values to be set on the element' )
|
|
22
|
+
.default( {} ),
|
|
15
23
|
elementType: z.string().describe( 'The type of the element to retreive the schema' ),
|
|
16
24
|
elementId: z.string().describe( 'The unique id of the element to configure' ),
|
|
17
25
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
|
-
import { WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
3
|
+
import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
4
4
|
import { doUpdateElementProperty } from '../../utils/do-update-element-property';
|
|
5
|
+
import { validateInput } from '../../utils/validate-input';
|
|
5
6
|
import { configureElementToolPrompt } from './prompt';
|
|
6
7
|
import { inputSchema as schema, outputSchema } from './schema';
|
|
7
8
|
|
|
@@ -13,20 +14,29 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
|
|
|
13
14
|
description: configureElementToolPrompt,
|
|
14
15
|
schema,
|
|
15
16
|
outputSchema,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
17
|
+
requiredResources: [
|
|
18
|
+
{ description: 'Widgets schema', uri: WIDGET_SCHEMA_URI },
|
|
19
|
+
{ description: 'Styles schema', uri: STYLE_SCHEMA_URI },
|
|
20
|
+
],
|
|
21
|
+
handler: ( { elementId, propertiesToChange, elementType, stylePropertiesToChange } ) => {
|
|
22
22
|
const toUpdate = Object.entries( propertiesToChange );
|
|
23
|
+
const { valid, errors } = validateInput.validatePropSchema( elementType, propertiesToChange );
|
|
24
|
+
const { valid: stylesValid, errors: stylesErrors } = validateInput.validateStyles(
|
|
25
|
+
stylePropertiesToChange || {}
|
|
26
|
+
);
|
|
27
|
+
if ( ! valid ) {
|
|
28
|
+
const errorMessage = `Failed to configure element "${ elementId }" due to invalid properties: ${ errors?.join(
|
|
29
|
+
'\n- '
|
|
30
|
+
) }`;
|
|
31
|
+
throw new Error( errorMessage );
|
|
32
|
+
}
|
|
33
|
+
if ( ! stylesValid ) {
|
|
34
|
+
const errorMessage = `Failed to configure element "${ elementId }" due to invalid style properties: ${ stylesErrors?.join(
|
|
35
|
+
'\n- '
|
|
36
|
+
) }`;
|
|
37
|
+
throw new Error( errorMessage );
|
|
38
|
+
}
|
|
23
39
|
for ( const [ propertyName, propertyValue ] of toUpdate ) {
|
|
24
|
-
if ( ! propertyName && ! elementId && ! elementType ) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
'propertyName, elementId, elementType are required to configure an element. If you want to retreive the schema, use the get-element-configuration-schema tool.'
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
40
|
try {
|
|
31
41
|
doUpdateElementProperty( {
|
|
32
42
|
elementId,
|
|
@@ -40,6 +50,28 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
|
|
|
40
50
|
elementId,
|
|
41
51
|
elementType,
|
|
42
52
|
error: error as Error,
|
|
53
|
+
propertyType: 'prop',
|
|
54
|
+
} );
|
|
55
|
+
throw new Error( errorMessage );
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for ( const [ stylePropertyName, stylePropertyValue ] of Object.entries( stylePropertiesToChange || {} ) ) {
|
|
59
|
+
try {
|
|
60
|
+
doUpdateElementProperty( {
|
|
61
|
+
elementId,
|
|
62
|
+
elementType,
|
|
63
|
+
propertyName: '_styles',
|
|
64
|
+
propertyValue: {
|
|
65
|
+
[ stylePropertyName ]: stylePropertyValue,
|
|
66
|
+
},
|
|
67
|
+
} );
|
|
68
|
+
} catch ( error ) {
|
|
69
|
+
const errorMessage = createUpdateErrorMessage( {
|
|
70
|
+
propertyName: `(style) ${ stylePropertyName }`,
|
|
71
|
+
elementId,
|
|
72
|
+
elementType,
|
|
73
|
+
propertyType: 'style',
|
|
74
|
+
error: error as Error,
|
|
43
75
|
} );
|
|
44
76
|
throw new Error( errorMessage );
|
|
45
77
|
}
|
|
@@ -56,12 +88,24 @@ function createUpdateErrorMessage( opts: {
|
|
|
56
88
|
elementId: string;
|
|
57
89
|
elementType: string;
|
|
58
90
|
error: Error;
|
|
91
|
+
propertyType: 'prop' | 'style';
|
|
59
92
|
} ) {
|
|
60
|
-
const { propertyName, elementId, elementType, error } = opts;
|
|
93
|
+
const { propertyName, elementId, elementType, error, propertyType } = opts;
|
|
61
94
|
return `Failed to update property "${ propertyName }" on element "${ elementId }": ${ error.message }.
|
|
95
|
+
${
|
|
96
|
+
propertyType === 'prop'
|
|
97
|
+
? `
|
|
62
98
|
Check the element's PropType schema at the resource [${ WIDGET_SCHEMA_URI.replace(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Now that you have this information, ensure you have the schema and try again
|
|
99
|
+
'{widgetType}',
|
|
100
|
+
elementType
|
|
101
|
+
) }] for type "${ elementType }" to ensure the property exists and the value matches the expected PropType.
|
|
102
|
+
Now that you have this information, ensure you have the schema and try again.`
|
|
103
|
+
: `
|
|
104
|
+
Check the styles schema at the resource [${ STYLE_SCHEMA_URI.replace(
|
|
105
|
+
'{category}',
|
|
106
|
+
propertyName
|
|
107
|
+
) }] at editor-canvas__elementor://styles/schema/{category} to ensure the style property exists and the value matches the expected PropType.
|
|
108
|
+
`
|
|
109
|
+
};
|
|
110
|
+
}`;
|
|
67
111
|
}
|
|
@@ -8,11 +8,12 @@ const schema = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
const outputSchema = {
|
|
11
|
-
|
|
11
|
+
properties: z
|
|
12
12
|
.record( z.string(), z.any() )
|
|
13
|
-
.describe(
|
|
14
|
-
|
|
15
|
-
),
|
|
13
|
+
.describe( 'A record mapping PropTypes to their corresponding PropValues' ),
|
|
14
|
+
style: z
|
|
15
|
+
.record( z.string(), z.any() )
|
|
16
|
+
.describe( 'A record mapping StyleSchema properties to their corresponding PropValues' ),
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
|
|
@@ -29,7 +30,9 @@ export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
|
|
|
29
30
|
throw new Error( `Element with ID ${ elementId } not found.` );
|
|
30
31
|
}
|
|
31
32
|
const elementRawSettings = element.settings;
|
|
32
|
-
const propSchema =
|
|
33
|
+
const propSchema =
|
|
34
|
+
getWidgetsCache()?.[ element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '' ]
|
|
35
|
+
?.atomic_props_schema;
|
|
33
36
|
|
|
34
37
|
if ( ! elementRawSettings || ! propSchema ) {
|
|
35
38
|
throw new Error( `No settings or prop schema found for element ID: ${ elementId }` );
|
|
@@ -55,13 +58,18 @@ export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
|
|
|
55
58
|
stylePropValues[ stylePropName ] = structuredClone( styleProps[ stylePropName ] );
|
|
56
59
|
}
|
|
57
60
|
} );
|
|
61
|
+
if ( defaultVariant.custom_css ) {
|
|
62
|
+
stylePropValues.custom_css = atob( defaultVariant.custom_css.raw );
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
return {
|
|
62
|
-
|
|
68
|
+
properties: {
|
|
63
69
|
...propValues,
|
|
64
|
-
|
|
70
|
+
},
|
|
71
|
+
style: {
|
|
72
|
+
...stylePropValues,
|
|
65
73
|
},
|
|
66
74
|
};
|
|
67
75
|
},
|
|
@@ -5,13 +5,7 @@ import {
|
|
|
5
5
|
updateElementSettings,
|
|
6
6
|
updateElementStyle,
|
|
7
7
|
} from '@elementor/editor-elements';
|
|
8
|
-
import {
|
|
9
|
-
getPropSchemaFromCache,
|
|
10
|
-
type PropValue,
|
|
11
|
-
Schema,
|
|
12
|
-
stringPropTypeUtil,
|
|
13
|
-
type TransformablePropValue,
|
|
14
|
-
} from '@elementor/editor-props';
|
|
8
|
+
import { getPropSchemaFromCache, type PropValue, Schema, type TransformablePropValue } from '@elementor/editor-props';
|
|
15
9
|
import { type CustomCss, getStylesSchema } from '@elementor/editor-styles';
|
|
16
10
|
|
|
17
11
|
type OwnParams = {
|
|
@@ -22,9 +16,13 @@ type OwnParams = {
|
|
|
22
16
|
};
|
|
23
17
|
|
|
24
18
|
function resolvePropValue( value: unknown, forceKey?: string ): PropValue {
|
|
25
|
-
return Schema.adjustLlmPropValueSchema( value as PropValue, forceKey );
|
|
19
|
+
return Schema.adjustLlmPropValueSchema( value as PropValue, { forceKey } );
|
|
26
20
|
}
|
|
27
21
|
|
|
22
|
+
/*
|
|
23
|
+
* This function expects a PropValue bag for updaing an element.
|
|
24
|
+
* Also, it supports updating styles "on-the-way" by checking for "_styles" property with PropValue bag that fits the common style schema.
|
|
25
|
+
*/
|
|
28
26
|
export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
29
27
|
const { elementId, propertyName, propertyValue, elementType } = params;
|
|
30
28
|
|
|
@@ -48,12 +46,12 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
|
48
46
|
Object.keys( propertyMapValue as Record< string, unknown > ).forEach( ( stylePropName ) => {
|
|
49
47
|
const propertyRawSchema = styleSchema[ stylePropName ];
|
|
50
48
|
if ( stylePropName === 'custom_css' ) {
|
|
51
|
-
let customCssValue = propertyMapValue[ stylePropName ] as
|
|
52
|
-
if ( typeof customCssValue === 'object' ) {
|
|
53
|
-
customCssValue =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
let customCssValue = propertyMapValue[ stylePropName ] as Record< string, unknown > | string;
|
|
50
|
+
if ( typeof customCssValue === 'object' && customCssValue && customCssValue.value ) {
|
|
51
|
+
customCssValue = String( customCssValue.value );
|
|
52
|
+
}
|
|
53
|
+
if ( ! customCssValue ) {
|
|
54
|
+
customCssValue = '';
|
|
57
55
|
}
|
|
58
56
|
customCss = {
|
|
59
57
|
raw: btoa( customCssValue as string ),
|
|
@@ -62,7 +60,7 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
|
62
60
|
}
|
|
63
61
|
const isSupported = !! propertyRawSchema;
|
|
64
62
|
if ( ! isSupported ) {
|
|
65
|
-
throw new Error( `
|
|
63
|
+
throw new Error( `Style property ${ stylePropName } is not supported.` );
|
|
66
64
|
}
|
|
67
65
|
if ( propertyRawSchema.kind === 'plain' ) {
|
|
68
66
|
if ( typeof ( propertyMapValue as Record< string, unknown > )[ stylePropName ] !== 'object' ) {
|
|
@@ -74,6 +72,7 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
|
74
72
|
}
|
|
75
73
|
}
|
|
76
74
|
} );
|
|
75
|
+
delete transformedStyleValues.custom_css;
|
|
77
76
|
const localStyle = Object.values( elementStyles ).find( ( style ) => style.label === 'local' );
|
|
78
77
|
if ( ! localStyle ) {
|
|
79
78
|
createElementStyle( {
|
|
@@ -118,7 +117,8 @@ export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
|
118
117
|
) }`
|
|
119
118
|
);
|
|
120
119
|
}
|
|
121
|
-
const
|
|
120
|
+
const propKey = elementPropSchema[ propertyName ].key;
|
|
121
|
+
const value = resolvePropValue( propertyValue, propKey );
|
|
122
122
|
updateElementSettings( {
|
|
123
123
|
id: elementId,
|
|
124
124
|
props: {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getWidgetsCache } from '@elementor/editor-elements';
|
|
2
|
+
import { type PropsSchema, type PropValue, Schema } from '@elementor/editor-props';
|
|
3
|
+
import { getStylesSchema } from '@elementor/editor-styles';
|
|
4
|
+
|
|
5
|
+
let _widgetsSchema: Record< string, PropsSchema > | null = null;
|
|
6
|
+
|
|
7
|
+
type ValidationResult = {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
errors?: string[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const validateInput = {
|
|
13
|
+
get widgetsSchema(): Record< string, PropsSchema > {
|
|
14
|
+
if ( ! _widgetsSchema ) {
|
|
15
|
+
const schema: Record< string, PropsSchema > = {};
|
|
16
|
+
const cache = getWidgetsCache();
|
|
17
|
+
if ( ! cache ) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
Object.entries( cache ).forEach( ( [ widgetType, widgetData ] ) => {
|
|
21
|
+
if ( widgetData.atomic_props_schema ) {
|
|
22
|
+
schema[ widgetType ] = structuredClone( widgetData.atomic_props_schema );
|
|
23
|
+
}
|
|
24
|
+
} );
|
|
25
|
+
_widgetsSchema = schema;
|
|
26
|
+
}
|
|
27
|
+
return _widgetsSchema;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
validateProps(
|
|
31
|
+
schema: PropsSchema | undefined | null,
|
|
32
|
+
values: Record< string, unknown >,
|
|
33
|
+
ignore: string[] = []
|
|
34
|
+
): ValidationResult {
|
|
35
|
+
if ( ! schema ) {
|
|
36
|
+
throw new Error( 'No schema provided for validation.' );
|
|
37
|
+
}
|
|
38
|
+
const errors: string[] = [];
|
|
39
|
+
let hasInvalidKey = false;
|
|
40
|
+
Object.entries( values ).forEach( ( [ propName, propValue ] ) => {
|
|
41
|
+
if ( ignore.includes( propName ) ) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const propSchema = schema[ propName ];
|
|
45
|
+
if ( ! propSchema ) {
|
|
46
|
+
errors.push( `Property "${ propName }" is not defined in the schema.` );
|
|
47
|
+
hasInvalidKey = true;
|
|
48
|
+
} else if ( ! Schema.isPropKeyConfigurable( propName ) ) {
|
|
49
|
+
errors.push( `Property "${ propName }" is not configurable.` );
|
|
50
|
+
} else {
|
|
51
|
+
const { valid, errorMessages } = Schema.validatePropValue( propSchema, propValue as PropValue );
|
|
52
|
+
if ( ! valid ) {
|
|
53
|
+
errors.push( `Invalid property "${ propName }": ${ errorMessages }` );
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} );
|
|
57
|
+
if ( hasInvalidKey ) {
|
|
58
|
+
errors.push( 'Available properties: ' + Object.keys( schema ).join( ', ' ) );
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
errors,
|
|
62
|
+
valid: errors.length === 0,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
validateStyles( values: Record< string, unknown > ): ValidationResult {
|
|
67
|
+
const styleSchema = getStylesSchema();
|
|
68
|
+
const customCssValue = values.custom_css;
|
|
69
|
+
const result = this.validateProps( styleSchema, values, [ 'custom_css' ] );
|
|
70
|
+
const appendInvalidCustomCssErr = () => {
|
|
71
|
+
result.valid = false;
|
|
72
|
+
result.errors = result.errors || [];
|
|
73
|
+
result.errors.push( 'Invalid property "custom_css". Expected a string value.' );
|
|
74
|
+
};
|
|
75
|
+
if ( customCssValue && typeof customCssValue === 'object' ) {
|
|
76
|
+
if ( typeof ( customCssValue as Record< string, unknown > ).value !== 'string' ) {
|
|
77
|
+
appendInvalidCustomCssErr();
|
|
78
|
+
}
|
|
79
|
+
} else if (
|
|
80
|
+
typeof customCssValue !== 'string' &&
|
|
81
|
+
typeof customCssValue !== 'undefined' &&
|
|
82
|
+
customCssValue !== null
|
|
83
|
+
) {
|
|
84
|
+
appendInvalidCustomCssErr();
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
validatePropSchema(
|
|
90
|
+
widgetType: string,
|
|
91
|
+
values: Record< string, unknown >,
|
|
92
|
+
ignore: string[] = []
|
|
93
|
+
): ValidationResult {
|
|
94
|
+
const schema = this.widgetsSchema[ widgetType ];
|
|
95
|
+
if ( ! schema ) {
|
|
96
|
+
return { valid: false, errors: [ `No schema found for widget type "${ widgetType }".` ] };
|
|
97
|
+
}
|
|
98
|
+
return this.validateProps( schema, values, ignore );
|
|
99
|
+
},
|
|
100
|
+
};
|