Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ type NumericScrubState = {
cursor?: SVGElement;
direction: NumericScrubDirection;
status: "idle" | "scrubbing";
/**
* On Windows, requestPointerLock might already be called,
* but document.pointerLockElement may not have been updated yet.
*/
pointerCaptureRequested: boolean;
};

const getValueDefault = (
Expand Down Expand Up @@ -143,6 +148,14 @@ const addCursorUI = (direction: NumericScrubDirection) => {
};
};

const isWindows = () => {
if (typeof window !== "undefined") {
return navigator.platform.toLowerCase().includes("win");
}

return false;
};

export const numericScrubControl = (
targetNode: HTMLElement | SVGElement,
options: NumericScrubOptions
Expand All @@ -168,6 +181,7 @@ export const numericScrubControl = (
cursor: undefined,
direction,
status: "idle",
pointerCaptureRequested: false,
};

// The appearance of the custom cursor is delayed, so we need to track the mouse position
Expand All @@ -182,6 +196,8 @@ export const numericScrubControl = (
task();
}

cleanupTasks.length = 0;

if (state.status === "scrubbing") {
state.status = "idle";
onStatusChange?.("idle");
Expand Down Expand Up @@ -209,8 +225,7 @@ export const numericScrubControl = (
return;
}

const { type, movementY, movementX } = event;
const movement = direction === "horizontal" ? movementX : -movementY;
const { type } = event;

switch (type) {
case "pointerup": {
Expand All @@ -230,6 +245,8 @@ export const numericScrubControl = (
break;
}
case "pointerdown": {
cleanup();

if (
event.target &&
shouldHandleEvent?.(event.target as Node) === false
Expand Down Expand Up @@ -296,6 +313,11 @@ export const numericScrubControl = (
break;
}
case "pointermove": {
const { movementY, movementX } = event;

const movement = direction === "horizontal" ? movementX : -movementY;

// console.log("movement", movement, event);
mouseState.x = event.clientX;
mouseState.y = event.clientY;

Expand Down Expand Up @@ -328,12 +350,12 @@ export const numericScrubControl = (
// When cursor moves out of the browser window
// we want it to come back from the other side
const top = wrapAround(
Number.parseFloat(state.cursor.style.top) + event.movementY,
Number.parseFloat(state.cursor.style.top) + movementY,
0,
globalThis.innerHeight
);
const left = wrapAround(
Number.parseFloat(state.cursor.style.left) + event.movementX,
Number.parseFloat(state.cursor.style.left) + movementX,
0,
globalThis.innerWidth
);
Expand All @@ -345,11 +367,21 @@ export const numericScrubControl = (
}
break;
}

case "pointercancel": {
cleanup();
break;
}

case "lostpointercapture": {
// On Mac if this happens it's near 100% probability that pointerup event will not fire
if (isWindows()) {
// This Windows fix cause other bug, in some cases pointerup event will not fire
if (state.pointerCaptureRequested) {
break;
}
}

if (document.pointerLockElement === null) {
cleanup();
}
Expand Down Expand Up @@ -417,18 +449,36 @@ const requestPointerLock = (
disposeOnCleanup(() => {
targetNode.setPointerCapture(pointerId);
return () => {
targetNode.releasePointerCapture(pointerId);
if (targetNode.hasPointerCapture(pointerId)) {
targetNode.releasePointerCapture(pointerId);
}
};
});

let isDisposed = false;
disposeOnCleanup(() => () => {
isDisposed = true;
});

const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

// Safari supports pointer lock well, but the issue lies with the pointer lock banner.
// It shifts the entire page down, which creates a poor user experience.
if (!isSafari) {
disposeOnCleanup(() => {
const timerId = window.setTimeout(() => {
state.pointerCaptureRequested = true;
requestPointerLockSafe(targetNode)
.then(() => {
state.pointerCaptureRequested = false;

if (isDisposed) {
if (targetNode.ownerDocument.pointerLockElement === targetNode) {
targetNode.ownerDocument.exitPointerLock();
}
return;
}

const cursorNode =
(targetNode.ownerDocument.querySelector(
"#numeric-guesture-control-cursor"
Expand Down Expand Up @@ -466,17 +516,23 @@ const requestPointerLock = (
}
})
.catch((error) => {
state.pointerCaptureRequested = false;
console.error("requestPointerLock", error);
});
}, scrubTimeout);

return () => {
state.pointerCaptureRequested = false;

if (state.cursor) {
state.cursor.remove();
state.cursor = undefined;
}

targetNode.ownerDocument.exitPointerLock();
if (targetNode.ownerDocument.pointerLockElement === targetNode) {
targetNode.ownerDocument.exitPointerLock();
}

clearTimeout(timerId);
};
});
Expand Down
Loading