@elementor/editor-canvas 0.11.1 → 0.13.0

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 (44) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +46 -0
  3. package/dist/index.d.mts +6 -1
  4. package/dist/index.d.ts +6 -1
  5. package/dist/index.js +406 -45
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +419 -46
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +11 -10
  10. package/src/__tests__/__mocks__/styles-schema.ts +72 -3
  11. package/src/__tests__/init-styles-renderer.test.ts +19 -5
  12. package/src/__tests__/mock-attachment-data.ts +15 -0
  13. package/src/__tests__/prop-types.ts +65 -0
  14. package/src/__tests__/settings-props-resolver.test.ts +193 -0
  15. package/src/__tests__/styles-prop-resolver.test.ts +59 -16
  16. package/src/index.ts +1 -0
  17. package/src/init-settings-transformers.ts +19 -0
  18. package/src/init-style-transformers.ts +13 -9
  19. package/src/init-styles-renderer.ts +9 -3
  20. package/src/init.tsx +8 -0
  21. package/src/legacy/create-element-type.ts +84 -0
  22. package/src/legacy/init-legacy-views.ts +22 -0
  23. package/src/legacy/types.ts +60 -0
  24. package/src/settings-transformers-registry.ts +3 -0
  25. package/src/style-commands/__tests__/paste-style.test.ts +554 -0
  26. package/src/style-commands/__tests__/reset-style.test.ts +153 -0
  27. package/src/style-commands/init-style-commands.ts +7 -0
  28. package/src/style-commands/paste-style.ts +53 -0
  29. package/src/style-commands/reset-style.ts +34 -0
  30. package/src/style-commands/undoable-actions/paste-element-style.ts +107 -0
  31. package/src/style-commands/undoable-actions/reset-element-style.ts +60 -0
  32. package/src/style-commands/utils.ts +62 -0
  33. package/src/transformers/settings/array-transformer.ts +5 -0
  34. package/src/transformers/settings/link-transformer.ts +14 -0
  35. package/src/transformers/{styles → shared}/image-src-transformer.ts +2 -2
  36. package/src/transformers/shared/image-transformer.ts +41 -0
  37. package/src/transformers/shared/plain-transformer.ts +5 -0
  38. package/src/transformers/styles/background-color-overlay-transformer.ts +13 -3
  39. package/src/transformers/styles/background-gradient-overlay-transformer.ts +16 -0
  40. package/src/transformers/styles/background-image-overlay-transformer.ts +6 -2
  41. package/src/transformers/styles/color-stop-transformer.ts +10 -0
  42. package/src/transformers/styles/image-attachment-transformer.ts +0 -15
  43. package/src/transformers/styles/image-transformer.ts +0 -34
  44. package/src/transformers/styles/primitive-transformer.ts +0 -3
