@elementor/editor-controls 1.0.0 → 1.2.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 +60 -0
- package/dist/index.d.mts +78 -41
- package/dist/index.d.ts +78 -41
- package/dist/index.js +875 -617
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +713 -467
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
- package/src/components/font-family-selector.tsx +50 -174
- package/src/components/popover-content.tsx +3 -11
- package/src/components/repeater.tsx +27 -11
- package/src/components/text-field-popover.tsx +3 -3
- package/src/controls/aspect-ratio-control.tsx +20 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-size.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +9 -4
- package/src/controls/box-shadow-repeater-control.tsx +2 -2
- package/src/controls/equal-unequal-sizes-control.tsx +3 -9
- package/src/controls/filter-repeater-control.tsx +186 -0
- package/src/controls/font-family-control/font-family-control.tsx +6 -2
- package/src/controls/gap-control.tsx +3 -3
- package/src/controls/image-control.tsx +22 -35
- package/src/controls/key-value-control.tsx +119 -0
- package/src/controls/link-control.tsx +3 -1
- package/src/controls/linked-dimensions-control.tsx +3 -3
- package/src/controls/number-control.tsx +3 -3
- package/src/controls/position-control.tsx +109 -0
- package/src/controls/repeatable-control.tsx +119 -0
- package/src/controls/size-control.tsx +11 -9
- package/src/controls/stroke-control.tsx +2 -2
- package/src/controls/svg-media-control.tsx +0 -2
- package/src/hooks/use-repeatable-control-context.ts +24 -0
- package/src/index.ts +6 -1
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.2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -41,27 +41,27 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@elementor/editor-current-user": "0.5.0",
|
|
44
|
-
"@elementor/editor-elements": "0.8.
|
|
45
|
-
"@elementor/editor-props": "0.
|
|
46
|
-
"@elementor/editor-responsive": "0.13.
|
|
47
|
-
"@elementor/editor-ui": "0.
|
|
48
|
-
"@elementor/editor-v1-adapters": "0.12.
|
|
44
|
+
"@elementor/editor-elements": "0.8.7",
|
|
45
|
+
"@elementor/editor-props": "0.15.0",
|
|
46
|
+
"@elementor/editor-responsive": "0.13.6",
|
|
47
|
+
"@elementor/editor-ui": "0.13.0",
|
|
48
|
+
"@elementor/editor-v1-adapters": "0.12.1",
|
|
49
49
|
"@elementor/env": "0.3.5",
|
|
50
50
|
"@elementor/http-client": "0.3.0",
|
|
51
51
|
"@elementor/icons": "1.44.0",
|
|
52
52
|
"@elementor/locations": "0.8.0",
|
|
53
53
|
"@elementor/query": "0.2.4",
|
|
54
54
|
"@elementor/session": "0.1.0",
|
|
55
|
-
"@elementor/ui": "1.
|
|
56
|
-
"@elementor/utils": "0.
|
|
57
|
-
"@elementor/wp-media": "0.6.
|
|
58
|
-
"@tanstack/react-virtual": "3.13.3",
|
|
55
|
+
"@elementor/ui": "1.35.5",
|
|
56
|
+
"@elementor/utils": "0.5.0",
|
|
57
|
+
"@elementor/wp-media": "0.6.1",
|
|
59
58
|
"@wordpress/i18n": "^5.13.0"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
61
|
"tsup": "^8.3.5"
|
|
63
62
|
},
|
|
64
63
|
"peerDependencies": {
|
|
65
|
-
"react": "^18.3.1"
|
|
64
|
+
"react": "^18.3.1",
|
|
65
|
+
"react-dom": "^18.3.1"
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react';
|
|
2
1
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
Divider,
|
|
8
|
-
InputAdornment,
|
|
9
|
-
Link,
|
|
10
|
-
MenuList,
|
|
11
|
-
MenuSubheader,
|
|
12
|
-
Stack,
|
|
13
|
-
styled,
|
|
14
|
-
TextField,
|
|
15
|
-
Typography,
|
|
16
|
-
} from '@elementor/ui';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { PopoverHeader, PopoverMenuList, PopoverScrollableContent, PopoverSearch } from '@elementor/editor-ui';
|
|
4
|
+
import { TextIcon } from '@elementor/icons';
|
|
5
|
+
import { Box, Divider, Link, Stack, Typography } from '@elementor/ui';
|
|
17
6
|
import { debounce } from '@elementor/utils';
|
|
18
|
-
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
19
7
|
import { __ } from '@wordpress/i18n';
|
|
20
8
|
|
|
21
9
|
import { enqueueFont } from '../controls/font-family-control/enqueue-font';
|
|
@@ -29,6 +17,7 @@ type FontFamilySelectorProps = {
|
|
|
29
17
|
fontFamily: string | null;
|
|
30
18
|
onFontFamilyChange: ( fontFamily: string ) => void;
|
|
31
19
|
onClose: () => void;
|
|
20
|
+
sectionWidth: number;
|
|
32
21
|
};
|
|
33
22
|
|
|
34
23
|
export const FontFamilySelector = ( {
|
|
@@ -36,13 +25,14 @@ export const FontFamilySelector = ( {
|
|
|
36
25
|
fontFamily,
|
|
37
26
|
onFontFamilyChange,
|
|
38
27
|
onClose,
|
|
28
|
+
sectionWidth,
|
|
39
29
|
}: FontFamilySelectorProps ) => {
|
|
40
30
|
const [ searchValue, setSearchValue ] = useState( '' );
|
|
41
31
|
|
|
42
32
|
const filteredFontFamilies = useFilteredFontFamilies( fontFamilies, searchValue );
|
|
43
33
|
|
|
44
|
-
const handleSearch = (
|
|
45
|
-
setSearchValue(
|
|
34
|
+
const handleSearch = ( value: string ) => {
|
|
35
|
+
setSearchValue( value );
|
|
46
36
|
};
|
|
47
37
|
|
|
48
38
|
const handleClose = () => {
|
|
@@ -58,35 +48,31 @@ export const FontFamilySelector = ( {
|
|
|
58
48
|
icon={ <TextIcon fontSize={ SIZE } /> }
|
|
59
49
|
/>
|
|
60
50
|
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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>
|
|
51
|
+
<PopoverSearch
|
|
52
|
+
value={ searchValue }
|
|
53
|
+
onSearch={ handleSearch }
|
|
54
|
+
placeholder={ __( 'Search', 'elementor' ) }
|
|
55
|
+
/>
|
|
56
|
+
|
|
79
57
|
<Divider />
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
58
|
+
|
|
59
|
+
<PopoverScrollableContent width={ sectionWidth }>
|
|
60
|
+
{ filteredFontFamilies.length > 0 ? (
|
|
61
|
+
<FontList
|
|
62
|
+
fontListItems={ filteredFontFamilies }
|
|
63
|
+
setFontFamily={ onFontFamilyChange }
|
|
64
|
+
handleClose={ handleClose }
|
|
65
|
+
fontFamily={ fontFamily }
|
|
66
|
+
/>
|
|
67
|
+
) : (
|
|
68
|
+
<Stack
|
|
69
|
+
alignItems="center"
|
|
70
|
+
justifyContent="center"
|
|
71
|
+
height="100%"
|
|
72
|
+
p={ 2.5 }
|
|
73
|
+
gap={ 1.5 }
|
|
74
|
+
overflow={ 'hidden' }
|
|
75
|
+
>
|
|
90
76
|
<TextIcon fontSize="large" />
|
|
91
77
|
<Box sx={ { maxWidth: 160, overflow: 'hidden' } }>
|
|
92
78
|
<Typography align="center" variant="subtitle2" color="text.secondary">
|
|
@@ -108,7 +94,12 @@ export const FontFamilySelector = ( {
|
|
|
108
94
|
<span>”.</span>
|
|
109
95
|
</Typography>
|
|
110
96
|
</Box>
|
|
111
|
-
<Typography
|
|
97
|
+
<Typography
|
|
98
|
+
align="center"
|
|
99
|
+
variant="caption"
|
|
100
|
+
color="text.secondary"
|
|
101
|
+
sx={ { display: 'flex', flexDirection: 'column' } }
|
|
102
|
+
>
|
|
112
103
|
{ __( 'Try something else.', 'elementor' ) }
|
|
113
104
|
<Link
|
|
114
105
|
color="secondary"
|
|
@@ -120,8 +111,8 @@ export const FontFamilySelector = ( {
|
|
|
120
111
|
</Link>
|
|
121
112
|
</Typography>
|
|
122
113
|
</Stack>
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
) }
|
|
115
|
+
</PopoverScrollableContent>
|
|
125
116
|
</Stack>
|
|
126
117
|
);
|
|
127
118
|
};
|
|
@@ -133,11 +124,7 @@ type FontListProps = {
|
|
|
133
124
|
fontFamily: string | null;
|
|
134
125
|
};
|
|
135
126
|
|
|
136
|
-
const LIST_ITEM_HEIGHT = 36;
|
|
137
|
-
const LIST_ITEMS_BUFFER = 6;
|
|
138
|
-
|
|
139
127
|
const FontList = ( { fontListItems, setFontFamily, handleClose, fontFamily }: FontListProps ) => {
|
|
140
|
-
const containerRef = useRef< HTMLDivElement >( null );
|
|
141
128
|
const selectedItem = fontListItems.find( ( item ) => item.value === fontFamily );
|
|
142
129
|
|
|
143
130
|
const debouncedVirtualizeChange = useDebounce( ( { getVirtualIndexes }: { getVirtualIndexes: () => number[] } ) => {
|
|
@@ -149,131 +136,20 @@ const FontList = ( { fontListItems, setFontFamily, handleClose, fontFamily }: Fo
|
|
|
149
136
|
} );
|
|
150
137
|
}, 100 );
|
|
151
138
|
|
|
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
139
|
return (
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
} }
|
|
177
|
-
|
|
178
|
-
|
|
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>
|
|
140
|
+
<PopoverMenuList
|
|
141
|
+
items={ fontListItems }
|
|
142
|
+
selectedValue={ selectedItem?.value }
|
|
143
|
+
onChange={ debouncedVirtualizeChange }
|
|
144
|
+
onSelect={ setFontFamily }
|
|
145
|
+
onClose={ handleClose }
|
|
146
|
+
itemStyle={ ( item ) => ( { fontFamily: item.value } ) }
|
|
147
|
+
data-testid="font-list"
|
|
148
|
+
/>
|
|
245
149
|
);
|
|
246
150
|
};
|
|
247
151
|
|
|
248
|
-
const
|
|
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 ) => {
|
|
152
|
+
const useDebounce = < TArgs extends unknown[] >( fn: ( ...args: TArgs ) => void, delay: number ) => {
|
|
277
153
|
const [ debouncedFn ] = useState( () => debounce( fn, delay ) );
|
|
278
154
|
|
|
279
155
|
useEffect( () => () => debouncedFn.cancel(), [ debouncedFn ] );
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import { type FC, type PropsWithChildren } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { Stack } from '@elementor/ui';
|
|
3
|
+
import { Stack, type StackProps } from '@elementor/ui';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
gap?: number;
|
|
8
|
-
p?: 1.5 | 2 | 2.5;
|
|
9
|
-
pt?: 2.5;
|
|
10
|
-
pb?: 3;
|
|
11
|
-
} >;
|
|
12
|
-
|
|
13
|
-
export const PopoverContent: FC< PopoverContentProps > = ( { alignItems, gap = 1.5, p, pt, pb, children } ) => (
|
|
14
|
-
<Stack alignItems={ alignItems } gap={ gap } p={ p } pt={ pt } pb={ pb }>
|
|
5
|
+
export const PopoverContent: FC< PropsWithChildren< StackProps > > = ( { gap = 1.5, children, ...props } ) => (
|
|
6
|
+
<Stack { ...props } gap={ gap }>
|
|
15
7
|
{ children }
|
|
16
8
|
</Stack>
|
|
17
9
|
);
|
|
@@ -48,6 +48,9 @@ type RepeaterProps< T > = {
|
|
|
48
48
|
value: T;
|
|
49
49
|
} >;
|
|
50
50
|
};
|
|
51
|
+
showDuplicate?: boolean;
|
|
52
|
+
showToggle?: boolean;
|
|
53
|
+
isSortable?: boolean;
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
const EMPTY_OPEN_ITEM = -1;
|
|
@@ -60,6 +63,9 @@ export const Repeater = < T, >( {
|
|
|
60
63
|
addToBottom = false,
|
|
61
64
|
values: repeaterValues = [],
|
|
62
65
|
setValues: setRepeaterValues,
|
|
66
|
+
showDuplicate = true,
|
|
67
|
+
showToggle = true,
|
|
68
|
+
isSortable = true,
|
|
63
69
|
}: RepeaterProps< Item< T > > ) => {
|
|
64
70
|
const [ openItem, setOpenItem ] = useState( EMPTY_OPEN_ITEM );
|
|
65
71
|
|
|
@@ -176,7 +182,7 @@ export const Repeater = < T, >( {
|
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
return (
|
|
179
|
-
<SortableItem id={ key } key={ `sortable-${ key }` } disabled={
|
|
185
|
+
<SortableItem id={ key } key={ `sortable-${ key }` } disabled={ ! isSortable }>
|
|
180
186
|
<RepeaterItem
|
|
181
187
|
disabled={ disabled }
|
|
182
188
|
propDisabled={ value?.disabled }
|
|
@@ -195,6 +201,8 @@ export const Repeater = < T, >( {
|
|
|
195
201
|
toggleDisableItem={ () => toggleDisableRepeaterItem( index ) }
|
|
196
202
|
openOnMount={ openOnAdd && openItem === key }
|
|
197
203
|
onOpen={ () => setOpenItem( EMPTY_OPEN_ITEM ) }
|
|
204
|
+
showDuplicate={ showDuplicate }
|
|
205
|
+
showToggle={ showToggle }
|
|
198
206
|
>
|
|
199
207
|
{ ( props ) => (
|
|
200
208
|
<itemSettings.Content { ...props } value={ value } bind={ String( index ) } />
|
|
@@ -219,6 +227,8 @@ type RepeaterItemProps = {
|
|
|
219
227
|
children: ( { anchorEl }: { anchorEl: AnchorEl } ) => React.ReactNode;
|
|
220
228
|
openOnMount: boolean;
|
|
221
229
|
onOpen: () => void;
|
|
230
|
+
showDuplicate: boolean;
|
|
231
|
+
showToggle: boolean;
|
|
222
232
|
disabled?: boolean;
|
|
223
233
|
};
|
|
224
234
|
|
|
@@ -232,6 +242,8 @@ const RepeaterItem = ( {
|
|
|
232
242
|
toggleDisableItem,
|
|
233
243
|
openOnMount,
|
|
234
244
|
onOpen,
|
|
245
|
+
showDuplicate,
|
|
246
|
+
showToggle,
|
|
235
247
|
disabled,
|
|
236
248
|
}: RepeaterItemProps ) => {
|
|
237
249
|
const [ anchorEl, setAnchorEl ] = useState< AnchorEl >( null );
|
|
@@ -255,16 +267,20 @@ const RepeaterItem = ( {
|
|
|
255
267
|
startIcon={ startIcon }
|
|
256
268
|
actions={
|
|
257
269
|
<>
|
|
258
|
-
|
|
259
|
-
<
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
{ showDuplicate && (
|
|
271
|
+
<Tooltip title={ duplicateLabel } placement="top">
|
|
272
|
+
<IconButton size={ SIZE } onClick={ duplicateItem } aria-label={ duplicateLabel }>
|
|
273
|
+
<CopyIcon fontSize={ SIZE } />
|
|
274
|
+
</IconButton>
|
|
275
|
+
</Tooltip>
|
|
276
|
+
) }
|
|
277
|
+
{ showToggle && (
|
|
278
|
+
<Tooltip title={ toggleLabel } placement="top">
|
|
279
|
+
<IconButton size={ SIZE } onClick={ toggleDisableItem } aria-label={ toggleLabel }>
|
|
280
|
+
{ propDisabled ? <EyeOffIcon fontSize={ SIZE } /> : <EyeIcon fontSize={ SIZE } /> }
|
|
281
|
+
</IconButton>
|
|
282
|
+
</Tooltip>
|
|
283
|
+
) }
|
|
268
284
|
<Tooltip title={ removeLabel } placement="top">
|
|
269
285
|
<IconButton size={ SIZE } onClick={ removeItem } aria-label={ removeLabel }>
|
|
270
286
|
<XIcon fontSize={ SIZE } />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type RefObject } from 'react';
|
|
3
3
|
import { bindPopover, Paper, Popover, type PopupState, TextField } from '@elementor/ui';
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
6
6
|
popupState: PopupState;
|
|
7
|
-
anchorRef:
|
|
7
|
+
anchorRef: RefObject< HTMLDivElement | null >;
|
|
8
8
|
restoreValue: () => void;
|
|
9
9
|
value: string;
|
|
10
10
|
onChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
|
|
@@ -26,7 +26,7 @@ export const TextFieldPopover = ( props: Props ) => {
|
|
|
26
26
|
>
|
|
27
27
|
<Paper
|
|
28
28
|
sx={ {
|
|
29
|
-
width: anchorRef.current
|
|
29
|
+
width: anchorRef.current?.offsetWidth + 'px',
|
|
30
30
|
borderRadius: 2,
|
|
31
31
|
p: 1.5,
|
|
32
32
|
} }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import { stringPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { MenuListItem } from '@elementor/editor-ui';
|
|
5
5
|
import { ArrowsMoveHorizontalIcon, ArrowsMoveVerticalIcon } from '@elementor/icons';
|
|
@@ -38,6 +38,24 @@ export const AspectRatioControl = createControl( ( { label }: { label: string }
|
|
|
38
38
|
isCustomSelected ? CUSTOM_RATIO : aspectRatioValue || ''
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
+
useEffect( () => {
|
|
42
|
+
const isCustomValue =
|
|
43
|
+
aspectRatioValue && ! RATIO_OPTIONS.some( ( option ) => option.value === aspectRatioValue );
|
|
44
|
+
|
|
45
|
+
if ( isCustomValue ) {
|
|
46
|
+
const [ width, height ] = aspectRatioValue.split( '/' );
|
|
47
|
+
setCustomWidth( width || '' );
|
|
48
|
+
setCustomHeight( height || '' );
|
|
49
|
+
setSelectedValue( CUSTOM_RATIO );
|
|
50
|
+
setIsCustom( true );
|
|
51
|
+
} else {
|
|
52
|
+
setSelectedValue( aspectRatioValue || '' );
|
|
53
|
+
setIsCustom( false );
|
|
54
|
+
setCustomWidth( '' );
|
|
55
|
+
setCustomHeight( '' );
|
|
56
|
+
}
|
|
57
|
+
}, [ aspectRatioValue ] );
|
|
58
|
+
|
|
41
59
|
const handleSelectChange = ( event: SelectChangeEvent< string > ) => {
|
|
42
60
|
const newValue = event.target.value;
|
|
43
61
|
const isCustomRatio = newValue === CUSTOM_RATIO;
|
|
@@ -71,7 +89,7 @@ export const AspectRatioControl = createControl( ( { label }: { label: string }
|
|
|
71
89
|
|
|
72
90
|
return (
|
|
73
91
|
<ControlActions>
|
|
74
|
-
<Stack direction="column"
|
|
92
|
+
<Stack direction="column" gap={ 2 }>
|
|
75
93
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
76
94
|
<Grid item xs={ 6 }>
|
|
77
95
|
<ControlLabel>{ label }</ControlLabel>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useRef } from 'react';
|
|
3
3
|
import { backgroundImagePositionOffsetPropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { MenuListItem } from '@elementor/editor-ui';
|
|
5
5
|
import { LetterXIcon, LetterYIcon } from '@elementor/icons';
|
|
@@ -41,7 +41,7 @@ export const BackgroundImageOverlayPosition = () => {
|
|
|
41
41
|
const stringPropContext = useBoundProp( stringPropTypeUtil );
|
|
42
42
|
|
|
43
43
|
const isCustom = !! backgroundImageOffsetContext.value;
|
|
44
|
-
const rowRef
|
|
44
|
+
const rowRef = useRef< HTMLDivElement >( null );
|
|
45
45
|
|
|
46
46
|
const handlePositionChange = ( event: SelectChangeEvent< Positions > ) => {
|
|
47
47
|
const value = event.target.value || null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useRef } from 'react';
|
|
3
3
|
import { backgroundImageSizeScalePropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import {
|
|
5
5
|
ArrowBarBothIcon,
|
|
@@ -55,7 +55,7 @@ export const BackgroundImageOverlaySize = () => {
|
|
|
55
55
|
const stringPropContext = useBoundProp( stringPropTypeUtil );
|
|
56
56
|
|
|
57
57
|
const isCustom = !! backgroundImageScaleContext.value;
|
|
58
|
-
const rowRef
|
|
58
|
+
const rowRef = useRef< HTMLDivElement >( null );
|
|
59
59
|
|
|
60
60
|
const handleSizeChange = ( size: Sizes | null ) => {
|
|
61
61
|
if ( size === 'custom' ) {
|
package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { useWpMediaAttachment } from '@elementor/wp-media';
|
|
|
12
12
|
import { __ } from '@wordpress/i18n';
|
|
13
13
|
|
|
14
14
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../../../bound-prop-context';
|
|
15
|
+
import { ControlFormLabel } from '../../../components/control-form-label';
|
|
15
16
|
import { PopoverContent } from '../../../components/popover-content';
|
|
16
17
|
import { Repeater } from '../../../components/repeater';
|
|
17
18
|
import { createControl } from '../../../create-control';
|
|
@@ -237,10 +238,14 @@ const ImageOverlayContent = () => {
|
|
|
237
238
|
<PropKeyProvider bind={ 'image' }>
|
|
238
239
|
<Grid container spacing={ 1 } alignItems="center">
|
|
239
240
|
<Grid item xs={ 12 }>
|
|
240
|
-
<
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
242
|
+
<Grid item xs={ 6 }>
|
|
243
|
+
<ControlFormLabel>{ __( 'Resolution', 'elementor' ) }</ControlFormLabel>
|
|
244
|
+
</Grid>
|
|
245
|
+
<Grid item xs={ 6 } sx={ { overflow: 'hidden' } }>
|
|
246
|
+
<ImageControl sizes={ backgroundResolutionOptions } />
|
|
247
|
+
</Grid>
|
|
248
|
+
</Grid>
|
|
244
249
|
</Grid>
|
|
245
250
|
</Grid>
|
|
246
251
|
</PropKeyProvider>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type RefObject, useRef } from 'react';
|
|
3
3
|
import { boxShadowPropTypeUtil, type PropKey, shadowPropTypeUtil, type ShadowPropValue } from '@elementor/editor-props';
|
|
4
4
|
import { FormLabel, Grid, type SxProps, type Theme, UnstableColorIndicator } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -49,7 +49,7 @@ const ItemContent = ( { anchorEl, bind }: { anchorEl: HTMLElement | null; bind:
|
|
|
49
49
|
|
|
50
50
|
const Content = ( { anchorEl }: { anchorEl: HTMLElement | null } ) => {
|
|
51
51
|
const context = useBoundProp( shadowPropTypeUtil );
|
|
52
|
-
const rowRef:
|
|
52
|
+
const rowRef: RefObject< HTMLDivElement >[] = [ useRef( null ), useRef( null ) ];
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
55
|
<PropProvider { ...context }>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ReactNode, type RefObject, useId, useRef } from 'react';
|
|
3
3
|
import { type PropKey, type PropTypeUtil, sizePropTypeUtil, type SizePropValue } from '@elementor/editor-props';
|
|
4
4
|
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
5
5
|
import { bindPopover, bindToggle, Grid, Popover, Stack, ToggleButton, Tooltip, usePopupState } from '@elementor/ui';
|
|
@@ -63,7 +63,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
63
63
|
|
|
64
64
|
const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
|
|
65
65
|
|
|
66
|
-
const rowRefs:
|
|
66
|
+
const rowRefs: RefObject< HTMLDivElement >[] = [ useRef( null ), useRef( null ) ];
|
|
67
67
|
|
|
68
68
|
const splitEqualValue = () => {
|
|
69
69
|
if ( ! sizeValue ) {
|
|
@@ -172,13 +172,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
const MultiSizeValueControl = ( {
|
|
176
|
-
item,
|
|
177
|
-
rowRef,
|
|
178
|
-
}: {
|
|
179
|
-
item: Item;
|
|
180
|
-
rowRef: MutableRefObject< HTMLElement | undefined >;
|
|
181
|
-
} ) => {
|
|
175
|
+
const MultiSizeValueControl = ( { item, rowRef }: { item: Item; rowRef: RefObject< HTMLDivElement > } ) => {
|
|
182
176
|
const isUsingNestedProps = isExperimentActive( 'e_v_3_30' );
|
|
183
177
|
|
|
184
178
|
return (
|