@elementor/editor-controls 1.3.0 → 1.5.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/CHANGELOG.md +40 -0
- package/dist/index.d.mts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +777 -629
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +617 -458
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/components/font-family-selector.tsx +54 -56
- package/src/components/repeater.tsx +22 -11
- package/src/components/size-control/size-input.tsx +4 -4
- package/src/controls/color-control.tsx +12 -1
- package/src/controls/filter-control/drop-shadow-item-content.tsx +69 -0
- package/src/controls/filter-control/drop-shadow-item-label.tsx +20 -0
- package/src/controls/filter-repeater-control.tsx +108 -21
- package/src/controls/key-value-control.tsx +57 -46
- package/src/controls/repeatable-control.tsx +48 -29
- package/src/controls/size-control.tsx +25 -12
- package/src/controls/text-control.tsx +33 -18
- package/src/utils/size-control.ts +4 -2
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": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor-current-user": "0.6.
|
|
44
|
-
"@elementor/editor-elements": "0.9.
|
|
45
|
-
"@elementor/editor-props": "0.
|
|
43
|
+
"@elementor/editor-current-user": "0.6.1",
|
|
44
|
+
"@elementor/editor-elements": "0.9.2",
|
|
45
|
+
"@elementor/editor-props": "0.18.0",
|
|
46
46
|
"@elementor/editor-responsive": "0.13.6",
|
|
47
|
-
"@elementor/editor-ui": "0.14.
|
|
47
|
+
"@elementor/editor-ui": "0.14.2",
|
|
48
48
|
"@elementor/editor-v1-adapters": "0.12.1",
|
|
49
49
|
"@elementor/env": "0.3.5",
|
|
50
50
|
"@elementor/http-client": "0.3.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import { PopoverHeader, PopoverMenuList,
|
|
3
|
+
import { PopoverBody, PopoverHeader, PopoverMenuList, PopoverSearch } from '@elementor/editor-ui';
|
|
4
4
|
import { TextIcon } from '@elementor/icons';
|
|
5
5
|
import { Box, Divider, Link, Stack, Typography } from '@elementor/ui';
|
|
6
6
|
import { debounce } from '@elementor/utils';
|
|
@@ -41,7 +41,7 @@ export const FontFamilySelector = ( {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
|
-
<
|
|
44
|
+
<PopoverBody width={ sectionWidth }>
|
|
45
45
|
<PopoverHeader
|
|
46
46
|
title={ __( 'Font Family', 'elementor' ) }
|
|
47
47
|
onClose={ handleClose }
|
|
@@ -56,64 +56,62 @@ export const FontFamilySelector = ( {
|
|
|
56
56
|
|
|
57
57
|
<Divider />
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</Typography>
|
|
81
|
-
<Typography
|
|
82
|
-
variant="subtitle2"
|
|
83
|
-
color="text.secondary"
|
|
84
|
-
sx={ {
|
|
85
|
-
display: 'flex',
|
|
86
|
-
width: '100%',
|
|
87
|
-
justifyContent: 'center',
|
|
88
|
-
} }
|
|
89
|
-
>
|
|
90
|
-
<span>“</span>
|
|
91
|
-
<span style={ { maxWidth: '80%', overflow: 'hidden', textOverflow: 'ellipsis' } }>
|
|
92
|
-
{ searchValue }
|
|
93
|
-
</span>
|
|
94
|
-
<span>”.</span>
|
|
95
|
-
</Typography>
|
|
96
|
-
</Box>
|
|
59
|
+
{ filteredFontFamilies.length > 0 ? (
|
|
60
|
+
<FontList
|
|
61
|
+
fontListItems={ filteredFontFamilies }
|
|
62
|
+
setFontFamily={ onFontFamilyChange }
|
|
63
|
+
handleClose={ handleClose }
|
|
64
|
+
fontFamily={ fontFamily }
|
|
65
|
+
/>
|
|
66
|
+
) : (
|
|
67
|
+
<Stack
|
|
68
|
+
alignItems="center"
|
|
69
|
+
justifyContent="center"
|
|
70
|
+
height="100%"
|
|
71
|
+
p={ 2.5 }
|
|
72
|
+
gap={ 1.5 }
|
|
73
|
+
overflow={ 'hidden' }
|
|
74
|
+
>
|
|
75
|
+
<TextIcon fontSize="large" />
|
|
76
|
+
<Box sx={ { maxWidth: 160, overflow: 'hidden' } }>
|
|
77
|
+
<Typography align="center" variant="subtitle2" color="text.secondary">
|
|
78
|
+
{ __( 'Sorry, nothing matched', 'elementor' ) }
|
|
79
|
+
</Typography>
|
|
97
80
|
<Typography
|
|
98
|
-
|
|
99
|
-
variant="caption"
|
|
81
|
+
variant="subtitle2"
|
|
100
82
|
color="text.secondary"
|
|
101
|
-
sx={ {
|
|
83
|
+
sx={ {
|
|
84
|
+
display: 'flex',
|
|
85
|
+
width: '100%',
|
|
86
|
+
justifyContent: 'center',
|
|
87
|
+
} }
|
|
102
88
|
>
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
onClick={ () => setSearchValue( '' ) }
|
|
109
|
-
>
|
|
110
|
-
{ __( 'Clear & try again', 'elementor' ) }
|
|
111
|
-
</Link>
|
|
89
|
+
<span>“</span>
|
|
90
|
+
<span style={ { maxWidth: '80%', overflow: 'hidden', textOverflow: 'ellipsis' } }>
|
|
91
|
+
{ searchValue }
|
|
92
|
+
</span>
|
|
93
|
+
<span>”.</span>
|
|
112
94
|
</Typography>
|
|
113
|
-
</
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
95
|
+
</Box>
|
|
96
|
+
<Typography
|
|
97
|
+
align="center"
|
|
98
|
+
variant="caption"
|
|
99
|
+
color="text.secondary"
|
|
100
|
+
sx={ { display: 'flex', flexDirection: 'column' } }
|
|
101
|
+
>
|
|
102
|
+
{ __( 'Try something else.', 'elementor' ) }
|
|
103
|
+
<Link
|
|
104
|
+
color="secondary"
|
|
105
|
+
variant="caption"
|
|
106
|
+
component="button"
|
|
107
|
+
onClick={ () => setSearchValue( '' ) }
|
|
108
|
+
>
|
|
109
|
+
{ __( 'Clear & try again', 'elementor' ) }
|
|
110
|
+
</Link>
|
|
111
|
+
</Typography>
|
|
112
|
+
</Stack>
|
|
113
|
+
) }
|
|
114
|
+
</PopoverBody>
|
|
117
115
|
);
|
|
118
116
|
};
|
|
119
117
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import { type PropKey } from '@elementor/editor-props';
|
|
3
|
+
import { type PropKey, type PropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { CopyIcon, EyeIcon, EyeOffIcon, PlusIcon, XIcon } from '@elementor/icons';
|
|
5
5
|
import {
|
|
6
6
|
bindPopover,
|
|
@@ -30,6 +30,16 @@ type AnchorEl = HTMLElement | null;
|
|
|
30
30
|
type Item< T > = {
|
|
31
31
|
disabled?: boolean;
|
|
32
32
|
} & T;
|
|
33
|
+
export type CollectionPropUtil< T > = PropTypeUtil< PropKey, T[] >;
|
|
34
|
+
|
|
35
|
+
type RepeaterItemContentProps< T > = {
|
|
36
|
+
anchorEl: AnchorEl;
|
|
37
|
+
bind: PropKey;
|
|
38
|
+
value: T;
|
|
39
|
+
collectionPropUtil?: CollectionPropUtil< T >;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type RepeaterItemContent< T > = React.ComponentType< RepeaterItemContentProps< T > >;
|
|
33
43
|
|
|
34
44
|
type RepeaterProps< T > = {
|
|
35
45
|
label: string;
|
|
@@ -42,15 +52,12 @@ type RepeaterProps< T > = {
|
|
|
42
52
|
initialValues: T;
|
|
43
53
|
Label: React.ComponentType< { value: T } >;
|
|
44
54
|
Icon: React.ComponentType< { value: T } >;
|
|
45
|
-
Content:
|
|
46
|
-
anchorEl: AnchorEl;
|
|
47
|
-
bind: PropKey;
|
|
48
|
-
value: T;
|
|
49
|
-
} >;
|
|
55
|
+
Content: RepeaterItemContent< T >;
|
|
50
56
|
};
|
|
51
57
|
showDuplicate?: boolean;
|
|
52
58
|
showToggle?: boolean;
|
|
53
59
|
isSortable?: boolean;
|
|
60
|
+
collectionPropUtil?: CollectionPropUtil< T >;
|
|
54
61
|
};
|
|
55
62
|
|
|
56
63
|
const EMPTY_OPEN_ITEM = -1;
|
|
@@ -66,6 +73,7 @@ export const Repeater = < T, >( {
|
|
|
66
73
|
showDuplicate = true,
|
|
67
74
|
showToggle = true,
|
|
68
75
|
isSortable = true,
|
|
76
|
+
collectionPropUtil,
|
|
69
77
|
}: RepeaterProps< Item< T > > ) => {
|
|
70
78
|
const [ openItem, setOpenItem ] = useState( EMPTY_OPEN_ITEM );
|
|
71
79
|
|
|
@@ -203,6 +211,7 @@ export const Repeater = < T, >( {
|
|
|
203
211
|
onOpen={ () => setOpenItem( EMPTY_OPEN_ITEM ) }
|
|
204
212
|
showDuplicate={ showDuplicate }
|
|
205
213
|
showToggle={ showToggle }
|
|
214
|
+
collectionPropUtil={ collectionPropUtil }
|
|
206
215
|
>
|
|
207
216
|
{ ( props ) => (
|
|
208
217
|
<itemSettings.Content { ...props } value={ value } bind={ String( index ) } />
|
|
@@ -217,22 +226,23 @@ export const Repeater = < T, >( {
|
|
|
217
226
|
);
|
|
218
227
|
};
|
|
219
228
|
|
|
220
|
-
type RepeaterItemProps = {
|
|
229
|
+
type RepeaterItemProps< T > = {
|
|
221
230
|
label: React.ReactNode;
|
|
222
231
|
propDisabled?: boolean;
|
|
223
232
|
startIcon: UnstableTagProps[ 'startIcon' ];
|
|
224
233
|
removeItem: () => void;
|
|
225
234
|
duplicateItem: () => void;
|
|
226
235
|
toggleDisableItem: () => void;
|
|
227
|
-
children: (
|
|
236
|
+
children: ( props: Pick< RepeaterItemContentProps< T >, 'anchorEl' | 'collectionPropUtil' > ) => React.ReactNode;
|
|
228
237
|
openOnMount: boolean;
|
|
229
238
|
onOpen: () => void;
|
|
230
239
|
showDuplicate: boolean;
|
|
231
240
|
showToggle: boolean;
|
|
232
241
|
disabled?: boolean;
|
|
242
|
+
collectionPropUtil?: CollectionPropUtil< T >;
|
|
233
243
|
};
|
|
234
244
|
|
|
235
|
-
const RepeaterItem = ( {
|
|
245
|
+
const RepeaterItem = < T, >( {
|
|
236
246
|
label,
|
|
237
247
|
propDisabled,
|
|
238
248
|
startIcon,
|
|
@@ -245,7 +255,8 @@ const RepeaterItem = ( {
|
|
|
245
255
|
showDuplicate,
|
|
246
256
|
showToggle,
|
|
247
257
|
disabled,
|
|
248
|
-
|
|
258
|
+
collectionPropUtil,
|
|
259
|
+
}: RepeaterItemProps< T > ) => {
|
|
249
260
|
const [ anchorEl, setAnchorEl ] = useState< AnchorEl >( null );
|
|
250
261
|
const { popoverState, popoverProps, ref, setRef } = usePopover( openOnMount, onOpen );
|
|
251
262
|
|
|
@@ -301,7 +312,7 @@ const RepeaterItem = ( {
|
|
|
301
312
|
{ ...popoverProps }
|
|
302
313
|
anchorEl={ ref }
|
|
303
314
|
>
|
|
304
|
-
<Box>{ children( { anchorEl } ) }</Box>
|
|
315
|
+
<Box>{ children( { anchorEl, collectionPropUtil } ) }</Box>
|
|
305
316
|
</Popover>
|
|
306
317
|
</>
|
|
307
318
|
);
|
|
@@ -4,19 +4,19 @@ import { PencilIcon } from '@elementor/icons';
|
|
|
4
4
|
import { Box, InputAdornment, type PopupState } from '@elementor/ui';
|
|
5
5
|
|
|
6
6
|
import ControlActions from '../../control-actions/control-actions';
|
|
7
|
-
import { type ExtendedOption, isUnitExtendedOption, type Unit } from '../../utils/size-control';
|
|
7
|
+
import { type DegreeUnit, type ExtendedOption, isUnitExtendedOption, type Unit } from '../../utils/size-control';
|
|
8
8
|
import { SelectionEndAdornment, TextFieldInnerSelection } from '../size-control/text-field-inner-selection';
|
|
9
9
|
|
|
10
10
|
type SizeInputProps = {
|
|
11
|
-
unit: Unit | ExtendedOption;
|
|
11
|
+
unit: Unit | DegreeUnit | ExtendedOption;
|
|
12
12
|
size: number | string;
|
|
13
13
|
placeholder?: string;
|
|
14
14
|
startIcon?: React.ReactNode;
|
|
15
|
-
units: ( Unit | ExtendedOption )[];
|
|
15
|
+
units: ( Unit | DegreeUnit | ExtendedOption )[];
|
|
16
16
|
onBlur?: ( event: React.FocusEvent< HTMLInputElement > ) => void;
|
|
17
17
|
onFocus?: ( event: React.FocusEvent< HTMLInputElement > ) => void;
|
|
18
18
|
onClick?: ( event: React.MouseEvent< HTMLInputElement > ) => void;
|
|
19
|
-
handleUnitChange: ( unit: Unit | ExtendedOption ) => void;
|
|
19
|
+
handleUnitChange: ( unit: Unit | DegreeUnit | ExtendedOption ) => void;
|
|
20
20
|
handleSizeChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
|
|
21
21
|
popupState: PopupState;
|
|
22
22
|
disabled?: boolean;
|
|
@@ -13,7 +13,9 @@ type Props = Partial< Omit< UnstableColorFieldProps, 'value' | 'onChange' > > &
|
|
|
13
13
|
|
|
14
14
|
export const ColorControl = createControl(
|
|
15
15
|
( { propTypeUtil = colorPropTypeUtil, anchorEl, slotProps = {}, ...props }: Props ) => {
|
|
16
|
-
const { value, setValue, disabled } = useBoundProp( propTypeUtil );
|
|
16
|
+
const { value, setValue, placeholder: boundPropPlaceholder, disabled } = useBoundProp( propTypeUtil );
|
|
17
|
+
|
|
18
|
+
const placeholder = props.placeholder ?? boundPropPlaceholder;
|
|
17
19
|
|
|
18
20
|
const handleChange = ( selectedColor: string ) => {
|
|
19
21
|
setValue( selectedColor || null );
|
|
@@ -25,6 +27,7 @@ export const ColorControl = createControl(
|
|
|
25
27
|
size="tiny"
|
|
26
28
|
fullWidth
|
|
27
29
|
value={ value ?? '' }
|
|
30
|
+
placeholder={ placeholder ?? '' }
|
|
28
31
|
onChange={ handleChange }
|
|
29
32
|
{ ...props }
|
|
30
33
|
disabled={ disabled }
|
|
@@ -40,6 +43,14 @@ export const ColorControl = createControl(
|
|
|
40
43
|
vertical: 'top',
|
|
41
44
|
horizontal: -10,
|
|
42
45
|
},
|
|
46
|
+
slotProps: {
|
|
47
|
+
colorIndicator: {
|
|
48
|
+
value: value ?? placeholder ?? '',
|
|
49
|
+
},
|
|
50
|
+
colorBox: {
|
|
51
|
+
value: value ?? placeholder ?? '',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
43
54
|
},
|
|
44
55
|
} }
|
|
45
56
|
/>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { type DropShadowFilterPropValue, type PropTypeUtil } from '@elementor/editor-props';
|
|
4
|
+
import { Grid } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
|
|
8
|
+
import { ControlFormLabel } from '../../components/control-form-label';
|
|
9
|
+
import { PopoverGridContainer } from '../../components/popover-grid-container';
|
|
10
|
+
import { type Unit } from '../../utils/size-control';
|
|
11
|
+
import { ColorControl } from '../color-control';
|
|
12
|
+
import { SizeControl } from '../size-control';
|
|
13
|
+
|
|
14
|
+
const items = [
|
|
15
|
+
{
|
|
16
|
+
bind: 'xAxis',
|
|
17
|
+
label: __( 'X-axis', 'elementor' ),
|
|
18
|
+
rowIndex: 0,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
bind: 'yAxis',
|
|
22
|
+
label: __( 'Y-axis', 'elementor' ),
|
|
23
|
+
rowIndex: 0,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
bind: 'blur',
|
|
27
|
+
label: __( 'Blur', 'elementor' ),
|
|
28
|
+
rowIndex: 1,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
bind: 'color',
|
|
32
|
+
label: __( 'Color', 'elementor' ),
|
|
33
|
+
rowIndex: 1,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export const DropShadowItemContent = ( {
|
|
38
|
+
propType,
|
|
39
|
+
units,
|
|
40
|
+
anchorEl,
|
|
41
|
+
}: {
|
|
42
|
+
propType: PropTypeUtil< 'drop-shadow', DropShadowFilterPropValue[ 'value' ] >;
|
|
43
|
+
units: Unit[];
|
|
44
|
+
anchorEl?: HTMLElement | null;
|
|
45
|
+
} ) => {
|
|
46
|
+
const context = useBoundProp( propType );
|
|
47
|
+
const rowRefs = [ useRef< HTMLDivElement >( null ), useRef< HTMLDivElement >( null ) ];
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<PropProvider { ...context }>
|
|
51
|
+
{ items.map( ( item ) => (
|
|
52
|
+
<PopoverGridContainer key={ item.bind } ref={ rowRefs[ item.rowIndex ] ?? null }>
|
|
53
|
+
<PropKeyProvider bind={ item.bind }>
|
|
54
|
+
<Grid item xs={ 6 }>
|
|
55
|
+
<ControlFormLabel>{ item.label }</ControlFormLabel>
|
|
56
|
+
</Grid>
|
|
57
|
+
<Grid item xs={ 6 }>
|
|
58
|
+
{ item.bind === 'color' ? (
|
|
59
|
+
<ColorControl anchorEl={ anchorEl } />
|
|
60
|
+
) : (
|
|
61
|
+
<SizeControl anchorRef={ rowRefs[ item.rowIndex ] } units={ units } defaultUnit="px" />
|
|
62
|
+
) }
|
|
63
|
+
</Grid>
|
|
64
|
+
</PropKeyProvider>
|
|
65
|
+
</PopoverGridContainer>
|
|
66
|
+
) ) }
|
|
67
|
+
</PropProvider>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type FilterItemPropValue } from '@elementor/editor-props';
|
|
3
|
+
import { Box } from '@elementor/ui';
|
|
4
|
+
|
|
5
|
+
export const DropShadowItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
|
|
6
|
+
const { xAxis, yAxis, blur } = value.value;
|
|
7
|
+
|
|
8
|
+
const xValue = `${ xAxis?.value?.size ?? 0 }${ xAxis?.value?.unit ?? 'px' }`;
|
|
9
|
+
const yValue = `${ yAxis?.value?.size ?? 0 }${ yAxis?.value?.unit ?? 'px' }`;
|
|
10
|
+
const blurValue = `${ blur?.value?.size ?? 10 }${ blur?.value?.unit ?? 'px' }`;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Box component="span">
|
|
14
|
+
<Box component="span" style={ { textTransform: 'capitalize' } }>
|
|
15
|
+
Drop shadow:
|
|
16
|
+
</Box>
|
|
17
|
+
{ `${ xValue } ${ yValue } ${ blurValue }` }
|
|
18
|
+
</Box>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -3,12 +3,20 @@ import { useRef } from 'react';
|
|
|
3
3
|
import {
|
|
4
4
|
blurFilterPropTypeUtil,
|
|
5
5
|
brightnessFilterPropTypeUtil,
|
|
6
|
+
contrastFilterPropTypeUtil,
|
|
7
|
+
dropShadowFilterPropTypeUtil,
|
|
6
8
|
type FilterItemPropValue,
|
|
7
9
|
filterPropTypeUtil,
|
|
10
|
+
grayscaleFilterPropTypeUtil,
|
|
11
|
+
hueRotateFilterPropTypeUtil,
|
|
12
|
+
invertFilterPropTypeUtil,
|
|
8
13
|
type PropKey,
|
|
9
14
|
type PropTypeUtil,
|
|
15
|
+
saturateFilterPropTypeUtil,
|
|
16
|
+
sepiaFilterPropTypeUtil,
|
|
10
17
|
type SizePropValue,
|
|
11
18
|
} from '@elementor/editor-props';
|
|
19
|
+
import { backdropFilterPropTypeUtil } from '@elementor/editor-props';
|
|
12
20
|
import { MenuListItem } from '@elementor/editor-ui';
|
|
13
21
|
import { Box, Grid, Select, type SelectChangeEvent } from '@elementor/ui';
|
|
14
22
|
import { __ } from '@wordpress/i18n';
|
|
@@ -17,9 +25,11 @@ import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-conte
|
|
|
17
25
|
import { ControlLabel } from '../components/control-label';
|
|
18
26
|
import { PopoverContent } from '../components/popover-content';
|
|
19
27
|
import { PopoverGridContainer } from '../components/popover-grid-container';
|
|
20
|
-
import { Repeater } from '../components/repeater';
|
|
28
|
+
import { type CollectionPropUtil, Repeater } from '../components/repeater';
|
|
21
29
|
import { createControl } from '../create-control';
|
|
22
|
-
import { defaultUnits } from '../utils/size-control';
|
|
30
|
+
import { defaultUnits, type Unit } from '../utils/size-control';
|
|
31
|
+
import { DropShadowItemContent } from './filter-control/drop-shadow-item-content';
|
|
32
|
+
import { DropShadowItemLabel } from './filter-control/drop-shadow-item-label';
|
|
23
33
|
import { SizeControl } from './size-control';
|
|
24
34
|
|
|
25
35
|
type FilterType = FilterItemPropValue[ '$$type' ];
|
|
@@ -43,6 +53,21 @@ const filterConfig: Record< FilterType, FilterItemConfig > = {
|
|
|
43
53
|
propType: blurFilterPropTypeUtil,
|
|
44
54
|
units: defaultUnits.filter( ( unit ) => unit !== '%' ),
|
|
45
55
|
},
|
|
56
|
+
'drop-shadow': {
|
|
57
|
+
defaultValue: {
|
|
58
|
+
$$type: 'drop-shadow',
|
|
59
|
+
value: {
|
|
60
|
+
xAxis: { $$type: 'size', value: { size: 0, unit: 'px' } },
|
|
61
|
+
yAxis: { $$type: 'size', value: { size: 0, unit: 'px' } },
|
|
62
|
+
blur: { $$type: 'size', value: { size: 10, unit: 'px' } },
|
|
63
|
+
color: { $$type: 'color', value: 'rgba(0, 0, 0, 1)' },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
name: __( 'Drop shadow', 'elementor' ),
|
|
67
|
+
valueName: __( 'Drop-shadow', 'elementor' ),
|
|
68
|
+
propType: dropShadowFilterPropTypeUtil,
|
|
69
|
+
units: defaultUnits.filter( ( unit ) => unit !== '%' ),
|
|
70
|
+
},
|
|
46
71
|
brightness: {
|
|
47
72
|
defaultValue: { $$type: 'amount', amount: { $$type: 'size', value: { size: 100, unit: '%' } } },
|
|
48
73
|
name: __( 'Brightness', 'elementor' ),
|
|
@@ -50,18 +75,62 @@ const filterConfig: Record< FilterType, FilterItemConfig > = {
|
|
|
50
75
|
propType: brightnessFilterPropTypeUtil,
|
|
51
76
|
units: [ '%' ],
|
|
52
77
|
},
|
|
78
|
+
contrast: {
|
|
79
|
+
defaultValue: { $$type: 'contrast', contrast: { $$type: 'size', value: { size: 100, unit: '%' } } },
|
|
80
|
+
name: __( 'Contrast', 'elementor' ),
|
|
81
|
+
valueName: __( 'Amount', 'elementor' ),
|
|
82
|
+
propType: contrastFilterPropTypeUtil,
|
|
83
|
+
units: [ '%' ],
|
|
84
|
+
},
|
|
85
|
+
'hue-rotate': {
|
|
86
|
+
defaultValue: { $$type: 'hue-rotate', 'hue-rotate': { $$type: 'size', value: { size: 0, unit: 'deg' } } },
|
|
87
|
+
name: __( 'Hue Rotate', 'elementor' ),
|
|
88
|
+
valueName: __( 'Angle', 'elementor' ),
|
|
89
|
+
propType: hueRotateFilterPropTypeUtil,
|
|
90
|
+
units: [ 'deg', 'rad', 'grad', 'turn' ],
|
|
91
|
+
},
|
|
92
|
+
saturate: {
|
|
93
|
+
defaultValue: { $$type: 'saturate', saturate: { $$type: 'size', value: { size: 100, unit: '%' } } },
|
|
94
|
+
name: __( 'Saturate', 'elementor' ),
|
|
95
|
+
valueName: __( 'Amount', 'elementor' ),
|
|
96
|
+
propType: saturateFilterPropTypeUtil,
|
|
97
|
+
units: [ '%' ],
|
|
98
|
+
},
|
|
99
|
+
grayscale: {
|
|
100
|
+
defaultValue: { $$type: 'grayscale', grayscale: { $$type: 'size', value: { size: 0, unit: '%' } } },
|
|
101
|
+
name: __( 'Grayscale', 'elementor' ),
|
|
102
|
+
valueName: __( 'Amount', 'elementor' ),
|
|
103
|
+
propType: grayscaleFilterPropTypeUtil,
|
|
104
|
+
units: [ '%' ],
|
|
105
|
+
},
|
|
106
|
+
invert: {
|
|
107
|
+
defaultValue: { $$type: 'invert', invert: { $$type: 'size', value: { size: 0, unit: '%' } } },
|
|
108
|
+
name: __( 'Invert', 'elementor' ),
|
|
109
|
+
valueName: __( 'Amount', 'elementor' ),
|
|
110
|
+
propType: invertFilterPropTypeUtil,
|
|
111
|
+
units: [ '%' ],
|
|
112
|
+
},
|
|
113
|
+
sepia: {
|
|
114
|
+
defaultValue: { $$type: 'sepia', sepia: { $$type: 'size', value: { size: 0, unit: '%' } } },
|
|
115
|
+
name: __( 'Sepia', 'elementor' ),
|
|
116
|
+
valueName: __( 'Amount', 'elementor' ),
|
|
117
|
+
propType: sepiaFilterPropTypeUtil,
|
|
118
|
+
units: [ '%' ],
|
|
119
|
+
},
|
|
53
120
|
};
|
|
54
121
|
|
|
55
122
|
const filterKeys = Object.keys( filterConfig ) as FilterType[];
|
|
56
123
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return filter[ filter.$$type ].$$type === 'size';
|
|
61
|
-
} ) as FilterType[];
|
|
124
|
+
const isSingleSize = ( key: FilterType ): boolean => {
|
|
125
|
+
return ! [ 'drop-shadow' ].includes( key );
|
|
126
|
+
};
|
|
62
127
|
|
|
63
|
-
export const FilterRepeaterControl = createControl( () => {
|
|
64
|
-
const
|
|
128
|
+
export const FilterRepeaterControl = createControl( ( { filterPropName = 'filter' }: { filterPropName?: string } ) => {
|
|
129
|
+
const [ propUtil, label ] =
|
|
130
|
+
filterPropName === 'backdrop-filter'
|
|
131
|
+
? [ backdropFilterPropTypeUtil, __( 'Backdrop Filters', 'elementor' ) ]
|
|
132
|
+
: [ filterPropTypeUtil, __( 'Filters', 'elementor' ) ];
|
|
133
|
+
const { propType, value: filterValues, setValue, disabled } = useBoundProp( propUtil );
|
|
65
134
|
|
|
66
135
|
return (
|
|
67
136
|
<PropProvider propType={ propType } value={ filterValues } setValue={ setValue }>
|
|
@@ -70,7 +139,8 @@ export const FilterRepeaterControl = createControl( () => {
|
|
|
70
139
|
disabled={ disabled }
|
|
71
140
|
values={ filterValues ?? [] }
|
|
72
141
|
setValues={ setValue }
|
|
73
|
-
label={
|
|
142
|
+
label={ label }
|
|
143
|
+
collectionPropUtil={ propUtil }
|
|
74
144
|
itemSettings={ {
|
|
75
145
|
Icon: ItemIcon,
|
|
76
146
|
Label: ItemLabel,
|
|
@@ -87,10 +157,12 @@ export const FilterRepeaterControl = createControl( () => {
|
|
|
87
157
|
|
|
88
158
|
const ItemIcon = () => <></>;
|
|
89
159
|
|
|
90
|
-
const ItemLabel = (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
160
|
+
const ItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
|
|
161
|
+
return isSingleSize( value.$$type ) ? (
|
|
162
|
+
<SingleSizeItemLabel value={ value } />
|
|
163
|
+
) : (
|
|
164
|
+
<DropShadowItemLabel value={ value } />
|
|
165
|
+
);
|
|
94
166
|
};
|
|
95
167
|
|
|
96
168
|
const SingleSizeItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
|
|
@@ -113,8 +185,16 @@ const SingleSizeItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
|
|
|
113
185
|
);
|
|
114
186
|
};
|
|
115
187
|
|
|
116
|
-
const ItemContent = ( {
|
|
117
|
-
|
|
188
|
+
const ItemContent = ( {
|
|
189
|
+
bind,
|
|
190
|
+
collectionPropUtil,
|
|
191
|
+
anchorEl,
|
|
192
|
+
}: {
|
|
193
|
+
bind: PropKey;
|
|
194
|
+
collectionPropUtil?: CollectionPropUtil< FilterItemPropValue >;
|
|
195
|
+
anchorEl?: HTMLElement | null;
|
|
196
|
+
} ) => {
|
|
197
|
+
const { value: filterValues, setValue } = useBoundProp( collectionPropUtil ?? filterPropTypeUtil );
|
|
118
198
|
const itemIndex = parseInt( bind, 10 );
|
|
119
199
|
const item = filterValues?.[ itemIndex ];
|
|
120
200
|
|
|
@@ -124,7 +204,7 @@ const ItemContent = ( { bind }: { bind: PropKey } ) => {
|
|
|
124
204
|
|
|
125
205
|
newFilterValues[ itemIndex ] = {
|
|
126
206
|
$$type: filterType,
|
|
127
|
-
value: filterConfig[ filterType ].defaultValue,
|
|
207
|
+
value: { ...filterConfig[ filterType ].defaultValue },
|
|
128
208
|
} as FilterItemPropValue;
|
|
129
209
|
|
|
130
210
|
setValue( newFilterValues );
|
|
@@ -153,14 +233,20 @@ const ItemContent = ( { bind }: { bind: PropKey } ) => {
|
|
|
153
233
|
</Select>
|
|
154
234
|
</Grid>
|
|
155
235
|
</PopoverGridContainer>
|
|
156
|
-
<Content filterType={ item?.$$type } />
|
|
236
|
+
<Content filterType={ item?.$$type } anchorEl={ anchorEl } />
|
|
157
237
|
</PopoverContent>
|
|
158
238
|
</PropKeyProvider>
|
|
159
239
|
);
|
|
160
240
|
};
|
|
161
241
|
|
|
162
|
-
const Content = ( { filterType }: { filterType: FilterType } ) => {
|
|
163
|
-
|
|
242
|
+
const Content = ( { filterType, anchorEl }: { filterType: FilterType; anchorEl?: HTMLElement | null } ) => {
|
|
243
|
+
const { propType, units = [] } = filterConfig[ filterType ];
|
|
244
|
+
|
|
245
|
+
return isSingleSize( filterType ) ? (
|
|
246
|
+
<SingleSizeItemContent filterType={ filterType } />
|
|
247
|
+
) : (
|
|
248
|
+
<DropShadowItemContent propType={ propType } units={ units as Unit[] } anchorEl={ anchorEl } />
|
|
249
|
+
);
|
|
164
250
|
};
|
|
165
251
|
|
|
166
252
|
const SingleSizeItemContent = ( { filterType }: { filterType: FilterType } ) => {
|
|
@@ -168,6 +254,7 @@ const SingleSizeItemContent = ( { filterType }: { filterType: FilterType } ) =>
|
|
|
168
254
|
const { $$type } = defaultValue;
|
|
169
255
|
const context = useBoundProp( propType );
|
|
170
256
|
const rowRef = useRef< HTMLDivElement >( null );
|
|
257
|
+
const defaultUnit = defaultValue[ $$type ].value.unit;
|
|
171
258
|
|
|
172
259
|
return (
|
|
173
260
|
<PropProvider { ...context }>
|
|
@@ -177,7 +264,7 @@ const SingleSizeItemContent = ( { filterType }: { filterType: FilterType } ) =>
|
|
|
177
264
|
<ControlLabel>{ valueName }</ControlLabel>
|
|
178
265
|
</Grid>
|
|
179
266
|
<Grid item xs={ 6 }>
|
|
180
|
-
<SizeControl anchorRef={ rowRef } units={ units } />
|
|
267
|
+
<SizeControl anchorRef={ rowRef } units={ units } defaultUnit={ defaultUnit } />
|
|
181
268
|
</Grid>
|
|
182
269
|
</PopoverGridContainer>
|
|
183
270
|
</PropKeyProvider>
|