mobile touch events

This commit is contained in:
Josh Hawkins 2024-03-03 12:30:59 -06:00
parent c74eb75554
commit b50ad87d34
2 changed files with 33 additions and 20 deletions

View File

@ -159,14 +159,6 @@ export function EventReviewTimeline({
useEffect(() => { useEffect(() => {
generateSegments(); generateSegments();
// TODO: touch events for mobile
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
// we know that these deps are correct // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [generateSegments, timelineStart, handleMouseUp, handleMouseMove]); }, [generateSegments, timelineStart, handleMouseUp, handleMouseMove]);
@ -174,6 +166,10 @@ export function EventReviewTimeline({
return ( return (
<div <div
ref={timelineRef} ref={timelineRef}
onMouseMove={handleMouseMove}
onTouchMove={handleMouseMove}
onMouseUp={handleMouseUp}
onTouchEnd={handleMouseUp}
className={`relative h-full overflow-y-scroll no-scrollbar bg-secondary ${ className={`relative h-full overflow-y-scroll no-scrollbar bg-secondary ${
isDragging && showHandlebar ? "cursor-grabbing" : "cursor-auto" isDragging && showHandlebar ? "cursor-grabbing" : "cursor-auto"
}`} }`}
@ -181,13 +177,16 @@ export function EventReviewTimeline({
<div className="flex flex-col">{segments}</div> <div className="flex flex-col">{segments}</div>
{showHandlebar && ( {showHandlebar && (
<div className={`absolute left-0 top-0 z-20 w-full `} role="scrollbar"> <div className={`absolute left-0 top-0 z-20 w-full `} role="scrollbar">
<div className={`flex items-center justify-center `}> <div
className="flex items-center justify-center touch-none select-none"
onMouseDown={handleMouseDown}
onTouchStart={handleMouseDown}
>
<div <div
ref={scrollTimeRef} ref={scrollTimeRef}
className={`relative w-full ${ className={`relative w-full ${
isDragging ? "cursor-grabbing" : "cursor-grab" isDragging ? "cursor-grabbing" : "cursor-grab"
}`} }`}
onMouseDown={handleMouseDown}
> >
<div <div
className={`bg-destructive rounded-full mx-auto ${ className={`bg-destructive rounded-full mx-auto ${

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect } from "react"; import { useCallback, useEffect } from "react";
import scrollIntoView from "scroll-into-view-if-needed"; import { isMobile } from "react-device-detect";
type DragHandlerProps = { type DragHandlerProps = {
contentRef: React.RefObject<HTMLElement>; contentRef: React.RefObject<HTMLElement>;
@ -34,7 +34,9 @@ function useDraggableHandler({
setIsDragging, setIsDragging,
}: DragHandlerProps) { }: DragHandlerProps) {
const handleMouseDown = useCallback( const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => { (
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setIsDragging(true); setIsDragging(true);
@ -43,7 +45,9 @@ function useDraggableHandler({
); );
const handleMouseUp = useCallback( const handleMouseUp = useCallback(
(e: MouseEvent) => { (
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (isDragging) { if (isDragging) {
@ -76,10 +80,6 @@ function useDraggableHandler({
minute: "2-digit", minute: "2-digit",
...(segmentDuration < 60 && { second: "2-digit" }), ...(segmentDuration < 60 && { second: "2-digit" }),
}); });
scrollIntoView(thumb, {
scrollMode: "if-needed",
behavior: "smooth",
});
} }
}); });
if (setHandlebarTime) { if (setHandlebarTime) {
@ -91,7 +91,9 @@ function useDraggableHandler({
); );
const handleMouseMove = useCallback( const handleMouseMove = useCallback(
(e: MouseEvent) => { (
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
) => {
if ( if (
!contentRef.current || !contentRef.current ||
!timelineRef.current || !timelineRef.current ||
@ -100,10 +102,17 @@ function useDraggableHandler({
return; return;
} }
let clientY;
if (isMobile && e.nativeEvent instanceof TouchEvent) {
clientY = e.nativeEvent.touches[0].clientY;
} else if (e.nativeEvent instanceof MouseEvent) {
clientY = e.nativeEvent.clientY;
}
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (showHandlebar && isDragging) { if (showHandlebar && isDragging && clientY) {
const { const {
scrollHeight: timelineHeight, scrollHeight: timelineHeight,
clientHeight: visibleTimelineHeight, clientHeight: visibleTimelineHeight,
@ -120,7 +129,7 @@ function useDraggableHandler({
visibleTimelineHeight - timelineTop + parentScrollTop, visibleTimelineHeight - timelineTop + parentScrollTop,
Math.max( Math.max(
segmentHeight + scrolled, segmentHeight + scrolled,
e.clientY - timelineTop + parentScrollTop, clientY - timelineTop + parentScrollTop,
), ),
); );
@ -172,6 +181,11 @@ function useDraggableHandler({
scrolled; scrolled;
updateHandlebarPosition(newHandlePosition - segmentHeight, handlebarTime); updateHandlebarPosition(newHandlePosition - segmentHeight, handlebarTime);
scrollTimeRef.current.scrollIntoView({
behavior: "smooth",
block: "center",
});
} }
// we know that these deps are correct // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps