@elementor/editor-controls 0.15.0 → 0.16.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-controls",
3
3
  "description": "This package contains the controls model and utils for the Elementor editor",
4
- "version": "0.15.0",
4
+ "version": "0.16.0",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,10 +40,10 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor-props": "0.9.4",
43
+ "@elementor/editor-props": "0.10.0",
44
44
  "@elementor/env": "0.3.5",
45
45
  "@elementor/http": "0.1.4",
46
- "@elementor/icons": "1.35.0",
46
+ "@elementor/icons": "1.37.0",
47
47
  "@elementor/query": "0.2.4",
48
48
  "@elementor/session": "0.1.0",
49
49
  "@elementor/ui": "1.26.0",
@@ -0,0 +1,101 @@
1
+ import * as React from 'react';
2
+ import {
3
+ backgroundGradientOverlayPropTypeUtil,
4
+ type BackgroundGradientOverlayPropValue,
5
+ type BackgroundOverlayItemPropValue,
6
+ colorPropTypeUtil,
7
+ type ColorPropValue,
8
+ colorStopPropTypeUtil,
9
+ gradientColorStopPropTypeUtil,
10
+ numberPropTypeUtil,
11
+ type NumberPropValue,
12
+ stringPropTypeUtil,
13
+ type TransformablePropValue,
14
+ } from '@elementor/editor-props';
15
+ import { UnstableGradientBox } from '@elementor/ui';
16
+
17
+ import { useBoundProp } from '../../bound-prop-context';
18
+ import ControlActions from '../../control-actions/control-actions';
19
+ import { createControl } from '../../create-control';
20
+
21
+ export type ColorStop = TransformablePropValue<
22
+ 'color-stop',
23
+ {
24
+ color: ColorPropValue;
25
+ offset: NumberPropValue;
26
+ }
27
+ >;
28
+
29
+ export const BackgroundGradientColorControl = createControl( () => {
30
+ const { value, setValue } = useBoundProp( backgroundGradientOverlayPropTypeUtil );
31
+
32
+ const handleChange = ( newValue: BackgroundGradientOverlayPropValue[ 'value' ] ) => {
33
+ const transformedValue = createTransformableValue( newValue );
34
+
35
+ if ( transformedValue.positions ) {
36
+ transformedValue.positions = stringPropTypeUtil.create( newValue.positions.join( ' ' ) );
37
+ }
38
+
39
+ setValue( transformedValue );
40
+ };
41
+
42
+ // TODO: To support Global variables this won't be needed when we have a flexible Gradient Box
43
+ const createTransformableValue = ( newValue: BackgroundGradientOverlayPropValue[ 'value' ] ) => ( {
44
+ ...newValue,
45
+ type: stringPropTypeUtil.create( newValue.type ),
46
+ angle: numberPropTypeUtil.create( newValue.angle ),
47
+ stops: gradientColorStopPropTypeUtil.create(
48
+ newValue.stops.map( ( { color, offset }: { color: string; offset: number } ) =>
49
+ colorStopPropTypeUtil.create( {
50
+ color: colorPropTypeUtil.create( color ),
51
+ offset: numberPropTypeUtil.create( offset ),
52
+ } )
53
+ )
54
+ ),
55
+ } );
56
+
57
+ // TODO: To support Global variables this won't be needed when we have a flexible Gradient Box
58
+ const normalizeValue = () => {
59
+ if ( ! value ) {
60
+ return;
61
+ }
62
+
63
+ const { type, angle, stops, positions } = value;
64
+
65
+ return {
66
+ type: type.value,
67
+ angle: angle.value,
68
+ stops: stops.value.map( ( { value: { color, offset } }: ColorStop ) => ( {
69
+ color: color.value,
70
+ offset: offset.value,
71
+ } ) ),
72
+ positions: positions?.value.split( ' ' ),
73
+ };
74
+ };
75
+
76
+ return (
77
+ <ControlActions>
78
+ <UnstableGradientBox
79
+ sx={ { width: 'auto', padding: 1.5 } }
80
+ value={ normalizeValue() }
81
+ onChange={ handleChange }
82
+ />
83
+ </ControlActions>
84
+ );
85
+ } );
86
+
87
+ export const initialBackgroundGradientOverlay: BackgroundOverlayItemPropValue =
88
+ backgroundGradientOverlayPropTypeUtil.create( {
89
+ type: stringPropTypeUtil.create( 'linear' ),
90
+ angle: numberPropTypeUtil.create( 180 ),
91
+ stops: gradientColorStopPropTypeUtil.create( [
92
+ colorStopPropTypeUtil.create( {
93
+ color: stringPropTypeUtil.create( 'var(--primary-color)' ),
94
+ offset: numberPropTypeUtil.create( 0 ),
95
+ } ),
96
+ colorStopPropTypeUtil.create( {
97
+ color: colorPropTypeUtil.create( 'rgb(255,255,255)' ),
98
+ offset: numberPropTypeUtil.create( 100 ),
99
+ } ),
100
+ ] ),
101
+ } );
@@ -17,6 +17,11 @@ import { createControl } from '../../../create-control';
17
17
  import { env } from '../../../env';
