@react-three/fiber 8.16.8 → 8.17.1

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,100 +1,189 @@
1
- import { c as createEvents, e as extend, u as useMutableCallback, a as useIsomorphicLayoutEffect, b as createRoot, i as isRef, E as ErrorBoundary, B as Block, d as unmountComponentAtNode } from './index-99983b2d.esm.js';
2
- export { t as ReactThreeFiber, x as _roots, v as act, o as addAfterEffect, n as addEffect, p as addTail, m as advance, j as applyProps, w as buildGraph, f as context, c as createEvents, g as createPortal, b as createRoot, k as dispose, e as extend, q as flushGlobalEffects, s as getRootState, l as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, C as useFrame, D as useGraph, y as useInstanceHandle, F as useLoader, z as useStore, A as useThree } from './index-99983b2d.esm.js';
1
+ import { c as createPointerEvents, e as extend, u as useMutableCallback, a as useIsomorphicLayoutEffect, b as createRoot, i as isRef, E as ErrorBoundary, B as Block, d as unmountComponentAtNode } from './events-3515660a.esm.js';
2
+ export { t as ReactThreeFiber, z as _roots, x as act, p as addAfterEffect, o as addEffect, q as addTail, n as advance, k as applyProps, y as buildGraph, g as context, f as createEvents, c as createPointerEvents, h as createPortal, b as createRoot, l as dispose, c as events, e as extend, s as flushGlobalEffects, v as flushSync, w as getRootState, m as invalidate, j as reconciler, r as render, d as unmountComponentAtNode, F as useFrame, G as useGraph, A as useInstanceHandle, H as useLoader, C as useStore, D as useThree } from './events-3515660a.esm.js';
3
3
  import * as React from 'react';
4
+ import { useState, useRef, useEffect, useMemo } from 'react';
4
5
  import * as THREE from 'three';
5
- import useMeasure from 'react-use-measure';
6
+ import createDebounce from 'debounce';
6
7
  import { FiberProvider, useContextBridge } from 'its-fine';
7
8
  import { jsx } from 'react/jsx-runtime';
8
9
  import 'react-reconciler/constants';
9
10
  import 'zustand';
11
+ import 'suspend-react';
10
12
  import 'react-reconciler';
11
13
  import 'scheduler';
12
- import 'suspend-react';
13
14
 
