UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

157 lines (154 loc) 8.31 kB
import { __rest } from '../../node_modules/tslib/tslib.es6.js'; import React, { forwardRef, useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from '../../_virtual/index.js'; import '@popperjs/core'; import isRTL from '../../utils/isRTL.js'; import { useForkedRef } from '../../hooks/useForkedRef.js'; import { getThumbSize, calculateMoveValue, updateValue, calculateTooltipPosition, updateGradient, calculateLabelPosition, getLabelValue, calculateClickValue, getNearestValueIndex, validateValue } from './utils.js'; const CRangeSlider = forwardRef((_a, ref) => { var { className, clickableLabels = true, disabled = false, distance = 0, labels, min = 0, max = 100, name, step = 1, value = [], onChange, tooltips = true, tooltipsFormat, track = 'fill', vertical = false } = _a, rest = __rest(_a, ["className", "clickableLabels", "disabled", "distance", "labels", "min", "max", "name", "step", "value", "onChange", "tooltips", "tooltipsFormat", "track", "vertical"]); const rangeSliderRef = useRef(null); const forkedRef = useForkedRef(ref, rangeSliderRef); const inputsRef = useRef([]); const labelsContainerRef = useRef(null); const labelsRef = useRef([]); const trackRef = useRef(null); const [currentValue, setCurrentValue] = useState(Array.isArray(value) ? value : [value]); const [isDragging, setIsDragging] = useState(false); const [_isRTL, setIsRTL] = useState(false); const [dragIndex, setDragIndex] = useState(0); const [thumbSize, setThumbSize] = useState(); useEffect(() => { setCurrentValue(Array.isArray(value) ? value : [value]); }, [value]); useEffect(() => { if (rangeSliderRef.current) { setIsRTL(isRTL(rangeSliderRef.current)); setThumbSize(getThumbSize(rangeSliderRef.current, vertical)); } }, [rangeSliderRef]); useEffect(() => { const maxSize = Math.max(...labelsRef.current.map((label) => (vertical ? label.offsetWidth : label.offsetHeight))); if (labelsContainerRef.current) { labelsContainerRef.current.style[vertical ? 'width' : 'height'] = `${maxSize}px`; } }, [labelsRef]); useEffect(() => { if (isDragging) { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); } return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; }, [currentValue]); const updateNearestValue = (value) => { const nearestIndex = getNearestValueIndex(value, currentValue); const newCurrentValue = [...currentValue]; newCurrentValue[nearestIndex] = validateValue(value, currentValue, distance, nearestIndex); setTimeout(() => { inputsRef.current[nearestIndex].focus(); }); setCurrentValue(newCurrentValue); if (onChange) { onChange(newCurrentValue); } }; const handleInputChange = (event, index) => { setIsDragging(false); const target = event.target; const value = Number(target.value); const newCurrentValue = updateValue(value, currentValue, distance, index); setCurrentValue(newCurrentValue); // Trigger change event if needed if (onChange) { onChange(newCurrentValue); } }; const handleInputsContainerMouseDown = (event) => { if (trackRef.current === null || event.button !== 0 || disabled) { return; } const target = event.target; if (!(target instanceof HTMLInputElement) && target !== trackRef.current) { return; } const clickValue = calculateClickValue(event, trackRef.current, min, max, step, vertical, _isRTL); const index = getNearestValueIndex(clickValue, currentValue); setIsDragging(true); setDragIndex(index); updateNearestValue(clickValue); }; const handleLabelClick = (event, value) => { if (!clickableLabels || disabled || event.button !== 0) { return; } updateNearestValue(value); }; const handleMouseMove = (event) => { if (!isDragging || trackRef.current === null || disabled) { return; } const moveValue = calculateMoveValue(event, trackRef.current, min, max, step, vertical, _isRTL); const newCurrentValue = updateValue(moveValue, currentValue, distance, dragIndex); setCurrentValue(newCurrentValue); if (onChange) { onChange(newCurrentValue); } }; const handleMouseUp = () => { setIsDragging(false); }; return (React.createElement("div", Object.assign({ className: classNames('range-slider', className, { 'range-slider-vertical': vertical, disabled, }) }, rest, { ref: forkedRef }), React.createElement("div", { className: "range-slider-inputs-container", onMouseDown: handleInputsContainerMouseDown }, currentValue.map((value, index) => (React.createElement(React.Fragment, { key: index }, React.createElement("input", { className: "range-slider-input", type: "range", min: min, max: max, step: step, value: value, name: Array.isArray(name) ? name[index] : `${name || ''}-${index}}`, role: "slider", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": value, "aria-orientation": vertical ? 'vertical' : 'horizontal', disabled: disabled, onChange: (event) => handleInputChange(event, index), ref: (el) => { inputsRef.current[index] = el; } }), tooltips && (React.createElement("div", Object.assign({ className: "range-slider-tooltip" }, (thumbSize && { style: calculateTooltipPosition(min, max, value, thumbSize, vertical, _isRTL), })), React.createElement("div", { className: "range-slider-tooltip-inner" }, tooltipsFormat ? tooltipsFormat(value) : value), React.createElement("div", { className: "range-slider-tooltip-arrow" })))))), React.createElement("div", Object.assign({ className: "range-slider-track" }, (track && { style: updateGradient(min, max, currentValue, vertical, _isRTL), }), { ref: trackRef }))), labels && (React.createElement("div", { className: "range-slider-labels-container", ref: labelsContainerRef }, Array.isArray(labels) && labels.map((label, index) => { const labelPosition = calculateLabelPosition(min, max, labels, label, index); const labelValue = getLabelValue(min, max, labels, label, index); const labelStyle = Object.assign(vertical ? { bottom: labelPosition } : _isRTL ? { right: labelPosition } : { left: labelPosition }, typeof label === 'object' && 'style' in label && label.style); return (React.createElement("div", { className: classNames('range-slider-label', { clickable: clickableLabels, }, typeof label === 'object' && 'className' in label && label.className), style: labelStyle, onMouseDown: (event) => handleLabelClick(event, labelValue), key: index, ref: (el) => { labelsRef.current[index] = el; } }, typeof label === 'object' && 'label' in label ? label.label : label)); }))))); }); CRangeSlider.propTypes = { clickableLabels: PropTypes.bool, disabled: PropTypes.bool, distance: PropTypes.number, labels: PropTypes.any, max: PropTypes.number, min: PropTypes.number, name: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), step: PropTypes.number, tooltips: PropTypes.bool, tooltipsFormat: PropTypes.func, track: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['fill'])]), value: PropTypes.oneOfType([PropTypes.array, PropTypes.number]), vertical: PropTypes.bool, }; CRangeSlider.displayName = 'CRangeSlider'; export { CRangeSlider }; //# sourceMappingURL=CRangeSlider.js.map