@react-three/fiber 9.0.0-beta.1 → 9.0.0-rc.0

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/declarations/src/core/events.d.ts +91 -0
  3. package/dist/declarations/src/core/hooks.d.ts +52 -0
  4. package/dist/declarations/src/core/index.d.ts +13 -0
  5. package/dist/declarations/src/core/loop.d.ts +31 -0
  6. package/dist/declarations/src/core/reconciler.d.ts +55 -0
  7. package/dist/declarations/src/core/renderer.d.ts +87 -0
  8. package/dist/declarations/src/core/store.d.ts +130 -0
  9. package/dist/declarations/src/core/utils.d.ts +138 -0
  10. package/dist/declarations/src/index.d.ts +6 -0
  11. package/dist/declarations/src/native/Canvas.d.ts +14 -0
  12. package/dist/declarations/src/native/events.d.ts +4 -0
  13. package/dist/declarations/src/native.d.ts +6 -0
  14. package/dist/declarations/src/three-types.d.ts +62 -0
  15. package/dist/declarations/src/web/Canvas.d.ts +24 -0
  16. package/dist/declarations/src/web/events.d.ts +4 -0
  17. package/dist/declarations/src/web/use-measure.d.ts +34 -0
  18. package/dist/{loop-b00a3b86.esm.js → events-5a08b43f.esm.js} +91 -5
  19. package/dist/{loop-dfcc9ca9.cjs.prod.js → events-aef54ace.cjs.prod.js} +91 -4
  20. package/dist/{loop-eb3c7218.cjs.dev.js → events-fa0fb3db.cjs.dev.js} +91 -4
  21. package/dist/react-three-fiber.cjs.dev.js +230 -122
  22. package/dist/react-three-fiber.cjs.prod.js +230 -122
  23. package/dist/react-three-fiber.esm.js +193 -84
  24. package/native/dist/react-three-fiber-native.cjs.dev.js +190 -128
  25. package/native/dist/react-three-fiber-native.cjs.prod.js +190 -128
  26. package/native/dist/react-three-fiber-native.esm.js +157 -95
  27. package/package.json +88 -86
@@ -1,101 +1,210 @@
1
- import { c as createEvents, e as extend, u as useBridge, a as useMutableCallback, b as useIsomorphicLayoutEffect, d as createRoot, i as isRef, E as ErrorBoundary, B as Block, f as unmountComponentAtNode } from './loop-b00a3b86.esm.js';
2
- export { t as ReactThreeFiber, _ as _roots, w as act, j as addAfterEffect, h as addEffect, k as addTail, m as advance, q as applyProps, x as buildGraph, p as context, c as createEvents, o as createPortal, d as createRoot, v as dispose, e as extend, g as flushGlobalEffects, s as getRootState, l as invalidate, r as reconciler, n as render, f as unmountComponentAtNode, C as useFrame, D as useGraph, y as useInstanceHandle, F as useLoader, z as useStore, A as useThree } from './loop-b00a3b86.esm.js';
1
+ import { e as extend, u as useBridge, a as useMutableCallback, b as useIsomorphicLayoutEffect, c as createRoot, i as isRef, E as ErrorBoundary, B as Block, d as unmountComponentAtNode, f as createPointerEvents } from './events-5a08b43f.esm.js';
2
+ export { t as ReactThreeFiber, _ as _roots, x as act, k as addAfterEffect, j as addEffect, l as addTail, n as advance, s as applyProps, y as buildGraph, q as context, g as createEvents, p as createPortal, c as createRoot, w as dispose, f as events, e as extend, h as flushGlobalEffects, v as getRootState, m as invalidate, r as reconciler, o as render, d as unmountComponentAtNode, D as useFrame, F as useGraph, z as useInstanceHandle, G as useLoader, A as useStore, C as useThree } from './events-5a08b43f.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 } from 'its-fine';
7
8
  import { jsx } from 'react/jsx-runtime';
