@elementor/editor-controls 4.3.0-beta1 → 4.3.0-beta3
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 +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +2108 -922
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1950 -751
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -16
- package/src/controls/icon-library/font-awesome-7-catalog.ts +113 -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-filter.tsx +166 -0
- package/src/controls/icon-library/icon-library-grid.tsx +344 -0
- package/src/controls/icon-library/icon-library-popover.tsx +305 -0
- package/src/controls/icon-library/icon-library-tooltip.ts +1 -0
- package/src/controls/icon-library/icon-library-view-toggle.tsx +104 -0
- package/src/controls/icon-library/use-font-awesome-7-catalog.ts +14 -0
- package/src/controls/notice-control.tsx +105 -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/controls/toggle-control.tsx +13 -2
- package/src/index.ts +7 -0
|
@@ -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
|
+
);
|
|
@@ -14,6 +14,7 @@ export type ToggleControlProps< T extends PropValue > = {
|
|
|
14
14
|
exclusive?: boolean;
|
|
15
15
|
maxItems?: number;
|
|
16
16
|
convertOptions?: boolean;
|
|
17
|
+
allowEmpty?: boolean;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export const ToggleControl = createControl(
|
|
@@ -24,6 +25,7 @@ export const ToggleControl = createControl(
|
|
|
24
25
|
exclusive = true,
|
|
25
26
|
maxItems,
|
|
26
27
|
convertOptions = false,
|
|
28
|
+
allowEmpty = false,
|
|
27
29
|
}: ToggleControlProps< StringPropValue[ 'value' ] > ) => {
|
|
28
30
|
const { value, setValue, placeholder, disabled } = useBoundProp( stringPropTypeUtil );
|
|
29
31
|
|
|
@@ -54,11 +56,20 @@ export const ToggleControl = createControl(
|
|
|
54
56
|
placeholder,
|
|
55
57
|
};
|
|
56
58
|
|
|
59
|
+
const handleExclusiveToggle = ( selectedValue: StringPropValue[ 'value' ] | null ) => {
|
|
60
|
+
if ( allowEmpty && ! selectedValue ) {
|
|
61
|
+
setValue( '' );
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setValue( selectedValue );
|
|
66
|
+
};
|
|
67
|
+
|
|
57
68
|
return exclusive ? (
|
|
58
69
|
<ControlToggleButtonGroup
|
|
59
70
|
{ ...toggleButtonGroupProps }
|
|
60
|
-
value={ value ?? null }
|
|
61
|
-
onChange={
|
|
71
|
+
value={ allowEmpty ? value || null : value ?? null }
|
|
72
|
+
onChange={ handleExclusiveToggle }
|
|
62
73
|
disabled={ disabled }
|
|
63
74
|
exclusive={ true }
|
|
64
75
|
/>
|
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';
|
|
@@ -45,6 +51,7 @@ export { TimeRangeControl } from './controls/time-range-control';
|
|
|
45
51
|
export { InlineEditingControl } from './controls/inline-editing-control';
|
|
46
52
|
export { EmailFormActionControl } from './controls/email-form-action-control';
|
|
47
53
|
export { AttachmentTypeControl } from './controls/attachment-type-control';
|
|
54
|
+
export { NoticeControl } from './controls/notice-control';
|
|
48
55
|
export { UnstableSizeControl } from './controls/size-control/unstable-size-control';
|
|
49
56
|
export { GridSpanControl } from './controls/grid-span-control';
|
|
50
57
|
|