@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,19 +39,20 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "
|
|
43
|
-
"@elementor/editor-controls": "
|
|
44
|
-
"@elementor/editor-elements": "
|
|
45
|
-
"@elementor/menus": "
|
|
46
|
-
"@elementor/editor-props": "
|
|
47
|
-
"@elementor/editor-panels": "
|
|
48
|
-
"@elementor/editor-responsive": "
|
|
49
|
-
"@elementor/editor-styles": "
|
|
50
|
-
"@elementor/editor-v1-adapters": "
|
|
51
|
-
"@elementor/icons": "^1.
|
|
52
|
-
"@elementor/
|
|
53
|
-
"@elementor/
|
|
54
|
-
"@
|
|
42
|
+
"@elementor/editor": "0.17.2",
|
|
43
|
+
"@elementor/editor-controls": "0.2.0",
|
|
44
|
+
"@elementor/editor-elements": "0.3.2",
|
|
45
|
+
"@elementor/menus": "0.1.2",
|
|
46
|
+
"@elementor/editor-props": "0.4.0",
|
|
47
|
+
"@elementor/editor-panels": "0.10.2",
|
|
48
|
+
"@elementor/editor-responsive": "0.12.4",
|
|
49
|
+
"@elementor/editor-styles": "0.3.1",
|
|
50
|
+
"@elementor/editor-v1-adapters": "0.8.5",
|
|
51
|
+
"@elementor/icons": "^1.20.0",
|
|
52
|
+
"@elementor/schema": "0.1.2",
|
|
53
|
+
"@elementor/ui": "^1.22.0",
|
|
54
|
+
"@elementor/utils": "0.3.0",
|
|
55
|
+
"@wordpress/i18n": "^5.13.0"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
58
|
"react": "^18.3.1"
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { updateSettings, useElementSetting, useElementStyles } from '@elementor/editor-elements';
|
|
3
|
+
import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
|
|
4
|
+
import { type StyleDefinitionID } from '@elementor/editor-styles';
|
|
5
|
+
import { Chip, Stack, Typography } from '@elementor/ui';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
import { useClassesProp } from '../contexts/classes-prop-context';
|
|
9
|
+
import { useElement } from '../contexts/element-context';
|
|
10
|
+
import { useStyle } from '../contexts/style-context';
|
|
11
|
+
import { MultiCombobox, type Option } from './multi-combobox';
|
|
12
|
+
|
|
13
|
+
const ID = 'elementor-css-class-selector';
|
|
14
|
+
const TAGS_LIMIT = 8;
|
|
15
|
+
|
|
16
|
+
export function CssClassSelector() {
|
|
17
|
+
const options = useOptions();
|
|
18
|
+
|
|
19
|
+
const { id: activeId, setId: setActiveId } = useStyle();
|
|
20
|
+
const [ appliedIds ] = useAppliedClassesIds();
|
|
21
|
+
|
|
22
|
+
const handleApply = useHandleApply();
|
|
23
|
+
const handleActivate = ( { value }: Option ) => setActiveId( value );
|
|
24
|
+
|
|
25
|
+
const active = options.find( ( option ) => option.value === activeId ) || null;
|
|
26
|
+
|
|
27
|
+
const applied = appliedIds
|
|
28
|
+
.map( ( id ) => options.find( ( option ) => option.value === id ) )
|
|
29
|
+
.filter( ( option ) => !! option );
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Stack gap={ 1 } p={ 2 }>
|
|
33
|
+
<Typography component="label" variant="caption" htmlFor={ ID }>
|
|
34
|
+
{ __( 'CSS Classes', 'elementor' ) }
|
|
35
|
+
</Typography>
|
|
36
|
+
<MultiCombobox
|
|
37
|
+
id={ ID }
|
|
38
|
+
size="tiny"
|
|
39
|
+
options={ options }
|
|
40
|
+
selected={ applied }
|
|
41
|
+
onSelect={ handleApply }
|
|
42
|
+
limitTags={ TAGS_LIMIT }
|
|
43
|
+
optionsLabel={ __( 'Global CSS Classes', 'elementor' ) }
|
|
44
|
+
renderTags={ ( values, getTagProps ) =>
|
|
45
|
+
values.map( ( value, index ) => {
|
|
46
|
+
const chipProps = getTagProps( { index } );
|
|
47
|
+
const isActive = value.value === active?.value;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Chip
|
|
51
|
+
{ ...chipProps }
|
|
52
|
+
key={ chipProps.key }
|
|
53
|
+
size="small"
|
|
54
|
+
label={ value.label }
|
|
55
|
+
variant={ isActive ? 'filled' : 'standard' }
|
|
56
|
+
color={ isActive && value.color ? value.color : 'default' }
|
|
57
|
+
onClick={ () => handleActivate( value ) }
|
|
58
|
+
onDelete={ null }
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
} )
|
|
62
|
+
}
|
|
63
|
+
/>
|
|
64
|
+
</Stack>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function useOptions() {
|
|
69
|
+
const { element } = useElement();
|
|
70
|
+
|
|
71
|
+
const styleDefs = useElementStyles( element.id );
|
|
72
|
+
|
|
73
|
+
return Object.values( styleDefs ).map< Option >( ( styleDef ) => ( {
|
|
74
|
+
label: styleDef.label,
|
|
75
|
+
value: styleDef.id,
|
|
76
|
+
fixed: true,
|
|
77
|
+
color: 'primary',
|
|
78
|
+
} ) );
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function useAppliedClassesIds() {
|
|
82
|
+
const { element } = useElement();
|
|
83
|
+
const currentClassesProp = useClassesProp();
|
|
84
|
+
|
|
85
|
+
const value = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
|
|
86
|
+
|
|
87
|
+
const setValue = ( ids: StyleDefinitionID[] ) => {
|
|
88
|
+
updateSettings( {
|
|
89
|
+
id: element.id,
|
|
90
|
+
props: {
|
|
91
|
+
[ currentClassesProp ]: classesPropTypeUtil.create( ids ),
|
|
92
|
+
},
|
|
93
|
+
} );
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return [ value, setValue ] as const;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function useHandleApply() {
|
|
100
|
+
const { id: activeId, setId: setActiveId } = useStyle();
|
|
101
|
+
const [ appliedIds, setAppliedIds ] = useAppliedClassesIds();
|
|
102
|
+
|
|
103
|
+
return ( selectedOptions: Option[] ) => {
|
|
104
|
+
const selectedValues = selectedOptions.map( ( { value } ) => value );
|
|
105
|
+
|
|
106
|
+
const isSameClassesAlreadyApplied =
|
|
107
|
+
selectedValues.length === appliedIds.length &&
|
|
108
|
+
selectedValues.every( ( value ) => appliedIds.includes( value ) );
|
|
109
|
+
|
|
110
|
+
// Should not trigger to avoid register an undo step.
|
|
111
|
+
if ( isSameClassesAlreadyApplied ) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setAppliedIds( selectedValues );
|
|
116
|
+
|
|
117
|
+
const addedValue = selectedValues.find( ( id ) => ! appliedIds.includes( id ) );
|
|
118
|
+
|
|
119
|
+
if ( addedValue ) {
|
|
120
|
+
setActiveId( addedValue );
|
|
121
|
+
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const removedValue = appliedIds.find( ( id ) => ! selectedValues.includes( id ) );
|
|
126
|
+
|
|
127
|
+
if ( removedValue && removedValue === activeId ) {
|
|
128
|
+
setActiveId( selectedValues[ 0 ] ?? null );
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -13,12 +13,12 @@ import { type FilterOptionsState } from '@mui/base';
|
|
|
13
13
|
import { type ActionOption, type Actions, type Option } from './types';
|
|
14
14
|
import { useComboboxActions } from './use-combobox-actions';
|
|
15
15
|
|
|
16
|
-
type Props = Omit< AutocompleteProps< Option, true, true, true >, 'renderInput' | 'getLimitTagsText' > & {
|
|
16
|
+
type Props = Omit< AutocompleteProps< Option, true, true, true >, 'renderInput' | 'getLimitTagsText' | 'onSelect' > & {
|
|
17
17
|
actions?: Actions;
|
|
18
18
|
selected: Option[];
|
|
19
19
|
options: Option[];
|
|
20
20
|
optionsLabel?: string;
|
|
21
|
-
|
|
21
|
+
onSelect?: ( value: Option[] ) => void;
|
|
22
22
|
onCreate?: ( value: string ) => void;
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -27,27 +27,17 @@ export const MultiCombobox = ( {
|
|
|
27
27
|
selected,
|
|
28
28
|
options,
|
|
29
29
|
optionsLabel,
|
|
30
|
-
|
|
30
|
+
onSelect,
|
|
31
31
|
onCreate,
|
|
32
32
|
...props
|
|
33
33
|
}: Props ) => {
|
|
34
|
-
const { action: actionProps, option: optionProps } = useComboboxActions(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return optionProps.onChange( values as Option[] );
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const handleCreateOption = ( values: Array< ActionOption | Option | string > ) => {
|
|
47
|
-
const value = values.find( ( option ) => typeof option === 'string' );
|
|
48
|
-
|
|
49
|
-
onCreate?.( value as string );
|
|
50
|
-
};
|
|
34
|
+
const { action: actionProps, option: optionProps } = useComboboxActions(
|
|
35
|
+
selected,
|
|
36
|
+
actions,
|
|
37
|
+
// TODO: make the group mechanism more generic, allow passing list of groups.
|
|
38
|
+
optionsLabel,
|
|
39
|
+
onSelect
|
|
40
|
+
);
|
|
51
41
|
|
|
52
42
|
return (
|
|
53
43
|
<Autocomplete
|
|
@@ -62,31 +52,43 @@ export const MultiCombobox = ( {
|
|
|
62
52
|
options={ options }
|
|
63
53
|
renderGroup={ renderGroup }
|
|
64
54
|
renderInput={ ( params ) => <TextField { ...params } /> }
|
|
55
|
+
// TODO: is it relevant for the combobox? or should be in the parent component?
|
|
65
56
|
getLimitTagsText={ ( more ) => <Chip size="tiny" variant="standard" label={ `+${ more }` } clickable /> }
|
|
66
|
-
onChange={ ( _,
|
|
67
|
-
if ( reason === '
|
|
68
|
-
|
|
57
|
+
onChange={ ( _, selectedOrTypedValue, reason ) => {
|
|
58
|
+
if ( reason === 'createOption' ) {
|
|
59
|
+
const typedValue = selectedOrTypedValue.find( ( option ) => typeof option === 'string' );
|
|
60
|
+
|
|
61
|
+
return typedValue && onCreate?.( typedValue );
|
|
69
62
|
}
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
const action = selectedOrTypedValue.find( ( value ) => actionProps.is( value ) );
|
|
65
|
+
|
|
66
|
+
if ( reason === 'selectOption' && action ) {
|
|
67
|
+
return actionProps.onChange( action );
|
|
73
68
|
}
|
|
74
69
|
|
|
75
|
-
|
|
70
|
+
const selectedValues = selectedOrTypedValue.filter( ( v ) => typeof v !== 'string' );
|
|
71
|
+
const fixedValues = options.filter( ( option ) => option.fixed );
|
|
72
|
+
|
|
73
|
+
optionProps.onChange( [ ...new Set( [ ...fixedValues, ...selectedValues ] ) ] );
|
|
76
74
|
} }
|
|
77
75
|
getOptionLabel={ ( option ) => {
|
|
78
|
-
if ( optionProps.is( option
|
|
79
|
-
return optionProps.getLabel( option
|
|
76
|
+
if ( optionProps.is( option ) ) {
|
|
77
|
+
return optionProps.getLabel( option );
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if ( actionProps.is( option ) ) {
|
|
81
|
+
return actionProps.getLabel( option );
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
return
|
|
84
|
+
return '';
|
|
83
85
|
} }
|
|
84
86
|
filterOptions={ ( optionList: Option[], params: FilterOptionsState< ActionOption | Option > ) => {
|
|
85
|
-
const
|
|
87
|
+
const filteredOptions = optionProps.getFilteredOptions( optionList, params );
|
|
86
88
|
|
|
87
89
|
const actionOptions = actionProps.getFilteredActions( optionList, params );
|
|
88
90
|
|
|
89
|
-
return [ ...actionOptions, ...
|
|
91
|
+
return [ ...actionOptions, ...filteredOptions ];
|
|
90
92
|
} }
|
|
91
93
|
groupBy={ ( option ) =>
|
|
92
94
|
( optionProps.is( option ) ? optionProps.groupBy() : actionProps.groupBy( option ) ) ?? ''
|
|
@@ -95,7 +97,7 @@ export const MultiCombobox = ( {
|
|
|
95
97
|
);
|
|
96
98
|
};
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
const renderGroup = ( params: AutocompleteRenderGroupParams ) => (
|
|
99
101
|
<Group key={ params.key }>
|
|
100
102
|
<GroupHeader>{ params.group }</GroupHeader>
|
|
101
103
|
<GroupItems>{ params.children }</GroupItems>
|
|
@@ -7,10 +7,10 @@ export const useComboboxActions = (
|
|
|
7
7
|
applied: Option[],
|
|
8
8
|
actions: Actions,
|
|
9
9
|
optionsLabel?: string,
|
|
10
|
-
|
|
10
|
+
onSelect?: ( value: Option[] ) => void
|
|
11
11
|
) => ( {
|
|
12
12
|
action: {
|
|
13
|
-
is: ( opt: ActionOption ): opt is ActionOption =>
|
|
13
|
+
is: ( opt: ActionOption | Option | string ): opt is ActionOption => typeof opt !== 'string' && 'action' in opt,
|
|
14
14
|
getLabel: ( option: ActionOption ) => option.action.getLabel( option.label ),
|
|
15
15
|
groupBy: ( option: ActionOption ) => option.action.groupLabel,
|
|
16
16
|
onChange: ( { action, label }: ActionOption ) => action?.apply( label ),
|
|
@@ -34,10 +34,10 @@ export const useComboboxActions = (
|
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
option: {
|
|
37
|
-
is: ( opt: ActionOption | Option ): opt is Option => ! ( 'action' in opt ),
|
|
37
|
+
is: ( opt: ActionOption | Option | string ): opt is Option => typeof opt !== 'string' && ! ( 'action' in opt ),
|
|
38
38
|
getLabel: ( option: Option ) => option.label,
|
|
39
39
|
groupBy: () => optionsLabel ?? '',
|
|
40
|
-
onChange: ( optionValues: Option[] ) =>
|
|
40
|
+
onChange: ( optionValues: Option[] ) => onSelect?.( optionValues ),
|
|
41
41
|
getFilteredOptions: ( optionList: Option[], params: FilterOptionsState< Option > ) => {
|
|
42
42
|
const appliedValues = applied.map( ( option ) => option.value );
|
|
43
43
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type EqualUnequalItems, EqualUnequalSizesControl } from '@elementor/editor-controls';
|
|
3
|
-
import
|
|
3
|
+
import { borderRadiusPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import {
|
|
5
5
|
BorderCornersIcon,
|
|
6
6
|
RadiusBottomLeftIcon,
|
|
@@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
12
12
|
|
|
13
13
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
14
14
|
|
|
15
|
-
const corners: EqualUnequalItems
|
|
15
|
+
const corners: EqualUnequalItems = [
|
|
16
16
|
{
|
|
17
17
|
label: __( 'Top Left', 'elementor' ),
|
|
18
18
|
icon: <RadiusTopLeftIcon fontSize={ 'tiny' } />,
|
|
@@ -39,10 +39,10 @@ export const BorderRadiusField = () => {
|
|
|
39
39
|
return (
|
|
40
40
|
<StylesField bind={ 'border-radius' }>
|
|
41
41
|
<EqualUnequalSizesControl
|
|
42
|
+
items={ corners }
|
|
42
43
|
label={ __( 'Border Radius', 'elementor' ) }
|
|
43
44
|
icon={ <BorderCornersIcon fontSize={ 'tiny' } /> }
|
|
44
|
-
|
|
45
|
-
multiSizeType={ 'border-radius' }
|
|
45
|
+
multiSizePropTypeUtil={ borderRadiusPropTypeUtil }
|
|
46
46
|
/>
|
|
47
47
|
</StylesField>
|
|
48
48
|
);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type EqualUnequalItems, EqualUnequalSizesControl } from '@elementor/editor-controls';
|
|
3
|
-
import {
|
|
3
|
+
import { borderWidthPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { SideAllIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
8
|
|
|
9
|
-
const edges: EqualUnequalItems
|
|
9
|
+
const edges: EqualUnequalItems = [
|
|
10
10
|
{
|
|
11
11
|
label: __( 'Top', 'elementor' ),
|
|
12
12
|
icon: <SideTopIcon fontSize={ 'tiny' } />,
|
|
@@ -33,10 +33,10 @@ export const BorderWidthField = () => {
|
|
|
33
33
|
return (
|
|
34
34
|
<StylesField bind={ 'border-width' }>
|
|
35
35
|
<EqualUnequalSizesControl
|
|
36
|
+
items={ edges }
|
|
36
37
|
label={ __( 'Border Width', 'elementor' ) }
|
|
37
38
|
icon={ <SideAllIcon fontSize={ 'tiny' } /> }
|
|
38
|
-
|
|
39
|
-
multiSizeType={ 'border-width' }
|
|
39
|
+
multiSizePropTypeUtil={ borderWidthPropTypeUtil }
|
|
40
40
|
/>
|
|
41
41
|
</StylesField>
|
|
42
42
|
);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
+
import {
|
|
4
|
+
LayoutAlignCenterIcon as CenterIcon,
|
|
5
|
+
LayoutAlignLeftIcon,
|
|
6
|
+
LayoutAlignRightIcon,
|
|
7
|
+
LayoutDistributeVerticalIcon as JustifyIcon,
|
|
8
|
+
} from '@elementor/icons';
|
|
9
|
+
import { DirectionProvider, Grid, ThemeProvider, withDirection } from '@elementor/ui';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
13
|
+
import { useDirection } from '../../../hooks/use-direction';
|
|
14
|
+
import { RotatedIcon } from './utils/rotated-icon';
|
|
15
|
+
|
|
16
|
+
type AlignItems = 'start' | 'center' | 'end' | 'stretch';
|
|
17
|
+
|
|
18
|
+
const StartIcon = withDirection( LayoutAlignLeftIcon );
|
|
19
|
+
const EndIcon = withDirection( LayoutAlignRightIcon );
|
|
20
|
+
|
|
21
|
+
const iconProps = {
|
|
22
|
+
isClockwise: false,
|
|
23
|
+
offset: 90,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const options: ToggleButtonGroupItem< AlignItems >[] = [
|
|
27
|
+
{
|
|
28
|
+
value: 'start',
|
|
29
|
+
label: __( 'Start', 'elementor' ),
|
|
30
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ StartIcon } size={ size } { ...iconProps } />,
|
|
31
|
+
showTooltip: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: 'center',
|
|
35
|
+
label: __( 'Center', 'elementor' ),
|
|
36
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ CenterIcon } size={ size } { ...iconProps } />,
|
|
37
|
+
showTooltip: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: 'end',
|
|
41
|
+
label: __( 'End', 'elementor' ),
|
|
42
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EndIcon } size={ size } { ...iconProps } />,
|
|
43
|
+
showTooltip: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
value: 'stretch',
|
|
47
|
+
label: __( 'Stretch', 'elementor' ),
|
|
48
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ JustifyIcon } size={ size } { ...iconProps } />,
|
|
49
|
+
showTooltip: true,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const AlignItemsField = () => {
|
|
54
|
+
const { isSiteRtl } = useDirection();
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
58
|
+
<ThemeProvider>
|
|
59
|
+
<StylesField bind="align-items">
|
|
60
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
61
|
+
<Grid item xs={ 6 }>
|
|
62
|
+
<ControlLabel>{ __( 'Align items', 'elementor' ) }</ControlLabel>
|
|
63
|
+
</Grid>
|
|
64
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
65
|
+
<ToggleControl options={ options } />
|
|
66
|
+
</Grid>
|
|
67
|
+
</Grid>
|
|
68
|
+
</StylesField>
|
|
69
|
+
</ThemeProvider>
|
|
70
|
+
</DirectionProvider>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
+
import {
|
|
4
|
+
LayoutAlignCenterIcon as CenterIcon,
|
|
5
|
+
LayoutAlignLeftIcon,
|
|
6
|
+
LayoutAlignRightIcon,
|
|
7
|
+
LayoutDistributeVerticalIcon as JustifyIcon,
|
|
8
|
+
} from '@elementor/icons';
|
|
9
|
+
import { DirectionProvider, Grid, ThemeProvider, withDirection } from '@elementor/ui';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
13
|
+
import { useDirection } from '../../../hooks/use-direction';
|
|
14
|
+
import { RotatedIcon } from './utils/rotated-icon';
|
|
15
|
+
|
|
16
|
+
type AlignItems = 'start' | 'center' | 'end' | 'stretch';
|
|
17
|
+
|
|
18
|
+
const StartIcon = withDirection( LayoutAlignLeftIcon );
|
|
19
|
+
const EndIcon = withDirection( LayoutAlignRightIcon );
|
|
20
|
+
|
|
21
|
+
const iconProps = {
|
|
22
|
+
isClockwise: false,
|
|
23
|
+
offset: 90,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const options: ToggleButtonGroupItem< AlignItems >[] = [
|
|
27
|
+
{
|
|
28
|
+
value: 'start',
|
|
29
|
+
label: __( 'Start', 'elementor' ),
|
|
30
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ StartIcon } size={ size } { ...iconProps } />,
|
|
31
|
+
showTooltip: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: 'center',
|
|
35
|
+
label: __( 'Center', 'elementor' ),
|
|
36
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ CenterIcon } size={ size } { ...iconProps } />,
|
|
37
|
+
showTooltip: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: 'end',
|
|
41
|
+
label: __( 'End', 'elementor' ),
|
|
42
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ EndIcon } size={ size } { ...iconProps } />,
|
|
43
|
+
showTooltip: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
value: 'stretch',
|
|
47
|
+
label: __( 'Stretch', 'elementor' ),
|
|
48
|
+
renderContent: ( { size } ) => <RotatedIcon icon={ JustifyIcon } size={ size } { ...iconProps } />,
|
|
49
|
+
showTooltip: true,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const AlignSelfChild = () => {
|
|
54
|
+
const { isSiteRtl } = useDirection();
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
58
|
+
<ThemeProvider>
|
|
59
|
+
<StylesField bind={ 'align-self' }>
|
|
60
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
61
|
+
<Grid item xs={ 6 }>
|
|
62
|
+
<ControlLabel>{ __( 'Align self', 'elementor' ) }</ControlLabel>
|
|
63
|
+
</Grid>
|
|
64
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'flex-end' } }>
|
|
65
|
+
<ToggleControl options={ options } />
|
|
66
|
+
</Grid>
|
|
67
|
+
</Grid>
|
|
68
|
+
</StylesField>
|
|
69
|
+
</ThemeProvider>
|
|
70
|
+
</DirectionProvider>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
+
import { ArrowDownSmallIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpSmallIcon } from '@elementor/icons';
|
|
4
|
+
import { DirectionProvider, Grid, ThemeProvider, withDirection } 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
|
+
export type FlexDirection = 'row' | 'row-reverse' | 'column' | 'column-reverse';
|
|
11
|
+
|
|
12
|
+
const options: ToggleButtonGroupItem< FlexDirection >[] = [
|
|
13
|
+
{
|
|
14
|
+
value: 'row',
|
|
15
|
+
label: __( 'Row', 'elementor' ),
|
|
16
|
+
renderContent: ( { size } ) => {
|
|
17
|
+
const StartIcon = withDirection( ArrowRightIcon );
|
|
18
|
+
return <StartIcon fontSize={ size } />;
|
|
19
|
+
},
|
|
20
|
+
showTooltip: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: 'column',
|
|
24
|
+
label: __( 'Column', 'elementor' ),
|
|
25
|
+
renderContent: ( { size } ) => <ArrowDownSmallIcon fontSize={ size } />,
|
|
26
|
+
showTooltip: true,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: 'row-reverse',
|
|
30
|
+
label: __( 'Reversed row', 'elementor' ),
|
|
31
|
+
renderContent: ( { size } ) => {
|
|
32
|
+
const EndIcon = withDirection( ArrowLeftIcon );
|
|
33
|
+
return <EndIcon fontSize={ size } />;
|
|
34
|
+
},
|
|
35
|
+
showTooltip: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
value: 'column-reverse',
|
|
39
|
+
label: __( 'Reversed column', 'elementor' ),
|
|
40
|
+
renderContent: ( { size } ) => <ArrowUpSmallIcon fontSize={ size } />,
|
|
41
|
+
showTooltip: true,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export const FlexDirectionField = () => {
|
|
46
|
+
const { isSiteRtl } = useDirection();
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<DirectionProvider rtl={ isSiteRtl }>
|
|
50
|
+
<ThemeProvider>
|
|
51
|
+
<StylesField bind="flex-direction">
|
|
52
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
53
|
+
<Grid item xs={ 6 }>
|
|
54
|
+
<ControlLabel>{ __( 'Direction', 'elementor' ) }</ControlLabel>
|
|
55
|
+
</Grid>
|
|
56
|
+
<Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'end' } }>
|
|
57
|
+
<ToggleControl options={ options } />
|
|
58
|
+
</Grid>
|
|
59
|
+
</Grid>
|
|
60
|
+
</StylesField>
|
|
61
|
+
</ThemeProvider>
|
|
62
|
+
</DirectionProvider>
|
|
63
|
+
);
|
|
64
|
+
};
|