zarm
Version:
基于 React 的移动端UI库
224 lines (194 loc) • 7.23 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { createBEM } from '@zarm-design/bem';
import { useDrag } from '@use-gesture/react';
import isPlainObject from 'lodash/isPlainObject';
import Events from '../utils/events';
import Tooltip from '../tooltip';
import ensureValuePrecision from './utils/ensureValuePrecision';
import getValue from './utils/getValue';
import { ConfigContext } from '../config-provider';
var Slider = /*#__PURE__*/React.forwardRef(function (props, ref) {
var _React$useContext = React.useContext(ConfigContext),
prefixCls = _React$useContext.prefixCls;
var bem = createBEM('slider', {
prefixCls: prefixCls
});
var className = props.className,
disabled = props.disabled,
min = props.min,
max = props.max,
vertical = props.vertical,
showMark = props.showMark,
value = props.value,
marks = props.marks,
onChange = props.onChange,
onSlideChange = props.onSlideChange,
defaultValue = props.defaultValue,
style = props.style;
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
tooltip = _useState2[0],
setTooltip = _useState2[1];
var _React$useState = React.useState(getValue(props, 0)),
_React$useState2 = _slicedToArray(_React$useState, 2),
currentValue = _React$useState2[0],
setCurrentValue = _React$useState2[1];
var lineRef = React.useRef(null);
var getMaxOffset = function getMaxOffset() {
var _lineRef$current;
var divRect = lineRef === null || lineRef === void 0 ? void 0 : (_lineRef$current = lineRef.current) === null || _lineRef$current === void 0 ? void 0 : _lineRef$current.getBoundingClientRect();
return (vertical ? divRect === null || divRect === void 0 ? void 0 : divRect.height : divRect === null || divRect === void 0 ? void 0 : divRect.width) || 0;
};
var getOffsetByValue = function getOffsetByValue(val) {
var maxOffset = getMaxOffset();
var range = max - min;
return vertical ? maxOffset * ((max - val) / range) : maxOffset * ((val - min) / range);
};
var getValueByOffset = function getValueByOffset(offset) {
var maxOffset = getMaxOffset();
var percent = offset / maxOffset;
var val = vertical ? (1 - percent) * (max - min) + min : Math.round(min + (max - min) * percent);
return ensureValuePrecision(val, props);
};
var offsetStart = useRef(0);
useEffect(function () {
var val = getValue({
defaultValue: defaultValue,
value: value
}, 0);
setCurrentValue(val);
}, [defaultValue, value]);
var trackClick = useCallback(function (event) {
event.stopPropagation();
if (disabled) return;
var line = lineRef.current;
if (!line) return;
var _line$getBoundingClie = line.getBoundingClientRect(),
left = _line$getBoundingClie.left,
top = _line$getBoundingClie.top;
var offset = vertical ? event.clientY - top : event.clientX - left;
var current = getValueByOffset(offset);
current = Math.min(max, Math.max(min, current));
setCurrentValue(current);
if (typeof onChange === 'function') {
onChange(current);
}
}, [onChange, max, min]);
var bind = useDrag(function (state) {
var offsetX = state.xy[0] - state.initial[0],
offsetY = state.xy[1] - state.initial[1];
state.event.stopPropagation();
if (state.first) {
offsetStart.current = getOffsetByValue(currentValue);
setTooltip(true);
}
var offset = vertical ? offsetY : offsetX;
offset += offsetStart.current;
var maxOffset = getMaxOffset();
offset = Math.min(maxOffset, Math.max(offset, 0));
var current = getValueByOffset(offset);
setCurrentValue(current);
if (state.dragging && !state.first) {
onSlideChange === null || onSlideChange === void 0 ? void 0 : onSlideChange(current);
}
if (state.last) {
setTooltip(false);
onChange === null || onChange === void 0 ? void 0 : onChange(currentValue);
}
}, {
enabled: !props.disabled,
axis: vertical ? 'y' : 'x',
pointer: {
touch: true
},
preventDefault: !Events.supportsPassiveEvents
});
var renderMark = function renderMark() {
var isEmptyMarks = !isPlainObject(marks) || JSON.stringify(marks) === '{}';
if (showMark && isEmptyMarks) {
console.error('请输入有效的 marks');
return null;
} // 判断是否为空对象
if (isEmptyMarks) {
return null;
}
var markKeys = Object.keys(marks || {});
var lineDot = markKeys.map(function (item) {
var dotStyle = bem('dot', [{
active: currentValue >= +item
}]);
var markStyle = _defineProperty({}, "".concat(vertical ? 'bottom' : 'left'), "".concat(item, "%"));
return /*#__PURE__*/React.createElement("span", {
key: item,
className: dotStyle,
style: markStyle
});
});
if (!showMark) {
return lineDot;
}
var marksElement = markKeys.map(function (item) {
var markStyle = _defineProperty({}, "".concat(vertical ? 'bottom' : 'left'), "".concat(item, "%"));
return /*#__PURE__*/React.createElement("span", {
key: item,
className: bem('mark'),
style: markStyle
}, marks === null || marks === void 0 ? void 0 : marks[+item]);
});
return /*#__PURE__*/React.createElement(React.Fragment, null, lineDot, /*#__PURE__*/React.createElement("div", {
className: bem('marks')
}, marksElement));
};
var cls = bem([{
disabled: disabled,
vertical: vertical,
marked: showMark
}, className]);
var ratio = (currentValue - min) / (max - min);
var offset = "".concat(ratio * 100, "%");
var knobStyle = _defineProperty({}, "".concat(vertical ? 'bottom' : 'left'), offset || 0);
var lineBg = _defineProperty({}, "".concat(vertical ? 'height' : 'width'), offset || 0);
return /*#__PURE__*/React.createElement("div", {
className: cls,
ref: ref,
style: style
}, /*#__PURE__*/React.createElement("div", {
className: bem('content')
}, /*#__PURE__*/React.createElement("div", {
className: bem('line'),
ref: lineRef,
onClick: trackClick
}, /*#__PURE__*/React.createElement("div", {
className: bem('line__bg'),
style: lineBg
}), renderMark()), /*#__PURE__*/React.createElement("div", _extends({
className: bem('knob'),
role: "slider",
"aria-valuemin": min,
"aria-valuemax": max,
"aria-valuenow": value,
"aria-orientation": vertical ? 'vertical' : 'horizontal',
style: knobStyle
}, bind()), /*#__PURE__*/React.createElement(Tooltip, {
trigger: "manual",
arrowPointAtCenter: true,
visible: tooltip,
content: currentValue
}, /*#__PURE__*/React.createElement("div", {
className: bem('knob__shadow')
})))));
});
Slider.displayName = 'Slider';
Slider.defaultProps = {
disabled: false,
showMark: false,
vertical: false,
step: 1,
min: 0,
max: 100,
marks: {}
};
export default Slider;