8
9
  import 'react-reconciler/constants';
9
10
  import 'zustand/traditional';
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 => {
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
+ orientationHandler: null
54
+ });
55
+
56
+ // set actual debounce values early, so effects know if they should react accordingly
57
+ const scrollDebounce = debounce ? typeof debounce === 'number' ? debounce : debounce.scroll : null;
58
+ const resizeDebounce = debounce ? typeof debounce === 'number' ? debounce : debounce.resize : null;
59
+
60
+ // make sure to update state only as long as the component is truly mounted
61
+ const mounted = useRef(false);
62
+ useEffect(() => {
63
+ mounted.current = true;
64
+ return () => void (mounted.current = false);
65
+ });
66
+
67
+ // memoize handlers, so event-listeners know when they should update
68
+ const [forceRefresh, resizeChange, scrollChange] = useMemo(() => {
69
+ const callback = () => {
70
+ if (!state.current.element) return;
55
71
  const {
56
- set,
57
- events
58
- } = store.getState();
59
- events.disconnect == null ? void 0 : events.disconnect();
60
- set(state => ({
61
- events: {
62
- ...state.events,
63
- connected: target
64
- }
65
- }));
66
- if (events.handlers) {
67
- for (const name in events.handlers) {
68
- const event = events.handlers[name];
69
- const [eventName, passive] = DOM_EVENTS[name];
70
- target.addEventListener(eventName, event, {
71
- passive
72
- });
73
- }
72
+ left,
73
+ top,
74
+ width,
75
+ height,
76
+ bottom,
77
+ right,
78
+ x,
79
+ y
80
+ } = state.current.element.getBoundingClientRect();
81
+ const size = {
82
+ left,
83
+ top,
84
+ width,
85
+ height,
86
+ bottom,
87
+ right,
88
+ x,
89
+ y
90
+ };
91
+ if (state.current.element instanceof HTMLElement && offsetSize) {
92
+ size.height = state.current.element.offsetHeight;
93
+ size.width = state.current.element.offsetWidth;
74
94
  }
75
- },
76
- disconnect: () => {
77
- const {
78
- set,
79
- events
80
- } = store.getState();
81
- if (events.connected) {
82
- if (events.handlers) {
83
- for (const name in events.handlers) {
84
- const event = events.handlers[name];
85
- const [eventName] = DOM_EVENTS[name];
86
- events.connected.removeEventListener(eventName, event);
87
- }
88
- }
89
- set(state => ({
90
- events: {
91
- ...state.events,
92
- connected: undefined
93
- }
94
- }));
95
+ Object.freeze(size);
96
+ if (mounted.current && !areBoundsEqual(state.current.lastBounds, size)) set(state.current.lastBounds = size);
97
+ };
98
+ return [callback, resizeDebounce ? createDebounce(callback, resizeDebounce) : callback, scrollDebounce ? createDebounce(callback, scrollDebounce) : callback];
99
+ }, [set, offsetSize, scrollDebounce, resizeDebounce]);
100
+
101
+ // cleanup current scroll-listeners / observers
102
+ function removeListeners() {
103
+ if (state.current.scrollContainers) {
104
+ state.current.scrollContainers.forEach(element => element.removeEventListener('scroll', scrollChange, true));
105
+ state.current.scrollContainers = null;
106
+ }
107
+ if (state.current.resizeObserver) {
108
+ state.current.resizeObserver.disconnect();
109
+ state.current.resizeObserver = null;
110
+ }
111
+ if (state.current.orientationHandler) {
112
+ if ('orientation' in screen && 'removeEventListener' in screen.orientation) {
113
+ screen.orientation.removeEventListener('change', state.current.orientationHandler);
114
+ } else if ('onorientationchange' in window) {
115
+ window.removeEventListener('orientationchange', state.current.orientationHandler);
95
116
  }
96
117
  }
118
+ }
119
+
120
+ // add scroll-listeners / observers
121
+ function addListeners() {
122
+ var _state$current$resize;
123
+ if (!state.current.element) return;
124
+ state.current.resizeObserver = new ResizeObserver(resizeChange);
125
+ (_state$current$resize = state.current.resizeObserver) == null ? void 0 : _state$current$resize.observe(state.current.element);
126
+ if (scroll && state.current.scrollContainers) {
127
+ state.current.scrollContainers.forEach(scrollContainer => scrollContainer.addEventListener('scroll', scrollChange, {
128
+ capture: true,
129
+ passive: true
130
+ }));
131
+ }
132
+
133
+ // Handle orientation changes
134
+ state.current.orientationHandler = () => {
135
+ scrollChange();
136
+ };
137
+
138
+ // Use screen.orientation if available
139
+ if ('orientation' in screen && 'addEventListener' in screen.orientation) {
140
+ screen.orientation.addEventListener('change', state.current.orientationHandler);
141
+ } else if ('onorientationchange' in window) {
142
+ // Fallback to orientationchange event
143
+ window.addEventListener('orientationchange', state.current.orientationHandler);
144
+ }
145
+ }
146
+
147
+ // the ref we expose to the user
148
+ const ref = node => {
149
+ if (!node || node === state.current.element) return;
150
+ removeListeners();
151
+ state.current.element = node;
152
+ state.current.scrollContainers = findScrollContainers(node);
153
+ addListeners();
97
154
  };
155
+
156
+ // add general event listeners
157
+ useOnWindowScroll(scrollChange, Boolean(scroll));
158
+ useOnWindowResize(resizeChange);
159
+
160
+ // respond to changes that are relevant for the listeners
161
+ useEffect(() => {
162
+ removeListeners();
163
+ addListeners();
164
+ }, [scroll, scrollChange, resizeChange]);
165
+
166
+ // remove all listeners when the components unmounts
167
+ useEffect(() => removeListeners, []);
168
+ return [ref, bounds, forceRefresh];
169
+ }
170
+
171
+ // Adds native resize listener to window
172
+ function useOnWindowResize(onWindowResize) {
173
+ useEffect(() => {
174
+ const cb = onWindowResize;
175
+ window.addEventListener('resize', cb);
176
+ return () => void window.removeEventListener('resize', cb);
177
+ }, [onWindowResize]);
98
178
  }
