@elementor/editor-editing-panel 1.1.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 +24 -0
- package/dist/index.js +630 -377
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +605 -337
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/components/css-class-selector.tsx +131 -0
- package/src/components/multi-combobox/multi-combobox.tsx +34 -32
- package/src/components/multi-combobox/types.ts +2 -0
- package/src/components/multi-combobox/use-combobox-actions.ts +4 -4
- package/src/components/style-sections/layout-section/align-items-field.tsx +92 -0
- package/src/components/style-sections/layout-section/flex-direction-field.tsx +64 -0
- package/src/components/style-sections/layout-section/flex-order-field.tsx +114 -0
- package/src/components/style-sections/layout-section/justify-content-field.tsx +58 -31
- package/src/components/style-sections/layout-section/layout-section.tsx +21 -2
- package/src/components/style-sections/layout-section/wrap-field.tsx +52 -0
- package/src/components/style-sections/typography-section/text-stroke-field.tsx +41 -6
- package/src/components/style-tab.tsx +2 -2
- package/src/components/css-class-selector-section.tsx +0 -76
- package/src/components/style-sections/layout-section/utils/rotate-flex-icon.ts +0 -12
|
@@ -1,82 +1,109 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type JSX } from 'react';
|
|
2
3
|
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
4
|
import {
|
|
4
5
|
JustifyBottomIcon,
|
|
5
|
-
JustifyCenterIcon,
|
|
6
|
-
JustifyDistributeVerticalIcon,
|
|
7
|
-
JustifySpaceAroundVerticalIcon,
|
|
8
|
-
JustifySpaceBetweenVerticalIcon,
|
|
6
|
+
JustifyCenterIcon as CenterIcon,
|
|
7
|
+
JustifyDistributeVerticalIcon as EvenlyIcon,
|
|
8
|
+
JustifySpaceAroundVerticalIcon as AroundIcon,
|
|
9
|
+
JustifySpaceBetweenVerticalIcon as BetweenIcon,
|
|
9
10
|
JustifyTopIcon,
|
|
10
11
|
} from '@elementor/icons';
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DirectionProvider,
|
|
14
|
+
Stack,
|
|
15
|
+
ThemeProvider,
|
|
16
|
+
type ToggleButtonProps,
|
|
17
|
+
useTheme,
|
|
18
|
+
withDirection,
|
|
19
|
+
} from '@elementor/ui';
|
|
12
20
|
import { __ } from '@wordpress/i18n';
|
|
13
21
|
|
|
14
22
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
23
|
import { useDirection } from '../../../hooks/use-direction';
|
|
16
24
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
17
|
-
import {
|
|
25
|
+
import { type FlexDirection } from './flex-direction-field';
|
|
18
26
|
|
|
19
27
|
type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
|
|
20
28
|
|
|
21
29
|
export const JustifyContentField = () => {
|
|
22
|
-
const
|
|
30
|
+
const options = useOptions(),
|
|
31
|
+
{ isSiteRtl } = useDirection();
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
return (
|
|
34
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
35
|
+
<ThemeProvider>
|
|
36
|
+
<StylesField bind="justify-content">
|
|
37
|
+
<Stack gap={ 1 }>
|
|
38
|
+
<ControlLabel>{ __( 'Justify Content', 'elementor' ) }</ControlLabel>
|
|
39
|
+
<ToggleControl options={ options } fullWidth={ true } />
|
|
40
|
+
</Stack>
|
|
41
|
+
</StylesField>
|
|
42
|
+
</ThemeProvider>
|
|
43
|
+
</DirectionProvider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
47
|
+
const useOptions = (): ToggleButtonGroupItem< JustifyContent >[] => {
|
|
48
|
+
const StartIcon = withDirection( JustifyTopIcon ),
|
|
49
|
+
EndIcon = withDirection( JustifyBottomIcon );
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
return [
|
|
32
52
|
{
|
|
33
53
|
value: 'start',
|
|
34
54
|
label: __( 'Start', 'elementor' ),
|
|
35
|
-
renderContent: ( { size } ) => <
|
|
55
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ StartIcon } size={ size } />,
|
|
36
56
|
showTooltip: true,
|
|
37
57
|
},
|
|
38
58
|
{
|
|
39
59
|
value: 'center',
|
|
40
60
|
label: __( 'Center', 'elementor' ),
|
|
41
|
-
renderContent: ( { size } ) => <
|
|
61
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ CenterIcon } size={ size } />,
|
|
42
62
|
showTooltip: true,
|
|
43
63
|
},
|
|
44
64
|
{
|
|
45
65
|
value: 'end',
|
|
46
66
|
label: __( 'End', 'elementor' ),
|
|
47
|
-
renderContent: ( { size } ) => <
|
|
67
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EndIcon } size={ size } />,
|
|
48
68
|
showTooltip: true,
|
|
49
69
|
},
|
|
50
70
|
{
|
|
51
71
|
value: 'space-between',
|
|
52
|
-
label: __( 'Space
|
|
53
|
-
renderContent: ( { size } ) => <
|
|
72
|
+
label: __( 'Space between', 'elementor' ),
|
|
73
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ BetweenIcon } size={ size } />,
|
|
54
74
|
showTooltip: true,
|
|
55
75
|
},
|
|
56
76
|
{
|
|
57
77
|
value: 'space-around',
|
|
58
|
-
label: __( 'Space
|
|
59
|
-
renderContent: ( { size } ) => <
|
|
78
|
+
label: __( 'Space around', 'elementor' ),
|
|
79
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ AroundIcon } size={ size } />,
|
|
60
80
|
showTooltip: true,
|
|
61
81
|
},
|
|
62
82
|
{
|
|
63
83
|
value: 'space-evenly',
|
|
64
|
-
label: __( 'Space
|
|
65
|
-
renderContent: ( { size } ) => <
|
|
84
|
+
label: __( 'Space evenly', 'elementor' ),
|
|
85
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EvenlyIcon } size={ size } />,
|
|
66
86
|
showTooltip: true,
|
|
67
87
|
},
|
|
68
88
|
];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const RotatedIcon = ( { icon: Icon, size }: { icon: JSX.ElementType; size: ToggleButtonProps[ 'size' ] } ) => {
|
|
92
|
+
const [ direction ] = useStylesField< FlexDirection >( 'flex-direction' ),
|
|
93
|
+
isRtl = 'rtl' === useTheme().direction,
|
|
94
|
+
rotationMultiplier = isRtl ? -1 : 1;
|
|
69
95
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
96
|
+
const rotationAngelMap: Record< FlexDirection, number > = {
|
|
97
|
+
row: -90,
|
|
98
|
+
column: 0,
|
|
99
|
+
'row-reverse': 90,
|
|
100
|
+
'column-reverse': 180,
|
|
101
|
+
};
|
|
73
102
|
|
|
74
103
|
return (
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</Stack>
|
|
80
|
-
</StylesField>
|
|
104
|
+
<Icon
|
|
105
|
+
fontSize={ size }
|
|
106
|
+
sx={ { transition: '.3s', rotate: `${ rotationAngelMap[ direction || 'row' ] * rotationMultiplier }deg` } }
|
|
107
|
+
/>
|
|
81
108
|
);
|
|
82
109
|
};
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ControlLabel } from '@elementor/editor-controls';
|
|
3
|
+
import { Divider, Stack } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
3
5
|
|
|
4
6
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
7
|
+
import { AlignItemsField } from './align-items-field';
|
|
5
8
|
import { DisplayField } from './display-field';
|
|
9
|
+
import { FlexDirectionField } from './flex-direction-field';
|
|
10
|
+
import { FlexOrderField } from './flex-order-field';
|
|
6
11
|
import { JustifyContentField } from './justify-content-field';
|
|
12
|
+
import { WrapField } from './wrap-field';
|
|
7
13
|
|
|
8
14
|
export const LayoutSection = () => {
|
|
9
15
|
const [ display ] = useStylesField( 'display' );
|
|
@@ -11,7 +17,20 @@ export const LayoutSection = () => {
|
|
|
11
17
|
return (
|
|
12
18
|
<Stack gap={ 2 }>
|
|
13
19
|
<DisplayField />
|
|
14
|
-
{ 'flex' === display && <
|
|
20
|
+
{ 'flex' === display && <FlexFields /> }
|
|
15
21
|
</Stack>
|
|
16
22
|
);
|
|
17
23
|
};
|
|
24
|
+
|
|
25
|
+
const FlexFields = () => (
|
|
26
|
+
<>
|
|
27
|
+
<FlexDirectionField />
|
|
28
|
+
<JustifyContentField />
|
|
29
|
+
<AlignItemsField />
|
|
30
|
+
<Divider />
|
|
31
|
+
<WrapField />
|
|
32
|
+
<Divider />
|
|
33
|
+
<ControlLabel>{ __( 'Flex child', 'elementor' ) }</ControlLabel>
|
|
34
|
+
<FlexOrderField />
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
+
import { ArrowBackIcon, ArrowForwardIcon, ArrowRightIcon } from '@elementor/icons';
|
|
4
|
+
import { DirectionProvider, Grid, ThemeProvider } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
+
import { useDirection } from '../../../hooks/use-direction';
|
|
9
|
+
|
|
10
|
+
type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
11
|
+
|
|
12
|
+
const options: ToggleButtonGroupItem< FlexWrap >[] = [
|
|
13
|
+
{
|
|
14
|
+
value: 'nowrap',
|
|
15
|
+
label: __( 'No wrap', 'elementor' ),
|
|
16
|
+
renderContent: ( { size } ) => <ArrowRightIcon fontSize={ size } />,
|
|
17
|
+
showTooltip: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: 'wrap',
|
|
21
|
+
label: __( 'Wrap', 'elementor' ),
|
|
22
|
+
renderContent: ( { size } ) => <ArrowBackIcon fontSize={ size } />,
|
|
23
|
+
showTooltip: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: 'wrap-reverse',
|
|
27
|
+
label: __( 'Wrap reverse', 'elementor' ),
|
|
28
|
+
renderContent: ( { size } ) => <ArrowForwardIcon fontSize={ size } />,
|
|
29
|
+
showTooltip: true,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export const WrapField = () => {
|
|
34
|
+
const { isSiteRtl } = useDirection();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
38
|
+
<ThemeProvider>
|
|
39
|
+
<StylesField bind={ 'flex-wrap' }>
|
|
40
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
41
|
+
<Grid item xs={ 6 }>
|
|
42
|
+
<ControlLabel>{ __( 'Wrap', 'elementor' ) }</ControlLabel>
|
|
43
|
+
</Grid>
|
|
44
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'flex-end' } }>
|
|
45
|
+
<ToggleControl options={ options } />
|
|
46
|
+
</Grid>
|
|
47
|
+
</Grid>
|
|
48
|
+
</StylesField>
|
|
49
|
+
</ThemeProvider>
|
|
50
|
+
</DirectionProvider>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { StrokeControl } from '@elementor/editor-controls';
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
5
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
6
|
-
import {
|
|
6
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
7
|
+
import { AddOrRemoveContent } from '../../add-or-remove-content';
|
|
8
|
+
|
|
9
|
+
const initTextStroke = {
|
|
10
|
+
$$type: 'stroke',
|
|
11
|
+
value: {
|
|
12
|
+
color: {
|
|
13
|
+
$$type: 'color',
|
|
14
|
+
value: '#000000',
|
|
15
|
+
},
|
|
16
|
+
width: {
|
|
17
|
+
$$type: 'size',
|
|
18
|
+
value: {
|
|
19
|
+
unit: 'px',
|
|
20
|
+
size: 1,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
7
25
|
|
|
8
26
|
export const TextStrokeField = () => {
|
|
27
|
+
const [ textStroke, setTextStroke ] = useStylesField( '-webkit-text-stroke' );
|
|
28
|
+
|
|
29
|
+
const addTextStroke = () => {
|
|
30
|
+
setTextStroke( initTextStroke );
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const removeTextStroke = () => {
|
|
34
|
+
setTextStroke( null );
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const hasTextStroke = Boolean( textStroke );
|
|
38
|
+
|
|
9
39
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
40
|
+
<AddOrRemoveContent
|
|
41
|
+
label={ __( 'Text Stroke', 'elementor' ) }
|
|
42
|
+
isAdded={ hasTextStroke }
|
|
43
|
+
onAdd={ addTextStroke }
|
|
44
|
+
onRemove={ removeTextStroke }
|
|
45
|
+
>
|
|
46
|
+
<StylesField bind={ '-webkit-text-stroke' }>
|
|
12
47
|
<StrokeControl />
|
|
13
|
-
</
|
|
14
|
-
</
|
|
48
|
+
</StylesField>
|
|
49
|
+
</AddOrRemoveContent>
|
|
15
50
|
);
|
|
16
51
|
};
|
|
@@ -10,7 +10,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
10
10
|
import { ClassesPropProvider } from '../contexts/classes-prop-context';
|
|
11
11
|
import { useElement } from '../contexts/element-context';
|
|
12
12
|
import { StyleProvider } from '../contexts/style-context';
|
|
13
|
-
import {
|
|
13
|
+
import { CssClassSelector } from './css-class-selector';
|
|
14
14
|
import { Section } from './section';
|
|
15
15
|
import { SectionsList } from './sections-list';
|
|
16
16
|
import { BackgroundSection } from './style-sections/background-section/background-section';
|
|
@@ -32,7 +32,7 @@ export const StyleTab = () => {
|
|
|
32
32
|
return (
|
|
33
33
|
<ClassesPropProvider prop={ currentClassesProp }>
|
|
34
34
|
<StyleProvider meta={ { breakpoint, state: null } } id={ activeStyleDefId } setId={ setActiveStyleDefId }>
|
|
35
|
-
<
|
|
35
|
+
<CssClassSelector />
|
|
36
36
|
<Divider />
|
|
37
37
|
<SectionsList>
|
|
38
38
|
<Section title={ __( 'Layout', 'elementor' ) }>
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { useElementSetting, useElementStyles } from '@elementor/editor-elements';
|
|
3
|
-
import { type ClassesPropValue } from '@elementor/editor-props';
|
|
4
|
-
import { Chip, Stack, Typography } from '@elementor/ui';
|
|
5
|
-
import { __ } from '@wordpress/i18n';
|
|
6
|
-
|
|
7
|
-
import { useClassesProp } from '../contexts/classes-prop-context';
|
|
8
|
-
import { useElement } from '../contexts/element-context';
|
|
9
|
-
import { useStyle } from '../contexts/style-context';
|
|
10
|
-
import { MultiCombobox, type Option } from './multi-combobox';
|
|
11
|
-
|
|
12
|
-
const ID = 'elementor-css-class-selector';
|
|
13
|
-
const TAGS_LIMIT = 8;
|
|
14
|
-
|
|
15
|
-
export function CssClassSelectorSection() {
|
|
16
|
-
const options = useOptions();
|
|
17
|
-
|
|
18
|
-
const { id: activeId, setId: setActiveId } = useStyle();
|
|
19
|
-
const appliedIds = useAppliedClassesIds();
|
|
20
|
-
|
|
21
|
-
const applied = options.filter( ( option ) => appliedIds.includes( option.value ) );
|
|
22
|
-
const active = options.find( ( option ) => option.value === activeId ) || null;
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<Stack gap={ 1 } p={ 2 }>
|
|
26
|
-
<Typography component="label" variant="caption" htmlFor={ ID }>
|
|
27
|
-
{ __( 'CSS Classes', 'elementor' ) }
|
|
28
|
-
</Typography>
|
|
29
|
-
<MultiCombobox
|
|
30
|
-
id={ ID }
|
|
31
|
-
size="tiny"
|
|
32
|
-
options={ options }
|
|
33
|
-
selected={ applied }
|
|
34
|
-
limitTags={ TAGS_LIMIT }
|
|
35
|
-
optionsLabel={ __( 'Global CSS Classes', 'elementor' ) }
|
|
36
|
-
renderTags={ ( tagValue, getTagProps ) =>
|
|
37
|
-
tagValue.map( ( option, index ) => {
|
|
38
|
-
const chipProps = getTagProps( { index } );
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Chip
|
|
42
|
-
{ ...chipProps }
|
|
43
|
-
key={ chipProps.key }
|
|
44
|
-
size="small"
|
|
45
|
-
label={ option.label }
|
|
46
|
-
variant={ option.value === active?.value ? 'filled' : 'standard' }
|
|
47
|
-
color={ option.color ?? 'default' }
|
|
48
|
-
onClick={ () => setActiveId( option.value ) }
|
|
49
|
-
onDelete={ null }
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
52
|
-
} )
|
|
53
|
-
}
|
|
54
|
-
/>
|
|
55
|
-
</Stack>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function useAppliedClassesIds() {
|
|
60
|
-
const { element } = useElement();
|
|
61
|
-
const currentClassesProp = useClassesProp();
|
|
62
|
-
|
|
63
|
-
return useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function useOptions() {
|
|
67
|
-
const { element } = useElement();
|
|
68
|
-
|
|
69
|
-
const styleDefs = useElementStyles( element.id );
|
|
70
|
-
|
|
71
|
-
return Object.values( styleDefs ).map< Option >( ( styleDef ) => ( {
|
|
72
|
-
label: styleDef.label,
|
|
73
|
-
value: styleDef.id,
|
|
74
|
-
color: 'primary',
|
|
75
|
-
} ) );
|
|
76
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export function rotateFlexIcon( direction: string | null = 'row', initValue: number ) {
|
|
2
|
-
const rotationIndexMap: Record< string, number > = {
|
|
3
|
-
row: 0,
|
|
4
|
-
column: 1,
|
|
5
|
-
'row-reverse': 2,
|
|
6
|
-
'column-reverse': 3,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const rotationIndex = initValue + ( rotationIndexMap[ direction || 'row' ] ?? 0 );
|
|
10
|
-
|
|
11
|
-
return `rotate(calc(90deg * ${ rotationIndex }))`;
|
|
12
|
-
}
|