@carbon/react 1.90.0 → 1.91.0-rc.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/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +921 -921
- package/es/components/CodeSnippet/CodeSnippet.d.ts +1 -1
- package/es/components/CodeSnippet/CodeSnippet.js +1 -1
- package/es/components/ComboBox/ComboBox.js +1 -12
- package/es/components/ComboButton/index.js +1 -1
- package/es/components/ComposedModal/ComposedModal.js +1 -1
- package/es/components/Copy/Copy.d.ts +1 -1
- package/es/components/Copy/Copy.js +1 -1
- package/es/components/CopyButton/CopyButton.d.ts +1 -1
- package/es/components/CopyButton/CopyButton.js +1 -1
- package/es/components/DataTable/DataTable.d.ts +60 -15
- package/es/components/DataTable/DataTable.js +106 -179
- package/es/components/DataTable/Table.d.ts +2 -2
- package/es/components/DataTable/Table.js +1 -1
- package/es/components/DataTable/TableExpandHeader.d.ts +1 -1
- package/es/components/DataTable/TableExpandHeader.js +1 -1
- package/es/components/DatePicker/DatePicker.d.ts +0 -12
- package/es/components/DatePicker/DatePicker.js +3 -3
- package/es/components/DatePicker/plugins/rangePlugin.d.ts +19 -2
- package/es/components/DatePicker/plugins/rangePlugin.js +18 -14
- package/es/components/Dropdown/Dropdown.js +1 -12
- package/es/components/FeatureFlags/index.js +1 -0
- package/es/components/IconButton/index.js +1 -1
- package/es/components/Menu/MenuItem.d.ts +1 -1
- package/es/components/Menu/MenuItem.js +5 -5
- package/es/components/Modal/Modal.js +1 -1
- package/es/components/MultiSelect/FilterableMultiSelect.js +1 -1
- package/es/components/MultiSelect/MultiSelect.js +1 -12
- package/es/components/Notification/Notification.d.ts +6 -6
- package/es/components/Notification/Notification.js +6 -6
- package/es/components/OverflowMenu/OverflowMenu.js +1 -1
- package/es/components/OverflowMenu/next/index.js +1 -1
- package/es/components/Popover/index.js +1 -1
- package/es/components/Search/Search.d.ts +4 -2
- package/es/components/Search/Search.js +5 -4
- package/es/components/Slider/Slider.d.ts +144 -188
- package/es/components/Slider/Slider.js +787 -710
- package/es/components/Slider/index.d.ts +2 -2
- package/es/components/Tabs/Tabs.d.ts +4 -0
- package/es/components/TextArea/TextArea.js +13 -6
- package/es/components/TextInput/ControlledPasswordInput.js +2 -2
- package/es/components/TextInput/PasswordInput.js +2 -2
- package/es/components/TextInput/TextInput.js +2 -2
- package/es/components/TextInput/util.d.ts +17 -5
- package/es/components/TextInput/util.js +2 -7
- package/es/components/UIShell/HeaderPanel.d.ts +1 -1
- package/es/index.d.ts +12 -13
- package/es/index.js +25 -24
- package/es/internal/defaultItemToString.d.ts +7 -0
- package/es/internal/defaultItemToString.js +17 -0
- package/es/internal/index.d.ts +1 -0
- package/es/prop-types/deprecateValuesWithin.d.ts +8 -1
- package/es/prop-types/deprecateValuesWithin.js +6 -6
- package/es/prop-types/requiredIfGivenPropIsTruthy.d.ts +8 -7
- package/es/prop-types/requiredIfGivenPropIsTruthy.js +10 -10
- package/lib/components/CodeSnippet/CodeSnippet.d.ts +1 -1
- package/lib/components/CodeSnippet/CodeSnippet.js +1 -1
- package/lib/components/ComboBox/ComboBox.js +3 -14
- package/lib/components/ComboButton/index.js +1 -1
- package/lib/components/ComposedModal/ComposedModal.js +1 -1
- package/lib/components/Copy/Copy.d.ts +1 -1
- package/lib/components/Copy/Copy.js +1 -1
- package/lib/components/CopyButton/CopyButton.d.ts +1 -1
- package/lib/components/CopyButton/CopyButton.js +1 -1
- package/lib/components/DataTable/DataTable.d.ts +60 -15
- package/lib/components/DataTable/DataTable.js +106 -179
- package/lib/components/DataTable/Table.d.ts +2 -2
- package/lib/components/DataTable/Table.js +1 -1
- package/lib/components/DataTable/TableExpandHeader.d.ts +1 -1
- package/lib/components/DataTable/TableExpandHeader.js +3 -3
- package/lib/components/DatePicker/DatePicker.d.ts +0 -12
- package/lib/components/DatePicker/DatePicker.js +2 -2
- package/lib/components/DatePicker/plugins/rangePlugin.d.ts +19 -2
- package/lib/components/DatePicker/plugins/rangePlugin.js +18 -16
- package/lib/components/Dropdown/Dropdown.js +3 -14
- package/lib/components/FeatureFlags/index.js +1 -0
- package/lib/components/IconButton/index.js +1 -1
- package/lib/components/Menu/MenuItem.d.ts +1 -1
- package/lib/components/Menu/MenuItem.js +6 -6
- package/lib/components/Modal/Modal.js +1 -1
- package/lib/components/MultiSelect/FilterableMultiSelect.js +8 -8
- package/lib/components/MultiSelect/MultiSelect.js +2 -13
- package/lib/components/Notification/Notification.d.ts +6 -6
- package/lib/components/Notification/Notification.js +6 -6
- package/lib/components/OverflowMenu/OverflowMenu.js +1 -1
- package/lib/components/OverflowMenu/next/index.js +1 -1
- package/lib/components/Popover/index.js +1 -1
- package/lib/components/Search/Search.d.ts +4 -2
- package/lib/components/Search/Search.js +5 -4
- package/lib/components/Slider/Slider.d.ts +144 -188
- package/lib/components/Slider/Slider.js +784 -709
- package/lib/components/Slider/index.d.ts +2 -2
- package/lib/components/Tabs/Tabs.d.ts +4 -0
- package/lib/components/TextArea/TextArea.js +13 -6
- package/lib/components/TextInput/ControlledPasswordInput.js +1 -1
- package/lib/components/TextInput/PasswordInput.js +1 -1
- package/lib/components/TextInput/TextInput.js +1 -1
- package/lib/components/TextInput/util.d.ts +17 -5
- package/lib/components/TextInput/util.js +2 -7
- package/lib/components/UIShell/HeaderPanel.d.ts +1 -1
- package/lib/index.d.ts +12 -13
- package/lib/index.js +51 -28
- package/lib/internal/defaultItemToString.d.ts +7 -0
- package/lib/internal/defaultItemToString.js +19 -0
- package/lib/internal/index.d.ts +1 -0
- package/lib/prop-types/deprecateValuesWithin.d.ts +8 -1
- package/lib/prop-types/deprecateValuesWithin.js +6 -8
- package/lib/prop-types/requiredIfGivenPropIsTruthy.d.ts +8 -7
- package/lib/prop-types/requiredIfGivenPropIsTruthy.js +10 -12
- package/package.json +8 -7
- package/es/components/MultiSelect/tools/itemToString.d.ts +0 -1
- package/es/components/MultiSelect/tools/itemToString.js +0 -21
- package/es/components/Slider/index.js +0 -14
- package/es/internal/createClassWrapper.js +0 -23
- package/lib/components/MultiSelect/tools/itemToString.d.ts +0 -1
- package/lib/components/MultiSelect/tools/itemToString.js +0 -23
- package/lib/components/Slider/index.js +0 -20
- package/lib/internal/createClassWrapper.js +0 -25
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import React, {
|
|
8
|
+
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
|
+
import React, { useReducer, useRef, useEffect, useMemo } from 'react';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import cx from 'classnames';
|
|
12
|
-
import { ArrowDown, ArrowLeft, ArrowUp, ArrowRight
|
|
12
|
+
import { Enter, ArrowDown, ArrowLeft, ArrowUp, ArrowRight } from '../../internal/keyboard/keys.js';
|
|
13
13
|
import { matches } from '../../internal/keyboard/match.js';
|
|
14
14
|
import { PrefixContext } from '../../internal/usePrefix.js';
|
|
15
15
|
import { deprecate } from '../../prop-types/deprecate.js';
|
|
16
|
-
import { FeatureFlagContext } from '../FeatureFlags/index.js';
|
|
17
16
|
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
|
|
18
17
|
import '../Text/index.js';
|
|
19
18
|
import '../Tooltip/DefinitionTooltip.js';
|
|
@@ -76,752 +75,834 @@ var HandlePosition = /*#__PURE__*/function (HandlePosition) {
|
|
|
76
75
|
HandlePosition["LOWER"] = "lower";
|
|
77
76
|
HandlePosition["UPPER"] = "upper";
|
|
78
77
|
return HandlePosition;
|
|
79
|
-
}(HandlePosition || {});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
super(props);
|
|
83
|
-
_defineProperty(this, "state", {
|
|
84
|
-
value: this.props.value,
|
|
85
|
-
valueUpper: this.props.unstable_valueUpper,
|
|
86
|
-
left: 0,
|
|
87
|
-
leftUpper: 0,
|
|
88
|
-
needsOnRelease: false,
|
|
89
|
-
isValid: true,
|
|
90
|
-
isValidUpper: true,
|
|
91
|
-
activeHandle: undefined,
|
|
92
|
-
correctedValue: null,
|
|
93
|
-
correctedPosition: null,
|
|
94
|
-
isRtl: false
|
|
95
|
-
});
|
|
96
|
-
_defineProperty(this, "thumbRef", void 0);
|
|
97
|
-
_defineProperty(this, "thumbRefUpper", void 0);
|
|
98
|
-
_defineProperty(this, "filledTrackRef", void 0);
|
|
99
|
-
_defineProperty(this, "element", null);
|
|
100
|
-
_defineProperty(this, "inputId", '');
|
|
101
|
-
_defineProperty(this, "track", void 0);
|
|
102
|
-
_defineProperty(this, "handleDrag", event => {
|
|
103
|
-
if (event instanceof globalThis.MouseEvent || event instanceof globalThis.TouchEvent) {
|
|
104
|
-
this.onDrag(event);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
/**
|
|
108
|
-
* Sets up "drag" event handlers and calls `this.onDrag` in case dragging
|
|
109
|
-
* started on somewhere other than the thumb without a corresponding "move"
|
|
110
|
-
* event.
|
|
111
|
-
*/
|
|
112
|
-
_defineProperty(this, "onDragStart", evt => {
|
|
113
|
-
// Do nothing if component is disabled
|
|
114
|
-
if (this.props.disabled || this.props.readOnly) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// We're going to force focus on one of the handles later on here, b/c we're
|
|
119
|
-
// firing on a mousedown event, we need to call event.preventDefault() to
|
|
120
|
-
// keep the focus from leaving the HTMLElement.
|
|
121
|
-
// @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#notes
|
|
122
|
-
evt.preventDefault();
|
|
123
|
-
|
|
124
|
-
// Add drag stop handlers
|
|
125
|
-
DRAG_STOP_EVENT_TYPES.forEach(element => {
|
|
126
|
-
this.element?.ownerDocument.addEventListener(element, this.onDragStop);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Add drag handlers
|
|
130
|
-
DRAG_EVENT_TYPES.forEach(element => {
|
|
131
|
-
this.element?.ownerDocument.addEventListener(element, this.handleDrag);
|
|
132
|
-
});
|
|
133
|
-
const clientX = this.getClientXFromEvent(evt.nativeEvent);
|
|
134
|
-
let activeHandle;
|
|
135
|
-
if (this.hasTwoHandles()) {
|
|
136
|
-
if (evt.target == this.thumbRef.current) {
|
|
137
|
-
activeHandle = HandlePosition.LOWER;
|
|
138
|
-
} else if (evt.target == this.thumbRefUpper.current) {
|
|
139
|
-
activeHandle = HandlePosition.UPPER;
|
|
140
|
-
} else if (clientX) {
|
|
141
|
-
const distanceToLower = this.calcDistanceToHandle(HandlePosition.LOWER, clientX);
|
|
142
|
-
const distanceToUpper = this.calcDistanceToHandle(HandlePosition.UPPER, clientX);
|
|
143
|
-
if (distanceToLower <= distanceToUpper) {
|
|
144
|
-
activeHandle = HandlePosition.LOWER;
|
|
145
|
-
} else {
|
|
146
|
-
activeHandle = HandlePosition.UPPER;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
78
|
+
}(HandlePosition || {}); // TODO: Delete this type and directory type the properties in the function.
|
|
79
|
+
const Slider = props => {
|
|
80
|
+
// TODO: Move destructured `props` from the IIFE to here.
|
|
150
81
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.setState({
|
|
165
|
-
activeHandle
|
|
166
|
-
});
|
|
82
|
+
const initialState = {
|
|
83
|
+
value: props.value,
|
|
84
|
+
valueUpper: props.unstable_valueUpper,
|
|
85
|
+
left: 0,
|
|
86
|
+
leftUpper: 0,
|
|
87
|
+
needsOnRelease: false,
|
|
88
|
+
isValid: true,
|
|
89
|
+
isValidUpper: true,
|
|
90
|
+
activeHandle: undefined,
|
|
91
|
+
correctedValue: null,
|
|
92
|
+
correctedPosition: null,
|
|
93
|
+
isRtl: false
|
|
94
|
+
};
|
|
167
95
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
* Removes "drag" and "drag stop" event handlers and calls sets the flag
|
|
174
|
-
* indicating that the `onRelease` callback should be called.
|
|
175
|
-
*/
|
|
176
|
-
_defineProperty(this, "onDragStop", () => {
|
|
177
|
-
// Do nothing if component is disabled
|
|
178
|
-
if (this.props.disabled || this.props.readOnly) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
96
|
+
// TODO: Investigate using generics on the hook.
|
|
97
|
+
const [state, setState] = useReducer((prev, args) => ({
|
|
98
|
+
...prev,
|
|
99
|
+
...args
|
|
100
|
+
}), initialState);
|
|
181
101
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
102
|
+
// TODO: Investigate getting rid of these references.
|
|
103
|
+
const stateRef = useRef(state);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
stateRef.current = state;
|
|
106
|
+
}, [state]);
|
|
107
|
+
const propsRef = useRef(props);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
propsRef.current = props;
|
|
110
|
+
}, [props]);
|
|
111
|
+
const thumbRef = useRef(null);
|
|
112
|
+
const thumbRefUpper = useRef(null);
|
|
113
|
+
const filledTrackRef = useRef(null);
|
|
114
|
+
const elementRef = useRef(null);
|
|
115
|
+
const trackRef = useRef(null);
|
|
116
|
+
const inputIdRef = useRef('');
|
|
186
117
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
118
|
+
// TODO: Delete this function and set its return value as the value of
|
|
119
|
+
// `twoHandles`.
|
|
120
|
+
const hasTwoHandles = () => {
|
|
121
|
+
return typeof state.valueUpper !== 'undefined';
|
|
122
|
+
};
|
|
123
|
+
const twoHandles = hasTwoHandles();
|
|
191
124
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
* accordingly.
|
|
202
|
-
*
|
|
203
|
-
* @param evt The event.
|
|
204
|
-
* @param activeHandle The first drag event call, we may have an explicit
|
|
205
|
-
* activeHandle value, which is to be used before state is used.
|
|
206
|
-
*/
|
|
207
|
-
_defineProperty(this, "_onDrag", (evt, activeHandle) => {
|
|
208
|
-
activeHandle = activeHandle ?? this.state.activeHandle;
|
|
209
|
-
// Do nothing if component is disabled, or we have no event.
|
|
210
|
-
if (this.props.disabled || this.props.readOnly || !evt) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const clientX = this.getClientXFromEvent(evt);
|
|
214
|
-
const {
|
|
215
|
-
value,
|
|
216
|
-
left
|
|
217
|
-
} = this.calcValue({
|
|
218
|
-
clientX,
|
|
219
|
-
value: this.state.value
|
|
220
|
-
});
|
|
221
|
-
// If we're set to two handles, negotiate which drag handle is closest to
|
|
222
|
-
// the users' interaction.
|
|
223
|
-
if (this.hasTwoHandles() && activeHandle) {
|
|
224
|
-
this.setValueLeftForHandle(activeHandle, {
|
|
225
|
-
value: this.nearestStepValue(value),
|
|
125
|
+
/**
|
|
126
|
+
* Sets up initial slider position and value in response to component mount.
|
|
127
|
+
*/
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (elementRef.current) {
|
|
130
|
+
const isRtl = document?.dir === 'rtl';
|
|
131
|
+
if (hasTwoHandles()) {
|
|
132
|
+
const {
|
|
133
|
+
value,
|
|
226
134
|
left
|
|
135
|
+
} = calcValue({
|
|
136
|
+
value: stateRef.current.value,
|
|
137
|
+
useRawValue: true
|
|
227
138
|
});
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
139
|
+
const {
|
|
140
|
+
value: valueUpper,
|
|
141
|
+
left: leftUpper
|
|
142
|
+
} = calcValue({
|
|
143
|
+
value: stateRef.current.valueUpper,
|
|
144
|
+
useRawValue: true
|
|
145
|
+
});
|
|
146
|
+
setState({
|
|
147
|
+
isRtl,
|
|
148
|
+
value,
|
|
231
149
|
left,
|
|
232
|
-
|
|
150
|
+
valueUpper,
|
|
151
|
+
leftUpper
|
|
233
152
|
});
|
|
234
|
-
}
|
|
235
|
-
this.setState({
|
|
236
|
-
correctedValue: null,
|
|
237
|
-
correctedPosition: null
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
/**
|
|
241
|
-
* Throttles calls to `this._onDrag` by limiting events to being processed at
|
|
242
|
-
* most once every `EVENT_THROTTLE` milliseconds.
|
|
243
|
-
*/
|
|
244
|
-
_defineProperty(this, "onDrag", throttle(this._onDrag, EVENT_THROTTLE, {
|
|
245
|
-
leading: true,
|
|
246
|
-
trailing: false
|
|
247
|
-
}));
|
|
248
|
-
/**
|
|
249
|
-
* Handles a `keydown` event by recalculating the value/thumb and setting
|
|
250
|
-
* state accordingly.
|
|
251
|
-
*/
|
|
252
|
-
_defineProperty(this, "onKeyDown", evt => {
|
|
253
|
-
// Do nothing if component is disabled, or we don't have a valid event
|
|
254
|
-
if (this.props.disabled || this.props.readOnly) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
const {
|
|
258
|
-
step = 1,
|
|
259
|
-
stepMultiplier = 4
|
|
260
|
-
} = this.props;
|
|
261
|
-
let delta = 0;
|
|
262
|
-
if (matches(evt, [ArrowDown, ArrowLeft])) {
|
|
263
|
-
delta = -step;
|
|
264
|
-
} else if (matches(evt, [ArrowUp, ArrowRight])) {
|
|
265
|
-
delta = step;
|
|
266
153
|
} else {
|
|
267
|
-
// Ignore keys we don't want to handle
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// If shift was held, account for the stepMultiplier
|
|
272
|
-
if (evt.shiftKey) {
|
|
273
|
-
delta *= stepMultiplier;
|
|
274
|
-
}
|
|
275
|
-
if (this.hasTwoHandles() && this.state.activeHandle) {
|
|
276
|
-
const currentValue = this.state.activeHandle === HandlePosition.LOWER ? this.state.value : this.state.valueUpper;
|
|
277
154
|
const {
|
|
278
155
|
value,
|
|
279
156
|
left
|
|
280
|
-
} =
|
|
281
|
-
value:
|
|
282
|
-
|
|
283
|
-
this.setValueLeftForHandle(this.state.activeHandle, {
|
|
284
|
-
value: this.nearestStepValue(value),
|
|
285
|
-
left
|
|
157
|
+
} = calcValue({
|
|
158
|
+
value: stateRef.current.value,
|
|
159
|
+
useRawValue: true
|
|
286
160
|
});
|
|
287
|
-
|
|
288
|
-
|
|
161
|
+
setState({
|
|
162
|
+
isRtl,
|
|
289
163
|
value,
|
|
290
164
|
left
|
|
291
|
-
} = this.calcValue({
|
|
292
|
-
// Ensures custom value from `<input>` won't cause skipping next stepping
|
|
293
|
-
// point with right arrow key, e.g. Typing 51 in `<input>`, moving focus
|
|
294
|
-
// onto the thumb and the hitting right arrow key should yield 52 instead
|
|
295
|
-
// of 54.
|
|
296
|
-
value: this.calcValueForDelta(this.state.value, delta, this.props.step)
|
|
297
|
-
});
|
|
298
|
-
this.setState({
|
|
299
|
-
value: this.nearestStepValue(value),
|
|
300
|
-
left,
|
|
301
|
-
isValid: true
|
|
302
165
|
});
|
|
303
166
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Do nothing if we have no valid event, target, or value
|
|
321
|
-
if (!evt || !('target' in evt) || typeof evt.target.value !== 'string') {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
167
|
+
}
|
|
168
|
+
return () => {
|
|
169
|
+
DRAG_STOP_EVENT_TYPES.forEach(element => elementRef.current?.ownerDocument.removeEventListener(element, onDragStop));
|
|
170
|
+
DRAG_EVENT_TYPES.forEach(element => elementRef.current?.ownerDocument.removeEventListener(element, handleDrag));
|
|
171
|
+
};
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
}, []);
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
// TODO: Uncomment this code and delete all of the `filledTrackRef.current`
|
|
176
|
+
// checks.
|
|
177
|
+
// const el = filledTrackRef.current;
|
|
178
|
+
//
|
|
179
|
+
// if (!el) return;
|
|
324
180
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
-
this.setValueForHandle(activeHandle, evt.target.value);
|
|
331
|
-
} else if (this.isValidValueForPosition({
|
|
332
|
-
handle: activeHandle,
|
|
333
|
-
value: targetValue,
|
|
334
|
-
min: this.props.min,
|
|
335
|
-
max: this.props.max
|
|
336
|
-
})) {
|
|
337
|
-
this.processNewInputValue(evt.target);
|
|
338
|
-
} else {
|
|
339
|
-
this.setValueForHandle(activeHandle, targetValue);
|
|
340
|
-
}
|
|
341
|
-
} else {
|
|
342
|
-
if (isNaN(targetValue)) {
|
|
343
|
-
this.setState({
|
|
344
|
-
value: evt.target.value
|
|
345
|
-
});
|
|
346
|
-
} else if (this.isValidValue({
|
|
347
|
-
value: targetValue,
|
|
348
|
-
min: this.props.min,
|
|
349
|
-
max: this.props.max
|
|
350
|
-
})) {
|
|
351
|
-
this.processNewInputValue(evt.target);
|
|
352
|
-
} else {
|
|
353
|
-
this.setState({
|
|
354
|
-
value: targetValue
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
/**
|
|
360
|
-
* Checks for validity of input value after clicking out of the input. It also
|
|
361
|
-
* Handles state change to isValid state.
|
|
362
|
-
*/
|
|
363
|
-
_defineProperty(this, "onBlur", evt => {
|
|
364
|
-
// Do nothing if we have no valid event, target, or value
|
|
365
|
-
if (!evt || !('target' in evt) || typeof evt.target.value !== 'string') {
|
|
366
|
-
return;
|
|
181
|
+
// Fire onChange event handler if present, if there's a usable value, and
|
|
182
|
+
// if the value is different from the last one
|
|
183
|
+
if (hasTwoHandles()) {
|
|
184
|
+
if (filledTrackRef.current) {
|
|
185
|
+
filledTrackRef.current.style.transform = state.isRtl ? `translate(${100 - state.leftUpper}%, -50%) scaleX(${(state.leftUpper - state.left) / 100})` : `translate(${state.left}%, -50%) scaleX(${(state.leftUpper - state.left) / 100})`;
|
|
367
186
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
this.processNewInputValue(evt.target);
|
|
372
|
-
this.props.onBlur?.({
|
|
373
|
-
value: targetValue,
|
|
374
|
-
handlePosition: evt.target.dataset.handlePosition
|
|
375
|
-
});
|
|
376
|
-
});
|
|
377
|
-
_defineProperty(this, "onInputKeyDown", evt => {
|
|
378
|
-
// Do nothing if component is disabled, or we don't have a valid event.
|
|
379
|
-
if (this.props.disabled || this.props.readOnly || !(evt.target instanceof HTMLInputElement)) {
|
|
380
|
-
return;
|
|
187
|
+
} else {
|
|
188
|
+
if (filledTrackRef.current) {
|
|
189
|
+
filledTrackRef.current.style.transform = state.isRtl ? `translate(100%, -50%) scaleX(-${state.left / 100})` : `translate(0%, -50%) scaleX(${state.left / 100})`;
|
|
381
190
|
}
|
|
191
|
+
}
|
|
192
|
+
// TODO: Investigate whether the missing dependency should be added.
|
|
193
|
+
//
|
|
194
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
195
|
+
}, [state.left, state.leftUpper, state.isRtl]);
|
|
382
196
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
_defineProperty(this, "processNewInputValue", input => {
|
|
392
|
-
this.setState({
|
|
393
|
-
correctedValue: null,
|
|
394
|
-
correctedPosition: null
|
|
197
|
+
// Fire onChange when value(s) change
|
|
198
|
+
const prevValsRef = useRef(null);
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
const prev = prevValsRef.current;
|
|
201
|
+
if (prev && (prev.value !== state.value || prev.valueUpper !== state.valueUpper) && typeof props.onChange === 'function') {
|
|
202
|
+
props.onChange({
|
|
203
|
+
value: state.value,
|
|
204
|
+
valueUpper: state.valueUpper
|
|
395
205
|
});
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
this.setState({
|
|
413
|
-
isValid: validity
|
|
206
|
+
}
|
|
207
|
+
prevValsRef.current = {
|
|
208
|
+
value: state.value,
|
|
209
|
+
valueUpper: state.valueUpper
|
|
210
|
+
};
|
|
211
|
+
// TODO: Investigate whether the missing dependency should be added.
|
|
212
|
+
//
|
|
213
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
214
|
+
}, [state.value, state.valueUpper, props.onChange]);
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
// Fire onRelease event handler if present and if needed
|
|
217
|
+
if (state.needsOnRelease && typeof props.onRelease === 'function') {
|
|
218
|
+
props.onRelease({
|
|
219
|
+
value: state.value,
|
|
220
|
+
valueUpper: state.valueUpper
|
|
414
221
|
});
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
222
|
+
// Reset the flag
|
|
223
|
+
setState({
|
|
224
|
+
needsOnRelease: false
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
// TODO: Investigate whether the missing dependency should be added.
|
|
228
|
+
//
|
|
229
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
230
|
+
}, [state.needsOnRelease, state.value, state.valueUpper, props.onRelease]);
|
|
231
|
+
const prevSyncKeysRef = useRef(null);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
const prev = prevSyncKeysRef.current;
|
|
234
|
+
const next = [props.value, props.unstable_valueUpper, props.max, props.min];
|
|
235
|
+
|
|
236
|
+
// If value from props does not change, do nothing here.
|
|
237
|
+
// Otherwise, do prop -> state sync without "value capping".
|
|
238
|
+
if (!prev || prev[0] !== next[0] || prev[1] !== next[1] || prev[2] !== next[2] || prev[3] !== next[3]) {
|
|
239
|
+
setState(calcValue({
|
|
240
|
+
value: props.value,
|
|
241
|
+
useRawValue: true
|
|
242
|
+
}));
|
|
243
|
+
if (typeof props.unstable_valueUpper !== 'undefined') {
|
|
437
244
|
const {
|
|
438
|
-
value,
|
|
439
|
-
left
|
|
440
|
-
} =
|
|
441
|
-
value:
|
|
245
|
+
value: valueUpper,
|
|
246
|
+
left: leftUpper
|
|
247
|
+
} = calcValue({
|
|
248
|
+
value: props.unstable_valueUpper,
|
|
442
249
|
useRawValue: true
|
|
443
250
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
});
|
|
454
|
-
}
|
|
251
|
+
setState({
|
|
252
|
+
valueUpper,
|
|
253
|
+
leftUpper
|
|
254
|
+
});
|
|
255
|
+
} else {
|
|
256
|
+
setState({
|
|
257
|
+
valueUpper: undefined,
|
|
258
|
+
leftUpper: undefined
|
|
259
|
+
});
|
|
455
260
|
}
|
|
261
|
+
prevSyncKeysRef.current = next;
|
|
262
|
+
}
|
|
263
|
+
// TODO: Investigate whether the missing dependency should be added.
|
|
264
|
+
//
|
|
265
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
266
|
+
}, [props.value, props.unstable_valueUpper, props.max, props.min]);
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Rounds a given value to the nearest step defined by the slider's `step`
|
|
270
|
+
* prop.
|
|
271
|
+
*
|
|
272
|
+
* @param value - The value to adjust to the nearest step. Defaults to `0`.
|
|
273
|
+
* @returns The value rounded to the precision determined by the step.
|
|
274
|
+
*/
|
|
275
|
+
const nearestStepValue = (value = 0) => {
|
|
276
|
+
// TODO: Use a nullish coalescing operator.
|
|
277
|
+
const decimals = (props.step?.toString().split('.')[1] || '').length;
|
|
278
|
+
return Number(value.toFixed(decimals));
|
|
279
|
+
};
|
|
280
|
+
const handleDrag = event => {
|
|
281
|
+
if (event instanceof globalThis.MouseEvent || event instanceof globalThis.TouchEvent) {
|
|
282
|
+
onDrag(event);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Sets up "drag" event handlers and calls `onDrag` in case dragging
|
|
288
|
+
* started on somewhere other than the thumb without a corresponding "move"
|
|
289
|
+
* event.
|
|
290
|
+
*/
|
|
291
|
+
const onDragStart = evt => {
|
|
292
|
+
// Do nothing if component is disabled
|
|
293
|
+
if (props.disabled || props.readOnly) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// We're going to force focus on one of the handles later on here, b/c we're
|
|
298
|
+
// firing on a mousedown event, we need to call event.preventDefault() to
|
|
299
|
+
// keep the focus from leaving the HTMLElement.
|
|
300
|
+
// @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#notes
|
|
301
|
+
evt.preventDefault();
|
|
302
|
+
|
|
303
|
+
// TODO: Abstract `elementRef.current?.ownerDocument` to a variable that can
|
|
304
|
+
// be used here and everywhere else in this file.
|
|
305
|
+
|
|
306
|
+
// Add drag stop handlers
|
|
307
|
+
DRAG_STOP_EVENT_TYPES.forEach(element => {
|
|
308
|
+
elementRef.current?.ownerDocument.addEventListener(element, onDragStop);
|
|
456
309
|
});
|
|
457
|
-
_defineProperty(this, "calcLeftPercent", ({
|
|
458
|
-
clientX,
|
|
459
|
-
value,
|
|
460
|
-
range
|
|
461
|
-
}) => {
|
|
462
|
-
const boundingRect = this.element?.getBoundingClientRect?.();
|
|
463
|
-
let width = boundingRect ? boundingRect.right - boundingRect.left : 0;
|
|
464
310
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
311
|
+
// Add drag handlers
|
|
312
|
+
DRAG_EVENT_TYPES.forEach(element => {
|
|
313
|
+
elementRef.current?.ownerDocument.addEventListener(element, handleDrag);
|
|
314
|
+
});
|
|
315
|
+
const clientX = getClientXFromEvent(evt.nativeEvent);
|
|
316
|
+
let activeHandle;
|
|
317
|
+
if (hasTwoHandles()) {
|
|
318
|
+
if (evt.target == thumbRef.current) {
|
|
319
|
+
activeHandle = HandlePosition.LOWER;
|
|
320
|
+
} else if (evt.target == thumbRefUpper.current) {
|
|
321
|
+
activeHandle = HandlePosition.UPPER;
|
|
322
|
+
} else if (clientX) {
|
|
323
|
+
const distanceToLower = calcDistanceToHandle(HandlePosition.LOWER, clientX);
|
|
324
|
+
const distanceToUpper = calcDistanceToHandle(HandlePosition.UPPER, clientX);
|
|
325
|
+
if (distanceToLower <= distanceToUpper) {
|
|
326
|
+
activeHandle = HandlePosition.LOWER;
|
|
327
|
+
} else {
|
|
328
|
+
activeHandle = HandlePosition.UPPER;
|
|
329
|
+
}
|
|
468
330
|
}
|
|
331
|
+
}
|
|
469
332
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
333
|
+
// Force focus to the appropriate handle.
|
|
334
|
+
const focusOptions = {
|
|
335
|
+
preventScroll: true
|
|
336
|
+
};
|
|
337
|
+
if (hasTwoHandles()) {
|
|
338
|
+
if (thumbRef.current && activeHandle === HandlePosition.LOWER) {
|
|
339
|
+
thumbRef.current.focus(focusOptions);
|
|
340
|
+
} else if (thumbRefUpper.current && activeHandle === HandlePosition.UPPER) {
|
|
341
|
+
thumbRefUpper.current.focus(focusOptions);
|
|
478
342
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
343
|
+
} else if (thumbRef.current) {
|
|
344
|
+
thumbRef.current.focus(focusOptions);
|
|
345
|
+
}
|
|
346
|
+
setState({
|
|
347
|
+
activeHandle
|
|
482
348
|
});
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
discretePercent
|
|
504
|
-
};
|
|
349
|
+
|
|
350
|
+
// Perform first recalculation since we probably didn't click exactly in the
|
|
351
|
+
// middle of the thumb.
|
|
352
|
+
onDrag(evt.nativeEvent, activeHandle);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Removes "drag" and "drag stop" event handlers and calls sets the flag
|
|
357
|
+
* indicating that the `onRelease` callback should be called.
|
|
358
|
+
*/
|
|
359
|
+
const onDragStop = () => {
|
|
360
|
+
// Do nothing if component is disabled
|
|
361
|
+
if (props.disabled || props.readOnly) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// TODO: Rename parameters in `DRAG_*` loops to `type`.
|
|
366
|
+
// Remove drag stop handlers
|
|
367
|
+
DRAG_STOP_EVENT_TYPES.forEach(element => {
|
|
368
|
+
elementRef.current?.ownerDocument.removeEventListener(element, onDragStop);
|
|
505
369
|
});
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
370
|
+
|
|
371
|
+
// Remove drag handlers
|
|
372
|
+
DRAG_EVENT_TYPES.forEach(element => {
|
|
373
|
+
elementRef.current?.ownerDocument.removeEventListener(element, handleDrag);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Set needsOnRelease flag so event fires on next update.
|
|
377
|
+
setState({
|
|
378
|
+
needsOnRelease: true,
|
|
379
|
+
isValid: true,
|
|
380
|
+
isValidUpper: true
|
|
381
|
+
});
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// TODO: Rename this reference.
|
|
385
|
+
/**
|
|
386
|
+
* Handles a "drag" event by recalculating the value/thumb and setting state
|
|
387
|
+
* accordingly.
|
|
388
|
+
*
|
|
389
|
+
* @param evt The event.
|
|
390
|
+
* @param activeHandle The first drag event call, we may have an explicit
|
|
391
|
+
* activeHandle value, which is to be used before state is used.
|
|
392
|
+
*/
|
|
393
|
+
const _onDragRef = useRef(null);
|
|
394
|
+
_onDragRef.current = (evt, activeHandle) => {
|
|
395
|
+
activeHandle = activeHandle ?? stateRef.current.activeHandle;
|
|
396
|
+
// Do nothing if component is disabled, or we have no event.
|
|
397
|
+
if (propsRef.current.disabled || propsRef.current.readOnly || !evt) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const clientX = getClientXFromEvent(evt);
|
|
401
|
+
const {
|
|
512
402
|
value,
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
403
|
+
left
|
|
404
|
+
} = calcValue({
|
|
405
|
+
clientX,
|
|
406
|
+
value: stateRef.current.value
|
|
407
|
+
});
|
|
408
|
+
// If we're set to two handles, negotiate which drag handle is closest to
|
|
409
|
+
// the users' interaction.
|
|
410
|
+
if (hasTwoHandles() && activeHandle) {
|
|
411
|
+
setValueLeftForHandle(activeHandle, {
|
|
412
|
+
value: nearestStepValue(value),
|
|
413
|
+
left
|
|
520
414
|
});
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
415
|
+
} else {
|
|
416
|
+
setState({
|
|
417
|
+
value: nearestStepValue(value),
|
|
418
|
+
left,
|
|
419
|
+
isValid: true
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
// TODO: Investigate if it would be better to not call `setState`
|
|
423
|
+
// back-to-back here and in other places.
|
|
424
|
+
setState({
|
|
425
|
+
correctedValue: null,
|
|
426
|
+
correctedPosition: null
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Throttles calls to `_onDrag` by limiting events to being processed at
|
|
432
|
+
* most once every `EVENT_THROTTLE` milliseconds.
|
|
433
|
+
*/
|
|
434
|
+
const onDrag = useMemo(() => throttle((evt, activeHandle) => {
|
|
435
|
+
_onDragRef.current?.(evt, activeHandle);
|
|
436
|
+
}, EVENT_THROTTLE, {
|
|
437
|
+
leading: true,
|
|
438
|
+
trailing: false
|
|
439
|
+
}), []);
|
|
529
440
|
|
|
530
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Handles a `keydown` event by recalculating the value/thumb and setting
|
|
443
|
+
* state accordingly.
|
|
444
|
+
*/
|
|
445
|
+
const onKeyDown = evt => {
|
|
446
|
+
// Do nothing if component is disabled, or we don't have a valid event
|
|
447
|
+
if (props.disabled || props.readOnly) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const {
|
|
451
|
+
step = 1,
|
|
452
|
+
stepMultiplier = 4
|
|
453
|
+
} = props;
|
|
454
|
+
let delta = 0;
|
|
455
|
+
if (matches(evt, [ArrowDown, ArrowLeft])) {
|
|
456
|
+
delta = -step;
|
|
457
|
+
} else if (matches(evt, [ArrowUp, ArrowRight])) {
|
|
458
|
+
delta = step;
|
|
459
|
+
} else {
|
|
460
|
+
// Ignore keys we don't want to handle
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// If shift was held, account for the stepMultiplier
|
|
465
|
+
if (evt.shiftKey) {
|
|
466
|
+
delta *= stepMultiplier;
|
|
467
|
+
}
|
|
468
|
+
if (hasTwoHandles() && state.activeHandle) {
|
|
469
|
+
const currentValue = state.activeHandle === HandlePosition.LOWER ? state.value : state.valueUpper;
|
|
531
470
|
const {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
} =
|
|
535
|
-
|
|
471
|
+
value,
|
|
472
|
+
left
|
|
473
|
+
} = calcValue({
|
|
474
|
+
value: calcValueForDelta(currentValue ?? props.min, delta, props.step)
|
|
536
475
|
});
|
|
537
|
-
|
|
538
|
-
value:
|
|
539
|
-
left
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
_defineProperty(this, "calcDistanceToHandle", (handle, clientX) => {
|
|
543
|
-
const handleBoundingRect = this.getHandleBoundingRect(handle);
|
|
544
|
-
// x co-ordinate of the midpoint.
|
|
545
|
-
const handleX = handleBoundingRect.left + handleBoundingRect.width / 2;
|
|
546
|
-
return Math.abs(handleX - clientX);
|
|
547
|
-
});
|
|
548
|
-
/**
|
|
549
|
-
* Calculates a new slider value based on the current value, a change delta,
|
|
550
|
-
* and a step.
|
|
551
|
-
*
|
|
552
|
-
* @param currentValue - The starting value from which the slider is moving.
|
|
553
|
-
* @param delta - The amount to adjust the current value by.
|
|
554
|
-
* @param step - The step. Defaults to `1`.
|
|
555
|
-
* @returns The new slider value, rounded to the same number of decimal places
|
|
556
|
-
* as the step.
|
|
557
|
-
*/
|
|
558
|
-
_defineProperty(this, "calcValueForDelta", (currentValue, delta, step = 1) => {
|
|
559
|
-
const base = delta > 0 ? Math.floor(currentValue / step) * step : currentValue;
|
|
560
|
-
const newValue = base + delta;
|
|
561
|
-
const decimals = (step.toString().split('.')[1] || '').length;
|
|
562
|
-
return Number(newValue.toFixed(decimals));
|
|
563
|
-
});
|
|
564
|
-
/**
|
|
565
|
-
* Sets state relevant to the given handle position.
|
|
566
|
-
*
|
|
567
|
-
* Guards against setting either lower or upper values beyond its counterpart.
|
|
568
|
-
*/
|
|
569
|
-
_defineProperty(this, "setValueLeftForHandle", (handle, {
|
|
570
|
-
value: newValue,
|
|
571
|
-
left: newLeft
|
|
572
|
-
}) => {
|
|
476
|
+
setValueLeftForHandle(state.activeHandle, {
|
|
477
|
+
value: nearestStepValue(value),
|
|
478
|
+
left
|
|
479
|
+
});
|
|
480
|
+
} else {
|
|
573
481
|
const {
|
|
574
482
|
value,
|
|
575
|
-
|
|
483
|
+
left
|
|
484
|
+
} = calcValue({
|
|
485
|
+
// Ensures custom value from `<input>` won't cause skipping next stepping
|
|
486
|
+
// point with right arrow key, e.g. Typing 51 in `<input>`, moving focus
|
|
487
|
+
// onto the thumb and the hitting right arrow key should yield 52 instead
|
|
488
|
+
// of 54.
|
|
489
|
+
value: calcValueForDelta(state.value, delta, props.step)
|
|
490
|
+
});
|
|
491
|
+
setState({
|
|
492
|
+
value: nearestStepValue(value),
|
|
576
493
|
left,
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
494
|
+
isValid: true
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
setState({
|
|
498
|
+
correctedValue: null,
|
|
499
|
+
correctedPosition: null
|
|
500
|
+
});
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Provides the two-way binding for the input field of the Slider. It also
|
|
505
|
+
* Handles a change to the input field by recalculating the value/thumb and
|
|
506
|
+
* setting state accordingly.
|
|
507
|
+
*/
|
|
508
|
+
const onChangeInput = evt => {
|
|
509
|
+
// Do nothing if component is disabled
|
|
510
|
+
if (props.disabled || props.readOnly) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Do nothing if we have no valid event, target, or value
|
|
515
|
+
if (!evt || !('target' in evt) || typeof evt.target.value !== 'string') {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Avoid calling calcValue for invalid numbers, but still update the state.
|
|
520
|
+
const activeHandle = evt.target.dataset.handlePosition ?? HandlePosition.LOWER;
|
|
521
|
+
const targetValue = Number.parseFloat(evt.target.value);
|
|
522
|
+
if (hasTwoHandles()) {
|
|
523
|
+
if (isNaN(targetValue)) {
|
|
524
|
+
setValueForHandle(activeHandle, evt.target.value);
|
|
525
|
+
} else if (isValidValueForPosition({
|
|
526
|
+
handle: activeHandle,
|
|
527
|
+
value: targetValue,
|
|
528
|
+
min: props.min,
|
|
529
|
+
max: props.max
|
|
530
|
+
})) {
|
|
531
|
+
processNewInputValue(evt.target);
|
|
532
|
+
} else {
|
|
533
|
+
setValueForHandle(activeHandle, targetValue);
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
if (isNaN(targetValue)) {
|
|
537
|
+
// TODO: Address this error
|
|
538
|
+
//
|
|
539
|
+
// @ts-expect-error - Passing a string to something that expects a
|
|
540
|
+
// number.
|
|
541
|
+
setState({
|
|
542
|
+
value: evt.target.value
|
|
585
543
|
});
|
|
544
|
+
} else if (isValidValue({
|
|
545
|
+
value: targetValue,
|
|
546
|
+
min: props.min,
|
|
547
|
+
max: props.max
|
|
548
|
+
})) {
|
|
549
|
+
processNewInputValue(evt.target);
|
|
586
550
|
} else {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
leftUpper: value && newValue < value ? left : newLeft,
|
|
590
|
-
isValidUpper: true
|
|
551
|
+
setState({
|
|
552
|
+
value: targetValue
|
|
591
553
|
});
|
|
592
554
|
}
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Checks for validity of input value after clicking out of the input. It also
|
|
560
|
+
* Handles state change to isValid state.
|
|
561
|
+
*/
|
|
562
|
+
const onBlurInput = evt => {
|
|
563
|
+
// Do nothing if we have no valid event, target, or value
|
|
564
|
+
if (!evt || !('target' in evt) || typeof evt.target.value !== 'string') {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const {
|
|
568
|
+
value: targetValue
|
|
569
|
+
} = evt.target;
|
|
570
|
+
processNewInputValue(evt.target);
|
|
571
|
+
props.onBlur?.({
|
|
572
|
+
value: targetValue,
|
|
573
|
+
handlePosition: evt.target.dataset.handlePosition
|
|
593
574
|
});
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
575
|
+
};
|
|
576
|
+
const onInputKeyDown = evt => {
|
|
577
|
+
// Do nothing if component is disabled, or we don't have a valid event.
|
|
578
|
+
if (props.disabled || props.readOnly || !(evt.target instanceof HTMLInputElement)) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Do nothing if we have no valid event, target, or value.
|
|
583
|
+
if (!evt || !('target' in evt) || typeof evt.target.value !== 'string') {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (matches(evt, [Enter])) {
|
|
587
|
+
processNewInputValue(evt.target);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
const processNewInputValue = input => {
|
|
591
|
+
setState({
|
|
592
|
+
correctedValue: null,
|
|
593
|
+
correctedPosition: null
|
|
594
|
+
});
|
|
595
|
+
const targetValue = Number.parseFloat(input.value);
|
|
596
|
+
const validity = !isNaN(targetValue);
|
|
597
|
+
|
|
598
|
+
// When there are two handles, we'll also have the data-handle-position
|
|
599
|
+
// attribute to consider the other value before settling on the validity to
|
|
600
|
+
// set.
|
|
601
|
+
const handlePosition = input.dataset.handlePosition;
|
|
602
|
+
if (handlePosition === HandlePosition.LOWER) {
|
|
603
|
+
setState({
|
|
604
|
+
isValid: validity
|
|
605
|
+
});
|
|
606
|
+
} else if (handlePosition === HandlePosition.UPPER) {
|
|
607
|
+
setState({
|
|
608
|
+
isValidUpper: validity
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
setState({
|
|
612
|
+
isValid: validity
|
|
613
|
+
});
|
|
614
|
+
if (validity) {
|
|
615
|
+
const adjustedValue = handlePosition ? getAdjustedValueForPosition({
|
|
616
|
+
handle: handlePosition,
|
|
617
|
+
value: targetValue,
|
|
618
|
+
min: props.min,
|
|
619
|
+
max: props.max
|
|
620
|
+
}) : getAdjustedValue({
|
|
621
|
+
value: targetValue,
|
|
622
|
+
min: props.min,
|
|
623
|
+
max: props.max
|
|
624
|
+
});
|
|
625
|
+
if (adjustedValue !== targetValue) {
|
|
626
|
+
setState({
|
|
627
|
+
correctedValue: targetValue.toString(),
|
|
628
|
+
correctedPosition: handlePosition ?? null
|
|
599
629
|
});
|
|
600
630
|
} else {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
631
|
+
setState({
|
|
632
|
+
correctedValue: null,
|
|
633
|
+
correctedPosition: null
|
|
604
634
|
});
|
|
605
635
|
}
|
|
606
|
-
});
|
|
607
|
-
_defineProperty(this, "isValidValueForPosition", ({
|
|
608
|
-
handle,
|
|
609
|
-
value: newValue,
|
|
610
|
-
min,
|
|
611
|
-
max
|
|
612
|
-
}) => {
|
|
613
636
|
const {
|
|
614
637
|
value,
|
|
615
|
-
|
|
616
|
-
} =
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
638
|
+
left
|
|
639
|
+
} = calcValue({
|
|
640
|
+
value: adjustedValue,
|
|
641
|
+
useRawValue: true
|
|
642
|
+
});
|
|
643
|
+
if (handlePosition) {
|
|
644
|
+
setValueLeftForHandle(handlePosition, {
|
|
645
|
+
value: nearestStepValue(value),
|
|
646
|
+
left
|
|
647
|
+
});
|
|
648
|
+
} else {
|
|
649
|
+
setState({
|
|
650
|
+
value,
|
|
651
|
+
left
|
|
652
|
+
});
|
|
628
653
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
const calcLeftPercent = ({
|
|
657
|
+
clientX,
|
|
658
|
+
value,
|
|
659
|
+
range
|
|
660
|
+
}) => {
|
|
661
|
+
// TODO: Delete the optional chaining operator after `getBoundingClientRect`.
|
|
662
|
+
const boundingRect = elementRef.current?.getBoundingClientRect?.();
|
|
663
|
+
let width = boundingRect ? boundingRect.right - boundingRect.left : 0;
|
|
664
|
+
|
|
665
|
+
// Enforce a minimum width of at least 1 for calculations
|
|
666
|
+
if (width <= 0) {
|
|
667
|
+
width = 1;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// If a clientX is specified, use it to calculate the leftPercent. If not,
|
|
671
|
+
// use the provided value to calculate it instead.
|
|
672
|
+
if (clientX) {
|
|
673
|
+
const leftOffset = state.isRtl ? (boundingRect?.right ?? 0) - clientX : clientX - (boundingRect?.left ?? 0);
|
|
674
|
+
return leftOffset / width;
|
|
675
|
+
} else if (value !== null && typeof value !== 'undefined' && range) {
|
|
676
|
+
// Prevent NaN calculation if the range is 0.
|
|
677
|
+
return range === 0 ? 0 : (value - props.min) / range;
|
|
678
|
+
}
|
|
679
|
+
// We should never end up in this scenario, but in case we do, and to
|
|
680
|
+
// re-assure Typescript, return 0.
|
|
681
|
+
return 0;
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Calculates the discrete value (snapped to the nearest step) along
|
|
686
|
+
* with the corresponding handle position percentage.
|
|
687
|
+
*/
|
|
688
|
+
const calcDiscreteValueAndPercent = ({
|
|
689
|
+
leftPercent
|
|
690
|
+
}) => {
|
|
691
|
+
const {
|
|
692
|
+
step = 1,
|
|
641
693
|
min,
|
|
642
694
|
max
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
695
|
+
} = props;
|
|
696
|
+
const numSteps = Math.floor((max - min) / step) + ((max - min) % step === 0 ? 1 : 2);
|
|
697
|
+
/** Index of the step that corresponds to `leftPercent`. */
|
|
698
|
+
const stepIndex = Math.round(leftPercent * (numSteps - 1));
|
|
699
|
+
const discreteValue = stepIndex === numSteps - 1 ? max : min + step * stepIndex;
|
|
700
|
+
/** Percentage corresponding to the step index. */
|
|
701
|
+
const discretePercent = stepIndex / (numSteps - 1);
|
|
702
|
+
return {
|
|
703
|
+
discreteValue,
|
|
704
|
+
discretePercent
|
|
705
|
+
};
|
|
706
|
+
};
|
|
653
707
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
708
|
+
/**
|
|
709
|
+
* Calculates the slider's value and handle position based on either a
|
|
710
|
+
* mouse/touch event or an explicit value.
|
|
711
|
+
*/
|
|
712
|
+
const calcValue = ({
|
|
713
|
+
clientX,
|
|
714
|
+
value,
|
|
715
|
+
useRawValue
|
|
716
|
+
}) => {
|
|
717
|
+
const range = props.max - props.min;
|
|
718
|
+
const leftPercentRaw = calcLeftPercent({
|
|
719
|
+
clientX,
|
|
663
720
|
value,
|
|
664
|
-
|
|
665
|
-
max
|
|
666
|
-
}) => {
|
|
667
|
-
if (value < min) {
|
|
668
|
-
value = min;
|
|
669
|
-
}
|
|
670
|
-
if (value > max) {
|
|
671
|
-
value = max;
|
|
672
|
-
}
|
|
673
|
-
return value;
|
|
721
|
+
range
|
|
674
722
|
});
|
|
675
|
-
/**
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
723
|
+
/** `leftPercentRaw` clamped between 0 and 1. */
|
|
724
|
+
const leftPercent = clamp(leftPercentRaw, 0, 1);
|
|
725
|
+
if (useRawValue) {
|
|
726
|
+
return {
|
|
727
|
+
value,
|
|
728
|
+
left: leftPercent * 100
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Use the discrete value and percentage for snapping.
|
|
733
|
+
const {
|
|
734
|
+
discreteValue,
|
|
735
|
+
discretePercent
|
|
736
|
+
} = calcDiscreteValueAndPercent({
|
|
737
|
+
leftPercent
|
|
688
738
|
});
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
739
|
+
return {
|
|
740
|
+
value: discreteValue,
|
|
741
|
+
left: discretePercent * 100
|
|
742
|
+
};
|
|
743
|
+
};
|
|
744
|
+
const calcDistanceToHandle = (handle, clientX) => {
|
|
745
|
+
const handleBoundingRect = getHandleBoundingRect(handle);
|
|
746
|
+
/** x-coordinate of the midpoint. */
|
|
747
|
+
const handleX = handleBoundingRect.left + handleBoundingRect.width / 2;
|
|
748
|
+
return Math.abs(handleX - clientX);
|
|
749
|
+
};
|
|
693
750
|
|
|
694
751
|
/**
|
|
695
|
-
*
|
|
752
|
+
* Calculates a new slider value based on the current value, a change delta,
|
|
753
|
+
* and a step.
|
|
754
|
+
*
|
|
755
|
+
* @param currentValue - The starting value from which the slider is moving.
|
|
756
|
+
* @param delta - The amount to adjust the current value by.
|
|
757
|
+
* @param step - The step. Defaults to `1`.
|
|
758
|
+
* @returns The new slider value, rounded to the same number of decimal places
|
|
759
|
+
* as the step.
|
|
696
760
|
*/
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
} = this.calcValue({
|
|
705
|
-
value: this.state.value,
|
|
706
|
-
useRawValue: true
|
|
707
|
-
});
|
|
708
|
-
const {
|
|
709
|
-
value: valueUpper,
|
|
710
|
-
left: leftUpper
|
|
711
|
-
} = this.calcValue({
|
|
712
|
-
value: this.state.valueUpper,
|
|
713
|
-
useRawValue: true
|
|
714
|
-
});
|
|
715
|
-
this.setState({
|
|
716
|
-
isRtl,
|
|
717
|
-
value,
|
|
718
|
-
left,
|
|
719
|
-
valueUpper,
|
|
720
|
-
leftUpper
|
|
721
|
-
});
|
|
722
|
-
if (this.filledTrackRef.current) {
|
|
723
|
-
this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(${100 - this.state.leftUpper}%, -50%) scaleX(${(this.state.leftUpper - this.state.left) / 100})` : `translate(${this.state.left}%, -50%) scaleX(${(this.state.leftUpper - this.state.left) / 100})`;
|
|
724
|
-
}
|
|
725
|
-
} else {
|
|
726
|
-
const {
|
|
727
|
-
value,
|
|
728
|
-
left
|
|
729
|
-
} = this.calcValue({
|
|
730
|
-
value: this.state.value,
|
|
731
|
-
useRawValue: true
|
|
732
|
-
});
|
|
733
|
-
this.setState({
|
|
734
|
-
isRtl,
|
|
735
|
-
value,
|
|
736
|
-
left
|
|
737
|
-
});
|
|
738
|
-
if (this.filledTrackRef.current) {
|
|
739
|
-
this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(100%, -50%) scaleX(-${this.state.left / 100})` : `translate(0%, -50%) scaleX(${this.state.left / 100})`;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
761
|
+
const calcValueForDelta = (currentValue, delta, step = 1) => {
|
|
762
|
+
const base = delta > 0 ? Math.floor(currentValue / step) * step : currentValue;
|
|
763
|
+
const newValue = base + delta;
|
|
764
|
+
// TODO: Why is the logical OR needed here?
|
|
765
|
+
const decimals = (step.toString().split('.')[1] || '').length;
|
|
766
|
+
return Number(newValue.toFixed(decimals));
|
|
767
|
+
};
|
|
744
768
|
|
|
745
769
|
/**
|
|
746
|
-
*
|
|
747
|
-
* response to state changes.
|
|
770
|
+
* Sets state relevant to the given handle position.
|
|
748
771
|
*
|
|
749
|
-
*
|
|
750
|
-
* @param {*} prevState The previous Slider state, used to see if callbacks
|
|
751
|
-
* should be called.
|
|
772
|
+
* Guards against setting either lower or upper values beyond its counterpart.
|
|
752
773
|
*/
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
774
|
+
const setValueLeftForHandle = (handle, {
|
|
775
|
+
value: newValue,
|
|
776
|
+
left: newLeft
|
|
777
|
+
}) => {
|
|
778
|
+
const {
|
|
779
|
+
value,
|
|
780
|
+
valueUpper,
|
|
781
|
+
left,
|
|
782
|
+
leftUpper
|
|
783
|
+
} = state;
|
|
784
|
+
if (handle === HandlePosition.LOWER) {
|
|
785
|
+
// Don't allow higher than the upper handle.
|
|
786
|
+
setState({
|
|
787
|
+
value: valueUpper && newValue > valueUpper ? valueUpper : newValue,
|
|
788
|
+
left: valueUpper && newValue > valueUpper ? leftUpper : newLeft,
|
|
789
|
+
isValid: true
|
|
790
|
+
});
|
|
760
791
|
} else {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if ((prevState.value !== this.state.value || prevState.valueUpper !== this.state.valueUpper) && typeof this.props.onChange === 'function') {
|
|
766
|
-
this.props.onChange({
|
|
767
|
-
value: this.state.value,
|
|
768
|
-
valueUpper: this.state.valueUpper
|
|
792
|
+
setState({
|
|
793
|
+
valueUpper: value && newValue < value ? value : newValue,
|
|
794
|
+
leftUpper: value && newValue < value ? left : newLeft,
|
|
795
|
+
isValidUpper: true
|
|
769
796
|
});
|
|
770
797
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
798
|
+
};
|
|
799
|
+
const setValueForHandle = (handle, value) => {
|
|
800
|
+
if (handle === HandlePosition.LOWER) {
|
|
801
|
+
setState({
|
|
802
|
+
// TODO: Address this error
|
|
803
|
+
//
|
|
804
|
+
// @ts-expect-error - Passing a string to something that expects a
|
|
805
|
+
// number.
|
|
806
|
+
value,
|
|
807
|
+
isValid: true
|
|
777
808
|
});
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
809
|
+
} else {
|
|
810
|
+
setState({
|
|
811
|
+
// TODO: Address this error
|
|
812
|
+
//
|
|
813
|
+
// @ts-expect-error - Passing a string to something that expects a
|
|
814
|
+
// number.
|
|
815
|
+
valueUpper: value,
|
|
816
|
+
isValidUpper: true
|
|
781
817
|
});
|
|
782
818
|
}
|
|
819
|
+
};
|
|
820
|
+
const isValidValueForPosition = ({
|
|
821
|
+
handle,
|
|
822
|
+
value: newValue,
|
|
823
|
+
min,
|
|
824
|
+
max
|
|
825
|
+
}) => {
|
|
826
|
+
const {
|
|
827
|
+
value,
|
|
828
|
+
valueUpper
|
|
829
|
+
} = state;
|
|
830
|
+
if (!isValidValue({
|
|
831
|
+
value: newValue,
|
|
832
|
+
min,
|
|
833
|
+
max
|
|
834
|
+
})) {
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
if (handle === HandlePosition.LOWER) {
|
|
838
|
+
return !valueUpper || newValue <= valueUpper;
|
|
839
|
+
} else if (handle === HandlePosition.UPPER) {
|
|
840
|
+
return !value || newValue >= value;
|
|
841
|
+
}
|
|
842
|
+
return false;
|
|
843
|
+
};
|
|
844
|
+
const isValidValue = ({
|
|
845
|
+
value,
|
|
846
|
+
min,
|
|
847
|
+
max
|
|
848
|
+
}) => {
|
|
849
|
+
return !(value < min || value > max);
|
|
850
|
+
};
|
|
851
|
+
const getAdjustedValueForPosition = ({
|
|
852
|
+
handle,
|
|
853
|
+
value: newValueInput,
|
|
854
|
+
min,
|
|
855
|
+
max
|
|
856
|
+
}) => {
|
|
857
|
+
const {
|
|
858
|
+
value,
|
|
859
|
+
valueUpper
|
|
860
|
+
} = state;
|
|
861
|
+
let newValue = getAdjustedValue({
|
|
862
|
+
value: newValueInput,
|
|
863
|
+
min,
|
|
864
|
+
max
|
|
865
|
+
});
|
|
783
866
|
|
|
784
|
-
//
|
|
785
|
-
//
|
|
786
|
-
if (
|
|
787
|
-
|
|
867
|
+
// TODO: Just return the value.
|
|
868
|
+
// Next adjust to the opposite handle.
|
|
869
|
+
if (handle === HandlePosition.LOWER && valueUpper) {
|
|
870
|
+
newValue = newValue > valueUpper ? valueUpper : newValue;
|
|
871
|
+
} else if (handle === HandlePosition.UPPER && value) {
|
|
872
|
+
newValue = newValue < value ? value : newValue;
|
|
788
873
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
useRawValue: true
|
|
800
|
-
});
|
|
801
|
-
this.setState({
|
|
802
|
-
valueUpper,
|
|
803
|
-
leftUpper
|
|
804
|
-
});
|
|
805
|
-
} else {
|
|
806
|
-
this.setState({
|
|
807
|
-
valueUpper: undefined,
|
|
808
|
-
leftUpper: undefined
|
|
809
|
-
});
|
|
874
|
+
return newValue;
|
|
875
|
+
};
|
|
876
|
+
const getAdjustedValue = ({
|
|
877
|
+
value,
|
|
878
|
+
min,
|
|
879
|
+
max
|
|
880
|
+
}) => {
|
|
881
|
+
// TODO: Just return the value.
|
|
882
|
+
if (value < min) {
|
|
883
|
+
value = min;
|
|
810
884
|
}
|
|
811
|
-
|
|
885
|
+
if (value > max) {
|
|
886
|
+
value = max;
|
|
887
|
+
}
|
|
888
|
+
return value;
|
|
889
|
+
};
|
|
812
890
|
|
|
813
891
|
/**
|
|
814
|
-
*
|
|
815
|
-
* prop.
|
|
892
|
+
* Get the bounding rect for the requested handles' DOM element.
|
|
816
893
|
*
|
|
817
|
-
*
|
|
818
|
-
* @returns The value rounded to the precision determined by the step.
|
|
894
|
+
* If the bounding rect is not available, a new, empty DOMRect is returned.
|
|
819
895
|
*/
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
896
|
+
const getHandleBoundingRect = handle => {
|
|
897
|
+
let boundingRect;
|
|
898
|
+
if (handle === HandlePosition.LOWER) {
|
|
899
|
+
boundingRect = thumbRef.current?.getBoundingClientRect();
|
|
900
|
+
} else {
|
|
901
|
+
boundingRect = thumbRefUpper.current?.getBoundingClientRect();
|
|
902
|
+
}
|
|
903
|
+
return boundingRect ?? new DOMRect();
|
|
904
|
+
};
|
|
905
|
+
const getClientXFromEvent = event => {
|
|
825
906
|
let clientX;
|
|
826
907
|
if ('clientX' in event) {
|
|
827
908
|
clientX = event.clientX;
|
|
@@ -829,17 +910,12 @@ class Slider extends PureComponent {
|
|
|
829
910
|
clientX = event.touches[0].clientX;
|
|
830
911
|
}
|
|
831
912
|
return clientX;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
return typeof this.state.valueUpper !== 'undefined';
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// syncs invalid state and prop
|
|
838
|
-
static getDerivedStateFromProps(props, state) {
|
|
913
|
+
};
|
|
914
|
+
useEffect(() => {
|
|
839
915
|
const {
|
|
840
916
|
isValid,
|
|
841
917
|
isValidUpper
|
|
842
|
-
} =
|
|
918
|
+
} = stateRef.current;
|
|
843
919
|
const derivedState = {};
|
|
844
920
|
|
|
845
921
|
// Will override state in favor of invalid prop
|
|
@@ -850,16 +926,20 @@ class Slider extends PureComponent {
|
|
|
850
926
|
if (isValid === false) derivedState.isValid = true;
|
|
851
927
|
if (isValidUpper === false) derivedState.isValidUpper = true;
|
|
852
928
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
929
|
+
if (Object.keys(derivedState).length) {
|
|
930
|
+
setState(derivedState);
|
|
931
|
+
}
|
|
932
|
+
}, [props.invalid]);
|
|
933
|
+
|
|
934
|
+
// TODO: Delete this IIFE. It was added to maintain whitespace and to make it clear
|
|
935
|
+
// what exactly has changed.
|
|
936
|
+
return ((_Fragment, _Fragment2, _Fragment3, _Fragment4) => {
|
|
857
937
|
const {
|
|
858
938
|
ariaLabelInput,
|
|
859
939
|
unstable_ariaLabelInputUpper: ariaLabelInputUpper,
|
|
860
940
|
className,
|
|
861
941
|
hideTextInput = false,
|
|
862
|
-
id =
|
|
942
|
+
id = inputIdRef.current = inputIdRef.current ||
|
|
863
943
|
// TODO:
|
|
864
944
|
// 1. Why isn't `inputId` just set to this value instead of an empty
|
|
865
945
|
// string?
|
|
@@ -889,8 +969,7 @@ class Slider extends PureComponent {
|
|
|
889
969
|
warnText,
|
|
890
970
|
translateWithId: t = translateWithId,
|
|
891
971
|
...other
|
|
892
|
-
} =
|
|
893
|
-
const twoHandles = this.hasTwoHandles();
|
|
972
|
+
} = props;
|
|
894
973
|
delete other.onRelease;
|
|
895
974
|
delete other.invalid;
|
|
896
975
|
delete other.unstable_valueUpper;
|
|
@@ -902,7 +981,7 @@ class Slider extends PureComponent {
|
|
|
902
981
|
correctedValue,
|
|
903
982
|
correctedPosition,
|
|
904
983
|
isRtl
|
|
905
|
-
} =
|
|
984
|
+
} = state;
|
|
906
985
|
const showWarning = !readOnly && warn ||
|
|
907
986
|
// TODO: https://github.com/carbon-design-system/carbon/issues/18991#issuecomment-2795709637
|
|
908
987
|
// eslint-disable-next-line valid-typeof , no-constant-binary-expression -- https://github.com/carbon-design-system/carbon/issues/20071
|
|
@@ -961,12 +1040,12 @@ class Slider extends PureComponent {
|
|
|
961
1040
|
}]);
|
|
962
1041
|
const lowerThumbWrapperProps = {
|
|
963
1042
|
style: {
|
|
964
|
-
insetInlineStart: `${
|
|
1043
|
+
insetInlineStart: `${state.left}%`
|
|
965
1044
|
}
|
|
966
1045
|
};
|
|
967
1046
|
const upperThumbWrapperProps = {
|
|
968
1047
|
style: {
|
|
969
|
-
insetInlineStart: `${
|
|
1048
|
+
insetInlineStart: `${state.leftUpper}%`
|
|
970
1049
|
}
|
|
971
1050
|
};
|
|
972
1051
|
return /*#__PURE__*/React.createElement("div", {
|
|
@@ -992,10 +1071,10 @@ class Slider extends PureComponent {
|
|
|
992
1071
|
min: min,
|
|
993
1072
|
max: max,
|
|
994
1073
|
step: step,
|
|
995
|
-
onChange:
|
|
996
|
-
onBlur:
|
|
997
|
-
onKeyUp:
|
|
998
|
-
onKeyDown:
|
|
1074
|
+
onChange: onChangeInput,
|
|
1075
|
+
onBlur: onBlurInput,
|
|
1076
|
+
onKeyUp: props.onInputKeyUp,
|
|
1077
|
+
onKeyDown: onInputKeyDown,
|
|
999
1078
|
"data-invalid": !isValid && !readOnly ? true : null,
|
|
1000
1079
|
"data-handle-position": HandlePosition.LOWER,
|
|
1001
1080
|
"aria-invalid": !isValid && !readOnly ? true : undefined,
|
|
@@ -1009,11 +1088,11 @@ class Slider extends PureComponent {
|
|
|
1009
1088
|
}, formatLabel(min, minLabel)), /*#__PURE__*/React.createElement("div", _extends({
|
|
1010
1089
|
className: sliderClasses,
|
|
1011
1090
|
ref: node => {
|
|
1012
|
-
|
|
1091
|
+
elementRef.current = node;
|
|
1013
1092
|
},
|
|
1014
|
-
onMouseDown:
|
|
1015
|
-
onTouchStart:
|
|
1016
|
-
onKeyDown:
|
|
1093
|
+
onMouseDown: onDragStart,
|
|
1094
|
+
onTouchStart: onDragStart,
|
|
1095
|
+
onKeyDown: onKeyDown,
|
|
1017
1096
|
role: "presentation",
|
|
1018
1097
|
tabIndex: -1,
|
|
1019
1098
|
"data-invalid": (twoHandles ? !isValid || !isValidUpper : !isValid) && !readOnly ? true : null
|
|
@@ -1033,8 +1112,8 @@ class Slider extends PureComponent {
|
|
|
1033
1112
|
"aria-valuenow": value,
|
|
1034
1113
|
"aria-labelledby": twoHandles ? undefined : labelId,
|
|
1035
1114
|
"aria-label": twoHandles ? ariaLabelInput : undefined,
|
|
1036
|
-
ref:
|
|
1037
|
-
onFocus: () =>
|
|
1115
|
+
ref: thumbRef,
|
|
1116
|
+
onFocus: () => setState({
|
|
1038
1117
|
activeHandle: HandlePosition.LOWER
|
|
1039
1118
|
})
|
|
1040
1119
|
}, twoHandles && !isRtl ? _Fragment || (_Fragment = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(LowerHandle, {
|
|
@@ -1058,8 +1137,8 @@ class Slider extends PureComponent {
|
|
|
1058
1137
|
"aria-valuemin": value,
|
|
1059
1138
|
"aria-valuenow": valueUpper,
|
|
1060
1139
|
"aria-label": ariaLabelInputUpper,
|
|
1061
|
-
ref:
|
|
1062
|
-
onFocus: () =>
|
|
1140
|
+
ref: thumbRefUpper,
|
|
1141
|
+
onFocus: () => setState({
|
|
1063
1142
|
activeHandle: HandlePosition.UPPER
|
|
1064
1143
|
})
|
|
1065
1144
|
}, twoHandles && !isRtl ? _Fragment3 || (_Fragment3 = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpperHandle, {
|
|
@@ -1073,11 +1152,11 @@ class Slider extends PureComponent {
|
|
|
1073
1152
|
}))) : undefined)) : null, /*#__PURE__*/React.createElement("div", {
|
|
1074
1153
|
className: `${prefix}--slider__track`,
|
|
1075
1154
|
ref: node => {
|
|
1076
|
-
|
|
1155
|
+
trackRef.current = node;
|
|
1077
1156
|
}
|
|
1078
1157
|
}), /*#__PURE__*/React.createElement("div", {
|
|
1079
1158
|
className: `${prefix}--slider__filled-track`,
|
|
1080
|
-
ref:
|
|
1159
|
+
ref: filledTrackRef
|
|
1081
1160
|
})), /*#__PURE__*/React.createElement(Text, {
|
|
1082
1161
|
className: `${prefix}--slider__range-label`
|
|
1083
1162
|
}, formatLabel(max, maxLabel)), /*#__PURE__*/React.createElement("div", {
|
|
@@ -1095,10 +1174,10 @@ class Slider extends PureComponent {
|
|
|
1095
1174
|
min: min,
|
|
1096
1175
|
max: max,
|
|
1097
1176
|
step: step,
|
|
1098
|
-
onChange:
|
|
1099
|
-
onBlur:
|
|
1100
|
-
onKeyDown:
|
|
1101
|
-
onKeyUp:
|
|
1177
|
+
onChange: onChangeInput,
|
|
1178
|
+
onBlur: onBlurInput,
|
|
1179
|
+
onKeyDown: onInputKeyDown,
|
|
1180
|
+
onKeyUp: props.onInputKeyUp,
|
|
1102
1181
|
"data-invalid": (twoHandles ? !isValidUpper : !isValid) && !readOnly ? true : null,
|
|
1103
1182
|
"data-handle-position": twoHandles ? HandlePosition.UPPER : null,
|
|
1104
1183
|
"aria-invalid": (twoHandles ? !isValidUpper : !isValid) && !readOnly ? true : undefined,
|
|
@@ -1121,10 +1200,8 @@ class Slider extends PureComponent {
|
|
|
1121
1200
|
correctedValue
|
|
1122
1201
|
})));
|
|
1123
1202
|
});
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
_defineProperty(Slider, "contextType", FeatureFlagContext);
|
|
1127
|
-
_defineProperty(Slider, "translationIds", Object.values(translationIds));
|
|
1203
|
+
})();
|
|
1204
|
+
};
|
|
1128
1205
|
Slider.propTypes = {
|
|
1129
1206
|
/**
|
|
1130
1207
|
* The `ariaLabel` for the `<input>`.
|
|
@@ -1265,4 +1342,4 @@ Slider.propTypes = {
|
|
|
1265
1342
|
warnText: PropTypes.node
|
|
1266
1343
|
};
|
|
1267
1344
|
|
|
1268
|
-
export { Slider
|
|
1345
|
+
export { Slider };
|