Skip to content

Commit

Permalink
Merge pull request #254 from VLADISLAW9/#244
Browse files Browse the repository at this point in the history
#244 add use pointer lock
  • Loading branch information
debabin authored Nov 12, 2024
2 parents 6876a7a + 21738a4 commit f4ae93d
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export * from './usePageLeave/usePageLeave';
export * from './usePaint/usePaint';
export * from './useParallax/useParallax';
export * from './usePermission/usePermission';
export * from './usePointerLock/usePointerLock';
export * from './usePreferredColorScheme/usePreferredColorScheme';
export * from './usePreferredContrast/usePreferredContrast';
export * from './usePreferredDark/usePreferredDark';
Expand Down
30 changes: 30 additions & 0 deletions src/hooks/usePointerLock/usePointerLock.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { CSSProperties } from 'react';

import { usePointerLock } from './usePointerLock';

const Demo = () => {
const { lock, unlock } = usePointerLock();

const containerStyle: CSSProperties = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
};

const elementStyle: CSSProperties = {
border: '1px solid #949CE0',
color: '#949CE0',
padding: '25px',
cursor: 'move'
};

return (
<div style={containerStyle}>
<div style={elementStyle} onMouseDownCapture={lock} onMouseUpCapture={unlock}>
Move me
</div>
</div>
);
};

export default Demo;
91 changes: 91 additions & 0 deletions src/hooks/usePointerLock/usePointerLock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { MouseEvent, RefObject } from 'react';
import { useEffect, useState } from 'react';

type UsePointerLockTarget = RefObject<Element | undefined | null>;

interface UsePointerLockReturn {
supported: boolean;
element?: Element;
lock: (event: MouseEvent<Element> | Event) => void;
unlock: () => boolean;
}

/**
* @name usePointerLock
* @description Hook that provides reactive pointer lock
* @category Sensors
*
* @param {UsePointerLockTarget} target The target element for the pointer lock
* @returns {UsePointerLockReturn} An object containing the pointer lock element and functions to interact with the pointer lock
*
* @example
* const { supported, lock, unlock, element } = usePointerLock();
*/

export const usePointerLock = (target?: UsePointerLockTarget): UsePointerLockReturn => {
const supported = !!document && 'pointerLockElement' in document;

const [element, setElement] = useState<Element>();

useEffect(() => {
if (!supported) return;

const handlePointerLockChange = () => {
if (!supported) return;

const currentElement = document.pointerLockElement ?? element;

if (currentElement && currentElement === element) {
setElement(document.pointerLockElement as Element);
}
};
const handlePointerLockError = () => {
if (!supported) return;

const currentElement = document.pointerLockElement ?? element;

if (currentElement && currentElement === element) {
const action = document.pointerLockElement ? 'release' : 'acquire';

throw new Error(`Failed to ${action} pointer lock.`);
}
};

document.addEventListener('pointerlockchange', handlePointerLockChange);
document.addEventListener('pointerlockerror', handlePointerLockError);

return () => {
document.removeEventListener('pointerlockchange', handlePointerLockChange);
document.removeEventListener('pointerlockerror', handlePointerLockError);
};
}, [supported, element]);

const lock = (event: MouseEvent<Element> | Event) => {
if (!supported) return;

const element = event instanceof Event ? target?.current : event.currentTarget;

if (!element) return;

element.requestPointerLock();

setElement(element);
};

const unlock = () => {
if (!element) return false;

document.exitPointerLock();

setElement(undefined);

return true;
};

return {
supported,
element,
lock,
unlock
};
};

0 comments on commit f4ae93d

Please sign in to comment.