Skip to content

Commit

Permalink
fix: portal events, update examples
Browse files Browse the repository at this point in the history
  • Loading branch information
drcmda committed Jan 12, 2024
1 parent 191e72b commit a4a31ed
Show file tree
Hide file tree
Showing 19 changed files with 855 additions and 478 deletions.
28 changes: 14 additions & 14 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@
"serve": "vite preview"
},
"dependencies": {
"@react-spring/core": "^9.6.1",
"@react-spring/three": "^9.6.1",
"@react-three/drei": "^9.74.7",
"@react-spring/core": "^9.7.3",
"@react-spring/three": "^9.7.3",
"@react-three/drei": "^9.93.0",
"@use-gesture/react": "latest",
"@vitejs/plugin-react": "^3.1.0",
"@vitejs/plugin-react": "^4.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-merge-refs": "^2.0.1",
"react-merge-refs": "^2.1.1",
"react-use-refs": "^1.0.1",
"styled-components": "^5.3.6",
"three": "^0.149.0",
"three-stdlib": "^2.21.8",
"styled-components": "^6.1.8",
"three": "^0.160.0",
"three-stdlib": "^2.29.1",
"use-error-boundary": "^2.0.6",
"wouter": "^2.10.0",
"zustand": "^4.3.3"
"wouter": "^2.12.1",
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/styled-components": "^5.1.26",
"@types/react": "^18.2.47",
"@types/styled-components": "^5.1.34",
"@vitejs/plugin-react-refresh": "^1.3.6",
"typescript": "^4.9.5",
"vite": "^4.1.1"
"typescript": "^5.3.3",
"vite": "^5.0.11"
}
}
2 changes: 1 addition & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Demo() {
const { Component } = visibleComponents[compName]

return (
<ErrorBoundary key={compName} fallback={(e: any) => <Error>{e}</Error>}>
<ErrorBoundary key={compName} fallback={(e: any) => <Error>{e.message}</Error>}>
<Component />
</ErrorBoundary>
)
Expand Down
2 changes: 1 addition & 1 deletion example/src/demos/AutoDispose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function Switcher() {
export default function App() {
return (
<Canvas orthographic camera={{ zoom: 100 }}>
<ambientLight />
<ambientLight intensity={Math.PI} />
<Switcher />
</Canvas>
)
Expand Down
6 changes: 3 additions & 3 deletions example/src/demos/ContextMenuOverride.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default function App() {
orthographic
camera={{ zoom: 150, fov: 75, position: [0, 0, 25] }}
onPointerMissed={() => console.log('canvas.missed')}>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[10, 10, 10]} />
<mesh
scale={[2, 2, 2]}
position={[1, 0, 0]}
Expand All @@ -19,7 +19,7 @@ export default function App() {
set((value) => !value)
}}
onPointerMissed={() => console.log('mesh.missed')}>
<boxBufferGeometry args={[1, 1, 1]} />
<boxGeometry args={[1, 1, 1]} />
<meshPhysicalMaterial color={state ? 'hotpink' : 'blue'} />
</mesh>
</Canvas>
Expand Down
6 changes: 3 additions & 3 deletions example/src/demos/Gestures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ function Obj({ scale = 1, z = 0, opacity = 1 }) {
export default function App() {
return (
<Canvas>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<ambientLight intensity={0.5 * Math.PI} />
<spotLight decay={0} position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight decay={0} position={[-10, -10, -10]} />
<Obj z={-1} scale={0.5} />
<Obj opacity={0.8} />
</Canvas>
Expand Down
2 changes: 1 addition & 1 deletion example/src/demos/Gltf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function Test() {
export default function App() {
return (
<Canvas>
<ambientLight />
<ambientLight intensity={Math.PI} />
<Suspense fallback={null}>
<Test />
</Suspense>
Expand Down
6 changes: 3 additions & 3 deletions example/src/demos/MultiView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ const App = () => (
function Scene({ children, controls = true, preset }: any) {
return (
<Bounds fit clip observe>
<ambientLight intensity={1} />
<pointLight position={[20, 30, 10]} />
<pointLight position={[-10, -10, -10]} color="blue" />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[20, 30, 10]} />
<pointLight decay={0} position={[-10, -10, -10]} color="blue" />
<Soda scale={3} position={[-1, -0.75, 1]} />
<Soda scale={3} position={[1, -0.75, 1]} />
<Soda scale={3} position={[0, -0.75, 0]} />
Expand Down
6 changes: 3 additions & 3 deletions example/src/demos/Portals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export function Lights() {
return (
<>
<color attach="background" args={['#f0f0f0']} />
<ambientLight intensity={1} />
<pointLight position={[20, 30, 10]} />
<pointLight position={[-10, -10, -10]} color="blue" />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[20, 30, 10]} />
<pointLight decay={0} position={[-10, -10, -10]} color="blue" />
</>
)
}
Expand Down
6 changes: 3 additions & 3 deletions example/src/demos/ResetProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ function Scene() {

return (
<>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} intensity={2} />
<pointLight position={[-10, -10, -10]} color="red" intensity={4} />
<ambientLight intensity={0.5 * Math.PI} />
<pointLight decay={0} position={[10, 10, 10]} intensity={2} />
<pointLight decay={0} position={[-10, -10, -10]} color="red" intensity={4} />

<mesh
scale={hovered ? 1.25 : 1}
Expand Down
4 changes: 2 additions & 2 deletions example/src/demos/StopPropagation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ function Plane({ stop = false, color, position }: any) {
const App = () => (
<Canvas camera={{ fov: 75, position: [0, 0, -2.25] }}>
<Suspense fallback={null}>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[10, 10, 10]} />
<Plane color="lightblue" position={[0.5, 0, -1]} />
<Plane stop color="aquamarine" position={[0, 0, -0.5]} />
<Plane color="hotpink" position={[-0.5, 0, 0]} />
Expand Down
4 changes: 2 additions & 2 deletions example/src/demos/SuspenseAndErrors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export default function App() {
}, [])
return (
<Canvas orthographic camera={{ position: [10, 10, 10], zoom: 100 }}>
<ambientLight />
<pointLight position={[10, 10, 5]} intensity={2} />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[10, 10, 5]} intensity={2} />
<mesh>
<boxGeometry />
<meshStandardMaterial color="orange" />
Expand Down
2 changes: 1 addition & 1 deletion example/src/demos/SuspenseMaterial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function App() {
const [arg, inc] = useReducer((x) => x + 1, 0)
return (
<Canvas>
<ambientLight />
<ambientLight intensity={Math.PI} />
<directionalLight />
<mesh onClick={inc}>
<sphereGeometry args={[1, 64, 32]} />
Expand Down
55 changes: 33 additions & 22 deletions example/src/demos/Test.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
import * as THREE from 'three'
import React, { useState, useEffect, useReducer } from 'react'
import * as React from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls, Hud } from '@react-three/drei'

function Test() {
const [o1] = useState(
() => new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 'hotpink' })),
)
const [o2] = useState(
() => new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 'aquamarine' })),
function Box({ color = 'orange', ...props }) {
const ref = React.useRef<THREE.Mesh>(null!)
const [hovered, hover] = React.useState(false)
const [clicked, click] = React.useState(false)
useFrame((state, delta) => (ref.current.rotation.x += delta))
return (
<mesh
{...props}
ref={ref}
scale={clicked ? 1.5 : 1}
onClick={() => click(!clicked)}
onPointerOver={(event) => (event.stopPropagation(), hover(true))}
onPointerOut={() => hover(false)}>
<boxGeometry />
<meshStandardMaterial color={hovered ? 'hotpink' : color} />
</mesh>
)
const [which, toggle] = useReducer((state) => !state, true)
useEffect(() => {
const interval = setInterval(toggle, 1000)
return () => clearInterval(interval)
}, [])

useFrame((state) => {
//console.log(state.pointer.x)
})

return <primitive object={which ? o1 : o2} />
}

export default function App() {
const [foo, bar] = useState(0)
useEffect(() => {
setTimeout(() => bar(1), 1000)
const [visible, set] = React.useState(true)
React.useEffect(() => {
setTimeout(() => set(false), 2000)
setTimeout(() => set(true), 4000)
}, [])
return (
<Canvas>
<Test />
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Box position={[-1.2, 0, 0]} />
<Hud>
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
{visible && <Box color="skyblue" position={[1.2, 0, 0]} />}
</Hud>
<OrbitControls />
</Canvas>
)
}
6 changes: 3 additions & 3 deletions example/src/demos/ViewTracking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ export default function App() {
function Scene() {
return (
<>
<ambientLight intensity={1} />
<pointLight position={[20, 30, 10]} intensity={1} />
<pointLight position={[-10, -10, -10]} color="blue" />
<ambientLight intensity={Math.PI} />
<pointLight decay={0} position={[20, 30, 10]} intensity={1} />
<pointLight decay={0} position={[-10, -10, -10]} color="blue" />
<Environment preset="dawn" />
</>
)
Expand Down
4 changes: 2 additions & 2 deletions example/src/demos/Viewcube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ function Viewcube() {
))}
<boxGeometry args={[80, 80, 80]} />
</mesh>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} intensity={0.5} />
<ambientLight intensity={0.5 * Math.PI} />
<pointLight decay={0} position={[10, 10, 10]} intensity={0.5} />
</group>,
scene,
{ camera, events: { priority: events.priority + 1 } },
Expand Down
16 changes: 10 additions & 6 deletions packages/fiber/src/core/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DefaultEventPriority } from 'react-reconciler/constants'
import {
is,
prepare,
findInitialRoot,
diffProps,
DiffSet,
applyProps,
Expand Down Expand Up @@ -196,9 +197,10 @@ function createRenderer<TCanvas>(_roots: Map<TCanvas, Root>, _getEventPriority?:
detach(parentInstance, child, child.__r3f.attach)
} else if (child.isObject3D && parentInstance.isObject3D) {
parentInstance.remove(child)
// Remove interactivity
// @ts-ignore
// Remove interactivity on the initial root
if (child.__r3f?.root) {
removeInteractivity(child.__r3f.root, child as unknown as THREE.Object3D)
removeInteractivity(findInitialRoot(child), child as unknown as THREE.Object3D)
}
}

Expand Down Expand Up @@ -278,9 +280,9 @@ function createRenderer<TCanvas>(_roots: Map<TCanvas, Root>, _getEventPriority?:
}
appendChild(parent, newInstance)

// Re-bind event handlers
// Re-bind event handlers on the initial root
if (newInstance.raycast && newInstance.__r3f.eventCount) {
const rootState = newInstance.__r3f.root.getState()
const rootState = findInitialRoot(newInstance).getState()
rootState.internal.interaction.push(newInstance as unknown as THREE.Object3D)
}

Expand Down Expand Up @@ -391,10 +393,12 @@ function createRenderer<TCanvas>(_roots: Map<TCanvas, Root>, _getEventPriority?:
},
commitMount(instance, _type, _props, _int) {
// https://github.com/facebook/react/issues/20271
// This will make sure events are only added once to the central container
// This will make sure events are only added once to the central container on the initial root
const localState = (instance.__r3f ?? {}) as LocalState
if (instance.raycast && localState.handlers && localState.eventCount) {
instance.__r3f.root.getState().internal.interaction.push(instance as unknown as THREE.Object3D)
findInitialRoot(instance)
.getState()
.internal.interaction.push(instance as unknown as THREE.Object3D)
}
},
getPublicInstance: (instance) => instance!,
Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export type RootState = {
setFrameloop: (frameloop?: 'always' | 'demand' | 'never') => void
/** When the canvas was clicked but nothing was hit */
onPointerMissed?: (event: MouseEvent) => void
/** If this state model is layerd (via createPortal) then this contains the previous layer */
/** If this state model is layered (via createPortal) then this contains the previous layer */
previousRoot?: UseBoundStore<RootState, StoreApi<RootState>>
/** Internals */
internal: InternalState
Expand Down
19 changes: 15 additions & 4 deletions packages/fiber/src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ export function calculateDpr(dpr: Dpr) {
export const getRootState = (obj: THREE.Object3D): RootState | undefined =>
(obj as unknown as Instance).__r3f?.root.getState()

/**
* Returns the instances initial (outmost) root
*/
export function findInitialRoot(child: Instance) {
let root = child.__r3f.root
while (root.getState().previousRoot) root = root.getState().previousRoot!
return root
}

export type EquConfig = {
/** Compare arrays by reference equality a === b (default), or by shallow equality */
arrays?: 'reference' | 'shallow'
Expand Down Expand Up @@ -417,12 +426,14 @@ export function applyProps(instance: Instance, data: InstanceProps | DiffSet) {
invalidateInstance(instance)
}

if (localState.parent && rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
if (localState.parent && instance.raycast && prevHandlers !== localState.eventCount) {
// Get the initial root state's internals
const internal = findInitialRoot(instance).getState().internal
// Pre-emptively remove the instance from the interaction manager
const index = rootState.internal.interaction.indexOf(instance as unknown as THREE.Object3D)
if (index > -1) rootState.internal.interaction.splice(index, 1)
const index = internal.interaction.indexOf(instance as unknown as THREE.Object3D)
if (index > -1) internal.interaction.splice(index, 1)
// Add the instance to the interaction manager only when it has handlers
if (localState.eventCount) rootState.internal.interaction.push(instance as unknown as THREE.Object3D)
if (localState.eventCount) internal.interaction.push(instance as unknown as THREE.Object3D)
}

// Call the update lifecycle when it is being updated, but only when it is part of the scene.
Expand Down
Loading

0 comments on commit a4a31ed

Please sign in to comment.