@wordpress/components 19.6.1-next.a55ed9455a.0 → 19.7.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 -1
- package/build/base-control/index.js +19 -14
- package/build/base-control/index.js.map +1 -1
- package/build/base-control/styles/base-control-styles.js +33 -12
- package/build/base-control/styles/base-control-styles.js.map +1 -1
- package/build/box-control/all-input-control.js +3 -7
- package/build/box-control/all-input-control.js.map +1 -1
- package/build/box-control/axial-input-controls.js +20 -15
- package/build/box-control/axial-input-controls.js.map +1 -1
- package/build/box-control/input-controls.js +21 -16
- package/build/box-control/input-controls.js.map +1 -1
- package/build/box-control/utils.js +25 -11
- package/build/box-control/utils.js.map +1 -1
- package/build/checkbox-control/index.js +21 -1
- package/build/checkbox-control/index.js.map +1 -1
- package/build/color-palette/index.js +53 -4
- package/build/color-palette/index.js.map +1 -1
- package/build/custom-select-control/index.js +8 -3
- package/build/custom-select-control/index.js.map +1 -1
- package/build/divider/styles.js +28 -16
- package/build/divider/styles.js.map +1 -1
- package/build/focal-point-picker/controls.js +2 -3
- package/build/focal-point-picker/controls.js.map +1 -1
- package/build/form-file-upload/index.js +4 -1
- package/build/form-file-upload/index.js.map +1 -1
- package/build/input-control/input-field.js +21 -14
- package/build/input-control/input-field.js.map +1 -1
- package/build/input-control/reducer/actions.js +1 -3
- package/build/input-control/reducer/actions.js.map +1 -1
- package/build/input-control/reducer/reducer.js +1 -43
- package/build/input-control/reducer/reducer.js.map +1 -1
- package/build/number-control/index.js +15 -10
- package/build/number-control/index.js.map +1 -1
- package/build/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js +4 -4
- package/build/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js.map +1 -1
- package/build/toggle-group-control/toggle-group-control-option/component.js +1 -4
- package/build/toggle-group-control/toggle-group-control-option/component.js.map +1 -1
- package/build/toggle-group-control/toggle-group-control-option/styles.js +12 -19
- package/build/toggle-group-control/toggle-group-control-option/styles.js.map +1 -1
- package/build/tree-grid/index.js +4 -1
- package/build/tree-grid/index.js.map +1 -1
- package/build/unit-control/index.js +49 -27
- package/build/unit-control/index.js.map +1 -1
- package/build/unit-control/unit-select-control.js +2 -4
- package/build/unit-control/unit-select-control.js.map +1 -1
- package/build-module/base-control/index.js +19 -14
- package/build-module/base-control/index.js.map +1 -1
- package/build-module/base-control/styles/base-control-styles.js +34 -6
- package/build-module/base-control/styles/base-control-styles.js.map +1 -1
- package/build-module/box-control/all-input-control.js +4 -8
- package/build-module/box-control/all-input-control.js.map +1 -1
- package/build-module/box-control/axial-input-controls.js +18 -14
- package/build-module/box-control/axial-input-controls.js.map +1 -1
- package/build-module/box-control/input-controls.js +18 -14
- package/build-module/box-control/input-controls.js.map +1 -1
- package/build-module/box-control/utils.js +25 -11
- package/build-module/box-control/utils.js.map +1 -1
- package/build-module/checkbox-control/index.js +24 -3
- package/build-module/checkbox-control/index.js.map +1 -1
- package/build-module/color-palette/index.js +52 -4
- package/build-module/color-palette/index.js.map +1 -1
- package/build-module/custom-select-control/index.js +8 -3
- package/build-module/custom-select-control/index.js.map +1 -1
- package/build-module/divider/styles.js +29 -10
- package/build-module/divider/styles.js.map +1 -1
- package/build-module/focal-point-picker/controls.js +2 -3
- package/build-module/focal-point-picker/controls.js.map +1 -1
- package/build-module/form-file-upload/index.js +4 -1
- package/build-module/form-file-upload/index.js.map +1 -1
- package/build-module/input-control/input-field.js +21 -13
- package/build-module/input-control/input-field.js.map +1 -1
- package/build-module/input-control/reducer/actions.js +0 -1
- package/build-module/input-control/reducer/actions.js.map +1 -1
- package/build-module/input-control/reducer/reducer.js +2 -39
- package/build-module/input-control/reducer/reducer.js.map +1 -1
- package/build-module/number-control/index.js +15 -9
- package/build-module/number-control/index.js.map +1 -1
- package/build-module/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js +4 -4
- package/build-module/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js.map +1 -1
- package/build-module/toggle-group-control/toggle-group-control-option/component.js +1 -4
- package/build-module/toggle-group-control/toggle-group-control-option/component.js.map +1 -1
- package/build-module/toggle-group-control/toggle-group-control-option/styles.js +11 -17
- package/build-module/toggle-group-control/toggle-group-control-option/styles.js.map +1 -1
- package/build-module/tree-grid/index.js +4 -1
- package/build-module/tree-grid/index.js.map +1 -1
- package/build-module/unit-control/index.js +47 -25
- package/build-module/unit-control/index.js.map +1 -1
- package/build-module/unit-control/unit-select-control.js +2 -3
- package/build-module/unit-control/unit-select-control.js.map +1 -1
- package/build-style/style-rtl.css +29 -181
- package/build-style/style.css +29 -181
- package/build-types/base-control/index.d.ts +23 -18
- package/build-types/base-control/index.d.ts.map +1 -1
- package/build-types/base-control/styles/base-control-styles.d.ts +4 -0
- package/build-types/base-control/styles/base-control-styles.d.ts.map +1 -1
- package/build-types/card/card-divider/hook.d.ts +1 -1
- package/build-types/color-palette/index.d.ts.map +1 -1
- package/build-types/color-picker/styles.d.ts +1 -1
- package/build-types/divider/stories/index.d.ts +1 -0
- package/build-types/divider/stories/index.d.ts.map +1 -1
- package/build-types/divider/styles.d.ts.map +1 -1
- package/build-types/divider/types.d.ts +8 -1
- package/build-types/divider/types.d.ts.map +1 -1
- package/build-types/input-control/input-field.d.ts.map +1 -1
- package/build-types/input-control/reducer/actions.d.ts +1 -3
- package/build-types/input-control/reducer/actions.d.ts.map +1 -1
- package/build-types/input-control/reducer/reducer.d.ts +3 -9
- package/build-types/input-control/reducer/reducer.d.ts.map +1 -1
- package/build-types/input-control/types.d.ts +2 -2
- package/build-types/input-control/types.d.ts.map +1 -1
- package/build-types/number-control/index.d.ts +3 -3
- package/build-types/number-control/index.d.ts.map +1 -1
- package/build-types/range-control/styles/range-control-styles.d.ts +1 -1
- package/build-types/resizable-box/resize-tooltip/styles/resize-tooltip.styles.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control-option/styles.d.ts +0 -4
- package/build-types/toggle-group-control/toggle-group-control-option/styles.d.ts.map +1 -1
- package/build-types/unit-control/index.d.ts +7 -4
- package/build-types/unit-control/index.d.ts.map +1 -1
- package/build-types/unit-control/stories/index.d.ts +33 -0
- package/build-types/unit-control/stories/index.d.ts.map +1 -0
- package/build-types/unit-control/styles/unit-control-styles.d.ts +1 -1
- package/build-types/unit-control/types.d.ts +23 -6
- package/build-types/unit-control/types.d.ts.map +1 -1
- package/build-types/unit-control/unit-select-control.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/base-control/README.md +9 -1
- package/src/base-control/index.js +20 -13
- package/src/base-control/stories/index.js +2 -2
- package/src/base-control/styles/base-control-styles.js +23 -1
- package/src/box-control/all-input-control.js +2 -10
- package/src/box-control/axial-input-controls.js +32 -21
- package/src/box-control/input-controls.js +30 -19
- package/src/box-control/utils.js +29 -12
- package/src/checkbox-control/index.js +34 -3
- package/src/checkbox-control/stories/index.js +44 -0
- package/src/checkbox-control/style.scss +4 -2
- package/src/color-palette/index.js +73 -8
- package/src/color-palette/stories/index.js +62 -26
- package/src/color-palette/style.scss +11 -3
- package/src/color-palette/test/__snapshots__/index.js.snap +662 -12
- package/src/color-palette/test/index.js +1 -1
- package/src/custom-select-control/index.js +8 -2
- package/src/custom-select-control/stories/index.js +77 -74
- package/src/custom-select-control/style.scss +18 -3
- package/src/divider/stories/index.tsx +26 -23
- package/src/divider/styles.ts +9 -0
- package/src/divider/types.ts +11 -1
- package/src/focal-point-picker/controls.js +2 -3
- package/src/font-size-picker/test/index.js +0 -2
- package/src/form-file-upload/README.md +18 -0
- package/src/form-file-upload/index.js +3 -0
- package/src/form-file-upload/test/index.js +73 -11
- package/src/input-control/input-field.tsx +23 -12
- package/src/input-control/reducer/actions.ts +1 -7
- package/src/input-control/reducer/reducer.ts +0 -29
- package/src/input-control/types.ts +2 -1
- package/src/mobile/image/style.native.scss +1 -0
- package/src/number-control/README.md +14 -0
- package/src/number-control/index.js +13 -12
- package/src/number-control/stories/index.js +14 -7
- package/src/number-control/test/index.js +79 -1
- package/src/range-control/stories/index.js +91 -119
- package/src/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js +1 -0
- package/src/toggle-group-control/test/__snapshots__/index.js.snap +0 -27
- package/src/toggle-group-control/toggle-group-control-option/component.tsx +1 -4
- package/src/toggle-group-control/toggle-group-control-option/styles.ts +0 -12
- package/src/toolbar-group/style.scss +0 -73
- package/src/tree-grid/README.md +1 -1
- package/src/tree-grid/index.js +4 -0
- package/src/tree-grid/test/index.js +61 -17
- package/src/unit-control/README.md +1 -3
- package/src/unit-control/index.tsx +59 -30
- package/src/unit-control/stories/index.tsx +170 -0
- package/src/unit-control/test/index.js +143 -100
- package/src/unit-control/types.ts +60 -41
- package/src/unit-control/unit-select-control.tsx +2 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/src/unit-control/stories/index.js +0 -127
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { isEmpty } from 'lodash';
|
|
5
4
|
import type { SyntheticEvent } from 'react';
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -38,27 +37,6 @@ function mergeInitialState(
|
|
|
38
37
|
} as InputState;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
/**
|
|
42
|
-
* Composes multiple stateReducers into a single stateReducer, building
|
|
43
|
-
* the pipeline to control the flow for state and actions.
|
|
44
|
-
*
|
|
45
|
-
* @param fns State reducers.
|
|
46
|
-
* @return The single composed stateReducer.
|
|
47
|
-
*/
|
|
48
|
-
export const composeStateReducers = (
|
|
49
|
-
...fns: StateReducer[]
|
|
50
|
-
): StateReducer => {
|
|
51
|
-
return ( ...args ) => {
|
|
52
|
-
return fns.reduceRight( ( state, fn ) => {
|
|
53
|
-
// TODO: Assess whether this can be replaced with a more standard `compose` implementation
|
|
54
|
-
// like wp.data.compose() (aka lodash flowRight) or Redux compose().
|
|
55
|
-
// The current implementation only works by functions mutating the original state object.
|
|
56
|
-
const fnState = fn( ...args );
|
|
57
|
-
return isEmpty( fnState ) ? state : { ...state, ...fnState };
|
|
58
|
-
}, {} as InputState );
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
40
|
/**
|
|
63
41
|
* Creates a reducer that opens the channel for external state subscription
|
|
64
42
|
* and modification.
|
|
@@ -122,11 +100,6 @@ function inputControlStateReducer(
|
|
|
122
100
|
nextState.value = action.payload.value || state.initialValue;
|
|
123
101
|
break;
|
|
124
102
|
|
|
125
|
-
case actions.UPDATE:
|
|
126
|
-
nextState.value = action.payload.value;
|
|
127
|
-
nextState.isDirty = false;
|
|
128
|
-
break;
|
|
129
|
-
|
|
130
103
|
/**
|
|
131
104
|
* Validation
|
|
132
105
|
*/
|
|
@@ -219,7 +192,6 @@ export function useInputControlStateReducer(
|
|
|
219
192
|
dispatch( { type: actions.INVALIDATE, payload: { error, event } } );
|
|
220
193
|
const reset = createChangeEvent( actions.RESET );
|
|
221
194
|
const commit = createChangeEvent( actions.COMMIT );
|
|
222
|
-
const update = createChangeEvent( actions.UPDATE );
|
|
223
195
|
|
|
224
196
|
const dragStart = createDragEvent( actions.DRAG_START );
|
|
225
197
|
const drag = createDragEvent( actions.DRAG );
|
|
@@ -242,6 +214,5 @@ export function useInputControlStateReducer(
|
|
|
242
214
|
pressUp,
|
|
243
215
|
reset,
|
|
244
216
|
state,
|
|
245
|
-
update,
|
|
246
217
|
} as const;
|
|
247
218
|
}
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ReactNode,
|
|
7
7
|
ChangeEvent,
|
|
8
8
|
SyntheticEvent,
|
|
9
|
+
PointerEvent,
|
|
9
10
|
} from 'react';
|
|
10
11
|
import type { useDrag } from '@use-gesture/react';
|
|
11
12
|
|
|
@@ -33,7 +34,7 @@ interface BaseProps {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export type InputChangeCallback<
|
|
36
|
-
E = ChangeEvent< HTMLInputElement >,
|
|
37
|
+
E = ChangeEvent< HTMLInputElement > | PointerEvent< HTMLInputElement >,
|
|
37
38
|
P = {}
|
|
38
39
|
> = ( nextValue: string | undefined, extra: { event: E } & P ) => void;
|
|
39
40
|
|
|
@@ -97,6 +97,20 @@ The minimum `value` allowed.
|
|
|
97
97
|
- Required: No
|
|
98
98
|
- Default: `-Infinity`
|
|
99
99
|
|
|
100
|
+
### onChange
|
|
101
|
+
|
|
102
|
+
Callback fired whenever the value of the input changes.
|
|
103
|
+
|
|
104
|
+
The callback receives two arguments:
|
|
105
|
+
|
|
106
|
+
1. `newValue`: the new value of the input
|
|
107
|
+
2. `extra`: an object containing, under the `event` key, the original browser event.
|
|
108
|
+
|
|
109
|
+
Note that the value received as the first argument of the callback is _not_ guaranteed to be a valid value (e.g. it could be outside of the range defined by the [`min`, `max`] props, or it could not match the `step`). In order to check the value's validity, check the `event.target?.validity.valid` property from the callback's second argument.
|
|
110
|
+
|
|
111
|
+
- Type: `(newValue, extra) => void`
|
|
112
|
+
- Required: No
|
|
113
|
+
|
|
100
114
|
### required
|
|
101
115
|
|
|
102
116
|
If `true` enforces a valid number within the control's min/max range. If `false` allows an empty string as a valid value.
|
|
@@ -15,13 +15,12 @@ import { isRTL } from '@wordpress/i18n';
|
|
|
15
15
|
*/
|
|
16
16
|
import { Input } from './styles/number-control-styles';
|
|
17
17
|
import * as inputControlActionTypes from '../input-control/reducer/actions';
|
|
18
|
-
import { composeStateReducers } from '../input-control/reducer/reducer';
|
|
19
18
|
import { add, subtract, roundClamp } from '../utils/math';
|
|
20
19
|
import { isValueEmpty } from '../utils/values';
|
|
21
20
|
|
|
22
21
|
export function NumberControl(
|
|
23
22
|
{
|
|
24
|
-
__unstableStateReducer:
|
|
23
|
+
__unstableStateReducer: stateReducerProp,
|
|
25
24
|
className,
|
|
26
25
|
dragDirection = 'n',
|
|
27
26
|
hideHTMLArrows = false,
|
|
@@ -62,9 +61,11 @@ export function NumberControl(
|
|
|
62
61
|
* @return {Object} The updated state to apply to InputControl
|
|
63
62
|
*/
|
|
64
63
|
const numberControlStateReducer = ( state, action ) => {
|
|
64
|
+
const nextState = { ...state };
|
|
65
|
+
|
|
65
66
|
const { type, payload } = action;
|
|
66
67
|
const event = payload?.event;
|
|
67
|
-
const currentValue =
|
|
68
|
+
const currentValue = nextState.value;
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* Handles custom UP and DOWN Keyboard events
|
|
@@ -94,7 +95,7 @@ export function NumberControl(
|
|
|
94
95
|
nextValue = subtract( nextValue, incrementalValue );
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
nextState.value = constrainValue(
|
|
98
99
|
nextValue,
|
|
99
100
|
enableShift ? incrementalValue : null
|
|
100
101
|
);
|
|
@@ -139,7 +140,7 @@ export function NumberControl(
|
|
|
139
140
|
delta = Math.ceil( Math.abs( delta ) ) * Math.sign( delta );
|
|
140
141
|
const distance = delta * modifier * directionModifier;
|
|
141
142
|
|
|
142
|
-
|
|
143
|
+
nextState.value = constrainValue(
|
|
143
144
|
add( currentValue, distance ),
|
|
144
145
|
enableShift ? modifier : null
|
|
145
146
|
);
|
|
@@ -147,7 +148,7 @@ export function NumberControl(
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
/**
|
|
150
|
-
* Handles commit (ENTER key press or
|
|
151
|
+
* Handles commit (ENTER key press or blur)
|
|
151
152
|
*/
|
|
152
153
|
if (
|
|
153
154
|
type === inputControlActionTypes.PRESS_ENTER ||
|
|
@@ -155,12 +156,12 @@ export function NumberControl(
|
|
|
155
156
|
) {
|
|
156
157
|
const applyEmptyValue = required === false && currentValue === '';
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
nextState.value = applyEmptyValue
|
|
159
160
|
? currentValue
|
|
160
161
|
: constrainValue( currentValue );
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
return
|
|
164
|
+
return nextState;
|
|
164
165
|
};
|
|
165
166
|
|
|
166
167
|
return (
|
|
@@ -180,10 +181,10 @@ export function NumberControl(
|
|
|
180
181
|
step={ step }
|
|
181
182
|
type={ typeProp }
|
|
182
183
|
value={ valueProp }
|
|
183
|
-
__unstableStateReducer={
|
|
184
|
-
numberControlStateReducer,
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
__unstableStateReducer={ ( state, action ) => {
|
|
185
|
+
const baseState = numberControlStateReducer( state, action );
|
|
186
|
+
return stateReducerProp?.( baseState, action ) ?? baseState;
|
|
187
|
+
} }
|
|
187
188
|
/>
|
|
188
189
|
);
|
|
189
190
|
}
|
|
@@ -23,6 +23,7 @@ export default {
|
|
|
23
23
|
|
|
24
24
|
function Example() {
|
|
25
25
|
const [ value, setValue ] = useState( '0' );
|
|
26
|
+
const [ isValidValue, setIsValidValue ] = useState( true );
|
|
26
27
|
|
|
27
28
|
const props = {
|
|
28
29
|
disabled: boolean( 'disabled', false ),
|
|
@@ -32,18 +33,24 @@ function Example() {
|
|
|
32
33
|
label: text( 'label', 'Number' ),
|
|
33
34
|
min: number( 'min', 0 ),
|
|
34
35
|
max: number( 'max', 100 ),
|
|
35
|
-
placeholder: text( 'placeholder', 0 ),
|
|
36
|
+
placeholder: text( 'placeholder', '0' ),
|
|
36
37
|
required: boolean( 'required', false ),
|
|
37
38
|
shiftStep: number( 'shiftStep', 10 ),
|
|
38
|
-
step: text( 'step', 1 ),
|
|
39
|
+
step: text( 'step', '1' ),
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
return (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
<>
|
|
44
|
+
<NumberControl
|
|
45
|
+
{ ...props }
|
|
46
|
+
value={ value }
|
|
47
|
+
onChange={ ( v, extra ) => {
|
|
48
|
+
setValue( v );
|
|
49
|
+
setIsValidValue( extra.event.target.validity.valid );
|
|
50
|
+
} }
|
|
51
|
+
/>
|
|
52
|
+
<p>Is valid? { isValidValue ? 'Yes' : 'No' }</p>
|
|
53
|
+
</>
|
|
47
54
|
);
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -63,6 +63,68 @@ describe( 'NumberControl', () => {
|
|
|
63
63
|
|
|
64
64
|
expect( spy ).toHaveBeenCalledWith( '10' );
|
|
65
65
|
} );
|
|
66
|
+
|
|
67
|
+
it( 'should call onChange callback when value is clamped on blur', async () => {
|
|
68
|
+
const spy = jest.fn();
|
|
69
|
+
render(
|
|
70
|
+
<NumberControl
|
|
71
|
+
value={ 5 }
|
|
72
|
+
min={ 4 }
|
|
73
|
+
max={ 10 }
|
|
74
|
+
onChange={ ( v ) => spy( v ) }
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const input = getInput();
|
|
79
|
+
input.focus();
|
|
80
|
+
fireEvent.change( input, { target: { value: 1 } } );
|
|
81
|
+
|
|
82
|
+
// Before blurring, the value is still un-clamped
|
|
83
|
+
expect( input.value ).toBe( '1' );
|
|
84
|
+
|
|
85
|
+
input.blur();
|
|
86
|
+
|
|
87
|
+
// After blur, value is clamped
|
|
88
|
+
expect( input.value ).toBe( '4' );
|
|
89
|
+
|
|
90
|
+
// After the blur, the `onChange` callback fires asynchronously.
|
|
91
|
+
await waitFor( () => {
|
|
92
|
+
expect( spy ).toHaveBeenCalledTimes( 2 );
|
|
93
|
+
expect( spy ).toHaveBeenNthCalledWith( 1, '1' );
|
|
94
|
+
expect( spy ).toHaveBeenNthCalledWith( 2, 4 );
|
|
95
|
+
} );
|
|
96
|
+
} );
|
|
97
|
+
|
|
98
|
+
it( 'should call onChange callback when value is not valid', () => {
|
|
99
|
+
const spy = jest.fn();
|
|
100
|
+
render(
|
|
101
|
+
<NumberControl
|
|
102
|
+
value={ 5 }
|
|
103
|
+
min={ 1 }
|
|
104
|
+
max={ 10 }
|
|
105
|
+
onChange={ ( v, extra ) =>
|
|
106
|
+
spy( v, extra.event.target.validity.valid )
|
|
107
|
+
}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const input = getInput();
|
|
112
|
+
input.focus();
|
|
113
|
+
fireEvent.change( input, { target: { value: 14 } } );
|
|
114
|
+
|
|
115
|
+
expect( input.value ).toBe( '14' );
|
|
116
|
+
|
|
117
|
+
fireKeyDown( { keyCode: ENTER } );
|
|
118
|
+
|
|
119
|
+
expect( input.value ).toBe( '10' );
|
|
120
|
+
|
|
121
|
+
expect( spy ).toHaveBeenCalledTimes( 2 );
|
|
122
|
+
|
|
123
|
+
// First call: invalid, unclamped value
|
|
124
|
+
expect( spy ).toHaveBeenNthCalledWith( 1, '14', false );
|
|
125
|
+
// Second call: valid, clamped value
|
|
126
|
+
expect( spy ).toHaveBeenNthCalledWith( 2, 10, true );
|
|
127
|
+
} );
|
|
66
128
|
} );
|
|
67
129
|
|
|
68
130
|
describe( 'Validation', () => {
|
|
@@ -82,6 +144,22 @@ describe( 'NumberControl', () => {
|
|
|
82
144
|
expect( input.value ).toBe( '0' );
|
|
83
145
|
} );
|
|
84
146
|
|
|
147
|
+
it( 'should clamp value within range on blur', () => {
|
|
148
|
+
render( <NumberControl value={ 5 } min={ 0 } max={ 10 } /> );
|
|
149
|
+
|
|
150
|
+
const input = getInput();
|
|
151
|
+
input.focus();
|
|
152
|
+
fireEvent.change( input, { target: { value: 41 } } );
|
|
153
|
+
|
|
154
|
+
// Before blurring, the value is still un-clamped
|
|
155
|
+
expect( input.value ).toBe( '41' );
|
|
156
|
+
|
|
157
|
+
input.blur();
|
|
158
|
+
|
|
159
|
+
// After blur, value is clamped
|
|
160
|
+
expect( input.value ).toBe( '10' );
|
|
161
|
+
} );
|
|
162
|
+
|
|
85
163
|
it( 'should parse to number value on ENTER keypress when required', () => {
|
|
86
164
|
render( <NumberControl value={ 5 } required={ true } /> );
|
|
87
165
|
|
|
@@ -1,145 +1,128 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import styled from '@emotion/styled';
|
|
5
|
-
import { boolean, number, text } from '@storybook/addon-knobs';
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* WordPress dependencies
|
|
9
3
|
*/
|
|
10
4
|
import { useState } from '@wordpress/element';
|
|
11
|
-
import { wordpress } from '@wordpress/icons';
|
|
5
|
+
import { styles, wordpress } from '@wordpress/icons';
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* Internal dependencies
|
|
15
9
|
*/
|
|
16
10
|
import RangeControl from '../index';
|
|
17
|
-
|
|
11
|
+
|
|
12
|
+
const ICONS = { styles, wordpress };
|
|
18
13
|
|
|
19
14
|
export default {
|
|
20
15
|
title: 'Components/RangeControl',
|
|
21
16
|
component: RangeControl,
|
|
17
|
+
argTypes: {
|
|
18
|
+
afterIcon: {
|
|
19
|
+
control: { type: 'select' },
|
|
20
|
+
options: Object.keys( ICONS ),
|
|
21
|
+
mapping: ICONS,
|
|
22
|
+
},
|
|
23
|
+
allowReset: { control: { type: 'boolean' } },
|
|
24
|
+
beforeIcon: {
|
|
25
|
+
control: { type: 'select' },
|
|
26
|
+
options: Object.keys( ICONS ),
|
|
27
|
+
mapping: ICONS,
|
|
28
|
+
},
|
|
29
|
+
color: { control: { type: 'color' } },
|
|
30
|
+
disabled: { control: { type: 'boolean' } },
|
|
31
|
+
help: { control: { type: 'text' } },
|
|
32
|
+
initialPosition: { control: { type: 'number' } },
|
|
33
|
+
marks: { control: { type: 'object' } },
|
|
34
|
+
min: { control: { type: 'number' } },
|
|
35
|
+
max: { control: { type: 'number' } },
|
|
36
|
+
railColor: { control: { type: 'color' } },
|
|
37
|
+
showTooltip: { control: { type: 'boolean' } },
|
|
38
|
+
step: { control: { type: 'number' } },
|
|
39
|
+
trackColor: { control: { type: 'color' } },
|
|
40
|
+
withInputField: { control: { type: 'boolean' } },
|
|
41
|
+
},
|
|
22
42
|
parameters: {
|
|
23
|
-
|
|
43
|
+
docs: { source: { state: 'open' } },
|
|
24
44
|
},
|
|
25
45
|
};
|
|
26
46
|
|
|
27
47
|
const RangeControlWithState = ( props ) => {
|
|
28
|
-
const
|
|
29
|
-
const [ value, setValue ] = useState( initialValue );
|
|
48
|
+
const [ value, setValue ] = useState();
|
|
30
49
|
|
|
31
50
|
return <RangeControl { ...props } value={ value } onChange={ setValue } />;
|
|
32
51
|
};
|
|
33
52
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const showBeforeIcon = boolean( 'beforeIcon', false );
|
|
38
|
-
const showAfterIcon = boolean( 'afterIcon', false );
|
|
39
|
-
|
|
40
|
-
const props = {
|
|
41
|
-
afterIcon: showAfterIcon ? wordpress : undefined,
|
|
42
|
-
allowReset: boolean( 'allowReset', false ),
|
|
43
|
-
beforeIcon: showBeforeIcon ? wordpress : undefined,
|
|
44
|
-
color: text( 'color', COLORS.ui.theme ),
|
|
45
|
-
disabled: boolean( 'disabled', false ),
|
|
46
|
-
help: text( 'help', '' ),
|
|
47
|
-
label: text( 'label', 'Range Label' ),
|
|
48
|
-
marks: boolean( 'marks', false ),
|
|
49
|
-
max: number( 'max', 100 ),
|
|
50
|
-
min: number( 'min', 0 ),
|
|
51
|
-
showTooltip: boolean( 'showTooltip', false ),
|
|
52
|
-
step: text( 'step', 1 ),
|
|
53
|
-
railColor: text( 'railColor', null ),
|
|
54
|
-
trackColor: text( 'trackColor', null ),
|
|
55
|
-
withInputField: boolean( 'withInputField', true ),
|
|
56
|
-
value,
|
|
57
|
-
onChange: setValue,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<Wrapper>
|
|
62
|
-
<RangeControl { ...props } />
|
|
63
|
-
</Wrapper>
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const RangeControlLabeledByMarksType = ( props ) => {
|
|
68
|
-
const label = Array.isArray( props.marks ) ? 'Custom' : 'Automatic';
|
|
69
|
-
return <RangeControl { ...{ ...props, label } } />;
|
|
53
|
+
export const Default = RangeControlWithState.bind( {} );
|
|
54
|
+
Default.args = {
|
|
55
|
+
label: 'Range label',
|
|
70
56
|
};
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
/**
|
|
59
|
+
* The `initialPosition` prop sets the starting position of the slider when no `value` is provided.
|
|
60
|
+
*/
|
|
61
|
+
export const InitialValueZero = RangeControlWithState.bind( {} );
|
|
62
|
+
InitialValueZero.args = {
|
|
63
|
+
...Default.args,
|
|
64
|
+
initialPosition: 0,
|
|
65
|
+
max: 20,
|
|
74
66
|
};
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Setting the `step` prop to `"any"` will allow users to select non-integer values.
|
|
70
|
+
* This also overrides both `withInputField` and `showTooltip` props to `false`.
|
|
71
|
+
*/
|
|
72
|
+
export const WithAnyStep = ( props ) => {
|
|
73
|
+
const [ value, setValue ] = useState( 1.2345 );
|
|
78
74
|
|
|
79
75
|
return (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
min={ 0 }
|
|
85
|
-
value={ null }
|
|
86
|
-
/>
|
|
76
|
+
<>
|
|
77
|
+
<RangeControl value={ value } onChange={ setValue } { ...props } />
|
|
78
|
+
<p>Current value: { value }</p>
|
|
79
|
+
</>
|
|
87
80
|
);
|
|
88
81
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
WithAnyStep.args = {
|
|
83
|
+
label: 'Brightness',
|
|
84
|
+
step: 'any',
|
|
92
85
|
};
|
|
93
86
|
|
|
94
|
-
export const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
return <RangeControlWithState label={ label } help={ help } />;
|
|
87
|
+
export const WithHelp = RangeControlWithState.bind( {} );
|
|
88
|
+
WithHelp.args = {
|
|
89
|
+
...Default.args,
|
|
90
|
+
label: 'How many columns should this use?',
|
|
91
|
+
help: 'Please select the number of columns you would like this to contain.',
|
|
102
92
|
};
|
|
103
93
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Set `min` and `max` values to constrain the range of allowed values.
|
|
96
|
+
*/
|
|
97
|
+
export const WithMinimumAndMaximumLimits = RangeControlWithState.bind( {} );
|
|
98
|
+
WithMinimumAndMaximumLimits.args = {
|
|
99
|
+
...Default.args,
|
|
100
|
+
min: 2,
|
|
101
|
+
max: 10,
|
|
110
102
|
};
|
|
111
103
|
|
|
112
|
-
export const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<RangeControlWithState
|
|
118
|
-
label={ label }
|
|
119
|
-
beforeIcon={ showIcon ? wordpress : undefined }
|
|
120
|
-
/>
|
|
121
|
-
);
|
|
104
|
+
export const WithIconBefore = RangeControlWithState.bind( {} );
|
|
105
|
+
WithIconBefore.args = {
|
|
106
|
+
...Default.args,
|
|
107
|
+
beforeIcon: wordpress,
|
|
122
108
|
};
|
|
123
109
|
|
|
124
|
-
export const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return (
|
|
129
|
-
<RangeControlWithState
|
|
130
|
-
label={ label }
|
|
131
|
-
afterIcon={ showIcon ? wordpress : undefined }
|
|
132
|
-
/>
|
|
133
|
-
);
|
|
110
|
+
export const WithIconAfter = RangeControlWithState.bind( {} );
|
|
111
|
+
WithIconAfter.args = {
|
|
112
|
+
...Default.args,
|
|
113
|
+
afterIcon: wordpress,
|
|
134
114
|
};
|
|
135
115
|
|
|
136
|
-
export const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
116
|
+
export const WithReset = RangeControlWithState.bind( {} );
|
|
117
|
+
WithReset.args = {
|
|
118
|
+
...Default.args,
|
|
119
|
+
allowReset: true,
|
|
140
120
|
};
|
|
141
121
|
|
|
142
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Use `marks` to render a visual representation of `step` ticks. Custom mark indicators can be provided by an `Array`.
|
|
124
|
+
*/
|
|
125
|
+
export const WithMarks = ( props ) => {
|
|
143
126
|
const marksBase = [
|
|
144
127
|
{ value: 0, label: '0' },
|
|
145
128
|
{ value: 1, label: '1' },
|
|
@@ -164,11 +147,15 @@ export const marks = () => {
|
|
|
164
147
|
const minNegative = { min: -10, max: 10, step: 1 };
|
|
165
148
|
const rangeNegative = { min: -10, max: -1, step: 1 };
|
|
166
149
|
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
const Range = ( localProps ) => {
|
|
151
|
+
const label = Array.isArray( localProps.marks )
|
|
152
|
+
? 'Custom'
|
|
153
|
+
: 'Automatic';
|
|
154
|
+
return <RangeControl { ...{ ...localProps, ...props, label } } />;
|
|
155
|
+
};
|
|
169
156
|
|
|
170
157
|
return (
|
|
171
|
-
|
|
158
|
+
<>
|
|
172
159
|
<h2>Integer Step</h2>
|
|
173
160
|
<Range marks { ...stepInteger } />
|
|
174
161
|
<Range marks={ marksBase } { ...stepInteger } />
|
|
@@ -188,21 +175,6 @@ export const marks = () => {
|
|
|
188
175
|
<h2>Any Step</h2>
|
|
189
176
|
<Range marks { ...{ ...stepInteger, step: 'any' } } />
|
|
190
177
|
<Range marks={ marksBase } { ...{ ...stepInteger, step: 'any' } } />
|
|
191
|
-
|
|
178
|
+
</>
|
|
192
179
|
);
|
|
193
180
|
};
|
|
194
|
-
|
|
195
|
-
export const multiple = () => {
|
|
196
|
-
return (
|
|
197
|
-
<Wrapper>
|
|
198
|
-
<RangeControlWithState />
|
|
199
|
-
<RangeControlWithState />
|
|
200
|
-
<RangeControlWithState />
|
|
201
|
-
<RangeControlWithState />
|
|
202
|
-
</Wrapper>
|
|
203
|
-
);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
const Wrapper = styled.div`
|
|
207
|
-
padding: 60px 40px;
|
|
208
|
-
`;
|
|
@@ -122,21 +122,6 @@ exports[`ToggleGroupControl should render correctly 1`] = `
|
|
|
122
122
|
.emotion-11 {
|
|
123
123
|
font-size: 13px;
|
|
124
124
|
line-height: 1;
|
|
125
|
-
position: absolute;
|
|
126
|
-
top: 50%;
|
|
127
|
-
left: 50%;
|
|
128
|
-
-webkit-transform: translate( -50%, -50% );
|
|
129
|
-
-moz-transform: translate( -50%, -50% );
|
|
130
|
-
-ms-transform: translate( -50%, -50% );
|
|
131
|
-
transform: translate( -50%, -50% );
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.emotion-13 {
|
|
135
|
-
font-size: 13px;
|
|
136
|
-
font-weight: bold;
|
|
137
|
-
height: 0;
|
|
138
|
-
overflow: hidden;
|
|
139
|
-
visibility: hidden;
|
|
140
125
|
}
|
|
141
126
|
|
|
142
127
|
<div
|
|
@@ -180,12 +165,6 @@ exports[`ToggleGroupControl should render correctly 1`] = `
|
|
|
180
165
|
>
|
|
181
166
|
R
|
|
182
167
|
</div>
|
|
183
|
-
<div
|
|
184
|
-
aria-hidden="true"
|
|
185
|
-
class="emotion-13 emotion-14"
|
|
186
|
-
>
|
|
187
|
-
R
|
|
188
|
-
</div>
|
|
189
168
|
</button>
|
|
190
169
|
</div>
|
|
191
170
|
<div
|
|
@@ -208,12 +187,6 @@ exports[`ToggleGroupControl should render correctly 1`] = `
|
|
|
208
187
|
>
|
|
209
188
|
J
|
|
210
189
|
</div>
|
|
211
|
-
<div
|
|
212
|
-
aria-hidden="true"
|
|
213
|
-
class="emotion-13 emotion-14"
|
|
214
|
-
>
|
|
215
|
-
J
|
|
216
|
-
</div>
|
|
217
190
|
</button>
|
|
218
191
|
</div>
|
|
219
192
|
</div>
|
|
@@ -24,7 +24,7 @@ import * as styles from './styles';
|
|
|
24
24
|
import { useCx } from '../../utils/hooks';
|
|
25
25
|
import Tooltip from '../../tooltip';
|
|
26
26
|
|
|
27
|
-
const { ButtonContentView,
|
|
27
|
+
const { ButtonContentView, LabelView } = styles;
|
|
28
28
|
|
|
29
29
|
const WithToolTip = ( { showTooltip, text, children }: WithToolTipProps ) => {
|
|
30
30
|
if ( showTooltip && text ) {
|
|
@@ -88,9 +88,6 @@ function ToggleGroupControlOption(
|
|
|
88
88
|
value={ value }
|
|
89
89
|
>
|
|
90
90
|
<ButtonContentView>{ label }</ButtonContentView>
|
|
91
|
-
<LabelPlaceholderView aria-hidden>
|
|
92
|
-
{ label }
|
|
93
|
-
</LabelPlaceholderView>
|
|
94
91
|
</Radio>
|
|
95
92
|
</WithToolTip>
|
|
96
93
|
</LabelView>
|