@elementor/editor-canvas 4.2.0-861 → 4.2.0-863
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -4083,6 +4083,7 @@ var validateInput = {
|
|
|
4083
4083
|
};
|
|
4084
4084
|
|
|
4085
4085
|
// src/composition-builder/composition-builder.ts
|
|
4086
|
+
var CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = "createElement did not return an element container with a model.";
|
|
4086
4087
|
var CompositionBuilder = class _CompositionBuilder {
|
|
4087
4088
|
elementConfig = {};
|
|
4088
4089
|
elementStylesConfig = {};
|
|
@@ -4301,6 +4302,9 @@ ${childTypeErrors.join("\n")}`);
|
|
|
4301
4302
|
model: modelTree,
|
|
4302
4303
|
options: { useHistory: false }
|
|
4303
4304
|
});
|
|
4305
|
+
if (!newElement?.model) {
|
|
4306
|
+
throw new Error(CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE);
|
|
4307
|
+
}
|
|
4304
4308
|
this.rootContainers.push(newElement);
|
|
4305
4309
|
await this.awaitViewRender(newElement);
|
|
4306
4310
|
} catch (e) {
|
|
@@ -4766,6 +4770,13 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
|
|
|
4766
4770
|
configureElementToolPrompt.instruction(
|
|
4767
4771
|
"The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects."
|
|
4768
4772
|
);
|
|
4773
|
+
configureElementToolPrompt.instruction(`
|
|
4774
|
+
V4 only: If MCP fails, give manual steps using V4 UI.
|
|
4775
|
+
|
|
4776
|
+
V4 Editor structure:
|
|
4777
|
+
Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
|
|
4778
|
+
NO Advanced tab. Never mention Advanced tab.
|
|
4779
|
+
`);
|
|
4769
4780
|
return configureElementToolPrompt.prompt();
|
|
4770
4781
|
};
|
|
4771
4782
|
var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
|
package/dist/index.mjs
CHANGED
|
@@ -4078,6 +4078,7 @@ var validateInput = {
|
|
|
4078
4078
|
};
|
|
4079
4079
|
|
|
4080
4080
|
// src/composition-builder/composition-builder.ts
|
|
4081
|
+
var CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = "createElement did not return an element container with a model.";
|
|
4081
4082
|
var CompositionBuilder = class _CompositionBuilder {
|
|
4082
4083
|
elementConfig = {};
|
|
4083
4084
|
elementStylesConfig = {};
|
|
@@ -4296,6 +4297,9 @@ ${childTypeErrors.join("\n")}`);
|
|
|
4296
4297
|
model: modelTree,
|
|
4297
4298
|
options: { useHistory: false }
|
|
4298
4299
|
});
|
|
4300
|
+
if (!newElement?.model) {
|
|
4301
|
+
throw new Error(CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE);
|
|
4302
|
+
}
|
|
4299
4303
|
this.rootContainers.push(newElement);
|
|
4300
4304
|
await this.awaitViewRender(newElement);
|
|
4301
4305
|
} catch (e) {
|
|
@@ -4761,6 +4765,13 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
|
|
|
4761
4765
|
configureElementToolPrompt.instruction(
|
|
4762
4766
|
"The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects."
|
|
4763
4767
|
);
|
|
4768
|
+
configureElementToolPrompt.instruction(`
|
|
4769
|
+
V4 only: If MCP fails, give manual steps using V4 UI.
|
|
4770
|
+
|
|
4771
|
+
V4 Editor structure:
|
|
4772
|
+
Panel tabs: General (\u2192 Settings section: ID, Tag, Link), Style, Interactions.
|
|
4773
|
+
NO Advanced tab. Never mention Advanced tab.
|
|
4774
|
+
`);
|
|
4764
4775
|
return configureElementToolPrompt.prompt();
|
|
4765
4776
|
};
|
|
4766
4777
|
var CONFIGURE_ELEMENT_GUIDE_TEXT = generatePrompt2();
|
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.2.0-
|
|
4
|
+
"version": "4.2.0-863",
|
|
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.2.0-
|
|
40
|
+
"@elementor/editor": "4.2.0-863",
|
|
41
41
|
"dompurify": "^3.2.6",
|
|
42
|
-
"@elementor/editor-controls": "4.2.0-
|
|
43
|
-
"@elementor/editor-documents": "4.2.0-
|
|
44
|
-
"@elementor/editor-elements": "4.2.0-
|
|
45
|
-
"@elementor/editor-interactions": "4.2.0-
|
|
46
|
-
"@elementor/editor-mcp": "4.2.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.2.0-
|
|
48
|
-
"@elementor/editor-props": "4.2.0-
|
|
49
|
-
"@elementor/editor-responsive": "4.2.0-
|
|
50
|
-
"@elementor/editor-styles": "4.2.0-
|
|
51
|
-
"@elementor/editor-styles-repository": "4.2.0-
|
|
52
|
-
"@elementor/editor-ui": "4.2.0-
|
|
53
|
-
"@elementor/editor-v1-adapters": "4.2.0-
|
|
54
|
-
"@elementor/schema": "4.2.0-
|
|
55
|
-
"@elementor/twing": "4.2.0-
|
|
42
|
+
"@elementor/editor-controls": "4.2.0-863",
|
|
43
|
+
"@elementor/editor-documents": "4.2.0-863",
|
|
44
|
+
"@elementor/editor-elements": "4.2.0-863",
|
|
45
|
+
"@elementor/editor-interactions": "4.2.0-863",
|
|
46
|
+
"@elementor/editor-mcp": "4.2.0-863",
|
|
47
|
+
"@elementor/editor-notifications": "4.2.0-863",
|
|
48
|
+
"@elementor/editor-props": "4.2.0-863",
|
|
49
|
+
"@elementor/editor-responsive": "4.2.0-863",
|
|
50
|
+
"@elementor/editor-styles": "4.2.0-863",
|
|
51
|
+
"@elementor/editor-styles-repository": "4.2.0-863",
|
|
52
|
+
"@elementor/editor-ui": "4.2.0-863",
|
|
53
|
+
"@elementor/editor-v1-adapters": "4.2.0-863",
|
|
54
|
+
"@elementor/schema": "4.2.0-863",
|
|
55
|
+
"@elementor/twing": "4.2.0-863",
|
|
56
56
|
"@elementor/ui": "1.37.5",
|
|
57
|
-
"@elementor/utils": "4.2.0-
|
|
58
|
-
"@elementor/wp-media": "4.2.0-
|
|
57
|
+
"@elementor/utils": "4.2.0-863",
|
|
58
|
+
"@elementor/wp-media": "4.2.0-863",
|
|
59
59
|
"@floating-ui/react": "^0.27.5",
|
|
60
60
|
"@wordpress/i18n": "^5.13.0"
|
|
61
61
|
},
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { type V1Element } from '@elementor/editor-elements';
|
|
2
|
+
|
|
3
|
+
import { CompositionBuilder } from '../composition-builder';
|
|
4
|
+
|
|
5
|
+
const ROOT_CHILD_TAG = 'column';
|
|
6
|
+
const GENERATED_ELEMENT_ID = 'generated-element-id';
|
|
7
|
+
const CONFIG_ID = 'cfg-a';
|
|
8
|
+
const ELEMENT_CONFIG_PROPERTY = 'title';
|
|
9
|
+
const ELEMENT_CONFIG_VALUE = 'configured-value';
|
|
10
|
+
|
|
11
|
+
const xmlStringWithConfiguration = `<${ ROOT_CHILD_TAG } configuration-id="${ CONFIG_ID }" />`;
|
|
12
|
+
|
|
13
|
+
const createElementConfigPayload = () => ( {
|
|
14
|
+
[ CONFIG_ID ]: {
|
|
15
|
+
[ ELEMENT_CONFIG_PROPERTY ]: ELEMENT_CONFIG_VALUE,
|
|
16
|
+
},
|
|
17
|
+
} );
|
|
18
|
+
|
|
19
|
+
const createMinimalWidgetsCache = () =>
|
|
20
|
+
( {
|
|
21
|
+
[ ROOT_CHILD_TAG ]: {
|
|
22
|
+
elType: 'column',
|
|
23
|
+
},
|
|
24
|
+
} ) as Record< string, { elType: string } >;
|
|
25
|
+
|
|
26
|
+
const createMockRootContainer = (): V1Element =>
|
|
27
|
+
( {
|
|
28
|
+
id: 'root',
|
|
29
|
+
model: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
|
|
30
|
+
settings: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
|
|
31
|
+
children: [],
|
|
32
|
+
} ) as unknown as V1Element;
|
|
33
|
+
|
|
34
|
+
const createMockPartialContainer = ( id: string ): V1Element =>
|
|
35
|
+
( {
|
|
36
|
+
id,
|
|
37
|
+
model: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
|
|
38
|
+
settings: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
|
|
39
|
+
children: [],
|
|
40
|
+
} ) as unknown as V1Element;
|
|
41
|
+
|
|
42
|
+
describe( 'CompositionBuilder.build createElement failure cleanup', () => {
|
|
43
|
+
it( 'calls deleteElement when createElement fails and getContainer returns a container', async () => {
|
|
44
|
+
// Arrange
|
|
45
|
+
const partialContainer = createMockPartialContainer( GENERATED_ELEMENT_ID );
|
|
46
|
+
const deleteElement = jest.fn();
|
|
47
|
+
const doUpdateElementProperty = jest.fn();
|
|
48
|
+
const createElement = jest.fn().mockImplementation( () => {
|
|
49
|
+
throw new Error( 'create failed' );
|
|
50
|
+
} );
|
|
51
|
+
const getContainer = jest
|
|
52
|
+
.fn()
|
|
53
|
+
.mockImplementation( ( id: string ) => ( id === GENERATED_ELEMENT_ID ? partialContainer : undefined ) );
|
|
54
|
+
const builder = CompositionBuilder.fromXMLString( xmlStringWithConfiguration, {
|
|
55
|
+
createElement,
|
|
56
|
+
deleteElement,
|
|
57
|
+
getContainer,
|
|
58
|
+
generateElementId: jest.fn().mockReturnValue( GENERATED_ELEMENT_ID ),
|
|
59
|
+
getWidgetsCache: jest.fn().mockReturnValue( createMinimalWidgetsCache() ),
|
|
60
|
+
doUpdateElementProperty,
|
|
61
|
+
} );
|
|
62
|
+
builder.setElementConfig( createElementConfigPayload() );
|
|
63
|
+
|
|
64
|
+
// Act
|
|
65
|
+
await expect( builder.build( createMockRootContainer() ) ).rejects.toThrow( 'create failed' );
|
|
66
|
+
|
|
67
|
+
// Assert
|
|
68
|
+
expect( getContainer ).toHaveBeenCalledWith( GENERATED_ELEMENT_ID );
|
|
69
|
+
expect( deleteElement ).toHaveBeenCalledTimes( 1 );
|
|
70
|
+
expect( deleteElement ).toHaveBeenCalledWith( { container: partialContainer } );
|
|
71
|
+
expect( doUpdateElementProperty ).not.toHaveBeenCalled();
|
|
72
|
+
} );
|
|
73
|
+
|
|
74
|
+
it( 'does not call deleteElement when createElement fails and getContainer returns undefined', async () => {
|
|
75
|
+
// Arrange
|
|
76
|
+
const deleteElement = jest.fn();
|
|
77
|
+
const doUpdateElementProperty = jest.fn();
|
|
78
|
+
const createElement = jest.fn().mockImplementation( () => {
|
|
79
|
+
throw new Error( 'create failed' );
|
|
80
|
+
} );
|
|
81
|
+
const getContainer = jest.fn().mockReturnValue( undefined );
|
|
82
|
+
const builder = CompositionBuilder.fromXMLString( xmlStringWithConfiguration, {
|
|
83
|
+
createElement,
|
|
84
|
+
deleteElement,
|
|
85
|
+
getContainer,
|
|
86
|
+
generateElementId: jest.fn().mockReturnValue( GENERATED_ELEMENT_ID ),
|
|
87
|
+
getWidgetsCache: jest.fn().mockReturnValue( createMinimalWidgetsCache() ),
|
|
88
|
+
doUpdateElementProperty,
|
|
89
|
+
} );
|
|
90
|
+
builder.setElementConfig( createElementConfigPayload() );
|
|
91
|
+
|
|
92
|
+
// Act
|
|
93
|
+
await expect( builder.build( createMockRootContainer() ) ).rejects.toThrow( 'create failed' );
|
|
94
|
+
|
|
95
|
+
// Assert
|
|
96
|
+
expect( getContainer ).toHaveBeenCalledWith( GENERATED_ELEMENT_ID );
|
|
97
|
+
expect( deleteElement ).not.toHaveBeenCalled();
|
|
98
|
+
expect( doUpdateElementProperty ).not.toHaveBeenCalled();
|
|
99
|
+
} );
|
|
100
|
+
|
|
101
|
+
it( 'calls deleteElement when createElement returns without a model', async () => {
|
|
102
|
+
// Arrange
|
|
103
|
+
const partialContainer = createMockPartialContainer( GENERATED_ELEMENT_ID );
|
|
104
|
+
const deleteElement = jest.fn();
|
|
105
|
+
const doUpdateElementProperty = jest.fn();
|
|
106
|
+
const createElement = jest.fn().mockReturnValue( {} as V1Element );
|
|
107
|
+
const getContainer = jest
|
|
108
|
+
.fn()
|
|
109
|
+
.mockImplementation( ( id: string ) => ( id === GENERATED_ELEMENT_ID ? partialContainer : undefined ) );
|
|
110
|
+
const builder = CompositionBuilder.fromXMLString( xmlStringWithConfiguration, {
|
|
111
|
+
createElement,
|
|
112
|
+
deleteElement,
|
|
113
|
+
getContainer,
|
|
114
|
+
generateElementId: jest.fn().mockReturnValue( GENERATED_ELEMENT_ID ),
|
|
115
|
+
getWidgetsCache: jest.fn().mockReturnValue( createMinimalWidgetsCache() ),
|
|
116
|
+
doUpdateElementProperty,
|
|
117
|
+
} );
|
|
118
|
+
builder.setElementConfig( createElementConfigPayload() );
|
|
119
|
+
|
|
120
|
+
// Act
|
|
121
|
+
await expect( builder.build( createMockRootContainer() ) ).rejects.toThrow(
|
|
122
|
+
'createElement did not return an element container with a model.'
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Assert
|
|
126
|
+
expect( getContainer ).toHaveBeenCalledWith( GENERATED_ELEMENT_ID );
|
|
127
|
+
expect( deleteElement ).toHaveBeenCalledTimes( 1 );
|
|
128
|
+
expect( deleteElement ).toHaveBeenCalledWith( { container: partialContainer } );
|
|
129
|
+
expect( doUpdateElementProperty ).not.toHaveBeenCalled();
|
|
130
|
+
} );
|
|
131
|
+
} );
|
|
132
|
+
|
|
133
|
+
describe( 'CompositionBuilder.build applyProperties after create', () => {
|
|
134
|
+
it( 'calls doUpdateElementProperty when create succeeds with element config', async () => {
|
|
135
|
+
// Arrange
|
|
136
|
+
const deleteElement = jest.fn();
|
|
137
|
+
const doUpdateElementProperty = jest.fn();
|
|
138
|
+
const createdElement = createMockPartialContainer( GENERATED_ELEMENT_ID );
|
|
139
|
+
const createElement = jest.fn().mockReturnValue( createdElement );
|
|
140
|
+
const getContainer = jest
|
|
141
|
+
.fn()
|
|
142
|
+
.mockImplementation( ( id: string ) => ( id === GENERATED_ELEMENT_ID ? createdElement : undefined ) );
|
|
143
|
+
const builder = CompositionBuilder.fromXMLString( xmlStringWithConfiguration, {
|
|
144
|
+
createElement,
|
|
145
|
+
deleteElement,
|
|
146
|
+
getContainer,
|
|
147
|
+
generateElementId: jest.fn().mockReturnValue( GENERATED_ELEMENT_ID ),
|
|
148
|
+
getWidgetsCache: jest.fn().mockReturnValue( createMinimalWidgetsCache() ),
|
|
149
|
+
doUpdateElementProperty,
|
|
150
|
+
} );
|
|
151
|
+
builder.setElementConfig( createElementConfigPayload() );
|
|
152
|
+
|
|
153
|
+
// Act
|
|
154
|
+
await builder.build( createMockRootContainer() );
|
|
155
|
+
|
|
156
|
+
// Assert
|
|
157
|
+
expect( deleteElement ).not.toHaveBeenCalled();
|
|
158
|
+
expect( createElement ).toHaveBeenCalledTimes( 1 );
|
|
159
|
+
expect( doUpdateElementProperty ).toHaveBeenCalledTimes( 1 );
|
|
160
|
+
expect( doUpdateElementProperty ).toHaveBeenCalledWith( {
|
|
161
|
+
elementId: GENERATED_ELEMENT_ID,
|
|
162
|
+
propertyName: ELEMENT_CONFIG_PROPERTY,
|
|
163
|
+
propertyValue: ELEMENT_CONFIG_VALUE,
|
|
164
|
+
elementType: ROOT_CHILD_TAG,
|
|
165
|
+
} );
|
|
166
|
+
} );
|
|
167
|
+
|
|
168
|
+
it( 'does not call doUpdateElementProperty when create succeeds without element config', async () => {
|
|
169
|
+
// Arrange
|
|
170
|
+
const deleteElement = jest.fn();
|
|
171
|
+
const doUpdateElementProperty = jest.fn();
|
|
172
|
+
const createdElement = createMockPartialContainer( GENERATED_ELEMENT_ID );
|
|
173
|
+
const createElement = jest.fn().mockReturnValue( createdElement );
|
|
174
|
+
const builder = CompositionBuilder.fromXMLString( `<${ ROOT_CHILD_TAG } />`, {
|
|
175
|
+
createElement,
|
|
176
|
+
deleteElement,
|
|
177
|
+
getContainer: jest.fn(),
|
|
178
|
+
generateElementId: jest.fn().mockReturnValue( GENERATED_ELEMENT_ID ),
|
|
179
|
+
getWidgetsCache: jest.fn().mockReturnValue( createMinimalWidgetsCache() ),
|
|
180
|
+
doUpdateElementProperty,
|
|
181
|
+
} );
|
|
182
|
+
|
|
183
|
+
// Act
|
|
184
|
+
await builder.build( createMockRootContainer() );
|
|
185
|
+
|
|
186
|
+
// Assert
|
|
187
|
+
expect( deleteElement ).not.toHaveBeenCalled();
|
|
188
|
+
expect( doUpdateElementProperty ).not.toHaveBeenCalled();
|
|
189
|
+
} );
|
|
190
|
+
} );
|
|
@@ -17,6 +17,8 @@ import { validateInput } from '../mcp/utils/validate-input';
|
|
|
17
17
|
type AnyValue = z.infer< z.ZodTypeAny >;
|
|
18
18
|
type AnyConfig = Record< string, Record< string, AnyValue > >;
|
|
19
19
|
|
|
20
|
+
const CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = 'createElement did not return an element container with a model.';
|
|
21
|
+
|
|
20
22
|
type API = {
|
|
21
23
|
createElement: typeof createElement;
|
|
22
24
|
deleteElement: typeof deleteElement;
|
|
@@ -296,6 +298,9 @@ export class CompositionBuilder {
|
|
|
296
298
|
model: modelTree as CreateElementParams[ 'model' ],
|
|
297
299
|
options: { useHistory: false },
|
|
298
300
|
} );
|
|
301
|
+
if ( ! newElement?.model ) {
|
|
302
|
+
throw new Error( CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE );
|
|
303
|
+
}
|
|
299
304
|
this.rootContainers.push( newElement );
|
|
300
305
|
await this.awaitViewRender( newElement );
|
|
301
306
|
} catch ( e: unknown ) {
|
|
@@ -117,6 +117,14 @@ Use the EXACT "PROP-TYPE" Schema given, and ALWAYS include the "key" property fr
|
|
|
117
117
|
'The $$type property is MANDATORY for every value; it is required to parse the value and apply application-level effects.'
|
|
118
118
|
);
|
|
119
119
|
|
|
120
|
+
configureElementToolPrompt.instruction( `
|
|
121
|
+
V4 only: If MCP fails, give manual steps using V4 UI.
|
|
122
|
+
|
|
123
|
+
V4 Editor structure:
|
|
124
|
+
Panel tabs: General (→ Settings section: ID, Tag, Link), Style, Interactions.
|
|
125
|
+
NO Advanced tab. Never mention Advanced tab.
|
|
126
|
+
` );
|
|
127
|
+
|
|
120
128
|
return configureElementToolPrompt.prompt();
|
|
121
129
|
};
|
|
122
130
|
|