@elementor/editor-controls 0.14.0 → 0.15.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 +18 -0
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +297 -165
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +311 -178
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/src/api.ts +16 -0
- package/src/components/repeater.tsx +20 -23
- package/src/controls/equal-unequal-sizes-control.tsx +15 -10
- package/src/controls/font-family-control/enqueue-font.tsx +15 -0
- package/src/controls/font-family-control/font-family-control.tsx +286 -0
- package/src/controls/gap-control.tsx +19 -11
- package/src/controls/image-control.tsx +6 -1
- package/src/controls/image-media-control.tsx +4 -6
- package/src/controls/linked-dimensions-control.tsx +57 -25
- package/src/controls/svg-media-control.tsx +15 -5
- package/src/hooks/use-filtered-font-families.ts +13 -26
- package/src/hooks/use-unfiltered-files-upload.ts +40 -0
- package/src/index.ts +1 -1
- package/src/controls/font-family-control.tsx +0 -157
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { dimensionsPropTypeUtil, type PropKey, sizePropTypeUtil } from '@elementor/editor-props';
|
|
3
3
|
import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
4
|
-
import { Grid, Stack, ToggleButton } from '@elementor/ui';
|
|
4
|
+
import { Grid, Stack, ToggleButton, Tooltip } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
|
|
@@ -10,7 +10,15 @@ import { createControl } from '../create-control';
|
|
|
10
10
|
import { type ExtendedValue, SizeControl } from './size-control';
|
|
11
11
|
|
|
12
12
|
export const LinkedDimensionsControl = createControl(
|
|
13
|
-
( {
|
|
13
|
+
( {
|
|
14
|
+
label,
|
|
15
|
+
isSiteRtl = false,
|
|
16
|
+
extendedValues,
|
|
17
|
+
}: {
|
|
18
|
+
label: string;
|
|
19
|
+
isSiteRtl?: boolean;
|
|
20
|
+
extendedValues?: ExtendedValue[];
|
|
21
|
+
} ) => {
|
|
14
22
|
const {
|
|
15
23
|
value: dimensionsValue,
|
|
16
24
|
setValue: setDimensionsValue,
|
|
@@ -22,36 +30,44 @@ export const LinkedDimensionsControl = createControl(
|
|
|
22
30
|
|
|
23
31
|
const onLinkToggle = () => {
|
|
24
32
|
if ( ! isLinked ) {
|
|
25
|
-
setSizeValue( dimensionsValue?.
|
|
33
|
+
setSizeValue( dimensionsValue[ 'block-start' ]?.value );
|
|
26
34
|
return;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
const value = sizeValue ? sizePropTypeUtil.create( sizeValue ) : null;
|
|
30
38
|
|
|
31
39
|
setDimensionsValue( {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
'block-start': value,
|
|
41
|
+
'block-end': value,
|
|
42
|
+
'inline-start': value,
|
|
43
|
+
'inline-end': value,
|
|
36
44
|
} );
|
|
37
45
|
};
|
|
38
46
|
|
|
47
|
+
const tooltipLabel = label.toLowerCase();
|
|
48
|
+
|
|
39
49
|
const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
|
|
50
|
+
// translators: %s: Tooltip title.
|
|
51
|
+
const linkedLabel = __( 'Link %s', 'elementor' ).replace( '%s', tooltipLabel );
|
|
52
|
+
// translators: %s: Tooltip title.
|
|
53
|
+
const unlinkedLabel = __( 'Unlink %s', 'elementor' ).replace( '%s', tooltipLabel );
|
|
40
54
|
|
|
41
55
|
return (
|
|
42
56
|
<PropProvider propType={ propType } value={ dimensionsValue } setValue={ setDimensionsValue }>
|
|
43
57
|
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
44
58
|
<ControlLabel>{ label }</ControlLabel>
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
<Tooltip title={ isLinked ? unlinkedLabel : linkedLabel } placement="top">
|
|
60
|
+
<ToggleButton
|
|
61
|
+
aria-label={ isLinked ? unlinkedLabel : linkedLabel }
|
|
62
|
+
size={ 'tiny' }
|
|
63
|
+
value={ 'check' }
|
|
64
|
+
selected={ isLinked }
|
|
65
|
+
sx={ { marginLeft: 'auto' } }
|
|
66
|
+
onChange={ onLinkToggle }
|
|
67
|
+
>
|
|
68
|
+
<LinkedIcon fontSize={ 'tiny' } />
|
|
69
|
+
</ToggleButton>
|
|
70
|
+
</Tooltip>
|
|
55
71
|
</Stack>
|
|
56
72
|
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
57
73
|
<Grid container gap={ 1 } alignItems="center">
|
|
@@ -60,7 +76,7 @@ export const LinkedDimensionsControl = createControl(
|
|
|
60
76
|
</Grid>
|
|
61
77
|
<Grid item xs={ 12 }>
|
|
62
78
|
<Control
|
|
63
|
-
bind={ '
|
|
79
|
+
bind={ 'block-start' }
|
|
64
80
|
startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
|
|
65
81
|
isLinked={ isLinked }
|
|
66
82
|
extendedValues={ extendedValues }
|
|
@@ -69,12 +85,20 @@ export const LinkedDimensionsControl = createControl(
|
|
|
69
85
|
</Grid>
|
|
70
86
|
<Grid container gap={ 1 } alignItems="center">
|
|
71
87
|
<Grid item xs={ 12 }>
|
|
72
|
-
<ControlLabel>
|
|
88
|
+
<ControlLabel>
|
|
89
|
+
{ isSiteRtl ? __( 'Left', 'elementor' ) : __( 'Right', 'elementor' ) }
|
|
90
|
+
</ControlLabel>
|
|
73
91
|
</Grid>
|
|
74
92
|
<Grid item xs={ 12 }>
|
|
75
93
|
<Control
|
|
76
|
-
bind={ '
|
|
77
|
-
startIcon={
|
|
94
|
+
bind={ 'inline-end' }
|
|
95
|
+
startIcon={
|
|
96
|
+
isSiteRtl ? (
|
|
97
|
+
<SideLeftIcon fontSize={ 'tiny' } />
|
|
98
|
+
) : (
|
|
99
|
+
<SideRightIcon fontSize={ 'tiny' } />
|
|
100
|
+
)
|
|
101
|
+
}
|
|
78
102
|
isLinked={ isLinked }
|
|
79
103
|
extendedValues={ extendedValues }
|
|
80
104
|
/>
|
|
@@ -88,7 +112,7 @@ export const LinkedDimensionsControl = createControl(
|
|
|
88
112
|
</Grid>
|
|
89
113
|
<Grid item xs={ 12 }>
|
|
90
114
|
<Control
|
|
91
|
-
bind={ '
|
|
115
|
+
bind={ 'block-end' }
|
|
92
116
|
startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
|
|
93
117
|
isLinked={ isLinked }
|
|
94
118
|
extendedValues={ extendedValues }
|
|
@@ -97,12 +121,20 @@ export const LinkedDimensionsControl = createControl(
|
|
|
97
121
|
</Grid>
|
|
98
122
|
<Grid container gap={ 1 } alignItems="center">
|
|
99
123
|
<Grid item xs={ 12 }>
|
|
100
|
-
<ControlLabel>
|
|
124
|
+
<ControlLabel>
|
|
125
|
+
{ isSiteRtl ? __( 'Right', 'elementor' ) : __( 'Left', 'elementor' ) }
|
|
126
|
+
</ControlLabel>
|
|
101
127
|
</Grid>
|
|
102
128
|
<Grid item xs={ 12 }>
|
|
103
129
|
<Control
|
|
104
|
-
bind={ '
|
|
105
|
-
startIcon={
|
|
130
|
+
bind={ 'inline-start' }
|
|
131
|
+
startIcon={
|
|
132
|
+
isSiteRtl ? (
|
|
133
|
+
<SideRightIcon fontSize={ 'tiny' } />
|
|
134
|
+
) : (
|
|
135
|
+
<SideLeftIcon fontSize={ 'tiny' } />
|
|
136
|
+
)
|
|
137
|
+
}
|
|
106
138
|
isLinked={ isLinked }
|
|
107
139
|
extendedValues={ extendedValues }
|
|
108
140
|
/>
|
|
@@ -2,13 +2,14 @@ import * as React from 'react';
|
|
|
2
2
|
import { imageSrcPropTypeUtil } from '@elementor/editor-props';
|
|
3
3
|
import { UploadIcon } from '@elementor/icons';
|
|
4
4
|
import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack, styled } from '@elementor/ui';
|
|
5
|
-
import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
5
|
+
import { type OpenOptions, useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { useBoundProp } from '../bound-prop-context';
|
|
9
9
|
import { ControlLabel } from '../components/control-label';
|
|
10
10
|
import ControlActions from '../control-actions/control-actions';
|
|
11
11
|
import { createControl } from '../create-control';
|
|
12
|
+
import { useUnfilteredFilesUpload } from '../hooks/use-unfiltered-files-upload';
|
|
12
13
|
|
|
13
14
|
const TILE_SIZE = 8;
|
|
14
15
|
const TILE_WHITE = 'transparent';
|
|
@@ -40,9 +41,10 @@ export const SvgMediaControl = createControl( () => {
|
|
|
40
41
|
const { id, url } = value ?? {};
|
|
41
42
|
const { data: attachment, isFetching } = useWpMediaAttachment( id?.value || null );
|
|
42
43
|
const src = attachment?.url ?? url?.value ?? null;
|
|
44
|
+
const { data: allowSvgUpload } = useUnfilteredFilesUpload();
|
|
45
|
+
|
|
43
46
|
const { open } = useWpMediaFrame( {
|
|
44
|
-
|
|
45
|
-
allowedExtensions: [ 'svg' ],
|
|
47
|
+
mediaTypes: [ 'svg' ],
|
|
46
48
|
multiple: false,
|
|
47
49
|
selected: id?.value || null,
|
|
48
50
|
onSelect: ( selectedAttachment ) => {
|
|
@@ -56,6 +58,14 @@ export const SvgMediaControl = createControl( () => {
|
|
|
56
58
|
},
|
|
57
59
|
} );
|
|
58
60
|
|
|
61
|
+
const handleClick = ( openOptions?: OpenOptions ) => {
|
|
62
|
+
if ( allowSvgUpload ) {
|
|
63
|
+
open( openOptions );
|
|
64
|
+
} else {
|
|
65
|
+
// TODO open upload SVG confirmation modal
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
59
69
|
return (
|
|
60
70
|
<Stack gap={ 1 }>
|
|
61
71
|
<ControlLabel> { __( 'SVG', 'elementor' ) } </ControlLabel>
|
|
@@ -85,7 +95,7 @@ export const SvgMediaControl = createControl( () => {
|
|
|
85
95
|
size="tiny"
|
|
86
96
|
color="inherit"
|
|
87
97
|
variant="outlined"
|
|
88
|
-
onClick={ () =>
|
|
98
|
+
onClick={ () => handleClick( { mode: 'browse' } ) }
|
|
89
99
|
>
|
|
90
100
|
{ __( 'Select SVG', 'elementor' ) }
|
|
91
101
|
</Button>
|
|
@@ -94,7 +104,7 @@ export const SvgMediaControl = createControl( () => {
|
|
|
94
104
|
variant="text"
|
|
95
105
|
color="inherit"
|
|
96
106
|
startIcon={ <UploadIcon /> }
|
|
97
|
-
onClick={ () =>
|
|
107
|
+
onClick={ () => handleClick( { mode: 'upload' } ) }
|
|
98
108
|
>
|
|
99
109
|
{ __( 'Upload', 'elementor' ) }
|
|
100
110
|
</Button>
|
|
@@ -1,37 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const supportedCategories: Record< SupportedFonts, string > = {
|
|
6
|
-
system: __( 'System', 'elementor' ),
|
|
7
|
-
googlefonts: __( 'Google Fonts', 'elementor' ),
|
|
8
|
-
customfonts: __( 'Custom Fonts', 'elementor' ),
|
|
1
|
+
export type FontListItem = {
|
|
2
|
+
type: 'font' | 'category';
|
|
3
|
+
value: string;
|
|
9
4
|
};
|
|
10
5
|
|
|
11
|
-
export const useFilteredFontFamilies = ( fontFamilies: Record< string,
|
|
12
|
-
const filteredFontFamilies = Object.entries( fontFamilies ).reduce<
|
|
13
|
-
( acc, [
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if ( ! isMatch ) {
|
|
17
|
-
return acc;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const categoryLabel = supportedCategories[ category as SupportedFonts ];
|
|
6
|
+
export const useFilteredFontFamilies = ( fontFamilies: Record< string, string[] >, searchValue: string ) => {
|
|
7
|
+
const filteredFontFamilies = Object.entries( fontFamilies ).reduce< FontListItem[] >(
|
|
8
|
+
( acc, [ category, fonts ] ) => {
|
|
9
|
+
const filteredFonts = fonts.filter( ( font ) => font.toLowerCase().includes( searchValue.toLowerCase() ) );
|
|
21
10
|
|
|
22
|
-
if (
|
|
23
|
-
|
|
11
|
+
if ( filteredFonts.length ) {
|
|
12
|
+
acc.push( { type: 'category', value: category } );
|
|
24
13
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
acc.set( categoryLabel, [ font ] );
|
|
29
|
-
}
|
|
14
|
+
filteredFonts.forEach( ( font ) => {
|
|
15
|
+
acc.push( { type: 'font', value: font } );
|
|
16
|
+
} );
|
|
30
17
|
}
|
|
31
18
|
|
|
32
19
|
return acc;
|
|
33
20
|
},
|
|
34
|
-
|
|
21
|
+
[]
|
|
35
22
|
);
|
|
36
23
|
|
|
37
24
|
return [ ...filteredFontFamilies ];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useMutation, useQuery, useQueryClient } from '@elementor/query';
|
|
2
|
+
|
|
3
|
+
import { apiClient } from '../api';
|
|
4
|
+
|
|
5
|
+
export const UNFILTERED_FILES_UPLOAD_KEY = 'elementor_unfiltered_files_upload';
|
|
6
|
+
|
|
7
|
+
const unfilteredFilesQueryKey = {
|
|
8
|
+
queryKey: [ UNFILTERED_FILES_UPLOAD_KEY ],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Value = '0' | '1';
|
|
12
|
+
|
|
13
|
+
export const useUnfilteredFilesUpload = () =>
|
|
14
|
+
useQuery( {
|
|
15
|
+
...unfilteredFilesQueryKey,
|
|
16
|
+
queryFn: (): Promise< boolean > =>
|
|
17
|
+
apiClient.getElementorSetting< Value >( UNFILTERED_FILES_UPLOAD_KEY ).then( ( res ) => {
|
|
18
|
+
return formatResponse( res );
|
|
19
|
+
} ),
|
|
20
|
+
staleTime: Infinity,
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
export function useUpdateUnfilteredFilesUpload() {
|
|
24
|
+
const queryClient = useQueryClient();
|
|
25
|
+
|
|
26
|
+
const mutate = useMutation( {
|
|
27
|
+
mutationFn: ( { allowUnfilteredFilesUpload }: { allowUnfilteredFilesUpload: boolean } ) =>
|
|
28
|
+
apiClient.updateElementorSetting< Value >(
|
|
29
|
+
UNFILTERED_FILES_UPLOAD_KEY,
|
|
30
|
+
allowUnfilteredFilesUpload ? '1' : '0'
|
|
31
|
+
),
|
|
32
|
+
onSuccess: () => queryClient.invalidateQueries( unfilteredFilesQueryKey ),
|
|
33
|
+
} );
|
|
34
|
+
|
|
35
|
+
return mutate;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const formatResponse = ( response: Value ): boolean => {
|
|
39
|
+
return Boolean( response === '1' );
|
|
40
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { ToggleControl } from './controls/toggle-control';
|
|
|
11
11
|
export { NumberControl } from './controls/number-control';
|
|
12
12
|
export { EqualUnequalSizesControl } from './controls/equal-unequal-sizes-control';
|
|
13
13
|
export { LinkedDimensionsControl } from './controls/linked-dimensions-control';
|
|
14
|
-
export { FontFamilyControl } from './controls/font-family-control';
|
|
14
|
+
export { FontFamilyControl } from './controls/font-family-control/font-family-control';
|
|
15
15
|
export { UrlControl } from './controls/url-control';
|
|
16
16
|
export { LinkControl } from './controls/link-control';
|
|
17
17
|
export { GapControl } from './controls/gap-control';
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Fragment, useId, useState } from 'react';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { stringPropTypeUtil } from '@elementor/editor-props';
|
|
4
|
-
import { ChevronDownIcon, EditIcon, PhotoIcon, SearchIcon, XIcon } from '@elementor/icons';
|
|
5
|
-
import {
|
|
6
|
-
bindPopover,
|
|
7
|
-
bindTrigger,
|
|
8
|
-
Box,
|
|
9
|
-
Divider,
|
|
10
|
-
IconButton,
|
|
11
|
-
InputAdornment,
|
|
12
|
-
Link,
|
|
13
|
-
ListSubheader,
|
|
14
|
-
MenuItem,
|
|
15
|
-
MenuList,
|
|
16
|
-
Popover,
|
|
17
|
-
Stack,
|
|
18
|
-
TextField,
|
|
19
|
-
Typography,
|
|
20
|
-
UnstableTag,
|
|
21
|
-
usePopupState,
|
|
22
|
-
} from '@elementor/ui';
|
|
23
|
-
import { __ } from '@wordpress/i18n';
|
|
24
|
-
|
|
25
|
-
import { useBoundProp } from '../bound-prop-context';
|
|
26
|
-
import { createControl } from '../create-control';
|
|
27
|
-
import { useFilteredFontFamilies } from '../hooks/use-filtered-font-families';
|
|
28
|
-
|
|
29
|
-
const SIZE = 'tiny';
|
|
30
|
-
|
|
31
|
-
export const FontFamilyControl = createControl( ( { fontFamilies } ) => {
|
|
32
|
-
const [ searchValue, setSearchValue ] = useState( '' );
|
|
33
|
-
const { value: fontFamily, setValue: setFontFamily } = useBoundProp( stringPropTypeUtil );
|
|
34
|
-
|
|
35
|
-
const popupId = useId();
|
|
36
|
-
const popoverState = usePopupState( { variant: 'popover', popupId } );
|
|
37
|
-
|
|
38
|
-
const filteredFontFamilies = useFilteredFontFamilies( fontFamilies, searchValue );
|
|
39
|
-
|
|
40
|
-
if ( ! filteredFontFamilies ) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const handleSearch = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
45
|
-
setSearchValue( event.target.value );
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const handleClose = () => {
|
|
49
|
-
setSearchValue( '' );
|
|
50
|
-
|
|
51
|
-
popoverState.close();
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<>
|
|
56
|
-
<UnstableTag
|
|
57
|
-
variant="outlined"
|
|
58
|
-
label={ fontFamily }
|
|
59
|
-
endIcon={ <ChevronDownIcon fontSize="tiny" /> }
|
|
60
|
-
{ ...bindTrigger( popoverState ) }
|
|
61
|
-
fullWidth
|
|
62
|
-
/>
|
|
63
|
-
|
|
64
|
-
<Popover
|
|
65
|
-
disablePortal
|
|
66
|
-
disableScrollLock
|
|
67
|
-
anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
|
|
68
|
-
{ ...bindPopover( popoverState ) }
|
|
69
|
-
onClose={ handleClose }
|
|
70
|
-
>
|
|
71
|
-
<Stack>
|
|
72
|
-
<Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
|
|
73
|
-
<EditIcon fontSize={ SIZE } sx={ { mr: 0.5 } } />
|
|
74
|
-
<Typography variant="subtitle2">{ __( 'Font family', 'elementor' ) }</Typography>
|
|
75
|
-
<IconButton size={ SIZE } sx={ { ml: 'auto' } } onClick={ handleClose }>
|
|
76
|
-
<XIcon fontSize={ SIZE } />
|
|
77
|
-
</IconButton>
|
|
78
|
-
</Stack>
|
|
79
|
-
|
|
80
|
-
<Box px={ 1.5 } pb={ 1 }>
|
|
81
|
-
<TextField
|
|
82
|
-
fullWidth
|
|
83
|
-
size={ SIZE }
|
|
84
|
-
value={ searchValue }
|
|
85
|
-
placeholder={ __( 'Search fonts…', 'elementor' ) }
|
|
86
|
-
onChange={ handleSearch }
|
|
87
|
-
InputProps={ {
|
|
88
|
-
startAdornment: (
|
|
89
|
-
<InputAdornment position="start">
|
|
90
|
-
<SearchIcon fontSize={ SIZE } />
|
|
91
|
-
</InputAdornment>
|
|
92
|
-
),
|
|
93
|
-
} }
|
|
94
|
-
/>
|
|
95
|
-
</Box>
|
|
96
|
-
<Divider />
|
|
97
|
-
<Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
|
|
98
|
-
{ filteredFontFamilies.length > 0 ? (
|
|
99
|
-
<MenuList role="listbox" tabIndex={ 0 }>
|
|
100
|
-
{ filteredFontFamilies.map( ( [ category, items ], index ) => (
|
|
101
|
-
<Fragment key={ index }>
|
|
102
|
-
<ListSubheader
|
|
103
|
-
sx={ { px: 1.5, typography: 'caption', color: 'text.tertiary' } }
|
|
104
|
-
>
|
|
105
|
-
{ category }
|
|
106
|
-
</ListSubheader>
|
|
107
|
-
{ items.map( ( item ) => {
|
|
108
|
-
const isSelected = item === fontFamily;
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<MenuItem
|
|
112
|
-
key={ item }
|
|
113
|
-
selected={ isSelected }
|
|
114
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
115
|
-
autoFocus={ isSelected }
|
|
116
|
-
onClick={ () => {
|
|
117
|
-
setFontFamily( item );
|
|
118
|
-
handleClose();
|
|
119
|
-
} }
|
|
120
|
-
sx={ { px: 1.5, typography: 'caption' } }
|
|
121
|
-
style={ { fontFamily: item } }
|
|
122
|
-
>
|
|
123
|
-
{ item }
|
|
124
|
-
</MenuItem>
|
|
125
|
-
);
|
|
126
|
-
} ) }
|
|
127
|
-
</Fragment>
|
|
128
|
-
) ) }
|
|
129
|
-
</MenuList>
|
|
130
|
-
) : (
|
|
131
|
-
<Stack alignItems="center" p={ 2.5 } gap={ 1.5 }>
|
|
132
|
-
<PhotoIcon fontSize="large" />
|
|
133
|
-
<Typography align="center" variant="caption" color="text.secondary">
|
|
134
|
-
{ __( 'Sorry, nothing matched', 'elementor' ) }
|
|
135
|
-
<br />
|
|
136
|
-
“{ searchValue }”.
|
|
137
|
-
</Typography>
|
|
138
|
-
<Typography align="center" variant="caption" color="text.secondary">
|
|
139
|
-
<Link
|
|
140
|
-
color="secondary"
|
|
141
|
-
variant="caption"
|
|
142
|
-
component="button"
|
|
143
|
-
onClick={ () => setSearchValue( '' ) }
|
|
144
|
-
>
|
|
145
|
-
{ __( 'Clear the filters', 'elementor' ) }
|
|
146
|
-
</Link>
|
|
147
|
-
|
|
148
|
-
{ __( 'and try again.', 'elementor' ) }
|
|
149
|
-
</Typography>
|
|
150
|
-
</Stack>
|
|
151
|
-
) }
|
|
152
|
-
</Box>
|
|
153
|
-
</Stack>
|
|
154
|
-
</Popover>
|
|
155
|
-
</>
|
|
156
|
-
);
|
|
157
|
-
} );
|