feat: add touch handling

This commit is contained in:
p-sw 2024-06-02 01:27:41 +09:00
parent bd3892e314
commit 811be2f59b

View File

@ -1,5 +1,6 @@
import React, { import React, {
ComponentPropsWithoutRef, ComponentPropsWithoutRef,
TouchEvent as ReactTouchEvent,
forwardRef, forwardRef,
useContext, useContext,
useEffect, useEffect,
@ -171,6 +172,7 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
const [state, setState] = useContext(DrawerContext); const [state, setState] = useContext(DrawerContext);
const [dragState, setDragState] = useState({ const [dragState, setDragState] = useState({
isDragging: false, isDragging: false,
prevTouch: { x: 0, y: 0 },
delta: 0, delta: 0,
}); });
@ -188,11 +190,23 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
setDragState({ setDragState({
isDragging: true, isDragging: true,
delta: 0, delta: 0,
prevTouch: { x: 0, y: 0 },
});
}
function onTouchStart(e: ReactTouchEvent<HTMLDivElement>) {
setState((prev) => ({ ...prev, isDragging: true }));
setDragState({
isDragging: true,
delta: 0,
prevTouch: { x: e.touches[0].pageX, y: e.touches[0].pageY },
}); });
} }
useEffect(() => { useEffect(() => {
function onMouseUp(e: MouseEvent) { function onMouseUp(e: TouchEvent): void;
function onMouseUp(e: MouseEvent): void;
function onMouseUp(e: TouchEvent | MouseEvent) {
if ( if (
e.target instanceof Element && e.target instanceof Element &&
internalRef.current && internalRef.current &&
@ -220,15 +234,22 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
setDragState({ setDragState({
isDragging: false, isDragging: false,
delta: 0, delta: 0,
prevTouch: { x: 0, y: 0 },
}); });
} }
function onMouseMove(e: MouseEvent) { function onMouseMove(e: TouchEvent): void;
function onMouseMove(e: MouseEvent): void;
function onMouseMove(e: MouseEvent | TouchEvent) {
if (dragState.isDragging) { if (dragState.isDragging) {
setDragState((prev) => { setDragState((prev) => {
let movement = ["top", "bottom"].includes(position) let movement = ["top", "bottom"].includes(position)
? "movementY" in e
? e.movementY ? e.movementY
: e.movementX; : e.touches[0].pageY - prev.prevTouch.y
: "movementX" in e
? e.movementX
: e.touches[0].pageX - prev.prevTouch.x;
if ( if (
(["top", "left"].includes(position) && (["top", "left"].includes(position) &&
dragState.delta >= 0 && dragState.delta >= 0 &&
@ -243,6 +264,11 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
return { return {
...prev, ...prev,
delta: prev.delta + movement, delta: prev.delta + movement,
...("touches" in e
? {
prevTouch: { x: e.touches[0].pageX, y: e.touches[0].pageY },
}
: {}),
}; };
}); });
@ -268,9 +294,13 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
window.addEventListener("mousemove", onMouseMove); window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp); window.addEventListener("mouseup", onMouseUp);
window.addEventListener("touchmove", onMouseMove);
window.addEventListener("touchend", onMouseUp);
return () => { return () => {
window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", onMouseUp); window.removeEventListener("mouseup", onMouseUp);
window.removeEventListener("touchmove", onMouseMove);
window.removeEventListener("touchend", onMouseUp);
}; };
}, [state, dragState]); }, [state, dragState]);
@ -337,6 +367,7 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
dragState.isDragging && dragState.isDragging &&
setState((prev) => ({ ...prev, leaveWhileDragging: false })) setState((prev) => ({ ...prev, leaveWhileDragging: false }))
} }
onTouchStart={onTouchStart}
/> />
</div> </div>
); );