@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.
@@ -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
- configObject._styles = styleObject;
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 again the PropType schemas`;
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 property values correctly.
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 "_styles" configuration property.
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 _styles property in the configuration.
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 _styles, use the style schema provided, as it also uses the PropType format.
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
- _styles: {
71
- // List of available keys available at the [${ STYLE_SCHEMA_URI }] dynamic resource
72
- 'line-height': {
73
- $$type: 'size', // MANDATORY do not forget to include the correct $$type for every property
74
- value: {
75
- size: {
76
- $$type: 'number',
77
- value: 20
78
- },
79
- unit: {
80
- $$type: 'string',
81
- value: 'px'
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
- .string()
8
- .describe(
9
- 'The property name. If nested property, provide the root property name, and the object delta only.'
10
- ),
11
- z.any().describe( "The property's value" )
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
- .optional(),
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
- handler: ( { elementId, propertiesToChange, elementType } ) => {
17
- if ( ! propertiesToChange ) {
18
- throw new Error(
19
- 'propertiesToChange is required to configure an element. Now that you have this information, ensure you have the schema and try again.'
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
- '{widgetType}',
64
- elementType
65
- ) }] for type "${ elementType }" to ensure the property exists and the value matches the expected PropType.
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
- propValues: z
11
+ properties: z
12
12
  .record( z.string(), z.any() )
13
- .describe(
14
- 'A record mapping PropTypes to their corresponding PropValues, with _styles record for style-related PropValues'
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 = getWidgetsCache()?.[ element.model.get( 'widgetType' ) || '' ]?.atomic_props_schema;
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
- propValues: {
68
+ properties: {
63
69
  ...propValues,
64
- _styles: stylePropValues,
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 object | string;
52
- if ( typeof customCssValue === 'object' ) {
53
- customCssValue =
54
- stringPropTypeUtil.extract( customCssValue ) ||
55
- ( customCssValue as { value: unknown } )?.value ||
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( `_styles property ${ stylePropName } is not supported.` );
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 value = resolvePropValue( propertyValue );
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
+ };