14
- const DOM_EVENTS = {
15
- onClick: ['click', false],
16
- onContextMenu: ['contextmenu', false],
17
- onDoubleClick: ['dblclick', false],
18
- onWheel: ['wheel', true],
19
- onPointerDown: ['pointerdown', true],
20
- onPointerUp: ['pointerup', true],
21
- onPointerLeave: ['pointerleave', true],
22
- onPointerMove: ['pointermove', true],
23
- onPointerCancel: ['pointercancel', true],
24
- onLostPointerCapture: ['lostpointercapture', true]
25
- };
26
-
27
- /** Default R3F event manager for web */
28
- function createPointerEvents(store) {
29
- const {
30
- handlePointer
31
- } = createEvents(store);
32
- return {
33
- priority: 1,
34
- enabled: true,
35
- compute(event, state, previous) {
36
- // https://github.com/pmndrs/react-three-fiber/pull/782
37
- // Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
38
- state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
39
- state.raycaster.setFromCamera(state.pointer, state.camera);
40
- },
41
- connected: undefined,
42
- handlers: Object.keys(DOM_EVENTS).reduce((acc, key) => ({
43
- ...acc,
44
- [key]: handlePointer(key)
45
- }), {}),
46
- update: () => {
47
- var _internal$lastEvent;
48
- const {
49
- events,
50
- internal
51
- } = store.getState();
52
- if ((_internal$lastEvent = internal.lastEvent) != null && _internal$lastEvent.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current);
53
- },
54
- connect: target => {
55
- var _events$handlers;
56
- const {
57
- set,
58
- events
59
- } = store.getState();
60
- events.disconnect == null ? void 0 : events.disconnect();
61
- set(state => ({
62
- events: {
63
- ...state.events,
64
- connected: target
65
- }
66
- }));
67
- Object.entries((_events$handlers = events.handlers) != null ? _events$handlers : []).forEach(([name, event]) => {
68
- const [eventName, passive] = DOM_EVENTS[name];
69
- target.addEventListener(eventName, event, {
70
- passive
71
- });
72
- });
73
- },
74
- disconnect: () => {
15
+ /* eslint-disable react-hooks/rules-of-hooks */
16
+ function useMeasure({
17
+ debounce,
18
+ scroll,
19
+ polyfill,
20
+ offsetSize
21
+ } = {
22
+ debounce: 0,
23
+ scroll: false,
24
+ offsetSize: false
25
+ }) {
26
+ const ResizeObserver = polyfill || typeof window !== 'undefined' && window.ResizeObserver;
27
+ const [bounds, set] = useState({
28
+ left: 0,
29
+ top: 0,
30
+ width: 0,
31
+ height: 0,
32
+ bottom: 0,
33
+ right: 0,
34
+ x: 0,
35
+ y: 0
36
+ });
37
+
38
+ // In test mode
39
+ if (!ResizeObserver) {
40
+ // @ts-ignore
41
+ bounds.width = 1280;
42
+ // @ts-ignore
43
+ bounds.height = 800;
44
+ return [() => {}, bounds, () => {}];
45
+ }
46
+
47
+ // keep all state in a ref
48
+ const state = useRef({
49
+ element: null,
50
+ scrollContainers: null,
51
+ resizeObserver: null,
52
+ lastBounds: bounds
53
+ });
54
+
55
+ // set actual debounce values early, so effects know if they should react accordingly
56
+ const scrollDebounce = debounce ? typeof debounce === 'number' ? debounce : debounce.scroll : null;
57
+ const resizeDebounce = debounce ? typeof debounce === 'number' ? debounce : debounce.resize : null;
58
+
59
+ // make sure to update state only as long as the component is truly mounted
60
+ const mounted = useRef(false);
61
+ useEffect(() => {
62
+ mounted.current = true;
63
+ return () => void (mounted.current = false);
64
+ });
65
+
66
+ // memoize handlers, so event-listeners know when they should update
67
+ const [forceRefresh, resizeChange, scrollChange] = useMemo(() => {
68
+ const callback = () => {
69
+ if (!state.current.element) return;
75
70
  const {
76
- set,
77
- events
78
- } = store.getState();
79
- if (events.connected) {
80
- var _events$handlers2;
81
- Object.entries((_events$handlers2 = events.handlers) != null ? _events$handlers2 : []).forEach(([name, event]) => {
82
- if (events && events.connected instanceof HTMLElement) {
83
- const [eventName] = DOM_EVENTS[name];
84
- events.connected.removeEventListener(eventName, event);
85
- }
86
- });
87
- set(state => ({
88
- events: {
89
- ...state.events,
90
- connected: undefined
91
- }
92
- }));
71
+ left,
72
+ top,
73
+ width,
74
+ height,
75
+ bottom,
76
+ right,
77
+ x,
78
+ y
79
+ } = state.current.element.getBoundingClientRect();
80
+ const size = {
81
+ left,
82
+ top,
83
+ width,
84
+ height,
85
+ bottom,
86
+ right,
87
+ x,
88
+ y
89
+ };
90
+ if (state.current.element instanceof HTMLElement && offsetSize) {
91
+ size.height = state.current.element.offsetHeight;
92
+ size.width = state.current.element.offsetWidth;
93
93
  }
94
+ Object.freeze(size);
95
+ if (mounted.current && !areBoundsEqual(state.current.lastBounds, size)) set(state.current.lastBounds = size);
96
+ };
97
+ return [callback, resizeDebounce ? createDebounce(callback, resizeDebounce) : callback, scrollDebounce ? createDebounce(callback, scrollDebounce) : callback];
98
+ }, [set, offsetSize, scrollDebounce, resizeDebounce]);
99
+
100
+ // cleanup current scroll-listeners / observers
101
+ function removeListeners() {
102
+ if (state.current.scrollContainers) {
103
+ state.current.scrollContainers.forEach(element => element.removeEventListener('scroll', scrollChange, true));
104
+ state.current.scrollContainers = null;
105
+ }
106
+ if (state.current.resizeObserver) {
107
+ state.current.resizeObserver.disconnect();
108
+ state.current.resizeObserver = null;
109
+ }
110
+ }
111
+
112
+ // add scroll-listeners / observers
113
+ function addListeners() {
114
+ if (!state.current.element) return;
115
+ state.current.resizeObserver = new ResizeObserver(scrollChange);
116
+ state.current.resizeObserver.observe(state.current.element);
117
+ if (scroll && state.current.scrollContainers) {
118
+ state.current.scrollContainers.forEach(scrollContainer => scrollContainer.addEventListener('scroll', scrollChange, {
119
+ capture: true,
120
+ passive: true
121
+ }));
94
122
  }
123
+ }
124
+
125
+ // the ref we expose to the user
126
+ const ref = node => {
127
+ if (!node || node === state.current.element) return;
128
+ removeListeners();
129
+ state.current.element = node;
130
+ state.current.scrollContainers = findScrollContainers(node);
131
+ addListeners();
95
132
  };
133
+
134
+ // add general event listeners
135
+ useOnWindowScroll(scrollChange, Boolean(scroll));
136
+ useOnWindowResize(resizeChange);
137
+
138
+ // respond to changes that are relevant for the listeners
139
+ useEffect(() => {
140
+ removeListeners();
141
+ addListeners();
142
+ }, [scroll, scrollChange, resizeChange]);
143
+
144
+ // remove all listeners when the components unmounts
145
+ useEffect(() => removeListeners, []);
146
+ return [ref, bounds, forceRefresh];
147
+ }
148
+
149
+ // Adds native resize listener to window
150
+ function useOnWindowResize(onWindowResize) {
151
+ useEffect(() => {
152
+ const cb = onWindowResize;
153
+ window.addEventListener('resize', cb);
154
+ return () => void window.removeEventListener('resize', cb);
155
+ }, [onWindowResize]);
156
+ }
157
+ function useOnWindowScroll(onScroll, enabled) {
158
+ useEffect(() => {
159
+ if (enabled) {
160
+ const cb = onScroll;
161
+ window.addEventListener('scroll', cb, {
162
+ capture: true,
163
+ passive: true
164
+ });
165
+ return () => void window.removeEventListener('scroll', cb, true);
166
+ }
167
+ }, [onScroll, enabled]);
96
168
  }
97
169
 
170
+ // Returns a list of scroll offsets
171
+ function findScrollContainers(element) {
172
+ const result = [];
173
+ if (!element || element === document.body) return result;
174
+ const {
175
+ overflow,
176
+ overflowX,
177
+ overflowY
178
+ } = window.getComputedStyle(element);
179
+ if ([overflow, overflowX, overflowY].some(prop => prop === 'auto' || prop === 'scroll')) result.push(element);
180
+ return [...result, ...findScrollContainers(element.parentElement)];
181
+ }
182
+
183
+ // Checks if element boundaries are equal
184
+ const keys = ['x', 'y', 'top', 'bottom', 'left', 'right', 'width', 'height'];
185
+ const areBoundsEqual = (a, b) => keys.every(key => a[key] === b[key]);
186
+
98
187
  const CanvasImpl = /*#__PURE__*/React.forwardRef(function Canvas({
99
188
  children,
100
189
  fallback,
@@ -245,4 +334,4 @@ const Canvas = /*#__PURE__*/React.forwardRef(function CanvasWrapper(props, ref)
245
334
  });
246
335
  });
247
336
 
248
- export { Canvas, createPointerEvents as events };
337
+ export { Canvas };