@elementor/editor-editing-panel 1.1.0 → 1.3.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 +53 -0
- package/dist/index.js +868 -444
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +851 -403
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -14
- 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/border-section/border-radius-field.tsx +4 -4
- package/src/components/style-sections/border-section/border-width-field.tsx +4 -4
- package/src/components/style-sections/layout-section/align-items-field.tsx +72 -0
- package/src/components/style-sections/layout-section/align-self-child-field.tsx +72 -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 +120 -0
- package/src/components/style-sections/layout-section/flex-size-field.tsx +164 -0
- package/src/components/style-sections/layout-section/justify-content-field.tsx +62 -62
- package/src/components/style-sections/layout-section/layout-section.tsx +27 -3
- package/src/components/style-sections/layout-section/utils/rotated-icon.tsx +52 -0
- package/src/components/style-sections/layout-section/wrap-field.tsx +52 -0
- package/src/components/style-sections/position-section/position-section.tsx +3 -3
- package/src/components/style-sections/typography-section/line-height-field.tsx +21 -0
- package/src/components/style-sections/typography-section/text-stroke-field.tsx +41 -6
- package/src/components/style-sections/typography-section/text-style-field.tsx +31 -8
- package/src/components/style-sections/typography-section/typography-section.tsx +3 -1
- package/src/components/style-tab.tsx +2 -2
- package/src/controls-registry/controls-registry.tsx +4 -0
- package/src/dynamics/components/dynamic-selection-control.tsx +8 -5
- package/src/dynamics/components/dynamic-selection.tsx +10 -8
- package/src/dynamics/dynamic-control.tsx +9 -11
- package/src/dynamics/utils.ts +20 -3
- package/src/components/css-class-selector-section.tsx +0 -76
- package/src/components/style-sections/layout-section/utils/rotate-flex-icon.ts +0 -12
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
ControlLabel,
|
|
5
|
+
ControlToggleButtonGroup,
|
|
6
|
+
NumberControl,
|
|
7
|
+
type ToggleButtonGroupItem,
|
|
8
|
+
} from '@elementor/editor-controls';
|
|
9
|
+
import { type NumberPropValue } from '@elementor/editor-props';
|
|
10
|
+
import { ArrowDownSmallIcon, ArrowUpSmallIcon, PencilIcon } from '@elementor/icons';
|
|
11
|
+
import { DirectionProvider, Grid, Stack, ThemeProvider } from '@elementor/ui';
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
13
|
+
|
|
14
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
|
+
import { useDirection } from '../../../hooks/use-direction';
|
|
16
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
17
|
+
|
|
18
|
+
type GroupControlItemOption = 'first' | 'last' | 'custom';
|
|
19
|
+
|
|
20
|
+
export const FIRST_DEFAULT_VALUE = -99999,
|
|
21
|
+
LAST_DEFAULT_VALUE = 99999,
|
|
22
|
+
FIRST = 'first',
|
|
23
|
+
LAST = 'last',
|
|
24
|
+
CUSTOM = 'custom';
|
|
25
|
+
|
|
26
|
+
const orderValueMap = {
|
|
27
|
+
[ FIRST ]: FIRST_DEFAULT_VALUE,
|
|
28
|
+
[ LAST ]: LAST_DEFAULT_VALUE,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const items: ToggleButtonGroupItem< GroupControlItemOption >[] = [
|
|
32
|
+
{
|
|
33
|
+
value: FIRST,
|
|
34
|
+
label: __( 'First', 'elementor' ),
|
|
35
|
+
renderContent: ( { size } ) => <ArrowUpSmallIcon fontSize={ size } />,
|
|
36
|
+
showTooltip: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: LAST,
|
|
40
|
+
label: __( 'Last', 'elementor' ),
|
|
41
|
+
renderContent: ( { size } ) => <ArrowDownSmallIcon fontSize={ size } />,
|
|
42
|
+
showTooltip: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
value: CUSTOM,
|
|
46
|
+
label: __( 'Custom', 'elementor' ),
|
|
47
|
+
renderContent: ( { size } ) => <PencilIcon fontSize={ size } />,
|
|
48
|
+
showTooltip: true,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export const FlexOrderField = () => {
|
|
53
|
+
const { isSiteRtl } = useDirection(),
|
|
54
|
+
[ order, setOrder ] = useStylesField< NumberPropValue | null >( 'order' );
|
|
55
|
+
|
|
56
|
+
const [ groupControlValue, setGroupControlValue ] = useState( getGroupControlValue( order?.value || null ) );
|
|
57
|
+
|
|
58
|
+
const handleToggleButtonChange = ( group: GroupControlItemOption | null ) => {
|
|
59
|
+
setGroupControlValue( group );
|
|
60
|
+
|
|
61
|
+
if ( ! group || group === CUSTOM ) {
|
|
62
|
+
setOrder( null );
|
|
63
|
+
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setOrder( { $$type: 'number', value: orderValueMap[ group ] } );
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
72
|
+
<ThemeProvider>
|
|
73
|
+
<Stack gap={ 2 }>
|
|
74
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
75
|
+
<Grid item xs={ 6 }>
|
|
76
|
+
<ControlLabel>{ __( 'Order', 'elementor' ) }</ControlLabel>
|
|
77
|
+
</Grid>
|
|
78
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
79
|
+
<ControlToggleButtonGroup
|
|
80
|
+
items={ items }
|
|
81
|
+
value={ groupControlValue }
|
|
82
|
+
onChange={ handleToggleButtonChange }
|
|
83
|
+
exclusive={ true }
|
|
84
|
+
/>
|
|
85
|
+
</Grid>
|
|
86
|
+
</Grid>
|
|
87
|
+
|
|
88
|
+
{ CUSTOM === groupControlValue && (
|
|
89
|
+
<StylesField bind={ 'order' }>
|
|
90
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
91
|
+
<Grid item xs={ 6 }>
|
|
92
|
+
<ControlLabel>{ __( 'Custom order', 'elementor' ) }</ControlLabel>
|
|
93
|
+
</Grid>
|
|
94
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
95
|
+
<NumberControl
|
|
96
|
+
min={ FIRST_DEFAULT_VALUE + 1 }
|
|
97
|
+
max={ LAST_DEFAULT_VALUE - 1 }
|
|
98
|
+
shouldForceInt={ true }
|
|
99
|
+
/>
|
|
100
|
+
</Grid>
|
|
101
|
+
</Grid>
|
|
102
|
+
</StylesField>
|
|
103
|
+
) }
|
|
104
|
+
</Stack>
|
|
105
|
+
</ThemeProvider>
|
|
106
|
+
</DirectionProvider>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getGroupControlValue = ( order: number | null ): GroupControlItemOption | null => {
|
|
111
|
+
if ( LAST_DEFAULT_VALUE === order ) {
|
|
112
|
+
return LAST;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if ( FIRST_DEFAULT_VALUE === order ) {
|
|
116
|
+
return FIRST;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return 0 === order || order ? CUSTOM : null;
|
|
120
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ControlLabel,
|
|
4
|
+
ControlToggleButtonGroup,
|
|
5
|
+
NumberControl,
|
|
6
|
+
SizeControl,
|
|
7
|
+
type ToggleButtonGroupItem,
|
|
8
|
+
} from '@elementor/editor-controls';
|
|
9
|
+
import type { NumberPropValue, SizePropValue } from '@elementor/editor-props';
|
|
10
|
+
import { ExpandIcon, PencilIcon, ShrinkIcon } from '@elementor/icons';
|
|
11
|
+
import { DirectionProvider, Grid, Stack, ThemeProvider } from '@elementor/ui';
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
13
|
+
|
|
14
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
|
+
import { useDirection } from '../../../hooks/use-direction';
|
|
16
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
17
|
+
|
|
18
|
+
type GroupItem = 'flex-grow' | 'flex-shrink' | 'custom';
|
|
19
|
+
|
|
20
|
+
export const DEFAULT = 1;
|
|
21
|
+
|
|
22
|
+
const items: ToggleButtonGroupItem< GroupItem >[] = [
|
|
23
|
+
{
|
|
24
|
+
value: 'flex-grow',
|
|
25
|
+
label: __( 'Grow', 'elementor' ),
|
|
26
|
+
renderContent: ( { size } ) => <ExpandIcon fontSize={ size } />,
|
|
27
|
+
showTooltip: true,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: 'flex-shrink',
|
|
31
|
+
label: __( 'Shrink', 'elementor' ),
|
|
32
|
+
renderContent: ( { size } ) => <ShrinkIcon fontSize={ size } />,
|
|
33
|
+
showTooltip: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'custom',
|
|
37
|
+
label: __( 'Custom', 'elementor' ),
|
|
38
|
+
renderContent: ( { size } ) => <PencilIcon fontSize={ size } />,
|
|
39
|
+
showTooltip: true,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
export const FlexSizeField = () => {
|
|
44
|
+
const { isSiteRtl } = useDirection(),
|
|
45
|
+
[ growField, setGrowField ] = useStylesField< NumberPropValue | null >( 'flex-grow' ),
|
|
46
|
+
[ shrinkField, setShrinkField ] = useStylesField< NumberPropValue | null >( 'flex-shrink' ),
|
|
47
|
+
[ basisField, setBasisField ] = useStylesField< SizePropValue | null >( 'flex-basis' );
|
|
48
|
+
|
|
49
|
+
const grow = growField?.value || null,
|
|
50
|
+
shrink = shrinkField?.value || null,
|
|
51
|
+
basis = basisField?.value || null;
|
|
52
|
+
|
|
53
|
+
const currentGroup = React.useMemo( () => getActiveGroup( { grow, shrink, basis } ), [ grow, shrink, basis ] ),
|
|
54
|
+
[ activeGroup, setActiveGroup ] = React.useState( currentGroup );
|
|
55
|
+
|
|
56
|
+
const onChangeGroup = ( group: GroupItem | null = null ) => {
|
|
57
|
+
setActiveGroup( group );
|
|
58
|
+
setBasisField( null );
|
|
59
|
+
|
|
60
|
+
if ( ! group || group === 'custom' ) {
|
|
61
|
+
setGrowField( null );
|
|
62
|
+
setShrinkField( null );
|
|
63
|
+
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if ( group === 'flex-grow' ) {
|
|
68
|
+
setGrowField( { $$type: 'number', value: DEFAULT } );
|
|
69
|
+
setShrinkField( null );
|
|
70
|
+
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setGrowField( null );
|
|
75
|
+
setShrinkField( { $$type: 'number', value: DEFAULT } );
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
80
|
+
<ThemeProvider>
|
|
81
|
+
<Stack gap={ 2 }>
|
|
82
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
83
|
+
<Grid item xs={ 6 }>
|
|
84
|
+
<ControlLabel>{ __( 'Size', 'elementor' ) }</ControlLabel>
|
|
85
|
+
</Grid>
|
|
86
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
87
|
+
<ControlToggleButtonGroup
|
|
88
|
+
value={ activeGroup }
|
|
89
|
+
onChange={ onChangeGroup }
|
|
90
|
+
items={ items }
|
|
91
|
+
exclusive={ true }
|
|
92
|
+
/>
|
|
93
|
+
</Grid>
|
|
94
|
+
</Grid>
|
|
95
|
+
|
|
96
|
+
{ 'custom' === activeGroup && <FlexCustomField /> }
|
|
97
|
+
</Stack>
|
|
98
|
+
</ThemeProvider>
|
|
99
|
+
</DirectionProvider>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const FlexCustomField = () => (
|
|
104
|
+
<>
|
|
105
|
+
<StylesField bind={ 'flex-grow' }>
|
|
106
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
107
|
+
<Grid item xs={ 6 }>
|
|
108
|
+
<ControlLabel>{ __( 'Grow', 'elementor' ) }</ControlLabel>
|
|
109
|
+
</Grid>
|
|
110
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
111
|
+
<NumberControl min={ 0 } shouldForceInt={ true } />
|
|
112
|
+
</Grid>
|
|
113
|
+
</Grid>
|
|
114
|
+
</StylesField>
|
|
115
|
+
<StylesField bind={ 'flex-shrink' }>
|
|
116
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
117
|
+
<Grid item xs={ 6 }>
|
|
118
|
+
<ControlLabel>{ __( 'Shrink', 'elementor' ) }</ControlLabel>
|
|
119
|
+
</Grid>
|
|
120
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
121
|
+
<NumberControl min={ 0 } shouldForceInt={ true } />
|
|
122
|
+
</Grid>
|
|
123
|
+
</Grid>
|
|
124
|
+
</StylesField>
|
|
125
|
+
<StylesField bind={ 'flex-basis' }>
|
|
126
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
127
|
+
<Grid item xs={ 6 }>
|
|
128
|
+
<ControlLabel>{ __( 'Basis', 'elementor' ) }</ControlLabel>
|
|
129
|
+
</Grid>
|
|
130
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
131
|
+
<SizeControl />
|
|
132
|
+
</Grid>
|
|
133
|
+
</Grid>
|
|
134
|
+
</StylesField>
|
|
135
|
+
</>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const getActiveGroup = ( {
|
|
139
|
+
grow,
|
|
140
|
+
shrink,
|
|
141
|
+
basis,
|
|
142
|
+
}: {
|
|
143
|
+
grow: NumberPropValue[ 'value' ] | null;
|
|
144
|
+
shrink: NumberPropValue[ 'value' ] | null;
|
|
145
|
+
basis: SizePropValue[ 'value' ] | null;
|
|
146
|
+
} ): GroupItem | null => {
|
|
147
|
+
if ( null === grow && null === shrink && ! basis ) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if ( ( shrink && grow ) || basis ) {
|
|
152
|
+
return 'custom';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ( grow === DEFAULT ) {
|
|
156
|
+
return 'flex-grow';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if ( shrink === DEFAULT ) {
|
|
160
|
+
return 'flex-shrink';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return 'custom';
|
|
164
|
+
};
|
|
@@ -2,81 +2,81 @@ import * as React from 'react';
|
|
|
2
2
|
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
3
|
import {
|
|
4
4
|
JustifyBottomIcon,
|
|
5
|
-
JustifyCenterIcon,
|
|
6
|
-
JustifyDistributeVerticalIcon,
|
|
7
|
-
JustifySpaceAroundVerticalIcon,
|
|
8
|
-
JustifySpaceBetweenVerticalIcon,
|
|
5
|
+
JustifyCenterIcon as CenterIcon,
|
|
6
|
+
JustifyDistributeVerticalIcon as EvenlyIcon,
|
|
7
|
+
JustifySpaceAroundVerticalIcon as AroundIcon,
|
|
8
|
+
JustifySpaceBetweenVerticalIcon as BetweenIcon,
|
|
9
9
|
JustifyTopIcon,
|
|
10
10
|
} from '@elementor/icons';
|
|
11
|
-
import { Stack } from '@elementor/ui';
|
|
11
|
+
import { DirectionProvider, Stack, ThemeProvider, withDirection } from '@elementor/ui';
|
|
12
12
|
import { __ } from '@wordpress/i18n';
|
|
13
13
|
|
|
14
14
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
15
|
import { useDirection } from '../../../hooks/use-direction';
|
|
16
|
-
import {
|
|
17
|
-
import { rotateFlexIcon } from './utils/rotate-flex-icon';
|
|
16
|
+
import { RotatedIcon } from './utils/rotated-icon';
|
|
18
17
|
|
|
19
18
|
type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const { isUiRtl, isSiteRtl } = useDirection(),
|
|
25
|
-
sx = { transform: rotateFlexIcon( direction as string, -1 ) } as const,
|
|
26
|
-
shouldReverseOrder = isSiteRtl !== isUiRtl;
|
|
20
|
+
const StartIcon = withDirection( JustifyTopIcon );
|
|
21
|
+
const EndIcon = withDirection( JustifyBottomIcon );
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
const iconProps = {
|
|
24
|
+
isClockwise: true,
|
|
25
|
+
offset: -90,
|
|
26
|
+
};
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
28
|
+
const options: ToggleButtonGroupItem< JustifyContent >[] = [
|
|
29
|
+
{
|
|
30
|
+
value: 'start',
|
|
31
|
+
label: __( 'Start', 'elementor' ),
|
|
32
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ StartIcon } size={ size } { ...iconProps } />,
|
|
33
|
+
showTooltip: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'center',
|
|
37
|
+
label: __( 'Center', 'elementor' ),
|
|
38
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ CenterIcon } size={ size } { ...iconProps } />,
|
|
39
|
+
showTooltip: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: 'end',
|
|
43
|
+
label: __( 'End', 'elementor' ),
|
|
44
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EndIcon } size={ size } { ...iconProps } />,
|
|
45
|
+
showTooltip: true,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: 'space-between',
|
|
49
|
+
label: __( 'Space between', 'elementor' ),
|
|
50
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ BetweenIcon } size={ size } { ...iconProps } />,
|
|
51
|
+
showTooltip: true,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: 'space-around',
|
|
55
|
+
label: __( 'Space around', 'elementor' ),
|
|
56
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ AroundIcon } size={ size } { ...iconProps } />,
|
|
57
|
+
showTooltip: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
value: 'space-evenly',
|
|
61
|
+
label: __( 'Space evenly', 'elementor' ),
|
|
62
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EvenlyIcon } size={ size } { ...iconProps } />,
|
|
63
|
+
showTooltip: true,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
67
|
+
export const JustifyContentField = () => {
|
|
68
|
+
const { isSiteRtl } = useDirection();
|
|
73
69
|
|
|
74
70
|
return (
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
72
|
+
<ThemeProvider>
|
|
73
|
+
<StylesField bind="justify-content">
|
|
74
|
+
<Stack gap={ 1 }>
|
|
75
|
+
<ControlLabel>{ __( 'Justify content', 'elementor' ) }</ControlLabel>
|
|
76
|
+
<ToggleControl options={ options } fullWidth={ true } />
|
|
77
|
+
</Stack>
|
|
78
|
+
</StylesField>
|
|
79
|
+
</ThemeProvider>
|
|
80
|
+
</DirectionProvider>
|
|
81
81
|
);
|
|
82
82
|
};
|
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ControlLabel } from '@elementor/editor-controls';
|
|
3
|
+
import { type StringPropValue } from '@elementor/editor-props';
|
|
4
|
+
import { Divider, Stack } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
3
6
|
|
|
4
7
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
|
+
import { AlignItemsField } from './align-items-field';
|
|
9
|
+
import { AlignSelfChild } from './align-self-child-field';
|
|
5
10
|
import { DisplayField } from './display-field';
|
|
11
|
+
import { FlexDirectionField } from './flex-direction-field';
|
|
12
|
+
import { FlexOrderField } from './flex-order-field';
|
|
13
|
+
import { FlexSizeField } from './flex-size-field';
|
|
6
14
|
import { JustifyContentField } from './justify-content-field';
|
|
15
|
+
import { WrapField } from './wrap-field';
|
|
7
16
|
|
|
8
17
|
export const LayoutSection = () => {
|
|
9
|
-
const [ display ] = useStylesField( 'display' );
|
|
18
|
+
const [ display ] = useStylesField< StringPropValue >( 'display' );
|
|
10
19
|
|
|
11
20
|
return (
|
|
12
21
|
<Stack gap={ 2 }>
|
|
13
22
|
<DisplayField />
|
|
14
|
-
{ 'flex' === display && <
|
|
23
|
+
{ 'flex' === display?.value && <FlexFields /> }
|
|
15
24
|
</Stack>
|
|
16
25
|
);
|
|
17
26
|
};
|
|
27
|
+
|
|
28
|
+
const FlexFields = () => (
|
|
29
|
+
<>
|
|
30
|
+
<FlexDirectionField />
|
|
31
|
+
<JustifyContentField />
|
|
32
|
+
<AlignItemsField />
|
|
33
|
+
<Divider />
|
|
34
|
+
<WrapField />
|
|
35
|
+
<Divider />
|
|
36
|
+
<ControlLabel>{ __( 'Flex child', 'elementor' ) }</ControlLabel>
|
|
37
|
+
<AlignSelfChild />
|
|
38
|
+
<FlexOrderField />
|
|
39
|
+
<FlexSizeField />
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { type StringPropValue } from '@elementor/editor-props';
|
|
4
|
+
import { type ToggleButtonProps, useTheme } from '@elementor/ui';
|
|
5
|
+
|
|
6
|
+
import { useStylesField } from '../../../../hooks/use-styles-field';
|
|
7
|
+
import type { FlexDirection } from '../flex-direction-field';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
icon: React.JSX.ElementType;
|
|
11
|
+
size: ToggleButtonProps[ 'size' ];
|
|
12
|
+
isClockwise?: boolean;
|
|
13
|
+
offset?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const CLOCKWISE_ANGLES: Record< FlexDirection, number > = {
|
|
17
|
+
row: 0,
|
|
18
|
+
column: 90,
|
|
19
|
+
'row-reverse': 180,
|
|
20
|
+
'column-reverse': 270,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const COUNTER_CLOCKWISE_ANGLES: Record< FlexDirection, number > = {
|
|
24
|
+
row: 0,
|
|
25
|
+
column: -90,
|
|
26
|
+
'row-reverse': -180,
|
|
27
|
+
'column-reverse': -270,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const RotatedIcon = ( { icon: Icon, size, isClockwise = true, offset = 0 }: Props ) => {
|
|
31
|
+
const rotate = useRef( useGetTargetAngle( isClockwise, offset ) );
|
|
32
|
+
rotate.current = useGetTargetAngle( isClockwise, offset, rotate );
|
|
33
|
+
|
|
34
|
+
return <Icon fontSize={ size } sx={ { transition: '.3s', rotate: `${ rotate.current }deg` } } />;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const useGetTargetAngle = ( isClockwise: boolean, offset: number, existingRef?: React.MutableRefObject< number > ) => {
|
|
38
|
+
const [ direction ] = useStylesField< StringPropValue >( 'flex-direction' );
|
|
39
|
+
const isRtl = 'rtl' === useTheme().direction;
|
|
40
|
+
const rotationMultiplier = isRtl ? -1 : 1;
|
|
41
|
+
const angleMap = isClockwise ? CLOCKWISE_ANGLES : COUNTER_CLOCKWISE_ANGLES;
|
|
42
|
+
|
|
43
|
+
const currentAngle = existingRef
|
|
44
|
+
? existingRef.current * rotationMultiplier // Multiply by rotationMultiplier to get the correct angle for RTL, as it will have returned multiplied by this
|
|
45
|
+
: angleMap[ ( direction?.value as FlexDirection ) || 'row' ] + offset;
|
|
46
|
+
const targetAngle = angleMap[ ( direction?.value as FlexDirection ) || 'row' ] + offset;
|
|
47
|
+
|
|
48
|
+
const diffToTargetAngle = ( targetAngle - currentAngle + 360 ) % 360; // Make sure the diff is between 0, 360;
|
|
49
|
+
const formattedDiff = ( ( diffToTargetAngle + 180 ) % 360 ) - 180; // Get the angle to rotate as a value between -180, 180
|
|
50
|
+
|
|
51
|
+
return ( currentAngle + formattedDiff ) * rotationMultiplier;
|
|
52
|
+
};
|
|
@@ -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: __( 'Reversed wrap', '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,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
|
-
import type { PropValue } from '@elementor/editor-props';
|
|
3
|
+
import type { PropValue, StringPropValue } from '@elementor/editor-props';
|
|
4
4
|
import { Stack } from '@elementor/ui';
|
|
5
5
|
|
|
6
6
|
import { useStylePropsHistory } from '../../../hooks/use-style-prop-history';
|
|
@@ -12,10 +12,10 @@ import { ZIndexField } from './z-index-field';
|
|
|
12
12
|
const dimensionsPropKeys = [ 'top', 'bottom', 'left', 'right' ];
|
|
13
13
|
|
|
14
14
|
export const PositionSection = () => {
|
|
15
|
-
const [ positionValue ] = useStylesField( 'position' );
|
|
15
|
+
const [ positionValue ] = useStylesField< StringPropValue >( 'position' );
|
|
16
16
|
usePositionChangeHandler();
|
|
17
17
|
|
|
18
|
-
const isNotStatic = positionValue && positionValue !== 'static';
|
|
18
|
+
const isNotStatic = positionValue && positionValue?.value !== 'static';
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
21
|
<Stack gap={ 1.5 }>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlLabel, SizeControl } from '@elementor/editor-controls';
|
|
3
|
+
import { Grid } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
|
+
|
|
8
|
+
export const LineHeightField = () => {
|
|
9
|
+
return (
|
|
10
|
+
<StylesField bind="line-height">
|
|
11
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
12
|
+
<Grid item xs={ 6 }>
|
|
13
|
+
<ControlLabel>{ __( 'Line Height', 'elementor' ) }</ControlLabel>
|
|
14
|
+
</Grid>
|
|
15
|
+
<Grid item xs={ 6 }>
|
|
16
|
+
<SizeControl />
|
|
17
|
+
</Grid>
|
|
18
|
+
</Grid>
|
|
19
|
+
</StylesField>
|
|
20
|
+
);
|
|
21
|
+
};
|