Refactored files.
This commit is contained in:
+36
-51
@@ -1,33 +1,19 @@
|
|||||||
import { useEffect, useState, useRef, useCallback } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
|
||||||
import type { CartesianSpace } from "../types";
|
import type { CartesianSpace } from "../types";
|
||||||
import { minmax } from "../util";
|
import {
|
||||||
|
extractEventCoordinates,
|
||||||
|
isLeftMouseButton,
|
||||||
|
isTouchEvent,
|
||||||
|
minmax,
|
||||||
|
} from "../util";
|
||||||
|
|
||||||
if (typeof TouchEvent === "undefined") {
|
if (typeof TouchEvent === "undefined") {
|
||||||
// @ts-ignore - intentionally creating global
|
// @ts-ignore - intentionally creating global
|
||||||
window.TouchEvent = window.MouseEvent;
|
window.TouchEvent = window.MouseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTouchEvent(event: Event): event is TouchEvent {
|
|
||||||
return "touches" in event;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractEventCoordinates(event: MouseEvent | TouchEvent): {
|
|
||||||
clientX: number;
|
|
||||||
clientY: number;
|
|
||||||
} {
|
|
||||||
if (isTouchEvent(event)) {
|
|
||||||
return {
|
|
||||||
clientX: event.touches[0].clientX,
|
|
||||||
clientY: event.touches[0].clientY,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
clientX: event.clientX,
|
|
||||||
clientY: event.clientY,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCrosshair({
|
export function useCrosshair({
|
||||||
origin,
|
origin,
|
||||||
dimensions,
|
dimensions,
|
||||||
@@ -65,7 +51,7 @@ export function useCrosshair({
|
|||||||
[setXPosition, setYPosition],
|
[setXPosition, setYPosition],
|
||||||
);
|
);
|
||||||
|
|
||||||
const processCrosshairInteraction = useCallback(
|
const handleMove = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
calculatePositions(event);
|
calculatePositions(event);
|
||||||
@@ -73,69 +59,68 @@ export function useCrosshair({
|
|||||||
[calculatePositions],
|
[calculatePositions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const endCrosshairInteraction = useCallback(
|
const handleEnd = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
setIsDragging(false);
|
setIsDragging(false);
|
||||||
if (!isTouchEvent(event)) {
|
if (!isTouchEvent(event)) {
|
||||||
document.removeEventListener("mousemove", processCrosshairInteraction);
|
document.removeEventListener("mousemove", handleMove);
|
||||||
document.removeEventListener("mouseup", endCrosshairInteraction);
|
document.removeEventListener("mouseup", handleEnd);
|
||||||
} else {
|
} else {
|
||||||
document.removeEventListener("touchmove", processCrosshairInteraction);
|
document.removeEventListener("touchmove", handleMove);
|
||||||
document.removeEventListener("touchend", endCrosshairInteraction);
|
document.removeEventListener("touchend", handleEnd);
|
||||||
document.removeEventListener("touchcancel", endCrosshairInteraction);
|
document.removeEventListener("touchcancel", handleEnd);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[processCrosshairInteraction],
|
[handleMove],
|
||||||
);
|
);
|
||||||
|
|
||||||
const startCrosshairInteraction = useCallback(
|
const handleStart = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
|
if (!isTouchEvent(event) && !isLeftMouseButton(event.buttons)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
calculatePositions(event);
|
calculatePositions(event);
|
||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
|
|
||||||
if (!isTouchEvent(event)) {
|
if (!isTouchEvent(event)) {
|
||||||
document.addEventListener("mousemove", processCrosshairInteraction);
|
document.addEventListener("mousemove", handleMove);
|
||||||
document.addEventListener("mouseup", endCrosshairInteraction, {
|
document.addEventListener("mouseup", handleEnd, {
|
||||||
passive: true,
|
passive: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("touchmove", processCrosshairInteraction);
|
document.addEventListener("touchmove", handleMove);
|
||||||
document.addEventListener("touchend", endCrosshairInteraction, {
|
document.addEventListener("touchend", handleEnd, {
|
||||||
passive: true,
|
passive: true,
|
||||||
});
|
});
|
||||||
document.addEventListener("touchcancel", endCrosshairInteraction, {
|
document.addEventListener("touchcancel", handleEnd, {
|
||||||
passive: true,
|
passive: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[calculatePositions, processCrosshairInteraction, endCrosshairInteraction],
|
[calculatePositions, handleMove, handleEnd],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentRef = crosshairRef.current;
|
const currentRef = crosshairRef.current;
|
||||||
if (currentRef) {
|
if (currentRef) {
|
||||||
currentRef.addEventListener("mousedown", startCrosshairInteraction);
|
currentRef.addEventListener("mousedown", handleStart);
|
||||||
currentRef.addEventListener("touchstart", startCrosshairInteraction);
|
currentRef.addEventListener("touchstart", handleStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (currentRef) {
|
if (currentRef) {
|
||||||
currentRef.removeEventListener("mousedown", startCrosshairInteraction);
|
currentRef.removeEventListener("mousedown", handleStart);
|
||||||
currentRef.removeEventListener("touchstart", startCrosshairInteraction);
|
currentRef.removeEventListener("touchstart", handleStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.removeEventListener("mousemove", processCrosshairInteraction);
|
document.removeEventListener("mousemove", handleMove);
|
||||||
document.removeEventListener("mouseup", endCrosshairInteraction);
|
document.removeEventListener("mouseup", handleEnd);
|
||||||
document.removeEventListener("touchmove", processCrosshairInteraction);
|
document.removeEventListener("touchmove", handleMove);
|
||||||
document.removeEventListener("touchend", endCrosshairInteraction);
|
document.removeEventListener("touchend", handleEnd);
|
||||||
document.removeEventListener("touchcancel", endCrosshairInteraction);
|
document.removeEventListener("touchcancel", handleEnd);
|
||||||
};
|
};
|
||||||
}, [
|
}, [handleStart, handleMove, handleEnd]);
|
||||||
startCrosshairInteraction,
|
|
||||||
processCrosshairInteraction,
|
|
||||||
endCrosshairInteraction,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return { crosshairRef, isDragging };
|
return { crosshairRef, isDragging };
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-53
@@ -15,10 +15,6 @@ if (typeof TouchEvent === "undefined") {
|
|||||||
window.TouchEvent = window.MouseEvent;
|
window.TouchEvent = window.MouseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTouchEvent(event: Event): event is TouchEvent {
|
|
||||||
return "touches" in event;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Direction {
|
export enum Direction {
|
||||||
HORIZONTAL = "horizontal",
|
HORIZONTAL = "horizontal",
|
||||||
VERTICAL = "vertical",
|
VERTICAL = "vertical",
|
||||||
@@ -32,18 +28,12 @@ function chooseValueByDirection(
|
|||||||
return direction === Direction.HORIZONTAL ? xValue : yValue;
|
return direction === Direction.HORIZONTAL ? xValue : yValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractEventCoordinate(
|
function extractEventCoordinateByDirection(
|
||||||
event: MouseEvent | TouchEvent,
|
event: MouseEvent | TouchEvent,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
): number {
|
): number {
|
||||||
if (isTouchEvent(event)) {
|
const { clientX, clientY } = extractEventCoordinates(event);
|
||||||
return chooseValueByDirection(
|
return chooseValueByDirection(direction, clientX, clientY);
|
||||||
direction,
|
|
||||||
event.touches[0].clientX,
|
|
||||||
event.touches[0].clientY,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return chooseValueByDirection(direction, event.clientX, event.clientY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSlider({
|
export function useSlider({
|
||||||
@@ -77,7 +67,7 @@ export function useSlider({
|
|||||||
const orig = originRef.current;
|
const orig = originRef.current;
|
||||||
const dims = dimensionsRef.current;
|
const dims = dimensionsRef.current;
|
||||||
|
|
||||||
const clientCoord = extractEventCoordinate(event, dir);
|
const clientCoord = extractEventCoordinateByDirection(event, dir);
|
||||||
const positionValue = minmax(
|
const positionValue = minmax(
|
||||||
clientCoord - chooseValueByDirection(dir, orig.x, orig.y),
|
clientCoord - chooseValueByDirection(dir, orig.x, orig.y),
|
||||||
0,
|
0,
|
||||||
@@ -88,7 +78,7 @@ export function useSlider({
|
|||||||
[setPosition],
|
[setPosition],
|
||||||
);
|
);
|
||||||
|
|
||||||
const processSliderInteraction = useCallback(
|
const handleMove = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
calculatePosition(event);
|
calculatePosition(event);
|
||||||
@@ -96,43 +86,34 @@ export function useSlider({
|
|||||||
[calculatePosition],
|
[calculatePosition],
|
||||||
);
|
);
|
||||||
|
|
||||||
const endSliderInteraction = useCallback(
|
const handleEnd = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
|
document.removeEventListener("mousemove", handleMove);
|
||||||
|
document.removeEventListener("mouseup", handleEnd);
|
||||||
|
document.removeEventListener("touchmove", handleMove);
|
||||||
|
document.removeEventListener("touchend", handleEnd);
|
||||||
|
document.removeEventListener("touchcancel", handleEnd);
|
||||||
setIsDragging(false);
|
setIsDragging(false);
|
||||||
if (!isTouchEvent(event)) {
|
|
||||||
document.removeEventListener("mousemove", processSliderInteraction);
|
|
||||||
document.removeEventListener("mouseup", endSliderInteraction);
|
|
||||||
} else {
|
|
||||||
document.removeEventListener("touchmove", processSliderInteraction);
|
|
||||||
document.removeEventListener("touchend", endSliderInteraction);
|
|
||||||
document.removeEventListener("touchcancel", endSliderInteraction);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[processSliderInteraction],
|
[handleMove],
|
||||||
);
|
);
|
||||||
|
|
||||||
const startSliderInteraction = useCallback(
|
const handleStart = useCallback(
|
||||||
(event: MouseEvent | TouchEvent) => {
|
(event: MouseEvent | TouchEvent) => {
|
||||||
|
if (!isTouchEvent(event) && !isLeftMouseButton(event.buttons)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
calculatePosition(event);
|
calculatePosition(event);
|
||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
|
|
||||||
if (!isTouchEvent(event)) {
|
document.addEventListener("mousemove", handleMove);
|
||||||
document.addEventListener("mousemove", processSliderInteraction);
|
document.addEventListener("mouseup", handleEnd, { passive: true });
|
||||||
document.addEventListener("mouseup", endSliderInteraction, {
|
document.addEventListener("touchmove", handleMove);
|
||||||
passive: true,
|
document.addEventListener("touchend", handleEnd, { passive: true });
|
||||||
});
|
document.addEventListener("touchcancel", handleEnd, { passive: true });
|
||||||
} else {
|
|
||||||
document.addEventListener("touchmove", processSliderInteraction);
|
|
||||||
document.addEventListener("touchend", endSliderInteraction, {
|
|
||||||
passive: true,
|
|
||||||
});
|
|
||||||
document.addEventListener("touchcancel", endSliderInteraction, {
|
|
||||||
passive: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[calculatePosition, processSliderInteraction, endSliderInteraction],
|
[calculatePosition, handleMove, handleEnd],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Setup scroll handlers
|
// Setup scroll handlers
|
||||||
@@ -165,29 +146,29 @@ export function useSlider({
|
|||||||
const currentRef = sliderRef.current;
|
const currentRef = sliderRef.current;
|
||||||
if (currentRef) {
|
if (currentRef) {
|
||||||
addScrollListener();
|
addScrollListener();
|
||||||
currentRef.addEventListener("mousedown", startSliderInteraction);
|
currentRef.addEventListener("mousedown", handleStart);
|
||||||
currentRef.addEventListener("touchstart", startSliderInteraction);
|
currentRef.addEventListener("touchstart", handleStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (currentRef) {
|
if (currentRef) {
|
||||||
removeScrollListener();
|
removeScrollListener();
|
||||||
currentRef.removeEventListener("mousedown", startSliderInteraction);
|
currentRef.removeEventListener("mousedown", handleStart);
|
||||||
currentRef.removeEventListener("touchstart", startSliderInteraction);
|
currentRef.removeEventListener("touchstart", handleStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.removeEventListener("mousemove", processSliderInteraction);
|
document.removeEventListener("mousemove", handleMove);
|
||||||
document.removeEventListener("mouseup", endSliderInteraction);
|
document.removeEventListener("mouseup", handleEnd);
|
||||||
document.removeEventListener("touchmove", processSliderInteraction);
|
document.removeEventListener("touchmove", handleMove);
|
||||||
document.removeEventListener("touchend", endSliderInteraction);
|
document.removeEventListener("touchend", handleEnd);
|
||||||
document.removeEventListener("touchcancel", endSliderInteraction);
|
document.removeEventListener("touchcancel", handleEnd);
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
addScrollListener,
|
addScrollListener,
|
||||||
removeScrollListener,
|
removeScrollListener,
|
||||||
startSliderInteraction,
|
handleStart,
|
||||||
processSliderInteraction,
|
handleMove,
|
||||||
endSliderInteraction,
|
handleEnd,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { sliderRef, isDragging };
|
return { sliderRef, isDragging };
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ const triggerMouseEvent = (eventType: string, x: number, y: number) => {
|
|||||||
cy.dataCy("crosshair-container").trigger(eventType, {
|
cy.dataCy("crosshair-container").trigger(eventType, {
|
||||||
clientX: x,
|
clientX: x,
|
||||||
clientY: y,
|
clientY: y,
|
||||||
|
buttons: 1,
|
||||||
eventConstructor: "MouseEvent",
|
eventConstructor: "MouseEvent",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useRef, useEffect } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useSlider, Direction } from "../slider";
|
|
||||||
import type { CartesianSpace } from "../../types";
|
import type { CartesianSpace } from "../../types";
|
||||||
|
import { Direction, useSlider } from "../slider";
|
||||||
|
|
||||||
// Test Fixtures
|
// Test Fixtures
|
||||||
|
|
||||||
@@ -111,6 +112,7 @@ function createTestUtils(isHorizontal = true) {
|
|||||||
cy.dataCy("slider-container").trigger(eventType, {
|
cy.dataCy("slider-container").trigger(eventType, {
|
||||||
clientX: x,
|
clientX: x,
|
||||||
clientY: y,
|
clientY: y,
|
||||||
|
buttons: 1,
|
||||||
eventConstructor: "MouseEvent",
|
eventConstructor: "MouseEvent",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -176,28 +178,24 @@ describe("horizontal slider hook tests", () => {
|
|||||||
assertPosition(164);
|
assertPosition(164);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isTouchSupported()) {
|
it("moves the slider with touch events.", () => {
|
||||||
it("moves the slider with touch events.", () => {
|
assertPosition(0);
|
||||||
assertPosition(0);
|
|
||||||
|
|
||||||
triggerTouchEvent("touchstart", 86, 53);
|
triggerTouchEvent("touchstart", 86, 53);
|
||||||
assertPosition(0);
|
assertPosition(0);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 150, 150);
|
triggerTouchEvent("touchmove", 150, 150);
|
||||||
assertPosition(64);
|
assertPosition(64);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 500, 500);
|
triggerTouchEvent("touchmove", 500, 500);
|
||||||
assertPosition(250);
|
assertPosition(250);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 250, 250);
|
triggerTouchEvent("touchmove", 250, 250);
|
||||||
assertPosition(164);
|
assertPosition(164);
|
||||||
|
|
||||||
triggerTouchEvent("touchend", 250, 250);
|
triggerTouchEvent("touchend", 250, 250);
|
||||||
assertPosition(164);
|
assertPosition(164);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
console.log("Skipping Unsupported Touch Event Tests");
|
|
||||||
}
|
|
||||||
|
|
||||||
it("moves the slider with mouse wheel scrolling", () => {
|
it("moves the slider with mouse wheel scrolling", () => {
|
||||||
assertPosition(0);
|
assertPosition(0);
|
||||||
@@ -256,28 +254,24 @@ describe("vertical slider hook tests", () => {
|
|||||||
assertPosition(172);
|
assertPosition(172);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isTouchSupported()) {
|
it("moves the slider with touch events.", () => {
|
||||||
it("moves the slider with touch events.", () => {
|
assertPosition(0);
|
||||||
assertPosition(0);
|
|
||||||
|
|
||||||
triggerTouchEvent("touchstart", 86, 53);
|
triggerTouchEvent("touchstart", 86, 53);
|
||||||
assertPosition(0);
|
assertPosition(0);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 150, 150);
|
triggerTouchEvent("touchmove", 150, 150);
|
||||||
assertPosition(72);
|
assertPosition(72);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 500, 500);
|
triggerTouchEvent("touchmove", 500, 500);
|
||||||
assertPosition(250);
|
assertPosition(250);
|
||||||
|
|
||||||
triggerTouchEvent("touchmove", 250, 250);
|
triggerTouchEvent("touchmove", 250, 250);
|
||||||
assertPosition(172);
|
assertPosition(172);
|
||||||
|
|
||||||
triggerTouchEvent("touchend", 250, 250);
|
triggerTouchEvent("touchend", 250, 250);
|
||||||
assertPosition(172);
|
assertPosition(172);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
console.log("Skipping Unsupported Touch Event Tests");
|
|
||||||
}
|
|
||||||
|
|
||||||
it("moves the slider with mouse wheel scrolling", () => {
|
it("moves the slider with mouse wheel scrolling", () => {
|
||||||
assertPosition(0);
|
assertPosition(0);
|
||||||
|
|||||||
+24
@@ -1,3 +1,27 @@
|
|||||||
export function minmax(number: number, min: number, max: number) {
|
export function minmax(number: number, min: number, max: number) {
|
||||||
return Math.min(max, Math.max(min, number));
|
return Math.min(max, Math.max(min, number));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isTouchEvent(event: Event): event is TouchEvent {
|
||||||
|
return "touches" in event;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLeftMouseButton(buttonsValue: number) {
|
||||||
|
return buttonsValue === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractEventCoordinates(event: MouseEvent | TouchEvent): {
|
||||||
|
clientX: number;
|
||||||
|
clientY: number;
|
||||||
|
} {
|
||||||
|
if (isTouchEvent(event)) {
|
||||||
|
return {
|
||||||
|
clientX: event.touches[0].clientX,
|
||||||
|
clientY: event.touches[0].clientY,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
clientX: event.clientX,
|
||||||
|
clientY: event.clientY,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user