@elementor/editor-elements 3.33.0-99 → 3.34.3

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.
Files changed (51) hide show
  1. package/dist/index.d.mts +274 -119
  2. package/dist/index.d.ts +274 -119
  3. package/dist/index.js +1158 -394
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1141 -387
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +7 -5
  8. package/src/errors.ts +10 -0
  9. package/src/hooks/use-element-children.ts +12 -12
  10. package/src/hooks/use-element-editor-settings.ts +12 -0
  11. package/src/hooks/use-element-interactions.ts +25 -0
  12. package/src/hooks/use-element-setting.ts +1 -1
  13. package/src/hooks/use-selected-element.ts +2 -2
  14. package/src/index.ts +38 -27
  15. package/src/mcp/elements-tool.ts +345 -0
  16. package/src/mcp/handlers/common-style-utils.ts +23 -0
  17. package/src/mcp/handlers/create-element.ts +96 -0
  18. package/src/mcp/handlers/create-style.ts +42 -0
  19. package/src/mcp/handlers/delete-element.ts +17 -0
  20. package/src/mcp/handlers/delete-style.ts +22 -0
  21. package/src/mcp/handlers/deselect-element.ts +21 -0
  22. package/src/mcp/handlers/duplicate-element.ts +22 -0
  23. package/src/mcp/handlers/get-element-props.ts +28 -0
  24. package/src/mcp/handlers/get-element-schema.ts +17 -0
  25. package/src/mcp/handlers/get-selected.ts +5 -0
  26. package/src/mcp/handlers/get-styles.ts +26 -0
  27. package/src/mcp/handlers/list-available-types.ts +27 -0
  28. package/src/mcp/handlers/move-element.ts +30 -0
  29. package/src/mcp/handlers/select-element.ts +25 -0
  30. package/src/mcp/handlers/update-props.ts +22 -0
  31. package/src/mcp/handlers/update-styles.ts +45 -0
  32. package/src/mcp/index.ts +9 -0
  33. package/src/sync/delete-element.ts +8 -2
  34. package/src/sync/drop-element.ts +30 -0
  35. package/src/sync/duplicate-element.ts +5 -15
  36. package/src/sync/duplicate-elements.ts +11 -5
  37. package/src/sync/get-current-document-container.ts +1 -1
  38. package/src/sync/get-element-editor-settings.ts +8 -0
  39. package/src/sync/get-element-interactions.ts +15 -0
  40. package/src/sync/get-element-label.ts +6 -1
  41. package/src/sync/get-element-type.ts +28 -0
  42. package/src/sync/get-elements.ts +1 -1
  43. package/src/sync/get-widgets-cache.ts +4 -3
  44. package/src/sync/move-elements.ts +9 -1
  45. package/src/sync/remove-elements.ts +11 -0
  46. package/src/sync/replace-element.ts +50 -12
  47. package/src/sync/types.ts +32 -3
  48. package/src/sync/update-element-editor-settings.ts +28 -0
  49. package/src/sync/update-element-interactions.ts +32 -0
  50. package/src/types.ts +16 -1
  51. package/src/hooks/use-element-type.ts +0 -35
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- // src/hooks/use-element-setting.ts
2
- import { __privateUseListenTo as useListenTo, commandEndEvent } from "@elementor/editor-v1-adapters";
1
+ // src/hooks/use-element-children.ts
2
+ import { __privateUseListenTo as useListenTo, commandEndEvent, v1ReadyEvent } from "@elementor/editor-v1-adapters";
3
3
 
4
4
  // src/sync/get-container.ts
5
5
  import { __privateRunCommand as runCommand } from "@elementor/editor-v1-adapters";
@@ -16,6 +16,53 @@ var selectElement = (elementId) => {
16
16
  }
17
17
  };
18
18
 
19
+ // src/hooks/use-element-children.ts
20
+ function useElementChildren(elementId, childrenTypes) {
21
+ return useListenTo(
22
+ [
23
+ v1ReadyEvent(),
24
+ commandEndEvent("document/elements/create"),
25
+ commandEndEvent("document/elements/delete"),
26
+ commandEndEvent("document/elements/update"),
27
+ commandEndEvent("document/elements/set-settings")
28
+ ],
29
+ () => {
30
+ const container = getContainer(elementId);
31
+ const elementChildren = Object.entries(childrenTypes).reduce((acc, [parentType, childType]) => {
32
+ const parent = container?.children?.findRecursive?.(
33
+ ({ model }) => model.get("elType") === parentType
34
+ );
35
+ const children = parent?.children ?? [];
36
+ acc[childType] = children.filter(({ model }) => model.get("elType") === childType).map(({ id }) => ({ id }));
37
+ return acc;
38
+ }, {});
39
+ return elementChildren;
40
+ },
41
+ [elementId]
42
+ );
43
+ }
44
+
45
+ // src/hooks/use-element-editor-settings.ts
46
+ import { __privateUseListenTo as useListenTo2, windowEvent } from "@elementor/editor-v1-adapters";
47
+
48
+ // src/sync/get-element-editor-settings.ts
49
+ function getElementEditorSettings(elementId) {
50
+ const container = getContainer(elementId);
51
+ return container?.model.get("editor_settings") ?? {};
52
+ }
53
+
54
+ // src/hooks/use-element-editor-settings.ts
55
+ var useElementEditorSettings = (elementId) => {
56
+ return useListenTo2(
57
+ windowEvent("elementor/element/update_editor_settings"),
58
+ () => getElementEditorSettings(elementId),
59
+ [elementId]
60
+ );
61
+ };
62
+
63
+ // src/hooks/use-element-setting.ts
64
+ import { __privateUseListenTo as useListenTo3, commandEndEvent as commandEndEvent2 } from "@elementor/editor-v1-adapters";
65
+
19
66
  // src/sync/get-element-setting.ts
