45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
interface ProgressBarProps {
|
|
progress: number;
|
|
onSeek: (ratio: number) => void;
|
|
}
|
|
|
|
export function ProgressBar({ progress, onSeek }: ProgressBarProps) {
|
|
const seekFromClientX = (clientX: number, element: HTMLElement) => {
|
|
const rect = element.getBoundingClientRect();
|
|
onSeek((clientX - rect.left) / rect.width);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="relative h-1.5 rounded-full bg-white/25 overflow-hidden cursor-pointer touch-none"
|
|
onClick={(e) => {
|
|
seekFromClientX(e.clientX, e.currentTarget as HTMLElement);
|
|
}}
|
|
onPointerDown={(e) => {
|
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
seekFromClientX(e.clientX, e.currentTarget);
|
|
}}
|
|
onPointerMove={(e) => {
|
|
if (!e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
seekFromClientX(e.clientX, e.currentTarget);
|
|
}}
|
|
onPointerUp={(e) => {
|
|
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
}
|
|
}}
|
|
onPointerCancel={(e) => {
|
|
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
}
|
|
}}
|
|
>
|
|
<div
|
|
className="origin-left h-full bg-white"
|
|
style={{ transform: `scaleX(${progress || 0})` }}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|