@elementor/editor-controls 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/index.d.mts +20 -11
- package/dist/index.d.ts +20 -11
- package/dist/index.js +739 -565
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +548 -372
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
- package/src/components/font-family-selector.tsx +30 -13
- package/src/components/popover-content.tsx +3 -11
- package/src/components/repeater.tsx +3 -1
- package/src/components/text-field-popover.tsx +3 -3
- package/src/controls/aspect-ratio-control.tsx +20 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-size.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +9 -4
- package/src/controls/box-shadow-repeater-control.tsx +2 -2
- package/src/controls/equal-unequal-sizes-control.tsx +3 -9
- package/src/controls/filter-repeater-control.tsx +186 -0
- package/src/controls/font-family-control/font-family-control.tsx +6 -2
- package/src/controls/gap-control.tsx +3 -3
- package/src/controls/image-control.tsx +22 -35
- package/src/controls/key-value-control.tsx +39 -19
- package/src/controls/link-control.tsx +3 -1
- package/src/controls/linked-dimensions-control.tsx +3 -3
- package/src/controls/number-control.tsx +3 -3
- package/src/controls/repeatable-control.tsx +38 -8
- package/src/controls/size-control.tsx +3 -3
- package/src/controls/stroke-control.tsx +2 -2
- package/src/controls/svg-media-control.tsx +0 -2
- package/src/index.ts +3 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type ChangeEvent, useMemo, useState } from 'react';
|
|
3
3
|
import { keyValuePropTypeUtil } from '@elementor/editor-props';
|
|
4
|
-
import { FormHelperText, FormLabel, Grid,
|
|
4
|
+
import { FormHelperText, FormLabel, Grid, TextField } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { useBoundProp } from '../bound-prop-context';
|
|
@@ -13,7 +13,6 @@ type FieldType = 'key' | 'value';
|
|
|
13
13
|
type KeyValueControlProps = {
|
|
14
14
|
keyName?: string;
|
|
15
15
|
valueName?: string;
|
|
16
|
-
sx?: SxProps< Theme >;
|
|
17
16
|
regexKey?: string;
|
|
18
17
|
regexValue?: string;
|
|
19
18
|
validationErrorMessage?: string;
|
|
@@ -23,12 +22,15 @@ export const KeyValueControl = createControl( ( props: KeyValueControlProps = {}
|
|
|
23
22
|
const { value, setValue } = useBoundProp( keyValuePropTypeUtil );
|
|
24
23
|
const [ keyError, setKeyError ] = useState< string | null >( null );
|
|
25
24
|
const [ valueError, setValueError ] = useState< string | null >( null );
|
|
25
|
+
|
|
26
|
+
const [ sessionState, setSessionState ] = useState( {
|
|
27
|
+
key: value?.key?.value || '',
|
|
28
|
+
value: value?.value?.value || '',
|
|
29
|
+
} );
|
|
30
|
+
|
|
26
31
|
const keyLabel = props.keyName || __( 'Key', 'elementor' );
|
|
27
32
|
const valueLabel = props.valueName || __( 'Value', 'elementor' );
|
|
28
33
|
|
|
29
|
-
const keyValue = value?.key?.value || '';
|
|
30
|
-
const valueValue = value?.value?.value || '';
|
|
31
|
-
|
|
32
34
|
const [ keyRegex, valueRegex, errMsg ] = useMemo< [ RegExp | undefined, RegExp | undefined, string ] >(
|
|
33
35
|
() => [
|
|
34
36
|
props.regexKey ? new RegExp( props.regexKey ) : undefined,
|
|
@@ -38,28 +40,44 @@ export const KeyValueControl = createControl( ( props: KeyValueControlProps = {}
|
|
|
38
40
|
[ props.regexKey, props.regexValue, props.validationErrorMessage ]
|
|
39
41
|
);
|
|
40
42
|
|
|
41
|
-
const validate = ( newValue: string,
|
|
42
|
-
if (
|
|
43
|
+
const validate = ( newValue: string, fieldType: string ): boolean => {
|
|
44
|
+
if ( fieldType === 'key' && keyRegex ) {
|
|
43
45
|
const isValid = keyRegex.test( newValue );
|
|
44
46
|
setKeyError( isValid ? null : errMsg );
|
|
45
|
-
|
|
47
|
+
return isValid;
|
|
48
|
+
} else if ( fieldType === 'value' && valueRegex ) {
|
|
46
49
|
const isValid = valueRegex.test( newValue );
|
|
47
50
|
setValueError( isValid ? null : errMsg );
|
|
51
|
+
return isValid;
|
|
48
52
|
}
|
|
53
|
+
return true;
|
|
49
54
|
};
|
|
50
55
|
|
|
51
56
|
const handleChange = ( event: ChangeEvent< HTMLInputElement >, fieldType: FieldType ) => {
|
|
52
57
|
const newValue = event.target.value;
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
setSessionState( ( prev ) => ( {
|
|
60
|
+
...prev,
|
|
61
|
+
[ fieldType ]: newValue,
|
|
62
|
+
} ) );
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
if ( validate( newValue, fieldType ) ) {
|
|
65
|
+
setValue( {
|
|
66
|
+
...value,
|
|
67
|
+
[ fieldType ]: {
|
|
68
|
+
value: newValue,
|
|
69
|
+
$$type: 'string',
|
|
70
|
+
},
|
|
71
|
+
} );
|
|
72
|
+
} else {
|
|
73
|
+
setValue( {
|
|
74
|
+
...value,
|
|
75
|
+
[ fieldType ]: {
|
|
76
|
+
value: '',
|
|
77
|
+
$$type: 'string',
|
|
78
|
+
},
|
|
79
|
+
} );
|
|
80
|
+
}
|
|
63
81
|
};
|
|
64
82
|
|
|
65
83
|
const isKeyInvalid = keyError !== null;
|
|
@@ -67,14 +85,16 @@ export const KeyValueControl = createControl( ( props: KeyValueControlProps = {}
|
|
|
67
85
|
|
|
68
86
|
return (
|
|
69
87
|
<ControlActions>
|
|
70
|
-
<Grid container gap={ 1.5 }
|
|
88
|
+
<Grid container gap={ 1.5 }>
|
|
71
89
|
<Grid item xs={ 12 }>
|
|
72
90
|
<FormLabel size="tiny">{ keyLabel }</FormLabel>
|
|
73
91
|
<TextField
|
|
92
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
93
|
+
autoFocus
|
|
74
94
|
sx={ { pt: 1 } }
|
|
75
95
|
size="tiny"
|
|
76
96
|
fullWidth
|
|
77
|
-
value={
|
|
97
|
+
value={ sessionState.key }
|
|
78
98
|
onChange={ ( e: ChangeEvent< HTMLInputElement > ) => handleChange( e, 'key' ) }
|
|
79
99
|
error={ isKeyInvalid }
|
|
80
100
|
/>
|
|
@@ -86,7 +106,7 @@ export const KeyValueControl = createControl( ( props: KeyValueControlProps = {}
|
|
|
86
106
|
sx={ { pt: 1 } }
|
|
87
107
|
size="tiny"
|
|
88
108
|
fullWidth
|
|
89
|
-
value={
|
|
109
|
+
value={ sessionState.value }
|
|
90
110
|
onChange={ ( e: ChangeEvent< HTMLInputElement > ) => handleChange( e, 'value' ) }
|
|
91
111
|
disabled={ isKeyInvalid }
|
|
92
112
|
error={ isValueInvalid }
|
|
@@ -38,6 +38,7 @@ type Props = ControlProps< {
|
|
|
38
38
|
allowCustomValues?: boolean;
|
|
39
39
|
minInputLength?: number;
|
|
40
40
|
placeholder?: string;
|
|
41
|
+
label?: string;
|
|
41
42
|
} >;
|
|
42
43
|
|
|
43
44
|
type LinkSessionValue = {
|
|
@@ -66,6 +67,7 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
66
67
|
placeholder,
|
|
67
68
|
minInputLength = 2,
|
|
68
69
|
context: { elementId },
|
|
70
|
+
label = __( 'Link', 'elementor' ),
|
|
69
71
|
} = props || {};
|
|
70
72
|
|
|
71
73
|
const [ linkInLinkRestriction, setLinkInLinkRestriction ] = useState( getLinkInLinkRestriction( elementId ) );
|
|
@@ -163,7 +165,7 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
163
165
|
marginInlineEnd: -0.75,
|
|
164
166
|
} }
|
|
165
167
|
>
|
|
166
|
-
<ControlFormLabel>{
|
|
168
|
+
<ControlFormLabel>{ label }</ControlFormLabel>
|
|
167
169
|
<ConditionalInfoTip isVisible={ ! isActive } linkInLinkRestriction={ linkInLinkRestriction }>
|
|
168
170
|
<ToggleIconControl
|
|
169
171
|
disabled={ shouldDisableAddingLink }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type RefObject, useRef } from 'react';
|
|
3
3
|
import { dimensionsPropTypeUtil, type PropKey, sizePropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
5
5
|
import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
@@ -24,7 +24,7 @@ export const LinkedDimensionsControl = createControl(
|
|
|
24
24
|
extendedOptions?: ExtendedOption[];
|
|
25
25
|
} ) => {
|
|
26
26
|
const { value: sizeValue, setValue: setSizeValue, disabled: sizeDisabled } = useBoundProp( sizePropTypeUtil );
|
|
27
|
-
const gridRowRefs:
|
|
27
|
+
const gridRowRefs: RefObject< HTMLDivElement >[] = [ useRef( null ), useRef( null ) ];
|
|
28
28
|
|
|
29
29
|
const {
|
|
30
30
|
value: dimensionsValue,
|
|
@@ -127,7 +127,7 @@ const Control = ( {
|
|
|
127
127
|
startIcon: React.ReactNode;
|
|
128
128
|
isLinked: boolean;
|
|
129
129
|
extendedOptions?: ExtendedOption[];
|
|
130
|
-
anchorRef:
|
|
130
|
+
anchorRef: RefObject< HTMLDivElement >;
|
|
131
131
|
} ) => {
|
|
132
132
|
if ( isLinked ) {
|
|
133
133
|
return <SizeControl startIcon={ startIcon } extendedOptions={ extendedOptions } anchorRef={ anchorRef } />;
|
|
@@ -13,7 +13,7 @@ const RESTRICTED_INPUT_KEYS = [ 'e', 'E', '+', '-' ];
|
|
|
13
13
|
|
|
14
14
|
export const NumberControl = createControl(
|
|
15
15
|
( {
|
|
16
|
-
placeholder,
|
|
16
|
+
placeholder: labelPlaceholder,
|
|
17
17
|
max = Number.MAX_VALUE,
|
|
18
18
|
min = -Number.MAX_VALUE,
|
|
19
19
|
step = 1,
|
|
@@ -25,7 +25,7 @@ export const NumberControl = createControl(
|
|
|
25
25
|
step?: number;
|
|
26
26
|
shouldForceInt?: boolean;
|
|
27
27
|
} ) => {
|
|
28
|
-
const { value, setValue, disabled } = useBoundProp( numberPropTypeUtil );
|
|
28
|
+
const { value, setValue, placeholder, disabled } = useBoundProp( numberPropTypeUtil );
|
|
29
29
|
|
|
30
30
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
31
31
|
const eventValue: string = event.target.value;
|
|
@@ -50,7 +50,7 @@ export const NumberControl = createControl(
|
|
|
50
50
|
disabled={ disabled }
|
|
51
51
|
value={ isEmptyOrNaN( value ) ? '' : value }
|
|
52
52
|
onChange={ handleChange }
|
|
53
|
-
placeholder={ placeholder }
|
|
53
|
+
placeholder={ labelPlaceholder ?? ( placeholder ? String( placeholder ) : '' ) }
|
|
54
54
|
inputProps={ { step } }
|
|
55
55
|
onKeyDown={ ( event: KeyboardEvent ) => {
|
|
56
56
|
if ( RESTRICTED_INPUT_KEYS.includes( event.key ) ) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { createArrayPropUtils, type PropKey } from '@elementor/editor-props';
|
|
4
|
-
import {
|
|
4
|
+
import { Box } from '@elementor/ui';
|
|
5
5
|
|
|
6
|
+
/* eslint-disable */
|
|
6
7
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
|
|
7
8
|
import { PopoverContent } from '../components/popover-content';
|
|
8
9
|
import { PopoverGridContainer } from '../components/popover-grid-container';
|
|
@@ -16,13 +17,25 @@ import {
|
|
|
16
17
|
|
|
17
18
|
type RepeatableControlProps = {
|
|
18
19
|
label: string;
|
|
20
|
+
repeaterLabel: string;
|
|
19
21
|
childControlConfig: ChildControlConfig;
|
|
20
22
|
showDuplicate?: boolean;
|
|
21
23
|
showToggle?: boolean;
|
|
24
|
+
initialValues?: object;
|
|
25
|
+
patternLabel?: string;
|
|
26
|
+
placeholder?: string;
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
export const RepeatableControl = createControl(
|
|
25
|
-
( {
|
|
30
|
+
( {
|
|
31
|
+
repeaterLabel,
|
|
32
|
+
childControlConfig,
|
|
33
|
+
showDuplicate,
|
|
34
|
+
showToggle,
|
|
35
|
+
initialValues,
|
|
36
|
+
patternLabel,
|
|
37
|
+
placeholder,
|
|
38
|
+
}: RepeatableControlProps ) => {
|
|
26
39
|
const { propTypeUtil: childPropTypeUtil } = childControlConfig;
|
|
27
40
|
|
|
28
41
|
if ( ! childPropTypeUtil ) {
|
|
@@ -35,6 +48,20 @@ export const RepeatableControl = createControl(
|
|
|
35
48
|
);
|
|
36
49
|
|
|
37
50
|
const { propType, value, setValue } = useBoundProp( childArrayPropTypeUtil );
|
|
51
|
+
const ItemLabel = ( { value: itemValue }: { value: any } ) => {
|
|
52
|
+
const pattern = patternLabel || '';
|
|
53
|
+
const finalLabel = interpolate( pattern, itemValue.value );
|
|
54
|
+
|
|
55
|
+
if ( finalLabel ) {
|
|
56
|
+
return <span>{ finalLabel }</span>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Box component="span" color="text.tertiary">
|
|
61
|
+
{ placeholder }
|
|
62
|
+
</Box>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
38
65
|
|
|
39
66
|
return (
|
|
40
67
|
<PropProvider propType={ propType } value={ value } setValue={ setValue }>
|
|
@@ -43,12 +70,13 @@ export const RepeatableControl = createControl(
|
|
|
43
70
|
openOnAdd
|
|
44
71
|
values={ value ?? [] }
|
|
45
72
|
setValues={ setValue }
|
|
46
|
-
label={
|
|
73
|
+
label={ repeaterLabel }
|
|
74
|
+
isSortable={ false }
|
|
47
75
|
itemSettings={ {
|
|
48
76
|
Icon: ItemIcon,
|
|
49
77
|
Label: ItemLabel,
|
|
50
78
|
Content: ItemContent,
|
|
51
|
-
initialValues: childPropTypeUtil.create( null ),
|
|
79
|
+
initialValues: childPropTypeUtil.create( initialValues || null ),
|
|
52
80
|
} }
|
|
53
81
|
showDuplicate={ showDuplicate }
|
|
54
82
|
showToggle={ showToggle }
|
|
@@ -82,8 +110,10 @@ const Content = () => {
|
|
|
82
110
|
);
|
|
83
111
|
};
|
|
84
112
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
113
|
+
const interpolate = ( template: string, data: object ) => {
|
|
114
|
+
//remove it to be generic
|
|
115
|
+
if ( Object.values( data ).some( ( value ) => value.value === '' || value === '' ) ) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return new Function( ...Object.keys( data ), `return \`${ template }\`;` )( ...Object.values( data ) );
|
|
89
119
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type RefObject, useEffect, useState } from 'react';
|
|
3
3
|
import { sizePropTypeUtil, type SizePropValue } from '@elementor/editor-props';
|
|
4
4
|
import { useActiveBreakpoint } from '@elementor/editor-responsive';
|
|
5
5
|
import { usePopupState } from '@elementor/ui';
|
|
@@ -23,7 +23,7 @@ type SizeControlProps = {
|
|
|
23
23
|
units?: Unit[];
|
|
24
24
|
extendedOptions?: ExtendedOption[];
|
|
25
25
|
disableCustom?: boolean;
|
|
26
|
-
anchorRef?:
|
|
26
|
+
anchorRef?: RefObject< HTMLDivElement | null >;
|
|
27
27
|
defaultUnit?: Unit;
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -149,7 +149,7 @@ export const SizeControl = createControl( ( props: SizeControlProps ) => {
|
|
|
149
149
|
{ anchorRef?.current && (
|
|
150
150
|
<TextFieldPopover
|
|
151
151
|
popupState={ popupState }
|
|
152
|
-
anchorRef={ anchorRef
|
|
152
|
+
anchorRef={ anchorRef }
|
|
153
153
|
restoreValue={ restoreValue }
|
|
154
154
|
value={ controlSize as string }
|
|
155
155
|
onChange={ handleSizeChange }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { forwardRef,
|
|
2
|
+
import { forwardRef, useRef } from 'react';
|
|
3
3
|
import { strokePropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { Grid } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -22,7 +22,7 @@ const units: Unit[] = [ 'px', 'em', 'rem' ];
|
|
|
22
22
|
|
|
23
23
|
export const StrokeControl = createControl( () => {
|
|
24
24
|
const propContext = useBoundProp( strokePropTypeUtil );
|
|
25
|
-
const rowRef
|
|
25
|
+
const rowRef = useRef< HTMLDivElement >( null );
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
28
|
<PropProvider { ...propContext }>
|
|
@@ -7,7 +7,6 @@ import { type OpenOptions, useWpMediaAttachment, useWpMediaFrame } from '@elemen
|
|
|
7
7
|
import { __ } from '@wordpress/i18n';
|
|
8
8
|
|
|
9
9
|
import { useBoundProp } from '../bound-prop-context';
|
|
10
|
-
import { ControlFormLabel } from '../components/control-form-label';
|
|
11
10
|
import { EnableUnfilteredModal } from '../components/enable-unfiltered-modal';
|
|
12
11
|
import ControlActions from '../control-actions/control-actions';
|
|
13
12
|
import { createControl } from '../create-control';
|
|
@@ -83,7 +82,6 @@ export const SvgMediaControl = createControl( () => {
|
|
|
83
82
|
return (
|
|
84
83
|
<Stack gap={ 1 }>
|
|
85
84
|
<EnableUnfilteredModal open={ unfilteredModalOpenState } onClose={ onCloseUnfilteredModal } />
|
|
86
|
-
<ControlFormLabel> { __( 'SVG', 'elementor' ) } </ControlFormLabel>
|
|
87
85
|
<ControlActions>
|
|
88
86
|
<StyledCard variant="outlined">
|
|
89
87
|
<StyledCardMediaContainer>
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { TextAreaControl } from './controls/text-area-control';
|
|
|
5
5
|
export { SizeControl } from './controls/size-control';
|
|
6
6
|
export { StrokeControl } from './controls/stroke-control';
|
|
7
7
|
export { BoxShadowRepeaterControl } from './controls/box-shadow-repeater-control';
|
|
8
|
+
export { FilterRepeaterControl } from './controls/filter-repeater-control';
|
|
8
9
|
export { SelectControl } from './controls/select-control';
|
|
9
10
|
export { ColorControl } from './controls/color-control';
|
|
10
11
|
export { ToggleControl } from './controls/toggle-control';
|
|
@@ -22,6 +23,7 @@ export { SwitchControl } from './controls/switch-control';
|
|
|
22
23
|
export { RepeatableControl } from './controls/repeatable-control';
|
|
23
24
|
export { KeyValueControl } from './controls/key-value-control';
|
|
24
25
|
export { PositionControl } from './controls/position-control';
|
|
26
|
+
export { PopoverContent } from './components/popover-content';
|
|
25
27
|
|
|
26
28
|
// components
|
|
27
29
|
export { ControlFormLabel } from './components/control-form-label';
|
|
@@ -35,7 +37,7 @@ export type { EqualUnequalItems } from './controls/equal-unequal-sizes-control';
|
|
|
35
37
|
export type { ControlActionsItems } from './control-actions/control-actions-context';
|
|
36
38
|
export type { PropProviderProps } from './bound-prop-context';
|
|
37
39
|
export type { SetValue } from './bound-prop-context/prop-context';
|
|
38
|
-
export type { ExtendedOption } from './utils/size-control';
|
|
40
|
+
export type { ExtendedOption, Unit } from './utils/size-control';
|
|
39
41
|
export type { ToggleControlProps } from './controls/toggle-control';
|
|
40
42
|
export type { FontCategory } from './controls/font-family-control/font-family-control';
|
|
41
43
|
|