@@ -0,0 +1,193 @@
1
+ import {
2
+ booleanPropTypeUtil,
3
+ classesPropTypeUtil,
4
+ imageAttachmentIdPropType,
5
+ imagePropTypeUtil,
6
+ imageSrcPropTypeUtil,
7
+ linkPropTypeUtil,
8
+ numberPropTypeUtil,
9
+ type Props,
10
+ type PropsSchema,
11
+ stringPropTypeUtil,
12
+ urlPropTypeUtil,
13
+ } from '@elementor/editor-props';
14
+ import { getMediaAttachment } from '@elementor/wp-media';
15
+
16
+ import { initSettingsTransformers } from '../init-settings-transformers';
17
+ import { createPropsResolver } from '../renderers/create-props-resolver';
18
+ import { settingsTransformersRegistry } from '../settings-transformers-registry';
19
+ import { mockAttachmentData } from './mock-attachment-data';
20
+ import {
21
+ booleanPropType,
22
+ classesPropType,
23
+ imagePropType,
24
+ linkPropType,
25
+ numberPropType,
26
+ stringPropType,
27
+ urlPropType,
28
+ } from './prop-types';
29
+
30
+ jest.mock( '@elementor/wp-media' );
31
+
32
+ type Payload = {
33
+ name: string;
34
+ prepare?: () => void;
35
+ props: Props;
36
+ schema: PropsSchema;
37
+ expected: Record< string, unknown >;
38
+ };
39
+
40
+ describe( 'settings props resolver', () => {
41
+ it.each< Payload >( [
42
+ {
43
+ name: 'plain props',
44
+ props: {
45
+ string: stringPropTypeUtil.create( 'test' ),
46
+ url: urlPropTypeUtil.create( 'url' ),
47
+ number: numberPropTypeUtil.create( 123 ),
48
+ boolean: booleanPropTypeUtil.create( true ),
49
+ },
50
+ schema: {
51
+ string: stringPropType(),
52
+ number: numberPropType(),
53
+ boolean: booleanPropType(),
54
+ url: urlPropType(),
55
+ },
56
+ expected: {
57
+ string: 'test',
58
+ url: 'url',
59
+ number: 123,
60
+ boolean: true,
61
+ },
62
+ },
63
+ {
64
+ name: 'classes',
65
+ props: {
66
+ classes: classesPropTypeUtil.create( [
67
+ 'test-1',
68
+ 'test-2',
69
+ '',
70
+ null as unknown as string,
71
+ undefined as unknown as string,
72
+ ] ),
73
+ },
74
+ schema: {
75
+ classes: classesPropType(),
76
+ },
77
+ expected: {
78
+ classes: [ 'test-1', 'test-2' ],
79
+ },
80
+ },
81
+ {
82
+ name: 'link',
83
+ props: {
84
+ link1: linkPropTypeUtil.create( {
85
+ destination: 'https://elementor.com/blank',
86
+ isTargetBlank: true,
87
+ } ),
88
+ link2: linkPropTypeUtil.create( {
89
+ destination: 'https://elementor.com/self',
90
+ isTargetBlank: false,
91
+ } ),
92
+ },
93
+ schema: {
94
+ link1: linkPropType(),
95
+ link2: linkPropType(),
96
+ },
97
+ expected: {
98
+ link1: { href: 'https://elementor.com/blank', target: '_blank' },
99
+ link2: { href: 'https://elementor.com/self', target: '_self' },
100
+ },
101
+ },
102
+ {
103
+ name: 'image (url)',
104
+ props: {
105
+ image: imagePropTypeUtil.create( {
106
+ src: imageSrcPropTypeUtil.create( {
107
+ id: null,
108
+ url: urlPropTypeUtil.create( 'https://localhost.test/test-image.png' ),
109
+ } ),
110
+ size: stringPropTypeUtil.create( 'full' ),
111
+ } ),
112
+ },
113
+ schema: {
114
+ image: imagePropType(),
115
+ },
116
+ expected: {
117
+ image: {
118
+ src: 'https://localhost.test/test-image.png',
119
+ },
120
+ },
121
+ },
122
+ {
123
+ name: 'image (attachment with size)',
124
+ prepare: () => {
125
+ jest.mocked( getMediaAttachment ).mockImplementation(
126
+ ( args ) => Promise.resolve( mockAttachmentData( args.id ) ) as never
127
+ );
128
+ },
129
+ props: {
130
+ image: imagePropTypeUtil.create( {
131
+ src: imageSrcPropTypeUtil.create( {
132
+ id: imageAttachmentIdPropType.create( 123 ),
133
+ url: null,
134
+ } ),
135
+ size: stringPropTypeUtil.create( 'large' ),
136
+ } ),
137
+ },
138
+ schema: {
139
+ image: imagePropType(),
140
+ },
141
+ expected: {
142
+ image: {
143
+ src: 'large-image-url-123',
144
+ height: 3,
145
+ width: 3,
146
+ },
147
+ },
148
+ },
149
+ {
150
+ name: 'image (attachment with non existing size)',
151
+ prepare: () => {
152
+ jest.mocked( getMediaAttachment ).mockImplementation(
153
+ ( args ) => Promise.resolve( mockAttachmentData( args.id ) ) as never
154
+ );
155
+ },
156
+ props: {
157
+ image: imagePropTypeUtil.create( {
158
+ src: imageSrcPropTypeUtil.create( {
159
+ id: imageAttachmentIdPropType.create( 123 ),
160
+ url: null,
161
+ } ),
162
+ size: stringPropTypeUtil.create( 'non-existing-size' ),
163
+ } ),
164
+ },
165
+ schema: {
166
+ image: imagePropType(),
167
+ },
168
+ expected: {
169
+ image: {
170
+ src: 'original-image-url-123',
171
+ height: 0,
172
+ width: 0,
173
+ },
174
+ },
175
+ },
176
+ ] )( 'it should resolve props for `$name`', async ( { prepare, props, expected, schema } ) => {
177
+ // Arrange.
178
+ prepare?.();
179
+
180
+ initSettingsTransformers();
181
+
182
+ const resolve = createPropsResolver( {
183
+ transformers: settingsTransformersRegistry.all(),
184
+ schema,
185
+ } );
186
+
187
+ // Act.
188
+ const result = await resolve( { props } );
189
+
190
+ // Assert.
191
+ expect( result ).toStrictEqual( expected );
192
+ } );
193
+ } );
@@ -1,6 +1,7 @@
1
1
  import { styleTransformersRegistry } from '@elementor/editor-canvas';
