import React, { useState, useRef } from "react"; export interface Helper { position: number, text?: string, } export interface Props { value?: number, steps?: number, helpers?: Helper[], stickyHelpers?: boolean, tooltip?: string, disabled?: boolean className?: string, onChange?: (...args: any[]) => any, } const Slider = ({ value, steps = 1, helpers, stickyHelpers = true, tooltip, disabled, className, onChange }: Props): JSX.Element => { const [dragging, setDragging] = useState(false) const sliderEl = useRef(null) const getValue = (): number => { if (value > 100) return 100 if (value < 0) return 0 return value } const handleMouseDown = (event) => { changePostion(event) const handleMouseMove = event => { changePostion(event) setDragging(true) } const handleMouseUp = event => { changePostion(event) setDragging(false) document.removeEventListener("mousemove", handleMouseMove) document.removeEventListener("mouseup", handleMouseUp) } document.addEventListener("mousemove", handleMouseMove) document.addEventListener("mouseup", handleMouseUp) } const changePostion = event => { if (disabled || !onChange) return const container = sliderEl.current if (!container) return const containerDim = container.getBoundingClientRect() const width = containerDim.width const pxPos = event.clientX - containerDim.left let position = Math.round(pxPos * 100 / width) if (position < 0) position = 0 if (position > 100) position = 100 if (steps) { position = Math.round(position / steps) * steps } if (stickyHelpers) { const closestHelper = (() => { const helperDiffs = helpers.map((helper, index) => { let diff = helper.position - position if (diff < 0) diff *= -1 return { index, diff } }).sort((a, b) => { const posA = a.diff const posB = b.diff if (posA > posB) return 1 if (posA < posB) return -1 return 0 }) const closestHelper = helperDiffs[0] return { ...helpers[closestHelper.index], ...closestHelper } })() const stickyThreshold = 3 if (closestHelper.diff < stickyThreshold) { position = closestHelper.position } } onChange(position) } const setPosition = (position: number) => { onChange(position) } return (