movie-web/src/hooks/useProgressBar.ts

90 lines
2.7 KiB
TypeScript
Raw Normal View History

2023-01-09 21:51:24 +01:00
import React, { RefObject, useCallback, useEffect, useState } from "react";
2023-06-08 03:08:17 +02:00
export type MouseActivity = React.MouseEvent<HTMLElement> | MouseEvent;
type ActivityEvent = MouseActivity | React.TouchEvent<HTMLElement> | TouchEvent;
2023-01-09 21:51:24 +01:00
export function makePercentageString(num: number) {
return `${num.toFixed(2)}%`;
}
export function makePercentage(num: number) {
return Number(Math.max(0, Math.min(num, 100)).toFixed(2));
}
function isClickEvent(
evt: ActivityEvent,
2023-01-23 23:01:08 +01:00
): evt is React.MouseEvent<HTMLElement> | MouseEvent {
return (
evt.type === "mousedown" ||
evt.type === "mouseup" ||
evt.type === "mousemove"
);
}
2023-01-23 23:01:08 +01:00
const getEventX = (evt: ActivityEvent) => {
return isClickEvent(evt) ? evt.pageX : evt.changedTouches[0].pageX;
};
2023-01-09 21:51:24 +01:00
export function useProgressBar(
barRef: RefObject<HTMLElement>,
commit: (percentage: number) => void,
commitImmediately = false,
2023-01-09 21:51:24 +01:00
) {
const [mouseDown, setMouseDown] = useState<boolean>(false);
const [progress, setProgress] = useState<number>(0);
useEffect(() => {
2023-01-23 23:01:08 +01:00
function mouseMove(ev: ActivityEvent) {
2023-01-09 21:51:24 +01:00
if (!mouseDown || !barRef.current) return;
const rect = barRef.current.getBoundingClientRect();
2023-01-23 23:01:08 +01:00
const pos = (getEventX(ev) - rect.left) / barRef.current.offsetWidth;
2023-01-10 19:53:55 +01:00
setProgress(pos * 100);
2023-01-09 21:51:24 +01:00
if (commitImmediately) commit(pos);
}
2023-01-23 23:01:08 +01:00
function mouseUp(ev: ActivityEvent) {
2023-01-09 21:51:24 +01:00
if (!mouseDown) return;
setMouseDown(false);
document.body.removeAttribute("data-no-select");
if (!barRef.current) return;
const rect = barRef.current.getBoundingClientRect();
const pos = (getEventX(ev) - rect.left) / barRef.current.offsetWidth;
2023-01-09 21:51:24 +01:00
commit(pos);
}
document.addEventListener("mousemove", mouseMove);
2023-01-23 23:01:08 +01:00
document.addEventListener("touchmove", mouseMove);
2023-01-09 21:51:24 +01:00
document.addEventListener("mouseup", mouseUp);
document.addEventListener("touchend", mouseUp);
2023-01-09 21:51:24 +01:00
return () => {
document.removeEventListener("mousemove", mouseMove);
2023-01-23 23:01:08 +01:00
document.removeEventListener("touchmove", mouseMove);
2023-01-09 21:51:24 +01:00
document.removeEventListener("mouseup", mouseUp);
2023-01-23 23:01:08 +01:00
document.removeEventListener("touchend", mouseUp);
2023-01-09 21:51:24 +01:00
};
}, [mouseDown, barRef, commit, commitImmediately]);
const dragMouseDown = useCallback(
2023-01-23 23:01:08 +01:00
(ev: ActivityEvent) => {
2023-01-09 21:51:24 +01:00
setMouseDown(true);
document.body.setAttribute("data-no-select", "true");
if (!barRef.current) return;
const rect = barRef.current.getBoundingClientRect();
const pos =
((getEventX(ev) - rect.left) / barRef.current.offsetWidth) * 100;
2023-01-09 21:51:24 +01:00
setProgress(pos);
},
[setProgress, barRef],
2023-01-09 21:51:24 +01:00
);
return {
dragging: mouseDown,
dragPercentage: progress,
dragMouseDown,
};
}