@elementor/editor-canvas 4.0.0-manual → 4.0.1

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 (38) hide show
  1. package/dist/index.d.mts +11 -2
  2. package/dist/index.d.ts +11 -2
  3. package/dist/index.js +307 -128
  4. package/dist/index.mjs +273 -94
  5. package/package.json +19 -18
  6. package/src/components/__tests__/style-renderer.test.tsx +4 -0
  7. package/src/hooks/__tests__/use-style-items.test.ts +125 -0
  8. package/src/hooks/use-style-items.ts +40 -16
  9. package/src/index.ts +1 -1
  10. package/src/init-settings-transformers.ts +2 -0
  11. package/src/legacy/create-nested-templated-element-type.ts +15 -2
  12. package/src/legacy/create-templated-element-type.ts +8 -0
  13. package/src/legacy/replacements/base.ts +4 -0
  14. package/src/legacy/replacements/inline-editing/canvas-inline-editor.tsx +49 -27
  15. package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +16 -10
  16. package/src/legacy/replacements/inline-editing/inline-editing-utils.ts +12 -1
  17. package/src/legacy/replacements/manager.ts +13 -0
  18. package/src/legacy/types.ts +6 -1
  19. package/src/mcp/canvas-mcp.ts +5 -7
  20. package/src/mcp/resources/breakpoints-resource.ts +11 -4
  21. package/src/mcp/resources/document-structure-resource.ts +18 -13
  22. package/src/mcp/tools/build-composition/schema.ts +1 -1
  23. package/src/mcp/tools/build-composition/tool.ts +5 -1
  24. package/src/mcp/utils/__tests__/get-composition-target-container.test.ts +59 -0
  25. package/src/mcp/utils/get-composition-target-container.ts +15 -0
  26. package/src/renderers/__tests__/create-styles-renderer.test.ts +117 -0
  27. package/src/renderers/create-styles-renderer.ts +13 -3
  28. package/src/style-commands/__tests__/paste-style.test.ts +5 -3
  29. package/src/style-commands/__tests__/reset-style.test.ts +3 -3
  30. package/src/style-commands/paste-style.ts +7 -1
  31. package/src/style-commands/reset-style.ts +1 -1
  32. package/src/style-commands/undoable-actions/paste-element-style.ts +1 -1
  33. package/src/style-commands/undoable-actions/reset-element-style.ts +1 -1
  34. package/src/transformers/shared/__tests__/svg-src-transformer.test.ts +184 -0
  35. package/src/transformers/shared/svg-src-transformer.ts +87 -0
  36. package/src/transformers/styles/__tests__/size-transformer.test.ts +24 -0
  37. package/src/transformers/styles/size-transformer.ts +3 -0
  38. /package/src/{style-commands/utils.ts → utils/command-utils.ts} +0 -0
@@ -1,3 +1,5 @@
1
+ import { createRoot, type Root } from 'react-dom/client';
2
+
1
3
  import type { CreateTemplatedElementTypeOptions } from '../create-templated-element-type';
2
4
  import { createTemplatedElementView } from '../create-templated-element-type';
3
5
  import type { ElementType, ElementView, LegacyWindow, ReplacementSettings } from '../types';
