@elementor/editor-editing-panel 0.18.0 → 1.0.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 +64 -0
- package/dist/index.d.mts +8 -24
- package/dist/index.d.ts +8 -24
- package/dist/index.js +1452 -1122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1436 -1099
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -14
- package/src/components/accordion-section.tsx +3 -2
- package/src/components/add-or-remove-content.tsx +42 -0
- package/src/components/collapsible-field.tsx +34 -0
- package/src/components/editing-panel-error-fallback.tsx +12 -0
- package/src/components/editing-panel.tsx +27 -19
- package/src/components/settings-tab.tsx +12 -11
- package/src/components/style-sections/background-section/background-color-field.tsx +21 -0
- package/src/components/style-sections/background-section/background-section.tsx +15 -0
- package/src/components/style-sections/border-section/border-color-field.tsx +21 -0
- package/src/components/style-sections/border-section/border-field.tsx +47 -0
- package/src/components/style-sections/border-section/border-radius-field.tsx +48 -0
- package/src/components/style-sections/border-section/border-section.tsx +16 -0
- package/src/components/style-sections/border-section/border-style-field.tsx +32 -0
- package/src/components/style-sections/border-section/border-width-field.tsx +42 -0
- package/src/components/style-sections/effects-section/effects-section.tsx +5 -5
- package/src/components/style-sections/position-section/dimensions-field.tsx +46 -0
- package/src/components/style-sections/position-section/position-field.tsx +28 -0
- package/src/components/style-sections/position-section/position-section.tsx +15 -2
- package/src/components/style-sections/position-section/z-index-field.tsx +21 -0
- package/src/components/style-sections/size-section/overflow-field.tsx +45 -0
- package/src/components/style-sections/size-section/size-section.tsx +55 -0
- package/src/components/style-sections/spacing-section/spacing-section.tsx +6 -6
- package/src/components/style-sections/typography-section/font-size-field.tsx +21 -0
- package/src/components/style-sections/typography-section/{font-weight-control.tsx → font-weight-field.tsx} +7 -6
- package/src/components/style-sections/typography-section/letter-spacing-field.tsx +21 -0
- package/src/components/style-sections/typography-section/{text-alignment-control.tsx → text-alignment-field.tsx} +8 -8
- package/src/components/style-sections/typography-section/text-color-field.tsx +21 -0
- package/src/components/style-sections/typography-section/{text-direction-control.tsx → text-direction-field.tsx} +8 -8
- package/src/components/style-sections/typography-section/text-stroke-field.tsx +16 -0
- package/src/components/style-sections/typography-section/{text-style-control.tsx → text-style-field.tsx} +5 -5
- package/src/components/style-sections/typography-section/{transform-control.tsx → transform-field.tsx} +8 -7
- package/src/components/style-sections/typography-section/typography-section.tsx +20 -18
- package/src/components/style-sections/typography-section/word-spacing-field.tsx +21 -0
- package/src/components/style-tab.tsx +44 -25
- package/src/contexts/classes-prop-context.tsx +24 -0
- package/src/contexts/element-context.tsx +6 -10
- package/src/contexts/style-context.tsx +8 -22
- package/src/control-replacement.tsx +3 -0
- package/src/controls/bound-prop-context.tsx +30 -0
- package/src/controls/components/control-toggle-button-group.tsx +15 -6
- package/src/controls/components/repeater.tsx +1 -1
- package/src/controls/components/text-field-inner-selection.tsx +20 -24
- package/src/controls/control-actions/control-actions-context.tsx +27 -0
- package/src/controls/control-actions/control-actions-menu.ts +6 -7
- package/src/controls/control-actions/control-actions.tsx +14 -26
- package/src/{components/style-sections/effects-section/box-shadow-repeater.tsx → controls/controls/box-shadow-repeater-control.tsx} +51 -65
- package/src/controls/controls/color-control.tsx +25 -0
- package/src/controls/controls/equal-unequal-sizes-control.tsx +196 -0
- package/src/controls/{control-types → controls}/image-control.tsx +15 -23
- package/src/controls/{control-types → controls}/image-media-control.tsx +5 -14
- package/src/{components/style-sections/spacing-section → controls/controls}/linked-dimensions-control.tsx +10 -26
- package/src/controls/{control-types → controls}/number-control.tsx +2 -2
- package/src/controls/{control-types → controls}/select-control.tsx +4 -4
- package/src/controls/{control-types → controls}/size-control.tsx +8 -8
- package/src/controls/controls/stroke-control.tsx +105 -0
- package/src/controls/{control-types → controls}/text-area-control.tsx +3 -3
- package/src/controls/{control-types → controls}/text-control.tsx +3 -3
- package/src/controls/{control-types → controls}/toggle-control.tsx +4 -4
- package/src/controls/create-control-replacement.tsx +53 -0
- package/src/controls/create-control.tsx +12 -3
- package/src/controls/index.ts +24 -0
- package/src/controls-actions.ts +8 -0
- package/src/{controls/components → controls-registry}/control-type-container.tsx +1 -1
- package/src/{controls → controls-registry}/controls-registry.tsx +1 -6
- package/src/controls-registry/settings-field.tsx +35 -0
- package/src/controls-registry/styles-field.tsx +19 -0
- package/src/dynamics/components/dynamic-selection-control.tsx +11 -11
- package/src/dynamics/components/dynamic-selection.tsx +6 -6
- package/src/dynamics/dynamic-control.tsx +6 -5
- package/src/dynamics/hooks/use-dynamic-tag.ts +2 -2
- package/src/dynamics/hooks/use-prop-dynamic-action.tsx +7 -7
- package/src/dynamics/hooks/use-prop-dynamic-tags.ts +3 -3
- package/src/dynamics/hooks/use-prop-value-history.ts +3 -3
- package/src/dynamics/init.ts +2 -4
- package/src/dynamics/types.ts +2 -1
- package/src/dynamics/utils.ts +1 -2
- package/src/hooks/use-styles-field.ts +30 -0
- package/src/index.ts +3 -4
- package/src/sync/should-use-v2-panel.ts +1 -2
- package/src/sync/types.ts +3 -2
- package/src/components/style-sections/position-section/z-index-control.tsx +0 -20
- package/src/components/style-sections/size-section.tsx +0 -49
- package/src/components/style-sections/typography-section/font-size-control.tsx +0 -20
- package/src/components/style-sections/typography-section/letter-spacing-control.tsx +0 -20
- package/src/components/style-sections/typography-section/text-color-control.tsx +0 -20
- package/src/components/style-sections/typography-section/word-spacing-control.tsx +0 -20
- package/src/controls/control-context.tsx +0 -22
- package/src/controls/control-replacement.ts +0 -34
- package/src/controls/control-types/color-control.tsx +0 -27
- package/src/controls/hooks/use-style-control.ts +0 -29
- package/src/controls/settings-control.tsx +0 -37
- package/src/controls/style-control.tsx +0 -20
- package/src/hooks/use-element-style-prop.ts +0 -45
- package/src/hooks/use-element-styles.ts +0 -13
- package/src/hooks/use-element-type.ts +0 -33
- package/src/hooks/use-selected-elements.ts +0 -9
- package/src/hooks/use-widget-settings.ts +0 -16
- package/src/props/is-transformable.ts +0 -14
- package/src/sync/get-container.ts +0 -8
- package/src/sync/get-element-styles.ts +0 -9
- package/src/sync/get-selected-elements.ts +0 -21
- package/src/sync/get-widgets-cache.ts +0 -7
- package/src/sync/update-settings.ts +0 -14
- package/src/sync/update-style.ts +0 -24
- package/src/types.ts +0 -89
- package/src/{controls → controls-registry}/control.tsx +0 -0
- package/src/{controls/control-actions/actions/popover-action.tsx → popover-action.tsx} +1 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode, useId, useRef } from 'react';
|
|
3
|
+
import { PropValue, TransformablePropValue } from '@elementor/editor-props';
|
|
4
|
+
import { bindPopover, bindToggle, Grid, Popover, Stack, ToggleButton, usePopupState } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { ControlLabel } from '../../components/control-label';
|
|
7
|
+
import { BoundPropProvider, SizeControl, SizeControlValue, useBoundProp } from '../index';
|
|
8
|
+
|
|
9
|
+
type MultiSizePropValue< TMultiPropType extends string > = TransformablePropValue<
|
|
10
|
+
TMultiPropType,
|
|
11
|
+
Record< string, SizeControlValue >
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
type Item< TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > > = {
|
|
15
|
+
icon: ReactNode;
|
|
16
|
+
label: string;
|
|
17
|
+
bind: keyof TPropValue[ 'value' ];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type EqualUnequalItems<
|
|
21
|
+
TMultiPropType extends string,
|
|
22
|
+
TPropValue extends MultiSizePropValue< TMultiPropType >,
|
|
23
|
+
> = [
|
|
24
|
+
Item< TMultiPropType, TPropValue >,
|
|
25
|
+
Item< TMultiPropType, TPropValue >,
|
|
26
|
+
Item< TMultiPropType, TPropValue >,
|
|
27
|
+
Item< TMultiPropType, TPropValue >,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
type Props< TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > > = {
|
|
31
|
+
label: string;
|
|
32
|
+
icon: ReactNode;
|
|
33
|
+
items: EqualUnequalItems< TMultiPropType, TPropValue >;
|
|
34
|
+
multiSizeType: TMultiPropType;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function hasMixedSizes( values: SizeControlValue[] ): boolean {
|
|
38
|
+
const [ firstValue, ...restValues ] = values;
|
|
39
|
+
|
|
40
|
+
return restValues.some(
|
|
41
|
+
( value ) => value?.value?.size !== firstValue?.value?.size || value?.value?.unit !== firstValue?.value?.unit
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function EqualUnequalSizesControl<
|
|
46
|
+
TMultiPropType extends string,
|
|
47
|
+
TPropValue extends MultiSizePropValue< TMultiPropType >,
|
|
48
|
+
>( { label, icon, items, multiSizeType }: Props< TMultiPropType, TPropValue > ) {
|
|
49
|
+
const popupId = useId();
|
|
50
|
+
const controlRef = useRef< HTMLElement >( null );
|
|
51
|
+
const { value: controlValue, setValue: setControlValue } = useBoundProp< TPropValue >();
|
|
52
|
+
|
|
53
|
+
const actualValue: TPropValue[ 'value' ] = controlValue?.value ?? {};
|
|
54
|
+
const setActualValue = ( newValue: TPropValue[ 'value' ] ) => {
|
|
55
|
+
setControlValue( { $$type: multiSizeType, value: newValue } as TPropValue );
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const setNestedProp = ( item: Item< TMultiPropType, TPropValue >, newValue: PropValue ) => {
|
|
59
|
+
const { bind } = item;
|
|
60
|
+
|
|
61
|
+
const newValues = {
|
|
62
|
+
...actualValue,
|
|
63
|
+
[ bind ]: newValue,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
setActualValue( newValues );
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const setEqualValues = ( newValue: PropValue ) => {
|
|
70
|
+
const equalValues = items.reduce( ( values: TPropValue[ 'value' ], item ) => {
|
|
71
|
+
return {
|
|
72
|
+
...values,
|
|
73
|
+
[ item.bind ]: newValue,
|
|
74
|
+
};
|
|
75
|
+
}, {} );
|
|
76
|
+
|
|
77
|
+
setActualValue( equalValues );
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const popupState = usePopupState( {
|
|
81
|
+
variant: 'popover',
|
|
82
|
+
popupId,
|
|
83
|
+
} );
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<Grid container alignItems="center" ref={ controlRef }>
|
|
88
|
+
<Grid item xs={ 6 }>
|
|
89
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
90
|
+
</Grid>
|
|
91
|
+
<Grid item xs={ 6 }>
|
|
92
|
+
<EqualValuesControl
|
|
93
|
+
value={ actualValue }
|
|
94
|
+
setValue={ setEqualValues }
|
|
95
|
+
iconButton={
|
|
96
|
+
<ToggleButton
|
|
97
|
+
size={ 'tiny' }
|
|
98
|
+
value={ 'check' }
|
|
99
|
+
sx={ { marginLeft: 'auto' } }
|
|
100
|
+
{ ...bindToggle( popupState ) }
|
|
101
|
+
selected={ popupState.isOpen }
|
|
102
|
+
>
|
|
103
|
+
{ icon }
|
|
104
|
+
</ToggleButton>
|
|
105
|
+
}
|
|
106
|
+
/>
|
|
107
|
+
</Grid>
|
|
108
|
+
</Grid>
|
|
109
|
+
<Popover
|
|
110
|
+
disablePortal
|
|
111
|
+
disableScrollLock
|
|
112
|
+
anchorOrigin={ {
|
|
113
|
+
vertical: 'bottom',
|
|
114
|
+
horizontal: 'right',
|
|
115
|
+
} }
|
|
116
|
+
transformOrigin={ {
|
|
117
|
+
vertical: 'top',
|
|
118
|
+
horizontal: 'right',
|
|
119
|
+
} }
|
|
120
|
+
{ ...bindPopover( popupState ) }
|
|
121
|
+
slotProps={ {
|
|
122
|
+
paper: { sx: { mt: 0.5, p: 2, pt: 1, width: controlRef.current?.getBoundingClientRect().width } },
|
|
123
|
+
} }
|
|
124
|
+
>
|
|
125
|
+
<Stack gap={ 1.5 }>
|
|
126
|
+
<Grid container spacing={ 2 } alignItems="center">
|
|
127
|
+
<NestedValueControl item={ items[ 0 ] } value={ actualValue } setNestedProp={ setNestedProp } />
|
|
128
|
+
<NestedValueControl item={ items[ 1 ] } value={ actualValue } setNestedProp={ setNestedProp } />
|
|
129
|
+
</Grid>
|
|
130
|
+
<Grid container spacing={ 2 } alignItems="center">
|
|
131
|
+
<NestedValueControl item={ items[ 3 ] } value={ actualValue } setNestedProp={ setNestedProp } />
|
|
132
|
+
<NestedValueControl item={ items[ 2 ] } value={ actualValue } setNestedProp={ setNestedProp } />
|
|
133
|
+
</Grid>
|
|
134
|
+
</Stack>
|
|
135
|
+
</Popover>
|
|
136
|
+
</>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const NestedValueControl = < TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > >( {
|
|
141
|
+
item,
|
|
142
|
+
value,
|
|
143
|
+
setNestedProp,
|
|
144
|
+
}: {
|
|
145
|
+
item: Item< TMultiPropType, TPropValue >;
|
|
146
|
+
value: TPropValue[ 'value' ] | undefined;
|
|
147
|
+
setNestedProp: ( item: Item< TMultiPropType, TPropValue >, newValue: PropValue ) => void;
|
|
148
|
+
} ) => {
|
|
149
|
+
const { bind } = item;
|
|
150
|
+
|
|
151
|
+
const nestedValue = value?.[ bind ] ? value[ bind ] : undefined;
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<BoundPropProvider bind={ '' } setValue={ ( val ) => setNestedProp( item, val ) } value={ nestedValue }>
|
|
155
|
+
<Grid item xs={ 6 }>
|
|
156
|
+
<Grid container spacing={ 1 } alignItems="center">
|
|
157
|
+
<Grid item xs={ 12 }>
|
|
158
|
+
<ControlLabel>{ item.label }</ControlLabel>
|
|
159
|
+
</Grid>
|
|
160
|
+
<Grid item xs={ 12 }>
|
|
161
|
+
<SizeControl startIcon={ item.icon } />
|
|
162
|
+
</Grid>
|
|
163
|
+
</Grid>
|
|
164
|
+
</Grid>
|
|
165
|
+
</BoundPropProvider>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const EqualValuesControl = <
|
|
170
|
+
TMultiPropType extends string,
|
|
171
|
+
TPropValue extends MultiSizePropValue< TMultiPropType >[ 'value' ],
|
|
172
|
+
>( {
|
|
173
|
+
value,
|
|
174
|
+
setValue,
|
|
175
|
+
iconButton,
|
|
176
|
+
}: {
|
|
177
|
+
value: TPropValue | undefined;
|
|
178
|
+
setValue: ( newValue: TPropValue ) => void;
|
|
179
|
+
iconButton: ReactNode;
|
|
180
|
+
} ) => {
|
|
181
|
+
const values = Object.values( value ?? {} ) as SizeControlValue[];
|
|
182
|
+
const isMixed = hasMixedSizes( values );
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<BoundPropProvider
|
|
186
|
+
bind={ '' }
|
|
187
|
+
setValue={ ( val ) => setValue( val as TPropValue ) }
|
|
188
|
+
value={ isMixed ? undefined : values[ 0 ] }
|
|
189
|
+
>
|
|
190
|
+
<Stack direction="row" alignItems="center" gap={ 1 }>
|
|
191
|
+
<SizeControl placeholder={ __( 'MIXED', 'elementor' ) } />
|
|
192
|
+
{ iconButton }
|
|
193
|
+
</Stack>
|
|
194
|
+
</BoundPropProvider>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Grid, Stack } from '@elementor/ui';
|
|
3
2
|
import { __ } from '@wordpress/i18n';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
|
|
4
|
+
import { Grid, Stack } from '@elementor/ui';
|
|
5
|
+
import { PropValue, ImagePropValue, SizePropValue, ImageSrcPropValue } from '@elementor/editor-props';
|
|
6
|
+
import { ImageMediaControl } from './image-media-control';
|
|
8
7
|
import { SelectControl } from './select-control';
|
|
9
8
|
import { createControl } from '../create-control';
|
|
10
|
-
|
|
11
|
-
type Image = TransformablePropValue<
|
|
12
|
-
'image',
|
|
13
|
-
{
|
|
14
|
-
src?: ImageSrc;
|
|
15
|
-
size?: string;
|
|
16
|
-
}
|
|
17
|
-
>;
|
|
9
|
+
import { ControlLabel } from '../../components/control-label';
|
|
18
10
|
|
|
19
11
|
type SetContextValue = ( v: PropValue ) => void;
|
|
20
12
|
|
|
@@ -23,24 +15,24 @@ export type ImageControlProps = {
|
|
|
23
15
|
};
|
|
24
16
|
|
|
25
17
|
export const ImageControl = createControl( ( props: ImageControlProps ) => {
|
|
26
|
-
const { value, setValue } =
|
|
18
|
+
const { value, setValue } = useBoundProp< ImagePropValue | undefined >();
|
|
27
19
|
const { src, size } = value?.value || {};
|
|
28
20
|
|
|
29
|
-
const setImageSrc = ( newValue:
|
|
21
|
+
const setImageSrc = ( newValue: ImageSrcPropValue ) => {
|
|
30
22
|
setValue( {
|
|
31
23
|
$$type: 'image',
|
|
32
24
|
value: {
|
|
33
25
|
src: newValue,
|
|
34
|
-
size,
|
|
26
|
+
size: size as SizePropValue,
|
|
35
27
|
},
|
|
36
28
|
} );
|
|
37
29
|
};
|
|
38
30
|
|
|
39
|
-
const setImageSize = ( newValue:
|
|
31
|
+
const setImageSize = ( newValue: SizePropValue ) => {
|
|
40
32
|
setValue( {
|
|
41
33
|
$$type: 'image',
|
|
42
34
|
value: {
|
|
43
|
-
src,
|
|
35
|
+
src: src as ImageSrcPropValue,
|
|
44
36
|
size: newValue,
|
|
45
37
|
},
|
|
46
38
|
} );
|
|
@@ -48,19 +40,19 @@ export const ImageControl = createControl( ( props: ImageControlProps ) => {
|
|
|
48
40
|
|
|
49
41
|
return (
|
|
50
42
|
<Stack gap={ 2 }>
|
|
51
|
-
<
|
|
43
|
+
<BoundPropProvider value={ src } setValue={ setImageSrc as SetContextValue } bind={ 'src' }>
|
|
52
44
|
<ImageMediaControl />
|
|
53
|
-
</
|
|
54
|
-
<
|
|
45
|
+
</BoundPropProvider>
|
|
46
|
+
<BoundPropProvider value={ size } setValue={ setImageSize as SetContextValue } bind={ 'size' }>
|
|
55
47
|
<Grid container spacing={ 1 } alignItems="center">
|
|
56
48
|
<Grid item xs={ 6 }>
|
|
57
|
-
<
|
|
49
|
+
<ControlLabel> { __( 'Image Resolution', 'elementor' ) }</ControlLabel>
|
|
58
50
|
</Grid>
|
|
59
51
|
<Grid item xs={ 6 }>
|
|
60
52
|
<SelectControl options={ props.sizes } />
|
|
61
53
|
</Grid>
|
|
62
54
|
</Grid>
|
|
63
|
-
</
|
|
55
|
+
</BoundPropProvider>
|
|
64
56
|
</Stack>
|
|
65
57
|
);
|
|
66
58
|
} );
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { ImageSrcPropValue } from '@elementor/editor-props';
|
|
3
4
|
import { UploadIcon } from '@elementor/icons';
|
|
5
|
+
import { Button, Card, CardMedia, CardOverlay, Stack } from '@elementor/ui';
|
|
4
6
|
import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
5
|
-
import {
|
|
6
|
-
import { TransformablePropValue } from '../../types';
|
|
7
|
-
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
8
8
|
import ControlActions from '../control-actions/control-actions';
|
|
9
9
|
import { createControl } from '../create-control';
|
|
10
10
|
|
|
11
|
-
type ImageAttachmentID = TransformablePropValue< 'image-attachment-id', number >;
|
|
12
|
-
|
|
13
|
-
type Url = TransformablePropValue< 'url', string >;
|
|
14
|
-
|
|
15
|
-
export type ImageSrc = TransformablePropValue<
|
|
16
|
-
'image-src',
|
|
17
|
-
{ id: ImageAttachmentID; url: null } | { url: Url; id: null }
|
|
18
|
-
>;
|
|
19
|
-
|
|
20
11
|
export const ImageMediaControl = createControl( () => {
|
|
21
|
-
const { value, setValue } =
|
|
12
|
+
const { value, setValue } = useBoundProp< ImageSrcPropValue >();
|
|
22
13
|
const { id, url } = value?.value ?? {};
|
|
23
14
|
|
|
24
15
|
const { data: attachment } = useWpMediaAttachment( id?.value || null );
|
|
@@ -1,27 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { __ } from '@wordpress/i18n';
|
|
3
3
|
import { Grid, Stack, ToggleButton } from '@elementor/ui';
|
|
4
|
+
import { PropValue, LinkedDimensionsPropValue } from '@elementor/editor-props';
|
|
4
5
|
import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { createControl } from '../create-control';
|
|
7
|
+
import { ControlLabel } from '../../components/control-label';
|
|
8
|
+
import { SizeControl } from './size-control';
|
|
9
|
+
import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
|
|
9
10
|
|
|
10
11
|
export type Position = 'top' | 'right' | 'bottom' | 'left';
|
|
11
12
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
isLinked: boolean;
|
|
16
|
-
top: PropValue;
|
|
17
|
-
right: PropValue;
|
|
18
|
-
bottom: PropValue;
|
|
19
|
-
left: PropValue;
|
|
20
|
-
}
|
|
21
|
-
>;
|
|
22
|
-
|
|
23
|
-
export const LinkedDimensionsControl = ( { label }: { label: string } ) => {
|
|
24
|
-
const { value, setValue } = useControl< LinkedDimensionsValue >();
|
|
13
|
+
export const LinkedDimensionsControl = createControl( ( { label }: { label: string } ) => {
|
|
14
|
+
const { value, setValue } = useBoundProp< LinkedDimensionsPropValue >();
|
|
25
15
|
const { top, right, bottom, left, isLinked = true } = value?.value || {};
|
|
26
16
|
|
|
27
17
|
const setLinkedValue = ( position: Position, newValue: PropValue ) => {
|
|
@@ -130,7 +120,7 @@ export const LinkedDimensionsControl = ( { label }: { label: string } ) => {
|
|
|
130
120
|
</Stack>
|
|
131
121
|
</>
|
|
132
122
|
);
|
|
133
|
-
};
|
|
123
|
+
} );
|
|
134
124
|
|
|
135
125
|
const Control = ( {
|
|
136
126
|
bind,
|
|
@@ -143,13 +133,7 @@ const Control = ( {
|
|
|
143
133
|
startIcon: React.ReactNode;
|
|
144
134
|
setValue: ( bind: Position, newValue: PropValue ) => void;
|
|
145
135
|
} ) => (
|
|
146
|
-
<
|
|
147
|
-
value={ {
|
|
148
|
-
bind,
|
|
149
|
-
setValue: ( newValue ) => setValue( bind, newValue ),
|
|
150
|
-
value,
|
|
151
|
-
} }
|
|
152
|
-
>
|
|
136
|
+
<BoundPropProvider setValue={ ( newValue ) => setValue( bind, newValue ) } value={ value } bind={ bind }>
|
|
153
137
|
<SizeControl startIcon={ startIcon } />
|
|
154
|
-
</
|
|
138
|
+
</BoundPropProvider>
|
|
155
139
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
|
-
import {
|
|
3
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
4
4
|
import ControlActions from '../control-actions/control-actions';
|
|
5
5
|
import { createControl } from '../create-control';
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ const isEmptyOrNaN = ( value?: string | number ) =>
|
|
|
8
8
|
value === undefined || value === '' || Number.isNaN( Number( value ) );
|
|
9
9
|
|
|
10
10
|
export const NumberControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
|
|
11
|
-
const { value, setValue } =
|
|
11
|
+
const { value, setValue } = useBoundProp< number | undefined >();
|
|
12
12
|
|
|
13
13
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
14
14
|
const eventValue: string = event.target.value;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { PropValue } from '@elementor/editor-props';
|
|
2
3
|
import { MenuItem, Select, SelectChangeEvent } from '@elementor/ui';
|
|
3
|
-
import {
|
|
4
|
-
import { PropValue } from '../../types';
|
|
4
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
5
5
|
import ControlActions from '../control-actions/control-actions';
|
|
6
6
|
import { createControl } from '../create-control';
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@ type Props< T > = {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export const SelectControl = createControl( < T extends PropValue >( { options }: Props< T > ) => {
|
|
13
|
-
const { value, setValue } =
|
|
13
|
+
const { value, setValue } = useBoundProp< T >();
|
|
14
14
|
|
|
15
15
|
const handleChange = ( event: SelectChangeEvent< T > ) => {
|
|
16
16
|
setValue( event.target.value as T );
|
|
@@ -18,7 +18,7 @@ export const SelectControl = createControl( < T extends PropValue >( { options }
|
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<ControlActions>
|
|
21
|
-
<Select size="tiny" value={ value ?? '' } onChange={ handleChange }>
|
|
21
|
+
<Select displayEmpty size="tiny" value={ value ?? '' } onChange={ handleChange } fullWidth>
|
|
22
22
|
{ options.map( ( { label, ...props } ) => (
|
|
23
23
|
<MenuItem key={ props.value } { ...props }>
|
|
24
24
|
{ label }
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { SizePropValue, TransformablePropValue } from '@elementor/editor-props';
|
|
2
3
|
import { InputAdornment } from '@elementor/ui';
|
|
3
|
-
import {
|
|
4
|
-
import { useControl } from '../control-context';
|
|
4
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
5
5
|
import { useSyncExternalState } from '../hooks/use-sync-external-state';
|
|
6
6
|
import { SelectionEndAdornment, TextFieldInnerSelection } from '../components/text-field-inner-selection';
|
|
7
7
|
import ControlActions from '../control-actions/control-actions';
|
|
8
8
|
import { createControl } from '../create-control';
|
|
9
9
|
|
|
10
|
-
export type Unit = 'px' | '%' | 'em' | 'rem' | 'vw';
|
|
10
|
+
export type Unit = 'px' | '%' | 'em' | 'rem' | 'vw' | 'vh';
|
|
11
11
|
|
|
12
|
-
const defaultUnits: Unit[] = [ 'px', '%', 'em', 'rem', 'vw' ];
|
|
13
|
-
|
|
14
|
-
export type SizeControlValue = TransformablePropValue< 'size', { unit: Unit; size: number } >;
|
|
12
|
+
const defaultUnits: Unit[] = [ 'px', '%', 'em', 'rem', 'vw', 'vh' ];
|
|
15
13
|
|
|
16
14
|
export type SizeControlProps = {
|
|
17
15
|
placeholder?: string;
|
|
@@ -19,10 +17,12 @@ export type SizeControlProps = {
|
|
|
19
17
|
units?: Unit[];
|
|
20
18
|
};
|
|
21
19
|
|
|
20
|
+
export type SizeControlValue = TransformablePropValue< 'size', { unit: Unit; size: number } >;
|
|
21
|
+
|
|
22
22
|
export const SizeControl = createControl( ( { units = defaultUnits, placeholder, startIcon }: SizeControlProps ) => {
|
|
23
|
-
const { value, setValue } =
|
|
23
|
+
const { value, setValue } = useBoundProp< SizePropValue | undefined >();
|
|
24
24
|
|
|
25
|
-
const [ state, setState ] = useSyncExternalState<
|
|
25
|
+
const [ state, setState ] = useSyncExternalState< SizePropValue >( {
|
|
26
26
|
external: value,
|
|
27
27
|
setExternal: setValue,
|
|
28
28
|
persistWhen: ( controlValue ) => !! controlValue?.value.size || controlValue?.value.size === 0,
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { Grid, Stack } from '@elementor/ui';
|
|
4
|
+
import { createControl } from '../create-control';
|
|
5
|
+
import { SizeControl, Unit } from './size-control';
|
|
6
|
+
import { ControlLabel } from '../../components/control-label';
|
|
7
|
+
import { ColorControl } from './color-control';
|
|
8
|
+
import { PropValue, StrokePropValue, TransformablePropValue } from '@elementor/editor-props';
|
|
9
|
+
import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
|
|
10
|
+
|
|
11
|
+
type SetContextValue = ( v: PropValue ) => void;
|
|
12
|
+
|
|
13
|
+
const defaultStrokeControlValue: StrokePropValue = {
|
|
14
|
+
$$type: 'stroke',
|
|
15
|
+
value: {
|
|
16
|
+
color: {
|
|
17
|
+
$$type: 'color',
|
|
18
|
+
value: '#000000',
|
|
19
|
+
},
|
|
20
|
+
width: {
|
|
21
|
+
$$type: 'size',
|
|
22
|
+
value: {
|
|
23
|
+
unit: 'px',
|
|
24
|
+
size: NaN,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const units: Unit[] = [ 'px', 'em', 'rem' ];
|
|
31
|
+
|
|
32
|
+
export const StrokeControl = createControl( () => {
|
|
33
|
+
const { value, setValue } = useBoundProp< StrokePropValue >( defaultStrokeControlValue );
|
|
34
|
+
|
|
35
|
+
const setStrokeWidth = ( newValue: TransformablePropValue< 'size', { unit: Unit; size: number } > ) => {
|
|
36
|
+
const updatedValue = {
|
|
37
|
+
...( value?.value ?? defaultStrokeControlValue.value ),
|
|
38
|
+
width: newValue,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
setValue( {
|
|
42
|
+
$$type: 'stroke',
|
|
43
|
+
value: updatedValue,
|
|
44
|
+
} );
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const setStrokeColor = ( newValue: TransformablePropValue< 'color', string > ) => {
|
|
48
|
+
const updatedValue = {
|
|
49
|
+
...( value?.value ?? defaultStrokeControlValue.value ),
|
|
50
|
+
color: newValue,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
setValue( {
|
|
54
|
+
$$type: 'stroke',
|
|
55
|
+
value: updatedValue,
|
|
56
|
+
} );
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Stack gap={ 1.5 }>
|
|
61
|
+
<Control
|
|
62
|
+
bind="width"
|
|
63
|
+
label={ __( 'Stroke Width', 'elementor' ) }
|
|
64
|
+
value={ value?.value.width ?? defaultStrokeControlValue.value.width }
|
|
65
|
+
setValue={ setStrokeWidth }
|
|
66
|
+
>
|
|
67
|
+
<SizeControl units={ units } />
|
|
68
|
+
</Control>
|
|
69
|
+
|
|
70
|
+
<Control
|
|
71
|
+
bind="color"
|
|
72
|
+
label={ __( 'Stroke Color', 'elementor' ) }
|
|
73
|
+
value={ value?.value.color ?? defaultStrokeControlValue.value.color }
|
|
74
|
+
setValue={ setStrokeColor }
|
|
75
|
+
>
|
|
76
|
+
<ColorControl />
|
|
77
|
+
</Control>
|
|
78
|
+
</Stack>
|
|
79
|
+
);
|
|
80
|
+
} );
|
|
81
|
+
|
|
82
|
+
const Control = < T extends PropValue >( {
|
|
83
|
+
bind,
|
|
84
|
+
value,
|
|
85
|
+
setValue,
|
|
86
|
+
label,
|
|
87
|
+
children,
|
|
88
|
+
}: {
|
|
89
|
+
bind: string;
|
|
90
|
+
value: T;
|
|
91
|
+
setValue: ( v: T ) => void;
|
|
92
|
+
label: string;
|
|
93
|
+
children: React.ReactNode;
|
|
94
|
+
} ) => (
|
|
95
|
+
<BoundPropProvider bind={ bind } value={ value } setValue={ setValue as SetContextValue }>
|
|
96
|
+
<Grid container spacing={ 1 } alignItems="center">
|
|
97
|
+
<Grid item xs={ 6 }>
|
|
98
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
99
|
+
</Grid>
|
|
100
|
+
<Grid item xs={ 6 }>
|
|
101
|
+
{ children }
|
|
102
|
+
</Grid>
|
|
103
|
+
</Grid>
|
|
104
|
+
</BoundPropProvider>
|
|
105
|
+
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
|
-
import {
|
|
3
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
4
4
|
import ControlActions from '../control-actions/control-actions';
|
|
5
5
|
import { createControl } from '../create-control';
|
|
6
6
|
|
|
@@ -9,14 +9,14 @@ type Props = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const TextAreaControl = createControl( ( { placeholder }: Props ) => {
|
|
12
|
-
const { value, setValue } =
|
|
12
|
+
const { value, setValue } = useBoundProp< string >();
|
|
13
13
|
|
|
14
14
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
15
15
|
setValue( event.target.value );
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<ControlActions
|
|
19
|
+
<ControlActions>
|
|
20
20
|
<TextField
|
|
21
21
|
size="tiny"
|
|
22
22
|
multiline
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
|
-
import {
|
|
3
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
4
4
|
import ControlActions from '../control-actions/control-actions';
|
|
5
5
|
import { createControl } from '../create-control';
|
|
6
6
|
|
|
7
7
|
export const TextControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
|
|
8
|
-
const { value, setValue } =
|
|
8
|
+
const { value, setValue } = useBoundProp< string >( '' );
|
|
9
9
|
|
|
10
10
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => setValue( event.target.value );
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<ControlActions
|
|
13
|
+
<ControlActions>
|
|
14
14
|
<TextField type="text" size="tiny" value={ value } onChange={ handleChange } placeholder={ placeholder } />
|
|
15
15
|
</ControlActions>
|
|
16
16
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
3
3
|
import { ControlToggleButtonGroup, ToggleButtonGroupItem } from '../components/control-toggle-button-group';
|
|
4
|
-
import { PropValue } from '
|
|
4
|
+
import { PropValue } from '@elementor/editor-props';
|
|
5
5
|
import { createControl } from '../create-control';
|
|
6
6
|
|
|
7
7
|
type ToggleControlProps< T extends PropValue > = {
|
|
@@ -9,10 +9,10 @@ type ToggleControlProps< T extends PropValue > = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const ToggleControl = createControl( < T extends PropValue >( { options }: ToggleControlProps< T > ) => {
|
|
12
|
-
const { value, setValue } =
|
|
12
|
+
const { value, setValue } = useBoundProp< T | null >();
|
|
13
13
|
|
|
14
14
|
const handleToggle = ( option: T | null ) => {
|
|
15
|
-
setValue( option
|
|
15
|
+
setValue( option );
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
return (
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ComponentType, createContext, useContext } from 'react';
|
|
3
|
+
import { useBoundProp } from './bound-prop-context';
|
|
4
|
+
import { PropValue } from '@elementor/editor-props';
|
|
5
|
+
|
|
6
|
+
export type ReplaceWhenParams = {
|
|
7
|
+
value: PropValue;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type CreateControlReplacement = {
|
|
11
|
+
component: ComponentType;
|
|
12
|
+
condition: ( { value }: ReplaceWhenParams ) => boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ControlReplacementContext = createContext< CreateControlReplacement | undefined >( undefined );
|
|
16
|
+
|
|
17
|
+
export const ControlReplacementProvider = ( {
|
|
18
|
+
component,
|
|
19
|
+
condition,
|
|
20
|
+
children,
|
|
21
|
+
}: React.PropsWithChildren< CreateControlReplacement > ) => {
|
|
22
|
+
return (
|
|
23
|
+
<ControlReplacementContext.Provider value={ { component, condition } }>
|
|
24
|
+
{ children }
|
|
25
|
+
</ControlReplacementContext.Provider>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
export const useControlReplacement = () => {
|
|
29
|
+
const { value } = useBoundProp();
|
|
30
|
+
const controlReplacement = useContext( ControlReplacementContext );
|
|
31
|
+
|
|
32
|
+
let shouldReplace = false;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
shouldReplace = !! controlReplacement?.condition( { value } ) && !! controlReplacement.component;
|
|
36
|
+
} catch {}
|
|
37
|
+
|
|
38
|
+
return shouldReplace ? controlReplacement?.component : undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const createControlReplacement = () => {
|
|
42
|
+
let controlReplacement: CreateControlReplacement;
|
|
43
|
+
|
|
44
|
+
function replaceControl( { component, condition }: CreateControlReplacement ) {
|
|
45
|
+
controlReplacement = { component, condition };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getControlReplacement() {
|
|
49
|
+
return controlReplacement;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { replaceControl, getControlReplacement };
|
|
53
|
+
};
|