@elementor/editor-controls 0.24.0 → 0.25.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 +20 -0
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +127 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/bound-prop-context/prop-context.tsx +3 -0
- package/src/bound-prop-context/prop-key-context.tsx +3 -1
- package/src/bound-prop-context/use-bound-prop.ts +41 -2
- package/src/components/text-field-inner-selection.tsx +18 -2
- package/src/controls/font-family-control/font-family-control.tsx +2 -0
- package/src/controls/number-control.tsx +7 -0
- package/src/controls/size-control.tsx +25 -15
- package/src/controls/toggle-control.tsx +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-controls",
|
|
3
3
|
"description": "This package contains the controls model and utils for the Elementor editor",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.25.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@elementor/editor-current-user": "0.3.0",
|
|
44
|
-
"@elementor/editor-elements": "0.8.
|
|
45
|
-
"@elementor/editor-props": "0.
|
|
46
|
-
"@elementor/editor-ui": "0.7.
|
|
44
|
+
"@elementor/editor-elements": "0.8.1",
|
|
45
|
+
"@elementor/editor-props": "0.12.0",
|
|
46
|
+
"@elementor/editor-ui": "0.7.1",
|
|
47
47
|
"@elementor/env": "0.3.5",
|
|
48
48
|
"@elementor/http": "0.1.4",
|
|
49
49
|
"@elementor/icons": "1.37.0",
|
|
@@ -14,6 +14,7 @@ type PropContext< T extends PropValue, P extends PropType > = {
|
|
|
14
14
|
setValue: SetValue< T >;
|
|
15
15
|
value: T | null;
|
|
16
16
|
propType: P;
|
|
17
|
+
placeholder?: T;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const PropContext = createContext< PropContext< PropValue, PropType > | null >( null );
|
|
@@ -27,6 +28,7 @@ export const PropProvider = < T extends PropValue, P extends PropType >( {
|
|
|
27
28
|
value,
|
|
28
29
|
setValue,
|
|
29
30
|
propType,
|
|
31
|
+
placeholder,
|
|
30
32
|
}: PropProviderProps< T, P > ) => {
|
|
31
33
|
return (
|
|
32
34
|
<PropContext.Provider
|
|
@@ -34,6 +36,7 @@ export const PropProvider = < T extends PropValue, P extends PropType >( {
|
|
|
34
36
|
value,
|
|
35
37
|
propType,
|
|
36
38
|
setValue: setValue as SetValue< PropValue >,
|
|
39
|
+
placeholder,
|
|
37
40
|
} }
|
|
38
41
|
>
|
|
39
42
|
{ children }
|
|
@@ -19,6 +19,7 @@ export type PropKeyContextValue< T, P > = {
|
|
|
19
19
|
setValue: SetValue< T >;
|
|
20
20
|
value: T;
|
|
21
21
|
propType: P;
|
|
22
|
+
placeholder?: T;
|
|
22
23
|
path: PropKey[];
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -60,12 +61,13 @@ const ObjectPropKeyProvider = ( { children, bind }: PropKeyProviderProps ) => {
|
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
const value = context.value?.[ bind ];
|
|
64
|
+
const placeholder = context.placeholder?.[ bind ];
|
|
63
65
|
|
|
64
66
|
const propType = context.propType.shape[ bind ];
|
|
65
67
|
|
|
66
68
|
return (
|
|
67
69
|
<PropKeyContext.Provider
|
|
68
|
-
value={ { ...context, value, setValue, bind, propType, path: [ ...( path ?? [] ), bind ] } }
|
|
70
|
+
value={ { ...context, value, setValue, placeholder, bind, propType, path: [ ...( path ?? [] ), bind ] } }
|
|
69
71
|
>
|
|
70
72
|
{ children }
|
|
71
73
|
</PropKeyContext.Provider>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
1
2
|
import {
|
|
2
3
|
type CreateOptions,
|
|
3
4
|
type PropKey,
|
|
@@ -15,7 +16,9 @@ type UseBoundProp< TValue extends PropValue > = {
|
|
|
15
16
|
setValue: SetValue< TValue | null >;
|
|
16
17
|
value: TValue;
|
|
17
18
|
propType: PropType;
|
|
19
|
+
placeholder?: TValue;
|
|
18
20
|
path: PropKey[];
|
|
21
|
+
restoreValue: () => void;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export function useBoundProp< T extends PropValue = PropValue >(): PropKeyContextValue< T, PropType >;
|
|
@@ -29,12 +32,18 @@ export function useBoundProp< TKey extends string, TValue extends PropValue >(
|
|
|
29
32
|
) {
|
|
30
33
|
const propKeyContext = usePropKeyContext();
|
|
31
34
|
|
|
35
|
+
const { isValid, validate, restoreValue } = useValidation( propKeyContext.propType );
|
|
36
|
+
|
|
32
37
|
// allow using the hook without a propTypeUtil, with no modifications or validations.
|
|
33
38
|
if ( ! propTypeUtil ) {
|
|
34
39
|
return propKeyContext;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
function setValue( value: TValue | null, options: CreateOptions, meta: { bind?: PropKey } ) {
|
|
43
|
+
if ( ! validate( value ) ) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
if ( value === null ) {
|
|
39
48
|
return propKeyContext?.setValue( null, options, meta );
|
|
40
49
|
}
|
|
@@ -45,15 +54,45 @@ export function useBoundProp< TKey extends string, TValue extends PropValue >(
|
|
|
45
54
|
const propType = resolveUnionPropType( propKeyContext.propType, propTypeUtil.key );
|
|
46
55
|
|
|
47
56
|
const value = propTypeUtil.extract( propKeyContext.value ?? propType.default ?? null );
|
|
57
|
+
const placeholder = propTypeUtil.extract( propKeyContext.placeholder ?? null );
|
|
48
58
|
|
|
49
59
|
return {
|
|
50
60
|
...propKeyContext,
|
|
51
|
-
setValue,
|
|
52
|
-
value,
|
|
53
61
|
propType,
|
|
62
|
+
setValue,
|
|
63
|
+
value: isValid ? value : null,
|
|
64
|
+
restoreValue,
|
|
65
|
+
placeholder,
|
|
54
66
|
};
|
|
55
67
|
}
|
|
56
68
|
|
|
69
|
+
const useValidation = ( propType: PropType ) => {
|
|
70
|
+
const [ isValid, setIsValid ] = useState( true );
|
|
71
|
+
|
|
72
|
+
// If the value does not pass the prop type validation, set the isValid state to false.
|
|
73
|
+
// This will prevent the value from being set in the model, and its fallback will be used instead.
|
|
74
|
+
const validate = ( value: PropValue | null ) => {
|
|
75
|
+
let valid = true;
|
|
76
|
+
|
|
77
|
+
if ( propType.settings.required && value === null ) {
|
|
78
|
+
valid = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setIsValid( valid );
|
|
82
|
+
|
|
83
|
+
return valid;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const restoreValue = () => setIsValid( true );
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
isValid,
|
|
90
|
+
setIsValid,
|
|
91
|
+
validate,
|
|
92
|
+
restoreValue,
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
57
96
|
// utils
|
|
58
97
|
const resolveUnionPropType = ( propType: PropType, key: string ): PropType => {
|
|
59
98
|
let resolvedPropType = propType;
|
|
@@ -9,25 +9,41 @@ type TextFieldInnerSelectionProps = {
|
|
|
9
9
|
type: string;
|
|
10
10
|
value: PropValue;
|
|
11
11
|
onChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
|
|
12
|
+
onBlur?: ( event: React.FocusEvent< HTMLInputElement > ) => void;
|
|
13
|
+
onKeyDown?: ( event: React.KeyboardEvent< HTMLInputElement > ) => void;
|
|
12
14
|
endAdornment: React.ReactNode;
|
|
13
15
|
startAdornment?: React.ReactNode;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export const TextFieldInnerSelection = forwardRef(
|
|
17
|
-
(
|
|
19
|
+
(
|
|
20
|
+
{
|
|
21
|
+
placeholder,
|
|
22
|
+
type,
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
onBlur,
|
|
26
|
+
onKeyDown,
|
|
27
|
+
endAdornment,
|
|
28
|
+
startAdornment,
|
|
29
|
+
}: TextFieldInnerSelectionProps,
|
|
30
|
+
ref
|
|
31
|
+
) => {
|
|
18
32
|
return (
|
|
19
33
|
<TextField
|
|
34
|
+
ref={ ref }
|
|
20
35
|
size="tiny"
|
|
21
36
|
fullWidth
|
|
22
37
|
type={ type }
|
|
23
38
|
value={ value }
|
|
24
39
|
onChange={ onChange }
|
|
40
|
+
onKeyDown={ onKeyDown }
|
|
41
|
+
onBlur={ onBlur }
|
|
25
42
|
placeholder={ placeholder }
|
|
26
43
|
InputProps={ {
|
|
27
44
|
endAdornment,
|
|
28
45
|
startAdornment,
|
|
29
46
|
} }
|
|
30
|
-
ref={ ref }
|
|
31
47
|
/>
|
|
32
48
|
);
|
|
33
49
|
}
|
|
@@ -9,6 +9,8 @@ import { createControl } from '../create-control';
|
|
|
9
9
|
const isEmptyOrNaN = ( value?: string | number | null ) =>
|
|
10
10
|
value === null || value === undefined || value === '' || Number.isNaN( Number( value ) );
|
|
11
11
|
|
|
12
|
+
const RESTRICTED_INPUT_KEYS = [ 'e', 'E', '+', '-' ];
|
|
13
|
+
|
|
12
14
|
export const NumberControl = createControl(
|
|
13
15
|
( {
|
|
14
16
|
placeholder,
|
|
@@ -49,6 +51,11 @@ export const NumberControl = createControl(
|
|
|
49
51
|
onChange={ handleChange }
|
|
50
52
|
placeholder={ placeholder }
|
|
51
53
|
inputProps={ { step } }
|
|
54
|
+
onKeyDown={ ( event: KeyboardEvent ) => {
|
|
55
|
+
if ( RESTRICTED_INPUT_KEYS.includes( event.key ) ) {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
}
|
|
58
|
+
} }
|
|
52
59
|
/>
|
|
53
60
|
</ControlActions>
|
|
54
61
|
);
|
|
@@ -25,7 +25,7 @@ type SizeControlProps = {
|
|
|
25
25
|
|
|
26
26
|
export const SizeControl = createControl(
|
|
27
27
|
( { units = defaultUnits, extendedValues = [], placeholder, startIcon }: SizeControlProps ) => {
|
|
28
|
-
const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
|
|
28
|
+
const { value: sizeValue, setValue: setSizeValue, restoreValue } = useBoundProp( sizePropTypeUtil );
|
|
29
29
|
|
|
30
30
|
const [ state, setState ] = useSyncExternalState( {
|
|
31
31
|
external: sizeValue,
|
|
@@ -50,21 +50,21 @@ export const SizeControl = createControl(
|
|
|
50
50
|
} ) );
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
const
|
|
54
|
-
size: state.size,
|
|
55
|
-
unit: state.unit,
|
|
56
|
-
placeholder,
|
|
57
|
-
startIcon,
|
|
58
|
-
units,
|
|
59
|
-
extendedValues,
|
|
60
|
-
handleSizeChange,
|
|
61
|
-
handleUnitChange,
|
|
62
|
-
};
|
|
53
|
+
const Input = extendedValues?.length ? ExtendedSizeInput : SizeInput;
|
|
63
54
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
return (
|
|
56
|
+
<Input
|
|
57
|
+
size={ state.size }
|
|
58
|
+
unit={ state.unit }
|
|
59
|
+
placeholder={ placeholder }
|
|
60
|
+
startIcon={ startIcon }
|
|
61
|
+
units={ units }
|
|
62
|
+
extendedValues={ extendedValues }
|
|
63
|
+
handleSizeChange={ handleSizeChange }
|
|
64
|
+
handleUnitChange={ handleUnitChange }
|
|
65
|
+
onBlur={ restoreValue }
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
68
|
}
|
|
69
69
|
);
|
|
70
70
|
|
|
@@ -99,16 +99,20 @@ type SizeInputProps = {
|
|
|
99
99
|
startIcon?: React.ReactNode;
|
|
100
100
|
units: Unit[];
|
|
101
101
|
extendedValues?: ExtendedValue[];
|
|
102
|
+
onBlur?: ( event: React.FocusEvent< HTMLInputElement > ) => void;
|
|
102
103
|
handleUnitChange: ( unit: Unit ) => void;
|
|
103
104
|
handleSizeChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
|
|
104
105
|
};
|
|
105
106
|
|
|
107
|
+
const RESTRICTED_INPUT_KEYS = [ 'e', 'E', '+', '-' ];
|
|
108
|
+
|
|
106
109
|
const SizeInput = ( {
|
|
107
110
|
units,
|
|
108
111
|
handleUnitChange,
|
|
109
112
|
handleSizeChange,
|
|
110
113
|
placeholder,
|
|
111
114
|
startIcon,
|
|
115
|
+
onBlur,
|
|
112
116
|
size,
|
|
113
117
|
unit,
|
|
114
118
|
}: SizeInputProps ) => {
|
|
@@ -129,6 +133,12 @@ const SizeInput = ( {
|
|
|
129
133
|
type="number"
|
|
130
134
|
value={ Number.isNaN( size ) ? '' : size }
|
|
131
135
|
onChange={ handleSizeChange }
|
|
136
|
+
onBlur={ onBlur }
|
|
137
|
+
onKeyDown={ ( event ) => {
|
|
138
|
+
if ( RESTRICTED_INPUT_KEYS.includes( event.key ) ) {
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
}
|
|
141
|
+
} }
|
|
132
142
|
/>
|
|
133
143
|
</ControlActions>
|
|
134
144
|
);
|
|
@@ -20,7 +20,7 @@ export const ToggleControl = createControl(
|
|
|
20
20
|
size = 'tiny',
|
|
21
21
|
exclusive = true,
|
|
22
22
|
}: ToggleControlProps< StringPropValue[ 'value' ] > ) => {
|
|
23
|
-
const { value, setValue } = useBoundProp( stringPropTypeUtil );
|
|
23
|
+
const { value, setValue, placeholder } = useBoundProp( stringPropTypeUtil );
|
|
24
24
|
|
|
25
25
|
const exclusiveValues = options.filter( ( option ) => option.exclusive ).map( ( option ) => option.value );
|
|
26
26
|
|
|
@@ -44,14 +44,14 @@ export const ToggleControl = createControl(
|
|
|
44
44
|
return exclusive ? (
|
|
45
45
|
<ControlToggleButtonGroup
|
|
46
46
|
{ ...toggleButtonGroupProps }
|
|
47
|
-
value={ value ?? null }
|
|
47
|
+
value={ value ?? placeholder ?? null }
|
|
48
48
|
onChange={ setValue }
|
|
49
49
|
exclusive={ true }
|
|
50
50
|
/>
|
|
51
51
|
) : (
|
|
52
52
|
<ControlToggleButtonGroup
|
|
53
53
|
{ ...toggleButtonGroupProps }
|
|
54
|
-
value={ value?.split( ' ' ) ?? [] }
|
|
54
|
+
value={ ( value ?? placeholder )?.split( ' ' ) ?? [] }
|
|
55
55
|
onChange={ handleNonExclusiveToggle }
|
|
56
56
|
exclusive={ false }
|
|
57
57
|
/>
|