@react-three/fiber 8.6.2 → 8.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
- import * as React from 'react';
2
- import type { Options as ResizeOptions } from 'react-use-measure';
3
- import { RenderProps } from '../core';
4
- export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
- children: React.ReactNode;
6
- fallback?: React.ReactNode;
7
- resize?: ResizeOptions;
8
- eventSource?: HTMLElement;
9
- eventPrefix?: 'offset' | 'client' | 'page' | 'layer' | 'screen';
10
- }
11
- export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
1
+ import * as React from 'react';
2
+ import type { Options as ResizeOptions } from 'react-use-measure';
3
+ import { RenderProps } from '../core';
4
+ export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ fallback?: React.ReactNode;
7
+ resize?: ResizeOptions;
8
+ eventSource?: HTMLElement | React.MutableRefObject<HTMLElement>;
9
+ eventPrefix?: 'offset' | 'client' | 'page' | 'layer' | 'screen';
10
+ }
11
+ export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
@@ -1,4 +1,4 @@
1
- import { UseBoundStore } from 'zustand';
2
- import { RootState } from '../core/store';
3
- import { EventManager } from '../core/events';
4
- export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
1
+ import { UseBoundStore } from 'zustand';
2
+ import { RootState } from '../core/store';
3
+ import { EventManager } from '../core/events';
4
+ export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
@@ -12,6 +12,7 @@ var threeTypes = /*#__PURE__*/Object.freeze({
12
12
 
13
13
  var _window$document, _window$navigator;
14
14
  const isOrthographicCamera = def => def && def.isOrthographicCamera;
15
+ const isRef = obj => obj && obj.hasOwnProperty('current');
15
16
  /**
16
17
  * An SSR-friendly useLayoutEffect.
17
18
  *
@@ -476,9 +477,7 @@ function removeInteractivity(store, object) {
476
477
  });
477
478
  }
478
479
  function createEvents(store) {
479
- const temp = new THREE.Vector3();
480
480
  /** Calculates delta */
481
-
482
481
  function calculateDistance(event) {
483
482
  const {
484
483
  internal
@@ -578,108 +577,113 @@ function createEvents(store) {
578
577
 
579
578
 
580
579
  function handleIntersects(intersections, event, delta, callback) {
581
- const {
582
- raycaster,
583
- pointer,
584
- camera,
585
- internal
586
- } = store.getState(); // If anything has been found, forward it to the event listeners
587
-
580
+ // If anything has been found, forward it to the event listeners
588
581
  if (intersections.length) {
589
- const unprojectedPoint = temp.set(pointer.x, pointer.y, 0).unproject(camera);
590
582
  const localState = {
591
583
  stopped: false
592
584
  };
593
585
 
594
586
  for (const hit of intersections) {
595
- const hasPointerCapture = id => {
596
- var _internal$capturedMap, _internal$capturedMap2;
587
+ const state = getRootState(hit.object);
597
588
 
598
- return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
599
- };
589
+ if (state) {
590
+ const {
591
+ raycaster,
592
+ pointer,
593
+ camera,
594
+ internal
595
+ } = state;
596
+ const unprojectedPoint = new THREE.Vector3(pointer.x, pointer.y, 0).unproject(camera);
597
+
598
+ const hasPointerCapture = id => {
599
+ var _internal$capturedMap, _internal$capturedMap2;
600
600
 
601
- const setPointerCapture = id => {
602
- const captureData = {
603
- intersection: hit,
604
- target: event.target
601
+ return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
605
602
  };
606
603
 
607
- if (internal.capturedMap.has(id)) {
608
- // if the pointerId was previously captured, we add the hit to the
609
- // event capturedMap.
610
- internal.capturedMap.get(id).set(hit.eventObject, captureData);
611
- } else {
612
- // if the pointerId was not previously captured, we create a map
613
- // containing the hitObject, and the hit. hitObject is used for
614
- // faster access.
615
- internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
616
- } // Call the original event now
617
- event.target.setPointerCapture(id);
618
- };
604
+ const setPointerCapture = id => {
605
+ const captureData = {
606
+ intersection: hit,
607
+ target: event.target
608
+ };
609
+
610
+ if (internal.capturedMap.has(id)) {
611
+ // if the pointerId was previously captured, we add the hit to the
612
+ // event capturedMap.
613
+ internal.capturedMap.get(id).set(hit.eventObject, captureData);
614
+ } else {
615
+ // if the pointerId was not previously captured, we create a map
616
+ // containing the hitObject, and the hit. hitObject is used for
617
+ // faster access.
618
+ internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
619
+ } // Call the original event now
620
+ event.target.setPointerCapture(id);
621
+ };
619
622
 
620
- const releasePointerCapture = id => {
621
- const captures = internal.capturedMap.get(id);
623
+ const releasePointerCapture = id => {
624
+ const captures = internal.capturedMap.get(id);
622
625
 
623
- if (captures) {
624
- releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
625
- }
626
- }; // Add native event props
626
+ if (captures) {
627
+ releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
628
+ }
629
+ }; // Add native event props
627
630
 
628
631
 
629
- let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
632
+ let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
630
633
 
631
- for (let prop in event) {
632
- let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
633
- // called as event.nativeEvent.fn()
634
+ for (let prop in event) {
635
+ let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
636
+ // called as event.nativeEvent.fn()
634
637
 
635
- if (typeof property !== 'function') extractEventProps[prop] = property;
636
- }
638
+ if (typeof property !== 'function') extractEventProps[prop] = property;
639
+ }
637
640
 
638
- let raycastEvent = { ...hit,
639
- ...extractEventProps,
640
- pointer,
641
- intersections,
642
- stopped: localState.stopped,
643
- delta,
644
- unprojectedPoint,
645
- ray: raycaster.ray,
646
- camera: camera,
647
- // Hijack stopPropagation, which just sets a flag
648
- stopPropagation: () => {
649
- // https://github.com/pmndrs/react-three-fiber/issues/596
650
- // Events are not allowed to stop propagation if the pointer has been captured
651
- const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId); // We only authorize stopPropagation...
652
-
653
- if ( // ...if this pointer hasn't been captured
654
- !capturesForPointer || // ... or if the hit object is capturing the pointer
655
- capturesForPointer.has(hit.eventObject)) {
656
- raycastEvent.stopped = localState.stopped = true; // Propagation is stopped, remove all other hover records
657
- // An event handler is only allowed to flush other handlers if it is hovered itself
658
-
659
- if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
660
- // Objects cannot flush out higher up objects that have already caught the event
661
- const higher = intersections.slice(0, intersections.indexOf(hit));
662
- cancelPointer([...higher, hit]);
641
+ let raycastEvent = { ...hit,
642
+ ...extractEventProps,
643
+ pointer,
644
+ intersections,
645
+ stopped: localState.stopped,
646
+ delta,
647
+ unprojectedPoint,
648
+ ray: raycaster.ray,
649
+ camera: camera,
650
+ // Hijack stopPropagation, which just sets a flag
651
+ stopPropagation: () => {
652
+ // https://github.com/pmndrs/react-three-fiber/issues/596
653
+ // Events are not allowed to stop propagation if the pointer has been captured
654
+ const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId); // We only authorize stopPropagation...
655
+
656
+ if ( // ...if this pointer hasn't been captured
657
+ !capturesForPointer || // ... or if the hit object is capturing the pointer
658
+ capturesForPointer.has(hit.eventObject)) {
659
+ raycastEvent.stopped = localState.stopped = true; // Propagation is stopped, remove all other hover records
660
+ // An event handler is only allowed to flush other handlers if it is hovered itself
661
+
662
+ if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
663
+ // Objects cannot flush out higher up objects that have already caught the event
664
+ const higher = intersections.slice(0, intersections.indexOf(hit));
665
+ cancelPointer([...higher, hit]);
666
+ }
663
667
  }
664
- }
665
- },
666
- // there should be a distinction between target and currentTarget
667
- target: {
668
- hasPointerCapture,
669
- setPointerCapture,
670
- releasePointerCapture
671
- },
672
- currentTarget: {
673
- hasPointerCapture,
674
- setPointerCapture,
675
- releasePointerCapture
676
- },
677
- nativeEvent: event
678
- }; // Call subscribers
679
-
680
- callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
681
-
682
- if (localState.stopped === true) break;
668
+ },
669
+ // there should be a distinction between target and currentTarget
670
+ target: {
671
+ hasPointerCapture,
672
+ setPointerCapture,
673
+ releasePointerCapture
674
+ },
675
+ currentTarget: {
676
+ hasPointerCapture,
677
+ setPointerCapture,
678
+ releasePointerCapture
679
+ },
680
+ nativeEvent: event
681
+ }; // Call subscribers
682
+
683
+ callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
684
+
685
+ if (localState.stopped === true) break;
686
+ }
683
687
  }
684
688
  }
685
689
 
@@ -1468,11 +1472,24 @@ const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
1468
1472
  const addTail = callback => createSubs(callback, globalTailEffects);
1469
1473
 
1470
1474
  function run(effects, timestamp) {
1475
+ if (!effects.size) return;
1471
1476
  effects.forEach(({
1472
1477
  callback
1473
1478
  }) => callback(timestamp));
1474
1479
  }
1475
1480
 
1481
+ function flushGlobalEffects(type, timestamp) {
1482
+ switch (type) {
1483
+ case 'before':
1484
+ return run(globalEffects, timestamp);
1485
+
1486
+ case 'after':
1487
+ return run(globalAfterEffects, timestamp);
1488
+
1489
+ case 'tail':
1490
+ return run(globalTailEffects, timestamp);
1491
+ }
1492
+ }
1476
1493
  let subscribers;
1477
1494
  let subscription;
1478
1495
 
@@ -1512,7 +1529,7 @@ function createLoop(roots) {
1512
1529
  running = true;
1513
1530
  repeat = 0; // Run effects
1514
1531
 
1515
- if (globalEffects.size) run(globalEffects, timestamp); // Render all roots
1532
+ flushGlobalEffects('before', timestamp); // Render all roots
1516
1533
 
1517
1534
  roots.forEach(root => {
1518
1535
  var _state$gl$xr;
@@ -1524,11 +1541,11 @@ function createLoop(roots) {
1524
1541
  }
1525
1542
  }); // Run after-effects
1526
1543
 
1527
- if (globalAfterEffects.size) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1544
+ flushGlobalEffects('after', timestamp); // Stop the loop if nothing invalidates it
1528
1545
 
1529
1546
  if (repeat === 0) {
1530
1547
  // Tail call effects, they are called when rendering stops
1531
- if (globalTailEffects.size) run(globalTailEffects, timestamp); // Flag end of operation
1548
+ flushGlobalEffects('tail', timestamp); // Flag end of operation
1532
1549
 
1533
1550
  running = false;
1534
1551
  return cancelAnimationFrame(frame);
@@ -1550,9 +1567,9 @@ function createLoop(roots) {
1550
1567
  }
1551
1568
 
1552
1569
  function advance(timestamp, runGlobalEffects = true, state, frame) {
1553
- if (runGlobalEffects) run(globalEffects, timestamp);
1570
+ if (runGlobalEffects) flushGlobalEffects('before', timestamp);
1554
1571
  if (!state) roots.forEach(root => render$1(timestamp, root.store.getState()));else render$1(timestamp, state, frame);
1555
- if (runGlobalEffects) run(globalAfterEffects, timestamp);
1572
+ if (runGlobalEffects) flushGlobalEffects('after', timestamp);
1556
1573
  }
1557
1574
 
1558
1575
  return {
@@ -1572,6 +1589,17 @@ function createLoop(roots) {
1572
1589
  };
1573
1590
  }
1574
1591
 
1592
+ /**
1593
+ * Exposes an object's {@link LocalState}.
1594
+ * @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#useInstanceHandle
1595
+ *
1596
+ * **Note**: this is an escape hatch to react-internal fields. Expect this to change significantly between versions.
1597
+ */
1598
+ function useInstanceHandle(ref) {
1599
+ const instance = React.useRef(null);
1600
+ useIsomorphicLayoutEffect(() => void (instance.current = ref.current.__r3f), [ref]);
1601
+ return instance;
1602
+ }
1575
1603
  function useStore() {
1576
1604
  const store = React.useContext(context);
1577
1605
  if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
@@ -2105,4 +2133,4 @@ reconciler.injectIntoDevTools({
2105
2133
  });
2106
2134
  const act = React.unstable_act;
2107
2135
 
2108
- export { Block as B, ErrorBoundary as E, createRoot as a, useIsomorphicLayoutEffect as b, createEvents as c, unmountComponentAtNode as d, extend as e, context as f, createPortal as g, reconciler as h, applyProps as i, dispose as j, invalidate as k, advance as l, addEffect as m, addAfterEffect as n, addTail as o, getRootState as p, act as q, render as r, roots as s, threeTypes as t, useMutableCallback as u, useStore as v, useThree as w, useFrame as x, useGraph as y, useLoader as z };
2136
+ export { useGraph as A, Block as B, useLoader as C, ErrorBoundary as E, createRoot as a, useIsomorphicLayoutEffect as b, createEvents as c, unmountComponentAtNode as d, extend as e, context as f, createPortal as g, reconciler as h, isRef as i, applyProps as j, dispose as k, invalidate as l, advance as m, addEffect as n, addAfterEffect as o, addTail as p, getRootState as q, render as r, act as s, threeTypes as t, useMutableCallback as u, roots as v, useInstanceHandle as w, useStore as x, useThree as y, useFrame as z };
@@ -39,6 +39,7 @@ var threeTypes = /*#__PURE__*/Object.freeze({
39
39
 
40
40
  var _window$document, _window$navigator;
41
41
  const isOrthographicCamera = def => def && def.isOrthographicCamera;
42
+ const isRef = obj => obj && obj.hasOwnProperty('current');
42
43
  /**
43
44
  * An SSR-friendly useLayoutEffect.
44
45
  *
@@ -503,9 +504,7 @@ function removeInteractivity(store, object) {
503
504
  });
504
505
  }
505
506
  function createEvents(store) {
506
- const temp = new THREE__namespace.Vector3();
507
507
  /** Calculates delta */
508
-
509
508
  function calculateDistance(event) {
510
509
  const {
511
510
  internal
@@ -605,108 +604,113 @@ function createEvents(store) {
605
604
 
606
605
 
607
606
  function handleIntersects(intersections, event, delta, callback) {
608
- const {
609
- raycaster,
610
- pointer,
611
- camera,
612
- internal
613
- } = store.getState(); // If anything has been found, forward it to the event listeners
614
-
607
+ // If anything has been found, forward it to the event listeners
615
608
  if (intersections.length) {
616
- const unprojectedPoint = temp.set(pointer.x, pointer.y, 0).unproject(camera);
617
609
  const localState = {
618
610
  stopped: false
619
611
  };
620
612
 
621
613
  for (const hit of intersections) {
622
- const hasPointerCapture = id => {
623
- var _internal$capturedMap, _internal$capturedMap2;
614
+ const state = getRootState(hit.object);
624
615
 
625
- return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
626
- };
616
+ if (state) {
617
+ const {
618
+ raycaster,
619
+ pointer,
620
+ camera,
621
+ internal
622
+ } = state;
623
+ const unprojectedPoint = new THREE__namespace.Vector3(pointer.x, pointer.y, 0).unproject(camera);
624
+
625
+ const hasPointerCapture = id => {
626
+ var _internal$capturedMap, _internal$capturedMap2;
627
627
 
628
- const setPointerCapture = id => {
629
- const captureData = {
630
- intersection: hit,
631
- target: event.target
628
+ return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
632
629
  };
633
630
 
634
- if (internal.capturedMap.has(id)) {
635
- // if the pointerId was previously captured, we add the hit to the
636
- // event capturedMap.
637
- internal.capturedMap.get(id).set(hit.eventObject, captureData);
638
- } else {
639
- // if the pointerId was not previously captured, we create a map
640
- // containing the hitObject, and the hit. hitObject is used for
641
- // faster access.
642
- internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
643
- } // Call the original event now
644
- event.target.setPointerCapture(id);
645
- };
631
+ const setPointerCapture = id => {
632
+ const captureData = {
633
+ intersection: hit,
634
+ target: event.target
635
+ };
636
+
637
+ if (internal.capturedMap.has(id)) {
638
+ // if the pointerId was previously captured, we add the hit to the
639
+ // event capturedMap.
640
+ internal.capturedMap.get(id).set(hit.eventObject, captureData);
641
+ } else {
642
+ // if the pointerId was not previously captured, we create a map
643
+ // containing the hitObject, and the hit. hitObject is used for
644
+ // faster access.
645
+ internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
646
+ } // Call the original event now
647
+ event.target.setPointerCapture(id);
648
+ };
646
649
 
647
- const releasePointerCapture = id => {
648
- const captures = internal.capturedMap.get(id);
650
+ const releasePointerCapture = id => {
651
+ const captures = internal.capturedMap.get(id);
649
652
 
650
- if (captures) {
651
- releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
652
- }
653
- }; // Add native event props
653
+ if (captures) {
654
+ releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
655
+ }
656
+ }; // Add native event props
654
657
 
655
658
 
656
- let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
659
+ let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
657
660
 
658
- for (let prop in event) {
659
- let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
660
- // called as event.nativeEvent.fn()
661
+ for (let prop in event) {
662
+ let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
663
+ // called as event.nativeEvent.fn()
661
664
 
662
- if (typeof property !== 'function') extractEventProps[prop] = property;
663
- }
665
+ if (typeof property !== 'function') extractEventProps[prop] = property;
666
+ }
664
667
 
665
- let raycastEvent = { ...hit,
666
- ...extractEventProps,
667
- pointer,
668
- intersections,
669
- stopped: localState.stopped,
670
- delta,
671
- unprojectedPoint,
672
- ray: raycaster.ray,
673
- camera: camera,
674
- // Hijack stopPropagation, which just sets a flag
675
- stopPropagation: () => {
676
- // https://github.com/pmndrs/react-three-fiber/issues/596
677
- // Events are not allowed to stop propagation if the pointer has been captured
678
- const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId); // We only authorize stopPropagation...
679
-
680
- if ( // ...if this pointer hasn't been captured
681
- !capturesForPointer || // ... or if the hit object is capturing the pointer
682
- capturesForPointer.has(hit.eventObject)) {
683
- raycastEvent.stopped = localState.stopped = true; // Propagation is stopped, remove all other hover records
684
- // An event handler is only allowed to flush other handlers if it is hovered itself
685
-
686
- if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
687
- // Objects cannot flush out higher up objects that have already caught the event
688
- const higher = intersections.slice(0, intersections.indexOf(hit));
689
- cancelPointer([...higher, hit]);
668
+ let raycastEvent = { ...hit,
669
+ ...extractEventProps,
670
+ pointer,
671
+ intersections,
672
+ stopped: localState.stopped,
673
+ delta,
674
+ unprojectedPoint,
675
+ ray: raycaster.ray,
676
+ camera: camera,
677
+ // Hijack stopPropagation, which just sets a flag
678
+ stopPropagation: () => {
679
+ // https://github.com/pmndrs/react-three-fiber/issues/596
680
+ // Events are not allowed to stop propagation if the pointer has been captured
681
+ const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId); // We only authorize stopPropagation...
682
+
683
+ if ( // ...if this pointer hasn't been captured
684
+ !capturesForPointer || // ... or if the hit object is capturing the pointer
685
+ capturesForPointer.has(hit.eventObject)) {
686
+ raycastEvent.stopped = localState.stopped = true; // Propagation is stopped, remove all other hover records
687
+ // An event handler is only allowed to flush other handlers if it is hovered itself
688
+
689
+ if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
690
+ // Objects cannot flush out higher up objects that have already caught the event
691
+ const higher = intersections.slice(0, intersections.indexOf(hit));
692
+ cancelPointer([...higher, hit]);
693
+ }
690
694
  }
691
- }
692
- },
693
- // there should be a distinction between target and currentTarget
694
- target: {
695
- hasPointerCapture,
696
- setPointerCapture,
697
- releasePointerCapture
698
- },
699
- currentTarget: {
700
- hasPointerCapture,
701
- setPointerCapture,
702
- releasePointerCapture
703
- },
704
- nativeEvent: event
705
- }; // Call subscribers
706
-
707
- callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
708
-
709
- if (localState.stopped === true) break;
695
+ },
696
+ // there should be a distinction between target and currentTarget
697
+ target: {
698
+ hasPointerCapture,
699
+ setPointerCapture,
700
+ releasePointerCapture
701
+ },
702
+ currentTarget: {
703
+ hasPointerCapture,
704
+ setPointerCapture,
705
+ releasePointerCapture
706
+ },
707
+ nativeEvent: event
708
+ }; // Call subscribers
709
+
710
+ callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
711
+
712
+ if (localState.stopped === true) break;
713
+ }
710
714
  }
711
715
  }
712
716
 
@@ -1495,11 +1499,24 @@ const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
1495
1499
  const addTail = callback => createSubs(callback, globalTailEffects);
1496
1500
 
1497
1501
  function run(effects, timestamp) {
1502
+ if (!effects.size) return;
1498
1503
  effects.forEach(({
1499
1504
  callback
1500
1505
  }) => callback(timestamp));
1501
1506
  }
1502
1507
 
1508
+ function flushGlobalEffects(type, timestamp) {
1509
+ switch (type) {
1510
+ case 'before':
1511
+ return run(globalEffects, timestamp);
1512
+
1513
+ case 'after':
1514
+ return run(globalAfterEffects, timestamp);
1515
+
1516
+ case 'tail':
1517
+ return run(globalTailEffects, timestamp);
1518
+ }
1519
+ }
1503
1520
  let subscribers;
1504
1521
  let subscription;
1505
1522
 
@@ -1539,7 +1556,7 @@ function createLoop(roots) {
1539
1556
  running = true;
1540
1557
  repeat = 0; // Run effects
1541
1558
 
1542
- if (globalEffects.size) run(globalEffects, timestamp); // Render all roots
1559
+ flushGlobalEffects('before', timestamp); // Render all roots
1543
1560
 
1544
1561
  roots.forEach(root => {
1545
1562
  var _state$gl$xr;
@@ -1551,11 +1568,11 @@ function createLoop(roots) {
1551
1568
  }
1552
1569
  }); // Run after-effects
1553
1570
 
1554
- if (globalAfterEffects.size) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1571
+ flushGlobalEffects('after', timestamp); // Stop the loop if nothing invalidates it
1555
1572
 
1556
1573
  if (repeat === 0) {
1557
1574
  // Tail call effects, they are called when rendering stops
1558
- if (globalTailEffects.size) run(globalTailEffects, timestamp); // Flag end of operation
1575
+ flushGlobalEffects('tail', timestamp); // Flag end of operation
1559
1576
 
1560
1577
  running = false;
1561
1578
  return cancelAnimationFrame(frame);
@@ -1577,9 +1594,9 @@ function createLoop(roots) {
1577
1594
  }
1578
1595
 
1579
1596
  function advance(timestamp, runGlobalEffects = true, state, frame) {
1580
- if (runGlobalEffects) run(globalEffects, timestamp);
1597
+ if (runGlobalEffects) flushGlobalEffects('before', timestamp);
1581
1598
  if (!state) roots.forEach(root => render$1(timestamp, root.store.getState()));else render$1(timestamp, state, frame);
1582
- if (runGlobalEffects) run(globalAfterEffects, timestamp);
1599
+ if (runGlobalEffects) flushGlobalEffects('after', timestamp);
1583
1600
  }
1584
1601
 
1585
1602
  return {
@@ -1599,6 +1616,17 @@ function createLoop(roots) {
1599
1616
  };
1600
1617
  }
1601
1618
 
1619
+ /**
1620
+ * Exposes an object's {@link LocalState}.
1621
+ * @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#useInstanceHandle
1622
+ *
1623
+ * **Note**: this is an escape hatch to react-internal fields. Expect this to change significantly between versions.
1624
+ */
1625
+ function useInstanceHandle(ref) {
1626
+ const instance = React__namespace.useRef(null);
1627
+ useIsomorphicLayoutEffect(() => void (instance.current = ref.current.__r3f), [ref]);
1628
+ return instance;
1629
+ }
1602
1630
  function useStore() {
1603
1631
  const store = React__namespace.useContext(context);
1604
1632
  if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
@@ -2148,6 +2176,7 @@ exports.dispose = dispose;
2148
2176
  exports.extend = extend;
2149
2177
  exports.getRootState = getRootState;
2150
2178
  exports.invalidate = invalidate;
2179
+ exports.isRef = isRef;
2151
2180
  exports.reconciler = reconciler;
2152
2181
  exports.render = render;
2153
2182
  exports.roots = roots;
@@ -2155,6 +2184,7 @@ exports.threeTypes = threeTypes;
2155
2184
  exports.unmountComponentAtNode = unmountComponentAtNode;
2156
2185
  exports.useFrame = useFrame;
2157
2186
  exports.useGraph = useGraph;
2187
+ exports.useInstanceHandle = useInstanceHandle;
2158
2188
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
2159
2189
  exports.useLoader = useLoader;
2160
2190
  exports.useMutableCallback = useMutableCallback;