UNPKG

zarm

Version:

基于 React 的移动端UI库

224 lines (194 loc) 7.23 kB
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;