@elementor/editor-canvas 4.1.0-manual → 4.2.0-839
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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-canvas",
|
|
3
3
|
"description": "Elementor Editor Canvas",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0-839",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor": "4.
|
|
40
|
+
"@elementor/editor": "4.2.0-839",
|
|
41
41
|
"dompurify": "^3.2.6",
|
|
42
|
-
"@elementor/editor-controls": "4.
|
|
43
|
-
"@elementor/editor-documents": "4.
|
|
44
|
-
"@elementor/editor-elements": "4.
|
|
45
|
-
"@elementor/editor-interactions": "4.
|
|
46
|
-
"@elementor/editor-mcp": "4.
|
|
47
|
-
"@elementor/editor-notifications": "4.
|
|
48
|
-
"@elementor/editor-props": "4.
|
|
49
|
-
"@elementor/editor-responsive": "4.
|
|
50
|
-
"@elementor/editor-styles": "4.
|
|
51
|
-
"@elementor/editor-styles-repository": "4.
|
|
52
|
-
"@elementor/editor-ui": "4.
|
|
53
|
-
"@elementor/editor-v1-adapters": "4.
|
|
54
|
-
"@elementor/schema": "4.
|
|
55
|
-
"@elementor/twing": "4.
|
|
42
|
+
"@elementor/editor-controls": "4.2.0-839",
|
|
43
|
+
"@elementor/editor-documents": "4.2.0-839",
|
|
44
|
+
"@elementor/editor-elements": "4.2.0-839",
|
|
45
|
+
"@elementor/editor-interactions": "4.2.0-839",
|
|
46
|
+
"@elementor/editor-mcp": "4.2.0-839",
|
|
47
|
+
"@elementor/editor-notifications": "4.2.0-839",
|
|
48
|
+
"@elementor/editor-props": "4.2.0-839",
|
|
49
|
+
"@elementor/editor-responsive": "4.2.0-839",
|
|
50
|
+
"@elementor/editor-styles": "4.2.0-839",
|
|
51
|
+
"@elementor/editor-styles-repository": "4.2.0-839",
|
|
52
|
+
"@elementor/editor-ui": "4.2.0-839",
|
|
53
|
+
"@elementor/editor-v1-adapters": "4.2.0-839",
|
|
54
|
+
"@elementor/schema": "4.2.0-839",
|
|
55
|
+
"@elementor/twing": "4.2.0-839",
|
|
56
56
|
"@elementor/ui": "1.37.5",
|
|
57
|
-
"@elementor/utils": "4.
|
|
58
|
-
"@elementor/wp-media": "4.
|
|
57
|
+
"@elementor/utils": "4.2.0-839",
|
|
58
|
+
"@elementor/wp-media": "4.2.0-839",
|
|
59
59
|
"@floating-ui/react": "^0.27.5",
|
|
60
60
|
"@wordpress/i18n": "^5.13.0"
|
|
61
61
|
},
|
|
@@ -103,6 +103,7 @@ describe( 'settings props resolver', () => {
|
|
|
103
103
|
expected: {
|
|
104
104
|
image: {
|
|
105
105
|
src: 'https://localhost.test/test-image.png',
|
|
106
|
+
alt: '',
|
|
106
107
|
},
|
|
107
108
|
},
|
|
108
109
|
},
|
|
@@ -130,6 +131,7 @@ describe( 'settings props resolver', () => {
|
|
|
130
131
|
src: 'large-image-url-123',
|
|
131
132
|
height: 3,
|
|
132
133
|
width: 3,
|
|
134
|
+
alt: undefined,
|
|
133
135
|
},
|
|
134
136
|
},
|
|
135
137
|
},
|
|
@@ -157,6 +159,7 @@ describe( 'settings props resolver', () => {
|
|
|
157
159
|
src: 'original-image-url-123',
|
|
158
160
|
height: 0,
|
|
159
161
|
width: 0,
|
|
162
|
+
alt: undefined,
|
|
160
163
|
},
|
|
161
164
|
},
|
|
162
165
|
},
|
|
@@ -34,7 +34,7 @@ type CtorOptions = {
|
|
|
34
34
|
export class CompositionBuilder {
|
|
35
35
|
private elementConfig: Record< string, Record< string, AnyValue > > = {};
|
|
36
36
|
private elementStylesConfig: Record< string, Record< string, AnyValue > > = {};
|
|
37
|
-
private
|
|
37
|
+
private elementCustomCSS: Record< string, string > = {};
|
|
38
38
|
private rootContainers: V1Element[] = [];
|
|
39
39
|
private api: API = {
|
|
40
40
|
createElement,
|
|
@@ -76,7 +76,7 @@ export class CompositionBuilder {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
setCustomCSS( config: Record< string, string > ) {
|
|
79
|
-
this.
|
|
79
|
+
this.elementCustomCSS = config;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
getXML() {
|
|
@@ -176,7 +176,7 @@ export class CompositionBuilder {
|
|
|
176
176
|
const allConfigIds = new Set( [
|
|
177
177
|
...Object.keys( this.elementConfig ),
|
|
178
178
|
...Object.keys( this.elementStylesConfig ),
|
|
179
|
-
...Object.keys( this.
|
|
179
|
+
...Object.keys( this.elementCustomCSS ),
|
|
180
180
|
] );
|
|
181
181
|
|
|
182
182
|
for ( const configId of allConfigIds ) {
|
|
@@ -188,7 +188,7 @@ export class CompositionBuilder {
|
|
|
188
188
|
if ( this.elementConfig[ configId ] ) {
|
|
189
189
|
configErrors.push( msg );
|
|
190
190
|
}
|
|
191
|
-
if ( this.elementStylesConfig[ configId ] || this.
|
|
191
|
+
if ( this.elementStylesConfig[ configId ] || this.elementCustomCSS[ configId ] ) {
|
|
192
192
|
styleErrors.push( msg );
|
|
193
193
|
}
|
|
194
194
|
continue;
|
|
@@ -241,7 +241,7 @@ export class CompositionBuilder {
|
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
const customCSS = this.
|
|
244
|
+
const customCSS = this.elementCustomCSS[ configId ];
|
|
245
245
|
if ( customCSS ) {
|
|
246
246
|
try {
|
|
247
247
|
this.api.doUpdateElementProperty( {
|
|
@@ -41,6 +41,10 @@ export const FORM_FIELD_ELEMENT_TYPES = new Set( [
|
|
|
41
41
|
'e-form-checkbox',
|
|
42
42
|
'e-form-submit-button',
|
|
43
43
|
'e-form-select',
|
|
44
|
+
'e-form-radio-button',
|
|
45
|
+
'e-form-file-upload',
|
|
46
|
+
'e-form-date-picker',
|
|
47
|
+
'e-form-time-picker',
|
|
44
48
|
] );
|
|
45
49
|
|
|
46
50
|
export function getArgsElementType( args: CreateArgs ): string | undefined {
|
|
@@ -408,6 +408,61 @@ describe( 'useStyleItems', () => {
|
|
|
408
408
|
] );
|
|
409
409
|
} );
|
|
410
410
|
|
|
411
|
+
it( 'should remove cached items for breakpoints whose variants no longer exist', async () => {
|
|
412
|
+
// Arrange.
|
|
413
|
+
const renderStylesMock = jest.fn().mockImplementation( ( { styles } ) =>
|
|
414
|
+
Promise.resolve(
|
|
415
|
+
styles.map( ( style: StyleDefinition ) => ( {
|
|
416
|
+
id: style.id,
|
|
417
|
+
breakpoint: style?.variants[ 0 ]?.meta.breakpoint || 'desktop',
|
|
418
|
+
} ) )
|
|
419
|
+
)
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
jest.mocked( useStyleRenderer ).mockReturnValue( renderStylesMock );
|
|
423
|
+
|
|
424
|
+
const styleWithTwoBreakpoints = createMockStyleDefinitionWithVariants( {
|
|
425
|
+
id: 'style1',
|
|
426
|
+
variants: [
|
|
427
|
+
{ meta: { breakpoint: null, state: null }, props: { 'font-family': 'Arial' }, custom_css: null },
|
|
428
|
+
{ meta: { breakpoint: 'tablet', state: null }, props: { 'font-family': 'Roboto' }, custom_css: null },
|
|
429
|
+
],
|
|
430
|
+
} );
|
|
431
|
+
|
|
432
|
+
const mockProvider = createMockStylesProvider( { key: 'provider1', priority: 1 }, [ styleWithTwoBreakpoints ] );
|
|
433
|
+
|
|
434
|
+
jest.mocked( stylesRepository ).getProviders.mockReturnValue( [ mockProvider ] );
|
|
435
|
+
|
|
436
|
+
const { result } = renderHook( () => useStyleItems() );
|
|
437
|
+
|
|
438
|
+
await act( async () => {
|
|
439
|
+
mockProvider.actions.updateProps?.( {
|
|
440
|
+
id: 'style1',
|
|
441
|
+
meta: { breakpoint: null, state: null },
|
|
442
|
+
props: {},
|
|
443
|
+
} );
|
|
444
|
+
} );
|
|
445
|
+
|
|
446
|
+
expect( result.current ).toEqual( [
|
|
447
|
+
{ id: 'style1', breakpoint: 'desktop' },
|
|
448
|
+
{ id: 'style1', breakpoint: 'tablet' },
|
|
449
|
+
] );
|
|
450
|
+
|
|
451
|
+
// Act - simulate the tablet variant being removed (e.g. user cleared its only prop,
|
|
452
|
+
// global-classes store calls getNonEmptyVariants which drops empty variants).
|
|
453
|
+
await act( async () => {
|
|
454
|
+
mockProvider.actions.update?.( {
|
|
455
|
+
id: 'style1',
|
|
456
|
+
variants: [
|
|
457
|
+
{ meta: { breakpoint: null, state: null }, props: { 'font-family': 'Arial' }, custom_css: null },
|
|
458
|
+
],
|
|
459
|
+
} );
|
|
460
|
+
} );
|
|
461
|
+
|
|
462
|
+
// Assert - the tablet item must be evicted from the cache.
|
|
463
|
+
expect( result.current ).toEqual( [ { id: 'style1', breakpoint: 'desktop' } ] );
|
|
464
|
+
} );
|
|
465
|
+
|
|
411
466
|
it( 'should only re-render changed styles on differential update', async () => {
|
|
412
467
|
// Arrange.
|
|
413
468
|
const renderStylesMock = jest.fn().mockImplementation( ( { styles } ) =>
|
|
@@ -200,8 +200,10 @@ function createProviderSubscriber( { provider, renderStyles, setStyleItems, getC
|
|
|
200
200
|
cssName: provider.actions.resolveCssName( style.id ),
|
|
201
201
|
} ) );
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
const breakpointSplit = breakToBreakpoints( changedStyles );
|
|
204
|
+
|
|
205
|
+
return renderStyles( { styles: breakpointSplit, signal } ).then( ( rendered ) => {
|
|
206
|
+
updateCacheItems( cache, changedIds, rendered );
|
|
205
207
|
|
|
206
208
|
return getOrderedItems( cache );
|
|
207
209
|
} );
|
|
@@ -277,19 +279,15 @@ function getOrderedItems( cache: StyleItemsCache ): StyleItem[] {
|
|
|
277
279
|
.flat();
|
|
278
280
|
}
|
|
279
281
|
|
|
280
|
-
function updateCacheItems( cache: StyleItemsCache, changedItems: StyleItem[] ): void {
|
|
282
|
+
function updateCacheItems( cache: StyleItemsCache, changedIds: string[], changedItems: StyleItem[] ): void {
|
|
283
|
+
for ( const id of changedIds ) {
|
|
284
|
+
cache.itemsById.delete( id );
|
|
285
|
+
}
|
|
286
|
+
|
|
281
287
|
for ( const item of changedItems ) {
|
|
282
|
-
const existing = cache.itemsById.get( item.id );
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if ( idx >= 0 ) {
|
|
286
|
-
existing[ idx ] = item;
|
|
287
|
-
} else {
|
|
288
|
-
existing.push( item );
|
|
289
|
-
}
|
|
290
|
-
} else {
|
|
291
|
-
cache.itemsById.set( item.id, [ item ] );
|
|
292
|
-
}
|
|
288
|
+
const existing = cache.itemsById.get( item.id ) || [];
|
|
289
|
+
existing.push( item );
|
|
290
|
+
cache.itemsById.set( item.id, existing );
|
|
293
291
|
}
|
|
294
292
|
}
|
|
295
293
|
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { createPropsResolver, type PropsResolver } from './renderers/create-prop
|
|
|
21
21
|
export { settingsTransformersRegistry } from './settings-transformers-registry';
|
|
22
22
|
export { styleTransformersRegistry } from './style-transformers-registry';
|
|
23
23
|
export { endDragElementFromPanel, startDragElementFromPanel } from './sync/drag-element-from-panel';
|
|
24
|
+
export { GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload } from './sync/global-styles-imported-event';
|
|
24
25
|
export { DOCUMENT_STRUCTURE_URI } from './mcp/resources/document-structure-resource';
|
|
25
26
|
export { WIDGET_SCHEMA_URI } from './mcp/resources/widgets-schema-resource';
|
|
26
27
|
export * from './legacy/types';
|
|
@@ -31,3 +32,4 @@ export {
|
|
|
31
32
|
} from './transformers/create-transformers-registry';
|
|
32
33
|
export { type AnyTransformer, type TransformerOptions } from './transformers/types';
|
|
33
34
|
export { UnknownStyleTypeError, UnknownStyleStateError } from './renderers/errors';
|
|
35
|
+
export { doAfterRender } from './utils/after-render';
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { settingsTransformersRegistry } from './settings-transformers-registry';
|
|
2
2
|
import { attributesTransformer } from './transformers/settings/attributes-transformer';
|
|
3
3
|
import { createClassesTransformer } from './transformers/settings/classes-transformer';
|
|
4
|
+
import { dateRangeTransformer } from './transformers/settings/date-range-transformer';
|
|
4
5
|
import { dateTimeTransformer } from './transformers/settings/date-time-transformer';
|
|
5
6
|
import { htmlV2Transformer } from './transformers/settings/html-v2-transformer';
|
|
6
7
|
import { htmlV3Transformer } from './transformers/settings/html-v3-transformer';
|
|
7
8
|
import { linkTransformer } from './transformers/settings/link-transformer';
|
|
8
9
|
import { queryTransformer } from './transformers/settings/query-transformer';
|
|
10
|
+
import { timeRangeTransformer } from './transformers/settings/time-range-transformer';
|
|
9
11
|
import { imageSrcTransformer } from './transformers/shared/image-src-transformer';
|
|
10
12
|
import { imageTransformer } from './transformers/shared/image-transformer';
|
|
11
13
|
import { plainTransformer } from './transformers/shared/plain-transformer';
|
|
@@ -25,5 +27,7 @@ export function initSettingsTransformers() {
|
|
|
25
27
|
.register( 'date-time', dateTimeTransformer )
|
|
26
28
|
.register( 'html-v2', htmlV2Transformer )
|
|
27
29
|
.register( 'html-v3', htmlV3Transformer )
|
|
30
|
+
.register( 'date-range', dateRangeTransformer )
|
|
31
|
+
.register( 'time-range', timeRangeTransformer )
|
|
28
32
|
.registerFallback( plainTransformer );
|
|
29
33
|
}
|
|
@@ -17,6 +17,7 @@ import { perspectiveOriginTransformer } from './transformers/styles/perspective-
|
|
|
17
17
|
import { positionTransformer } from './transformers/styles/position-transformer';
|
|
18
18
|
import { shadowTransformer } from './transformers/styles/shadow-transformer';
|
|
19
19
|
import { sizeTransformer } from './transformers/styles/size-transformer';
|
|
20
|
+
import { spanTransformer } from './transformers/styles/span-transformer';
|
|
20
21
|
import { strokeTransformer } from './transformers/styles/stroke-transformer';
|
|
21
22
|
import { transformFunctionsTransformer } from './transformers/styles/transform-functions-transformer';
|
|
22
23
|
import { transformMoveTransformer } from './transformers/styles/transform-move-transformer';
|
|
@@ -53,6 +54,7 @@ export function initStyleTransformers() {
|
|
|
53
54
|
.register( 'image-src', imageSrcTransformer )
|
|
54
55
|
.register( 'image', imageTransformer )
|
|
55
56
|
.register( 'object-position', positionTransformer )
|
|
57
|
+
.register( 'span', spanTransformer )
|
|
56
58
|
.register( 'transform-origin', transformOriginTransformer )
|
|
57
59
|
.register( 'perspective-origin', perspectiveOriginTransformer )
|
|
58
60
|
.register( 'transform-move', transformMoveTransformer )
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { ELEMENT_STYLE_CHANGE_EVENT } from '@elementor/editor-elements';
|
|
1
|
+
import { ELEMENT_STYLE_CHANGE_EVENT, type V1ElementModelProps } from '@elementor/editor-elements';
|
|
2
2
|
|
|
3
3
|
import { type DomRenderer } from '../renderers/create-dom-renderer';
|
|
4
4
|
import { signalizedProcess } from '../utils/signalized-process';
|
|
5
|
+
import { createPendingElement } from './create-pending-element';
|
|
5
6
|
import { canBeTemplated, type TemplatedElementConfig } from './create-templated-element-type';
|
|
6
7
|
import {
|
|
7
8
|
createAfterRender,
|
|
@@ -101,6 +102,7 @@ export function createNestedTemplatedElementView( {
|
|
|
101
102
|
const AtomicElementBaseView = legacyWindow.elementor.modules.elements.views.createAtomicElementBase( type );
|
|
102
103
|
const parentRenderChildren = AtomicElementBaseView.prototype._renderChildren;
|
|
103
104
|
const parentOpenEditingPanel = AtomicElementBaseView.prototype._openEditingPanel;
|
|
105
|
+
const parentAddElement = AtomicElementBaseView.prototype.addElement;
|
|
104
106
|
|
|
105
107
|
return AtomicElementBaseView.extend( {
|
|
106
108
|
_abortController: null as AbortController | null,
|
|
@@ -254,7 +256,6 @@ export function createNestedTemplatedElementView( {
|
|
|
254
256
|
targetEl.setAttribute( attr.name, attr.value );
|
|
255
257
|
} );
|
|
256
258
|
|
|
257
|
-
targetEl.setAttribute( 'draggable', 'true' );
|
|
258
259
|
targetEl.innerHTML = overlayHTML + newEl.innerHTML;
|
|
259
260
|
|
|
260
261
|
if ( needsTagSwap ) {
|
|
@@ -381,6 +382,14 @@ export function createNestedTemplatedElementView( {
|
|
|
381
382
|
this._doAfterRender( () => parentOpenEditingPanel.call( this, options ) );
|
|
382
383
|
},
|
|
383
384
|
|
|
385
|
+
addElement( data: Partial< V1ElementModelProps >, options?: { edit?: boolean; at?: number } ) {
|
|
386
|
+
if ( this.isRendered ) {
|
|
387
|
+
return parentAddElement.call( this, data, options );
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return createPendingElement( this, data, options );
|
|
391
|
+
},
|
|
392
|
+
|
|
384
393
|
getInteractionId() {
|
|
385
394
|
const originId = this.model.get( 'originId' );
|
|
386
395
|
const id = this.model.get( 'id' );
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addModelToParent,
|
|
3
|
+
findModelInDocument,
|
|
4
|
+
generateElementId,
|
|
5
|
+
getContainer,
|
|
6
|
+
type V1Element,
|
|
7
|
+
type V1ElementModelProps,
|
|
8
|
+
} from '@elementor/editor-elements';
|
|
9
|
+
|
|
10
|
+
import { type ElementView } from './types';
|
|
11
|
+
|
|
12
|
+
export function createPendingElement(
|
|
13
|
+
wrapperView: ElementView,
|
|
14
|
+
data: Partial< V1ElementModelProps >,
|
|
15
|
+
options: { edit?: boolean; at?: number } = {}
|
|
16
|
+
): { getContainer: () => V1Element } | undefined {
|
|
17
|
+
const parentContainer = wrapperView.getContainer();
|
|
18
|
+
const model: Partial< V1ElementModelProps > = { ...data };
|
|
19
|
+
|
|
20
|
+
if ( ! model.id ) {
|
|
21
|
+
model.id = generateElementId();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if ( ! model.elements ) {
|
|
25
|
+
model.elements = [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const added = addModelToParent( parentContainer.id, model as V1ElementModelProps, options );
|
|
29
|
+
|
|
30
|
+
if ( ! added ) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const childId = model.id;
|
|
35
|
+
const childModel = findModelInDocument( childId );
|
|
36
|
+
|
|
37
|
+
if ( ! childModel ) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const pendingContainer: V1Element = {
|
|
42
|
+
id: childId,
|
|
43
|
+
settings: { get: () => ( {} ), set: () => ( {} ), toJSON: () => ( {} ) } as V1Element[ 'settings' ],
|
|
44
|
+
parent: parentContainer,
|
|
45
|
+
model: childModel as V1Element[ 'model' ],
|
|
46
|
+
view: undefined,
|
|
47
|
+
lookup() {
|
|
48
|
+
return getContainer( childId ) ?? pendingContainer;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
wrapperView.once( 'render', () => {
|
|
53
|
+
wrapperView.model?.trigger?.( 'navigator:add', childModel, options );
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
if ( options.edit !== false ) {
|
|
57
|
+
selectChildWhenWrapperRenders( wrapperView, childId );
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { getContainer: () => pendingContainer };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function selectChildWhenWrapperRenders( wrapperView: ElementView, childId: string ): void {
|
|
64
|
+
wrapperView.once( 'render', () => {
|
|
65
|
+
const childContainer = getContainer( childId );
|
|
66
|
+
|
|
67
|
+
if ( childContainer?.model?.trigger ) {
|
|
68
|
+
childContainer.model.trigger( 'request:edit' );
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
wrapperView.model?.trigger?.( 'request:edit' );
|
|
73
|
+
} );
|
|
74
|
+
}
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
} from './twig-rendering-utils';
|
|
14
14
|
import {
|
|
15
15
|
type ElementType,
|
|
16
|
-
type ElementView,
|
|
17
16
|
type LegacyWindow,
|
|
18
17
|
type NamespacedRenderContext,
|
|
19
18
|
type RenderContext,
|
|
19
|
+
type TemplatedElementView,
|
|
20
20
|
} from './types';
|
|
21
21
|
|
|
22
22
|
export type CreateTemplatedElementTypeOptions = {
|
|
@@ -66,7 +66,7 @@ export function createTemplatedElementView( {
|
|
|
66
66
|
type,
|
|
67
67
|
renderer,
|
|
68
68
|
element,
|
|
69
|
-
}: CreateTemplatedElementTypeOptions ): typeof
|
|
69
|
+
}: CreateTemplatedElementTypeOptions ): typeof TemplatedElementView {
|
|
70
70
|
const BaseView = createElementViewClassDeclaration();
|
|
71
71
|
|
|
72
72
|
const { templateKey, baseStylesDictionary, resolveProps } = setupTwigRenderer( {
|
package/src/legacy/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Root } from 'react-dom/client';
|
|
2
|
-
import { type V1Element } from '@elementor/editor-elements';
|
|
2
|
+
import { type V1Element, type V1ElementModelProps } from '@elementor/editor-elements';
|
|
3
3
|
import { type Props, type PropValue } from '@elementor/editor-props';
|
|
4
4
|
|
|
5
5
|
export type RenderContext< T = unknown > = Record< string, T >;
|
|
@@ -89,6 +89,8 @@ export declare class ElementView {
|
|
|
89
89
|
|
|
90
90
|
constructor( ...args: unknown[] );
|
|
91
91
|
|
|
92
|
+
addElement( data: Partial< V1ElementModelProps >, options?: object ): unknown;
|
|
93
|
+
|
|
92
94
|
onRender( ...args: unknown[] ): void;
|
|
93
95
|
|
|
94
96
|
onDestroy( ...args: unknown[] ): void;
|
|
@@ -163,6 +165,12 @@ export declare class ElementView {
|
|
|
163
165
|
_openEditingPanel( options?: { scrollIntoView: boolean } ): void;
|
|
164
166
|
|
|
165
167
|
once: ( event: string, callback: () => void ) => void;
|
|
168
|
+
|
|
169
|
+
getContainer(): V1Element;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export declare class TemplatedElementView extends ElementView {
|
|
173
|
+
_doAfterRender( callback: () => void ): void;
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
type JQueryElement = {
|
package/src/mcp/canvas-mcp.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
|
+
import { initAvailableWidgetsResource } from './resources/available-widgets-resource';
|
|
3
4
|
import { initBreakpointsResource } from './resources/breakpoints-resource';
|
|
4
5
|
import { initDocumentStructureResource } from './resources/document-structure-resource';
|
|
6
|
+
import { initEditorStateResource } from './resources/editor-state-resource';
|
|
7
|
+
import { initGeneralContextResource } from './resources/general-context-resource';
|
|
8
|
+
import { initSelectedElementResource } from './resources/selected-element-resource';
|
|
5
9
|
import { initWidgetsSchemaResource } from './resources/widgets-schema-resource';
|
|
6
10
|
import { initBuildCompositionsTool } from './tools/build-composition/tool';
|
|
7
11
|
import { initConfigureElementTool } from './tools/configure-element/tool';
|
|
@@ -18,7 +22,11 @@ export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
|
|
|
18
22
|
`
|
|
19
23
|
);
|
|
20
24
|
initWidgetsSchemaResource( reg );
|
|
25
|
+
initAvailableWidgetsResource( reg );
|
|
21
26
|
initDocumentStructureResource( reg );
|
|
27
|
+
initSelectedElementResource( reg );
|
|
28
|
+
initEditorStateResource( reg );
|
|
29
|
+
initGeneralContextResource( reg );
|
|
22
30
|
initBuildCompositionsTool( reg );
|
|
23
31
|
initGetElementConfigTool( reg );
|
|
24
32
|
initConfigureElementTool( reg );
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
|
+
import { v1ReadyEvent } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
import { type AvailableWidget, getAvailableWidgets } from '../utils/element-data-util';
|
|
5
|
+
|
|
6
|
+
export const AVAILABLE_WIDGETS_URI = 'elementor://context/available-widgets';
|
|
7
|
+
export const AVAILABLE_WIDGETS_URI_V4 = 'elementor://context/available-widgets/v4';
|
|
8
|
+
|
|
9
|
+
export const initAvailableWidgetsResource = ( reg: MCPRegistryEntry ) => {
|
|
10
|
+
const { resource, sendResourceUpdated } = reg;
|
|
11
|
+
|
|
12
|
+
const buildContents = ( uri: string, filterFunction: ( x: AvailableWidget ) => boolean = () => true ) => {
|
|
13
|
+
const widgets = getAvailableWidgets().filter( filterFunction );
|
|
14
|
+
return {
|
|
15
|
+
contents: [
|
|
16
|
+
{
|
|
17
|
+
uri,
|
|
18
|
+
mimeType: 'application/json',
|
|
19
|
+
text: JSON.stringify( widgets, null, 2 ),
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const notifyResourcesUpdated = () => {
|
|
26
|
+
sendResourceUpdated( {
|
|
27
|
+
uri: AVAILABLE_WIDGETS_URI,
|
|
28
|
+
...buildContents( AVAILABLE_WIDGETS_URI ),
|
|
29
|
+
} );
|
|
30
|
+
sendResourceUpdated( {
|
|
31
|
+
uri: AVAILABLE_WIDGETS_URI_V4,
|
|
32
|
+
...buildContents( AVAILABLE_WIDGETS_URI_V4, ( w: AvailableWidget ) => w.version === 'v4' ),
|
|
33
|
+
} );
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
resource(
|
|
37
|
+
'available-widgets-v4',
|
|
38
|
+
AVAILABLE_WIDGETS_URI_V4,
|
|
39
|
+
{
|
|
40
|
+
description: 'All registered v4 version widgets',
|
|
41
|
+
},
|
|
42
|
+
async () => buildContents( AVAILABLE_WIDGETS_URI_V4, ( w ) => w.version === 'v4' )
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
resource(
|
|
46
|
+
'available-widgets',
|
|
47
|
+
AVAILABLE_WIDGETS_URI,
|
|
48
|
+
{
|
|
49
|
+
description: 'All registered widget types with v3/v4 version metadata and description.',
|
|
50
|
+
},
|
|
51
|
+
async () => buildContents( AVAILABLE_WIDGETS_URI )
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const eventName = v1ReadyEvent().name;
|
|
55
|
+
|
|
56
|
+
const onV1Ready = () => {
|
|
57
|
+
const widgets = getAvailableWidgets();
|
|
58
|
+
if ( widgets.length === 0 ) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
window.removeEventListener( eventName, onV1Ready );
|
|
62
|
+
notifyResourcesUpdated();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
window.addEventListener( eventName, onV1Ready );
|
|
66
|
+
onV1Ready();
|
|
67
|
+
};
|