mirror of
https://github.com/italicsjenga/agb.git
synced 2025-02-02 12:36:35 +11:00
73 lines
1.6 KiB
TypeScript
73 lines
1.6 KiB
TypeScript
import { useRef } from "react";
|
|
import { styled } from "styled-components";
|
|
|
|
const SliderWrapper = styled.div`
|
|
padding: 1ex 0;
|
|
width: 100%;
|
|
`;
|
|
|
|
const SliderContainer = styled.div`
|
|
display: block;
|
|
position: relative;
|
|
width: 100%;
|
|
height: 0.25ex;
|
|
background-color: black;
|
|
margin: auto;
|
|
min-width: 10ex;
|
|
`;
|
|
|
|
const SliderBox = styled.div<{ $proportion: number }>`
|
|
position: absolute;
|
|
width: 1ex;
|
|
height: 1ex;
|
|
top: -0.3ex;
|
|
background-color: black;
|
|
left: ${(props) => props.$proportion * 90}%;
|
|
`;
|
|
|
|
export function Slider({
|
|
value,
|
|
onChange,
|
|
}: {
|
|
value: number;
|
|
onChange: (newValue: number) => void;
|
|
}) {
|
|
const slider = useRef<HTMLDivElement>(null);
|
|
|
|
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
onChange(
|
|
event.nativeEvent.offsetX / (event.target as HTMLDivElement).offsetWidth
|
|
);
|
|
|
|
event.stopPropagation();
|
|
};
|
|
|
|
const handleDrag = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
const sliderRef = slider.current;
|
|
|
|
if (!sliderRef || event.buttons !== 1) {
|
|
return;
|
|
}
|
|
|
|
const relativePosition =
|
|
event.clientX - sliderRef.getBoundingClientRect().left;
|
|
const proportion = relativePosition / sliderRef.offsetWidth;
|
|
|
|
const clamped = Math.min(1, Math.max(0, proportion));
|
|
|
|
onChange(clamped);
|
|
};
|
|
|
|
return (
|
|
<SliderWrapper ref={slider} onClick={handleClick} onMouseMove={handleDrag}>
|
|
<SliderContainer>
|
|
<SliderBox
|
|
$proportion={value}
|
|
onClick={(e: React.MouseEvent) => {
|
|
e.stopPropagation();
|
|
}}
|
|
/>
|
|
</SliderContainer>
|
|
</SliderWrapper>
|
|
);
|
|
}
|