UNPKG

@react-three/xr

Version:

VR/AR for react-three-fiber

119 lines (118 loc) 4.11 kB
import { PointerEvent } from '@pmndrs/pointer-events'; import { useEffect, useRef } from 'react'; import { useXRInputSourceState, useXRInputSourceStateContext } from '../input.js'; import { useXRSpace } from '../space.js'; import { useXR } from '../xr.js'; const eventTranslations = { onBlur: 'pointerleave', onHover: 'pointerenter', onMove: 'pointermove', onSelect: { type: 'click', filter: (e) => e.pointerType === 'ray', }, onSelectEnd: { type: 'pointerup', filter: (e) => e.pointerType === 'ray', }, onSelectStart: { type: 'pointerdown', filter: (e) => e.pointerType === 'ray', }, onSqueeze: { type: 'click', filter: (e) => e.pointerType === 'grab', }, onSqueezeEnd: { type: 'pointerup', filter: (e) => e.pointerType === 'grab', }, onSqueezeStart: { type: 'pointerdown', filter: (e) => e.pointerType === 'grab', }, }; /** * @deprecated Use normal react-three/fiber event listeners instead (e.g. `<mesh onClick={...} />`) */ export function useInteraction(ref, type, handler) { const handlerRef = useRef(handler); handlerRef.current = handler; useEffect(() => { const { current } = ref; if (current == null) { return; } const translation = eventTranslations[type]; const fn = typeof translation === 'string' ? (event) => handlerRef.current?.({ intersection: event, intersections: [event], target: event.pointerState }) : (event) => { if (event instanceof PointerEvent && !translation.filter(event)) { return; } handlerRef.current?.({ intersection: event, intersections: [event], target: event.pointerState }); }; const eventName = typeof translation === 'string' ? translation : translation.type; current.addEventListener(eventName, fn); return () => current.removeEventListener(eventName, fn); }, [ref, type]); } /** * @deprecated Implement custom listeners instead */ export function useXREvent(type, handler, { handedness } = {}) { const session = useXR((xr) => xr.session); const handlerRef = useRef(handler); handlerRef.current = handler; useEffect(() => { if (session == null) { return; } const fn = (e) => { handlerRef.current?.({ type: e.type, data: e.inputSource, }); }; session.addEventListener(type, fn); return () => session.removeEventListener(type, fn); }, [session, handedness, type]); } export function useXRTransientPointerState(handedness) { return handedness == null ? // eslint-disable-next-line react-hooks/rules-of-hooks useXRInputSourceStateContext('transientPointer') : // eslint-disable-next-line react-hooks/rules-of-hooks useXRInputSourceState('transientPointer', handedness); } /** * Hook for getting the gaze state * * @deprecated use `useXRInputSourceStateContext("gaze")` instead */ export function useXRGazeState() { return useXRInputSourceStateContext('gaze'); } /** * Hook for getting the screen-input state * * @deprecated `useXRInputSourceStateContext("screenInput")` instead */ export function useXRScreenInputState() { return useXRInputSourceStateContext('screenInput'); } export function useXRHandState(handedness) { // eslint-disable-next-line react-hooks/rules-of-hooks return handedness == null ? useXRInputSourceStateContext('hand') : useXRInputSourceState('hand', handedness); } export function useXRControllerState(handedness) { return handedness == null ? // eslint-disable-next-line react-hooks/rules-of-hooks useXRInputSourceStateContext('controller') : // eslint-disable-next-line react-hooks/rules-of-hooks useXRInputSourceState('controller', handedness); } /** * @deprecated use `useXRSpace` instead */ export const useXRReferenceSpace = useXRSpace;