18
18
  import { ColorControl } from '../../color-control';
19
19
  import { ImageControl } from '../../image-control';
20
+ import {
21
+ BackgroundGradientColorControl,
22
+ type ColorStop,
23
+ initialBackgroundGradientOverlay,
24
+ } from '../background-gradient-color-control';
20
25
  import { BackgroundImageOverlayAttachment } from './background-image-overlay/background-image-overlay-attachment';
21
26
  import { BackgroundImageOverlayPosition } from './background-image-overlay/background-image-overlay-position';
22
27
  import { BackgroundImageOverlayRepeat } from './background-image-overlay/background-image-overlay-repeat';
@@ -93,6 +98,7 @@ const Content = () => {
93
98
  const { getTabsProps, getTabProps, getTabPanelProps } = useBackgroundTabsHistory( {
94
99
  image: getInitialBackgroundOverlay().value,
95
100
  color: initialBackgroundColorOverlay.value,
101
+ gradient: initialBackgroundGradientOverlay.value,
96
102
  } );
97
103
 
98
104
  return (
@@ -100,6 +106,7 @@ const Content = () => {
100
106
  <Box sx={ { borderBottom: 1, borderColor: 'divider' } }>
101
107
  <Tabs { ...getTabsProps() } aria-label={ __( 'Background Overlay', 'elementor' ) }>
102
108
  <Tab label={ __( 'Image', 'elementor' ) } { ...getTabProps( 'image' ) } />
109
+ <Tab label={ __( 'Gradient', 'elementor' ) } { ...getTabProps( 'gradient' ) } />
103
110
  <Tab label={ __( 'Color', 'elementor' ) } { ...getTabProps( 'color' ) } />
104
111
  </Tabs>
105
112
  </Box>
@@ -108,12 +115,11 @@ const Content = () => {
108
115
  <ImageOverlayContent />
109
116
  </PopoverContent>
110
117
  </TabPanel>
118
+ <TabPanel sx={ { p: 1.5 } } { ...getTabPanelProps( 'gradient' ) }>
119
+ <BackgroundGradientColorControl />
120
+ </TabPanel>
111
121
  <TabPanel { ...getTabPanelProps( 'color' ) } sx={ { p: 1.5 } }>
112
- <Grid container spacing={ 1 } alignItems="center">
113
- <Grid item xs={ 12 }>
114
- <ColorControl propTypeUtil={ backgroundColorOverlayPropTypeUtil } />
115
- </Grid>
116
- </Grid>
122
+ <ColorControl propTypeUtil={ backgroundColorOverlayPropTypeUtil } />
117
123
  </TabPanel>
118
124
  </Box>
119
125
  );
@@ -125,6 +131,8 @@ const ItemIcon = ( { value }: { value: BackgroundOverlayItemPropValue } ) => {
125
131
  return <ItemIconImage value={ value as BackgroundImageOverlay } />;
126
132
  case 'background-color-overlay':
127
133
  return <ItemIconColor value={ value } />;
134
+ case 'background-gradient-overlay':
135
+ return <ItemIconGradient value={ value } />;
128
136
  default:
129
137
  return null;
130
138
  }
@@ -140,12 +148,20 @@ const ItemIconImage = ( { value }: { value: BackgroundImageOverlay } ) => {
140
148
  return <CardMedia image={ imageUrl } sx={ { height: 13, width: 13, borderRadius: '4px' } } />;
141
149
  };
142
150
 
151
+ const ItemIconGradient = ( { value }: { value: BackgroundOverlayItemPropValue } ) => {
152
+ const gradient = getGradientValue( value );
153
+
154
+ return <UnstableColorIndicator size="inherit" component="span" value={ gradient } />;
155
+ };
156
+
143
157
  const ItemLabel = ( { value }: { value: BackgroundOverlayItemPropValue } ) => {
144
158
  switch ( value.$$type ) {
145
159
  case 'background-image-overlay':
146
160
  return <ItemLabelImage value={ value as BackgroundImageOverlay } />;
147
161
  case 'background-color-overlay':
148
162
  return <ItemLabelColor value={ value } />;
163
+ case 'background-gradient-overlay':
164
+ return <ItemLabelGradient value={ value } />;
149
165
  default:
150
166
  return null;
151
167
  }
@@ -161,6 +177,14 @@ const ItemLabelImage = ( { value }: { value: BackgroundImageOverlay } ) => {
161
177
  return <span>{ imageTitle }</span>;
162
178
  };
163
179
 
180
+ const ItemLabelGradient = ( { value }: { value: BackgroundOverlayItemPropValue } ) => {
181
+ if ( value.value.type.value === 'linear' ) {
182
+ return <span>{ __( 'Linear Gradient', 'elementor' ) }</span>;
183
+ }
184
+
185
+ return <span>{ __( 'Radial Gradient', 'elementor' ) }</span>;
186
+ };
187
+
164
188
  const ImageOverlayContent = () => {
165
189
  const propContext = useBoundProp( backgroundImageOverlayPropTypeUtil );
166
190
 
@@ -210,3 +234,17 @@ const useImage = ( image: BackgroundImageOverlay ) => {
210
234
 
211
235
  return { imageTitle, imageUrl };
212
236
  };
237
+
238
+ const getGradientValue = ( value: BackgroundOverlayItemPropValue ) => {
239
+ const gradient = value.value;
240
+
241
+ const stops = gradient.stops.value
242
+ ?.map( ( { value: { color, offset } }: ColorStop ) => `${ color.value } ${ offset.value ?? 0 }%` )
243
+ ?.join( ',' );
244
+
245
+ if ( gradient.type.value === 'linear' ) {
246
+ return `linear-gradient(${ gradient.angle.value }deg, ${ stops })`;
247
+ }
248
+
249
+ return `radial-gradient(circle at ${ gradient.positions.value }, ${ stops })`;
250
+ };
@@ -1,6 +1,7 @@
1
1
  import { useRef } from 'react';
2
2
  import {
3
3
  backgroundColorOverlayPropTypeUtil,
4
+ backgroundGradientOverlayPropTypeUtil,
4
5
  backgroundImageOverlayPropTypeUtil,
5
6
  type BackgroundOverlayItemPropValue,
6
7
  } from '@elementor/editor-props';
@@ -9,25 +10,41 @@ import { useTabs } from '@elementor/ui';
9
10
  import { useBoundProp } from '../../../bound-prop-context';
10
11
  import { type BackgroundImageOverlay } from './types';
11
12
 
12
- type OverlayType = 'image' | 'color';
13
+ type OverlayType = 'image' | 'gradient' | 'color';
13
14
 
14
15
  type InitialBackgroundValues = {
15
16
  color: BackgroundOverlayItemPropValue[ 'value' ];
16
17
  image: BackgroundImageOverlay[ 'value' ];
18
+ gradient: BackgroundOverlayItemPropValue[ 'value' ];
17
19
  };
18
20
 
19
21
  export const useBackgroundTabsHistory = ( {
20
22
  color: initialBackgroundColorOverlay,
21
23
  image: initialBackgroundImageOverlay,
24
+ gradient: initialBackgroundGradientOverlay,
22
25
  }: InitialBackgroundValues ) => {
23
26
  const { value: imageValue, setValue: setImageValue } = useBoundProp( backgroundImageOverlayPropTypeUtil );
24
27
  const { value: colorValue, setValue: setColorValue } = useBoundProp( backgroundColorOverlayPropTypeUtil );
28
+ const { value: gradientValue, setValue: setGradientValue } = useBoundProp( backgroundGradientOverlayPropTypeUtil );
25
29
 
26
- const { getTabsProps, getTabProps, getTabPanelProps } = useTabs< OverlayType >( colorValue ? 'color' : 'image' );
30
+ const getCurrentOverlayType = (): OverlayType => {
31
+ if ( colorValue ) {
32
+ return 'color';
33
+ }
34
+
35
+ if ( gradientValue ) {
36
+ return 'gradient';
37
+ }
38
+
39
+ return 'image';
40
+ };
41
+
42
+ const { getTabsProps, getTabProps, getTabPanelProps } = useTabs< OverlayType >( getCurrentOverlayType() );
27
43
 
28
44
  const valuesHistory = useRef< InitialBackgroundValues >( {
29
45
  image: initialBackgroundImageOverlay,
30
46
  color: initialBackgroundColorOverlay,
47
+ gradient: initialBackgroundGradientOverlay,
31
48
  } );
32
49
 
33
50
  const saveToHistory = ( key: keyof InitialBackgroundValues, value: BackgroundOverlayItemPropValue[ 'value' ] ) => {
@@ -42,6 +59,15 @@ export const useBackgroundTabsHistory = ( {
42
59
  setImageValue( valuesHistory.current.image );
43
60
 
44
61
  saveToHistory( 'color', colorValue );
62
+ saveToHistory( 'gradient', gradientValue );
63
+
64
+ break;
65
+
66
+ case 'gradient':
67
+ setGradientValue( valuesHistory.current.gradient );
68
+
69
+ saveToHistory( 'color', colorValue );
70
+ saveToHistory( 'image', imageValue );
45
71
 
46
72
  break;
47
73
 
@@ -49,6 +75,7 @@ export const useBackgroundTabsHistory = ( {
49
75
  setColorValue( valuesHistory.current.color );
50
76
 
51
77
  saveToHistory( 'image', imageValue );
78
+ saveToHistory( 'gradient', gradientValue );
52
79
  }
53
80
 
54
81
  return getTabsProps().onChange( e, tabName );
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { stringPropTypeUtil } from '@elementor/editor-props';
4
- import { ChevronDownIcon, EditIcon, PhotoIcon, SearchIcon, XIcon } from '@elementor/icons';
4
+ import { ChevronDownIcon, SearchIcon, TextIcon, XIcon } from '@elementor/icons';
5
5
  import {
6
6
  bindPopover,
7
7
  bindTrigger,
@@ -72,7 +72,7 @@ export const FontFamilyControl = createControl( ( { fontFamilies }: FontFamilyCo
72
72
  >
73
73
  <Stack>
74
74
  <Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
75
- <EditIcon fontSize={ SIZE } sx={ { mr: 0.5 } } />
75
+ <TextIcon fontSize={ SIZE } sx={ { mr: 0.5 } } />
76
76
  <Typography variant="subtitle2">{ __( 'Font Family', 'elementor' ) }</Typography>
77
77
  <IconButton size={ SIZE } sx={ { ml: 'auto' } } onClick={ handleClose }>
78
78
  <XIcon fontSize={ SIZE } />
@@ -105,24 +105,40 @@ export const FontFamilyControl = createControl( ( { fontFamilies }: FontFamilyCo
105
105
  />
106
106
  ) : (
107
107
  <Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
108
- <Stack alignItems="center" p={ 2.5 } gap={ 1.5 }>
109
- <PhotoIcon fontSize="large" />
110
- <Typography align="center" variant="caption" color="text.secondary">
111
- { __( 'Sorry, nothing matched', 'elementor' ) }
112
- <br />
113
- &ldquo;{ searchValue }&rdquo;.
114
- </Typography>
108
+ <Stack alignItems="center" p={ 2.5 } gap={ 1.5 } overflow={ 'hidden' }>
109
+ <TextIcon fontSize="large" />
110
+ <Box sx={ { maxWidth: 160, overflow: 'hidden' } }>
111
+ <Typography align="center" variant="subtitle2" color="text.secondary">
112
+ { __( 'Sorry, nothing matched', 'elementor' ) }
113
+ </Typography>
114
+ <Typography
115
+ variant="subtitle2"
116
+ color="text.secondary"
117
+ sx={ {
118
+ display: 'flex',
119
+ width: '100%',
120
+ justifyContent: 'center',
121
+ } }
122
+ >
123
+ <span>&ldquo;</span>
124
+ <span
125
+ style={ { maxWidth: '80%', overflow: 'hidden', textOverflow: 'ellipsis' } }
126
+ >
127
+ { searchValue }
128
+ </span>
129
+ <span>&rdquo;.</span>
130
+ </Typography>
131
+ </Box>
115
132
  <Typography align="center" variant="caption" color="text.secondary">
133
+ { __( 'Try something else.', 'elementor' ) }
116
134
  <Link
117
135
  color="secondary"
118
136
  variant="caption"
119
137
  component="button"
120
138
  onClick={ () => setSearchValue( '' ) }
121
139
  >
122
- { __( 'Clear the filters', 'elementor' ) }
140
+ { __( 'Clear & try again', 'elementor' ) }
123
141
  </Link>
124
- &nbsp;
125
- { __( 'and try again.', 'elementor' ) }
126
142
  </Typography>
127
143
  </Stack>
128
144
  </Box>