@elementor/editor-canvas 0.6.1 → 0.7.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.
@@ -6,14 +6,29 @@ import enqueueUsedFonts from './styles-renderer/enqueue-used-fonts';
6
6
  import { getCanvasIframeBody } from './sync/get-canvas-iframe-body';
7
7
 
8
8
  const WRAPPER_DATA_ATTR = 'data-styles-container';
9
+ const SELECTOR_PREFIX = '.elementor';
9
10
 
10
11
  export function initStylesRenderer() {
11
- stylesRepository.subscribe( () => {
12
+ let abortController: AbortController | null = null;
13
+
14
+ stylesRepository.subscribe( async () => {
12
15
  const styleContainer = getStylesContainer();
13
16
  const styles = stylesRepository.all();
14
17
  const breakpoints = getBreakpointsMap();
15
18
 
16
- styleContainer.innerHTML = render( { transformers, styles, breakpoints } );
19
+ if ( abortController ) {
20
+ abortController.abort();
21
+ }
22
+
23
+ abortController = new AbortController();
24
+
25
+ styleContainer.innerHTML = await render( {
26
+ transformers,
27
+ styles,
28
+ breakpoints,
29
+ selectorPrefix: SELECTOR_PREFIX,
30
+ signal: abortController.signal,
31
+ } );
17
32
 
18
33
  enqueueUsedFonts( styles );
19
34
  } );
@@ -533,7 +533,46 @@ export const stylesSchemaMock = {
533
533
  key: 'string',
534
534
  default: null,
535
535
  meta: {},
536
- settings: {},
536
+ settings: {
537
+ enum: [ 'repeat', 'repeat-x', 'repeat-y', 'no-repeat' ],
538
+ },
539
+ },
540
+ size: {
541
+ kind: 'plain',
542
+ key: 'string',
543
+ default: null,
544
+ meta: {},
545
+ settings: {
546
+ enum: [ 'auto', 'cover', 'contain' ],
547
+ },
548
+ },
549
+ attachment: {
550
+ kind: 'plain',
551
+ key: 'string',
552
+ default: null,
553
+ meta: {},
554
+ settings: {
555
+ enum: [ 'fixed', 'scroll' ],
556
+ },
557
+ },
558
+ position: {
559
+ kind: 'plain',
560
+ key: 'string',
561
+ default: null,
562
+ meta: {},
563
+ settings: {
564
+ enum: [
565
+ 'center center',
566
+ 'center left',
567
+ 'center right',
568
+ 'top center',
569
+ 'top left',
570
+ 'top right',
571
+ 'bottom center',
572
+ 'bottom left',
573
+ 'bottom right',
574
+ ],
575
+ },
537
576
  },
538
577
  },
539
578
  },
@@ -21,7 +21,10 @@ describe( 'enqueueUsedFonts', () => {
21
21
  state: null,
22
22
  },
23
23
  props: {
24
- 'font-family': 'Open Sans',
24
+ 'font-family': {
25
+ $$type: 'string',
26
+ value: 'Open Sans',
27
+ },
25
28
  },
26
29
  },
27
30
  ],
@@ -36,7 +39,10 @@ describe( 'enqueueUsedFonts', () => {
36
39
  state: 'hover',
37
40
  },
38
41
  props: {
39
- 'font-family': 'Roboto',
42
+ 'font-family': {
43
+ $$type: 'string',
44
+ value: 'Roboto',
45
+ },
40
46
  },
41
47
  },
42
48
  ],
@@ -10,21 +10,24 @@ import {
10
10
  boxShadowPropTypeUtil,
11
11
  colorPropTypeUtil,
12
12
  dimensionsPropTypeUtil,
13
- gapPropTypeUtil,
13
+ imageAttachmentIdPropType,
14
+ imageSrcPropTypeUtil,
15
+ layoutDirectionPropTypeUtil,
14
16
  shadowPropTypeUtil,
15
17
  sizePropTypeUtil,
16
18
  strokePropTypeUtil,
17
19
  } from '@elementor/editor-props';
18
20
  import type { BreakpointsMap } from '@elementor/editor-responsive';
19
- import { type StyleDefinition } from '@elementor/editor-styles';
21
+ import { getStylesSchema, type StyleDefinition } from '@elementor/editor-styles';
22
+ import { getMediaAttachment } from '@elementor/wp-media';
20
23
 
