Skip to content

Commit

Permalink
chore: restore native events export
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyJasonBennett committed Aug 10, 2024
1 parent 6d1aab5 commit 971ffd5
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 63 deletions.
60 changes: 0 additions & 60 deletions packages/fiber/src/core/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,63 +531,3 @@ export function createEvents(store: UseBoundStore<RootState>) {

return { handlePointer }
}

const DOM_EVENTS = {
onClick: ['click', false],
onContextMenu: ['contextmenu', false],
onDoubleClick: ['dblclick', false],
onWheel: ['wheel', true],
onPointerDown: ['pointerdown', true],
onPointerUp: ['pointerup', true],
onPointerLeave: ['pointerleave', true],
onPointerMove: ['pointermove', true],
onPointerCancel: ['pointercancel', true],
onLostPointerCapture: ['lostpointercapture', true],
} as const

/** Default R3F event manager for web */
export function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement> {
const { handlePointer } = createEvents(store)

return {
priority: 1,
enabled: true,
compute(event: DomEvent, state: RootState, previous?: RootState) {
// https://github.com/pmndrs/react-three-fiber/pull/782
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1)
state.raycaster.setFromCamera(state.pointer, state.camera)
},

connected: undefined,
handlers: Object.keys(DOM_EVENTS).reduce(
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
{},
) as unknown as Events,
update: () => {
const { events, internal } = store.getState()
if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current)
},
connect: (target: HTMLElement) => {
const { set, events } = store.getState()
events.disconnect?.()
set((state) => ({ events: { ...state.events, connected: target } }))
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
const [eventName, passive] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
target.addEventListener(eventName, event, { passive })
})
},
disconnect: () => {
const { set, events } = store.getState()
if (events.connected) {
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
if (events && events.connected instanceof HTMLElement) {
const [eventName] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
events.connected.removeEventListener(eventName, event)
}
})
set((state) => ({ events: { ...state.events, connected: undefined } }))
}
},
}
}
3 changes: 2 additions & 1 deletion packages/fiber/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ export type {
RootState,
} from './core/store'
export type { ThreeEvent, Events, EventManager, ComputeFunction } from './core/events'
export { createEvents, createPointerEvents as events } from './core/events'
export { createEvents } from './core/events'
export type { ObjectMap, Camera } from './core/utils'
export * from './web/Canvas'
export { createPointerEvents as events, createPointerEvents } from './web/events'
export type { GlobalRenderCallback, GlobalEffectType } from './core/loop'
export * from './core'
4 changes: 3 additions & 1 deletion packages/fiber/src/native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ export type {
RootState,
} from './core/store'
export type { ThreeEvent, Events, EventManager, ComputeFunction } from './core/events'
export { createEvents, createPointerEvents as events } from './core/events'
export { createEvents } from './core/events'
export type { ObjectMap, Camera } from './core/utils'
export * from './native/Canvas'
export { createTouchEvents as events } from './native/events'
export { createPointerEvents } from './web/events'
export type { GlobalRenderCallback, GlobalEffectType } from './core/loop'
export * from './core'

Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/src/native/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ExpoWebGLRenderingContext, GLView } from 'expo-gl'
import { useContextBridge, FiberProvider } from 'its-fine'
import { SetBlock, Block, ErrorBoundary, useMutableCallback } from '../core/utils'
import { extend, createRoot, unmountComponentAtNode, RenderProps, ReconcilerRoot } from '../core'
import { createPointerEvents } from '../core/events'
import { createPointerEvents } from '../web/events'
import { RootState, Size } from '../core/store'

