@elementor/editor-controls 0.34.2 → 0.36.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 +21 -0
- package/dist/index.d.mts +11 -5
- package/dist/index.d.ts +11 -5
- package/dist/index.js +363 -312
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +316 -272
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/control-form-label.tsx +3 -3
- package/src/components/control-label.tsx +1 -1
- package/src/components/font-family-selector.tsx +282 -0
- package/src/components/repeater.tsx +2 -4
- package/src/components/sortable.tsx +4 -2
- package/src/controls/aspect-ratio-control.tsx +51 -48
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +3 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-size.tsx +2 -1
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +1 -1
- package/src/controls/box-shadow-repeater-control.tsx +3 -3
- package/src/controls/equal-unequal-sizes-control.tsx +14 -4
- package/src/controls/font-family-control/font-family-control.tsx +12 -273
- package/src/controls/gap-control.tsx +3 -1
- package/src/controls/image-control.tsx +2 -2
- package/src/controls/link-control.tsx +1 -1
- package/src/controls/linked-dimensions-control.tsx +11 -4
- package/src/index.ts +1 -0
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.
|
|
4
|
+
"version": "0.36.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@elementor/editor-current-user": "0.5.0",
|
|
44
44
|
"@elementor/editor-elements": "0.8.4",
|
|
45
45
|
"@elementor/editor-props": "0.12.1",
|
|
46
|
-
"@elementor/editor-ui": "0.
|
|
46
|
+
"@elementor/editor-ui": "0.11.0",
|
|
47
47
|
"@elementor/editor-v1-adapters": "0.12.0",
|
|
48
48
|
"@elementor/env": "0.3.5",
|
|
49
49
|
"@elementor/http-client": "0.3.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { FormLabel } from '@elementor/ui';
|
|
2
|
+
import { FormLabel, type FormLabelProps } from '@elementor/ui';
|
|
3
3
|
|
|
4
|
-
export const ControlFormLabel = (
|
|
5
|
-
return <FormLabel size="tiny"
|
|
4
|
+
export const ControlFormLabel = ( props: FormLabelProps ) => {
|
|
5
|
+
return <FormLabel size="tiny" { ...props } />;
|
|
6
6
|
};
|
|
@@ -7,7 +7,7 @@ import { ControlFormLabel } from './control-form-label';
|
|
|
7
7
|
|
|
8
8
|
export const ControlLabel = ( { children }: PropsWithChildren< object > ) => {
|
|
9
9
|
return (
|
|
10
|
-
<Stack direction="row" alignItems="center" justifyItems="start" gap={
|
|
10
|
+
<Stack direction="row" alignItems="center" justifyItems="start" gap={ 0.25 }>
|
|
11
11
|
<ControlFormLabel>{ children }</ControlFormLabel>
|
|
12
12
|
<ControlAdornments />
|
|
13
13
|
</Stack>
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { PopoverHeader } from '@elementor/editor-ui';
|
|
4
|
+
import { SearchIcon, TextIcon } from '@elementor/icons';
|
|
5
|
+
import {
|
|
6
|
+
Box,
|
|
7
|
+
Divider,
|
|
8
|
+
InputAdornment,
|
|
9
|
+
Link,
|
|
10
|
+
MenuList,
|
|
11
|
+
MenuSubheader,
|
|
12
|
+
Stack,
|
|
13
|
+
styled,
|
|
14
|
+
TextField,
|
|
15
|
+
Typography,
|
|
16
|
+
} from '@elementor/ui';
|
|
17
|
+
import { debounce } from '@elementor/utils';
|
|
18
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
19
|
+
import { __ } from '@wordpress/i18n';
|
|
20
|
+
|
|
21
|
+
import { enqueueFont } from '../controls/font-family-control/enqueue-font';
|
|
22
|
+
import { type FontCategory } from '../controls/font-family-control/font-family-control';
|
|
23
|
+
import { type FontListItem, useFilteredFontFamilies } from '../hooks/use-filtered-font-families';
|
|
24
|
+
|
|
25
|
+
const SIZE = 'tiny';
|
|
26
|
+
|
|
27
|
+
type FontFamilySelectorProps = {
|
|
28
|
+
fontFamilies: FontCategory[];
|
|
29
|
+
fontFamily: string | null;
|
|
30
|
+
onFontFamilyChange: ( fontFamily: string ) => void;
|
|
31
|
+
onClose: () => void;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const FontFamilySelector = ( {
|
|
35
|
+
fontFamilies,
|
|
36
|
+
fontFamily,
|
|
37
|
+
onFontFamilyChange,
|
|
38
|
+
onClose,
|
|
39
|
+
}: FontFamilySelectorProps ) => {
|
|
40
|
+
const [ searchValue, setSearchValue ] = useState( '' );
|
|
41
|
+
|
|
42
|
+
const filteredFontFamilies = useFilteredFontFamilies( fontFamilies, searchValue );
|
|
43
|
+
|
|
44
|
+
const handleSearch = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
45
|
+
setSearchValue( event.target.value );
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleClose = () => {
|
|
49
|
+
setSearchValue( '' );
|
|
50
|
+
onClose();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Stack>
|
|
55
|
+
<PopoverHeader
|
|
56
|
+
title={ __( 'Font Family', 'elementor' ) }
|
|
57
|
+
onClose={ handleClose }
|
|
58
|
+
icon={ <TextIcon fontSize={ SIZE } /> }
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<Box px={ 1.5 } pb={ 1 }>
|
|
62
|
+
<TextField
|
|
63
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
64
|
+
autoFocus
|
|
65
|
+
fullWidth
|
|
66
|
+
size={ SIZE }
|
|
67
|
+
value={ searchValue }
|
|
68
|
+
placeholder={ __( 'Search', 'elementor' ) }
|
|
69
|
+
onChange={ handleSearch }
|
|
70
|
+
InputProps={ {
|
|
71
|
+
startAdornment: (
|
|
72
|
+
<InputAdornment position="start">
|
|
73
|
+
<SearchIcon fontSize={ SIZE } />
|
|
74
|
+
</InputAdornment>
|
|
75
|
+
),
|
|
76
|
+
} }
|
|
77
|
+
/>
|
|
78
|
+
</Box>
|
|
79
|
+
<Divider />
|
|
80
|
+
{ filteredFontFamilies.length > 0 ? (
|
|
81
|
+
<FontList
|
|
82
|
+
fontListItems={ filteredFontFamilies }
|
|
83
|
+
setFontFamily={ onFontFamilyChange }
|
|
84
|
+
handleClose={ handleClose }
|
|
85
|
+
fontFamily={ fontFamily }
|
|
86
|
+
/>
|
|
87
|
+
) : (
|
|
88
|
+
<Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
|
|
89
|
+
<Stack alignItems="center" p={ 2.5 } gap={ 1.5 } overflow={ 'hidden' }>
|
|
90
|
+
<TextIcon fontSize="large" />
|
|
91
|
+
<Box sx={ { maxWidth: 160, overflow: 'hidden' } }>
|
|
92
|
+
<Typography align="center" variant="subtitle2" color="text.secondary">
|
|
93
|
+
{ __( 'Sorry, nothing matched', 'elementor' ) }
|
|
94
|
+
</Typography>
|
|
95
|
+
<Typography
|
|
96
|
+
variant="subtitle2"
|
|
97
|
+
color="text.secondary"
|
|
98
|
+
sx={ {
|
|
99
|
+
display: 'flex',
|
|
100
|
+
width: '100%',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
} }
|
|
103
|
+
>
|
|
104
|
+
<span>“</span>
|
|
105
|
+
<span style={ { maxWidth: '80%', overflow: 'hidden', textOverflow: 'ellipsis' } }>
|
|
106
|
+
{ searchValue }
|
|
107
|
+
</span>
|
|
108
|
+
<span>”.</span>
|
|
109
|
+
</Typography>
|
|
110
|
+
</Box>
|
|
111
|
+
<Typography align="center" variant="caption" color="text.secondary">
|
|
112
|
+
{ __( 'Try something else.', 'elementor' ) }
|
|
113
|
+
<Link
|
|
114
|
+
color="secondary"
|
|
115
|
+
variant="caption"
|
|
116
|
+
component="button"
|
|
117
|
+
onClick={ () => setSearchValue( '' ) }
|
|
118
|
+
>
|
|
119
|
+
{ __( 'Clear & try again', 'elementor' ) }
|
|
120
|
+
</Link>
|
|
121
|
+
</Typography>
|
|
122
|
+
</Stack>
|
|
123
|
+
</Box>
|
|
124
|
+
) }
|
|
125
|
+
</Stack>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
type FontListProps = {
|
|
130
|
+
fontListItems: FontListItem[];
|
|
131
|
+
setFontFamily: ( fontFamily: string ) => void;
|
|
132
|
+
handleClose: () => void;
|
|
133
|
+
fontFamily: string | null;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const LIST_ITEM_HEIGHT = 36;
|
|
137
|
+
const LIST_ITEMS_BUFFER = 6;
|
|
138
|
+
|
|
139
|
+
const FontList = ( { fontListItems, setFontFamily, handleClose, fontFamily }: FontListProps ) => {
|
|
140
|
+
const containerRef = useRef< HTMLDivElement >( null );
|
|
141
|
+
const selectedItem = fontListItems.find( ( item ) => item.value === fontFamily );
|
|
142
|
+
|
|
143
|
+
const debouncedVirtualizeChange = useDebounce( ( { getVirtualIndexes }: { getVirtualIndexes: () => number[] } ) => {
|
|
144
|
+
getVirtualIndexes().forEach( ( index ) => {
|
|
145
|
+
const item = fontListItems[ index ];
|
|
146
|
+
if ( item && item.type === 'font' ) {
|
|
147
|
+
enqueueFont( item.value );
|
|
148
|
+
}
|
|
149
|
+
} );
|
|
150
|
+
}, 100 );
|
|
151
|
+
|
|
152
|
+
const virtualizer = useVirtualizer( {
|
|
153
|
+
count: fontListItems.length,
|
|
154
|
+
getScrollElement: () => containerRef.current,
|
|
155
|
+
estimateSize: () => LIST_ITEM_HEIGHT,
|
|
156
|
+
overscan: LIST_ITEMS_BUFFER,
|
|
157
|
+
onChange: debouncedVirtualizeChange,
|
|
158
|
+
} );
|
|
159
|
+
|
|
160
|
+
useEffect(
|
|
161
|
+
() => {
|
|
162
|
+
virtualizer.scrollToIndex( fontListItems.findIndex( ( item ) => item.value === fontFamily ) );
|
|
163
|
+
},
|
|
164
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
165
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
166
|
+
[ fontFamily ]
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<Box
|
|
171
|
+
ref={ containerRef }
|
|
172
|
+
sx={ {
|
|
173
|
+
overflowY: 'auto',
|
|
174
|
+
height: 260,
|
|
175
|
+
width: 220,
|
|
176
|
+
} }
|
|
177
|
+
>
|
|
178
|
+
<StyledMenuList
|
|
179
|
+
role="listbox"
|
|
180
|
+
style={ {
|
|
181
|
+
height: `${ virtualizer.getTotalSize() }px`,
|
|
182
|
+
} }
|
|
183
|
+
data-testid="font-list"
|
|
184
|
+
>
|
|
185
|
+
{ virtualizer.getVirtualItems().map( ( virtualRow ) => {
|
|
186
|
+
const item = fontListItems[ virtualRow.index ];
|
|
187
|
+
const isLast = virtualRow.index === fontListItems.length - 1;
|
|
188
|
+
// Ignore the first item, which is a category, and use the second item instead.
|
|
189
|
+
const isFirst = virtualRow.index === 1;
|
|
190
|
+
const isSelected = selectedItem?.value === item.value;
|
|
191
|
+
|
|
192
|
+
// If no item is selected, the first item should be focused.
|
|
193
|
+
const tabIndexFallback = ! selectedItem ? 0 : -1;
|
|
194
|
+
|
|
195
|
+
if ( item.type === 'category' ) {
|
|
196
|
+
return (
|
|
197
|
+
<MenuSubheader
|
|
198
|
+
key={ virtualRow.key }
|
|
199
|
+
style={ {
|
|
200
|
+
transform: `translateY(${ virtualRow.start }px)`,
|
|
201
|
+
} }
|
|
202
|
+
>
|
|
203
|
+
{ item.value }
|
|
204
|
+
</MenuSubheader>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<li
|
|
210
|
+
key={ virtualRow.key }
|
|
211
|
+
role="option"
|
|
212
|
+
aria-selected={ isSelected }
|
|
213
|
+
onClick={ () => {
|
|
214
|
+
setFontFamily( item.value );
|
|
215
|
+
handleClose();
|
|
216
|
+
} }
|
|
217
|
+
onKeyDown={ ( event ) => {
|
|
218
|
+
if ( event.key === 'Enter' ) {
|
|
219
|
+
setFontFamily( item.value );
|
|
220
|
+
handleClose();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if ( event.key === 'ArrowDown' && isLast ) {
|
|
224
|
+
event.preventDefault();
|
|
225
|
+
event.stopPropagation();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if ( event.key === 'ArrowUp' && isFirst ) {
|
|
229
|
+
event.preventDefault();
|
|
230
|
+
event.stopPropagation();
|
|
231
|
+
}
|
|
232
|
+
} }
|
|
233
|
+
tabIndex={ isSelected ? 0 : tabIndexFallback }
|
|
234
|
+
style={ {
|
|
235
|
+
transform: `translateY(${ virtualRow.start }px)`,
|
|
236
|
+
fontFamily: item.value,
|
|
237
|
+
} }
|
|
238
|
+
>
|
|
239
|
+
{ item.value }
|
|
240
|
+
</li>
|
|
241
|
+
);
|
|
242
|
+
} ) }
|
|
243
|
+
</StyledMenuList>
|
|
244
|
+
</Box>
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const StyledMenuList = styled( MenuList )( ( { theme } ) => ( {
|
|
249
|
+
'& > li': {
|
|
250
|
+
height: LIST_ITEM_HEIGHT,
|
|
251
|
+
position: 'absolute',
|
|
252
|
+
top: 0,
|
|
253
|
+
left: 0,
|
|
254
|
+
width: '100%',
|
|
255
|
+
display: 'flex',
|
|
256
|
+
alignItems: 'center',
|
|
257
|
+
},
|
|
258
|
+
'& > [role="option"]': {
|
|
259
|
+
...theme.typography.caption,
|
|
260
|
+
lineHeight: 'inherit',
|
|
261
|
+
padding: theme.spacing( 0.75, 2, 0.75, 4 ),
|
|
262
|
+
'&:hover, &:focus': {
|
|
263
|
+
backgroundColor: theme.palette.action.hover,
|
|
264
|
+
},
|
|
265
|
+
'&[aria-selected="true"]': {
|
|
266
|
+
backgroundColor: theme.palette.action.selected,
|
|
267
|
+
},
|
|
268
|
+
cursor: 'pointer',
|
|
269
|
+
textOverflow: 'ellipsis',
|
|
270
|
+
},
|
|
271
|
+
width: '100%',
|
|
272
|
+
position: 'relative',
|
|
273
|
+
} ) );
|
|
274
|
+
|
|
275
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
276
|
+
const useDebounce = < TArgs extends any[] >( fn: ( ...args: TArgs ) => void, delay: number ) => {
|
|
277
|
+
const [ debouncedFn ] = useState( () => debounce( fn, delay ) );
|
|
278
|
+
|
|
279
|
+
useEffect( () => () => debouncedFn.cancel(), [ debouncedFn ] );
|
|
280
|
+
|
|
281
|
+
return debouncedFn;
|
|
282
|
+
};
|
|
@@ -143,8 +143,6 @@ export const Repeater = < T, >( {
|
|
|
143
143
|
} );
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
-
const ItemWrapper = disabled ? React.Fragment : SortableItem;
|
|
147
|
-
|
|
148
146
|
return (
|
|
149
147
|
<SectionContent>
|
|
150
148
|
<Stack
|
|
@@ -178,7 +176,7 @@ export const Repeater = < T, >( {
|
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
return (
|
|
181
|
-
<
|
|
179
|
+
<SortableItem id={ key } key={ `sortable-${ key }` } disabled={ disabled }>
|
|
182
180
|
<RepeaterItem
|
|
183
181
|
disabled={ disabled }
|
|
184
182
|
propDisabled={ value?.disabled }
|
|
@@ -202,7 +200,7 @@ export const Repeater = < T, >( {
|
|
|
202
200
|
<itemSettings.Content { ...props } value={ value } bind={ String( index ) } />
|
|
203
201
|
) }
|
|
204
202
|
</RepeaterItem>
|
|
205
|
-
</
|
|
203
|
+
</SortableItem>
|
|
206
204
|
);
|
|
207
205
|
} ) }
|
|
208
206
|
</SortableProvider>
|
|
@@ -23,12 +23,14 @@ export const SortableProvider = < T extends number >( props: UnstableSortablePro
|
|
|
23
23
|
type SortableItemProps = {
|
|
24
24
|
id: UnstableSortableItemProps[ 'id' ];
|
|
25
25
|
children: React.ReactNode;
|
|
26
|
+
disabled?: boolean;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
export const SortableItem = ( { id, children }: SortableItemProps ): React.ReactNode => {
|
|
29
|
+
export const SortableItem = ( { id, children, disabled }: SortableItemProps ): React.ReactNode => {
|
|
29
30
|
return (
|
|
30
31
|
<UnstableSortableItem
|
|
31
32
|
id={ id }
|
|
33
|
+
disabled={ disabled }
|
|
32
34
|
render={ ( {
|
|
33
35
|
itemProps,
|
|
34
36
|
triggerProps,
|
|
@@ -39,7 +41,7 @@ export const SortableItem = ( { id, children }: SortableItemProps ): React.React
|
|
|
39
41
|
}: UnstableSortableItemRenderProps ) => {
|
|
40
42
|
return (
|
|
41
43
|
<StyledListItem { ...itemProps } style={ itemStyle }>
|
|
42
|
-
<SortableTrigger { ...triggerProps } style={ triggerStyle } />
|
|
44
|
+
{ ! disabled && <SortableTrigger { ...triggerProps } style={ triggerStyle } /> }
|
|
43
45
|
{ children }
|
|
44
46
|
{ showDropIndication && <StyledDivider style={ dropIndicationStyle } /> }
|
|
45
47
|
</StyledListItem>
|
|
@@ -8,6 +8,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
8
8
|
|
|
9
9
|
import { useBoundProp } from '../bound-prop-context';
|
|
10
10
|
import { ControlLabel } from '../components/control-label';
|
|
11
|
+
import ControlActions from '../control-actions/control-actions';
|
|
11
12
|
import { createControl } from '../create-control';
|
|
12
13
|
|
|
13
14
|
const RATIO_OPTIONS = [
|
|
@@ -69,61 +70,63 @@ export const AspectRatioControl = createControl( ( { label }: { label: string }
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
return (
|
|
72
|
-
<
|
|
73
|
-
<
|
|
74
|
-
<Grid item xs={ 6 }>
|
|
75
|
-
<ControlLabel>{ label }</ControlLabel>
|
|
76
|
-
</Grid>
|
|
77
|
-
<Grid item xs={ 6 }>
|
|
78
|
-
<Select
|
|
79
|
-
size="tiny"
|
|
80
|
-
displayEmpty
|
|
81
|
-
sx={ { overflow: 'hidden' } }
|
|
82
|
-
disabled={ disabled }
|
|
83
|
-
value={ selectedValue }
|
|
84
|
-
onChange={ handleSelectChange }
|
|
85
|
-
fullWidth
|
|
86
|
-
>
|
|
87
|
-
{ [ ...RATIO_OPTIONS, { label: __( 'Custom', 'elementor' ), value: CUSTOM_RATIO } ].map(
|
|
88
|
-
( { label: optionLabel, ...props } ) => (
|
|
89
|
-
<MenuListItem key={ props.value } { ...props } value={ props.value ?? '' }>
|
|
90
|
-
{ optionLabel }
|
|
91
|
-
</MenuListItem>
|
|
92
|
-
)
|
|
93
|
-
) }
|
|
94
|
-
</Select>
|
|
95
|
-
</Grid>
|
|
96
|
-
</Grid>
|
|
97
|
-
{ isCustom && (
|
|
73
|
+
<ControlActions>
|
|
74
|
+
<Stack direction="column" pt={ 2 } gap={ 2 }>
|
|
98
75
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
99
76
|
<Grid item xs={ 6 }>
|
|
100
|
-
<
|
|
101
|
-
size="tiny"
|
|
102
|
-
type="number"
|
|
103
|
-
fullWidth
|
|
104
|
-
disabled={ disabled }
|
|
105
|
-
value={ customWidth }
|
|
106
|
-
onChange={ handleCustomWidthChange }
|
|
107
|
-
InputProps={ {
|
|
108
|
-
startAdornment: <ArrowsMoveHorizontalIcon fontSize="tiny" />,
|
|
109
|
-
} }
|
|
110
|
-
/>
|
|
77
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
111
78
|
</Grid>
|
|
112
79
|
<Grid item xs={ 6 }>
|
|
113
|
-
<
|
|
80
|
+
<Select
|
|
114
81
|
size="tiny"
|
|
115
|
-
|
|
116
|
-
|
|
82
|
+
displayEmpty
|
|
83
|
+
sx={ { overflow: 'hidden' } }
|
|
117
84
|
disabled={ disabled }
|
|
118
|
-
value={
|
|
119
|
-
onChange={
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
85
|
+
value={ selectedValue }
|
|
86
|
+
onChange={ handleSelectChange }
|
|
87
|
+
fullWidth
|
|
88
|
+
>
|
|
89
|
+
{ [ ...RATIO_OPTIONS, { label: __( 'Custom', 'elementor' ), value: CUSTOM_RATIO } ].map(
|
|
90
|
+
( { label: optionLabel, ...props } ) => (
|
|
91
|
+
<MenuListItem key={ props.value } { ...props } value={ props.value ?? '' }>
|
|
92
|
+
{ optionLabel }
|
|
93
|
+
</MenuListItem>
|
|
94
|
+
)
|
|
95
|
+
) }
|
|
96
|
+
</Select>
|
|
124
97
|
</Grid>
|
|
125
98
|
</Grid>
|
|
126
|
-
|
|
127
|
-
|
|
99
|
+
{ isCustom && (
|
|
100
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
101
|
+
<Grid item xs={ 6 }>
|
|
102
|
+
<TextField
|
|
103
|
+
size="tiny"
|
|
104
|
+
type="number"
|
|
105
|
+
fullWidth
|
|
106
|
+
disabled={ disabled }
|
|
107
|
+
value={ customWidth }
|
|
108
|
+
onChange={ handleCustomWidthChange }
|
|
109
|
+
InputProps={ {
|
|
110
|
+
startAdornment: <ArrowsMoveHorizontalIcon fontSize="tiny" />,
|
|
111
|
+
} }
|
|
112
|
+
/>
|
|
113
|
+
</Grid>
|
|
114
|
+
<Grid item xs={ 6 }>
|
|
115
|
+
<TextField
|
|
116
|
+
size="tiny"
|
|
117
|
+
type="number"
|
|
118
|
+
fullWidth
|
|
119
|
+
disabled={ disabled }
|
|
120
|
+
value={ customHeight }
|
|
121
|
+
onChange={ handleCustomHeightChange }
|
|
122
|
+
InputProps={ {
|
|
123
|
+
startAdornment: <ArrowsMoveVerticalIcon fontSize="tiny" />,
|
|
124
|
+
} }
|
|
125
|
+
/>
|
|
126
|
+
</Grid>
|
|
127
|
+
</Grid>
|
|
128
|
+
) }
|
|
129
|
+
</Stack>
|
|
130
|
+
</ControlActions>
|
|
128
131
|
);
|
|
129
132
|
} );
|
|
@@ -60,10 +60,11 @@ export const BackgroundImageOverlayPosition = () => {
|
|
|
60
60
|
</Grid>
|
|
61
61
|
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'flex-end', overflow: 'hidden' } }>
|
|
62
62
|
<Select
|
|
63
|
+
fullWidth
|
|
63
64
|
size="tiny"
|
|
64
|
-
value={ ( backgroundImageOffsetContext.value ? 'custom' : stringPropContext.value ) ?? '' }
|
|
65
65
|
onChange={ handlePositionChange }
|
|
66
|
-
|
|
66
|
+
disabled={ stringPropContext.disabled }
|
|
67
|
+
value={ ( backgroundImageOffsetContext.value ? 'custom' : stringPropContext.value ) ?? '' }
|
|
67
68
|
>
|
|
68
69
|
{ backgroundPositionOptions.map( ( { label, value } ) => (
|
|
69
70
|
<MenuListItem key={ value } value={ value ?? '' }>
|
|
@@ -74,10 +74,11 @@ export const BackgroundImageOverlaySize = () => {
|
|
|
74
74
|
<ControlToggleButtonGroup
|
|
75
75
|
exclusive
|
|
76
76
|
items={ sizeControlOptions }
|
|
77
|
+
onChange={ handleSizeChange }
|
|
78
|
+
disabled={ stringPropContext.disabled }
|
|
77
79
|
value={
|
|
78
80
|
( backgroundImageScaleContext.value ? 'custom' : stringPropContext.value ) as Sizes
|
|
79
81
|
}
|
|
80
|
-
onChange={ handleSizeChange }
|
|
81
82
|
/>
|
|
82
83
|
</Grid>
|
|
83
84
|
</PopoverGridContainer>
|
package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx
CHANGED
|
@@ -74,7 +74,7 @@ export const BackgroundOverlayRepeaterControl = createControl( () => {
|
|
|
74
74
|
const { propType, value: overlayValues, setValue, disabled } = useBoundProp( backgroundOverlayPropTypeUtil );
|
|
75
75
|
|
|
76
76
|
return (
|
|
77
|
-
<PropProvider propType={ propType } value={ overlayValues } setValue={ setValue }>
|
|
77
|
+
<PropProvider propType={ propType } value={ overlayValues } setValue={ setValue } disabled={ disabled }>
|
|
78
78
|
<Repeater
|
|
79
79
|
openOnAdd
|
|
80
80
|
disabled={ disabled }
|
|
@@ -16,7 +16,7 @@ export const BoxShadowRepeaterControl = createControl( () => {
|
|
|
16
16
|
const { propType, value, setValue, disabled } = useBoundProp( boxShadowPropTypeUtil );
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<PropProvider propType={ propType } value={ value } setValue={ setValue }>
|
|
19
|
+
<PropProvider propType={ propType } value={ value } setValue={ setValue } disabled={ disabled }>
|
|
20
20
|
<Repeater
|
|
21
21
|
openOnAdd
|
|
22
22
|
disabled={ disabled }
|
|
@@ -47,10 +47,10 @@ const ItemContent = ( { anchorEl, bind }: { anchorEl: HTMLElement | null; bind:
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
const Content = ( { anchorEl }: { anchorEl: HTMLElement | null } ) => {
|
|
50
|
-
const
|
|
50
|
+
const context = useBoundProp( shadowPropTypeUtil );
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<PropProvider
|
|
53
|
+
<PropProvider { ...context }>
|
|
54
54
|
<PopoverContent p={ 1.5 }>
|
|
55
55
|
<PopoverGridContainer>
|
|
56
56
|
<Control bind="color" label={ __( 'Color', 'elementor' ) }>
|
|
@@ -62,7 +62,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
62
62
|
disabled: multiSizeDisabled,
|
|
63
63
|
} = useBoundProp( multiSizePropTypeUtil );
|
|
64
64
|
|
|
65
|
-
const { value: sizeValue, setValue: setSizeValue
|
|
65
|
+
const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
|
|
66
66
|
|
|
67
67
|
const splitEqualValue = () => {
|
|
68
68
|
if ( ! sizeValue ) {
|
|
@@ -98,13 +98,19 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
98
98
|
return splitEqualValue() ?? null;
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
const isShowingGeneralIndicator = ! isExperimentActive( 'e_v_3_30' ) || ! popupState.isOpen;
|
|
102
|
+
|
|
101
103
|
const isMixed = !! multiSizeValue;
|
|
102
104
|
|
|
103
105
|
return (
|
|
104
106
|
<>
|
|
105
107
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ controlRef }>
|
|
106
108
|
<Grid item xs={ 6 }>
|
|
107
|
-
|
|
109
|
+
{ ! isShowingGeneralIndicator ? (
|
|
110
|
+
<ControlFormLabel>{ label }</ControlFormLabel>
|
|
111
|
+
) : (
|
|
112
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
113
|
+
) }
|
|
108
114
|
</Grid>
|
|
109
115
|
<Grid item xs={ 6 }>
|
|
110
116
|
<Stack direction="row" alignItems="center" gap={ 1 }>
|
|
@@ -117,7 +123,6 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
117
123
|
{ ...bindToggle( popupState ) }
|
|
118
124
|
selected={ popupState.isOpen }
|
|
119
125
|
aria-label={ tooltipLabel }
|
|
120
|
-
disabled={ multiSizeDisabled || sizeDisabled }
|
|
121
126
|
>
|
|
122
127
|
{ icon }
|
|
123
128
|
</ToggleButton>
|
|
@@ -141,7 +146,12 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
141
146
|
paper: { sx: { mt: 0.5, width: controlRef.current?.getBoundingClientRect().width } },
|
|
142
147
|
} }
|
|
143
148
|
>
|
|
144
|
-
<PropProvider
|
|
149
|
+
<PropProvider
|
|
150
|
+
propType={ multiSizePropType }
|
|
151
|
+
value={ getMultiSizeValues() }
|
|
152
|
+
setValue={ setNestedProp }
|
|
153
|
+
disabled={ multiSizeDisabled }
|
|
154
|
+
>
|
|
145
155
|
<PopoverContent p={ 1.5 } pt={ 2.5 } pb={ 3 }>
|
|
146
156
|
<PopoverGridContainer>
|
|
147
157
|
<MultiSizeValueControl item={ items[ 0 ] } />
|