21
- import { getStylesSchema } from '../get-styles-schema';
22
24
  import render from '../render';
23
25
  import transformers from '../transformers';
24
26
  import backgroundTransformer from '../transformers/background-transformer';
25
27
  import { stylesSchemaMock } from './__mocks__/styles-schema';
26
28
 
27
- jest.mock( '../get-styles-schema' );
29
+ jest.mock( '@elementor/editor-styles' );
30
+ jest.mock( '@elementor/wp-media' );
28
31
 
29
32
  describe( 'styles-renderer', () => {
30
33
  beforeEach( () => {
@@ -35,7 +38,7 @@ describe( 'styles-renderer', () => {
35
38
  * Prop Types
36
39
  */
37
40
 
38
- it( 'should transform stroke (including also size, number, string & color)', () => {
41
+ it( 'should transform stroke (including also size, number, string & color)', async () => {
39
42
  const styleDef = createMockStyleDefinition( {
40
43
  id: 'test',
41
44
  props: {
@@ -49,7 +52,7 @@ describe( 'styles-renderer', () => {
49
52
  },
50
53
  } );
51
54
 
52
- const cssString = render( {
55
+ const cssString = await render( {
53
56
  styles: [ styleDef ],
54
57
  transformers,
55
58
  breakpoints: mockBreakpoints,
@@ -58,7 +61,7 @@ describe( 'styles-renderer', () => {
58
61
  expect( cssString ).toBe( `<style data-style-id="test">.test{text-stroke:1px #000000;}</style>` );
59
62
  } );
60
63
 
61
- it( 'should transform box-shadow (including also shadow)', () => {
64
+ it( 'should transform box-shadow (including also shadow)', async () => {
62
65
  // Arrange.
63
66
  const shadow = shadowPropTypeUtil.create( {
64
67
  hOffset: sizePropTypeUtil.create( {
@@ -96,7 +99,7 @@ describe( 'styles-renderer', () => {
96
99
  } );
97
100
 
98
101
  // Act.
99
- const cssString = render( {
102
+ const cssString = await render( {
100
103
  styles: [ styleDef ],
101
104
  transformers,
102
105
  breakpoints: mockBreakpoints,
@@ -108,7 +111,7 @@ describe( 'styles-renderer', () => {
108
111
  );
109
112
  } );
110
113
 
111
- it( 'should transform linked-dimensions (including also size, number & string)', () => {
114
+ it( 'should transform linked-dimensions (including also size, number & string)', async () => {
112
115
  // Arrange.
113
116
  const styleDef = createMockStyleDefinition( {
114
117
  id: 'test',
@@ -135,7 +138,7 @@ describe( 'styles-renderer', () => {
135
138
  } );
136
139
 
137
140
  // Act.
138
- const cssString = render( {
141
+ const cssString = await render( {
139
142
  styles: [ styleDef ],
140
143
  transformers,
141
144
  breakpoints: mockBreakpoints,
@@ -147,7 +150,7 @@ describe( 'styles-renderer', () => {
147
150
  );
148
151
  } );
149
152
 
150
- it( 'should transform border-width (including also size, number & string)', () => {
153
+ it( 'should transform border-width (including also size, number & string)', async () => {
151
154
  // Arrange.
152
155
  const styleDef = createMockStyleDefinition( {
153
156
  id: 'test',
@@ -173,7 +176,7 @@ describe( 'styles-renderer', () => {
173
176
  },
174
177
  } );
175
178
  // Act.
176
- const cssString = render( {
179
+ const cssString = await render( {
177
180
  styles: [ styleDef ],
178
181
  transformers,
179
182
  breakpoints: mockBreakpoints,
@@ -185,7 +188,7 @@ describe( 'styles-renderer', () => {
185
188
  );
186
189
  } );
187
190
 
188
- it( 'should transform border-radius (including also union, size, number & string)', () => {
191
+ it( 'should transform border-radius (including also union, size, number & string)', async () => {
189
192
  // Arrange.
190
193
  const styleDef = createMockStyleDefinition( {
191
194
  id: 'test',
@@ -212,7 +215,7 @@ describe( 'styles-renderer', () => {
212
215
  } );
213
216
 
214
217
  // Act.
215
- const cssString = render( {
218
+ const cssString = await render( {
216
219
  styles: [ styleDef ],
217
220
  transformers,
218
221
  breakpoints: mockBreakpoints,
@@ -224,13 +227,12 @@ describe( 'styles-renderer', () => {
224
227
  );
225
228
  } );
226
229
 
227
- it( 'should transform gap (including also size, number & string)', () => {
230
+ it( 'should transform layout direction', async () => {
228
231
  // Arrange.
229
232
  const styleDef = createMockStyleDefinition( {
230
233
  id: 'test',
231
234
  props: {
232
- gap: gapPropTypeUtil.create( {
233
- isLinked: true,
235
+ gap: layoutDirectionPropTypeUtil.create( {
234
236
  row: sizePropTypeUtil.create( {
235
237
  size: 10,
236
238
  unit: 'px',
@@ -244,7 +246,7 @@ describe( 'styles-renderer', () => {
244
246
  } );
245
247
 
246
248
  // Act.
247
- const cssString = render( {
249
+ const cssString = await render( {
248
250
  styles: [ styleDef ],
249
251
  transformers,
250
252
  breakpoints: mockBreakpoints,
@@ -257,7 +259,7 @@ describe( 'styles-renderer', () => {
257
259
  * Features
258
260
  */
259
261
 
260
- it( 'should render media queries', () => {
262
+ it( 'should render media queries', async () => {
261
263
  // Arrange.
262
264
  const styleDef: StyleDefinition = {
263
265
  id: 'test',
@@ -306,7 +308,7 @@ describe( 'styles-renderer', () => {
306
308
  };
307
309
 
308
310
  // Act.
309
- const cssString = render( {
311
+ const cssString = await render( {
310
312
  styles: [ styleDef ],
311
313
  transformers,
312
314
  breakpoints: mockBreakpoints,
@@ -322,7 +324,7 @@ describe( 'styles-renderer', () => {
322
324
  );
323
325
  } );
324
326
 
325
- it( 'should render pseudo classes', () => {
327
+ it( 'should render pseudo classes', async () => {
326
328
  // Arrange.
327
329
  const styleDef: StyleDefinition = {
328
330
  id: 'test',
@@ -371,7 +373,7 @@ describe( 'styles-renderer', () => {
371
373
  };
372
374
 
373
375
  // Act.
374
- const cssString = render( {
376
+ const cssString = await render( {
375
377
  styles: [ styleDef ],
376
378
  transformers,
377
379
  breakpoints: mockBreakpoints,
@@ -387,7 +389,7 @@ describe( 'styles-renderer', () => {
387
389
  );
388
390
  } );
389
391
 
390
- it( 'should skip disabled props', () => {
392
+ it( 'should skip disabled props', async () => {
391
393
  // Arrange.
392
394
  const styleDef = createMockStyleDefinition( {
393
395
  id: 'test',
@@ -407,7 +409,7 @@ describe( 'styles-renderer', () => {
407
409
  } );
408
410
 
409
411
  // Act.
410
- const cssString = render( {
412
+ const cssString = await render( {
411
413
  styles: [ styleDef ],
412
414
  transformers,
413
415
  breakpoints: mockBreakpoints,
@@ -417,7 +419,7 @@ describe( 'styles-renderer', () => {
417
419
  expect( cssString ).toBe( `<style data-style-id="test">.test{font-size:24px;}</style>` );
418
420
  } );
419
421
 
420
- it( 'should fallback to default value when there is no value', () => {
422
+ it( 'should fallback to default value when there is no value', async () => {
421
423
  // Arrange.
422
424
  const styleDef = createMockStyleDefinition( {
423
425
  id: 'test',
@@ -438,7 +440,7 @@ describe( 'styles-renderer', () => {
438
440
  } );
439
441
 
440
442
  // Act.
441
- const cssString = render( {
443
+ const cssString = await render( {
442
444
  styles: [ styleDef ],
443
445
  transformers,
444
446
  breakpoints: mockBreakpoints,
@@ -448,7 +450,7 @@ describe( 'styles-renderer', () => {
448
450
  expect( cssString ).toBe( `<style data-style-id="test">.test{overflow:hidden;}</style>` );
449
451
  } );
450
452
 
451
- it( 'should skip props that are not in the schema', () => {
453
+ it( 'should skip props that are not in the schema', async () => {
452
454
  // Arrange.
453
455
  const styleDef = createMockStyleDefinition( {
454
456
  id: 'test',
@@ -465,7 +467,7 @@ describe( 'styles-renderer', () => {
465
467
  } );
466
468
 
467
469
  // Act.
468
- const cssString = render( {
470
+ const cssString = await render( {
469
471
  styles: [ styleDef ],
470
472
  transformers,
471
473
  breakpoints: mockBreakpoints,
@@ -475,7 +477,7 @@ describe( 'styles-renderer', () => {
475
477
  expect( cssString ).toBe( `<style data-style-id="test">.test{font-size:24px;}</style>` );
476
478
  } );
477
479
 
478
- it( "should skip props that don't have a transformer", () => {
480
+ it( "should skip props that don't have a transformer", async () => {
479
481
  // Arrange.
480
482
  const styleDef = createMockStyleDefinition( {
481
483
  id: 'test',
@@ -492,7 +494,7 @@ describe( 'styles-renderer', () => {
492
494
  } );
493
495
 
494
496
  // Act.
495
- const cssString = render( {
497
+ const cssString = await render( {
496
498
  styles: [ styleDef ],
497
499
  transformers,
498
500
  breakpoints: mockBreakpoints,
@@ -502,7 +504,7 @@ describe( 'styles-renderer', () => {
502
504
  expect( cssString ).toBe( `<style data-style-id="test">.test{font-size:24px;}</style>` );
503
505
  } );
504
506
 
505
- it( 'should skip props when their transformer throws an error', () => {
507
+ it( 'should skip props when their transformer throws an error', async () => {
506
508
  // Arrange.
507
509
  const styleDef = createMockStyleDefinition( {
508
510
  id: 'test',
@@ -516,7 +518,7 @@ describe( 'styles-renderer', () => {
516
518
  } );
517
519
 
518
520
  // Act.
519
- const cssString = render( {
521
+ const cssString = await render( {
520
522
  styles: [ styleDef ],
521
523
  transformers: {
522
524
  size: () => {
@@ -530,7 +532,7 @@ describe( 'styles-renderer', () => {
530
532
  expect( cssString ).toBe( `<style data-style-id="test">.test{font-size:24px;}</style>` );
531
533
  } );
532
534
 
533
- it( 'should consider 0 as valid value', () => {
535
+ it( 'should consider 0 as valid value', async () => {
534
536
  // Arrange.
535
537
  const styleDef = createMockStyleDefinition( {
536
538
  id: 'test',
@@ -543,7 +545,7 @@ describe( 'styles-renderer', () => {
543
545
  } );
544
546
 
545
547
  // Act.
546
- const cssString = render( {
548
+ const cssString = await render( {
547
549
  styles: [ styleDef ],
548
550
  transformers,
549
551
  breakpoints: mockBreakpoints,
@@ -552,6 +554,30 @@ describe( 'styles-renderer', () => {
552
554
  // Assert.
553
555
  expect( cssString ).toBe( `<style data-style-id="test">.test{font-size:0px;}</style>` );
554
556
  } );
557
+
558
+ it( 'should add selector prefix to the output', async () => {
559
+ // Arrange.
560
+ const styleDef = createMockStyleDefinition( {
561
+ id: 'test',
562
+ props: {
563
+ 'font-size': sizePropTypeUtil.create( {
564
+ size: 24,
565
+ unit: 'px',
566
+ } ),
567
+ },
568
+ } );
569
+
570
+ // Act.
571
+ const cssString = await render( {
572
+ styles: [ styleDef ],
573
+ transformers,
574
+ selectorPrefix: '.elementor-prefix',
575
+ breakpoints: mockBreakpoints,
576
+ } );
577
+
578
+ // Assert.
579
+ expect( cssString ).toBe( `<style data-style-id="test">.elementor-prefix .test{font-size:24px;}</style>` );
580
+ } );
555
581
  } );
556
582
 
557
583
  const backgroundExpectationWrapper = ( id: string, bgShorthand: string ) => {
@@ -563,7 +589,7 @@ describe( 'background-transformer', () => {
563
589
  jest.mocked( getStylesSchema ).mockReturnValue( stylesSchemaMock );
564
590
  } );
565
591
 
566
- it( 'should transform background color', () => {
592
+ it( 'should transform background color', async () => {
567
593
  // Arrange.
568
594
  const styleDef = createMockStyleDefinition( {
569
595
  id: 'bg-color',
@@ -575,7 +601,7 @@ describe( 'background-transformer', () => {
575
601
  } );
576
602
 
577
603
  // Act.
578
- const cssString = render( {
604
+ const cssString = await render( {
579
605
  styles: [ styleDef ],
580
606
  transformers,
581
607
  breakpoints: mockBreakpoints,
@@ -585,8 +611,12 @@ describe( 'background-transformer', () => {
585
611
  expect( cssString ).toBe( backgroundExpectationWrapper( 'bg-color', '#ee00ff' ) );
586
612
  } );
587
613
 
588
- it( 'should transform background overlay (repeater)', () => {
614
+ it( 'should transform background overlay (repeater)', async () => {
589
615
  // Arrange.
616
+ jest.mocked( getMediaAttachment ).mockImplementation( ( args ) => {
617
+ return Promise.resolve( { url: `image-url-${ args.id }` } ) as never;
618
+ } );
619
+
590
620
  const styleDef = createMockStyleDefinition( {
591
621
  id: 'test',
592
622
  props: {
@@ -594,14 +624,30 @@ describe( 'background-transformer', () => {
594
624
  'background-overlay': backgroundOverlayPropTypeUtil.create( [
595
625
  backgroundColorOverlayPropTypeUtil.create( 'blue' ),
596
626
  backgroundColorOverlayPropTypeUtil.create( 'yellow' ),
597
- backgroundImageOverlayPropTypeUtil.create( { 'image-src': { id: 123, url: null } } ),
627
+ backgroundImageOverlayPropTypeUtil.create( {
628
+ 'image-src': imageSrcPropTypeUtil.create( {
629
+ id: imageAttachmentIdPropType.create( 123 ),
630
+ url: null,
631
+ } ),
632
+ size: 'contain',
633
+ } ),
634
+ backgroundImageOverlayPropTypeUtil.create( {
635
+ 'image-src': imageSrcPropTypeUtil.create( {
636
+ id: imageAttachmentIdPropType.create( 123 ),
637
+ url: null,
638
+ } ),
639
+ size: 'auto',
640
+ position: 'center right',
641
+ repeat: 'repeat-x',
642
+ attachment: 'fixed',
643
+ } ),
598
644
  ] ),
599
645
  } ),
600
646
  },
601
647
  } );
602
648
 
603
649
  // Act.
604
- const cssString = render( {
650
+ const cssString = await render( {
605
651
  styles: [ styleDef ],
606
652
  transformers,
607
653
  breakpoints: mockBreakpoints,
@@ -611,13 +657,17 @@ describe( 'background-transformer', () => {
611
657
  expect( cssString ).toBe(
612
658
  backgroundExpectationWrapper(
613
659
  'test',
614
- 'linear-gradient(blue, blue),linear-gradient(yellow, yellow),url("https://bit.ly/2rlzaXi")'
660
+ 'linear-gradient(blue, blue),linear-gradient(yellow, yellow),url(image-url-123) 0% 0% / contain,url(image-url-123) repeat-x fixed center right / auto'
615
661
  )
616
662
  );
617
663
  } );
618
664
 
619
- it( 'should transform background (including also background-overlay & color)', () => {
665
+ it( 'should transform background (including also background-overlay & color)', async () => {
620
666
  // Arrange.
667
+ jest.mocked( getMediaAttachment ).mockImplementation( ( args ) => {
668
+ return Promise.resolve( { url: `image-url-${ args.id }` } ) as never;
669
+ } );
670
+
621
671
  const styleDef = createMockStyleDefinition( {
622
672
  id: 'test',
623
673
  props: {
@@ -626,14 +676,30 @@ describe( 'background-transformer', () => {
626
676
  'background-overlay': backgroundOverlayPropTypeUtil.create( [
627
677
  backgroundColorOverlayPropTypeUtil.create( '#FFFFFF' ),
628
678
  backgroundColorOverlayPropTypeUtil.create( '#FF2222' ),
629
- backgroundImageOverlayPropTypeUtil.create( { 'image-src': { id: 123, url: null } } ),
679
+ backgroundImageOverlayPropTypeUtil.create( {
680
+ 'image-src': imageSrcPropTypeUtil.create( {
681
+ id: imageAttachmentIdPropType.create( 123 ),
682
+ url: null,
683
+ } ),
684
+ size: 'contain',
685
+ } ),
686
+ backgroundImageOverlayPropTypeUtil.create( {
687
+ 'image-src': imageSrcPropTypeUtil.create( {
688
+ id: imageAttachmentIdPropType.create( 123 ),
689
+ url: null,
690
+ } ),
691
+ size: 'auto',
692
+ position: 'center right',
693
+ repeat: 'repeat-y',
694
+ attachment: 'fixed',
695
+ } ),
630
696
  ] ),
631
697
  } ),
632
698
  },
633
699
  } );
634
700
 
635
701
  // Act.
636
- const cssString = render( {
702
+ const cssString = await render( {
637
703
  styles: [ styleDef ],
638
704
  transformers,
639
705
  breakpoints: mockBreakpoints,
@@ -643,7 +709,7 @@ describe( 'background-transformer', () => {
643
709
  expect( cssString ).toBe(
644
710
  backgroundExpectationWrapper(
645
711
  'test',
646
- 'linear-gradient(#FFFFFF, #FFFFFF),linear-gradient(#FF2222, #FF2222),url("https://bit.ly/2rlzaXi") #000'
712
+ 'linear-gradient(#FFFFFF, #FFFFFF),linear-gradient(#FF2222, #FF2222),url(image-url-123) 0% 0% / contain,url(image-url-123) repeat-y fixed center right / auto #000'
647
713
  )
648
714
  );
649
715
  } );
@@ -657,7 +723,7 @@ describe( 'background-overlay-transformer', () => {
657
723
  };
658
724
 
659
725
  // Act.
660
- const result = backgroundTransformer( initialData, 'background-overlay' );
726
+ const result = backgroundTransformer( initialData, { key: 'background-overlay' } );
661
727
 
662
728
  // Assert.
663
729
  expect( result ).toBe( '' );
@@ -672,7 +738,7 @@ describe( 'background-overlay-transformer', () => {
672
738
  };
673
739
 
674
740
  // Act.
675
- const result = backgroundTransformer( initialData, 'background-overlay' );
741
+ const result = backgroundTransformer( initialData, { key: 'background-overlay' } );
676
742
 
677
743
  // Assert.
678
744
  expect( result ).toBe( backgroundColor );
@@ -688,7 +754,7 @@ describe( 'background-overlay-transformer', () => {
688
754
  };
689
755
 
690
756
  // Act.
691
- const result = backgroundTransformer( initialData, 'background-overlay' );
757
+ const result = backgroundTransformer( initialData, { key: 'background-overlay' } );
692
758
 
693
759
  // Assert.
694
760
  expect( result ).toBe( expected );
@@ -1,3 +1,4 @@
1
+ import { type StringPropValue } from '@elementor/editor-props';
1
2
  import { type StyleDefinition } from '@elementor/editor-styles';
2
3
  import { ensureError } from '@elementor/utils';
3
4
 
@@ -7,10 +8,10 @@ export default function enqueueUsedFonts( styles: StyleDefinition[] ) {
7
8
  try {
8
9
  styles.forEach( ( styleDef ) => {
9
10
  Object.values( styleDef.variants ).forEach( ( variant ) => {
10
- const fontFamily = variant.props[ 'font-family' ] ?? null;
11
+ const fontFamily = variant.props[ 'font-family' ] as StringPropValue;
11
12
 
12
- if ( fontFamily && typeof fontFamily === 'string' ) {
13
- enqueueFont( fontFamily );
13
+ if ( fontFamily?.value ) {
14
+ enqueueFont( fontFamily.value );
14
15
  }
15
16
  } );
16
17
  } );
@@ -0,0 +1,6 @@
1
+ import { createError } from '@elementor/utils';
2
+
3
+ export const UnknownStyleTypeError = createError< { type: string } >( {
4
+ code: 'unknown_style_type',
5
+ message: 'Unknown style type',
6
+ } );