export interface CanvasProps extends Omit<RenderProps<HTMLCanvasElement>, 'size' | 'dpr'>, ViewProps {
Expand Down
71 changes: 71 additions & 0 deletions packages/fiber/src/native/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { UseBoundStore } from 'zustand'
import { RootState } from '../core/store'
import { createEvents, DomEvent, EventManager, Events } from '../core/events'
import { type GestureResponderEvent, PanResponder } from 'react-native'

/** Default R3F event manager for react-native */
export function createTouchEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement> {
const { handlePointer } = createEvents(store)

const handleTouch = (event: GestureResponderEvent, name: string): true => {
event.persist()

// Apply offset
;(event as any).nativeEvent.offsetX = event.nativeEvent.locationX
;(event as any).nativeEvent.offsetY = event.nativeEvent.locationY

// Emulate DOM event
const callback = handlePointer(name)
callback(event.nativeEvent as any)

return true
}

const responder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderTerminationRequest: () => true,
onStartShouldSetPanResponderCapture: (e) => handleTouch(e, 'onPointerCapture'),
onPanResponderStart: (e) => handleTouch(e, 'onPointerDown'),
onPanResponderMove: (e) => handleTouch(e, 'onPointerMove'),
onPanResponderEnd: (e, state) => {
handleTouch(e, 'onPointerUp')
if (Math.hypot(state.dx, state.dy) < 20) handleTouch(e, 'onClick')
},
onPanResponderRelease: (e) => handleTouch(e, 'onPointerLeave'),
onPanResponderTerminate: (e) => handleTouch(e, 'onLostPointerCapture'),
onPanResponderReject: (e) => handleTouch(e, 'onLostPointerCapture'),
})

return {
priority: 1,
enabled: true,
compute(event: DomEvent, state: RootState, previous?: RootState) {
// https://github.com/pmndrs/react-three-fiber/pull/782
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1)
state.raycaster.setFromCamera(state.pointer, state.camera)
},

connected: undefined,
handlers: responder.panHandlers as unknown as Events,
update: () => {
const { events, internal } = store.getState()
if (internal.lastEvent?.current && events.handlers) {
handlePointer('onPointerMove')(internal.lastEvent.current)
}
},
connect: () => {
const { set, events } = store.getState()
events.disconnect?.()

set((state) => ({ events: { ...state.events, connected: true } }))
},
disconnect: () => {
const { set } = store.getState()

set((state) => ({ events: { ...state.events, connected: false } }))
},
}
}
63 changes: 63 additions & 0 deletions packages/fiber/src/web/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { UseBoundStore } from 'zustand'
import { RootState } from '../core/store'
import { EventManager, Events, createEvents, DomEvent } from '../core/events'

const DOM_EVENTS = {
onClick: ['click', false],
onContextMenu: ['contextmenu', false],
onDoubleClick: ['dblclick', false],
onWheel: ['wheel', true],
onPointerDown: ['pointerdown', true],
onPointerUp: ['pointerup', true],
onPointerLeave: ['pointerleave', true],
onPointerMove: ['pointermove', true],
onPointerCancel: ['pointercancel', true],
onLostPointerCapture: ['lostpointercapture', true],
} as const

/** Default R3F event manager for web */
export function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement> {
const { handlePointer } = createEvents(store)

return {
priority: 1,
enabled: true,
compute(event: DomEvent, state: RootState, previous?: RootState) {
// https://github.com/pmndrs/react-three-fiber/pull/782
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1)
state.raycaster.setFromCamera(state.pointer, state.camera)
},

connected: undefined,
handlers: Object.keys(DOM_EVENTS).reduce(
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
{},
) as unknown as Events,
update: () => {
const { events, internal } = store.getState()
if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current)
},
connect: (target: HTMLElement) => {
const { set, events } = store.getState()
events.disconnect?.()
set((state) => ({ events: { ...state.events, connected: target } }))
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
const [eventName, passive] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
target.addEventListener(eventName, event, { passive })
})
},
disconnect: () => {
const { set, events } = store.getState()
if (events.connected) {
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
if (events && events.connected instanceof HTMLElement) {
const [eventName] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
events.connected.removeEventListener(eventName, event)
}
})
set((state) => ({ events: { ...state.events, connected: undefined } }))
}
},
}
}

0 comments on commit 971ffd5

Please sign in to comment.