@elementor/editor-canvas 0.9.0 → 0.11.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 (57) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +36 -0
  3. package/dist/index.d.mts +17 -1
  4. package/dist/index.d.ts +17 -1
  5. package/dist/index.js +203 -225
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +192 -227
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +10 -10
  10. package/src/{renderers/__tests__ → __tests__}/__mocks__/styles-schema.ts +258 -131
  11. package/src/__tests__/init-styles-renderer.test.ts +8 -3
  12. package/src/{renderers/__tests__/create-props-resolver.transformers.test.ts → __tests__/styles-prop-resolver.test.ts} +19 -27
  13. package/src/index.ts +2 -0
  14. package/src/init-style-transformers.ts +58 -0
  15. package/src/init-styles-renderer.ts +8 -6
  16. package/src/init.tsx +2 -0
  17. package/src/renderers/__tests__/create-props-resolver.test.ts +44 -34
  18. package/src/renderers/__tests__/render-styles.test.ts +3 -15
  19. package/src/renderers/create-props-resolver.ts +32 -31
  20. package/src/renderers/render-styles.ts +4 -7
  21. package/src/style-transformers-registry.ts +3 -0
  22. package/src/transformers/create-transformer.ts +13 -0
  23. package/src/transformers/create-transformers-registry.ts +16 -0
  24. package/src/transformers/styles/background-color-overlay-transformer.ts +5 -0
  25. package/src/transformers/styles/background-image-overlay-transformer.ts +28 -0
  26. package/src/transformers/styles/background-image-position-offset-transformer.ts +10 -0
  27. package/src/transformers/styles/background-image-size-scale-transformer.ts +10 -0
  28. package/src/transformers/styles/background-transformer.ts +13 -0
  29. package/src/transformers/styles/create-combine-array-transformer.ts +5 -0
  30. package/src/transformers/styles/create-multi-props-transformer.ts +14 -0
  31. package/src/transformers/styles/image-attachment-transformer.ts +15 -0
  32. package/src/transformers/styles/image-src-transformer.ts +11 -0
  33. package/src/transformers/styles/image-transformer.ts +34 -0
  34. package/src/transformers/styles/primitive-transformer.ts +3 -0
  35. package/src/transformers/styles/shadow-transformer.ts +16 -0
  36. package/src/transformers/styles/size-transformer.ts +10 -0
  37. package/src/transformers/styles/stroke-transformer.ts +17 -0
  38. package/src/transformers/types.ts +20 -0
  39. package/src/renderers/style-transformers/background-color-overlay-transformer.ts +0 -9
  40. package/src/renderers/style-transformers/background-image-overlay-transformer.ts +0 -24
  41. package/src/renderers/style-transformers/background-image-position-offset-transformer.ts +0 -10
  42. package/src/renderers/style-transformers/background-image-size-scale-transformer.ts +0 -10
  43. package/src/renderers/style-transformers/background-transformer.ts +0 -12
  44. package/src/renderers/style-transformers/create-combine-array-transformer.ts +0 -9
  45. package/src/renderers/style-transformers/create-corner-sizes-transformer.ts +0 -31
  46. package/src/renderers/style-transformers/create-edge-sizes-transformer.ts +0 -31
  47. package/src/renderers/style-transformers/dimensions.ts +0 -20
  48. package/src/renderers/style-transformers/image-attachment.ts +0 -14
  49. package/src/renderers/style-transformers/image-src.ts +0 -8
  50. package/src/renderers/style-transformers/image.ts +0 -25
  51. package/src/renderers/style-transformers/index.ts +0 -48
  52. package/src/renderers/style-transformers/layout-direction-transformer.ts +0 -20
  53. package/src/renderers/style-transformers/primitive-transformer.ts +0 -7
  54. package/src/renderers/style-transformers/shadow-transformer.ts +0 -11
  55. package/src/renderers/style-transformers/size-transformer.ts +0 -9
  56. package/src/renderers/style-transformers/stroke-transformer.ts +0 -16
  57. package/src/renderers/types.ts +0 -12
