@coreui/react-pro
Version:
UI Components Library for React.js
157 lines (154 loc) • 8.31 kB
JavaScript
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