@elementor/editor-canvas 4.1.0 → 4.2.0-840
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 +22 -4
- package/dist/index.d.ts +22 -4
- package/dist/index.js +773 -137
- package/dist/index.mjs +730 -86
- package/package.json +18 -18
- package/src/__tests__/settings-props-resolver.test.ts +3 -0
- package/src/composition-builder/composition-builder.ts +5 -5
- package/src/form-structure/utils.ts +4 -0
- package/src/hooks/__tests__/use-style-items.test.ts +55 -0
- package/src/hooks/use-style-items.ts +12 -14
- package/src/index.ts +2 -0
- package/src/init-settings-transformers.ts +4 -0
- package/src/init-style-transformers.ts +2 -0
- package/src/legacy/create-nested-templated-element-type.ts +11 -2
- package/src/legacy/create-pending-element.ts +74 -0
- package/src/legacy/create-templated-element-type.ts +2 -2
- package/src/legacy/types.ts +9 -1
- package/src/mcp/canvas-mcp.ts +8 -0
- package/src/mcp/resources/available-widgets-resource.ts +67 -0
- package/src/mcp/resources/document-structure-resource.ts +51 -36
- package/src/mcp/resources/editor-state-resource.ts +122 -0
- package/src/mcp/resources/general-context-resource.ts +99 -0
- package/src/mcp/resources/selected-element-resource.ts +217 -0
- package/src/mcp/resources/widgets-schema-resource.ts +74 -14
- package/src/mcp/tools/build-composition/prompt.ts +6 -0
- package/src/mcp/tools/build-composition/tool.ts +26 -0
- package/src/mcp/tools/configure-element/prompt.ts +6 -6
- package/src/mcp/tools/configure-element/schema.ts +1 -1
- package/src/mcp/tools/configure-element/tool.ts +12 -0
- package/src/mcp/tools/get-element-config/tool.ts +13 -3
- package/src/mcp/utils/do-update-element-property.ts +1 -1
- package/src/mcp/utils/element-data-util.ts +46 -0
- package/src/mcp/utils/validate-input.ts +1 -1
- package/src/sync/global-styles-imported-event.ts +8 -0
- package/src/transformers/settings/date-range-transformer.ts +12 -0
- package/src/transformers/settings/time-range-transformer.ts +12 -0
- package/src/transformers/shared/image-src-transformer.ts +2 -0
- package/src/transformers/shared/image-transformer.ts +4 -1
- package/src/transformers/styles/span-transformer.ts +5 -0
- package/src/utils/after-render.ts +26 -0
- package/src/mcp/utils/generate-available-tags.ts +0 -23
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { toolPrompts } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
|
+
import { AVAILABLE_WIDGETS_URI } from '../../resources/available-widgets-resource';
|
|
4
|
+
|
|
3
5
|
export const generatePrompt = () => {
|
|
4
6
|
const buildCompositionsToolPrompt = toolPrompts( 'build-compositions' );
|
|
5
7
|
|
|
@@ -7,6 +9,10 @@ export const generatePrompt = () => {
|
|
|
7
9
|
# RESOURCES (Read before use)
|
|
8
10
|
- [elementor://global-classes] - Check FIRST for reusable classes
|
|
9
11
|
- [elementor://global-variables] - ONLY use variables defined here
|
|
12
|
+
- [${ AVAILABLE_WIDGETS_URI }/v4]
|
|
13
|
+
|
|
14
|
+
# TOOL SUPPORT
|
|
15
|
+
This tool support v4 elements only
|
|
10
16
|
|
|
11
17
|
# WORKFLOW
|
|
12
18
|
1. Check/create global classes via "create-global-class" tool
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
10
10
|
|
|
11
11
|
import { CompositionBuilder } from '../../../composition-builder/composition-builder';
|
|
12
|
+
import { AVAILABLE_WIDGETS_URI_V4 } from '../../resources/available-widgets-resource';
|
|
12
13
|
import { BEST_PRACTICES_URI, STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
13
14
|
import { doUpdateElementProperty } from '../../utils/do-update-element-property';
|
|
14
15
|
import { getCompositionTargetContainer } from '../../utils/get-composition-target-container';
|
|
@@ -28,12 +29,14 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
|
|
|
28
29
|
{ description: 'Global Classes', uri: 'elementor://global-classes' },
|
|
29
30
|
{ description: 'Global Variables', uri: 'elementor://global-variables' },
|
|
30
31
|
{ description: 'Styles best practices', uri: BEST_PRACTICES_URI },
|
|
32
|
+
{ description: 'Available widgets for this tool', uri: AVAILABLE_WIDGETS_URI_V4 },
|
|
31
33
|
],
|
|
32
34
|
outputSchema,
|
|
33
35
|
modelPreferences: {
|
|
34
36
|
hints: [ { name: 'claude-sonnet-4-5' } ],
|
|
35
37
|
},
|
|
36
38
|
handler: async ( params ) => {
|
|
39
|
+
assertCompositionXmlUsesV4WidgetsOnly( params.xmlStructure );
|
|
37
40
|
const { xmlStructure, elementConfig, stylesConfig, customCSS } = params;
|
|
38
41
|
let generatedXML: string = '';
|
|
39
42
|
const errors: Error[] = [];
|
|
@@ -132,3 +135,26 @@ Remember: Global classes ensure design consistency and reusability. Don't skip a
|
|
|
132
135
|
},
|
|
133
136
|
} );
|
|
134
137
|
};
|
|
138
|
+
|
|
139
|
+
function assertCompositionXmlUsesV4WidgetsOnly( xmlStructure: string ) {
|
|
140
|
+
const doc = new DOMParser().parseFromString( xmlStructure, 'application/xml' );
|
|
141
|
+
if ( doc.querySelector( 'parsererror' ) ) {
|
|
142
|
+
throw new Error( 'Failed to parse XML string: ' + doc );
|
|
143
|
+
}
|
|
144
|
+
const widgetsCache = getWidgetsCache() ?? {};
|
|
145
|
+
for ( const node of doc.querySelectorAll( '*' ) ) {
|
|
146
|
+
const type = node.tagName;
|
|
147
|
+
const widgetData = widgetsCache[ type ];
|
|
148
|
+
if ( ! widgetData ) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if ( widgetData.elType !== 'widget' ) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if ( ! widgetData.atomic_props_schema ) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${ type }`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -9,11 +9,11 @@ export const configureElementToolPrompt = `Configure an existing element on the
|
|
|
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
11
|
Use this resource to understand which style properties are available for each element, and how to structure the "stylePropertiesToChange" parameter.
|
|
12
|
-
3. If not sure about the PropValues schema, you can use the "get-element-configuration-values" tool to
|
|
12
|
+
3. If not sure about the PropValues schema, you can use the "get-element-configuration-values" tool to retrieve 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}
|
|
15
15
|
All widgets share a common _style property for styling, which uses the common styles schema.
|
|
16
|
-
|
|
16
|
+
Retrieve 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
19
|
- propertiesToChange: An object containing the properties to change, with their new values. MANDATORY. When updating a style only, provide an empty object.
|
|
@@ -42,19 +42,19 @@ PropValue structure:
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
<IMPORTANT>
|
|
45
|
-
ALWAYS MAKE SURE you have the PropType schemas for the element you are configuring, and the common-styles schema for styling. If you are not sure,
|
|
45
|
+
ALWAYS MAKE SURE you have the PropType schemas for the element you are configuring, and the common-styles schema for styling. If you are not sure, retrieve the schema from the resources mentioned above.
|
|
46
46
|
</IMPORTANT>
|
|
47
47
|
|
|
48
48
|
You can use multiple property changes at once by providing multiple entries in the propertiesToChange object, including _style alongside non-style props.
|
|
49
49
|
Some properties are nested, use the root property name, then objects with nested values inside, as the complete schema suggests.
|
|
50
50
|
|
|
51
|
-
Make sure you have the "widget-schema-by-type" resource available to
|
|
52
|
-
Make sure you have to "styles-schema" resources available to
|
|
51
|
+
Make sure you have the "widget-schema-by-type" resource available to retrieve the PropType schema for the element type you are configuring.
|
|
52
|
+
Make sure you have to "styles-schema" resources available to retrieve the common styles schema.
|
|
53
53
|
|
|
54
54
|
# How to configure elements
|
|
55
55
|
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.
|
|
56
56
|
For styleProperties, use the style schema provided, as it also uses the PropType format.
|
|
57
|
-
For all non-primitive types, provide the key property as defined in the schema as $$type in the generated
|
|
57
|
+
For all non-primitive types, provide the key property as defined in the schema as $$type in the generated object, as it is MANDATORY for parsing.
|
|
58
58
|
|
|
59
59
|
Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property from the original configuration for every property you are changing.
|
|
60
60
|
|
|
@@ -20,7 +20,7 @@ export const inputSchema = {
|
|
|
20
20
|
)
|
|
21
21
|
.describe( 'An object record containing style property names and their new values to be set on the element' )
|
|
22
22
|
.default( {} ),
|
|
23
|
-
elementType: z.string().describe( 'The type of the element to
|
|
23
|
+
elementType: z.string().describe( 'The type of the element to retrieve the schema' ),
|
|
24
24
|
elementId: z.string().describe( 'The unique id of the element to configure' ),
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getWidgetsCache } from '@elementor/editor-elements';
|
|
1
2
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
3
|
|
|
3
4
|
import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
|
|
@@ -24,6 +25,17 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
|
|
|
24
25
|
speedPriority: 0.7,
|
|
25
26
|
},
|
|
26
27
|
handler: ( { elementId, propertiesToChange, elementType, stylePropertiesToChange } ) => {
|
|
28
|
+
const widgetData = getWidgetsCache()?.[ elementType ];
|
|
29
|
+
if ( ! widgetData ) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Unknown element type: ${ elementType }. Check the available-widgets resource for valid types.`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if ( ! widgetData.atomic_props_schema ) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${ elementType }`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
27
39
|
const toUpdate = Object.entries( propertiesToChange );
|
|
28
40
|
const { valid, errors } = validateInput.validatePropSchema( elementType, propertiesToChange );
|
|
29
41
|
const { valid: stylesValid, errors: stylesErrors } = validateInput.validateStyles(
|
|
@@ -59,10 +59,20 @@ export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
|
|
|
59
59
|
if ( ! element ) {
|
|
60
60
|
throw new Error( `Element with ID ${ elementId } not found.` );
|
|
61
61
|
}
|
|
62
|
+
const elementType = element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '';
|
|
63
|
+
const widgetData = getWidgetsCache()?.[ elementType ];
|
|
64
|
+
if ( ! widgetData ) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Unknown element type: ${ elementType }. Check the available-widgets resource for valid types.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if ( ! widgetData.atomic_props_schema ) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${ elementType }`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
62
74
|
const elementRawSettings = element.settings;
|
|
63
|
-
const propSchema =
|
|
64
|
-
getWidgetsCache()?.[ element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '' ]
|
|
65
|
-
?.atomic_props_schema;
|
|
75
|
+
const propSchema = getWidgetsCache()?.[ elementType ]?.atomic_props_schema;
|
|
66
76
|
|
|
67
77
|
if ( ! elementRawSettings || ! propSchema ) {
|
|
68
78
|
throw new Error( `No settings or prop schema found for element ID: ${ elementId }` );
|
|
@@ -30,7 +30,7 @@ export function resolvePropValue( value: unknown, forceKey?: string ): PropValue
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/*
|
|
33
|
-
* This function expects a PropValue bag for
|
|
33
|
+
* This function expects a PropValue bag for updating an element.
|
|
34
34
|
* Also, it supports updating styles "on-the-way" by checking for "_styles" property with PropValue bag that fits the common style schema.
|
|
35
35
|
*/
|
|
36
36
|
export const doUpdateElementProperty = ( params: OwnParams ) => {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getWidgetsCache, type V1ElementConfig } from '@elementor/editor-elements';
|
|
2
|
+
|
|
3
|
+
export type AvailableWidget = {
|
|
4
|
+
type: string;
|
|
5
|
+
version: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function hasV3Controls( controls: unknown ): boolean {
|
|
10
|
+
return typeof controls === 'object' && controls !== null && Object.keys( controls ).length > 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isWidgetAvailableForLLM( config: V1ElementConfig | undefined ): boolean {
|
|
14
|
+
if ( ! config ) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if ( config.meta?.llm_support === false ) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if ( config.atomic_props_schema ) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return hasV3Controls( config.controls );
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getWidgetVersion( config: V1ElementConfig | undefined ): string {
|
|
27
|
+
return config?.atomic_props_schema ? 'v4' : 'v3';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getAvailableWidgets(): AvailableWidget[] {
|
|
31
|
+
const cache = getWidgetsCache() ?? {};
|
|
32
|
+
|
|
33
|
+
return Object.keys( cache )
|
|
34
|
+
.filter( ( widgetType ) => isWidgetAvailableForLLM( cache[ widgetType ] ) )
|
|
35
|
+
.sort()
|
|
36
|
+
.map( ( widgetType ) => {
|
|
37
|
+
const config = cache[ widgetType ];
|
|
38
|
+
const description = typeof config?.meta?.description === 'string' ? config.meta.description : undefined;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
type: widgetType,
|
|
42
|
+
version: getWidgetVersion( config ),
|
|
43
|
+
...( description && { description } ),
|
|
44
|
+
};
|
|
45
|
+
} );
|
|
46
|
+
}
|
|
@@ -47,7 +47,7 @@ export const validateInput = {
|
|
|
47
47
|
if ( ! propSchema ) {
|
|
48
48
|
errors.push( `Property "${ propName }" is not defined in the schema.` );
|
|
49
49
|
hasInvalidKey = true;
|
|
50
|
-
} else if ( ! Schema.isPropKeyConfigurable( propName ) ) {
|
|
50
|
+
} else if ( ! Schema.isPropKeyConfigurable( propName, propSchema ) ) {
|
|
51
51
|
errors.push( `Property "${ propName }" is not configurable.` );
|
|
52
52
|
} else {
|
|
53
53
|
const { valid } = Schema.validatePropValue( propSchema, propValue as PropValue );
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type StyleDefinitionID, type StyleDefinitionsMap, type StyleVariables } from '@elementor/editor-styles';
|
|
2
|
+
|
|
3
|
+
export const GLOBAL_STYLES_IMPORTED_EVENT = 'elementor/global-styles/imported';
|
|
4
|
+
|
|
5
|
+
export type ImportedGlobalStylesPayload = {
|
|
6
|
+
global_variables?: { data: StyleVariables };
|
|
7
|
+
global_classes?: { items: StyleDefinitionsMap; order: StyleDefinitionID[] };
|
|
8
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createTransformer } from '../create-transformer';
|
|
2
|
+
|
|
3
|
+
export const dateRangeTransformer = createTransformer< { min?: string | null; max?: string | null } >( ( value ) => {
|
|
4
|
+
if ( ! value || Object.keys( value ).length === 0 ) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
min: value.min || null,
|
|
10
|
+
max: value.max || null,
|
|
11
|
+
};
|
|
12
|
+
} );
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createTransformer } from '../create-transformer';
|
|
2
|
+
|
|
3
|
+
export const timeRangeTransformer = createTransformer< { min?: string | null; max?: string | null } >( ( value ) => {
|
|
4
|
+
if ( ! value || Object.keys( value ).length === 0 ) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
min: value.min || null,
|
|
10
|
+
max: value.max || null,
|
|
11
|
+
};
|
|
12
|
+
} );
|
|
@@ -3,9 +3,11 @@ import { createTransformer } from '../create-transformer';
|
|
|
3
3
|
type ImageSrc = {
|
|
4
4
|
id?: unknown;
|
|
5
5
|
url?: unknown;
|
|
6
|
+
alt?: unknown;
|
|
6
7
|
};
|
|
7
8
|
|
|
8
9
|
export const imageSrcTransformer = createTransformer( ( value: ImageSrc ) => ( {
|
|
9
10
|
id: value.id ?? null,
|
|
10
11
|
url: value.url ?? null,
|
|
12
|
+
alt: value.alt ?? null,
|
|
11
13
|
} ) );
|
|
@@ -6,6 +6,7 @@ type Image = {
|
|
|
6
6
|
src?: {
|
|
7
7
|
id: number | null;
|
|
8
8
|
url: string | null;
|
|
9
|
+
alt?: string | null;
|
|
9
10
|
};
|
|
10
11
|
size?: string;
|
|
11
12
|
};
|
|
@@ -14,7 +15,7 @@ export const imageTransformer = createTransformer( async ( value: Image ) => {
|
|
|
14
15
|
const { src, size } = value;
|
|
15
16
|
|
|
16
17
|
if ( ! src?.id ) {
|
|
17
|
-
return src?.url ? { src: src.url } : null;
|
|
18
|
+
return src?.url ? { src: src.url, alt: src.alt ?? '' } : null;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
const attachment = await getMediaAttachment( { id: src.id } );
|
|
@@ -26,6 +27,7 @@ export const imageTransformer = createTransformer( async ( value: Image ) => {
|
|
|
26
27
|
src: sizedAttachment.url,
|
|
27
28
|
height: sizedAttachment.height,
|
|
28
29
|
width: sizedAttachment.width,
|
|
30
|
+
alt: attachment.alt,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -34,6 +36,7 @@ export const imageTransformer = createTransformer( async ( value: Image ) => {
|
|
|
34
36
|
src: attachment.url,
|
|
35
37
|
height: attachment.height,
|
|
36
38
|
width: attachment.width,
|
|
39
|
+
alt: attachment.alt,
|
|
37
40
|
};
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getContainer } from '@elementor/editor-elements';
|
|
2
|
+
|
|
3
|
+
import { type TemplatedElementView } from '../legacy/types';
|
|
4
|
+
|
|
5
|
+
export function doAfterRender( elementIds: string[], callback: ( elementIds: string[] ) => void ): void {
|
|
6
|
+
const pending = elementIds
|
|
7
|
+
.map( ( elementId ) => {
|
|
8
|
+
const view = getContainer( elementId )?.view;
|
|
9
|
+
if ( ! view || ! hasDoAfterRender( view ) ) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return new Promise< void >( ( resolve ) => view._doAfterRender( resolve ) );
|
|
14
|
+
} )
|
|
15
|
+
.filter( Boolean );
|
|
16
|
+
|
|
17
|
+
if ( pending.length > 0 ) {
|
|
18
|
+
Promise.all( pending ).then( () => callback( elementIds ) );
|
|
19
|
+
} else {
|
|
20
|
+
callback( elementIds );
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function hasDoAfterRender( view: unknown ): view is TemplatedElementView {
|
|
25
|
+
return typeof ( view as TemplatedElementView )?._doAfterRender === 'function';
|
|
26
|
+
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { getWidgetsCache, type V1ElementConfig } from '@elementor/editor-elements';
|
|
2
|
-
|
|
3
|
-
type ElTypedElementConfig = V1ElementConfig< {
|
|
4
|
-
elType?: string;
|
|
5
|
-
} >;
|
|
6
|
-
|
|
7
|
-
export const generateAvailableTags = () => {
|
|
8
|
-
const cache = getWidgetsCache< ElTypedElementConfig >();
|
|
9
|
-
if ( ! cache ) {
|
|
10
|
-
return [];
|
|
11
|
-
}
|
|
12
|
-
const customTags = Object.entries( cache )
|
|
13
|
-
.filter( ( [ , widgetData ] ) => !! widgetData.atomic_controls )
|
|
14
|
-
.map( ( [ widgetType, widgetData ] ) => {
|
|
15
|
-
const configurationSchema = widgetData; //getElementSchemaAsJsonSchema( widgetType );
|
|
16
|
-
return {
|
|
17
|
-
tag: `${ widgetType }`,
|
|
18
|
-
description: widgetData.title || widgetData.elType || `A ${ widgetType } element`,
|
|
19
|
-
configurationSchema: JSON.stringify( configurationSchema ),
|
|
20
|
-
};
|
|
21
|
-
} );
|
|
22
|
-
return customTags;
|
|
23
|
-
};
|