2
2
  import {
3
3
  backgroundColorOverlayPropTypeUtil,
4
+ backgroundGradientOverlayPropTypeUtil,
4
5
  backgroundImageOverlayPropTypeUtil,
5
6
  backgroundImagePositionOffsetPropTypeUtil,
6
7
  backgroundImageSizeScalePropTypeUtil,
@@ -10,11 +11,14 @@ import {
10
11
  borderWidthPropTypeUtil,
11
12
  boxShadowPropTypeUtil,
12
13
  colorPropTypeUtil,
14
+ colorStopPropTypeUtil,
13
15
  dimensionsPropTypeUtil,
16
+ gradientColorStopPropTypeUtil,
14
17
  imageAttachmentIdPropType,
15
18
  imagePropTypeUtil,
16
19
  imageSrcPropTypeUtil,
17
20
  layoutDirectionPropTypeUtil,
21
+ numberPropTypeUtil,
18
22
  type Props,
19
23
  shadowPropTypeUtil,
20
24
  sizePropTypeUtil,
@@ -26,8 +30,10 @@ import { getMediaAttachment } from '@elementor/wp-media';
26
30
  import { initStyleTransformers } from '../init-style-transformers';
27
31
  import { createPropsResolver } from '../renderers/create-props-resolver';
28
32
  import { stylesSchemaMock } from './__mocks__/styles-schema';
33
+ import { mockAttachmentData } from './mock-attachment-data';
29
34
 
30
35
  jest.mock( '@elementor/wp-media' );
36
+ jest.mock( '../style-commands/init-style-commands' );
31
37
 
32
38
  type Payload = {
33
39
  name: string;
@@ -196,8 +202,12 @@ describe( 'styles prop resolver', () => {
196
202
  background: backgroundPropTypeUtil.create( {
197
203
  color: colorPropTypeUtil.create( '#000' ),
198
204
  'background-overlay': backgroundOverlayPropTypeUtil.create( [
199
- backgroundColorOverlayPropTypeUtil.create( 'blue' ),
200
- backgroundColorOverlayPropTypeUtil.create( 'yellow' ),
205
+ backgroundColorOverlayPropTypeUtil.create( {
206
+ color: colorPropTypeUtil.create( 'blue' ),
207
+ } ),
208
+ backgroundColorOverlayPropTypeUtil.create( {
209
+ color: colorPropTypeUtil.create( 'yellow' ),
210
+ } ),
201
211
  backgroundImageOverlayPropTypeUtil.create( {
202
212
  image: imagePropTypeUtil.create( {
203
213
  src: imageSrcPropTypeUtil.create( {
@@ -283,6 +293,53 @@ describe( 'styles prop resolver', () => {
283
293
  background: 'url(medium_large-image-url-123) repeat-x,url(thumbnail-image-url-123) fixed',
284
294
  },
285
295
  },
296
+ {
297
+ name: 'background (only gradient)',
298
+ props: {
299
+ background: backgroundPropTypeUtil.create( {
300
+ 'background-overlay': backgroundOverlayPropTypeUtil.create( [
301
+ backgroundGradientOverlayPropTypeUtil.create( {
302
+ type: stringPropTypeUtil.create( 'linear' ),
303
+ angle: numberPropTypeUtil.create( 190 ),
304
+ stops: gradientColorStopPropTypeUtil.create( [
305
+ colorStopPropTypeUtil.create( {
306
+ color: colorPropTypeUtil.create( 'red' ),
307
+ offset: numberPropTypeUtil.create( 10 ),
308
+ } ),
309
+ colorStopPropTypeUtil.create( {
310
+ color: colorPropTypeUtil.create( 'yellow' ),
311
+ offset: numberPropTypeUtil.create( 40 ),
312
+ } ),
313
+ colorStopPropTypeUtil.create( {
314
+ color: colorPropTypeUtil.create( 'rgb(255,0,255)' ),
315
+ offset: numberPropTypeUtil.create( 87 ),
316
+ } ),
317
+ ] ),
318
+ } ),
319
+ backgroundGradientOverlayPropTypeUtil.create( {
320
+ type: stringPropTypeUtil.create( 'radial' ),
321
+ angle: numberPropTypeUtil.create( 95 ),
322
+ stops: gradientColorStopPropTypeUtil.create( [
323
+ colorStopPropTypeUtil.create( {
324
+ color: colorPropTypeUtil.create( 'rgb(0,190,245,0.7)' ),
325
+ offset: numberPropTypeUtil.create( 60 ),
326
+ } ),
327
+ colorStopPropTypeUtil.create( {
328
+ color: colorPropTypeUtil.create( 'rgb(255,0,255)' ),
329
+ offset: numberPropTypeUtil.create( 93 ),
330
+ } ),
331
+ ] ),
332
+ positions: stringPropTypeUtil.create( 'bottom left' ),
333
+ } ),
334
+ ] ),
335
+ } ),
336
+ },
337
+ expected: {
338
+ background:
339
+ 'linear-gradient(190deg, red 10%,yellow 40%,rgb(255,0,255) 87%),' +
340
+ 'radial-gradient(circle at bottom left, rgb(0,190,245,0.7) 60%,rgb(255,0,255) 93%)',
341
+ },
342
+ },
286
343
  ] )( 'it should resolve props for `$name`', async ( { prepare, props, expected } ) => {
287
344
  // Arrange.
288
345
  prepare?.();
@@ -301,17 +358,3 @@ describe( 'styles prop resolver', () => {
301
358
  expect( result ).toStrictEqual( expected );
302
359
  } );
303
360
  } );
304
-
305
- const mockAttachmentData = ( id: number | null ) => {
306
- const originalUrl = `original-image-url-${ id }`;
307
-
308
- return {
309
- url: originalUrl,
310
- sizes: {
311
- thumbnail: { url: `thumbnail-image-url-${ id }` },
312
- medium_large: { url: `medium_large-image-url-${ id }` },
313
- large: { url: `large-image-url-${ id }` },
314
- full: { url: originalUrl },
315
- },
316
- };
317
- };
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { init } from './init';
2
2
 
3
3
  export { styleTransformersRegistry } from './style-transformers-registry';
4
+ export { settingsTransformersRegistry } from './settings-transformers-registry';
4
5
 
5
6
  init();
@@ -0,0 +1,19 @@
1
+ import { settingsTransformersRegistry } from './settings-transformers-registry';
2
+ import { arrayTransformer } from './transformers/settings/array-transformer';
3
+ import { linkTransformer } from './transformers/settings/link-transformer';
4
+ import { imageSrcTransformer } from './transformers/shared/image-src-transformer';
5
+ import { imageTransformer } from './transformers/shared/image-transformer';
6
+ import { plainTransformer } from './transformers/shared/plain-transformer';
7
+
8
+ export function initSettingsTransformers() {
9
+ settingsTransformersRegistry
10
+ .register( 'string', plainTransformer )
11
+ .register( 'url', plainTransformer )
12
+ .register( 'number', plainTransformer )
13
+ .register( 'boolean', plainTransformer )
14
+ .register( 'classes', arrayTransformer )
15
+ .register( 'link', linkTransformer )
16
+ .register( 'image', imageTransformer )
17
+ .register( 'image-src', imageSrcTransformer )
18
+ .register( 'image-attachment-id', plainTransformer );
19
+ }
@@ -1,15 +1,16 @@
1
1
  import { styleTransformersRegistry } from './style-transformers-registry';
2
+ import { imageSrcTransformer } from './transformers/shared/image-src-transformer';
3
+ import { imageTransformer } from './transformers/shared/image-transformer';
4
+ import { plainTransformer } from './transformers/shared/plain-transformer';
2
5
  import { backgroundColorOverlayTransformer } from './transformers/styles/background-color-overlay-transformer';
6
+ import { backgroundGradientOverlayTransformer } from './transformers/styles/background-gradient-overlay-transformer';
3
7
  import { backgroundImageOverlayTransformer } from './transformers/styles/background-image-overlay-transformer';
4
8
  import { backgroundImagePositionOffsetTransformer } from './transformers/styles/background-image-position-offset-transformer';
5
9
  import { backgroundImageSizeScaleTransformer } from './transformers/styles/background-image-size-scale-transformer';
6
10
  import { backgroundTransformer } from './transformers/styles/background-transformer';
11
+ import { colorStopTransformer } from './transformers/styles/color-stop-transformer';
7
12
  import { createCombineArrayTransformer } from './transformers/styles/create-combine-array-transformer';
8
13
  import { createMultiPropsTransformer } from './transformers/styles/create-multi-props-transformer';
9
- import { imageAttachmentTransformer } from './transformers/styles/image-attachment-transformer';
10
- import { imageSrcTransformer } from './transformers/styles/image-src-transformer';
11
- import { imageTransformer } from './transformers/styles/image-transformer';
12
- import { primitiveTransformer } from './transformers/styles/primitive-transformer';
13
14
  import { shadowTransformer } from './transformers/styles/shadow-transformer';
14
15
  import { sizeTransformer } from './transformers/styles/size-transformer';
15
16
  import { strokeTransformer } from './transformers/styles/stroke-transformer';
@@ -26,18 +27,21 @@ export function initStyleTransformers() {
26
27
  ( { propKey, key } ) => `${ propKey }-${ key }`
27
28
  )
28
29
  )
29
- .register( 'color', primitiveTransformer )
30
- .register( 'number', primitiveTransformer )
31
- .register( 'string', primitiveTransformer )
32
- .register( 'url', primitiveTransformer )
30
+ .register( 'color', plainTransformer )
31
+ .register( 'number', plainTransformer )
32
+ .register( 'string', plainTransformer )
33
+ .register( 'url', plainTransformer )
33
34
  .register( 'box-shadow', createCombineArrayTransformer( ',' ) )
34
35
  .register( 'background', backgroundTransformer )
35
36
  .register( 'background-overlay', createCombineArrayTransformer( ',' ) )
36
37
  .register( 'background-color-overlay', backgroundColorOverlayTransformer )
37
38
  .register( 'background-image-overlay', backgroundImageOverlayTransformer )
39
+ .register( 'background-gradient-overlay', backgroundGradientOverlayTransformer )
40
+ .register( 'gradient-color-stop', createCombineArrayTransformer( ',' ) )
41
+ .register( 'color-stop', colorStopTransformer )
38
42
  .register( 'background-image-position-offset', backgroundImagePositionOffsetTransformer )
39
43
  .register( 'background-image-size-scale', backgroundImageSizeScaleTransformer )
40
- .register( 'image-attachment-id', imageAttachmentTransformer )
44
+ .register( 'image-attachment-id', plainTransformer )
41
45
  .register( 'image-src', imageSrcTransformer )
42
46
  .register( 'image', imageTransformer )
43
47
  .register(
@@ -1,7 +1,7 @@
1
1
  import { getBreakpointsMap } from '@elementor/editor-responsive';
2
2
  import { getStylesSchema } from '@elementor/editor-styles';
3
3
  import { stylesRepository } from '@elementor/editor-styles-repository';
4
- import { __privateListenTo as listenTo, v1ReadyEvent } from '@elementor/editor-v1-adapters';
4
+ import { __privateListenTo as listenTo, registerDataHook, v1ReadyEvent } from '@elementor/editor-v1-adapters';
5
5
 
6
6
  import { createPropsResolver } from './renderers/create-props-resolver';
7
7
  import renderStyles from './renderers/render-styles';
@@ -22,7 +22,7 @@ export function initStylesRenderer() {
22
22
  onPropResolve: enqueueUsedFonts,
23
23
  } );
24
24
 
25
- stylesRepository.subscribe( async () => {
25
+ const injectStyleElements = async () => {
26
26
  const styleContainer = getStylesContainer();
27
27
 
28
28
  // Styles should be printed in a reversed order, so the high priority styles will be printed last.
@@ -42,7 +42,13 @@ export function initStylesRenderer() {
42
42
  selectorPrefix: SELECTOR_PREFIX,
43
43
  signal: abortController.signal,
44
44
  } );
45
- } );
45
+ };
46
+
47
+ stylesRepository.subscribe( injectStyleElements );
48
+
49
+ // Add initial styles rendering as a hook to ensure the whole editor
50
+ // waits for styles to render before hiding the loaders.
51
+ registerDataHook( 'after', 'editor/documents/attach-preview', injectStyleElements );
46
52
  } );
47
53
  }
48
54
 
package/src/init.tsx CHANGED
@@ -1,12 +1,20 @@
1
1
  import { injectIntoTop } from '@elementor/editor';
2
2
 
3
3
  import { ElementsOverlays } from './components/elements-overlays';
4
+ import { initSettingsTransformers } from './init-settings-transformers';
4
5
  import { initStyleTransformers } from './init-style-transformers';
5
6
  import { initStylesRenderer } from './init-styles-renderer';
7
+ import { initLegacyViews } from './legacy/init-legacy-views';
8
+ import { initStyleCommands } from './style-commands/init-style-commands';
6
9
 
7
10
  export function init() {
8
11
  initStyleTransformers();
9
12
  initStylesRenderer();
13
+ initStyleCommands();
14
+
15
+ initLegacyViews();
16
+
17
+ initSettingsTransformers();
10
18
 
11
19
  injectIntoTop( {
12
20
  id: 'elements-overlays',
@@ -0,0 +1,84 @@
1
+ import { type ElementType, type ElementView, type LegacyWindow } from './types';
2
+
3
+ // Technically it shouldn't have a return type annotation, but for some
4
+ // reason TypeScript can't infer the types properly when emitting DTS.
5
+ //
6
+ // See: https://github.com/microsoft/TypeScript/issues/9944#issuecomment-244448079
7
+ export function createElementType( type: string ): typeof ElementType {
8
+ const legacyWindow = window as unknown as LegacyWindow;
9
+
10
+ return class extends legacyWindow.elementor.modules.elements.types.Widget {
11
+ getType() {
12
+ return type;
13
+ }
14
+
15
+ getView() {
16
+ return createElementView();
17
+ }
18
+ };
19
+ }
20
+
21
+ function createElementView(): typeof ElementView {
22
+ const legacyWindow = window as unknown as LegacyWindow;
23
+
24
+ return class extends legacyWindow.elementor.modules.elements.views.Widget {
25
+ // Dispatch `render` event so the overlay layer will be updated
26
+ onRender( ...args: unknown[] ) {
27
+ super.onRender( ...args );
28
+
29
+ this.#dispatchEvent( 'elementor/preview/atomic-widget/render' );
30
+ }
31
+
32
+ // Dispatch `destroy` event so the overlay layer will be updated
33
+ onDestroy( ...args: unknown[] ) {
34
+ super.onDestroy( ...args );
35
+
36
+ this.#dispatchEvent( 'elementor/preview/atomic-widget/destroy' );
37
+ }
38
+
39
+ attributes() {
40
+ return {
41
+ ...super.attributes(),
42
+
43
+ // Mark the widget as atomic, so external APIs (such as the overlay layer) can reference it.
44
+ 'data-atomic': '',
45
+
46
+ // Make the wrapper is non-existent in terms of CSS to mimic the frontend DOM tree.
47
+ style: 'display: contents !important;',
48
+ };
49
+ }
50
+
51
+ // Removes behaviors that are not needed for atomic widgets (that are implemented in the overlay layer).
52
+ behaviors() {
53
+ const disabledBehaviors = [ 'InlineEditing', 'Draggable', 'Resizable' ];
54
+
55
+ const behaviorsAsEntries = Object.entries( super.behaviors() ).filter(
56
+ ( [ key ] ) => ! disabledBehaviors.includes( key )
57
+ );
58
+
59
+ return Object.fromEntries( behaviorsAsEntries );
60
+ }
61
+
62
+ // Change the drag handle because the $el is not the draggable element (`display: contents`).
63
+ getDomElement() {
64
+ return this.$el.find( ':first-child' );
65
+ }
66
+
67
+ // Remove the overlay, so we can use the new overlay layer.
68
+ getHandlesOverlay() {
69
+ return null;
70
+ }
71
+
72
+ #dispatchEvent( eventType: string ) {
73
+ window.top?.dispatchEvent(
74
+ new CustomEvent( eventType, {
75
+ detail: { id: this.model.get( 'id' ) },
76
+ } )
77
+ );
78
+ }
79
+
80
+ getContextMenuGroups() {
81
+ return super.getContextMenuGroups().filter( ( group ) => group.name !== 'save' );
82
+ }
83
+ };
84
+ }
@@ -0,0 +1,22 @@
1
+ import { getWidgetsCache } from '@elementor/editor-elements';
2
+ import { __privateListenTo, v1ReadyEvent } from '@elementor/editor-v1-adapters';
3
+
4
+ import { createElementType } from './create-element-type';
5
+ import type { LegacyWindow } from './types';
6
+
7
+ export function initLegacyViews() {
8
+ __privateListenTo( v1ReadyEvent(), () => {
9
+ const config = getWidgetsCache() ?? {};
10
+ const legacyWindow = window as unknown as LegacyWindow;
11
+
12
+ Object.entries( config ).forEach( ( [ type, element ] ) => {
13
+ if ( ! element.atomic ) {
14
+ return;
15
+ }
16
+
17
+ const ElementType = createElementType( type );
18
+
19
+ legacyWindow.elementor.elementsManager.registerElementType( new ElementType() );
20
+ } );
21
+ } );
22
+ }
@@ -0,0 +1,60 @@
1
+ export type LegacyWindow = Window & {
2
+ elementor: {
3
+ modules: {
4
+ elements: {
5
+ types: {
6
+ Widget: typeof ElementType;
7
+ };
8
+ views: {
9
+ Widget: typeof ElementView;
10
+ };
11
+ };
12
+ };
13
+ elementsManager: {
14
+ registerElementType: ( type: ElementType ) => void;
15
+ };
16
+ };
17
+ };
18
+
19
+ export declare class ElementType {
20
+ getType(): string;
21
+
22
+ getView(): typeof ElementView;
23
+ }
24
+
25
+ export declare class ElementView {
26
+ $el: JQueryElement;
27
+
28
+ model: BackboneModel;
29
+
30
+ onRender( ...args: unknown[] ): void;
31
+
32
+ onDestroy( ...args: unknown[] ): void;
33
+
34
+ attributes(): Record< string, unknown >;
35
+
36
+ behaviors(): Record< string, unknown >;
37
+
38
+ getDomElement(): JQueryElement;
39
+
40
+ getHandlesOverlay(): JQueryElement | null;
41
+
42
+ getContextMenuGroups(): ContextMenuGroup[];
43
+ }
44
+
45
+ type JQueryElement = {
46
+ find: ( selector: string ) => JQueryElement;
47
+ };
48
+
49
+ type BackboneModel = {
50
+ get: < T extends keyof Model >( key: T ) => Model[ T ];
51
+ };
52
+
53
+ type Model = {
54
+ id: string;
55
+ };
56
+
57
+ type ContextMenuGroup = {
58
+ name: string;
59
+ action: unknown[];
60
+ };
@@ -0,0 +1,3 @@
1
+ import { createTransformersRegistry } from './transformers/create-transformers-registry';
2
+
3
+ export const settingsTransformersRegistry = createTransformersRegistry();