UNPKG

15.4 kBJavaScriptView Raw
1import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
2import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
3import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4import _typeof from "@babel/runtime/helpers/esm/typeof";
5import * as React from 'react';
6import classNames from 'classnames';
7import shallowEqual from 'shallowequal';
8import useMergedState from "rc-util/es/hooks/useMergedState";
9import Handles from './Handles';
10import useDrag from './hooks/useDrag';
11import SliderContext from './context';
12import Tracks from './Tracks';
13import Marks from './Marks';
14import Steps from './Steps';
15import useOffset from './hooks/useOffset';
16import warning from "rc-util/es/warning";
17var Slider = /*#__PURE__*/React.forwardRef(function (props, ref) {
18 var _classNames;
19
20 var _props$prefixCls = props.prefixCls,
21 prefixCls = _props$prefixCls === void 0 ? 'rc-slider' : _props$prefixCls,
22 className = props.className,
23 style = props.style,
24 _props$disabled = props.disabled,
25 disabled = _props$disabled === void 0 ? false : _props$disabled,
26 _props$keyboard = props.keyboard,
27 keyboard = _props$keyboard === void 0 ? true : _props$keyboard,
28 autoFocus = props.autoFocus,
29 onFocus = props.onFocus,
30 onBlur = props.onBlur,
31 _props$min = props.min,
32 min = _props$min === void 0 ? 0 : _props$min,
33 _props$max = props.max,
34 max = _props$max === void 0 ? 100 : _props$max,
35 _props$step = props.step,
36 step = _props$step === void 0 ? 1 : _props$step,
37 value = props.value,
38 defaultValue = props.defaultValue,
39 range = props.range,
40 count = props.count,
41 onChange = props.onChange,
42 onBeforeChange = props.onBeforeChange,
43 onAfterChange = props.onAfterChange,
44 _props$allowCross = props.allowCross,
45 allowCross = _props$allowCross === void 0 ? true : _props$allowCross,
46 _props$pushable = props.pushable,
47 pushable = _props$pushable === void 0 ? false : _props$pushable,
48 draggableTrack = props.draggableTrack,
49 reverse = props.reverse,
50 vertical = props.vertical,
51 _props$included = props.included,
52 included = _props$included === void 0 ? true : _props$included,
53 startPoint = props.startPoint,
54 trackStyle = props.trackStyle,
55 handleStyle = props.handleStyle,
56 railStyle = props.railStyle,
57 dotStyle = props.dotStyle,
58 activeDotStyle = props.activeDotStyle,
59 marks = props.marks,
60 dots = props.dots,
61 handleRender = props.handleRender,
62 _props$tabIndex = props.tabIndex,
63 tabIndex = _props$tabIndex === void 0 ? 0 : _props$tabIndex,
64 ariaLabelForHandle = props.ariaLabelForHandle,
65 ariaLabelledByForHandle = props.ariaLabelledByForHandle,
66 ariaValueTextFormatterForHandle = props.ariaValueTextFormatterForHandle;
67 var handlesRef = React.useRef();
68 var containerRef = React.useRef();
69 var direction = React.useMemo(function () {
70 if (vertical) {
71 return reverse ? 'ttb' : 'btt';
72 }
73
74 return reverse ? 'rtl' : 'ltr';
75 }, [reverse, vertical]); // ============================ Range =============================
76
77 var mergedMin = React.useMemo(function () {
78 return isFinite(min) ? min : 0;
79 }, [min]);
80 var mergedMax = React.useMemo(function () {
81 return isFinite(max) ? max : 100;
82 }, [max]); // ============================= Step =============================
83
84 var mergedStep = React.useMemo(function () {
85 return step !== null && step <= 0 ? 1 : step;
86 }, [step]); // ============================= Push =============================
87
88 var mergedPush = React.useMemo(function () {
89 if (pushable === true) {
90 return mergedStep;
91 }
92
93 return pushable >= 0 ? pushable : false;
94 }, [pushable, mergedStep]); // ============================ Marks =============================
95
96 var markList = React.useMemo(function () {
97 var keys = Object.keys(marks || {});
98 return keys.map(function (key) {
99 var mark = marks[key];
100 var markObj = {
101 value: Number(key)
102 };
103
104 if (mark && _typeof(mark) === 'object' && ! /*#__PURE__*/React.isValidElement(mark) && ('label' in mark || 'style' in mark)) {
105 markObj.style = mark.style;
106 markObj.label = mark.label;
107 } else {
108 markObj.label = mark;
109 }
110
111 return markObj;
112 }).filter(function (_ref) {
113 var label = _ref.label;
114 return label || typeof label === 'number';
115 }).sort(function (a, b) {
116 return a.value - b.value;
117 });
118 }, [marks]); // ============================ Format ============================
119
120 var _useOffset = useOffset(mergedMin, mergedMax, mergedStep, markList, allowCross, mergedPush),
121 _useOffset2 = _slicedToArray(_useOffset, 2),
122 formatValue = _useOffset2[0],
123 offsetValues = _useOffset2[1]; // ============================ Values ============================
124
125
126 var _useMergedState = useMergedState(defaultValue, {
127 value: value
128 }),
129 _useMergedState2 = _slicedToArray(_useMergedState, 2),
130 mergedValue = _useMergedState2[0],
131 setValue = _useMergedState2[1];
132
133 var rawValues = React.useMemo(function () {
134 var valueList = mergedValue === null || mergedValue === undefined ? [] : Array.isArray(mergedValue) ? mergedValue : [mergedValue];
135
136 var _valueList = _slicedToArray(valueList, 1),
137 _valueList$ = _valueList[0],
138 val0 = _valueList$ === void 0 ? mergedMin : _valueList$;
139
140 var returnValues = mergedValue === null ? [] : [val0]; // Format as range
141
142 if (range) {
143 returnValues = _toConsumableArray(valueList); // When count provided or value is `undefined`, we fill values
144
145 if (count || mergedValue === undefined) {
146 var pointCount = count >= 0 ? count + 1 : 2;
147 returnValues = returnValues.slice(0, pointCount); // Fill with count
148
149 while (returnValues.length < pointCount) {
150 var _returnValues;
151
152 returnValues.push((_returnValues = returnValues[returnValues.length - 1]) !== null && _returnValues !== void 0 ? _returnValues : mergedMin);
153 }
154 }
155
156 returnValues.sort(function (a, b) {
157 return a - b;
158 });
159 } // Align in range
160
161
162 returnValues.forEach(function (val, index) {
163 returnValues[index] = formatValue(val);
164 });
165 return returnValues;
166 }, [mergedValue, range, mergedMin, count, formatValue]); // =========================== onChange ===========================
167
168 var rawValuesRef = React.useRef(rawValues);
169 rawValuesRef.current = rawValues;
170
171 var getTriggerValue = function getTriggerValue(triggerValues) {
172 return range ? triggerValues : triggerValues[0];
173 };
174
175 var triggerChange = function triggerChange(nextValues) {
176 // Order first
177 var cloneNextValues = _toConsumableArray(nextValues).sort(function (a, b) {
178 return a - b;
179 }); // Trigger event if needed
180
181
182 if (onChange && !shallowEqual(cloneNextValues, rawValuesRef.current)) {
183 onChange(getTriggerValue(cloneNextValues));
184 } // We set this later since it will re-render component immediately
185
186
187 setValue(cloneNextValues);
188 };
189
190 var changeToCloseValue = function changeToCloseValue(newValue) {
191 if (!disabled) {
192 var valueIndex = 0;
193 var valueDist = mergedMax - mergedMin;
194 rawValues.forEach(function (val, index) {
195 var dist = Math.abs(newValue - val);
196
197 if (dist <= valueDist) {
198 valueDist = dist;
199 valueIndex = index;
200 }
201 }); // Create new values
202
203 var cloneNextValues = _toConsumableArray(rawValues);
204
205 cloneNextValues[valueIndex] = newValue; // Fill value to match default 2
206
207 if (range && !rawValues.length && count === undefined) {
208 cloneNextValues.push(newValue);
209 }
210
211 onBeforeChange === null || onBeforeChange === void 0 ? void 0 : onBeforeChange(getTriggerValue(cloneNextValues));
212 triggerChange(cloneNextValues);
213 onAfterChange === null || onAfterChange === void 0 ? void 0 : onAfterChange(getTriggerValue(cloneNextValues));
214 }
215 }; // ============================ Click =============================
216
217
218 var onSliderMouseDown = function onSliderMouseDown(e) {
219 e.preventDefault();
220
221 var _containerRef$current = containerRef.current.getBoundingClientRect(),
222 width = _containerRef$current.width,
223 height = _containerRef$current.height,
224 left = _containerRef$current.left,
225 top = _containerRef$current.top,
226 bottom = _containerRef$current.bottom,
227 right = _containerRef$current.right;
228
229 var clientX = e.clientX,
230 clientY = e.clientY;
231 var percent;
232
233 switch (direction) {
234 case 'btt':
235 percent = (bottom - clientY) / height;
236 break;
237
238 case 'ttb':
239 percent = (clientY - top) / height;
240 break;
241
242 case 'rtl':
243 percent = (right - clientX) / width;
244 break;
245
246 default:
247 percent = (clientX - left) / width;
248 }
249
250 var nextValue = mergedMin + percent * (mergedMax - mergedMin);
251 changeToCloseValue(formatValue(nextValue));
252 }; // =========================== Keyboard ===========================
253
254
255 var _React$useState = React.useState(null),
256 _React$useState2 = _slicedToArray(_React$useState, 2),
257 keyboardValue = _React$useState2[0],
258 setKeyboardValue = _React$useState2[1];
259
260 var onHandleOffsetChange = function onHandleOffsetChange(offset, valueIndex) {
261 if (!disabled) {
262 var next = offsetValues(rawValues, offset, valueIndex);
263 onBeforeChange === null || onBeforeChange === void 0 ? void 0 : onBeforeChange(getTriggerValue(rawValues));
264 triggerChange(next.values);
265 onAfterChange === null || onAfterChange === void 0 ? void 0 : onAfterChange(getTriggerValue(next.values));
266 setKeyboardValue(next.value);
267 }
268 };
269
270 React.useEffect(function () {
271 if (keyboardValue !== null) {
272 var valueIndex = rawValues.indexOf(keyboardValue);
273
274 if (valueIndex >= 0) {
275 handlesRef.current.focus(valueIndex);
276 }
277 }
278
279 setKeyboardValue(null);
280 }, [keyboardValue]); // ============================= Drag =============================
281
282 var mergedDraggableTrack = React.useMemo(function () {
283 if (draggableTrack && mergedStep === null) {
284 if (process.env.NODE_ENV !== 'production') {
285 warning(false, '`draggableTrack` is not supported when `step` is `null`.');
286 }
287
288 return false;
289 }
290
291 return draggableTrack;
292 }, [draggableTrack, mergedStep]);
293
294 var finishChange = function finishChange() {
295 onAfterChange === null || onAfterChange === void 0 ? void 0 : onAfterChange(getTriggerValue(rawValuesRef.current));
296 };
297
298 var _useDrag = useDrag(containerRef, direction, rawValues, mergedMin, mergedMax, formatValue, triggerChange, finishChange, offsetValues),
299 _useDrag2 = _slicedToArray(_useDrag, 4),
300 draggingIndex = _useDrag2[0],
301 draggingValue = _useDrag2[1],
302 cacheValues = _useDrag2[2],
303 onStartDrag = _useDrag2[3];
304
305 var onStartMove = function onStartMove(e, valueIndex) {
306 onStartDrag(e, valueIndex);
307 onBeforeChange === null || onBeforeChange === void 0 ? void 0 : onBeforeChange(getTriggerValue(rawValuesRef.current));
308 }; // Auto focus for updated handle
309
310
311 var dragging = draggingIndex !== -1;
312 React.useEffect(function () {
313 if (!dragging) {
314 var valueIndex = rawValues.lastIndexOf(draggingValue);
315 handlesRef.current.focus(valueIndex);
316 }
317 }, [dragging]); // =========================== Included ===========================
318
319 var sortedCacheValues = React.useMemo(function () {
320 return _toConsumableArray(cacheValues).sort(function (a, b) {
321 return a - b;
322 });
323 }, [cacheValues]); // Provide a range values with included [min, max]
324 // Used for Track, Mark & Dot
325
326 var _React$useMemo = React.useMemo(function () {
327 if (!range) {
328 return [mergedMin, sortedCacheValues[0]];
329 }
330
331 return [sortedCacheValues[0], sortedCacheValues[sortedCacheValues.length - 1]];
332 }, [sortedCacheValues, range, mergedMin]),
333 _React$useMemo2 = _slicedToArray(_React$useMemo, 2),
334 includedStart = _React$useMemo2[0],
335 includedEnd = _React$useMemo2[1]; // ============================= Refs =============================
336
337
338 React.useImperativeHandle(ref, function () {
339 return {
340 focus: function focus() {
341 handlesRef.current.focus(0);
342 },
343 blur: function blur() {
344 var _document = document,
345 activeElement = _document.activeElement;
346
347 if (containerRef.current.contains(activeElement)) {
348 activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur();
349 }
350 }
351 };
352 }); // ========================== Auto Focus ==========================
353
354 React.useEffect(function () {
355 if (autoFocus) {
356 handlesRef.current.focus(0);
357 }
358 }, []); // =========================== Context ============================
359
360 var context = React.useMemo(function () {
361 return {
362 min: mergedMin,
363 max: mergedMax,
364 direction: direction,
365 disabled: disabled,
366 keyboard: keyboard,
367 step: mergedStep,
368 included: included,
369 includedStart: includedStart,
370 includedEnd: includedEnd,
371 range: range,
372 tabIndex: tabIndex,
373 ariaLabelForHandle: ariaLabelForHandle,
374 ariaLabelledByForHandle: ariaLabelledByForHandle,
375 ariaValueTextFormatterForHandle: ariaValueTextFormatterForHandle
376 };
377 }, [mergedMin, mergedMax, direction, disabled, keyboard, mergedStep, included, includedStart, includedEnd, range, tabIndex, ariaLabelForHandle, ariaLabelledByForHandle, ariaValueTextFormatterForHandle]); // ============================ Render ============================
378
379 return /*#__PURE__*/React.createElement(SliderContext.Provider, {
380 value: context
381 }, /*#__PURE__*/React.createElement("div", {
382 ref: containerRef,
383 className: classNames(prefixCls, className, (_classNames = {}, _defineProperty(_classNames, "".concat(prefixCls, "-disabled"), disabled), _defineProperty(_classNames, "".concat(prefixCls, "-vertical"), vertical), _defineProperty(_classNames, "".concat(prefixCls, "-horizontal"), !vertical), _defineProperty(_classNames, "".concat(prefixCls, "-with-marks"), markList.length), _classNames)),
384 style: style,
385 onMouseDown: onSliderMouseDown
386 }, /*#__PURE__*/React.createElement("div", {
387 className: "".concat(prefixCls, "-rail"),
388 style: railStyle
389 }), /*#__PURE__*/React.createElement(Tracks, {
390 prefixCls: prefixCls,
391 style: trackStyle,
392 values: sortedCacheValues,
393 startPoint: startPoint,
394 onStartMove: mergedDraggableTrack ? onStartMove : null
395 }), /*#__PURE__*/React.createElement(Steps, {
396 prefixCls: prefixCls,
397 marks: markList,
398 dots: dots,
399 style: dotStyle,
400 activeStyle: activeDotStyle
401 }), /*#__PURE__*/React.createElement(Handles, {
402 ref: handlesRef,
403 prefixCls: prefixCls,
404 style: handleStyle,
405 values: cacheValues,
406 draggingIndex: draggingIndex,
407 onStartMove: onStartMove,
408 onOffsetChange: onHandleOffsetChange,
409 onFocus: onFocus,
410 onBlur: onBlur,
411 handleRender: handleRender
412 }), /*#__PURE__*/React.createElement(Marks, {
413 prefixCls: prefixCls,
414 marks: markList,
415 onClick: changeToCloseValue
416 })));
417});
418
419if (process.env.NODE_ENV !== 'production') {
420 Slider.displayName = 'Slider';
421}
422
423export default Slider;
\No newline at end of file