@coinmeca/ui
Version:
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
78 lines • 3.82 kB
JSX
"use client";
import { useEffect, useRef, useState } from "react";
import Style from "./Range.styled";
import { isNumber, parseNumber } from "../../../lib/utils";
export default function Range(props) {
const trackRef = useRef(null);
const thumbRef = useRef(null);
const [value, setValue] = useState(props?.value || 0);
const [percent, setPercent] = useState(0);
const color = props?.color || "white";
const step = props?.values?.length || (props?.step ? (props?.step > 2 ? props?.step : 2) : 2);
const snap = props?.snap || false;
const zero = props?.zero || false;
const min = props?.min || 0;
const max = props?.values?.length ? props?.values?.length - 1 : props?.max || min + 100;
const disabled = props?.disabled || false;
useEffect(() => {
typeof props?.value === "number" && isNumber(props?.value)
? setValue(props?.value < min ? min : props?.value > max ? max : props?.value)
: 0;
}, [props?.value, min, max]);
useEffect(() => {
setPercent(value === min ? 0 : ((value - min) / (max - min)) * 100);
}, [value, min, max]);
const handleChange = (e) => {
e?.stopPropagation();
const range = max - min;
let value = parseFloat(e.target.value) >= max ? max : parseFloat(e.target.value) <= min ? min : parseFloat(e.target.value);
if (snap) {
const tick = range / (step - 1);
if (zero && min < 0 && value >= tick / -4 && value <= tick / 4) {
value = 0;
}
else {
value = Math.round((value + min) / tick) * tick - min;
}
}
const percent = ((value - min) * 100) / range || 0;
setPercent(percent);
setValue(parseNumber(value));
props?.onChange?.(e, value, percent);
};
const handleMouseMove = (e) => {
if (disabled)
return;
if (!trackRef?.current || !thumbRef?.current)
return;
const mouse = e.clientX;
const rect = thumbRef.current.getBoundingClientRect();
const thumb = rect.left + rect.width / 2;
trackRef.current.style.cursor = e.buttons ? "grabbing" : mouse < thumb ? "w-resize" : "e-resize";
};
return (<>
<Style ref={trackRef} draggable={false} $color={color} $value={(max.toString().length > min.toString().length ? max.toString().length : min.toString().length) +
(props?.unit ? props?.unit.toString().length + 1 : 0)} data-show={props?.show} data-hide={props?.hide} onMouseMove={handleMouseMove}>
<input type="range" min={min} max={max} value={value} onChange={(e) => handleChange(e)}/>
<div>
<div>
<div style={{ backgroundSize: `${percent}% 100%` }}>
{zero && max % ((max - min) / (step - 1)) !== 0 && (<div className={`zero${value >= 0 ? " on" : ""}`} style={{
left: `${(Math.abs(min) / (max - min)) * 100}%`,
}}/>)}
{[...Array(step)].map((_, i) => (<div key={i} className={percent >= ((((max - min) / (step - 1)) * i) / (max - min)) * 100 ? "on" : ""}/>))}
</div>
</div>
<div>
<span ref={thumbRef} draggable={false} style={{ left: `${percent}%` }}>
<span>
{props?.values?.[Math.round(percent / (100 / (props.values.length - 1)))] || value.toFixed(0)}
{props?.unit && ` ${props?.unit}`}
</span>
</span>
</div>
</div>
</Style>
</>);
}
//# sourceMappingURL=Range.jsx.map