@elementor/editor-controls 0.36.0 → 1.1.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 +46 -0
- package/dist/index.d.mts +78 -45
- package/dist/index.d.ts +78 -45
- package/dist/index.js +951 -651
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +890 -596
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -7
- package/src/bound-prop-context/use-bound-prop.ts +4 -1
- package/src/components/font-family-selector.tsx +23 -164
- package/src/components/popover-grid-container.tsx +7 -10
- package/src/components/repeater.tsx +24 -10
- package/src/components/size-control/size-input.tsx +125 -0
- package/src/components/{text-field-inner-selection.tsx → size-control/text-field-inner-selection.tsx} +33 -16
- package/src/components/text-field-popover.tsx +47 -0
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +11 -3
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-size.tsx +7 -3
- package/src/controls/box-shadow-repeater-control.tsx +8 -6
- package/src/controls/equal-unequal-sizes-control.tsx +24 -14
- package/src/controls/gap-control.tsx +17 -6
- package/src/controls/key-value-control.tsx +99 -0
- package/src/controls/linked-dimensions-control.tsx +62 -81
- package/src/controls/position-control.tsx +109 -0
- package/src/controls/repeatable-control.tsx +89 -0
- package/src/controls/size-control.tsx +181 -149
- package/src/controls/stroke-control.tsx +9 -6
- package/src/hooks/use-repeatable-control-context.ts +24 -0
- package/src/hooks/use-size-extended-options.ts +21 -0
- package/src/index.ts +4 -1
- package/src/utils/size-control.ts +10 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { backgroundImagePositionOffsetPropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
|
|
3
4
|
import { MenuListItem } from '@elementor/editor-ui';
|
|
4
5
|
import { LetterXIcon, LetterYIcon } from '@elementor/icons';
|
|
@@ -40,6 +41,7 @@ export const BackgroundImageOverlayPosition = () => {
|
|
|
40
41
|
const stringPropContext = useBoundProp( stringPropTypeUtil );
|
|
41
42
|
|
|
42
43
|
const isCustom = !! backgroundImageOffsetContext.value;
|
|
44
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
43
45
|
|
|
44
46
|
const handlePositionChange = ( event: SelectChangeEvent< Positions > ) => {
|
|
45
47
|
const value = event.target.value || null;
|
|
@@ -78,15 +80,21 @@ export const BackgroundImageOverlayPosition = () => {
|
|
|
78
80
|
{ isCustom ? (
|
|
79
81
|
<PropProvider { ...backgroundImageOffsetContext }>
|
|
80
82
|
<Grid item xs={ 12 }>
|
|
81
|
-
<Grid container spacing={ 1.5 }>
|
|
83
|
+
<Grid container spacing={ 1.5 } ref={ rowRef }>
|
|
82
84
|
<Grid item xs={ 6 }>
|
|
83
85
|
<PropKeyProvider bind={ 'x' }>
|
|
84
|
-
<SizeControl
|
|
86
|
+
<SizeControl
|
|
87
|
+
startIcon={ <LetterXIcon fontSize={ 'tiny' } /> }
|
|
88
|
+
anchorRef={ rowRef }
|
|
89
|
+
/>
|
|
85
90
|
</PropKeyProvider>
|
|
86
91
|
</Grid>
|
|
87
92
|
<Grid item xs={ 6 }>
|
|
88
93
|
<PropKeyProvider bind={ 'y' }>
|
|
89
|
-
<SizeControl
|
|
94
|
+
<SizeControl
|
|
95
|
+
startIcon={ <LetterYIcon fontSize={ 'tiny' } /> }
|
|
96
|
+
anchorRef={ rowRef }
|
|
97
|
+
/>
|
|
90
98
|
</PropKeyProvider>
|
|
91
99
|
</Grid>
|
|
92
100
|
</Grid>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { backgroundImageSizeScalePropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
|
|
3
4
|
import {
|
|
4
5
|
ArrowBarBothIcon,
|
|
@@ -54,6 +55,7 @@ export const BackgroundImageOverlaySize = () => {
|
|
|
54
55
|
const stringPropContext = useBoundProp( stringPropTypeUtil );
|
|
55
56
|
|
|
56
57
|
const isCustom = !! backgroundImageScaleContext.value;
|
|
58
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
57
59
|
|
|
58
60
|
const handleSizeChange = ( size: Sizes | null ) => {
|
|
59
61
|
if ( size === 'custom' ) {
|
|
@@ -85,13 +87,14 @@ export const BackgroundImageOverlaySize = () => {
|
|
|
85
87
|
</Grid>
|
|
86
88
|
{ isCustom ? (
|
|
87
89
|
<PropProvider { ...backgroundImageScaleContext }>
|
|
88
|
-
<Grid item xs={ 12 }>
|
|
90
|
+
<Grid item xs={ 12 } ref={ rowRef }>
|
|
89
91
|
<PopoverGridContainer>
|
|
90
92
|
<Grid item xs={ 6 }>
|
|
91
93
|
<PropKeyProvider bind={ 'width' }>
|
|
92
94
|
<SizeControl
|
|
93
95
|
startIcon={ <ArrowsMoveHorizontalIcon fontSize={ 'tiny' } /> }
|
|
94
|
-
|
|
96
|
+
extendedOptions={ [ 'auto' ] }
|
|
97
|
+
anchorRef={ rowRef }
|
|
95
98
|
/>
|
|
96
99
|
</PropKeyProvider>
|
|
97
100
|
</Grid>
|
|
@@ -99,7 +102,8 @@ export const BackgroundImageOverlaySize = () => {
|
|
|
99
102
|
<PropKeyProvider bind={ 'height' }>
|
|
100
103
|
<SizeControl
|
|
101
104
|
startIcon={ <ArrowsMoveVerticalIcon fontSize={ 'tiny' } /> }
|
|
102
|
-
|
|
105
|
+
extendedOptions={ [ 'auto' ] }
|
|
106
|
+
anchorRef={ rowRef }
|
|
103
107
|
/>
|
|
104
108
|
</PropKeyProvider>
|
|
105
109
|
</Grid>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { boxShadowPropTypeUtil, type PropKey, shadowPropTypeUtil, type ShadowPropValue } from '@elementor/editor-props';
|
|
3
4
|
import { FormLabel, Grid, type SxProps, type Theme, UnstableColorIndicator } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -48,6 +49,7 @@ const ItemContent = ( { anchorEl, bind }: { anchorEl: HTMLElement | null; bind:
|
|
|
48
49
|
|
|
49
50
|
const Content = ( { anchorEl }: { anchorEl: HTMLElement | null } ) => {
|
|
50
51
|
const context = useBoundProp( shadowPropTypeUtil );
|
|
52
|
+
const rowRef: MutableRefObject< HTMLElement | undefined >[] = [ useRef(), useRef() ];
|
|
51
53
|
|
|
52
54
|
return (
|
|
53
55
|
<PropProvider { ...context }>
|
|
@@ -65,20 +67,20 @@ const Content = ( { anchorEl }: { anchorEl: HTMLElement | null } ) => {
|
|
|
65
67
|
/>
|
|
66
68
|
</Control>
|
|
67
69
|
</PopoverGridContainer>
|
|
68
|
-
<PopoverGridContainer>
|
|
70
|
+
<PopoverGridContainer ref={ rowRef[ 0 ] }>
|
|
69
71
|
<Control bind="hOffset" label={ __( 'Horizontal', 'elementor' ) }>
|
|
70
|
-
<SizeControl />
|
|
72
|
+
<SizeControl anchorRef={ rowRef[ 0 ] } />
|
|
71
73
|
</Control>
|
|
72
74
|
<Control bind="vOffset" label={ __( 'Vertical', 'elementor' ) }>
|
|
73
|
-
<SizeControl />
|
|
75
|
+
<SizeControl anchorRef={ rowRef[ 0 ] } />
|
|
74
76
|
</Control>
|
|
75
77
|
</PopoverGridContainer>
|
|
76
|
-
<PopoverGridContainer>
|
|
78
|
+
<PopoverGridContainer ref={ rowRef[ 1 ] }>
|
|
77
79
|
<Control bind="blur" label={ __( 'Blur', 'elementor' ) }>
|
|
78
|
-
<SizeControl />
|
|
80
|
+
<SizeControl anchorRef={ rowRef[ 1 ] } />
|
|
79
81
|
</Control>
|
|
80
82
|
<Control bind="spread" label={ __( 'Spread', 'elementor' ) }>
|
|
81
|
-
<SizeControl />
|
|
83
|
+
<SizeControl anchorRef={ rowRef[ 1 ] } />
|
|
82
84
|
</Control>
|
|
83
85
|
</PopoverGridContainer>
|
|
84
86
|
</PopoverContent>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type ReactNode, useId, useRef } from 'react';
|
|
2
|
+
import { type MutableRefObject, type ReactNode, useId, useRef } from 'react';
|
|
3
3
|
import { type PropKey, type PropTypeUtil, sizePropTypeUtil, type SizePropValue } from '@elementor/editor-props';
|
|
4
4
|
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
5
5
|
import { bindPopover, bindToggle, Grid, Popover, Stack, ToggleButton, Tooltip, usePopupState } from '@elementor/ui';
|
|
@@ -52,7 +52,6 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
52
52
|
multiSizePropTypeUtil,
|
|
53
53
|
}: Props< TMultiPropType, TPropValue > ) {
|
|
54
54
|
const popupId = useId();
|
|
55
|
-
const controlRef = useRef< HTMLElement >( null );
|
|
56
55
|
const popupState = usePopupState( { variant: 'popover', popupId } );
|
|
57
56
|
|
|
58
57
|
const {
|
|
@@ -64,6 +63,8 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
64
63
|
|
|
65
64
|
const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
|
|
66
65
|
|
|
66
|
+
const rowRefs: MutableRefObject< HTMLElement | undefined >[] = [ useRef(), useRef() ];
|
|
67
|
+
|
|
67
68
|
const splitEqualValue = () => {
|
|
68
69
|
if ( ! sizeValue ) {
|
|
69
70
|
return null;
|
|
@@ -104,7 +105,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
104
105
|
|
|
105
106
|
return (
|
|
106
107
|
<>
|
|
107
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={
|
|
108
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRefs[ 0 ] }>
|
|
108
109
|
<Grid item xs={ 6 }>
|
|
109
110
|
{ ! isShowingGeneralIndicator ? (
|
|
110
111
|
<ControlFormLabel>{ label }</ControlFormLabel>
|
|
@@ -114,7 +115,10 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
114
115
|
</Grid>
|
|
115
116
|
<Grid item xs={ 6 }>
|
|
116
117
|
<Stack direction="row" alignItems="center" gap={ 1 }>
|
|
117
|
-
<SizeControl
|
|
118
|
+
<SizeControl
|
|
119
|
+
placeholder={ isMixed ? __( 'Mixed', 'elementor' ) : undefined }
|
|
120
|
+
anchorRef={ rowRefs[ 0 ] }
|
|
121
|
+
/>
|
|
118
122
|
<Tooltip title={ tooltipLabel } placement="top">
|
|
119
123
|
<ToggleButton
|
|
120
124
|
size={ 'tiny' }
|
|
@@ -143,7 +147,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
143
147
|
} }
|
|
144
148
|
{ ...bindPopover( popupState ) }
|
|
145
149
|
slotProps={ {
|
|
146
|
-
paper: { sx: { mt: 0.5, width:
|
|
150
|
+
paper: { sx: { mt: 0.5, width: rowRefs[ 0 ].current?.getBoundingClientRect().width } },
|
|
147
151
|
} }
|
|
148
152
|
>
|
|
149
153
|
<PropProvider
|
|
@@ -152,14 +156,14 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
152
156
|
setValue={ setNestedProp }
|
|
153
157
|
disabled={ multiSizeDisabled }
|
|
154
158
|
>
|
|
155
|
-
<PopoverContent p={ 1.5 }
|
|
156
|
-
<PopoverGridContainer>
|
|
157
|
-
<MultiSizeValueControl item={ items[ 0 ] } />
|
|
158
|
-
<MultiSizeValueControl item={ items[ 1 ] } />
|
|
159
|
+
<PopoverContent p={ 1.5 }>
|
|
160
|
+
<PopoverGridContainer ref={ rowRefs[ 1 ] }>
|
|
161
|
+
<MultiSizeValueControl item={ items[ 0 ] } rowRef={ rowRefs[ 1 ] } />
|
|
162
|
+
<MultiSizeValueControl item={ items[ 1 ] } rowRef={ rowRefs[ 1 ] } />
|
|
159
163
|
</PopoverGridContainer>
|
|
160
|
-
<PopoverGridContainer>
|
|
161
|
-
<MultiSizeValueControl item={ items[ 2 ] } />
|
|
162
|
-
<MultiSizeValueControl item={ items[ 3 ] } />
|
|
164
|
+
<PopoverGridContainer ref={ rowRefs[ 2 ] }>
|
|
165
|
+
<MultiSizeValueControl item={ items[ 2 ] } rowRef={ rowRefs[ 2 ] } />
|
|
166
|
+
<MultiSizeValueControl item={ items[ 3 ] } rowRef={ rowRefs[ 2 ] } />
|
|
163
167
|
</PopoverGridContainer>
|
|
164
168
|
</PopoverContent>
|
|
165
169
|
</PropProvider>
|
|
@@ -168,7 +172,13 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
|
|
|
168
172
|
);
|
|
169
173
|
}
|
|
170
174
|
|
|
171
|
-
const MultiSizeValueControl = ( {
|
|
175
|
+
const MultiSizeValueControl = ( {
|
|
176
|
+
item,
|
|
177
|
+
rowRef,
|
|
178
|
+
}: {
|
|
179
|
+
item: Item;
|
|
180
|
+
rowRef: MutableRefObject< HTMLElement | undefined >;
|
|
181
|
+
} ) => {
|
|
172
182
|
const isUsingNestedProps = isExperimentActive( 'e_v_3_30' );
|
|
173
183
|
|
|
174
184
|
return (
|
|
@@ -183,7 +193,7 @@ const MultiSizeValueControl = ( { item }: { item: Item } ) => {
|
|
|
183
193
|
) }
|
|
184
194
|
</Grid>
|
|
185
195
|
<Grid item xs={ 12 }>
|
|
186
|
-
<SizeControl startIcon={ item.icon } />
|
|
196
|
+
<SizeControl startIcon={ item.icon } anchorRef={ rowRef } />
|
|
187
197
|
</Grid>
|
|
188
198
|
</Grid>
|
|
189
199
|
</Grid>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { layoutDirectionPropTypeUtil, type PropKey, sizePropTypeUtil } from '@elementor/editor-props';
|
|
3
4
|
import { DetachIcon, LinkIcon } from '@elementor/icons';
|
|
4
5
|
import { Grid, Stack, ToggleButton, Tooltip } from '@elementor/ui';
|
|
@@ -18,6 +19,8 @@ export const GapControl = createControl( ( { label }: { label: string } ) => {
|
|
|
18
19
|
disabled: directionDisabled,
|
|
19
20
|
} = useBoundProp( layoutDirectionPropTypeUtil );
|
|
20
21
|
|
|
22
|
+
const stackRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
23
|
+
|
|
21
24
|
const { value: sizeValue, setValue: setSizeValue, disabled: sizeDisabled } = useBoundProp( sizePropTypeUtil );
|
|
22
25
|
|
|
23
26
|
const isLinked = ! directionValue && ! sizeValue ? true : !! sizeValue;
|
|
@@ -64,13 +67,13 @@ export const GapControl = createControl( ( { label }: { label: string } ) => {
|
|
|
64
67
|
</ToggleButton>
|
|
65
68
|
</Tooltip>
|
|
66
69
|
</Stack>
|
|
67
|
-
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
70
|
+
<Stack direction="row" gap={ 2 } flexWrap="nowrap" ref={ stackRef }>
|
|
68
71
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
69
72
|
<Grid item xs={ 12 }>
|
|
70
73
|
<ControlFormLabel>{ __( 'Column', 'elementor' ) }</ControlFormLabel>
|
|
71
74
|
</Grid>
|
|
72
75
|
<Grid item xs={ 12 }>
|
|
73
|
-
<Control bind={ 'column' } isLinked={ isLinked } />
|
|
76
|
+
<Control bind={ 'column' } isLinked={ isLinked } anchorRef={ stackRef } />
|
|
74
77
|
</Grid>
|
|
75
78
|
</Grid>
|
|
76
79
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
@@ -78,7 +81,7 @@ export const GapControl = createControl( ( { label }: { label: string } ) => {
|
|
|
78
81
|
<ControlFormLabel>{ __( 'Row', 'elementor' ) }</ControlFormLabel>
|
|
79
82
|
</Grid>
|
|
80
83
|
<Grid item xs={ 12 }>
|
|
81
|
-
<Control bind={ 'row' } isLinked={ isLinked } />
|
|
84
|
+
<Control bind={ 'row' } isLinked={ isLinked } anchorRef={ stackRef } />
|
|
82
85
|
</Grid>
|
|
83
86
|
</Grid>
|
|
84
87
|
</Stack>
|
|
@@ -86,14 +89,22 @@ export const GapControl = createControl( ( { label }: { label: string } ) => {
|
|
|
86
89
|
);
|
|
87
90
|
} );
|
|
88
91
|
|
|
89
|
-
const Control = ( {
|
|
92
|
+
const Control = ( {
|
|
93
|
+
bind,
|
|
94
|
+
isLinked,
|
|
95
|
+
anchorRef,
|
|
96
|
+
}: {
|
|
97
|
+
bind: PropKey;
|
|
98
|
+
isLinked: boolean;
|
|
99
|
+
anchorRef: MutableRefObject< HTMLElement | undefined >;
|
|
100
|
+
} ) => {
|
|
90
101
|
if ( isLinked ) {
|
|
91
|
-
return <SizeControl />;
|
|
102
|
+
return <SizeControl anchorRef={ anchorRef } />;
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
return (
|
|
95
106
|
<PropKeyProvider bind={ bind }>
|
|
96
|
-
<SizeControl />
|
|
107
|
+
<SizeControl anchorRef={ anchorRef } />
|
|
97
108
|
</PropKeyProvider>
|
|
98
109
|
);
|
|
99
110
|
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type ChangeEvent, useMemo, useState } from 'react';
|
|
3
|
+
import { keyValuePropTypeUtil } from '@elementor/editor-props';
|
|
4
|
+
import { FormHelperText, FormLabel, Grid, type SxProps, TextField, type Theme } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
8
|
+
import ControlActions from '../control-actions/control-actions';
|
|
9
|
+
import { createControl } from '../create-control';
|
|
10
|
+
|
|
11
|
+
type FieldType = 'key' | 'value';
|
|
12
|
+
|
|
13
|
+
type KeyValueControlProps = {
|
|
14
|
+
keyName?: string;
|
|
15
|
+
valueName?: string;
|
|
16
|
+
sx?: SxProps< Theme >;
|
|
17
|
+
regexKey?: string;
|
|
18
|
+
regexValue?: string;
|
|
19
|
+
validationErrorMessage?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const KeyValueControl = createControl( ( props: KeyValueControlProps = {} ) => {
|
|
23
|
+
const { value, setValue } = useBoundProp( keyValuePropTypeUtil );
|
|
24
|
+
const [ keyError, setKeyError ] = useState< string | null >( null );
|
|
25
|
+
const [ valueError, setValueError ] = useState< string | null >( null );
|
|
26
|
+
const keyLabel = props.keyName || __( 'Key', 'elementor' );
|
|
27
|
+
const valueLabel = props.valueName || __( 'Value', 'elementor' );
|
|
28
|
+
|
|
29
|
+
const keyValue = value?.key?.value || '';
|
|
30
|
+
const valueValue = value?.value?.value || '';
|
|
31
|
+
|
|
32
|
+
const [ keyRegex, valueRegex, errMsg ] = useMemo< [ RegExp | undefined, RegExp | undefined, string ] >(
|
|
33
|
+
() => [
|
|
34
|
+
props.regexKey ? new RegExp( props.regexKey ) : undefined,
|
|
35
|
+
props.regexValue ? new RegExp( props.regexValue ) : undefined,
|
|
36
|
+
props.validationErrorMessage || __( 'Invalid Format', 'elementor' ),
|
|
37
|
+
],
|
|
38
|
+
[ props.regexKey, props.regexValue, props.validationErrorMessage ]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const validate = ( newValue: string, FieldType: string ): void => {
|
|
42
|
+
if ( FieldType === 'key' && keyRegex ) {
|
|
43
|
+
const isValid = keyRegex.test( newValue );
|
|
44
|
+
setKeyError( isValid ? null : errMsg );
|
|
45
|
+
} else if ( FieldType === 'value' && valueRegex ) {
|
|
46
|
+
const isValid = valueRegex.test( newValue );
|
|
47
|
+
setValueError( isValid ? null : errMsg );
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleChange = ( event: ChangeEvent< HTMLInputElement >, fieldType: FieldType ) => {
|
|
52
|
+
const newValue = event.target.value;
|
|
53
|
+
|
|
54
|
+
validate( newValue, fieldType );
|
|
55
|
+
|
|
56
|
+
setValue( {
|
|
57
|
+
...value,
|
|
58
|
+
[ fieldType ]: {
|
|
59
|
+
value: newValue,
|
|
60
|
+
$$type: 'string',
|
|
61
|
+
},
|
|
62
|
+
} );
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const isKeyInvalid = keyError !== null;
|
|
66
|
+
const isValueInvalid = valueError !== null;
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<ControlActions>
|
|
70
|
+
<Grid container gap={ 1.5 } p={ 1.5 } sx={ props.sx }>
|
|
71
|
+
<Grid item xs={ 12 }>
|
|
72
|
+
<FormLabel size="tiny">{ keyLabel }</FormLabel>
|
|
73
|
+
<TextField
|
|
74
|
+
sx={ { pt: 1 } }
|
|
75
|
+
size="tiny"
|
|
76
|
+
fullWidth
|
|
77
|
+
value={ keyValue }
|
|
78
|
+
onChange={ ( e: ChangeEvent< HTMLInputElement > ) => handleChange( e, 'key' ) }
|
|
79
|
+
error={ isKeyInvalid }
|
|
80
|
+
/>
|
|
81
|
+
{ isKeyInvalid && <FormHelperText error>{ keyError }</FormHelperText> }
|
|
82
|
+
</Grid>
|
|
83
|
+
<Grid item xs={ 12 }>
|
|
84
|
+
<FormLabel size="tiny">{ valueLabel }</FormLabel>
|
|
85
|
+
<TextField
|
|
86
|
+
sx={ { pt: 1 } }
|
|
87
|
+
size="tiny"
|
|
88
|
+
fullWidth
|
|
89
|
+
value={ valueValue }
|
|
90
|
+
onChange={ ( e: ChangeEvent< HTMLInputElement > ) => handleChange( e, 'value' ) }
|
|
91
|
+
disabled={ isKeyInvalid }
|
|
92
|
+
error={ isValueInvalid }
|
|
93
|
+
/>
|
|
94
|
+
{ isValueInvalid && <FormHelperText error>{ valueError }</FormHelperText> }
|
|
95
|
+
</Grid>
|
|
96
|
+
</Grid>
|
|
97
|
+
</ControlActions>
|
|
98
|
+
);
|
|
99
|
+
} );
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { dimensionsPropTypeUtil, type PropKey, sizePropTypeUtil } from '@elementor/editor-props';
|
|
3
4
|
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
4
5
|
import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
@@ -9,19 +10,21 @@ import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-conte
|
|
|
9
10
|
import { ControlFormLabel } from '../components/control-form-label';
|
|
10
11
|
import { ControlLabel } from '../components/control-label';
|
|
11
12
|
import { createControl } from '../create-control';
|
|
12
|
-
import { type
|
|
13
|
+
import { type ExtendedOption } from '../utils/size-control';
|
|
14
|
+
import { SizeControl } from './size-control';
|
|
13
15
|
|
|
14
16
|
export const LinkedDimensionsControl = createControl(
|
|
15
17
|
( {
|
|
16
18
|
label,
|
|
17
19
|
isSiteRtl = false,
|
|
18
|
-
|
|
20
|
+
extendedOptions,
|
|
19
21
|
}: {
|
|
20
22
|
label: string;
|
|
21
23
|
isSiteRtl?: boolean;
|
|
22
|
-
|
|
24
|
+
extendedOptions?: ExtendedOption[];
|
|
23
25
|
} ) => {
|
|
24
26
|
const { value: sizeValue, setValue: setSizeValue, disabled: sizeDisabled } = useBoundProp( sizePropTypeUtil );
|
|
27
|
+
const gridRowRefs: MutableRefObject< HTMLElement | undefined >[] = [ useRef(), useRef() ];
|
|
25
28
|
|
|
26
29
|
const {
|
|
27
30
|
value: dimensionsValue,
|
|
@@ -87,80 +90,27 @@ export const LinkedDimensionsControl = createControl(
|
|
|
87
90
|
</ToggleButton>
|
|
88
91
|
</Tooltip>
|
|
89
92
|
</Stack>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<Grid item xs={ 12 }>
|
|
112
|
-
<Control
|
|
113
|
-
bind={ 'inline-end' }
|
|
114
|
-
startIcon={
|
|
115
|
-
isSiteRtl ? (
|
|
116
|
-
<SideLeftIcon fontSize={ 'tiny' } />
|
|
117
|
-
) : (
|
|
118
|
-
<SideRightIcon fontSize={ 'tiny' } />
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
isLinked={ isLinked }
|
|
122
|
-
extendedValues={ extendedValues }
|
|
123
|
-
/>
|
|
124
|
-
</Grid>
|
|
125
|
-
</Grid>
|
|
126
|
-
</Stack>
|
|
127
|
-
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
128
|
-
<Grid container gap={ 0.75 } alignItems="center">
|
|
129
|
-
<Grid item xs={ 12 }>
|
|
130
|
-
<Label bind="block-end" label={ __( 'Bottom', 'elementor' ) } />
|
|
131
|
-
</Grid>
|
|
132
|
-
<Grid item xs={ 12 }>
|
|
133
|
-
<Control
|
|
134
|
-
bind={ 'block-end' }
|
|
135
|
-
startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
|
|
136
|
-
isLinked={ isLinked }
|
|
137
|
-
extendedValues={ extendedValues }
|
|
138
|
-
/>
|
|
139
|
-
</Grid>
|
|
140
|
-
</Grid>
|
|
141
|
-
<Grid container gap={ 0.75 } alignItems="center">
|
|
142
|
-
<Grid item xs={ 12 }>
|
|
143
|
-
<Label
|
|
144
|
-
bind="inline-start"
|
|
145
|
-
label={ isSiteRtl ? __( 'Right', 'elementor' ) : __( 'Left', 'elementor' ) }
|
|
146
|
-
/>
|
|
147
|
-
</Grid>
|
|
148
|
-
<Grid item xs={ 12 }>
|
|
149
|
-
<Control
|
|
150
|
-
bind={ 'inline-start' }
|
|
151
|
-
isLinked={ isLinked }
|
|
152
|
-
extendedValues={ extendedValues }
|
|
153
|
-
startIcon={
|
|
154
|
-
isSiteRtl ? (
|
|
155
|
-
<SideRightIcon fontSize={ 'tiny' } />
|
|
156
|
-
) : (
|
|
157
|
-
<SideLeftIcon fontSize={ 'tiny' } />
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
/>
|
|
161
|
-
</Grid>
|
|
162
|
-
</Grid>
|
|
163
|
-
</Stack>
|
|
93
|
+
|
|
94
|
+
{ getCssMarginProps( isSiteRtl ).map( ( row, index ) => (
|
|
95
|
+
<Stack direction="row" gap={ 2 } flexWrap="nowrap" key={ index } ref={ gridRowRefs[ index ] }>
|
|
96
|
+
{ row.map( ( { icon, ...props } ) => (
|
|
97
|
+
<Grid container gap={ 0.75 } alignItems="center" key={ props.bind }>
|
|
98
|
+
<Grid item xs={ 12 }>
|
|
99
|
+
<Label { ...props } />
|
|
100
|
+
</Grid>
|
|
101
|
+
<Grid item xs={ 12 }>
|
|
102
|
+
<Control
|
|
103
|
+
bind={ props.bind }
|
|
104
|
+
startIcon={ icon }
|
|
105
|
+
isLinked={ isLinked }
|
|
106
|
+
extendedOptions={ extendedOptions }
|
|
107
|
+
anchorRef={ gridRowRefs[ index ] }
|
|
108
|
+
/>
|
|
109
|
+
</Grid>
|
|
110
|
+
</Grid>
|
|
111
|
+
) ) }
|
|
112
|
+
</Stack>
|
|
113
|
+
) ) }
|
|
164
114
|
</PropProvider>
|
|
165
115
|
);
|
|
166
116
|
}
|
|
@@ -170,20 +120,22 @@ const Control = ( {
|
|
|
170
120
|
bind,
|
|
171
121
|
startIcon,
|
|
172
122
|
isLinked,
|
|
173
|
-
|
|
123
|
+
extendedOptions,
|
|
124
|
+
anchorRef,
|
|
174
125
|
}: {
|
|
175
126
|
bind: PropKey;
|
|
176
127
|
startIcon: React.ReactNode;
|
|
177
128
|
isLinked: boolean;
|
|
178
|
-
|
|
129
|
+
extendedOptions?: ExtendedOption[];
|
|
130
|
+
anchorRef: MutableRefObject< HTMLElement | undefined >;
|
|
179
131
|
} ) => {
|
|
180
132
|
if ( isLinked ) {
|
|
181
|
-
return <SizeControl startIcon={ startIcon }
|
|
133
|
+
return <SizeControl startIcon={ startIcon } extendedOptions={ extendedOptions } anchorRef={ anchorRef } />;
|
|
182
134
|
}
|
|
183
135
|
|
|
184
136
|
return (
|
|
185
137
|
<PropKeyProvider bind={ bind }>
|
|
186
|
-
<SizeControl startIcon={ startIcon }
|
|
138
|
+
<SizeControl startIcon={ startIcon } extendedOptions={ extendedOptions } anchorRef={ anchorRef } />
|
|
187
139
|
</PropKeyProvider>
|
|
188
140
|
);
|
|
189
141
|
};
|
|
@@ -201,3 +153,32 @@ const Label = ( { label, bind }: { label: string; bind: PropKey } ) => {
|
|
|
201
153
|
</PropKeyProvider>
|
|
202
154
|
);
|
|
203
155
|
};
|
|
156
|
+
|
|
157
|
+
function getCssMarginProps( isSiteRtl: boolean ) {
|
|
158
|
+
return [
|
|
159
|
+
[
|
|
160
|
+
{
|
|
161
|
+
bind: 'block-start',
|
|
162
|
+
label: __( 'Top', 'elementor' ),
|
|
163
|
+
icon: <SideTopIcon fontSize={ 'tiny' } />,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
bind: 'inline-end',
|
|
167
|
+
label: isSiteRtl ? __( 'Left', 'elementor' ) : __( 'Right', 'elementor' ),
|
|
168
|
+
icon: isSiteRtl ? <SideLeftIcon fontSize={ 'tiny' } /> : <SideRightIcon fontSize={ 'tiny' } />,
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
[
|
|
172
|
+
{
|
|
173
|
+
bind: 'block-end',
|
|
174
|
+
label: __( 'Bottom', 'elementor' ),
|
|
175
|
+
icon: <SideBottomIcon fontSize={ 'tiny' } />,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
bind: 'inline-start',
|
|
179
|
+
label: isSiteRtl ? __( 'Right', 'elementor' ) : __( 'Left', 'elementor' ),
|
|
180
|
+
icon: isSiteRtl ? <SideRightIcon fontSize={ 'tiny' } /> : <SideLeftIcon fontSize={ 'tiny' } />,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
];
|
|
184
|
+
}
|