@elementor/editor-controls 4.4.0-1077 → 4.4.0-1078
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.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +1400 -837
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1297 -741
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -16
- package/src/controls/icon-library/font-awesome-7-catalog.ts +104 -0
- package/src/controls/icon-library/font-awesome-7-data.ts +260 -0
- package/src/controls/icon-library/font-awesome-glyph.tsx +30 -0
- package/src/controls/icon-library/get-icon-library-anchor.ts +29 -0
- package/src/controls/icon-library/icon-library-popover.tsx +228 -0
- package/src/controls/icon-library/use-font-awesome-7-catalog.ts +14 -0
- package/src/controls/svg-media-control.tsx +132 -159
- package/src/controls/svg-media-overlay.tsx +137 -0
- package/src/controls/svg-media-preview.tsx +68 -0
- package/src/index.ts +6 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useQuery } from '@elementor/query';
|
|
2
|
+
|
|
3
|
+
import { type FontAwesome7Icon, loadFontAwesome7Catalog } from './font-awesome-7-catalog';
|
|
4
|
+
|
|
5
|
+
const FONT_AWESOME_7_CATALOG_QUERY_KEY = [ 'font-awesome-7-catalog' ];
|
|
6
|
+
|
|
7
|
+
export function useFontAwesome7Catalog( enabled: boolean ) {
|
|
8
|
+
return useQuery< FontAwesome7Icon[] >( {
|
|
9
|
+
queryKey: FONT_AWESOME_7_CATALOG_QUERY_KEY,
|
|
10
|
+
queryFn: ( { signal } ) => loadFontAwesome7Catalog( signal ),
|
|
11
|
+
enabled,
|
|
12
|
+
staleTime: Infinity,
|
|
13
|
+
} );
|
|
14
|
+
}
|
|
@@ -1,43 +1,29 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { useCurrentUserCapabilities } from '@elementor/editor-current-user';
|
|
4
4
|
import { iconPropTypeUtil, svgSrcPropTypeUtil, urlPropTypeUtil } from '@elementor/editor-props';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
Box,
|
|
8
|
-
Button,
|
|
9
|
-
Card,
|
|
10
|
-
CardMedia,
|
|
11
|
-
CardOverlay,
|
|
12
|
-
CircularProgress,
|
|
13
|
-
Stack,
|
|
14
|
-
styled,
|
|
15
|
-
ThemeProvider,
|
|
16
|
-
} from '@elementor/ui';
|
|
5
|
+
import { Box, Card, CardOverlay, Popover, Stack, styled, usePopupState } from '@elementor/ui';
|
|
17
6
|
import { type OpenOptions, useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
18
7
|
import { __ } from '@wordpress/i18n';
|
|
19
8
|
|
|
20
9
|
import { useBoundProp } from '../bound-prop-context';
|
|
21
|
-
import { ConditionalControlInfotip } from '../components/conditional-control-infotip';
|
|
22
10
|
import { EnableUnfilteredModal } from '../components/enable-unfiltered-modal';
|
|
23
11
|
import ControlActions from '../control-actions/control-actions';
|
|
24
12
|
import { createControl } from '../create-control';
|
|
25
13
|
import { useUnfilteredFilesUpload } from '../hooks/use-unfiltered-files-upload';
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
openIconLibrary,
|
|
32
|
-
} from './open-icon-library';
|
|
14
|
+
import { type IconLibraryAnchor, measureIconLibraryAnchor } from './icon-library/get-icon-library-anchor';
|
|
15
|
+
import { ICON_LIBRARY_POPOVER_WIDTH, IconLibraryPopover } from './icon-library/icon-library-popover';
|
|
16
|
+
import { createIconPropValue } from './open-icon-library';
|
|
17
|
+
import { SVG_MEDIA_CONTROL_CONTAINER_TEST_ID, SvgMediaOverlay } from './svg-media-overlay';
|
|
18
|
+
import { SvgMediaPreview } from './svg-media-preview';
|
|
33
19
|
|
|
34
20
|
const TILE_SIZE = 8;
|
|
35
21
|
const TILE_WHITE = 'transparent';
|
|
36
22
|
const TILE_BLACK = '#c1c1c1';
|
|
37
|
-
const ICON_PREVIEW_FONT_SIZE = 50;
|
|
38
23
|
export const TILES_GRADIENT_FORMULA = `linear-gradient(45deg, ${ TILE_BLACK } 25%, ${ TILE_WHITE } 0, ${ TILE_WHITE } 75%, ${ TILE_BLACK } 0, ${ TILE_BLACK })`;
|
|
39
24
|
|
|
40
25
|
const StyledCard = styled( Card )`
|
|
26
|
+
position: relative;
|
|
41
27
|
background-color: white;
|
|
42
28
|
background-image: ${ TILES_GRADIENT_FORMULA }, ${ TILES_GRADIENT_FORMULA };
|
|
43
29
|
background-size: ${ TILE_SIZE }px ${ TILE_SIZE }px;
|
|
@@ -47,6 +33,8 @@ const StyledCard = styled( Card )`
|
|
|
47
33
|
border: none;
|
|
48
34
|
`;
|
|
49
35
|
|
|
36
|
+
const PREVIEW_ICON_COLOR = '#000000';
|
|
37
|
+
|
|
50
38
|
const StyledCardMediaContainer = styled( Stack )`
|
|
51
39
|
position: relative;
|
|
52
40
|
height: 140px;
|
|
@@ -55,6 +43,7 @@ const StyledCardMediaContainer = styled( Stack )`
|
|
|
55
43
|
justify-content: center;
|
|
56
44
|
align-items: center;
|
|
57
45
|
background-color: rgba( 255, 255, 255, 0.37 );
|
|
46
|
+
color: ${ PREVIEW_ICON_COLOR };
|
|
58
47
|
`;
|
|
59
48
|
|
|
60
49
|
const MODE_BROWSE: OpenOptions = { mode: 'browse' };
|
|
@@ -73,6 +62,10 @@ export const SvgMediaControl = createControl( ( { showIconLibrary = false }: Svg
|
|
|
73
62
|
const src = attachment?.url ?? url?.value ?? null;
|
|
74
63
|
const { data: allowSvgUpload } = useUnfilteredFilesUpload();
|
|
75
64
|
const [ unfilteredModalOpenState, setUnfilteredModalOpenState ] = useState( false );
|
|
65
|
+
const iconLibraryPopoverState = usePopupState( { variant: 'popover' } );
|
|
66
|
+
const controlContainerRef = useRef< HTMLDivElement >( null );
|
|
67
|
+
const buttonGroupRef = useRef< HTMLDivElement >( null );
|
|
68
|
+
const [ iconLibraryAnchor, setIconLibraryAnchor ] = useState< IconLibraryAnchor | null >( null );
|
|
76
69
|
const { isAdmin } = useCurrentUserCapabilities();
|
|
77
70
|
const selectedIconClass =
|
|
78
71
|
showIconLibrary && typeof iconValue?.value?.value === 'string' ? iconValue.value.value : null;
|
|
@@ -94,7 +87,7 @@ export const SvgMediaControl = createControl( ( { showIconLibrary = false }: Svg
|
|
|
94
87
|
},
|
|
95
88
|
} );
|
|
96
89
|
|
|
97
|
-
const
|
|
90
|
+
const handleCloseUnfilteredModal = ( enabled: boolean ) => {
|
|
98
91
|
setUnfilteredModalOpenState( false );
|
|
99
92
|
|
|
100
93
|
if ( enabled ) {
|
|
@@ -110,152 +103,132 @@ export const SvgMediaControl = createControl( ( { showIconLibrary = false }: Svg
|
|
|
110
103
|
}
|
|
111
104
|
};
|
|
112
105
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
if ( isSvgLibrarySelection( icon ) ) {
|
|
118
|
-
setSvgValue( {
|
|
119
|
-
id: icon.value.id
|
|
120
|
-
? {
|
|
121
|
-
$$type: 'image-attachment-id',
|
|
122
|
-
value: icon.value.id,
|
|
123
|
-
}
|
|
124
|
-
: null,
|
|
125
|
-
url: icon.value.url ? urlPropTypeUtil.create( icon.value.url ) : null,
|
|
126
|
-
} );
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
106
|
+
const handleSelectSvg = () => {
|
|
107
|
+
handleClick( MODE_BROWSE );
|
|
108
|
+
};
|
|
129
109
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
110
|
+
const handleUpload = () => {
|
|
111
|
+
handleClick( MODE_UPLOAD );
|
|
133
112
|
};
|
|
134
113
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<>
|
|
139
|
-
{ __( 'To upload them anyway, ask the site administrator to enable unfiltered', 'elementor' ) }
|
|
140
|
-
<br />
|
|
141
|
-
{ __( 'file uploads.', 'elementor' ) }
|
|
142
|
-
</>
|
|
143
|
-
),
|
|
144
|
-
isEnabled: ! isAdmin,
|
|
114
|
+
const handleCloseIconLibrary = () => {
|
|
115
|
+
iconLibraryPopoverState.close();
|
|
116
|
+
setIconLibraryAnchor( null );
|
|
145
117
|
};
|
|
146
118
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
sx={ {
|
|
162
|
-
'&:hover': {
|
|
163
|
-
backgroundColor: 'rgba( 0, 0, 0, 0.75 )',
|
|
164
|
-
},
|
|
165
|
-
} }
|
|
166
|
-
>
|
|
167
|
-
<Stack gap={ 1 }>
|
|
168
|
-
<Button
|
|
169
|
-
size="tiny"
|
|
170
|
-
color="inherit"
|
|
171
|
-
variant="outlined"
|
|
172
|
-
onClick={ () => handleClick( MODE_BROWSE ) }
|
|
173
|
-
aria-label="Select SVG"
|
|
174
|
-
>
|
|
175
|
-
{ __( 'Select SVG', 'elementor' ) }
|
|
176
|
-
</Button>
|
|
177
|
-
{ showIconLibrary ? (
|
|
178
|
-
<Button
|
|
179
|
-
size="tiny"
|
|
180
|
-
variant="text"
|
|
181
|
-
color="inherit"
|
|
182
|
-
onClick={ () =>
|
|
183
|
-
openIconLibrary( {
|
|
184
|
-
selected:
|
|
185
|
-
selectedIconClass && selectedIconLibrary
|
|
186
|
-
? { value: selectedIconClass, library: selectedIconLibrary }
|
|
187
|
-
: undefined,
|
|
188
|
-
onSelect: handleIconLibrarySelect,
|
|
189
|
-
} )
|
|
190
|
-
}
|
|
191
|
-
aria-label={ __( 'Icon library', 'elementor' ) }
|
|
192
|
-
>
|
|
193
|
-
{ __( 'Icon library', 'elementor' ) }
|
|
194
|
-
</Button>
|
|
195
|
-
) : null }
|
|
196
|
-
<ConditionalControlInfotip { ...infotipProps }>
|
|
197
|
-
<span>
|
|
198
|
-
<ThemeProvider colorScheme={ isAdmin ? 'light' : 'dark' }>
|
|
199
|
-
<Button
|
|
200
|
-
size="tiny"
|
|
201
|
-
variant="text"
|
|
202
|
-
color="inherit"
|
|
203
|
-
startIcon={ <UploadIcon /> }
|
|
204
|
-
disabled={ ! isAdmin }
|
|
205
|
-
onClick={ () => isAdmin && handleClick( MODE_UPLOAD ) }
|
|
206
|
-
aria-label="Upload SVG"
|
|
207
|
-
>
|
|
208
|
-
{ __( 'Upload', 'elementor' ) }
|
|
209
|
-
</Button>
|
|
210
|
-
</ThemeProvider>
|
|
211
|
-
</span>
|
|
212
|
-
</ConditionalControlInfotip>
|
|
213
|
-
</Stack>
|
|
214
|
-
</CardOverlay>
|
|
215
|
-
</StyledCard>
|
|
216
|
-
</ControlActions>
|
|
217
|
-
</Stack>
|
|
218
|
-
);
|
|
219
|
-
} );
|
|
119
|
+
const handleIconLibrarySelect = ( icon: { value: string; library: string } ) => {
|
|
120
|
+
setIconValue( createIconPropValue( icon.value, icon.library ) );
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const handleOpenIconLibrary = ( event: React.MouseEvent< HTMLElement > ) => {
|
|
124
|
+
const anchor = measureIconLibraryAnchor( controlContainerRef.current, buttonGroupRef.current );
|
|
125
|
+
|
|
126
|
+
if ( ! anchor ) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
setIconLibraryAnchor( anchor );
|
|
131
|
+
iconLibraryPopoverState.open( event );
|
|
132
|
+
};
|
|
220
133
|
|
|
221
|
-
function SvgMediaPreview( {
|
|
222
|
-
isFetching,
|
|
223
|
-
src,
|
|
224
|
-
iconClassName,
|
|
225
|
-
iconLibrary,
|
|
226
|
-
}: {
|
|
227
|
-
isFetching: boolean;
|
|
228
|
-
src: string | null;
|
|
229
|
-
iconClassName: string | null;
|
|
230
|
-
iconLibrary: string | null;
|
|
231
|
-
} ) {
|
|
232
134
|
useEffect( () => {
|
|
233
|
-
if (
|
|
234
|
-
|
|
135
|
+
if ( ! iconLibraryPopoverState.isOpen ) {
|
|
136
|
+
return;
|
|
235
137
|
}
|
|
236
|
-
}, [ iconLibrary ] );
|
|
237
138
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
139
|
+
const handleResize = () => {
|
|
140
|
+
const nextAnchor = measureIconLibraryAnchor( controlContainerRef.current, buttonGroupRef.current );
|
|
241
141
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
142
|
+
if ( nextAnchor ) {
|
|
143
|
+
setIconLibraryAnchor( nextAnchor );
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
window.addEventListener( 'resize', handleResize );
|
|
148
|
+
|
|
149
|
+
return () => {
|
|
150
|
+
window.removeEventListener( 'resize', handleResize );
|
|
151
|
+
};
|
|
152
|
+
}, [ iconLibraryPopoverState.isOpen ] );
|
|
153
|
+
|
|
154
|
+
const iconLibraryWidth = iconLibraryAnchor?.width ?? ICON_LIBRARY_POPOVER_WIDTH;
|
|
252
155
|
|
|
253
156
|
return (
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
157
|
+
<Stack gap={ 1 } aria-label={ __( 'SVG control', 'elementor' ) }>
|
|
158
|
+
<EnableUnfilteredModal open={ unfilteredModalOpenState } onClose={ handleCloseUnfilteredModal } />
|
|
159
|
+
{ showIconLibrary && iconLibraryAnchor ? (
|
|
160
|
+
<Popover
|
|
161
|
+
disableScrollLock
|
|
162
|
+
open={ iconLibraryPopoverState.isOpen }
|
|
163
|
+
onClose={ handleCloseIconLibrary }
|
|
164
|
+
anchorReference="anchorPosition"
|
|
165
|
+
anchorPosition={ { top: iconLibraryAnchor.top, left: iconLibraryAnchor.left } }
|
|
166
|
+
anchorOrigin={ { vertical: 'top', horizontal: 'left' } }
|
|
167
|
+
transformOrigin={ { vertical: 'top', horizontal: 'left' } }
|
|
168
|
+
marginThreshold={ 0 }
|
|
169
|
+
PaperProps={ {
|
|
170
|
+
sx: {
|
|
171
|
+
width: iconLibraryWidth,
|
|
172
|
+
minWidth: iconLibraryWidth,
|
|
173
|
+
maxWidth: iconLibraryWidth,
|
|
174
|
+
m: 0,
|
|
175
|
+
},
|
|
176
|
+
} }
|
|
177
|
+
>
|
|
178
|
+
<IconLibraryPopover
|
|
179
|
+
open={ iconLibraryPopoverState.isOpen }
|
|
180
|
+
selectedIconClass={ selectedIconClass }
|
|
181
|
+
selectedIconLibrary={ selectedIconLibrary }
|
|
182
|
+
onSelect={ handleIconLibrarySelect }
|
|
183
|
+
onClose={ handleCloseIconLibrary }
|
|
184
|
+
width={ iconLibraryWidth }
|
|
185
|
+
/>
|
|
186
|
+
</Popover>
|
|
187
|
+
) : null }
|
|
188
|
+
<Box
|
|
189
|
+
ref={ controlContainerRef }
|
|
190
|
+
data-testid={ SVG_MEDIA_CONTROL_CONTAINER_TEST_ID }
|
|
191
|
+
sx={ { width: '100%' } }
|
|
192
|
+
>
|
|
193
|
+
<ControlActions>
|
|
194
|
+
<StyledCard variant="outlined">
|
|
195
|
+
<StyledCardMediaContainer>
|
|
196
|
+
<SvgMediaPreview
|
|
197
|
+
isFetching={ isFetching }
|
|
198
|
+
src={ src }
|
|
199
|
+
iconClassName={ selectedIconClass }
|
|
200
|
+
iconLibrary={ selectedIconLibrary }
|
|
201
|
+
/>
|
|
202
|
+
</StyledCardMediaContainer>
|
|
203
|
+
<CardOverlay
|
|
204
|
+
sx={ {
|
|
205
|
+
'&:hover': {
|
|
206
|
+
backgroundColor: 'rgba( 0, 0, 0, 0.75 )',
|
|
207
|
+
},
|
|
208
|
+
} }
|
|
209
|
+
>
|
|
210
|
+
<SvgMediaOverlay
|
|
211
|
+
isAdmin={ isAdmin }
|
|
212
|
+
showIconLibrary={ showIconLibrary }
|
|
213
|
+
buttonGroupRef={ buttonGroupRef }
|
|
214
|
+
onSelectSvg={ handleSelectSvg }
|
|
215
|
+
onUpload={ handleUpload }
|
|
216
|
+
onOpenIconLibrary={ handleOpenIconLibrary }
|
|
217
|
+
infotipTitle={ __( "Sorry, you can't upload that file yet.", 'elementor' ) }
|
|
218
|
+
infotipDescription={ <UnfilteredUploadInfotipDescription /> }
|
|
219
|
+
/>
|
|
220
|
+
</CardOverlay>
|
|
221
|
+
</StyledCard>
|
|
222
|
+
</ControlActions>
|
|
223
|
+
</Box>
|
|
224
|
+
</Stack>
|
|
260
225
|
);
|
|
261
|
-
}
|
|
226
|
+
} );
|
|
227
|
+
|
|
228
|
+
const UnfilteredUploadInfotipDescription = () => (
|
|
229
|
+
<>
|
|
230
|
+
{ __( 'To upload them anyway, ask the site administrator to enable unfiltered', 'elementor' ) }
|
|
231
|
+
<br />
|
|
232
|
+
{ __( 'file uploads.', 'elementor' ) }
|
|
233
|
+
</>
|
|
234
|
+
);
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { LibraryIcon, UploadIcon } from '@elementor/icons';
|
|
3
|
+
import { Box, Button, Stack, styled, type SxProps, ThemeProvider, Typography } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
import { ConditionalControlInfotip } from '../components/conditional-control-infotip';
|
|
7
|
+
|
|
8
|
+
export const SVG_MEDIA_CONTROL_CONTAINER_TEST_ID = 'svg-media-control-container';
|
|
9
|
+
export const SVG_MEDIA_ACTION_GROUP_TEST_ID = 'svg-media-action-group';
|
|
10
|
+
|
|
11
|
+
const MEDIA_ACTION_PADDING_Y = 0.75;
|
|
12
|
+
const MEDIA_ACTION_PADDING_X = 2;
|
|
13
|
+
const ICON_LIBRARY_PADDING = 0.625;
|
|
14
|
+
|
|
15
|
+
const svgButtonSx = {
|
|
16
|
+
px: MEDIA_ACTION_PADDING_X,
|
|
17
|
+
py: MEDIA_ACTION_PADDING_Y,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const MediaActionGroup = styled( Stack )( ( { theme } ) => ( {
|
|
21
|
+
display: 'inline-flex',
|
|
22
|
+
flexDirection: 'row',
|
|
23
|
+
alignItems: 'stretch',
|
|
24
|
+
border: '1px solid currentColor',
|
|
25
|
+
borderRadius: theme.shape.borderRadius,
|
|
26
|
+
overflow: 'hidden',
|
|
27
|
+
'& .MuiButton-root': {
|
|
28
|
+
border: 'none',
|
|
29
|
+
borderRadius: 0,
|
|
30
|
+
lineHeight: 1,
|
|
31
|
+
},
|
|
32
|
+
} ) );
|
|
33
|
+
|
|
34
|
+
type SvgMediaOverlayProps = {
|
|
35
|
+
isAdmin: boolean;
|
|
36
|
+
showIconLibrary: boolean;
|
|
37
|
+
buttonGroupRef: React.Ref< HTMLDivElement >;
|
|
38
|
+
onSelectSvg: () => void;
|
|
39
|
+
onUpload: () => void;
|
|
40
|
+
onOpenIconLibrary: ( event: React.MouseEvent< HTMLElement > ) => void;
|
|
41
|
+
infotipTitle: string;
|
|
42
|
+
infotipDescription: React.ReactNode;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const SvgMediaOverlay = ( {
|
|
46
|
+
isAdmin,
|
|
47
|
+
showIconLibrary,
|
|
48
|
+
buttonGroupRef,
|
|
49
|
+
onSelectSvg,
|
|
50
|
+
onUpload,
|
|
51
|
+
onOpenIconLibrary,
|
|
52
|
+
infotipTitle,
|
|
53
|
+
infotipDescription,
|
|
54
|
+
}: SvgMediaOverlayProps ) => (
|
|
55
|
+
<Stack alignItems="center" gap={ 1 }>
|
|
56
|
+
<MediaActionGroup ref={ buttonGroupRef } direction="row" data-testid={ SVG_MEDIA_ACTION_GROUP_TEST_ID }>
|
|
57
|
+
<Button
|
|
58
|
+
size="tiny"
|
|
59
|
+
color="inherit"
|
|
60
|
+
variant="text"
|
|
61
|
+
onClick={ onSelectSvg }
|
|
62
|
+
aria-label={ __( 'Select', 'elementor' ) }
|
|
63
|
+
sx={ svgButtonSx }
|
|
64
|
+
>
|
|
65
|
+
{ __( 'Select', 'elementor' ) }
|
|
66
|
+
</Button>
|
|
67
|
+
<Box
|
|
68
|
+
sx={ {
|
|
69
|
+
width: '1px',
|
|
70
|
+
alignSelf: 'stretch',
|
|
71
|
+
bgcolor: 'currentColor',
|
|
72
|
+
flexShrink: 0,
|
|
73
|
+
} }
|
|
74
|
+
/>
|
|
75
|
+
<ConditionalControlInfotip
|
|
76
|
+
title={ infotipTitle }
|
|
77
|
+
description={ infotipDescription }
|
|
78
|
+
isEnabled={ ! isAdmin }
|
|
79
|
+
>
|
|
80
|
+
<Box component="span" sx={ { display: 'inline-flex' } }>
|
|
81
|
+
<UploadControl isAdmin={ isAdmin } onUpload={ onUpload } />
|
|
82
|
+
</Box>
|
|
83
|
+
</ConditionalControlInfotip>
|
|
84
|
+
</MediaActionGroup>
|
|
85
|
+
{ showIconLibrary ? (
|
|
86
|
+
<Button
|
|
87
|
+
size="tiny"
|
|
88
|
+
color="inherit"
|
|
89
|
+
variant="text"
|
|
90
|
+
startIcon={ <LibraryIcon sx={ { height: '18px', width: '16px' } } /> }
|
|
91
|
+
aria-label={ __( 'Icon library', 'elementor' ) }
|
|
92
|
+
onClick={ onOpenIconLibrary }
|
|
93
|
+
sx={ {
|
|
94
|
+
height: '28px',
|
|
95
|
+
p: ICON_LIBRARY_PADDING,
|
|
96
|
+
'.MuiButton-icon': { ml: 0 },
|
|
97
|
+
} }
|
|
98
|
+
>
|
|
99
|
+
<Typography>{ __( 'Icon library', 'elementor' ) }</Typography>
|
|
100
|
+
</Button>
|
|
101
|
+
) : null }
|
|
102
|
+
</Stack>
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const UploadControl = ( { isAdmin, onUpload }: { isAdmin: boolean; onUpload: () => void } ) => {
|
|
106
|
+
if ( isAdmin ) {
|
|
107
|
+
return <UploadButton sx={ svgButtonSx } onClick={ onUpload } />;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<ThemeProvider colorScheme="dark">
|
|
112
|
+
<UploadButton disabled sx={ svgButtonSx } />
|
|
113
|
+
</ThemeProvider>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const UploadButton = ( {
|
|
118
|
+
disabled = false,
|
|
119
|
+
sx,
|
|
120
|
+
onClick,
|
|
121
|
+
}: {
|
|
122
|
+
disabled?: boolean;
|
|
123
|
+
sx?: SxProps;
|
|
124
|
+
onClick?: () => void;
|
|
125
|
+
} ) => (
|
|
126
|
+
<Button
|
|
127
|
+
sx={ sx }
|
|
128
|
+
size="tiny"
|
|
129
|
+
color="inherit"
|
|
130
|
+
variant="text"
|
|
131
|
+
disabled={ disabled }
|
|
132
|
+
onClick={ onClick }
|
|
133
|
+
aria-label={ __( 'Upload', 'elementor' ) }
|
|
134
|
+
>
|
|
135
|
+
<UploadIcon />
|
|
136
|
+
</Button>
|
|
137
|
+
);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Box, CardMedia, CircularProgress } from '@elementor/ui';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
|
|
5
|
+
import { findFontAwesome7Icon, type FontAwesome7Icon } from './icon-library/font-awesome-7-catalog';
|
|
6
|
+
import { FontAwesomeGlyph } from './icon-library/font-awesome-glyph';
|
|
7
|
+
import { useFontAwesome7Catalog } from './icon-library/use-font-awesome-7-catalog';
|
|
8
|
+
|
|
9
|
+
const ICON_PREVIEW_SIZE = 50;
|
|
10
|
+
const ICON_PREVIEW_COLOR = '#000000';
|
|
11
|
+
|
|
12
|
+
type SvgMediaPreviewProps = {
|
|
13
|
+
isFetching: boolean;
|
|
14
|
+
src: string | null;
|
|
15
|
+
iconClassName: string | null;
|
|
16
|
+
iconLibrary: string | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const SvgMediaPreview = ( { isFetching, src, iconClassName, iconLibrary }: SvgMediaPreviewProps ) => {
|
|
20
|
+
const shouldLoadIconCatalog = Boolean( iconClassName && iconLibrary );
|
|
21
|
+
const { data: icons = [], isLoading } = useFontAwesome7Catalog( shouldLoadIconCatalog );
|
|
22
|
+
const selectedIcon = findFontAwesome7Icon( icons, iconClassName, iconLibrary );
|
|
23
|
+
|
|
24
|
+
if ( isFetching || ( shouldLoadIconCatalog && isLoading ) ) {
|
|
25
|
+
return <CircularProgress role="progressbar" />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if ( selectedIcon ) {
|
|
29
|
+
return <IconPreview icon={ selectedIcon } />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if ( shouldLoadIconCatalog ) {
|
|
33
|
+
return <IconPreviewPlaceholder />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return <SvgPreview src={ src } />;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const IconPreview = ( { icon }: { icon: FontAwesome7Icon } ) => (
|
|
40
|
+
<Box sx={ { color: ICON_PREVIEW_COLOR } }>
|
|
41
|
+
<FontAwesomeGlyph
|
|
42
|
+
icon={ icon }
|
|
43
|
+
size={ ICON_PREVIEW_SIZE }
|
|
44
|
+
color={ ICON_PREVIEW_COLOR }
|
|
45
|
+
label={ __( 'Preview icon', 'elementor' ) }
|
|
46
|
+
/>
|
|
47
|
+
</Box>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const IconPreviewPlaceholder = () => (
|
|
51
|
+
<Box
|
|
52
|
+
aria-hidden
|
|
53
|
+
sx={ {
|
|
54
|
+
width: ICON_PREVIEW_SIZE,
|
|
55
|
+
height: ICON_PREVIEW_SIZE,
|
|
56
|
+
color: ICON_PREVIEW_COLOR,
|
|
57
|
+
} }
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const SvgPreview = ( { src }: { src: string | null } ) => (
|
|
62
|
+
<CardMedia
|
|
63
|
+
component="img"
|
|
64
|
+
image={ src }
|
|
65
|
+
alt={ __( 'Preview SVG', 'elementor' ) }
|
|
66
|
+
sx={ { maxHeight: '140px', width: `${ ICON_PREVIEW_SIZE }px`, color: ICON_PREVIEW_COLOR } }
|
|
67
|
+
/>
|
|
68
|
+
);
|
package/src/index.ts
CHANGED
|
@@ -37,6 +37,12 @@ export { TransformSettingsControl } from './controls/transform-control/transform
|
|
|
37
37
|
export { TransitionRepeaterControl } from './controls/transition-control/transition-repeater-control';
|
|
38
38
|
export { PopoverContent } from './components/popover-content';
|
|
39
39
|
export { enqueueFont } from './controls/font-family-control/enqueue-font';
|
|
40
|
+
export {
|
|
41
|
+
getFontAwesome7IconName,
|
|
42
|
+
resetFontAwesome7IconsCache,
|
|
43
|
+
resolveFontAwesome7Icon,
|
|
44
|
+
type FontAwesome7IconDefinition,
|
|
45
|
+
} from './controls/icon-library/font-awesome-7-data';
|
|
40
46
|
export { transitionProperties, transitionsItemsList } from './controls/transition-control/data';
|
|
41
47
|
export { DateTimeControl } from './controls/date-time-control';
|
|
42
48
|
export { DateRangeControl } from './controls/date-range-control';
|