@elementor/editor-controls 4.4.0-1084 → 4.4.0-1086
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/dist/index.js +921 -786
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +775 -629
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -16
- package/src/controls/icon-library/font-awesome-7-catalog.ts +14 -5
- package/src/controls/icon-library/icon-library-filter.tsx +159 -0
- package/src/controls/icon-library/icon-library-popover.tsx +55 -20
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": "4.4.0-
|
|
4
|
+
"version": "4.4.0-1086",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,23 +40,23 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor-current-user": "4.4.0-
|
|
44
|
-
"@elementor/editor-elements": "4.4.0-
|
|
45
|
-
"@elementor/editor-props": "4.4.0-
|
|
46
|
-
"@elementor/editor-responsive": "4.4.0-
|
|
47
|
-
"@elementor/editor-ui": "4.4.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "4.4.0-
|
|
49
|
-
"@elementor/env": "4.4.0-
|
|
50
|
-
"@elementor/events": "4.4.0-
|
|
51
|
-
"@elementor/http-client": "4.4.0-
|
|
43
|
+
"@elementor/editor-current-user": "4.4.0-1086",
|
|
44
|
+
"@elementor/editor-elements": "4.4.0-1086",
|
|
45
|
+
"@elementor/editor-props": "4.4.0-1086",
|
|
46
|
+
"@elementor/editor-responsive": "4.4.0-1086",
|
|
47
|
+
"@elementor/editor-ui": "4.4.0-1086",
|
|
48
|
+
"@elementor/editor-v1-adapters": "4.4.0-1086",
|
|
49
|
+
"@elementor/env": "4.4.0-1086",
|
|
50
|
+
"@elementor/events": "4.4.0-1086",
|
|
51
|
+
"@elementor/http-client": "4.4.0-1086",
|
|
52
52
|
"@elementor/icons": "~1.75.1",
|
|
53
|
-
"@elementor/locations": "4.4.0-
|
|
54
|
-
"@elementor/query": "4.4.0-
|
|
55
|
-
"@elementor/schema": "4.4.0-
|
|
56
|
-
"@elementor/session": "4.4.0-
|
|
53
|
+
"@elementor/locations": "4.4.0-1086",
|
|
54
|
+
"@elementor/query": "4.4.0-1086",
|
|
55
|
+
"@elementor/schema": "4.4.0-1086",
|
|
56
|
+
"@elementor/session": "4.4.0-1086",
|
|
57
57
|
"@elementor/ui": "1.37.5",
|
|
58
|
-
"@elementor/utils": "4.4.0-
|
|
59
|
-
"@elementor/wp-media": "4.4.0-
|
|
58
|
+
"@elementor/utils": "4.4.0-1086",
|
|
59
|
+
"@elementor/wp-media": "4.4.0-1086",
|
|
60
60
|
"@monaco-editor/react": "^4.7.0",
|
|
61
61
|
"@tiptap/extension-bold": "^3.11.1",
|
|
62
62
|
"@tiptap/extension-document": "^3.11.1",
|
|
@@ -8,10 +8,13 @@ import {
|
|
|
8
8
|
|
|
9
9
|
export { FONT_AWESOME_7_LIBRARIES, getFontAwesome7EditorConfig } from './font-awesome-7-data';
|
|
10
10
|
|
|
11
|
+
export type FontAwesome7Library = ( typeof FONT_AWESOME_7_LIBRARIES )[ number ][ 'library' ];
|
|
12
|
+
export type FontAwesome7LibraryFilter = FontAwesome7Library[];
|
|
13
|
+
|
|
11
14
|
export type FontAwesome7Icon = FontAwesome7IconDefinition & {
|
|
12
15
|
id: string;
|
|
13
16
|
label: string;
|
|
14
|
-
library:
|
|
17
|
+
library: FontAwesome7Library;
|
|
15
18
|
value: string;
|
|
16
19
|
};
|
|
17
20
|
|
|
@@ -37,14 +40,20 @@ export async function loadFontAwesome7Catalog( signal?: AbortSignal ): Promise<
|
|
|
37
40
|
return catalogs.flat();
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
export function filterFontAwesome7Icons(
|
|
43
|
+
export function filterFontAwesome7Icons(
|
|
44
|
+
icons: FontAwesome7Icon[],
|
|
45
|
+
searchValue?: string | null,
|
|
46
|
+
libraries: FontAwesome7LibraryFilter = []
|
|
47
|
+
): FontAwesome7Icon[] {
|
|
41
48
|
const query = searchValue?.trim().toLowerCase() ?? '';
|
|
49
|
+
const libraryIcons =
|
|
50
|
+
libraries.length === 0 ? icons : icons.filter( ( icon ) => libraries.includes( icon.library ) );
|
|
42
51
|
|
|
43
52
|
if ( query === '' ) {
|
|
44
|
-
return
|
|
53
|
+
return libraryIcons;
|
|
45
54
|
}
|
|
46
55
|
|
|
47
|
-
return
|
|
56
|
+
return libraryIcons.filter( ( icon ) => {
|
|
48
57
|
if ( icon.name.includes( query ) || icon.label.toLowerCase().includes( query ) ) {
|
|
49
58
|
return true;
|
|
50
59
|
}
|
|
@@ -93,7 +102,7 @@ export function findFontAwesome7Icon(
|
|
|
93
102
|
} );
|
|
94
103
|
}
|
|
95
104
|
|
|
96
|
-
function toCatalogIcon( icon: FontAwesome7IconDefinition, library:
|
|
105
|
+
function toCatalogIcon( icon: FontAwesome7IconDefinition, library: FontAwesome7Library ): FontAwesome7Icon {
|
|
97
106
|
return {
|
|
98
107
|
...icon,
|
|
99
108
|
id: `${ library }:${ icon.name }`,
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { CheckIcon, FilterIcon, LibraryIcon, ListIcon, StarFilledIcon, StarIcon } from '@elementor/icons';
|
|
4
|
+
import {
|
|
5
|
+
bindMenu,
|
|
6
|
+
bindToggle,
|
|
7
|
+
Box,
|
|
8
|
+
Menu,
|
|
9
|
+
MenuItem,
|
|
10
|
+
Stack,
|
|
11
|
+
ToggleButton,
|
|
12
|
+
Tooltip,
|
|
13
|
+
Typography,
|
|
14
|
+
usePopupState,
|
|
15
|
+
} from '@elementor/ui';
|
|
16
|
+
import { __ } from '@wordpress/i18n';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
FONT_AWESOME_7_LIBRARIES,
|
|
20
|
+
type FontAwesome7Library,
|
|
21
|
+
type FontAwesome7LibraryFilter,
|
|
22
|
+
} from './font-awesome-7-catalog';
|
|
23
|
+
|
|
24
|
+
const FILTER_MENU_WIDTH = 280;
|
|
25
|
+
const FILTER_INDICATOR_SIZE = 6;
|
|
26
|
+
const FILTER_INDICATOR_OFFSET = 4;
|
|
27
|
+
const LIBRARY_FILTER_ORDER = {
|
|
28
|
+
regular: 0,
|
|
29
|
+
solid: 1,
|
|
30
|
+
brands: 2,
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
const LIBRARY_FILTER_CONFIG: Record<
|
|
34
|
+
FontAwesome7Library,
|
|
35
|
+
{ getLabel: () => string; Icon: typeof StarIcon; order: number }
|
|
36
|
+
> = {
|
|
37
|
+
'fa-regular': {
|
|
38
|
+
getLabel: () => __( 'Font Awesome - Regular', 'elementor' ),
|
|
39
|
+
Icon: StarIcon,
|
|
40
|
+
order: LIBRARY_FILTER_ORDER.regular,
|
|
41
|
+
},
|
|
42
|
+
'fa-solid': {
|
|
43
|
+
getLabel: () => __( 'Font Awesome - Solid', 'elementor' ),
|
|
44
|
+
Icon: StarFilledIcon,
|
|
45
|
+
order: LIBRARY_FILTER_ORDER.solid,
|
|
46
|
+
},
|
|
47
|
+
'fa-brands': {
|
|
48
|
+
getLabel: () => __( 'Font Awesome - Brands', 'elementor' ),
|
|
49
|
+
Icon: LibraryIcon,
|
|
50
|
+
order: LIBRARY_FILTER_ORDER.brands,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type IconLibraryFilterProps = {
|
|
55
|
+
value: FontAwesome7LibraryFilter;
|
|
56
|
+
onChange: ( value: FontAwesome7LibraryFilter ) => void;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const IconLibraryFilter = ( { value, onChange }: IconLibraryFilterProps ) => {
|
|
60
|
+
const popupId = useId();
|
|
61
|
+
const popupState = usePopupState( {
|
|
62
|
+
variant: 'popover',
|
|
63
|
+
popupId,
|
|
64
|
+
} );
|
|
65
|
+
const options = FONT_AWESOME_7_LIBRARIES.map( ( { library } ) => ( {
|
|
66
|
+
value: library,
|
|
67
|
+
label: LIBRARY_FILTER_CONFIG[ library ].getLabel(),
|
|
68
|
+
Icon: LIBRARY_FILTER_CONFIG[ library ].Icon,
|
|
69
|
+
order: LIBRARY_FILTER_CONFIG[ library ].order,
|
|
70
|
+
} ) ).sort( ( firstOption, secondOption ) => firstOption.order - secondOption.order );
|
|
71
|
+
const isFiltered = value.length > 0;
|
|
72
|
+
const filterButtonLabel = isFiltered
|
|
73
|
+
? __( 'Filter by library, active', 'elementor' )
|
|
74
|
+
: __( 'Filter by library', 'elementor' );
|
|
75
|
+
|
|
76
|
+
const handleAllIconsClick = () => {
|
|
77
|
+
onChange( [] );
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleLibraryClick = ( library: FontAwesome7Library ) => {
|
|
81
|
+
const nextValue = value.includes( library )
|
|
82
|
+
? value.filter( ( selectedLibrary ) => selectedLibrary !== library )
|
|
83
|
+
: [ ...value, library ];
|
|
84
|
+
|
|
85
|
+
onChange( nextValue.length === FONT_AWESOME_7_LIBRARIES.length ? [] : nextValue );
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
<Tooltip title={ __( 'Filter by library', 'elementor' ) } placement="top">
|
|
91
|
+
<ToggleButton
|
|
92
|
+
aria-label={ filterButtonLabel }
|
|
93
|
+
value="filter"
|
|
94
|
+
size="tiny"
|
|
95
|
+
selected={ popupState.isOpen }
|
|
96
|
+
sx={ { position: 'relative', flexShrink: 0 } }
|
|
97
|
+
{ ...bindToggle( popupState ) }
|
|
98
|
+
aria-expanded={ popupState.isOpen }
|
|
99
|
+
>
|
|
100
|
+
<FilterIcon fontSize="tiny" />
|
|
101
|
+
{ isFiltered ? (
|
|
102
|
+
<Box
|
|
103
|
+
component="span"
|
|
104
|
+
aria-hidden="true"
|
|
105
|
+
sx={ {
|
|
106
|
+
position: 'absolute',
|
|
107
|
+
insetBlockStart: FILTER_INDICATOR_OFFSET,
|
|
108
|
+
insetInlineEnd: FILTER_INDICATOR_OFFSET,
|
|
109
|
+
width: FILTER_INDICATOR_SIZE,
|
|
110
|
+
height: FILTER_INDICATOR_SIZE,
|
|
111
|
+
borderRadius: '50%',
|
|
112
|
+
bgcolor: 'secondary.main',
|
|
113
|
+
} }
|
|
114
|
+
/>
|
|
115
|
+
) : null }
|
|
116
|
+
</ToggleButton>
|
|
117
|
+
</Tooltip>
|
|
118
|
+
<Menu
|
|
119
|
+
{ ...bindMenu( popupState ) }
|
|
120
|
+
MenuListProps={ {
|
|
121
|
+
dense: true,
|
|
122
|
+
autoFocusItem: true,
|
|
123
|
+
'aria-label': __( 'Filter by library', 'elementor' ),
|
|
124
|
+
} }
|
|
125
|
+
sx={ { '& .MuiPaper-root': { minWidth: FILTER_MENU_WIDTH } } }
|
|
126
|
+
>
|
|
127
|
+
<MenuItem
|
|
128
|
+
role="menuitemcheckbox"
|
|
129
|
+
aria-checked={ ! isFiltered }
|
|
130
|
+
selected={ ! isFiltered }
|
|
131
|
+
onClick={ handleAllIconsClick }
|
|
132
|
+
>
|
|
133
|
+
{ renderFilterMenuItemContent( __( 'All icons', 'elementor' ), ListIcon, ! isFiltered ) }
|
|
134
|
+
</MenuItem>
|
|
135
|
+
{ options.map( ( { value: library, label, Icon } ) => (
|
|
136
|
+
<MenuItem
|
|
137
|
+
key={ library }
|
|
138
|
+
role="menuitemcheckbox"
|
|
139
|
+
aria-checked={ value.includes( library ) }
|
|
140
|
+
selected={ value.includes( library ) }
|
|
141
|
+
onClick={ () => handleLibraryClick( library ) }
|
|
142
|
+
>
|
|
143
|
+
{ renderFilterMenuItemContent( label, Icon, value.includes( library ) ) }
|
|
144
|
+
</MenuItem>
|
|
145
|
+
) ) }
|
|
146
|
+
</Menu>
|
|
147
|
+
</>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const renderFilterMenuItemContent = ( label: string, Icon: typeof ListIcon, selected: boolean ) => (
|
|
152
|
+
<Stack direction="row" alignItems="center" gap={ 1 } width="100%">
|
|
153
|
+
<Icon fontSize="tiny" />
|
|
154
|
+
<Typography variant="caption" sx={ { flex: 1 } }>
|
|
155
|
+
{ label }
|
|
156
|
+
</Typography>
|
|
157
|
+
{ selected ? <CheckIcon fontSize="tiny" /> : null }
|
|
158
|
+
</Stack>
|
|
159
|
+
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
PopoverBody,
|
|
5
5
|
PopoverHeader,
|
|
@@ -18,8 +18,10 @@ import {
|
|
|
18
18
|
filterFontAwesome7Icons,
|
|
19
19
|
findFontAwesome7Icon,
|
|
20
20
|
type FontAwesome7Icon,
|
|
21
|
+
type FontAwesome7LibraryFilter,
|
|
21
22
|
} from './font-awesome-7-catalog';
|
|
22
23
|
import { FontAwesomeGlyph } from './font-awesome-glyph';
|
|
24
|
+
import { IconLibraryFilter } from './icon-library-filter';
|
|
23
25
|
import { useFontAwesome7Catalog } from './use-font-awesome-7-catalog';
|
|
24
26
|
|
|
25
27
|
export const ICON_LIBRARY_POPOVER_WIDTH = 300;
|
|
@@ -60,9 +62,13 @@ export const IconLibraryPopover = ( {
|
|
|
60
62
|
handleChange: handleSearchChange,
|
|
61
63
|
setImmediateValue: setSearchValue,
|
|
62
64
|
} = useDebounceState( { delay: ICON_LIBRARY_SEARCH_DEBOUNCE_DELAY } );
|
|
65
|
+
const [ activeLibraries, setActiveLibraries ] = useState< FontAwesome7LibraryFilter >( [] );
|
|
63
66
|
const { data: icons = [], isLoading } = useFontAwesome7Catalog( open );
|
|
64
67
|
|
|
65
|
-
const items = useMemo(
|
|
68
|
+
const items = useMemo(
|
|
69
|
+
() => createIconLibraryItems( icons, searchValue, activeLibraries ),
|
|
70
|
+
[ activeLibraries, icons, searchValue ]
|
|
71
|
+
);
|
|
66
72
|
const selectedValue = useMemo(
|
|
67
73
|
() => findFontAwesome7Icon( icons, selectedIconClass, selectedIconLibrary )?.id,
|
|
68
74
|
[ icons, selectedIconClass, selectedIconLibrary ]
|
|
@@ -70,6 +76,7 @@ export const IconLibraryPopover = ( {
|
|
|
70
76
|
|
|
71
77
|
const handleClose = () => {
|
|
72
78
|
setSearchValue( '' );
|
|
79
|
+
setActiveLibraries( [] );
|
|
73
80
|
onClose();
|
|
74
81
|
};
|
|
75
82
|
|
|
@@ -98,13 +105,16 @@ export const IconLibraryPopover = ( {
|
|
|
98
105
|
icon={ <ComponentsIcon fontSize="tiny" /> }
|
|
99
106
|
sx={ { pl: ICON_LIBRARY_INLINE_SPACING, pr: 0.5 } }
|
|
100
107
|
/>
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
<Stack direction="row" alignItems="center" gap={ 1 } sx={ { px: ICON_LIBRARY_INLINE_SPACING, pb: 1 } }>
|
|
109
|
+
<SearchField
|
|
110
|
+
value={ searchInputValue }
|
|
111
|
+
onSearch={ handleSearchChange }
|
|
112
|
+
placeholder={ __( 'Search', 'elementor' ) }
|
|
113
|
+
id="icon-library-search"
|
|
114
|
+
sx={ { flex: 1, px: 0, pb: 0 } }
|
|
115
|
+
/>
|
|
116
|
+
<IconLibraryFilter value={ activeLibraries } onChange={ setActiveLibraries } />
|
|
117
|
+
</Stack>
|
|
108
118
|
<Divider />
|
|
109
119
|
<Box sx={ { flex: 1, overflow: 'auto', minHeight: 0 } }>
|
|
110
120
|
<IconLibraryContent
|
|
@@ -112,6 +122,7 @@ export const IconLibraryPopover = ( {
|
|
|
112
122
|
items={ items }
|
|
113
123
|
selectedValue={ selectedValue }
|
|
114
124
|
searchValue={ searchValue }
|
|
125
|
+
isCatalogAvailable={ icons.length > 0 }
|
|
115
126
|
onSelect={ handleSelect }
|
|
116
127
|
onClose={ handleClose }
|
|
117
128
|
onClearSearch={ handleClearSearch }
|
|
@@ -126,6 +137,7 @@ type IconLibraryContentProps = {
|
|
|
126
137
|
items: IconLibraryItem[];
|
|
127
138
|
selectedValue: string | undefined;
|
|
128
139
|
searchValue: string;
|
|
140
|
+
isCatalogAvailable: boolean;
|
|
129
141
|
onSelect: ( id: string ) => void;
|
|
130
142
|
onClose: () => void;
|
|
131
143
|
onClearSearch: () => void;
|
|
@@ -136,6 +148,7 @@ const IconLibraryContent = ( {
|
|
|
136
148
|
items,
|
|
137
149
|
selectedValue,
|
|
138
150
|
searchValue,
|
|
151
|
+
isCatalogAvailable,
|
|
139
152
|
onSelect,
|
|
140
153
|
onClose,
|
|
141
154
|
onClearSearch,
|
|
@@ -153,7 +166,13 @@ const IconLibraryContent = ( {
|
|
|
153
166
|
onClose={ onClose }
|
|
154
167
|
itemHeight={ ICON_LIBRARY_ROW_HEIGHT }
|
|
155
168
|
menuItemContentTemplate={ IconLibraryRow }
|
|
156
|
-
noResultsComponent={
|
|
169
|
+
noResultsComponent={
|
|
170
|
+
<IconLibraryEmptyState
|
|
171
|
+
searchValue={ searchValue }
|
|
172
|
+
isCatalogAvailable={ isCatalogAvailable }
|
|
173
|
+
onClear={ onClearSearch }
|
|
174
|
+
/>
|
|
175
|
+
}
|
|
157
176
|
data-testid="icon-library-list"
|
|
158
177
|
/>
|
|
159
178
|
);
|
|
@@ -165,8 +184,16 @@ const IconLibraryLoadingState = () => (
|
|
|
165
184
|
</Stack>
|
|
166
185
|
);
|
|
167
186
|
|
|
168
|
-
const IconLibraryEmptyState = ( {
|
|
169
|
-
|
|
187
|
+
const IconLibraryEmptyState = ( {
|
|
188
|
+
searchValue,
|
|
189
|
+
isCatalogAvailable,
|
|
190
|
+
onClear,
|
|
191
|
+
}: {
|
|
192
|
+
searchValue: string;
|
|
193
|
+
isCatalogAvailable: boolean;
|
|
194
|
+
onClear: () => void;
|
|
195
|
+
} ) => {
|
|
196
|
+
if ( ! isCatalogAvailable ) {
|
|
170
197
|
return <CatalogUnavailable />;
|
|
171
198
|
}
|
|
172
199
|
|
|
@@ -218,17 +245,25 @@ const NoResults = ( { searchValue, onClear }: { searchValue: string; onClear: ()
|
|
|
218
245
|
<Typography align="center" variant="subtitle2" color="text.secondary">
|
|
219
246
|
{ __( 'Sorry, nothing matched', 'elementor' ) }
|
|
220
247
|
</Typography>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
248
|
+
{ searchValue ? (
|
|
249
|
+
<>
|
|
250
|
+
<Typography align="center" variant="subtitle2" color="text.secondary" noWrap sx={ { maxWidth: '80%' } }>
|
|
251
|
+
“{ searchValue }”.
|
|
252
|
+
</Typography>
|
|
253
|
+
<Link color="secondary" variant="caption" component="button" type="button" onClick={ onClear }>
|
|
254
|
+
{ __( 'Clear & try again', 'elementor' ) }
|
|
255
|
+
</Link>
|
|
256
|
+
</>
|
|
257
|
+
) : null }
|
|
227
258
|
</Stack>
|
|
228
259
|
);
|
|
229
260
|
|
|
230
|
-
const createIconLibraryItems = (
|
|
231
|
-
|
|
261
|
+
const createIconLibraryItems = (
|
|
262
|
+
icons: FontAwesome7Icon[],
|
|
263
|
+
searchValue: string,
|
|
264
|
+
libraries: FontAwesome7LibraryFilter
|
|
265
|
+
): IconLibraryItem[] =>
|
|
266
|
+
filterFontAwesome7Icons( icons, searchValue, libraries ).map( ( icon ) => ( {
|
|
232
267
|
...icon,
|
|
233
268
|
type: 'item',
|
|
234
269
|
value: icon.id,
|