179
+ function useOnWindowScroll(onScroll, enabled) {
180
+ useEffect(() => {
181
+ if (enabled) {
182
+ const cb = onScroll;
183
+ window.addEventListener('scroll', cb, {
184
+ capture: true,
185
+ passive: true
186
+ });
187
+ return () => void window.removeEventListener('scroll', cb, true);
188
+ }
189
+ }, [onScroll, enabled]);
190
+ }
191
+
192
+ // Returns a list of scroll offsets
193
+ function findScrollContainers(element) {
194
+ const result = [];
195
+ if (!element || element === document.body) return result;
196
+ const {
197
+ overflow,
198
+ overflowX,
199
+ overflowY
200
+ } = window.getComputedStyle(element);
201
+ if ([overflow, overflowX, overflowY].some(prop => prop === 'auto' || prop === 'scroll')) result.push(element);
202
+ return [...result, ...findScrollContainers(element.parentElement)];
203
+ }
204
+
205
+ // Checks if element boundaries are equal
206
+ const keys = ['x', 'y', 'top', 'bottom', 'left', 'right', 'width', 'height'];
207
+ const areBoundsEqual = (a, b) => keys.every(key => a[key] === b[key]);
99
208
 
100
209
  const CanvasImpl = /*#__PURE__*/React.forwardRef(function Canvas({
101
210
  children,
@@ -247,4 +356,4 @@ const Canvas = /*#__PURE__*/React.forwardRef(function CanvasWrapper(props, ref)
247
356
  });
248
357
  });
249
358
 
250
- export { Canvas, createPointerEvents as events };
359
+ export { Canvas };