Skip to content

Commit 9637418

Browse files
committed
Fix bugs
1 parent d60d3c5 commit 9637418

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

packages/design-system/src/components/primitives/numeric-gesture-control.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ type NumericScrubState = {
8181
cursor?: SVGElement;
8282
direction: NumericScrubDirection;
8383
status: "idle" | "scrubbing";
84+
/**
85+
* On windows it's possible that requestPointerLock is already called,
86+
* but document.pointerLockElement is not updated yet.
87+
*/
88+
pointerCaptureRequested: boolean;
8489
};
8590

8691
const getValueDefault = (
@@ -168,6 +173,7 @@ export const numericScrubControl = (
168173
cursor: undefined,
169174
direction,
170175
status: "idle",
176+
pointerCaptureRequested: false,
171177
};
172178

173179
// The appearance of the custom cursor is delayed, so we need to track the mouse position
@@ -208,9 +214,7 @@ export const numericScrubControl = (
208214
if (!(event instanceof PointerEvent)) {
209215
return;
210216
}
211-
212-
const { type, movementY, movementX } = event;
213-
const movement = direction === "horizontal" ? movementX : -movementY;
217+
const { type } = event;
214218

215219
switch (type) {
216220
case "pointerup": {
@@ -296,6 +300,11 @@ export const numericScrubControl = (
296300
break;
297301
}
298302
case "pointermove": {
303+
const { movementY, movementX } = event;
304+
305+
const movement = direction === "horizontal" ? movementX : -movementY;
306+
307+
// console.log("movement", movement, event);
299308
mouseState.x = event.clientX;
300309
mouseState.y = event.clientY;
301310

@@ -328,12 +337,12 @@ export const numericScrubControl = (
328337
// When cursor moves out of the browser window
329338
// we want it to come back from the other side
330339
const top = wrapAround(
331-
Number.parseFloat(state.cursor.style.top) + event.movementY,
340+
Number.parseFloat(state.cursor.style.top) + movementY,
332341
0,
333342
globalThis.innerHeight
334343
);
335344
const left = wrapAround(
336-
Number.parseFloat(state.cursor.style.left) + event.movementX,
345+
Number.parseFloat(state.cursor.style.left) + movementX,
337346
0,
338347
globalThis.innerWidth
339348
);
@@ -345,11 +354,17 @@ export const numericScrubControl = (
345354
}
346355
break;
347356
}
357+
348358
case "pointercancel": {
349359
cleanup();
350360
break;
351361
}
362+
352363
case "lostpointercapture": {
364+
if (state.pointerCaptureRequested) {
365+
break;
366+
}
367+
353368
if (document.pointerLockElement === null) {
354369
cleanup();
355370
}
@@ -389,6 +404,8 @@ export const numericScrubControl = (
389404

390405
const requestPointerLockSafe = async (targetNode: HTMLElement | SVGElement) => {
391406
try {
407+
// await targetNode.requestPointerLock();
408+
392409
return await targetNode.requestPointerLock({
393410
unadjustedMovement: true,
394411
});
@@ -417,18 +434,27 @@ const requestPointerLock = (
417434
disposeOnCleanup(() => {
418435
targetNode.setPointerCapture(pointerId);
419436
return () => {
420-
targetNode.releasePointerCapture(pointerId);
437+
if (targetNode.hasPointerCapture(pointerId)) {
438+
targetNode.releasePointerCapture(pointerId);
439+
}
421440
};
422441
});
423442

424443
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
444+
425445
// Safari supports pointer lock well, but the issue lies with the pointer lock banner.
426446
// It shifts the entire page down, which creates a poor user experience.
427447
if (!isSafari) {
428448
disposeOnCleanup(() => {
429449
const timerId = window.setTimeout(() => {
450+
state.pointerCaptureRequested = true;
430451
requestPointerLockSafe(targetNode)
431452
.then(() => {
453+
if (targetNode.hasPointerCapture(pointerId)) {
454+
targetNode.releasePointerCapture(pointerId);
455+
}
456+
457+
state.pointerCaptureRequested = false;
432458
const cursorNode =
433459
(targetNode.ownerDocument.querySelector(
434460
"#numeric-guesture-control-cursor"
@@ -466,17 +492,23 @@ const requestPointerLock = (
466492
}
467493
})
468494
.catch((error) => {
495+
state.pointerCaptureRequested = false;
469496
console.error("requestPointerLock", error);
470497
});
471498
}, scrubTimeout);
472499

473500
return () => {
501+
state.pointerCaptureRequested = false;
502+
474503
if (state.cursor) {
475504
state.cursor.remove();
476505
state.cursor = undefined;
477506
}
478507

479-
targetNode.ownerDocument.exitPointerLock();
508+
if (targetNode.ownerDocument.pointerLockElement === targetNode) {
509+
targetNode.ownerDocument.exitPointerLock();
510+
}
511+
480512
clearTimeout(timerId);
481513
};
482514
});

0 commit comments

Comments
 (0)