@@ -34,11 +36,18 @@ export const createViewWithReplacements = ( options: CreateTemplatedElementTypeO
34
36
  return class extends TemplatedView {
35
37
  #replacement: ReplacementBaseInterface | null = null;
36
38
  #config: ReplacementSettings;
39
+ #reactContainer: HTMLElement;
40
+ #reactRoot: Root;
37
41
 
38
42
  constructor( ...args: unknown[] ) {
39
43
  super( ...args );
40
44
  const settings = this.model.get( 'settings' );
41
45
 
46
+ this.#reactContainer = this.el.ownerDocument.createElement( 'div' );
47
+ this.#reactContainer.style.display = 'none';
48
+ this.el.ownerDocument.body.appendChild( this.#reactContainer );
49
+ this.#reactRoot = createRoot( this.#reactContainer );
50
+
42
51
  this.#config = {
43
52
  getSetting: settings.get.bind( settings ),
44
53
  setSetting: settings.set.bind( settings ),
@@ -46,6 +55,8 @@ export const createViewWithReplacements = ( options: CreateTemplatedElementTypeO
46
55
  type: this?.model?.get( 'widgetType' ) ?? this.container?.model?.get( 'elType' ) ?? null,
47
56
  id: this?.model?.get( 'id' ) ?? null,
48
57
  refreshView: this.refreshView.bind( this ),
58
+ reactRoot: this.#reactRoot,
59
+ reactContainer: this.#reactContainer,
49
60
  };
50
61
  }
51
62
 
@@ -72,6 +83,8 @@ export const createViewWithReplacements = ( options: CreateTemplatedElementTypeO
72
83
 
73
84
  onDestroy() {
74
85
  this.#triggerAltMethod( 'onDestroy' );
86
+ this.#reactRoot.unmount();
87
+ this.#reactContainer.remove();
75
88
  }
76
89
 
77
90
  _afterRender() {
@@ -1,3 +1,4 @@
1
+ import { type Root } from 'react-dom/client';
1
2
  import { type V1Element } from '@elementor/editor-elements';
2
3
  import { type Props, type PropValue } from '@elementor/editor-props';
3
4
 
@@ -203,6 +204,7 @@ type BackboneCollection< Model extends object > = {
203
204
 
204
205
  export type ElementModel = {
205
206
  id: string;
207
+ originId?: string;
206
208
  elType: string;
207
209
  settings: BackboneModel< Props >;
208
210
  editor_settings: Record< string, unknown >;
@@ -223,13 +225,14 @@ type ContextMenuGroup = {
223
225
  actions: ContextMenuAction[];
224
226
  };
225
227
 
228
+ export type ContextMenuEventData = { location: string; secondaryLocation: string; trigger: string };
226
229
  export type ContextMenuAction = {
227
230
  name: string;
228
231
  icon: string;
229
232
  title: string | ( () => string );
230
233
  shortcut?: string;
231
234
  isEnabled: () => boolean;
232
- callback: ( _: unknown, eventData: unknown ) => void;
235
+ callback: ( _: unknown, eventData: ContextMenuEventData ) => void;
233
236
  };
234
237
 
235
238
  export type ReplacementSettings = {
@@ -239,4 +242,6 @@ export type ReplacementSettings = {
239
242
  id: string;
240
243
  element: HTMLElement;
241
244
  refreshView: () => void;
245
+ reactRoot: Root;
246
+ reactContainer: HTMLElement;
242
247
  };
@@ -10,14 +10,12 @@ import { initGetElementConfigTool } from './tools/get-element-config/tool';
10
10
  export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
11
11
  const { setMCPDescription } = reg;
12
12
  setMCPDescription(
13
- `Everything related to creative design, layout, styling and building the pages, specifically element of type "widget".
13
+ `Everything related to V4 ( Atomic ) canvas.
14
14
  # Canvas workflow for new compositions
15
- - Check existing global variables
16
- - Check existing global classes
17
- - Create missing global variables
18
- - Create reusable global classes
19
- - Build valid XML with minimal inline styles (layout/positioning only)
20
- - Apply global classes to elements`
15
+ - Configure elements settings and styles
16
+ - Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
17
+ - Get and retrieve element configuration values
18
+ `
21
19
  );
22
20
  initWidgetsSchemaResource( reg );
23
21
  initDocumentStructureResource( reg );
@@ -5,7 +5,7 @@ import { v1ReadyEvent } from '@elementor/editor-v1-adapters';
5
5
  export const BREAKPOINTS_SCHEMA_URI = 'elementor://breakpoints/list';
6
6
 
7
7
  export const initBreakpointsResource = ( reg: MCPRegistryEntry ) => {
8
- const { mcpServer, sendResourceUpdated } = reg;
8
+ const { resource, sendResourceUpdated } = reg;
9
9
 
10
10
  const getBreakpointsList = () => {
11
11
  const { breakpoints } = ( window as unknown as ExtendedWindow ).elementor?.config?.responsive || {};
@@ -34,9 +34,16 @@ export const initBreakpointsResource = ( reg: MCPRegistryEntry ) => {
34
34
  ],
35
35
  } );
36
36
 
37
- mcpServer.resource( 'breakpoints ', BREAKPOINTS_SCHEMA_URI, () => {
38
- return buildResourceResponse();
39
- } );
37
+ resource(
38
+ 'breakpoints ',
39
+ BREAKPOINTS_SCHEMA_URI,
40
+ {
41
+ description: 'Breakpoints list.',
42
+ },
43
+ () => {
44
+ return buildResourceResponse();
45
+ }
46
+ );
40
47
 
41
48
  window.addEventListener( v1ReadyEvent().name, () => {
42
49
  sendResourceUpdated( {
@@ -39,7 +39,7 @@ type ElementorContainer = {
39
39
  export const DOCUMENT_STRUCTURE_URI = 'elementor://document/structure';
40
40
 
41
41
  export const initDocumentStructureResource = ( reg: MCPRegistryEntry ) => {
42
- const { mcpServer, sendResourceUpdated } = reg;
42
+ const { resource, sendResourceUpdated } = reg;
43
43
 
44
44
  let currentDocumentStructure: string | null = null;
45
45
 
@@ -69,18 +69,23 @@ export const initDocumentStructureResource = ( reg: MCPRegistryEntry ) => {
69
69
  // Initialize on load
70
70
  updateDocumentStructure();
71
71
 
72
- mcpServer.resource( 'document-structure', DOCUMENT_STRUCTURE_URI, async () => {
73
- const structure = getDocumentStructure();
74
-
75
- return {
76
- contents: [
77
- {
78
- uri: DOCUMENT_STRUCTURE_URI,
79
- text: JSON.stringify( structure, null, 2 ),
80
- },
81
- ],
82
- };
83
- } );
72
+ resource(
73
+ 'document-structure',
74
+ DOCUMENT_STRUCTURE_URI,
75
+ {
76
+ description: 'Document structure.',
77
+ },
78
+ async () => {
79
+ return {
80
+ contents: [
81
+ {
82
+ uri: DOCUMENT_STRUCTURE_URI,
83
+ text: JSON.stringify( getDocumentStructure(), null, 2 ),
84
+ },
85
+ ],
86
+ };
87
+ }
88
+ );
84
89
  };
85
90
 
86
91
  function getDocumentStructure() {
@@ -1,4 +1,4 @@
1
- import { zod as z } from '@elementor/editor-mcp';
1
+ import { z } from '@elementor/schema';
2
2
 
3
3
  import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
4
4
 
@@ -1,3 +1,4 @@
1
+ import { getCurrentDocument } from '@elementor/editor-documents';
1
2
  import {
2
3
  createElement,
3
4
  deleteElement,
@@ -10,6 +11,7 @@ import { type MCPRegistryEntry } from '@elementor/editor-mcp';
10
11
  import { CompositionBuilder } from '../../../composition-builder/composition-builder';
11
12
  import { BEST_PRACTICES_URI, STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from '../../resources/widgets-schema-resource';
12
13
  import { doUpdateElementProperty } from '../../utils/do-update-element-property';
14
+ import { getCompositionTargetContainer } from '../../utils/get-composition-target-container';
13
15
  import { generatePrompt } from './prompt';
14
16
  import { inputSchema as schema, outputSchema } from './schema';
15
17
 
@@ -37,6 +39,8 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
37
39
  const errors: Error[] = [];
38
40
  const rootContainers: V1Element[] = [];
39
41
  const documentContainer = getContainer( 'document' ) as unknown as V1Element;
42
+ const currentDocument = getCurrentDocument();
43
+ const targetContainer = getCompositionTargetContainer( documentContainer, currentDocument?.type.value );
40
44
  try {
41
45
  const compositionBuilder = CompositionBuilder.fromXMLString( xmlStructure, {
42
46
  createElement,
@@ -50,7 +54,7 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
50
54
  configErrors,
51
55
  invalidStyles,
52
56
  rootContainers: generatedRootContainers,
53
- } = compositionBuilder.build( documentContainer );
57
+ } = compositionBuilder.build( targetContainer );
54
58
 
55
59
  rootContainers.push( ...generatedRootContainers );
56
60
  generatedXML = new XMLSerializer().serializeToString( compositionBuilder.getXML() );
@@ -0,0 +1,59 @@
1
+ import { type V1Element } from '@elementor/editor-elements';
2
+
3
+ import { getCompositionTargetContainer } from '../get-composition-target-container';
4
+
5
+ const createMockContainer = ( id: string, children?: V1Element[] ): V1Element =>
6
+ ( {
7
+ id,
8
+ model: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
9
+ settings: { get: jest.fn(), set: jest.fn(), toJSON: jest.fn() },
10
+ children,
11
+ } ) as unknown as V1Element;
12
+
13
+ describe( 'getCompositionTargetContainer', () => {
14
+ it( 'should return first child when document type is elementor_component', () => {
15
+ // Arrange
16
+ const firstChild = createMockContainer( 'child-1' );
17
+ const documentContainer = createMockContainer( 'document', [ firstChild ] );
18
+
19
+ // Act
20
+ const result = getCompositionTargetContainer( documentContainer, 'elementor_component' );
21
+
22
+ // Assert
23
+ expect( result ).toBe( firstChild );
24
+ } );
25
+
26
+ it( 'should return document container when document type is not a component', () => {
27
+ // Arrange
28
+ const firstChild = createMockContainer( 'child-1' );
29
+ const documentContainer = createMockContainer( 'document', [ firstChild ] );
30
+
31
+ // Act
32
+ const result = getCompositionTargetContainer( documentContainer, 'page' );
33
+
34
+ // Assert
35
+ expect( result ).toBe( documentContainer );
36
+ } );
37
+
38
+ it( 'should return document container when document type is undefined', () => {
39
+ // Arrange
40
+ const documentContainer = createMockContainer( 'document' );
41
+
42
+ // Act
43
+ const result = getCompositionTargetContainer( documentContainer, undefined );
44
+
45
+ // Assert
46
+ expect( result ).toBe( documentContainer );
47
+ } );
48
+
49
+ it( 'should return document container when component has no children', () => {
50
+ // Arrange
51
+ const documentContainer = createMockContainer( 'document' );
52
+
53
+ // Act
54
+ const result = getCompositionTargetContainer( documentContainer, 'elementor_component' );
55
+
56
+ // Assert
57
+ expect( result ).toBe( documentContainer );
58
+ } );
59
+ } );
@@ -0,0 +1,15 @@
1
+ import { COMPONENT_DOCUMENT_TYPE } from '@elementor/editor-documents';
2
+ import { type V1Element } from '@elementor/editor-elements';
3
+
4
+ export function getCompositionTargetContainer(
5
+ documentContainer: V1Element,
6
+ documentType: string | undefined
7
+ ): V1Element {
8
+ const firstChild = documentContainer.children?.[ 0 ];
9
+
10
+ if ( documentType === COMPONENT_DOCUMENT_TYPE && firstChild ) {
11
+ return firstChild;
12
+ }
13
+
14
+ return documentContainer;
15
+ }
@@ -118,6 +118,123 @@ describe( 'renderStyles', () => {
118
118
  } );
119
119
  } );
120
120
 
121
+ describe( 'breakpoint deduplication', () => {
122
+ it( 'should render all breakpoints when same id has multiple breakpoint variants', async () => {
123
+ // Arrange - simulates output from breakToBreakpoints in use-style-items.
124
+ const desktopStyle: RendererStyleDefinition = {
125
+ id: 'button-style',
126
+ type: 'class',
127
+ cssName: 'e-button',
128
+ label: 'Button',
129
+ variants: [ { meta: { breakpoint: null, state: null }, props: { 'font-size': '16px' }, custom_css: null } ],
130
+ };
131
+ const tabletStyle: RendererStyleDefinition = {
132
+ ...desktopStyle,
133
+ variants: [
134
+ { meta: { breakpoint: 'tablet', state: null }, props: { 'font-size': '14px' }, custom_css: null },
135
+ ],
136
+ };
137
+ const mobileStyle: RendererStyleDefinition = {
138
+ ...desktopStyle,
139
+ variants: [
140
+ { meta: { breakpoint: 'mobile', state: null }, props: { 'font-size': '12px' }, custom_css: null },
141
+ ],
142
+ };
143
+
144
+ const resolve = jest.fn( ( { props } ) => props );
145
+ const renderStyles = createStylesRenderer( {
146
+ breakpoints: {
147
+ tablet: { width: 992, type: 'max-width' },
148
+ mobile: { width: 768, type: 'max-width' },
149
+ } as BreakpointsMap,
150
+ resolve,
151
+ } );
152
+
153
+ // Act.
154
+ const result = await renderStyles( { styles: [ desktopStyle, tabletStyle, mobileStyle ] } );
155
+
156
+ // Assert - all three breakpoints must be rendered (previously tablet/mobile were dropped).
157
+ expect( result ).toHaveLength( 3 );
158
+ expect( result.map( ( r ) => r.breakpoint ) ).toEqual( [ 'desktop', 'tablet', 'mobile' ] );
159
+ expect( result[ 0 ].value ).toContain( 'font-size:16px' );
160
+ expect( result[ 1 ].value ).toContain( '@media(max-width:992px)' );
161
+ expect( result[ 1 ].value ).toContain( 'font-size:14px' );
162
+ expect( result[ 2 ].value ).toContain( '@media(max-width:768px)' );
163
+ expect( result[ 2 ].value ).toContain( 'font-size:12px' );
164
+ } );
165
+
166
+ it( 'should deduplicate same id + breakpoint + state combinations', async () => {
167
+ // Arrange - two styles with same id, breakpoint, and state should dedupe.
168
+ const style1: RendererStyleDefinition = {
169
+ id: 'button-style',
170
+ type: 'class',
171
+ cssName: 'e-button',
172
+ label: 'Button',
173
+ variants: [
174
+ { meta: { breakpoint: 'tablet', state: null }, props: { 'font-size': '14px' }, custom_css: null },
175
+ ],
176
+ };
177
+ const style2: RendererStyleDefinition = {
178
+ ...style1,
179
+ variants: [
180
+ { meta: { breakpoint: 'tablet', state: null }, props: { 'font-size': '16px' }, custom_css: null },
181
+ ],
182
+ };
183
+
184
+ const resolve = jest.fn( ( { props } ) => props );
185
+ const renderStyles = createStylesRenderer( {
186
+ breakpoints: {
187
+ tablet: { width: 992, type: 'max-width' },
188
+ } as BreakpointsMap,
189
+ resolve,
190
+ } );
191
+
192
+ // Act.
193
+ const result = await renderStyles( { styles: [ style1, style2 ] } );
194
+
195
+ // Assert - should only render first occurrence.
196
+ expect( result ).toHaveLength( 1 );
197
+ expect( result[ 0 ].value ).toContain( 'font-size:14px' );
198
+ } );
199
+
200
+ it( 'should render separately when same id + breakpoint have different states', async () => {
201
+ // Arrange - same id and breakpoint but different states should NOT dedupe.
202
+ const normalStyle: RendererStyleDefinition = {
203
+ id: 'button-style',
204
+ type: 'class',
205
+ cssName: 'e-button',
206
+ label: 'Button',
207
+ variants: [
208
+ { meta: { breakpoint: 'tablet', state: null }, props: { 'font-size': '14px' }, custom_css: null },
209
+ ],
210
+ };
211
+ const hoverStyle: RendererStyleDefinition = {
212
+ ...normalStyle,
213
+ variants: [
214
+ { meta: { breakpoint: 'tablet', state: 'hover' }, props: { 'font-size': '16px' }, custom_css: null },
215
+ ],
216
+ };
217
+
218
+ const resolve = jest.fn( ( { props } ) => props );
219
+ const renderStyles = createStylesRenderer( {
220
+ breakpoints: {
221
+ tablet: { width: 992, type: 'max-width' },
222
+ } as BreakpointsMap,
223
+ resolve,
224
+ } );
225
+
226
+ // Act.
227
+ const result = await renderStyles( { styles: [ normalStyle, hoverStyle ] } );
228
+
229
+ // Assert - both should be rendered since states differ.
230
+ expect( result ).toHaveLength( 2 );
231
+ expect( result[ 0 ].state ).toBeNull();
232
+ expect( result[ 0 ].value ).toContain( 'font-size:14px' );
233
+ expect( result[ 1 ].state ).toBe( 'hover' );
234
+ expect( result[ 1 ].value ).toContain( 'font-size:16px' );
235
+ } );
236
+ } );
237
+
121
238
  describe( 'custom_css rendering', () => {
122
239
  it( 'should not render custom_css if raw is empty', async () => {
123
240
  // Arrange.
@@ -46,14 +46,24 @@ const SELECTORS_MAP: Record< StyleDefinitionType, string > = {
46
46
  class: '.',
47
47
  };
48
48
 
49
+ const DEFAULT_BREAKPOINT = 'desktop';
50
+ const DEFAULT_STATE = 'normal';
51
+
52
+ function getStyleUniqueKey( style: RendererStyleDefinition ): string {
53
+ const breakpoint = style.variants[ 0 ]?.meta?.breakpoint ?? DEFAULT_BREAKPOINT;
54
+ const state = style.variants[ 0 ]?.meta?.state ?? DEFAULT_STATE;
55
+ return `${ style.id }-${ breakpoint }-${ state }`;
56
+ }
57
+
49
58
  export function createStylesRenderer( { resolve, breakpoints, selectorPrefix = '' }: CreateStyleRendererArgs ) {
50
59
  return async ( { styles, signal }: StyleRendererArgs ): Promise< StyleItem[] > => {
51
- const seenIds = new Set< string >();
60
+ const seenKeys = new Set< string >();
52
61
  const uniqueStyles = styles.filter( ( style ) => {
53
- if ( seenIds.has( style.id ) ) {
62
+ const key = getStyleUniqueKey( style );
63
+ if ( seenKeys.has( key ) ) {
54
64
  return false;
55
65
  }
56
- seenIds.add( style.id );
66
+ seenKeys.add( key );
57
67
  return true;
58
68
  } );
59
69
 
@@ -19,14 +19,16 @@ import { classesPropTypeUtil } from '@elementor/editor-props';
19
19
  import { type StyleDefinition } from '@elementor/editor-styles';
20
20
  import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
21
21
 
22
+ import { getClipboardElements } from '../../utils/command-utils';
22
23
  import { initPasteStyleCommand } from '../paste-style';
23
- import { getClipboardElements } from '../utils';
24
24
 
25
25
  jest.mock( '@elementor/editor-elements' );
26
- jest.mock( '../utils', () => ( {
27
- ...jest.requireActual( '../utils' ),
26
+
27
+ jest.mock( '../../utils/command-utils', () => ( {
28
+ ...jest.requireActual( '../../utils/command-utils' ),
28
29
  getClipboardElements: jest.fn(),
29
30
  } ) );
31
+
30
32
  jest.mock( '@elementor/editor-v1-adapters', () => ( {
31
33
  ...jest.requireActual( '@elementor/editor-v1-adapters' ),
32
34
  blockCommand: jest.fn(),
@@ -7,13 +7,13 @@ import {
7
7
  import { createElementStyle, deleteElementStyle, getElementStyles } from '@elementor/editor-elements';
8
8
  import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
9
9
 
10
+ import { getClassesProp, hasAtomicWidgets, isAtomicWidget } from '../../utils/command-utils';
10
11
  import { initResetStyleCommand } from '../reset-style';
11
- import { getClassesProp, hasAtomicWidgets, isAtomicWidget } from '../utils';
12
12
 
13
13
  jest.mock( '@elementor/editor-elements' );
14
14
 
15
- jest.mock( '../utils', () => ( {
16
- ...jest.requireActual( '../utils' ),
15
+ jest.mock( '../../utils/command-utils', () => ( {
16
+ ...jest.requireActual( '../../utils/command-utils' ),
17
17
  getClassesProp: jest.fn(),
18
18
  hasAtomicWidgets: jest.fn(),
19
19
  isAtomicWidget: jest.fn(),
@@ -8,8 +8,14 @@ import {
8
8
  commandStartEvent,
9
9
  } from '@elementor/editor-v1-adapters';
10
10
 
11
+ import {
12
+ type ContainerArgs,
13
+ getClassesProp,
14
+ getClipboardElements,
15
+ hasAtomicWidgets,
16
+ isAtomicWidget,
17
+ } from '../utils/command-utils';
11
18
  import { undoablePasteElementStyle } from './undoable-actions/paste-element-style';
12
- import { type ContainerArgs, getClassesProp, getClipboardElements, hasAtomicWidgets, isAtomicWidget } from './utils';
13
19
 
14
20
  type PasteStylesCommandArgs = ContainerArgs & {
15
21
  storageKey?: string;
@@ -6,8 +6,8 @@ import {
6
6
  commandStartEvent,
7
7
  } from '@elementor/editor-v1-adapters';
8
8
 
9
+ import { type ContainerArgs, hasAtomicWidgets, isAtomicWidget } from '../utils/command-utils';
9
10
  import { undoableResetElementStyle } from './undoable-actions/reset-element-style';
10
- import { type ContainerArgs, hasAtomicWidgets, isAtomicWidget } from './utils';
11
11
 
12
12
  export function initResetStyleCommand() {
13
13
  const resetElementStyles = undoableResetElementStyle();
@@ -10,7 +10,7 @@ import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-reposit
10
10
  import { undoable } from '@elementor/editor-v1-adapters';
11
11
  import { __ } from '@wordpress/i18n';
12
12
 
13
- import { getClassesProp, getTitleForContainers } from '../utils';
13
+ import { getClassesProp, getTitleForContainers } from '../../utils/command-utils';
14
14
 
15
15
  type PasteElementStyleArgs = {
16
16
  containers: V1Element[];
@@ -3,7 +3,7 @@ import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-reposit
3
3
  import { undoable } from '@elementor/editor-v1-adapters';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
- import { getClassesProp, getTitleForContainers } from '../utils';
6
+ import { getClassesProp, getTitleForContainers } from '../../utils/command-utils';
7
7
 
8
8
  type ResetElementStyleArgs = {
9
9
  containers: V1Element[];