import React, { useRef, useState, useEffect } from 'react'; import './Slider.css'; /** * Aurora Admin Slider(React) * 对齐 组件7.txt SliderInput 规范:单/双滑块、刻度、输入框联动 * * props: * - value / defaultValue : number | [lo, hi] * - min / max / step * - range : 双滑块 * - showTicks : 刻度 * - showInput : 数值输入框联动 * - disabled * - onChange(value) */ export default function Slider({ value, defaultValue = 0, min = 0, max = 100, step = 1, range = false, showTicks = false, showInput = false, disabled = false, onChange }) { const trackRef = useRef(null); const [dragIndex, setDragIndex] = useState(-1); const current = value !== undefined ? value : defaultValue; const pct = (v) => ((v - min) / (max - min)) * 100; const clamp = (v) => { const snapped = Math.round((v - min) / step) * step + min; return Math.max(min, Math.min(max, snapped)); }; const valueFromClientX = (x) => { const rect = trackRef.current.getBoundingClientRect(); return clamp(min + (x - rect.left) / rect.width * (max - min)); }; const setVal = (next) => { if (value === undefined) onChange && onChange(next); else onChange && onChange(next); }; const onMove = (e) => { if (dragIndex < 0) return; const nv = valueFromClientX(e.clientX); if (range) { const arr = [...current]; arr[dragIndex] = nv; arr.sort((a, b) => a - b); setVal(arr); } else { setVal(nv); } }; const onUp = () => { setDragIndex(-1); window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); }; const onHandleDown = (i, e) => { if (disabled) return; e.preventDefault(); setDragIndex(i); window.addEventListener('pointermove', onMove); window.addEventListener('pointerup', onUp); }; const onTrackDown = (e) => { if (disabled || e.target.classList.contains('aa-slider-handle')) return; const nv = valueFromClientX(e.clientX); if (range) { const i = Math.abs(nv - current[0]) <= Math.abs(nv - current[1]) ? 0 : 1; const arr = [...current]; arr[i] = nv; arr.sort((a, b) => a - b); setVal(arr); } else { setVal(nv); } }; const onInput = (i, e) => { const v = +e.target.value; if (range) { const arr = [...current]; arr[i] = v; arr.sort((a, b) => a - b); setVal(arr); } else { setVal(v); } }; useEffect(() => () => onUp(), []); // eslint-disable-line const handlePercents = range ? [pct(current[0]), pct(current[1])] : [pct(current)]; const fillStyle = range ? { left: pct(current[0]) + '%', width: (pct(current[1]) - pct(current[0])) + '%' } : { left: '0%', width: pct(current) + '%' }; const tickPercents = Array.from( { length: Math.floor((max - min) / step) + 1 }, (_, i) => pct(min + i * step) ); return (