20
67
  var getElementSetting = (elementId, settingKey) => {
21
68
  const container = getContainer(elementId);
@@ -27,15 +74,15 @@ var getElementSettings = (elementId, settingKey) => {
27
74
 
28
75
  // src/hooks/use-element-setting.ts
29
76
  var useElementSetting = (elementId, settingKey) => {
30
- return useListenTo(
31
- commandEndEvent("document/elements/set-settings"),
77
+ return useListenTo3(
78
+ commandEndEvent2("document/elements/set-settings"),
32
79
  () => getElementSetting(elementId, settingKey),
33
80
  [elementId, settingKey]
34
81
  );
35
82
  };
36
83
  var useElementSettings = (elementId, settingKeys) => {
37
- return useListenTo(
38
- commandEndEvent("document/elements/set-settings"),
84
+ return useListenTo3(
85
+ commandEndEvent2("document/elements/set-settings"),
39
86
  () => settingKeys.reduce((settings, key) => {
40
87
  const value = getElementSetting(elementId, key);
41
88
  if (value !== null) {
@@ -43,49 +90,61 @@ var useElementSettings = (elementId, settingKeys) => {
43
90
  }
44
91
  return settings;
45
92
  }, {}),
46
- [elementId, ...settingKeys]
93
+ [elementId, settingKeys.join(",")]
47
94
  );
48
95
  };
49
96
 
50
- // src/hooks/use-element-type.ts
51
- import { __privateUseListenTo as useListenTo2, commandEndEvent as commandEndEvent2 } from "@elementor/editor-v1-adapters";
52
-
53
- // src/sync/get-widgets-cache.ts
54
- function getWidgetsCache() {
55
- const extendedWindow = window;
56
- return extendedWindow?.elementor?.widgetsCache || null;
57
- }
58
-
59
- // src/hooks/use-element-type.ts
60
- function useElementType(type) {
61
- return useListenTo2(
62
- commandEndEvent2("editor/documents/load"),
97
+ // src/hooks/use-parent-element.ts
98
+ import { __privateUseListenTo as useListenTo4, commandEndEvent as commandEndEvent3 } from "@elementor/editor-v1-adapters";
99
+ function useParentElement(elementId) {
100
+ return useListenTo4(
101
+ [commandEndEvent3("document/elements/create")],
63
102
  () => {
64
- if (!type) {
65
- return null;
66
- }
67
- const widgetsCache = getWidgetsCache();
68
- const elementType = widgetsCache?.[type];
69
- if (!elementType?.atomic_controls) {
103
+ if (!elementId) {
70
104
  return null;
71
105
  }
72
- if (!elementType?.atomic_props_schema) {
106
+ const extendedWindow = window;
107
+ const element = extendedWindow?.elementor?.getContainer?.(elementId);
108
+ if (!element) {
73
109
  return null;
74
110
  }
75
- return {
76
- key: type,
77
- controls: elementType.atomic_controls,
78
- propsSchema: elementType.atomic_props_schema,
79
- dependenciesPerTargetMapping: elementType.dependencies_per_target_mapping ?? {},
80
- title: elementType.title
81
- };
111
+ return element.parent;
82
112
  },
83
- [type]
113
+ [elementId]
84
114
  );
85
115
  }
86
116
 
87
117
  // src/hooks/use-selected-element.ts
88
- import { __privateUseListenTo as useListenTo3, commandEndEvent as commandEndEvent3 } from "@elementor/editor-v1-adapters";
118
+ import { __privateUseListenTo as useListenTo5, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
119
+
120
+ // src/sync/get-widgets-cache.ts
121
+ function getWidgetsCache() {
122
+ const extendedWindow = window;
123
+ return extendedWindow?.elementor?.widgetsCache || null;
124
+ }
125
+
126
+ // src/sync/get-element-type.ts
127
+ function getElementType(type) {
128
+ if (!type) {
129
+ return null;
130
+ }
131
+ const widgetsCache = getWidgetsCache();
132
+ const elementType = widgetsCache?.[type];
133
+ if (!elementType?.atomic_controls) {
134
+ return null;
135
+ }
136
+ if (!elementType?.atomic_props_schema) {
137
+ return null;
138
+ }
139
+ return {
140
+ key: type,
141
+ controls: elementType.atomic_controls,
142
+ propsSchema: elementType.atomic_props_schema,
143
+ dependenciesPerTargetMapping: elementType.dependencies_per_target_mapping ?? {},
144
+ title: elementType.title,
145
+ styleStates: elementType.atomic_style_states ?? []
146
+ };
147
+ }
89
148
 
90
149
  // src/sync/get-selected-elements.ts
91
150
  function getSelectedElements() {
@@ -105,72 +164,23 @@ function getSelectedElements() {
105
164
 
106
165
  // src/hooks/use-selected-element.ts
107
166
  function useSelectedElement() {
108
- const elements = useListenTo3(
167
+ const elements = useListenTo5(
109
168
  [
110
- commandEndEvent3("document/elements/select"),
111
- commandEndEvent3("document/elements/deselect"),
112
- commandEndEvent3("document/elements/select-all"),
113
- commandEndEvent3("document/elements/deselect-all")
169
+ commandEndEvent4("document/elements/select"),
170
+ commandEndEvent4("document/elements/deselect"),
171
+ commandEndEvent4("document/elements/select-all"),
172
+ commandEndEvent4("document/elements/deselect-all")
114
173
  ],
115
174
  getSelectedElements
116
175
  );
117
176
  const [element] = elements;
118
- const elementType = useElementType(element?.type);
177
+ const elementType = getElementType(element?.type);
119
178
  if (elements.length !== 1 || !elementType) {
120
179
  return { element: null, elementType: null };
121
180
  }
122
181
  return { element, elementType };
123
182
  }
124
183
 
125
- // src/hooks/use-parent-element.ts
126
- import { __privateUseListenTo as useListenTo4, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
127
- function useParentElement(elementId) {
128
- return useListenTo4(
129
- [commandEndEvent4("document/elements/create")],
130
- () => {
131
- if (!elementId) {
132
- return null;
133
- }
134
- const extendedWindow = window;
135
- const element = extendedWindow?.elementor?.getContainer?.(elementId);
136
- if (!element) {
137
- return null;
138
- }
139
- return element.parent;
140
- },
141
- [elementId]
142
- );
143
- }
144
-
145
- // src/hooks/use-element-children.ts
146
- import { __privateUseListenTo as useListenTo5, commandEndEvent as commandEndEvent5, v1ReadyEvent } from "@elementor/editor-v1-adapters";
147
- function useElementChildren(elementId, childrenTypes) {
148
- return useListenTo5(
149
- [
150
- v1ReadyEvent(),
151
- commandEndEvent5("document/elements/create"),
152
- commandEndEvent5("document/elements/delete"),
153
- commandEndEvent5("document/elements/update"),
154
- commandEndEvent5("document/elements/set-settings")
155
- ],
156
- () => {
157
- const container = getContainer(elementId);
158
- const elementChildren = childrenTypes.reduce((acc, type) => {
159
- acc[type] = [];
160
- return acc;
161
- }, {});
162
- container?.children?.forEachRecursive?.(({ model, id }) => {
163
- const elType = model.get("elType");
164
- if (elType && elType in elementChildren) {
165
- elementChildren[elType].push({ id });
166
- }
167
- });
168
- return elementChildren;
169
- },
170
- [elementId]
171
- );
172
- }
173
-
174
184
  // src/sync/create-element.ts
175
185
  import { __privateRunCommandSync as runCommandSync } from "@elementor/editor-v1-adapters";
176
186
  function createElement({ containerId, model, options }) {
@@ -185,152 +195,33 @@ function createElement({ containerId, model, options }) {
185
195
  });
186
196
  }
187
197
 
198
+ // src/sync/create-elements.ts
199
+ import { undoable } from "@elementor/editor-v1-adapters";
200
+ import { __ } from "@wordpress/i18n";
201
+
188
202
  // src/sync/delete-element.ts
189
203
  import { __privateRunCommand as runCommand2 } from "@elementor/editor-v1-adapters";
190
- function deleteElement({ elementId, options = {} }) {
204
+ function deleteElement({
205
+ elementId,
206
+ options = {}
207
+ }) {
191
208
  const container = getContainer(elementId);
192
209
  if (!container) {
193
210
  throw new Error(`Element with ID "${elementId}" not found`);
194
211
  }
195
- runCommand2("document/elements/delete", {
212
+ return runCommand2("document/elements/delete", {
196
213
  container,
197
214
  options
198
215
  });
199
216
  }
200
217
 
201
- // src/sync/move-element.ts
202
- function moveElement({ elementId, targetContainerId, options = {} }) {
203
- const container = getContainer(elementId);
204
- const target = getContainer(targetContainerId);
205
- if (!container) {
206
- throw new Error(`Element with ID "${elementId}" not found`);
207
- }
208
- if (!target) {
209
- throw new Error(`Target container with ID "${targetContainerId}" not found`);
210
- }
211
- const modelToRecreate = container.model.toJSON();
212
- deleteElement({
213
- elementId,
214
- // prevent inner history from being created
215
- options: { ...options, useHistory: false }
216
- });
217
- const newContainer = createElement({
218
- containerId: targetContainerId,
219
- model: modelToRecreate,
220
- // prevent inner history from being created
221
- options: { edit: false, ...options, useHistory: false }
222
- });
223
- return newContainer;
224
- }
225
-
226
- // src/sync/move-elements.ts
227
- import { undoable } from "@elementor/editor-v1-adapters";
228
- import { __ } from "@wordpress/i18n";
229
- var moveElements = ({
230
- moves: movesToMake,
231
- title,
232
- subtitle = __("Elements moved", "elementor")
233
- }) => {
234
- const undoableMove = undoable(
235
- {
236
- do: ({ moves }) => {
237
- const movedElements = [];
238
- moves.forEach((move) => {
239
- const { elementId } = move;
240
- const sourceContainer = getContainer(elementId);
241
- if (!sourceContainer) {
242
- throw new Error(`Element with ID "${elementId}" not found`);
243
- }
244
- const originalContainerId = sourceContainer.parent?.id || "";
245
- const originalIndex = sourceContainer.parent?.children?.indexOf(sourceContainer) ?? -1;
246
- const originalPosition = {
247
- elementId,
248
- originalContainerId,
249
- originalIndex
250
- };
251
- const element = moveElement({
252
- ...move,
253
- options: { ...move.options, useHistory: false }
254
- });
255
- movedElements.push({
256
- elementId,
257
- originalPosition,
258
- move,
259
- element
260
- });
261
- });
262
- return { movedElements };
263
- },
264
- undo: (_, { movedElements }) => {
265
- [...movedElements].reverse().forEach(({ originalPosition }) => {
266
- const { elementId, originalContainerId, originalIndex } = originalPosition;
267
- moveElement({
268
- elementId,
269
- targetContainerId: originalContainerId,
270
- options: {
271
- useHistory: false,
272
- at: originalIndex >= 0 ? originalIndex : void 0
273
- }
274
- });
275
- });
276
- },
277
- redo: (_, { movedElements }) => {
278
- const newMovedElements = [];
279
- movedElements.forEach(({ move, originalPosition }) => {
280
- const element = moveElement({
281
- ...move,
282
- options: { ...move.options, useHistory: false }
283
- });
284
- newMovedElements.push({
285
- elementId: move.elementId,
286
- originalPosition,
287
- move,
288
- element
289
- });
290
- });
291
- return { movedElements: newMovedElements };
292
- }
293
- },
294
- {
295
- title,
296
- subtitle
297
- }
298
- );
299
- return undoableMove({ moves: movesToMake });
300
- };
301
-
302
- // src/sync/duplicate-element.ts
303
- function duplicateElement({ elementId, options = {} }) {
304
- const elementToDuplicate = getContainer(elementId);
305
- if (!elementToDuplicate) {
306
- throw new Error(`Element with ID "${elementId}" not found`);
307
- }
308
- if (!elementToDuplicate.parent) {
309
- throw new Error(`Element with ID "${elementId}" has no parent container`);
310
- }
311
- const parentContainer = elementToDuplicate.parent;
312
- const elementModel = elementToDuplicate.model.toJSON();
313
- const currentIndex = elementToDuplicate.view?._index ?? 0;
314
- const insertPosition = options.clone !== false ? currentIndex + 1 : void 0;
315
- return createElement({
316
- containerId: parentContainer.id,
317
- model: elementModel,
318
- options: {
319
- at: insertPosition,
320
- ...options
321
- }
322
- });
323
- }
324
-
325
218
  // src/sync/create-elements.ts
326
- import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
327
- import { __ as __2 } from "@wordpress/i18n";
328
219
  var createElements = ({
329
220
  elements,
330
221
  title,
331
- subtitle = __2("Item added", "elementor")
222
+ subtitle = __("Item added", "elementor")
332
223
  }) => {
333
- const undoableCreate = undoable2(
224
+ const undoableCreate = undoable(
334
225
  {
335
226
  do: ({ elements: elementsParam }) => {
336
227
  const createdElements = [];
@@ -388,24 +279,55 @@ var createElements = ({
388
279
  return undoableCreate({ elements });
389
280
  };
390
281
 
282
+ // src/sync/drop-element.ts
283
+ import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
284
+ function dropElement({ containerId, model, options }) {
285
+ const container = getContainer(containerId);
286
+ if (!container) {
287
+ throw new Error(`Container with ID "${containerId}" not found`);
288
+ }
289
+ return runCommandSync2("preview/drop", {
290
+ container,
291
+ model,
292
+ options
293
+ });
294
+ }
295
+
296
+ // src/sync/duplicate-element.ts
297
+ import { __privateRunCommandSync as runCommandSync3 } from "@elementor/editor-v1-adapters";
298
+ function duplicateElement({ elementId, options = {} }) {
299
+ const elementToDuplicate = getContainer(elementId);
300
+ if (!elementToDuplicate) {
301
+ throw new Error(`Element with ID "${elementId}" not found`);
302
+ }
303
+ const currentIndex = elementToDuplicate.view?._index ?? 0;
304
+ const insertPosition = options.clone !== false ? currentIndex + 1 : void 0;
305
+ return runCommandSync3("document/elements/duplicate", {
306
+ container: elementToDuplicate,
307
+ options: { at: insertPosition, edit: false, ...options }
308
+ });
309
+ }
310
+
391
311
  // src/sync/duplicate-elements.ts
392
- import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
393
- import { __ as __3 } from "@wordpress/i18n";
312
+ import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
313
+ import { __ as __2 } from "@wordpress/i18n";
394
314
  var duplicateElements = ({
395
315
  elementIds,
396
316
  title,
397
- subtitle = __3("Item duplicated", "elementor"),
398
- onCreate
317
+ subtitle = __2("Item duplicated", "elementor"),
318
+ onDuplicateElements,
319
+ onRestoreElements
399
320
  }) => {
400
- const undoableDuplicate = undoable3(
321
+ const undoableDuplicate = undoable2(
401
322
  {
402
323
  do: ({ elementIds: elementIdsToDuplicate }) => {
324
+ onDuplicateElements?.();
403
325
  const duplicatedElements = elementIdsToDuplicate.reduce((acc, elementId) => {
404
326
  const originalContainer = getContainer(elementId);
405
327
  if (originalContainer?.parent) {
406
328
  const duplicatedElement = duplicateElement({
407
329
  elementId,
408
- options: { useHistory: false, clone: true }
330
+ options: { useHistory: false }
409
331
  });
410
332
  acc.push({
411
333
  id: duplicatedElement.id,
@@ -418,9 +340,10 @@ var duplicateElements = ({
418
340
  }
419
341
  return acc;
420
342
  }, []);
421
- return { duplicatedElements: onCreate?.(duplicatedElements) ?? duplicatedElements };
343
+ return { duplicatedElements };
422
344
  },
423
345
  undo: (_, { duplicatedElements }) => {
346
+ onRestoreElements?.();
424
347
  [...duplicatedElements].reverse().forEach(({ id }) => {
425
348
  deleteElement({
426
349
  elementId: id,
@@ -429,6 +352,7 @@ var duplicateElements = ({
429
352
  });
430
353
  },
431
354
  redo: (_, { duplicatedElements: previousElements }) => {
355
+ onDuplicateElements?.();
432
356
  const duplicatedElements = previousElements.reduce((acc, previousElement) => {
433
357
  if (previousElement.modelToRestore && previousElement.parentContainerId) {
434
358
  const createdElement = createElement({
@@ -451,7 +375,7 @@ var duplicateElements = ({
451
375
  }
452
376
  return acc;
453
377
  }, []);
454
- return { duplicatedElements: onCreate?.(duplicatedElements) ?? duplicatedElements };
378
+ return { duplicatedElements };
455
379
  }
456
380
  },
457
381
  {
@@ -462,14 +386,202 @@ var duplicateElements = ({
462
386
  return undoableDuplicate({ elementIds });
463
387
  };
464
388
 
465
- // src/sync/remove-elements.ts
466
- import { undoable as undoable4 } from "@elementor/editor-v1-adapters";
467
- import { __ as __4 } from "@wordpress/i18n";
468
- var removeElements = ({
469
- elementIds,
470
- title,
471
- subtitle = __4("Item removed", "elementor")
472
- }) => {
389
+ // src/sync/generate-element-id.ts
390
+ var generateElementId = () => {
391
+ const extendedWindow = window;
392
+ return extendedWindow.elementorCommon?.helpers?.getUniqueId?.() ?? `el-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
393
+ };
394
+
395
+ // src/sync/get-current-document-container.ts
396
+ function getCurrentDocumentContainer() {
397
+ const extendedWindow = window;
398
+ return extendedWindow.elementor?.documents?.getCurrent?.()?.container ?? null;
399
+ }
400
+
401
+ // src/sync/get-current-document-id.ts
402
+ function getCurrentDocumentId() {
403
+ const extendedWindow = window;
404
+ return extendedWindow.elementor?.documents?.getCurrentId?.() ?? null;
405
+ }
406
+
407
+ // src/errors.ts
408
+ import { createError } from "@elementor/utils";
409
+ var ElementNotFoundError = createError({
410
+ code: "element_not_found",
411
+ message: "Element not found."
412
+ });
413
+ var StyleNotFoundError = createError({
414
+ code: "style_not_found",
415
+ message: "Style not found."
416
+ });
417
+ var ElementTypeNotExistsError = createError({
418
+ code: "element_type_not_exists",
419
+ message: "Element type does not exist."
420
+ });
421
+ var ElementLabelNotExistsError = createError({
422
+ code: "element_label_not_exists",
423
+ message: "Element label does not exist."
424
+ });
425
+ var ElementParentNotFoundError = createError({
426
+ code: "element_parent_not_found",
427
+ message: "Element parent not found."
428
+ });
429
+ var ElementIndexNotFoundError = createError({
430
+ code: "element_index_not_found",
431
+ message: "Element index not found."
432
+ });
433
+
434
+ // src/sync/get-element-label.ts
435
+ function getElementLabel(elementId) {
436
+ if (!elementId) {
437
+ elementId = getSelectedElements()?.[0]?.id;
438
+ }
439
+ const container = getContainer(elementId);
440
+ const type = container?.model.get("widgetType") || container?.model.get("elType");
441
+ if (!type) {
442
+ throw new ElementTypeNotExistsError({ context: { elementId } });
443
+ }
444
+ const label = getWidgetsCache()?.[type]?.title;
445
+ if (!label) {
446
+ throw new ElementLabelNotExistsError({ context: { elementType: type } });
447
+ }
448
+ return label;
449
+ }
450
+
451
+ // src/sync/get-element-styles.ts
452
+ var getElementStyles = (elementID) => {
453
+ const container = getContainer(elementID);
454
+ return container?.model.get("styles") || null;
455
+ };
456
+
457
+ // src/sync/get-elements.ts
458
+ function getElements(root) {
459
+ const container = root ? getContainer(root) : getCurrentDocumentContainer();
460
+ if (!container) {
461
+ return [];
462
+ }
463
+ const children = [...container.model.get("elements") ?? []].flatMap(
464
+ (childModel) => getElements(childModel.get("id"))
465
+ );
466
+ return [container, ...children];
467
+ }
468
+
469
+ // src/sync/move-element.ts
470
+ function moveElement({ elementId, targetContainerId, options = {} }) {
471
+ const container = getContainer(elementId);
472
+ const target = getContainer(targetContainerId);
473
+ if (!container) {
474
+ throw new Error(`Element with ID "${elementId}" not found`);
475
+ }
476
+ if (!target) {
477
+ throw new Error(`Target container with ID "${targetContainerId}" not found`);
478
+ }
479
+ const modelToRecreate = container.model.toJSON();
480
+ deleteElement({
481
+ elementId,
482
+ // prevent inner history from being created
483
+ options: { ...options, useHistory: false }
484
+ });
485
+ const newContainer = createElement({
486
+ containerId: targetContainerId,
487
+ model: modelToRecreate,
488
+ // prevent inner history from being created
489
+ options: { edit: false, ...options, useHistory: false }
490
+ });
491
+ return newContainer;
492
+ }
493
+
494
+ // src/sync/move-elements.ts
495
+ import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
496
+ import { __ as __3 } from "@wordpress/i18n";
497
+ var moveElements = ({
498
+ moves: movesToMake,
499
+ title,
500
+ subtitle = __3("Elements moved", "elementor"),
501
+ onMoveElements,
502
+ onRestoreElements
503
+ }) => {
504
+ const undoableMove = undoable3(
505
+ {
506
+ do: ({ moves }) => {
507
+ const movedElements = [];
508
+ onMoveElements?.();
509
+ moves.forEach((move) => {
510
+ const { elementId } = move;
511
+ const sourceContainer = getContainer(elementId);
512
+ if (!sourceContainer) {
513
+ throw new Error(`Element with ID "${elementId}" not found`);
514
+ }
515
+ const originalContainerId = sourceContainer.parent?.id || "";
516
+ const originalIndex = sourceContainer.parent?.children?.indexOf(sourceContainer) ?? -1;
517
+ const originalPosition = {
518
+ elementId,
519
+ originalContainerId,
520
+ originalIndex
521
+ };
522
+ const element = moveElement({
523
+ ...move,
524
+ options: { ...move.options, useHistory: false }
525
+ });
526
+ movedElements.push({
527
+ elementId,
528
+ originalPosition,
529
+ move,
530
+ element
531
+ });
532
+ });
533
+ return { movedElements };
534
+ },
535
+ undo: (_, { movedElements }) => {
536
+ onRestoreElements?.();
537
+ [...movedElements].reverse().forEach(({ originalPosition }) => {
538
+ const { elementId, originalContainerId, originalIndex } = originalPosition;
539
+ moveElement({
540
+ elementId,
541
+ targetContainerId: originalContainerId,
542
+ options: {
543
+ useHistory: false,
544
+ at: originalIndex >= 0 ? originalIndex : void 0
545
+ }
546
+ });
547
+ });
548
+ },
549
+ redo: (_, { movedElements }) => {
550
+ const newMovedElements = [];
551
+ onMoveElements?.();
552
+ movedElements.forEach(({ move, originalPosition }) => {
553
+ const element = moveElement({
554
+ ...move,
555
+ options: { ...move.options, useHistory: false }
556
+ });
557
+ newMovedElements.push({
558
+ elementId: move.elementId,
559
+ originalPosition,
560
+ move,
561
+ element
562
+ });
563
+ });
564
+ return { movedElements: newMovedElements };
565
+ }
566
+ },
567
+ {
568
+ title,
569
+ subtitle
570
+ }
571
+ );
572
+ return undoableMove({ moves: movesToMake });
573
+ };
574
+
575
+ // src/sync/remove-elements.ts
576
+ import { undoable as undoable4 } from "@elementor/editor-v1-adapters";
577
+ import { __ as __4 } from "@wordpress/i18n";
578
+ var removeElements = ({
579
+ elementIds,
580
+ title,
581
+ subtitle = __4("Item removed", "elementor"),
582
+ onRemoveElements,
583
+ onRestoreElements
584
+ }) => {
473
585
  const undoableRemove = undoable4(
474
586
  {
475
587
  do: ({ elementIds: elementIdsParam }) => {
@@ -488,6 +600,7 @@ var removeElements = ({
488
600
  });
489
601
  }
490
602
  });
603
+ onRemoveElements?.();
491
604
  elementIdsParam.forEach((elementId) => {
492
605
  deleteElement({
493
606
  elementId,
@@ -497,6 +610,7 @@ var removeElements = ({
497
610
  return { elementIds: elementIdsParam, removedElements };
498
611
  },
499
612
  undo: (_, { removedElements }) => {
613
+ onRestoreElements?.();
500
614
  [...removedElements].reverse().forEach(({ model, parent, at }) => {
501
615
  if (parent && model) {
502
616
  createElement({
@@ -508,6 +622,7 @@ var removeElements = ({
508
622
  });
509
623
  },
510
624
  redo: (_, { elementIds: originalElementIds, removedElements }) => {
625
+ onRemoveElements?.();
511
626
  originalElementIds.forEach((elementId) => {
512
627
  deleteElement({
513
628
  elementId,
@@ -525,71 +640,65 @@ var removeElements = ({
525
640
  return undoableRemove({ elementIds });
526
641
  };
527
642
 
528
- // src/sync/get-element-styles.ts
529
- var getElementStyles = (elementID) => {
530
- const container = getContainer(elementID);
531
- return container?.model.get("styles") || null;
643
+ // src/sync/replace-element.ts
644
+ var replaceElement = ({ currentElement, newElement, withHistory = true }) => {
645
+ const { containerId, index } = getNewElementLocation(currentElement, newElement);
646
+ createElement({
647
+ containerId,
648
+ model: newElement,
649
+ options: { at: index, useHistory: withHistory }
650
+ });
651
+ deleteElement({ elementId: currentElement.id, options: { useHistory: withHistory } });
532
652
  };
533
-
534
- // src/errors.ts
535
- import { createError } from "@elementor/utils";
536
- var ElementNotFoundError = createError({
537
- code: "element_not_found",
538
- message: "Element not found."
539
- });
540
- var StyleNotFoundError = createError({
541
- code: "style_not_found",
542
- message: "Style not found."
543
- });
544
- var ElementTypeNotExistsError = createError({
545
- code: "element_type_not_exists",
546
- message: "Element type does not exist."
547
- });
548
- var ElementLabelNotExistsError = createError({
549
- code: "element_label_not_exists",
550
- message: "Element label does not exist."
551
- });
552
-
553
- // src/sync/get-element-label.ts
554
- function getElementLabel(elementId) {
555
- const container = getContainer(elementId);
556
- const type = container?.model.get("widgetType") || container?.model.get("elType");
557
- if (!type) {
558
- throw new ElementTypeNotExistsError({ context: { elementId } });
653
+ function getNewElementLocation(currentElement, newElement) {
654
+ let location;
655
+ const currentElementContainer = getContainer(currentElement.id);
656
+ if (!currentElementContainer) {
657
+ throw new ElementNotFoundError({ context: { elementId: currentElement.id } });
559
658
  }
560
- const label = getWidgetsCache()?.[type]?.title;
561
- if (!label) {
562
- throw new ElementLabelNotExistsError({ context: { elementType: type } });
659
+ const parent = currentElementContainer.parent;
660
+ if (!parent) {
661
+ throw new ElementParentNotFoundError({ context: { elementId: currentElement.id } });
563
662
  }
564
- return label;
663
+ const elementIndex = currentElementContainer.view?._index ?? 0;
664
+ if (elementIndex === void 0 || elementIndex === -1) {
665
+ throw new ElementIndexNotFoundError({ context: { elementId: currentElement.id } });
666
+ }
667
+ location = { containerId: parent.id, index: elementIndex };
668
+ if (parent.id === "document" && newElement.elType === "widget") {
669
+ location = createWrapperForWidget(parent.id, elementIndex);
670
+ }
671
+ return location;
565
672
  }
566
-
567
- // src/sync/get-current-document-container.ts
568
- function getCurrentDocumentContainer() {
569
- const extendedWindow = window;
570
- return extendedWindow.elementor?.documents?.getCurrent?.()?.container ?? null;
673
+ function createWrapperForWidget(parentId, elementIndex) {
674
+ const container = createElement({
675
+ containerId: parentId,
676
+ model: { elType: "container" },
677
+ options: { at: elementIndex, useHistory: false }
678
+ });
679
+ return { containerId: container.id, index: 0 };
571
680
  }
572
681
 
573
- // src/sync/get-elements.ts
574
- function getElements(root) {
575
- const container = root ? getContainer(root) : getCurrentDocumentContainer();
576
- if (!container) {
577
- return [];
682
+ // src/sync/update-element-editor-settings.ts
683
+ import { __privateRunCommandSync as runCommandSync4 } from "@elementor/editor-v1-adapters";
684
+ var updateElementEditorSettings = ({
685
+ elementId,
686
+ settings
687
+ }) => {
688
+ const element = getContainer(elementId);
689
+ if (!element) {
690
+ throw new Error(`Element with id ${elementId} not found`);
578
691
  }
579
- const children = [...container.model.get("elements") ?? []].flatMap(
580
- (childModel) => getElements(childModel.get("id"))
581
- );
582
- return [container, ...children];
583
- }
584
-
585
- // src/sync/get-current-document-id.ts
586
- function getCurrentDocumentId() {
587
- const extendedWindow = window;
588
- return extendedWindow.elementor?.documents?.getCurrentId?.() ?? null;
692
+ const editorSettings = element.model.get("editor_settings") ?? {};
693
+ element.model.set("editor_settings", { ...editorSettings, ...settings });
694
+ setDocumentModifiedStatus(true);
695
+ };
696
+ function setDocumentModifiedStatus(status) {
697
+ runCommandSync4("document/save/set-is-modified", { status }, { internal: true });
589
698
  }
590
699
 
591
700
  // src/sync/update-element-settings.ts
592
- import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
701
+ import { __privateRunCommandSync as runCommandSync5 } from "@elementor/editor-v1-adapters";
593
702
  var updateElementSettings = ({ id, props, withHistory = true }) => {
594
703
  const container = getContainer(id);
595
704
  const args = {
@@ -597,45 +706,105 @@ var updateElementSettings = ({ id, props, withHistory = true }) => {
597
706
  settings: { ...props }
598
707
  };
599
708
  if (withHistory) {
600
- runCommandSync2("document/elements/settings", args);
709
+ runCommandSync5("document/elements/settings", args);
601
710
  } else {
602
- runCommandSync2("document/elements/set-settings", args, { internal: true });
711
+ runCommandSync5("document/elements/set-settings", args, { internal: true });
603
712
  }
604
713
  };
605
714
 
606
- // src/sync/generate-element-id.ts
607
- var generateElementId = () => {
608
- const extendedWindow = window;
609
- return extendedWindow.elementorCommon?.helpers?.getUniqueId?.() ?? `el-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
610
- };
611
-
612
- // src/sync/replace-element.ts
613
- var replaceElement = ({ currentElement, newElement, withHistory = true }) => {
614
- const parent = getContainer(currentElement.id)?.parent;
615
- if (!parent) {
616
- throw new Error(`Parent not found for element ${currentElement.id}. Cannot replace element.`);
715
+ // src/link-restriction.ts
716
+ function getLinkInLinkRestriction(elementId) {
717
+ const anchoredDescendantId = getAnchoredDescendantId(elementId);
718
+ if (anchoredDescendantId) {
719
+ return {
720
+ shouldRestrict: true,
721
+ reason: "descendant",
722
+ elementId: anchoredDescendantId
723
+ };
617
724
  }
618
- const elementIndex = parent.children?.findIndex((child) => child.id === currentElement.id);
619
- if (elementIndex === void 0 || elementIndex === -1) {
620
- throw new Error(`Element ${currentElement.id} not found in parent container. Cannot replace element.`);
725
+ const ancestor = getAnchoredAncestorId(elementId);
726
+ if (ancestor) {
727
+ return {
728
+ shouldRestrict: true,
729
+ reason: "ancestor",
730
+ elementId: ancestor
731
+ };
621
732
  }
622
- createElement({
623
- containerId: parent.id,
624
- model: newElement,
625
- options: { at: elementIndex, useHistory: withHistory }
626
- });
627
- deleteElement({ elementId: currentElement.id, options: { useHistory: withHistory } });
628
- };
733
+ return {
734
+ shouldRestrict: false
735
+ };
736
+ }
737
+ function getAnchoredDescendantId(elementId) {
738
+ const element = getElementDOM(elementId);
739
+ if (!element) {
740
+ return null;
741
+ }
742
+ for (const childAnchorElement of Array.from(element.querySelectorAll("a"))) {
743
+ const childElementId = findElementIdOf(childAnchorElement);
744
+ if (childElementId !== elementId) {
745
+ return childElementId;
746
+ }
747
+ }
748
+ return null;
749
+ }
750
+ function getAnchoredAncestorId(elementId) {
751
+ const element = getElementDOM(elementId);
752
+ if (!element || element.parentElement === null) {
753
+ return null;
754
+ }
755
+ const parentAnchor = element.parentElement.closest("a");
756
+ return parentAnchor ? findElementIdOf(parentAnchor) : null;
757
+ }
758
+ function isElementAnchored(elementId) {
759
+ const element = getElementDOM(elementId);
760
+ if (!element) {
761
+ return false;
762
+ }
763
+ if (isAnchorTag(element.tagName)) {
764
+ return true;
765
+ }
766
+ return doesElementContainAnchor(element);
767
+ }
768
+ function doesElementContainAnchor(element) {
769
+ for (const child of element.children) {
770
+ if (isElementorElement(child)) {
771
+ continue;
772
+ }
773
+ if (isAnchorTag(child.tagName)) {
774
+ return true;
775
+ }
776
+ if (doesElementContainAnchor(child)) {
777
+ return true;
778
+ }
779
+ }
780
+ return false;
781
+ }
782
+ function findElementIdOf(element) {
783
+ return element.closest("[data-id]")?.dataset.id || null;
784
+ }
785
+ function getElementDOM(id) {
786
+ try {
787
+ return getContainer(id)?.view?.el || null;
788
+ } catch {
789
+ return null;
790
+ }
791
+ }
792
+ function isAnchorTag(tagName) {
793
+ return tagName.toLowerCase() === "a";
794
+ }
795
+ function isElementorElement(element) {
796
+ return element.hasAttribute("data-id");
797
+ }
629
798
 
630
799
  // src/styles/consts.ts
631
- import { commandEndEvent as commandEndEvent6, windowEvent } from "@elementor/editor-v1-adapters";
800
+ import { commandEndEvent as commandEndEvent5, windowEvent as windowEvent2 } from "@elementor/editor-v1-adapters";
632
801
  var ELEMENT_STYLE_CHANGE_EVENT = "elementor/editor-v2/editor-elements/style";
633
802
  var styleRerenderEvents = [
634
- commandEndEvent6("document/elements/create"),
635
- commandEndEvent6("document/elements/duplicate"),
636
- commandEndEvent6("document/elements/import"),
637
- commandEndEvent6("document/elements/paste"),
638
- windowEvent(ELEMENT_STYLE_CHANGE_EVENT)
803
+ commandEndEvent5("document/elements/create"),
804
+ commandEndEvent5("document/elements/duplicate"),
805
+ commandEndEvent5("document/elements/import"),
806
+ commandEndEvent5("document/elements/paste"),
807
+ windowEvent2(ELEMENT_STYLE_CHANGE_EVENT)
639
808
  ];
640
809
 
641
810
  // src/styles/create-element-style.ts
@@ -646,7 +815,7 @@ import {
646
815
 
647
816
  // src/styles/mutate-element-styles.ts
648
817
  import { classesPropTypeUtil } from "@elementor/editor-props";
649
- import { __privateRunCommandSync as runCommandSync3 } from "@elementor/editor-v1-adapters";
818
+ import { __privateRunCommandSync as runCommandSync6 } from "@elementor/editor-v1-adapters";
650
819
  function mutateElementStyles(elementId, mutator) {
651
820
  const container = getContainer(elementId);
652
821
  if (!container) {
@@ -702,7 +871,7 @@ function getClassesProps(container) {
702
871
  }
703
872
  function notifyChanges() {
704
873
  dispatchChangeEvent();
705
- runCommandSync3("document/save/set-is-modified", { status: true }, { internal: true });
874
+ runCommandSync6("document/save/set-is-modified", { status: true }, { internal: true });
706
875
  }
707
876
  function dispatchChangeEvent() {
708
877
  window.dispatchEvent(new CustomEvent(ELEMENT_STYLE_CHANGE_EVENT));
@@ -754,6 +923,14 @@ function shouldCreateNewLocalStyle(payload) {
754
923
  return !payload?.styleId && !payload?.provider;
755
924
  }
756
925
 
926
+ // src/styles/delete-element-style.ts
927
+ function deleteElementStyle(elementId, styleId) {
928
+ mutateElementStyles(elementId, (styles) => {
929
+ delete styles[styleId];
930
+ return styles;
931
+ });
932
+ }
933
+
757
934
  // src/styles/update-element-style.ts
758
935
  import { mergeProps } from "@elementor/editor-props";
759
936
  import { getVariantByMeta } from "@elementor/editor-styles";
@@ -775,96 +952,663 @@ function updateElementStyle(args) {
775
952
  });
776
953
  }
777
954
 
778
- // src/styles/delete-element-style.ts
779
- function deleteElementStyle(elementId, styleId) {
780
- mutateElementStyles(elementId, (styles) => {
781
- delete styles[styleId];
782
- return styles;
955
+ // src/hooks/use-element-interactions.ts
956
+ import { useState } from "react";
957
+ import { __privateUseListenTo as useListenTo6, windowEvent as windowEvent3 } from "@elementor/editor-v1-adapters";
958
+
959
+ // src/sync/get-element-interactions.ts
960
+ function getElementInteractions(elementId) {
961
+ const container = getContainer(elementId);
962
+ const interactions = container?.model?.get("interactions");
963
+ if (typeof interactions === "string") {
964
+ return JSON.parse(interactions);
965
+ }
966
+ return interactions;
967
+ }
968
+
969
+ // src/hooks/use-element-interactions.ts
970
+ var useElementInteractions = (elementId) => {
971
+ const [interactions, setInteractions] = useState(() => {
972
+ const initial = getElementInteractions(elementId);
973
+ return initial ?? { version: 1, items: [] };
783
974
  });
975
+ useListenTo6(
976
+ windowEvent3("elementor/element/update_interactions"),
977
+ () => {
978
+ const newInteractions = getElementInteractions(elementId);
979
+ setInteractions(newInteractions ?? { version: 1, items: [] });
980
+ },
981
+ [elementId]
982
+ );
983
+ return interactions;
984
+ };
985
+
986
+ // src/sync/update-element-interactions.ts
987
+ import { __privateRunCommandSync as runCommandSync7 } from "@elementor/editor-v1-adapters";
988
+ var updateElementInteractions = ({
989
+ elementId,
990
+ interactions
991
+ }) => {
992
+ const element = getContainer(elementId);
993
+ if (!element) {
994
+ throw new Error(`Element with id ${elementId} not found`);
995
+ }
996
+ element.model.set("interactions", interactions);
997
+ window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
998
+ setDocumentModifiedStatus2(true);
999
+ };
1000
+ var playElementInteractions = (elementId, animationId) => {
1001
+ window.top?.dispatchEvent(new CustomEvent("atomic/play_interactions", { detail: { elementId, animationId } }));
1002
+ };
1003
+ function setDocumentModifiedStatus2(status) {
1004
+ runCommandSync7("document/save/set-is-modified", { status }, { internal: true });
784
1005
  }
785
1006
 
786
- // src/link-restriction.ts
787
- function getLinkInLinkRestriction(elementId) {
788
- const anchoredDescendantId = getAnchoredDescendantId(elementId);
789
- if (anchoredDescendantId) {
790
- return {
791
- shouldRestrict: true,
792
- reason: "descendant",
793
- elementId: anchoredDescendantId
794
- };
1007
+ // src/mcp/index.ts
1008
+ import { getMCPByDomain as getMCPByDomain2 } from "@elementor/editor-mcp";
1009
+
1010
+ // src/mcp/elements-tool.ts
1011
+ import { getMCPByDomain } from "@elementor/editor-mcp";
1012
+ import { z } from "@elementor/schema";
1013
+
1014
+ // src/mcp/handlers/create-element.ts
1015
+ function handleCreateElement({
1016
+ elementType,
1017
+ containerId,
1018
+ props = {},
1019
+ styles
1020
+ }) {
1021
+ let container = containerId === "document" ? getCurrentDocumentContainer() : getContainer(containerId);
1022
+ if (!container) {
1023
+ if (containerId === "document") {
1024
+ throw new Error("Document container not found. Please ensure the editor is initialized.");
1025
+ }
1026
+ throw new Error(`Container with ID "${containerId}" not found`);
795
1027
  }
796
- const ancestor = getAnchoredAncestorId(elementId);
797
- if (ancestor) {
798
- return {
799
- shouldRestrict: true,
800
- reason: "ancestor",
801
- elementId: ancestor
1028
+ const containerElType = container.model.get("elType");
1029
+ const isDocument = container.id === "document" || containerElType === "document";
1030
+ if (isDocument) {
1031
+ const containerModel = {
1032
+ elType: "e-div-block"
802
1033
  };
1034
+ const createdContainer = createElement({
1035
+ containerId: container.id,
1036
+ model: containerModel,
1037
+ options: { useHistory: true }
1038
+ });
1039
+ createElementStyle({
1040
+ elementId: createdContainer.id,
1041
+ classesProp: "classes",
1042
+ label: "local",
1043
+ meta: { breakpoint: "desktop", state: null },
1044
+ props: {
1045
+ display: { $$type: "string", value: "flex" },
1046
+ "flex-direction": { $$type: "string", value: "row" },
1047
+ "flex-wrap": { $$type: "string", value: "wrap" }
1048
+ }
1049
+ });
1050
+ container = getContainer(createdContainer.id);
1051
+ if (!container) {
1052
+ throw new Error("Failed to create container for widget. Cannot create widgets directly in the document.");
1053
+ }
1054
+ }
1055
+ const actualContainerId = container.id;
1056
+ const elementTypeData = getElementType(elementType);
1057
+ if (!elementTypeData) {
1058
+ throw new Error(`Element type "${elementType}" not found or is not atomic`);
1059
+ }
1060
+ const model = {
1061
+ widgetType: elementType,
1062
+ elType: "widget",
1063
+ settings: props
1064
+ };
1065
+ const createdElement = createElement({
1066
+ containerId: actualContainerId,
1067
+ model,
1068
+ options: { useHistory: true }
1069
+ });
1070
+ if (styles) {
1071
+ createElementStyle({
1072
+ elementId: createdElement.id,
1073
+ classesProp: "classes",
1074
+ label: "local",
1075
+ meta: { breakpoint: "desktop", state: null },
1076
+ props: styles
1077
+ });
803
1078
  }
804
1079
  return {
805
- shouldRestrict: false
1080
+ elementId: createdElement.id,
1081
+ type: elementType
806
1082
  };
807
1083
  }
808
- function getAnchoredDescendantId(elementId) {
809
- const element = getElementDOM(elementId);
810
- if (!element) {
1084
+
1085
+ // src/mcp/handlers/common-style-utils.ts
1086
+ var VALID_BREAKPOINTS = [
1087
+ "widescreen",
1088
+ "desktop",
1089
+ "laptop",
1090
+ "tablet_extra",
1091
+ "tablet",
1092
+ "mobile_extra",
1093
+ "mobile"
1094
+ ];
1095
+ function resolveBreakpointId(breakpoint) {
1096
+ if (breakpoint === null) {
811
1097
  return null;
812
1098
  }
813
- for (const childAnchorElement of Array.from(element.querySelectorAll("a"))) {
814
- const childElementId = findElementIdOf(childAnchorElement);
815
- if (childElementId !== elementId) {
816
- return childElementId;
817
- }
1099
+ if (VALID_BREAKPOINTS.includes(breakpoint)) {
1100
+ return breakpoint;
818
1101
  }
819
- return null;
1102
+ return "desktop";
820
1103
  }
821
- function getAnchoredAncestorId(elementId) {
822
- const element = getElementDOM(elementId);
823
- if (!element || element.parentElement === null) {
824
- return null;
1104
+
1105
+ // src/mcp/handlers/create-style.ts
1106
+ function handleCreateStyle({
1107
+ elementId,
1108
+ styleId,
1109
+ classesProp = "classes",
1110
+ label = "local",
1111
+ styles,
1112
+ breakpoint = "desktop",
1113
+ state = null,
1114
+ customCss = null
1115
+ }) {
1116
+ const resolvedBreakpoint = resolveBreakpointId(breakpoint);
1117
+ const resolvedState = state === null || state === void 0 ? null : state;
1118
+ const createdStyleId = createElementStyle({
1119
+ styleId,
1120
+ elementId,
1121
+ classesProp,
1122
+ label,
1123
+ meta: { breakpoint: resolvedBreakpoint, state: resolvedState },
1124
+ props: styles,
1125
+ custom_css: customCss
1126
+ });
1127
+ return { styleId: createdStyleId };
1128
+ }
1129
+
1130
+ // src/mcp/handlers/delete-element.ts
1131
+ function handleDeleteElement(elementId) {
1132
+ const container = getContainer(elementId);
1133
+ if (!container) {
1134
+ throw new Error(`Element with ID "${elementId}" not found`);
825
1135
  }
826
- const parentAnchor = element.parentElement.closest("a");
827
- return parentAnchor ? findElementIdOf(parentAnchor) : null;
1136
+ deleteElement({
1137
+ elementId,
1138
+ options: { useHistory: true }
1139
+ });
1140
+ return { success: true };
828
1141
  }
829
- function isElementAnchored(elementId) {
830
- const element = getElementDOM(elementId);
831
- if (!element) {
832
- return false;
1142
+
1143
+ // src/mcp/handlers/delete-style.ts
1144
+ function handleDeleteStyle({ elementId, styleId }) {
1145
+ const elementStyles = getElementStyles(elementId);
1146
+ if (!elementStyles) {
1147
+ throw new Error(`Element with ID "${elementId}" has no styles.`);
833
1148
  }
834
- if (isAnchorTag(element.tagName)) {
835
- return true;
1149
+ const resolvedStyleId = styleId || Object.keys(elementStyles)[0];
1150
+ if (!resolvedStyleId) {
1151
+ throw new Error(`Element with ID "${elementId}" has no styles to delete.`);
836
1152
  }
837
- return doesElementContainAnchor(element);
1153
+ deleteElementStyle(elementId, resolvedStyleId);
1154
+ return { success: true };
838
1155
  }
839
- function doesElementContainAnchor(element) {
840
- for (const child of element.children) {
841
- if (isElementorElement(child)) {
842
- continue;
843
- }
844
- if (isAnchorTag(child.tagName)) {
845
- return true;
1156
+
1157
+ // src/mcp/handlers/deselect-element.ts
1158
+ import { __privateRunCommand as runCommand3 } from "@elementor/editor-v1-adapters";
1159
+ function handleDeselectElement(elementId) {
1160
+ const container = getContainer(elementId);
1161
+ if (!container) {
1162
+ throw new Error(`Element with ID "${elementId}" not found`);
1163
+ }
1164
+ runCommand3("document/elements/deselect", { container });
1165
+ return { success: true };
1166
+ }
1167
+ function handleDeselectAllElements() {
1168
+ runCommand3("document/elements/deselect-all", {});
1169
+ return { success: true };
1170
+ }
1171
+
1172
+ // src/mcp/handlers/duplicate-element.ts
1173
+ function handleDuplicateElement(elementId) {
1174
+ const container = getContainer(elementId);
1175
+ if (!container) {
1176
+ throw new Error(`Element with ID "${elementId}" not found`);
1177
+ }
1178
+ const duplicatedElement = duplicateElement({
1179
+ elementId,
1180
+ options: { useHistory: true }
1181
+ });
1182
+ const type = duplicatedElement.model.get("widgetType") || duplicatedElement.model.get("elType") || "";
1183
+ return {
1184
+ elementId: duplicatedElement.id,
1185
+ type
1186
+ };
1187
+ }
1188
+
1189
+ // src/mcp/handlers/get-element-props.ts
1190
+ function handleGetElementProps(elementId) {
1191
+ const container = getContainer(elementId);
1192
+ if (!container) {
1193
+ throw new Error(`Element with ID "${elementId}" not found`);
1194
+ }
1195
+ const type = container.model.get("widgetType") || container.model.get("elType");
1196
+ if (!type) {
1197
+ throw new Error(`Element with ID "${elementId}" has no type`);
1198
+ }
1199
+ const elementType = getElementType(type);
1200
+ if (!elementType) {
1201
+ throw new Error(`Element type "${type}" is not atomic`);
1202
+ }
1203
+ const propsSchema = elementType.propsSchema;
1204
+ const propKeys = Object.keys(propsSchema);
1205
+ return getElementSettings(elementId, propKeys);
1206
+ }
1207
+
1208
+ // src/mcp/handlers/get-element-schema.ts
1209
+ import { getStylesSchema } from "@elementor/editor-styles";
1210
+ function handleGetElementSchema(elementType) {
1211
+ const elementTypeData = getElementType(elementType);
1212
+ if (!elementTypeData) {
1213
+ throw new Error(`Element type "${elementType}" not found or is not atomic`);
1214
+ }
1215
+ return { ...elementTypeData, stylesSchema: getStylesSchema() };
1216
+ }
1217
+
1218
+ // src/mcp/handlers/get-selected.ts
1219
+ function handleGetSelected() {
1220
+ return getSelectedElements();
1221
+ }
1222
+
1223
+ // src/mcp/handlers/get-styles.ts
1224
+ function handleGetStyles(elementId) {
1225
+ const styles = getElementStyles(elementId);
1226
+ if (!styles) {
1227
+ return null;
1228
+ }
1229
+ return Object.fromEntries(
1230
+ Object.entries(styles).map(([id, style]) => [
1231
+ id,
1232
+ {
1233
+ id: style.id,
1234
+ label: style.label,
1235
+ type: style.type,
1236
+ variants: style.variants.map((variant) => ({
1237
+ meta: variant.meta,
1238
+ props: variant.props,
1239
+ custom_css: variant.custom_css
1240
+ }))
1241
+ }
1242
+ ])
1243
+ );
1244
+ }
1245
+
1246
+ // src/mcp/handlers/list-available-types.ts
1247
+ function handleListAvailableTypes() {
1248
+ const widgetsCache = getWidgetsCache();
1249
+ if (!widgetsCache) {
1250
+ return [];
1251
+ }
1252
+ const availableTypes = [];
1253
+ Object.entries(widgetsCache).forEach(([type, config]) => {
1254
+ if (config?.atomic_controls && config?.atomic_props_schema) {
1255
+ availableTypes.push({
1256
+ type,
1257
+ title: config.title || type
1258
+ });
846
1259
  }
847
- if (doesElementContainAnchor(child)) {
848
- return true;
1260
+ });
1261
+ return availableTypes;
1262
+ }
1263
+
1264
+ // src/mcp/handlers/move-element.ts
1265
+ function handleMoveElement({
1266
+ elementId,
1267
+ targetContainerId
1268
+ }) {
1269
+ const container = getContainer(elementId);
1270
+ if (!container) {
1271
+ throw new Error(`Element with ID "${elementId}" not found`);
1272
+ }
1273
+ const targetContainer = getContainer(targetContainerId);
1274
+ if (!targetContainer) {
1275
+ throw new Error(`Target container with ID "${targetContainerId}" not found`);
1276
+ }
1277
+ moveElement({
1278
+ elementId,
1279
+ targetContainerId,
1280
+ options: { useHistory: true }
1281
+ });
1282
+ return { success: true };
1283
+ }
1284
+
1285
+ // src/mcp/handlers/select-element.ts
1286
+ function handleSelectElement(elementId) {
1287
+ const container = getContainer(elementId);
1288
+ if (!container) {
1289
+ throw new Error(`Element with ID "${elementId}" not found`);
1290
+ }
1291
+ selectElement(elementId);
1292
+ return { success: true };
1293
+ }
1294
+ function handleSelectMultipleElements(elementIds) {
1295
+ elementIds.forEach((elementId) => {
1296
+ const container = getContainer(elementId);
1297
+ if (container) {
1298
+ selectElement(elementId);
849
1299
  }
1300
+ });
1301
+ return { success: true };
1302
+ }
1303
+
1304
+ // src/mcp/handlers/update-props.ts
1305
+ function handleUpdateProps({ elementId, props }) {
1306
+ const container = getContainer(elementId);
1307
+ if (!container) {
1308
+ throw new Error(`Element with ID "${elementId}" not found`);
850
1309
  }
851
- return false;
1310
+ updateElementSettings({
1311
+ id: elementId,
1312
+ props,
1313
+ withHistory: true
1314
+ });
1315
+ return { success: true };
852
1316
  }
853
- function findElementIdOf(element) {
854
- return element.closest("[data-id]")?.dataset.id || null;
1317
+
1318
+ // src/mcp/handlers/update-styles.ts
1319
+ function handleUpdateStyles({
1320
+ elementId,
1321
+ styleId,
1322
+ styles,
1323
+ breakpoint = "desktop",
1324
+ state = null
1325
+ }) {
1326
+ const resolvedBreakpoint = resolveBreakpointId(breakpoint);
1327
+ const resolvedState = state === null || state === void 0 ? null : state;
1328
+ const elementStyles = getElementStyles(elementId);
1329
+ if (!elementStyles) {
1330
+ throw new Error(`Element with ID "${elementId}" has no styles. Create a style first.`);
1331
+ }
1332
+ const resolvedStyleId = styleId || Object.keys(elementStyles)[0];
1333
+ if (!resolvedStyleId) {
1334
+ throw new Error(`Element with ID "${elementId}" has no styles. Create a style first.`);
1335
+ }
1336
+ updateElementStyle({
1337
+ elementId,
1338
+ styleId: resolvedStyleId,
1339
+ meta: { breakpoint: resolvedBreakpoint, state: resolvedState },
1340
+ props: styles
1341
+ });
1342
+ return { success: true };
855
1343
  }
856
- function getElementDOM(id) {
1344
+
1345
+ // src/mcp/elements-tool.ts
1346
+ var actionEnum = z.enum([
1347
+ "get-element-schema",
1348
+ "get-element-props",
1349
+ "create-element",
1350
+ "update-props",
1351
+ "create-style",
1352
+ "get-styles",
1353
+ "update-styles",
1354
+ "delete-style",
1355
+ "delete",
1356
+ "duplicate",
1357
+ "move",
1358
+ "select",
1359
+ "deselect",
1360
+ "deselect-all",
1361
+ "get-selected",
1362
+ "list-available-types"
1363
+ ]);
1364
+ var schema = {
1365
+ action: actionEnum.describe("The element operation to perform."),
1366
+ elementId: z.string().optional().describe("The ID of the target element"),
1367
+ elementIds: z.array(z.string()).optional().describe("Array of element IDs for multi-element operations"),
1368
+ elementType: z.string().optional().describe(
1369
+ "The type of element to create. Must be an atomic element type (required for create-element and get-element-schema actions)"
1370
+ ),
1371
+ props: z.record(z.any()).optional().describe("Props object for creating or updating an element. Must match the element type's propsSchema."),
1372
+ containerId: z.string().optional().describe(
1373
+ 'Parent container ID for element creation or move operations. Use "document" if parent is the document root.'
1374
+ ),
1375
+ targetContainerId: z.string().optional().describe("Target container ID for move operations"),
1376
+ styles: z.record(z.any()).optional().describe(
1377
+ "Styles object for creating or updating element styles. Must match the element type's stylesSchema."
1378
+ ),
1379
+ styleId: z.string().optional().describe(
1380
+ "Style definition ID for style operations. If not provided, the first available style will be used (for update/delete)."
1381
+ ),
1382
+ breakpoint: z.string().optional().describe('Breakpoint for style operations (e.g., "desktop", "tablet", "mobile"). Defaults to "desktop".'),
1383
+ state: z.string().optional().describe('State for style operations (e.g., "hover", "active", or null). Defaults to null.'),
1384
+ classesProp: z.string().optional().describe('Classes property name for create-style action. Defaults to "classes".'),
1385
+ label: z.string().optional().describe('Label for create-style action. Defaults to "local".'),
1386
+ custom_css: z.object({ raw: z.string() }).optional().describe("Custom CSS object with raw CSS string for create-style action.")
1387
+ };
1388
+ function routeAction(params) {
857
1389
  try {
858
- return getContainer(id)?.view?.el || null;
859
- } catch {
860
- return null;
1390
+ switch (params.action) {
1391
+ case "get-element-schema":
1392
+ if (!params.elementType) {
1393
+ throw new Error("elementType is required for get-element-schema action");
1394
+ }
1395
+ return handleGetElementSchema(params.elementType);
1396
+ case "get-element-props":
1397
+ if (!params.elementId) {
1398
+ throw new Error("elementId is required for get-element-props action");
1399
+ }
1400
+ return handleGetElementProps(params.elementId);
1401
+ case "create-element":
1402
+ if (!params.elementType) {
1403
+ throw new Error("elementType is required for create-element action");
1404
+ }
1405
+ if (!params.containerId) {
1406
+ throw new Error("containerId is required for create-element action");
1407
+ }
1408
+ return handleCreateElement({
1409
+ elementType: params.elementType,
1410
+ containerId: params.containerId,
1411
+ props: params.props,
1412
+ styles: params.styles
1413
+ });
1414
+ case "update-props":
1415
+ if (!params.elementId) {
1416
+ throw new Error("elementId is required for update-props action");
1417
+ }
1418
+ if (!params.props) {
1419
+ throw new Error("props is required for update-props action");
1420
+ }
1421
+ return handleUpdateProps({
1422
+ elementId: params.elementId,
1423
+ props: params.props
1424
+ });
1425
+ case "create-style":
1426
+ if (!params.elementId) {
1427
+ throw new Error("elementId is required for create-style action");
1428
+ }
1429
+ if (!params.styles) {
1430
+ throw new Error("styles is required for create-style action");
1431
+ }
1432
+ return handleCreateStyle({
1433
+ elementId: params.elementId,
1434
+ styleId: params.styleId,
1435
+ classesProp: params.classesProp,
1436
+ label: params.label,
1437
+ styles: params.styles,
1438
+ breakpoint: params.breakpoint,
1439
+ state: params.state,
1440
+ customCss: params.custom_css
1441
+ });
1442
+ case "get-styles":
1443
+ if (!params.elementId) {
1444
+ throw new Error("elementId is required for get-styles action");
1445
+ }
1446
+ return handleGetStyles(params.elementId);
1447
+ case "update-styles":
1448
+ if (!params.elementId) {
1449
+ throw new Error("elementId is required for update-styles action");
1450
+ }
1451
+ if (!params.styles) {
1452
+ throw new Error("styles is required for update-styles action");
1453
+ }
1454
+ return handleUpdateStyles({
1455
+ elementId: params.elementId,
1456
+ styleId: params.styleId,
1457
+ styles: params.styles,
1458
+ breakpoint: params.breakpoint,
1459
+ state: params.state
1460
+ });
1461
+ case "delete-style":
1462
+ if (!params.elementId) {
1463
+ throw new Error("elementId is required for delete-style action");
1464
+ }
1465
+ return handleDeleteStyle({
1466
+ elementId: params.elementId,
1467
+ styleId: params.styleId
1468
+ });
1469
+ case "delete":
1470
+ if (!params.elementId) {
1471
+ throw new Error("elementId is required for delete action");
1472
+ }
1473
+ return handleDeleteElement(params.elementId);
1474
+ case "duplicate":
1475
+ if (!params.elementId) {
1476
+ throw new Error("elementId is required for duplicate action");
1477
+ }
1478
+ return handleDuplicateElement(params.elementId);
1479
+ case "move":
1480
+ if (!params.elementId) {
1481
+ throw new Error("elementId is required for move action");
1482
+ }
1483
+ if (!params.targetContainerId) {
1484
+ throw new Error("targetContainerId is required for move action");
1485
+ }
1486
+ return handleMoveElement({
1487
+ elementId: params.elementId,
1488
+ targetContainerId: params.targetContainerId
1489
+ });
1490
+ case "select":
1491
+ if (params.elementIds && params.elementIds.length > 0) {
1492
+ return handleSelectMultipleElements(params.elementIds);
1493
+ }
1494
+ if (!params.elementId) {
1495
+ throw new Error("elementId or elementIds is required for select action");
1496
+ }
1497
+ return handleSelectElement(params.elementId);
1498
+ case "deselect":
1499
+ if (!params.elementId) {
1500
+ throw new Error("elementId is required for deselect action");
1501
+ }
1502
+ return handleDeselectElement(params.elementId);
1503
+ case "deselect-all":
1504
+ return handleDeselectAllElements();
1505
+ case "get-selected":
1506
+ return handleGetSelected();
1507
+ case "list-available-types":
1508
+ return handleListAvailableTypes();
1509
+ default:
1510
+ throw new Error(`Unknown action: ${params.action}`);
1511
+ }
1512
+ } catch (error) {
1513
+ const errorMessage = error instanceof Error ? error.message : String(error);
1514
+ throw new Error(`Failed to execute action "${params.action}": ${errorMessage}`);
861
1515
  }
862
1516
  }
863
- function isAnchorTag(tagName) {
864
- return tagName.toLowerCase() === "a";
1517
+ function initElementsTool() {
1518
+ getMCPByDomain("elements").addTool({
1519
+ name: "elements",
1520
+ schema,
1521
+ description: `This tool manages individual Elementor atomic elements (v4).
1522
+
1523
+ **When to use this tool:**
1524
+
1525
+ Use this tool to create, update, delete, duplicate, move, and select individual atomic elements, as well as retrieve their schemas and current props.
1526
+
1527
+ **Available actions:**
1528
+
1529
+ - \`list-available-types\`: List all available atomic element types.
1530
+ - \`get-element-schema\`: Get the propsSchema and controls for an element type. Required before creating elements of a new type.
1531
+ - \`get-element-props\`: Get the current prop values for an existing element.
1532
+ - \`create-element\`: Create a new atomic element with specified props and styles (Important to match props and styles by the schema, use get-element-schema to get the schema first).
1533
+ - \`update-props\`: Update props for an existing element.
1534
+ - \`create-style\`: Create a new style definition for an element.
1535
+ - \`get-styles\`: Get all style definitions for an element.
1536
+ - \`update-styles\`: Update styles for an existing element's style variant.
1537
+ - \`delete-style\`: Delete a style definition from an element.
1538
+ - \`delete\`: Delete an element.
1539
+ - \`duplicate\`: Duplicate an existing element.
1540
+ - \`move\`: Move an element to a different container.
1541
+ - \`select\`: Select one or more elements.
1542
+ - \`deselect\`: Deselect a specific element.
1543
+ - \`deselect-all\`: Deselect all selected elements.
1544
+ - \`get-selected\`: Get currently selected elements.
1545
+
1546
+ **Constraints:**
1547
+
1548
+ - Before creating an element of a certain type for the first time, you MUST call \`get-element-schema\` to retrieve its schema.
1549
+ - You can only update props for existing elements.
1550
+ - All props must match the element type's propsSchema keys.
1551
+ - Element types must be atomic (have atomic_controls and atomic_props_schema).
1552
+ - Container IDs must exist and be valid before create/move operations.
1553
+
1554
+ ** Must do with every operation **
1555
+ As of the user can ask in multiple ways the creation of the element, you need to first get the list of available types with "list-available-types" action.
1556
+ After getting it, convert to the most relevant type that the user requested and if this is not clear, request for user input.
1557
+ After finding out the proper type, get the schema for it with "get-element-schema" action.
1558
+
1559
+ ** Styles and Settings propUtils **
1560
+ Getting the schema is important as it introduces the propUtils for the styles and settings.
1561
+ You can use the propUtils to create, update, delete, and get the values of the styles and settings.
1562
+ Settings exists in the result of the get-element-schema action -> propsSchema.
1563
+ Styles exists in the result of the get-element-schema action -> stylesSchema.
1564
+
1565
+ **Examples:**
1566
+
1567
+ Get schema for heading element:
1568
+ \`\`\`json
1569
+ { "action": "get-element-schema", "elementType": "e-heading" }
1570
+ \`\`\`
1571
+
1572
+ Create a heading element:
1573
+ \`\`\`json
1574
+ { "action": "create-element", "elementType": "e-heading", "containerId": "document", "props": { "title": { $$type: "string", "value": "Hello World" } } }
1575
+ \`\`\`
1576
+
1577
+ Update element props:
1578
+ \`\`\`json
1579
+ { "action": "update-props", "elementId": "abc123", "props": { "title": "Updated Title" } }
1580
+ \`\`\`
1581
+
1582
+ Create element style:
1583
+ \`\`\`json
1584
+ { "action": "create-style", "elementId": "abc123", "styles": { "padding": "20px", "margin": "10px" } }
1585
+ \`\`\`
1586
+
1587
+ Get element styles:
1588
+ \`\`\`json
1589
+ { "action": "get-styles", "elementId": "abc123" }
1590
+ \`\`\`
1591
+
1592
+ Update element styles:
1593
+ \`\`\`json
1594
+ { "action": "update-styles", "elementId": "abc123", "styles": { "padding": "20px", "margin": "10px" } }
1595
+ \`\`\`
1596
+
1597
+ Delete element style:
1598
+ \`\`\`json
1599
+ { "action": "delete-style", "elementId": "abc123", "styleId": "style-id-123" }
1600
+ \`\`\``,
1601
+ handler: async (params) => {
1602
+ return routeAction(params);
1603
+ }
1604
+ });
865
1605
  }
866
- function isElementorElement(element) {
867
- return element.hasAttribute("data-id");
1606
+
1607
+ // src/mcp/index.ts
1608
+ function initMcp() {
1609
+ const { setMCPDescription } = getMCPByDomain2("elements");
1610
+ setMCPDescription("Tools for managing atomic elements in Elementor v4 editor");
1611
+ initElementsTool();
868
1612
  }
869
1613
  export {
870
1614
  ELEMENT_STYLE_CHANGE_EVENT,
@@ -873,35 +1617,45 @@ export {
873
1617
  createElements,
874
1618
  deleteElement,
875
1619
  deleteElementStyle,
1620
+ dropElement,
876
1621
  duplicateElement,
877
1622
  duplicateElements,
878
1623
  generateElementId,
879
1624
  getAnchoredAncestorId,
880
1625
  getAnchoredDescendantId,
881
1626
  getContainer,
1627
+ getCurrentDocumentContainer,
882
1628
  getCurrentDocumentId,
1629
+ getElementEditorSettings,
1630
+ getElementInteractions,
883
1631
  getElementLabel,
884
1632
  getElementSetting,
885
1633
  getElementSettings,
886
1634
  getElementStyles,
1635
+ getElementType,
887
1636
  getElements,
888
1637
  getLinkInLinkRestriction,
889
1638
  getSelectedElements,
890
1639
  getWidgetsCache,
1640
+ initMcp as initElementsMcp,
891
1641
  isElementAnchored,
892
1642
  moveElement,
893
1643
  moveElements,
1644
+ playElementInteractions,
894
1645
  removeElements,
895
1646
  replaceElement,
896
1647
  selectElement,
897
1648
  shouldCreateNewLocalStyle,
898
1649
  styleRerenderEvents,
1650
+ updateElementEditorSettings,
1651
+ updateElementInteractions,
899
1652
  updateElementSettings,
900
1653
  updateElementStyle,
901
1654
  useElementChildren,
1655
+ useElementEditorSettings,
1656
+ useElementInteractions,
902
1657
  useElementSetting,
903
1658
  useElementSettings,
904
- useElementType,
905
1659
  useParentElement,
906
1660
  useSelectedElement
907
1661
  };