@@ -1,3 +1,4 @@
1
+ import { styleTransformersRegistry } from '@elementor/editor-canvas';
1
2
  import {
2
3
  backgroundColorOverlayPropTypeUtil,
3
4
  backgroundImageOverlayPropTypeUtil,
@@ -15,15 +16,15 @@ import {
15
16
  imageSrcPropTypeUtil,
16
17
  layoutDirectionPropTypeUtil,
17
18
  type Props,
18
- type PropsSchema,
19
19
  shadowPropTypeUtil,
20
20
  sizePropTypeUtil,
21
+ stringPropTypeUtil,
21
22
  strokePropTypeUtil,
22
23
  } from '@elementor/editor-props';
23
24
  import { getMediaAttachment } from '@elementor/wp-media';
24
25
 
25
- import { createPropsResolver } from '../create-props-resolver';
26
- import { styleTransformers } from '../style-transformers';
26
+ import { initStyleTransformers } from '../init-style-transformers';
27
+ import { createPropsResolver } from '../renderers/create-props-resolver';
27
28
  import { stylesSchemaMock } from './__mocks__/styles-schema';
28
29
 
29
30
  jest.mock( '@elementor/wp-media' );
@@ -32,11 +33,10 @@ type Payload = {
32
33
  name: string;
33
34
  prepare?: () => void;
34
35
  props: Props;
35
- schema: PropsSchema;
36
36
  expected: Record< string, unknown >;
37
37
  };
38
38
 
39
- describe( 'createPropsResolver - transformers', () => {
39
+ describe( 'styles prop resolver', () => {
40
40
  it.each< Payload >( [
41
41
  {
42
42
  name: 'text-stroke',
@@ -49,7 +49,6 @@ describe( 'createPropsResolver - transformers', () => {
49
49
  color: colorPropTypeUtil.create( '#000000' ),
50
50
  } ),
51
51
  },
52
- schema: stylesSchemaMock,
53
52
  expected: {
54
53
  '-webkit-text-stroke': '1px #000000',
55
54
  stroke: '#000000',
@@ -77,7 +76,6 @@ describe( 'createPropsResolver - transformers', () => {
77
76
  } ),
78
77
  ] ),
79
78
  },
80
- schema: stylesSchemaMock,
81
79
  expected: {
82
80
  'box-shadow': '1px 1px 1px 1px #000000,1px 1px 1px 1px #000000 inset',
83
81
  },
@@ -85,7 +83,7 @@ describe( 'createPropsResolver - transformers', () => {
85
83
  {
86
84
  name: 'linked-dimensional',
87
85
  props: {
88
- padding: dimensionsPropTypeUtil.create( {
86
+ margin: dimensionsPropTypeUtil.create( {
89
87
  top: sizePropTypeUtil.create( {
90
88
  size: 10,
91
89
  unit: 'px',
@@ -98,18 +96,14 @@ describe( 'createPropsResolver - transformers', () => {
98
96
  size: 30,
99
97
  unit: 'px',
100
98
  } ),
101
- left: sizePropTypeUtil.create( {
102
- size: 40,
103
- unit: 'px',
104
- } ),
99
+ left: stringPropTypeUtil.create( 'auto' ),
105
100
  } ),
106
101
  },
107
- schema: stylesSchemaMock,
108
102
  expected: {
109
- 'padding-top': '10px',
110
- 'padding-right': '20px',
111
- 'padding-bottom': '30px',
112
- 'padding-left': '40px',
103
+ 'margin-top': '10px',
104
+ 'margin-right': '20px',
105
+ 'margin-bottom': '30px',
106
+ 'margin-left': 'auto',
113
107
  },
114
108
  },
115
109
  {
@@ -122,7 +116,6 @@ describe( 'createPropsResolver - transformers', () => {
122
116
  left: sizePropTypeUtil.create( { size: 40, unit: 'px' } ),
123
117
  } ),
124
118
  },
125
- schema: stylesSchemaMock,
126
119
  expected: {
127
120
  'border-top-width': '10px',
128
121
  'border-right-width': '20px',
@@ -140,7 +133,6 @@ describe( 'createPropsResolver - transformers', () => {
140
133
  'end-end': sizePropTypeUtil.create( { size: 40, unit: 'px' } ),
141
134
  } ),
142
135
  },
143
- schema: stylesSchemaMock,
144
136
  expected: {
145
137
  'border-start-start-radius': '10px',
146
138
  'border-start-end-radius': '20px',
@@ -156,7 +148,6 @@ describe( 'createPropsResolver - transformers', () => {
156
148
  column: sizePropTypeUtil.create( { size: 20, unit: 'px' } ),
157
149
  } ),
158
150
  },
159
- schema: stylesSchemaMock,
160
151
  expected: {
161
152
  'column-gap': '20px',
162
153
  'row-gap': '10px',
@@ -169,7 +160,6 @@ describe( 'createPropsResolver - transformers', () => {
169
160
  color: colorPropTypeUtil.create( '#ee00ff' ),
170
161
  } ),
171
162
  },
172
- schema: stylesSchemaMock,
173
163
  expected: {
174
164
  background: '#ee00ff',
175
165
  },
@@ -191,7 +181,6 @@ describe( 'createPropsResolver - transformers', () => {
191
181
  ] ),
192
182
  } ),
193
183
  },
194
- schema: stylesSchemaMock,
195
184
  expected: {
196
185
  background: 'url(https://localhost.test/test-image.png)',
197
186
  },
@@ -249,7 +238,6 @@ describe( 'createPropsResolver - transformers', () => {
249
238
  ] ),
250
239
  } ),
251
240
  },
252
- schema: stylesSchemaMock,
253
241
  expected: {
254
242
  background:
255
243
  'linear-gradient(blue, blue),linear-gradient(yellow, yellow),' +
@@ -291,19 +279,23 @@ describe( 'createPropsResolver - transformers', () => {
291
279
  ] ),
292
280
  } ),
293
281
  },
294
- schema: stylesSchemaMock,
295
282
  expected: {
296
283
  background: 'url(medium_large-image-url-123) repeat-x,url(thumbnail-image-url-123) fixed',
297
284
  },
298
285
  },
299
- ] )( 'it should resolve props for `$name`', async ( { prepare, props, schema, expected } ) => {
286
+ ] )( 'it should resolve props for `$name`', async ( { prepare, props, expected } ) => {
300
287
  // Arrange.
301
288
  prepare?.();
302
289
 
303
- const resolve = createPropsResolver( styleTransformers );
290
+ initStyleTransformers();
291
+
292
+ const resolve = createPropsResolver( {
293
+ transformers: styleTransformersRegistry.all(),
294
+ schema: stylesSchemaMock,
295
+ } );
304
296
 
305
297
  // Act.
306
- const result = await resolve( { props, schema } );
298
+ const result = await resolve( { props } );
307
299
 
308
300
  // Assert.
309
301
  expect( result ).toStrictEqual( expected );
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import { init } from './init';
2
2
 
3
+ export { styleTransformersRegistry } from './style-transformers-registry';
4
+
3
5
  init();
@@ -0,0 +1,58 @@
1
+ import { styleTransformersRegistry } from './style-transformers-registry';
2
+ import { backgroundColorOverlayTransformer } from './transformers/styles/background-color-overlay-transformer';
3
+ import { backgroundImageOverlayTransformer } from './transformers/styles/background-image-overlay-transformer';
4
+ import { backgroundImagePositionOffsetTransformer } from './transformers/styles/background-image-position-offset-transformer';
5
+ import { backgroundImageSizeScaleTransformer } from './transformers/styles/background-image-size-scale-transformer';
6
+ import { backgroundTransformer } from './transformers/styles/background-transformer';
7
+ import { createCombineArrayTransformer } from './transformers/styles/create-combine-array-transformer';
8
+ 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
+ import { shadowTransformer } from './transformers/styles/shadow-transformer';
14
+ import { sizeTransformer } from './transformers/styles/size-transformer';
15
+ import { strokeTransformer } from './transformers/styles/stroke-transformer';
16
+
17
+ export function initStyleTransformers() {
18
+ styleTransformersRegistry
19
+ .register( 'size', sizeTransformer )
20
+ .register( 'shadow', shadowTransformer )
21
+ .register( 'stroke', strokeTransformer )
22
+ .register(
23
+ 'dimensions',
24
+ createMultiPropsTransformer(
25
+ [ 'top', 'right', 'bottom', 'left' ],
26
+ ( { propKey, key } ) => `${ propKey }-${ key }`
27
+ )
28
+ )
29
+ .register( 'color', primitiveTransformer )
30
+ .register( 'number', primitiveTransformer )
31
+ .register( 'string', primitiveTransformer )
32
+ .register( 'url', primitiveTransformer )
33
+ .register( 'box-shadow', createCombineArrayTransformer( ',' ) )
34
+ .register( 'background', backgroundTransformer )
35
+ .register( 'background-overlay', createCombineArrayTransformer( ',' ) )
36
+ .register( 'background-color-overlay', backgroundColorOverlayTransformer )
37
+ .register( 'background-image-overlay', backgroundImageOverlayTransformer )
38
+ .register( 'background-image-position-offset', backgroundImagePositionOffsetTransformer )
39
+ .register( 'background-image-size-scale', backgroundImageSizeScaleTransformer )
40
+ .register( 'image-attachment-id', imageAttachmentTransformer )
41
+ .register( 'image-src', imageSrcTransformer )
42
+ .register( 'image', imageTransformer )
43
+ .register(
44
+ 'layout-direction',
45
+ createMultiPropsTransformer( [ 'row', 'column' ], ( { propKey, key } ) => `${ key }-${ propKey }` )
46
+ )
47
+ .register(
48
+ 'border-width',
49
+ createMultiPropsTransformer( [ 'top', 'right', 'bottom', 'left' ], ( { key } ) => `border-${ key }-width` )
50
+ )
51
+ .register(
52
+ 'border-radius',
53
+ createMultiPropsTransformer(
54
+ [ 'start-start', 'start-end', 'end-start', 'end-end' ],
55
+ ( { key } ) => `border-${ key }-radius`
56
+ )
57
+ );
58
+ }
@@ -5,7 +5,7 @@ import { __privateListenTo as listenTo, v1ReadyEvent } from '@elementor/editor-v
5
5
 
6
6
  import { createPropsResolver } from './renderers/create-props-resolver';
7
7
  import renderStyles from './renderers/render-styles';
8
- import { styleTransformers } from './renderers/style-transformers';
8
+ import { styleTransformersRegistry } from './style-transformers-registry';
9
9
  import { enqueueFont } from './sync/enqueue-font';
10
10
  import { getCanvasIframeBody } from './sync/get-canvas-iframe-body';
11
11
 
@@ -13,18 +13,21 @@ const WRAPPER_DATA_ATTR = 'data-styles-container';
13
13
  const SELECTOR_PREFIX = '.elementor';
14
14
 
15
15
  export function initStylesRenderer() {
16
- let abortController: AbortController | null = null;
16
+ listenTo( v1ReadyEvent(), () => {
17
+ let abortController: AbortController | null = null;
17
18
 
18
- const resolve = createPropsResolver( styleTransformers, { onPropResolve: enqueueUsedFonts } );
19
+ const resolve = createPropsResolver( {
20
+ transformers: styleTransformersRegistry.all(),
21
+ schema: getStylesSchema(),
22
+ onPropResolve: enqueueUsedFonts,
23
+ } );
19
24
 
20
- listenTo( v1ReadyEvent(), () => {
21
25
  stylesRepository.subscribe( async () => {
22
26
  const styleContainer = getStylesContainer();
23
27
 
24
28
  // Styles should be printed in a reversed order, so the high priority styles will be printed last.
25
29
  const styles = stylesRepository.all().reverse();
26
30
  const breakpoints = getBreakpointsMap();
27
- const schema = getStylesSchema();
28
31
 
29
32
  if ( abortController ) {
30
33
  abortController.abort();
@@ -38,7 +41,6 @@ export function initStylesRenderer() {
38
41
  breakpoints,
39
42
  selectorPrefix: SELECTOR_PREFIX,
40
43
  signal: abortController.signal,
41
- schema,
42
44
  } );
43
45
  } );
44
46
  } );
package/src/init.tsx CHANGED
@@ -1,9 +1,11 @@
1
1
  import { injectIntoTop } from '@elementor/editor';
2
2
 
3
3
  import { ElementsOverlays } from './components/elements-overlays';
4
+ import { initStyleTransformers } from './init-style-transformers';
4
5
  import { initStylesRenderer } from './init-styles-renderer';
5
6
 
6
7
  export function init() {
8
+ initStyleTransformers();
7
9
  initStylesRenderer();
8
10
 
9
11
  injectIntoTop( {
@@ -1,20 +1,21 @@
1
1
  import { createMockPropType } from 'test-utils';
2
2
 
3
+ import { createTransformer } from '../../transformers/create-transformer';
3
4
  import { createPropsResolver } from '../create-props-resolver';
4
5
 
5
6
  describe( 'createPropsResolver', () => {
6
7
  it( 'should resolve simple props', async () => {
7
8
  // Arrange.
8
- const resolve = createPropsResolver( { int: ( value ) => value + 1 } );
9
+ const resolve = createPropsResolver( {
10
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
11
+ schema: { int: createMockPropType( { kind: 'plain', key: 'int' } ) },
12
+ } );
9
13
 
10
14
  // Act.
11
15
  const result = await resolve( {
12
16
  props: {
13
17
  int: { $$type: 'int', value: 0 },
14
18
  },
15
- schema: {
16
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
17
- },
18
19
  } );
19
20
 
20
21
  // Assert.
@@ -23,7 +24,10 @@ describe( 'createPropsResolver', () => {
23
24
 
24
25
  it( 'should skip disabled props', async () => {
25
26
  // Arrange.
26
- const resolve = createPropsResolver( { int: ( value ) => value + 1 } );
27
+ const resolve = createPropsResolver( {
28
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
29
+ schema: { int: createMockPropType( { kind: 'plain', key: 'int' } ) },
30
+ } );
27
31
 
28
32
  // Act.
29
33
  const result = await resolve( {
@@ -34,9 +38,6 @@ describe( 'createPropsResolver', () => {
34
38
  disabled: true,
35
39
  },
36
40
  },
37
- schema: {
38
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
39
- },
40
41
  } );
41
42
 
42
43
  // Assert.
@@ -45,11 +46,8 @@ describe( 'createPropsResolver', () => {
45
46
 
46
47
  it( 'should fallback to default value when there is no value', async () => {
47
48
  // Arrange.
48
- const resolve = createPropsResolver( { int: ( value ) => value + 1 } );
49
-
50
- // Act.
51
- const result = await resolve( {
52
- props: {},
49
+ const resolve = createPropsResolver( {
50
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
53
51
  schema: {
54
52
  int: createMockPropType( {
55
53
  kind: 'plain',
@@ -59,13 +57,21 @@ describe( 'createPropsResolver', () => {
59
57
  },
60
58
  } );
61
59
 
60
+ // Act.
61
+ const result = await resolve( { props: {} } );
62
+
62
63
  // Assert.
63
64
  expect( result ).toEqual( { int: 4 } );
64
65
  } );
65
66
 
66
67
  it( 'should skip props that are not in the schema', async () => {
67
68
  // Arrange.
68
- const resolve = createPropsResolver( { int: ( value ) => value + 1 } );
69
+ const resolve = createPropsResolver( {
70
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
71
+ schema: {
72
+ int: createMockPropType( { kind: 'plain', key: 'int' } ),
73
+ },
74
+ } );
69
75
 
70
76
  // Act.
71
77
  const result = await resolve( {
@@ -79,9 +85,6 @@ describe( 'createPropsResolver', () => {
79
85
  value: 1,
80
86
  },
81
87
  },
82
- schema: {
83
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
84
- },
85
88
  } );
86
89
 
87
90
  // Assert.
@@ -90,7 +93,13 @@ describe( 'createPropsResolver', () => {
90
93
 
91
94
  it( "should skip props that don't have a transformer", async () => {
92
95
  // Arrange.
93
- const resolve = createPropsResolver( { int: ( value ) => value + 1 } );
96
+ const resolve = createPropsResolver( {
97
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
98
+ schema: {
99
+ int: createMockPropType( { kind: 'plain', key: 'int' } ),
100
+ invalid: createMockPropType( { kind: 'plain', key: 'invalid' } ),
101
+ },
102
+ } );
94
103
 
95
104
  // Act.
96
105
  const result = await resolve( {
@@ -104,10 +113,6 @@ describe( 'createPropsResolver', () => {
104
113
  value: 1,
105
114
  },
106
115
  },
107
- schema: {
108
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
109
- invalid: createMockPropType( { kind: 'plain', key: 'invalid' } ),
110
- },
111
116
  } );
112
117
 
113
118
  // Assert.
@@ -116,9 +121,15 @@ describe( 'createPropsResolver', () => {
116
121
 
117
122
  it( 'should skip props when their transformer throws an error', async () => {
118
123
  const resolve = createPropsResolver( {
119
- int: ( value ) => value + 1,
120
- throws: () => {
121
- throw new Error( 'Not Working!' );
124
+ transformers: {
125
+ int: createTransformer( ( value: number ) => value + 1 ),
126
+ throws: createTransformer< number >( () => {
127
+ throw new Error( 'Not Working!' );
128
+ } ),
129
+ },
130
+ schema: {
131
+ int: createMockPropType( { kind: 'plain', key: 'int' } ),
132
+ invalid: createMockPropType( { kind: 'plain', key: 'throws' } ),
122
133
  },
123
134
  } );
124
135
 
@@ -134,10 +145,6 @@ describe( 'createPropsResolver', () => {
134
145
  value: 1,
135
146
  },
136
147
  },
137
- schema: {
138
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
139
- invalid: createMockPropType( { kind: 'plain', key: 'throws' } ),
140
- },
141
148
  } );
142
149
 
143
150
  // Assert.
@@ -147,7 +154,14 @@ describe( 'createPropsResolver', () => {
147
154
  it( 'should trigger onResolve when resolving a prop', async () => {
148
155
  const onResolve = jest.fn();
149
156
 
150
- const resolve = createPropsResolver( { int: ( value ) => value + 1 }, { onPropResolve: onResolve } );
157
+ const resolve = createPropsResolver( {
158
+ transformers: { int: createTransformer( ( value: number ) => value + 1 ) },
159
+ schema: {
160
+ int: createMockPropType( { kind: 'plain', key: 'int' } ),
161
+ int2: createMockPropType( { kind: 'plain', key: 'int' } ),
162
+ },
163
+ onPropResolve: onResolve,
164
+ } );
151
165
 
152
166
  // Act.
153
167
  await resolve( {
@@ -161,10 +175,6 @@ describe( 'createPropsResolver', () => {
161
175
  value: 3,
162
176
  },
163
177
  },
164
- schema: {
165
- int: createMockPropType( { kind: 'plain', key: 'int' } ),
166
- int2: createMockPropType( { kind: 'plain', key: 'int' } ),
167
- },
168
178
  } );
169
179
 
170
180
  // Assert.
@@ -1,18 +1,10 @@
1
1
  /* eslint-disable testing-library/render-result-naming-convention */
2
- import { createMockPropType } from 'test-utils';
3
2
  import type { BreakpointsMap } from '@elementor/editor-responsive';
4
- import { getStylesSchema, type StyleDefinition } from '@elementor/editor-styles';
3
+ import { type StyleDefinition } from '@elementor/editor-styles';
5
4
 
6
5
  import renderStyles from '../render-styles';
7
- import { stylesSchemaMock } from './__mocks__/styles-schema';
8
-
9
- jest.mock( '@elementor/editor-styles' );
10
6
 
11
7
  describe( 'renderStyles', () => {
12
- beforeEach( () => {
13
- jest.mocked( getStylesSchema ).mockReturnValue( stylesSchemaMock );
14
- } );
15
-
16
8
  it( 'should render media queries', async () => {
17
9
  // Arrange.
18
10
  const styleDef: StyleDefinition = {
@@ -32,14 +24,12 @@ describe( 'renderStyles', () => {
32
24
  };
33
25
 
34
26
  const resolve = jest.fn( ( { props } ) => props );
35
- const schema = { 'font-size': createMockPropType( { kind: 'plain', key: 'string' } ) };
36
27
 
37
28
  // Act.
38
29
  const cssString = await renderStyles( {
39
30
  styles: [ styleDef ],
40
31
  resolve,
41
32
  breakpoints: { tablet: { width: 992, type: 'max-width' } } as BreakpointsMap,
42
- schema,
43
33
  } );
44
34
 
45
35
  // Assert.
@@ -49,8 +39,8 @@ describe( 'renderStyles', () => {
49
39
  expect( cssString ).toBe( `<style data-style-id="test">${ defaultStyle }${ tabletStyle }</style>` );
50
40
 
51
41
  expect( resolve ).toHaveBeenCalledTimes( 2 );
52
- expect( resolve ).toHaveBeenNthCalledWith( 1, { props: { 'font-size': '24px' }, schema } );
53
- expect( resolve ).toHaveBeenNthCalledWith( 2, { props: { 'font-size': '18px' }, schema } );
42
+ expect( resolve ).toHaveBeenNthCalledWith( 1, { props: { 'font-size': '24px' } } );
43
+ expect( resolve ).toHaveBeenNthCalledWith( 2, { props: { 'font-size': '18px' } } );
54
44
  } );
55
45
 
56
46
  it( 'should render pseudo classes', async () => {
@@ -82,7 +72,6 @@ describe( 'renderStyles', () => {
82
72
  styles: [ styleDef ],
83
73
  resolve,
84
74
  breakpoints: { mobile: { width: 768, type: 'max-width' } } as BreakpointsMap,
85
- schema: { 'font-size': createMockPropType( { kind: 'plain', key: 'string' } ) },
86
75
  } );
87
76
 
88
77
  // Assert.
@@ -115,7 +104,6 @@ describe( 'renderStyles', () => {
115
104
  const result = await renderStyles( {
116
105
  styles: [ styleDef ],
117
106
  resolve,
118
- schema: getStylesSchema(),
119
107
  selectorPrefix: '.elementor-prefix',
120
108
  breakpoints: {} as BreakpointsMap,
121
109
  } );
@@ -7,16 +7,18 @@ import {
7
7
  type PropValue,
8
8
  } from '@elementor/editor-props';
9
9
 
10
+ import { type TransformersMap } from '../transformers/types';
10
11
  import { getMultiPropsValue, isMultiProps } from './multi-props';
11
- import { type TransformersMap } from './types';
12
12
 
13
- type CreatePropResolverOptions = {
13
+ type CreatePropResolverArgs = {
14
+ transformers: TransformersMap;
15
+ schema: PropsSchema;
14
16
  onPropResolve?: ( args: { key: string; value: unknown } ) => void;
15
17
  };
16
18
 
17
19
  type ResolveArgs = {
18
20
  props: Props;
19
- schema: PropsSchema;
21
+ schema?: PropsSchema;
20
22
  signal?: AbortSignal;
21
23
  };
22
24
 
@@ -32,10 +34,33 @@ export type PropsResolver = ReturnType< typeof createPropsResolver >;
32
34
 
33
35
  const TRANSFORM_DEPTH_LIMIT = 3;
34
36
 
35
- export function createPropsResolver(
36
- transformers: TransformersMap,
37
- { onPropResolve }: CreatePropResolverOptions = {}
38
- ) {
37
+ export function createPropsResolver( { transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs ) {
38
+ async function resolve( { props, schema, signal }: ResolveArgs ) {
39
+ schema = schema ?? initialSchema;
40
+
41
+ const promises = Promise.all(
42
+ Object.entries( schema ).map( async ( [ key, type ] ) => {
43
+ const value = props[ key ] ?? type.default;
44
+
45
+ const transformed = await transform( { value, key, type, signal } );
46
+
47
+ if ( transformed === null ) {
48
+ return;
49
+ }
50
+
51
+ onPropResolve?.( { key, value: transformed } );
52
+
53
+ if ( isMultiProps( transformed ) ) {
54
+ return getMultiPropsValue( transformed );
55
+ }
56
+
57
+ return { [ key ]: transformed };
58
+ } )
59
+ );
60
+
61
+ return Object.assign( {}, ...( await promises ).filter( Boolean ) );
62
+ }
63
+
39
64
  async function transform( { value, key, type, signal, depth = 0 }: TransformArgs ) {
40
65
  if ( value === null || value === undefined ) {
41
66
  return null;
@@ -95,29 +120,5 @@ export function createPropsResolver(
95
120
  }
96
121
  }
97
122
 
98
- async function resolve( { props, schema, signal }: ResolveArgs ) {
99
- const promises = Promise.all(
100
- Object.entries( schema ).map( async ( [ key, type ] ) => {
101
- const value = props[ key ] ?? type.default;
102
-
103
- const transformed = await transform( { value, key, type, signal } );
104
-
105
- if ( transformed === null ) {
106
- return;
107
- }
108
-
109
- onPropResolve?.( { key, value: transformed } );
110
-
111
- if ( isMultiProps( transformed ) ) {
112
- return getMultiPropsValue( transformed );
113
- }
114
-
115
- return { [ key ]: transformed };
116
- } )
117
- );
118
-
119
- return Object.assign( {}, ...( await promises ).filter( Boolean ) );
120
- }
121
-
122
123
  return resolve;
123
124
  }
@@ -1,4 +1,4 @@
1
- import { type Props, type PropsSchema } from '@elementor/editor-props';
1
+ import { type Props } from '@elementor/editor-props';
2
2
  import { type Breakpoint, type BreakpointsMap } from '@elementor/editor-responsive';
3
3
  import { type StyleDefinition, type StyleDefinitionState, type StyleDefinitionType } from '@elementor/editor-styles';
4
4
 
@@ -8,7 +8,6 @@ import { UnknownStyleTypeError } from './errors';
8
8
  type RenderParams = {
9
9
  resolve: PropsResolver;
10
10
  styles: StyleDefinition[];
11
- schema: PropsSchema;
12
11
  breakpoints: BreakpointsMap;
13
12
  selectorPrefix?: string;
14
13
  signal?: AbortSignal;
@@ -16,7 +15,6 @@ type RenderParams = {
16
15
 
17
16
  type PropsToCssArgs = {
18
17
  props: Props;
19
- schema: PropsSchema;
20
18
  resolve: PropsResolver;
21
19
  signal?: AbortSignal;
22
20
  };
@@ -28,14 +26,13 @@ const SELECTORS_MAP: Record< StyleDefinitionType, string > = {
28
26
  export default async function renderStyles( {
29
27
  resolve,
30
28
  styles,
31
- schema,
32
29
  breakpoints,
33
30
  selectorPrefix = '',
34
31
  signal,
35
32
  }: RenderParams ) {
36
33
  const stylesCssPromises = styles.map( async ( style ) => {
37
34
  const variantCssPromises = Object.values( style.variants ).map( async ( variant ) => {
38
- const css = await propsToCss( { props: variant.props, schema, resolve, signal } );
35
+ const css = await propsToCss( { props: variant.props, resolve, signal } );
39
36
 
40
37
  return createStyleWrapper()
41
38
  .forStyle( style )
@@ -95,8 +92,8 @@ function createStyleWrapper( value: string = '', wrapper?: ( css: string ) => st
95
92
  };
96
93
  }
97
94
 
98
- async function propsToCss( { props, resolve, signal, schema }: PropsToCssArgs ) {
99
- const transformed = await resolve( { props, schema, signal } );
95
+ async function propsToCss( { props, resolve, signal }: PropsToCssArgs ) {
96
+ const transformed = await resolve( { props, signal } );
100
97
 
101
98
  return Object.entries( transformed )
102
99
  .reduce< string[] >( ( acc, [ propName, propValue ] ) => {
@@ -0,0 +1,3 @@
1
+ import { createTransformersRegistry } from './transformers/create-transformers-registry';
2
+
3
+ export const styleTransformersRegistry = createTransformersRegistry();
@@ -0,0 +1,13 @@
1
+ import { type AnyTransformable } from '@elementor/editor-props';
2
+
3
+ import { type Transformer, type UnbrandedTransformer } from './types';
4
+
5
+ // Wrap transformer for better DX (types).
6
+ // Inspired by: https://tkdodo.eu/blog/the-query-options-api
7
+ export function createTransformer< TValue = never >(
8
+ cb: TValue extends AnyTransformable
9
+ ? 'Transformable values are invalid, use the actual value instead.'
10
+ : UnbrandedTransformer< TValue >
11
+ ): Transformer< NoInfer< TValue > > {
12
+ return cb as never;
13
+ }