@react-three/fiber 8.13.2 → 8.13.4

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,13 +1,13 @@
1
- import * as React from 'react';
2
- import type { Options as ResizeOptions } from 'react-use-measure';
3
- import { RenderProps } from '../core';
4
- export interface CanvasProps 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 interface Props extends CanvasProps {
12
- }
13
- 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 CanvasProps 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 interface Props extends CanvasProps {
12
+ }
13
+ 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>;
@@ -251,8 +251,11 @@ function createRenderer(_roots, _getEventPriority) {
251
251
  return Boolean(localState.handlers);
252
252
  },
253
253
  prepareUpdate(instance, _type, oldProps, newProps) {
254
+ var _instance$__r3f3;
255
+ const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
256
+
254
257
  // Create diff-sets
255
- if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
258
+ if (localState.primitive && newProps.object && newProps.object !== instance) {
256
259
  return [true];
257
260
  } else {
258
261
  // This is a data object, let's extract critical information about it
@@ -287,10 +290,10 @@ function createRenderer(_roots, _getEventPriority) {
287
290
  else applyProps$1(instance, diff);
288
291
  },
289
292
  commitMount(instance, _type, _props, _int) {
290
- var _instance$__r3f3;
293
+ var _instance$__r3f4;
291
294
  // https://github.com/facebook/react/issues/20271
292
295
  // This will make sure events are only added once to the central container
293
- const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
296
+ const localState = (_instance$__r3f4 = instance.__r3f) != null ? _instance$__r3f4 : {};
294
297
  if (instance.raycast && localState.handlers && localState.eventCount) {
295
298
  instance.__r3f.root.getState().internal.interaction.push(instance);
296
299
  }
@@ -302,23 +305,23 @@ function createRenderer(_roots, _getEventPriority) {
302
305
  shouldSetTextContent: () => false,
303
306
  clearContainer: () => false,
304
307
  hideInstance(instance) {
305
- var _instance$__r3f4;
308
+ var _instance$__r3f5;
306
309
  // Detach while the instance is hidden
307
310
  const {
308
311
  attach: type,
309
312
  parent
310
- } = (_instance$__r3f4 = instance.__r3f) != null ? _instance$__r3f4 : {};
313
+ } = (_instance$__r3f5 = instance.__r3f) != null ? _instance$__r3f5 : {};
311
314
  if (type && parent) detach(parent, instance, type);
312
315
  if (instance.isObject3D) instance.visible = false;
313
316
  invalidateInstance(instance);
314
317
  },
315
318
  unhideInstance(instance, props) {
316
- var _instance$__r3f5;
319
+ var _instance$__r3f6;
317
320
  // Re-attach when the instance is unhidden
318
321
  const {
319
322
  attach: type,
320
323
  parent
321
- } = (_instance$__r3f5 = instance.__r3f) != null ? _instance$__r3f5 : {};
324
+ } = (_instance$__r3f6 = instance.__r3f) != null ? _instance$__r3f6 : {};
322
325
  if (type && parent) attach(parent, instance, type);
323
326
  if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
324
327
  invalidateInstance(instance);
@@ -494,19 +497,17 @@ function dispose(obj) {
494
497
  // Each object in the scene carries a small LocalState descriptor
495
498
  function prepare(object, state) {
496
499
  const instance = object;
497
- if (state != null && state.primitive || !instance.__r3f) {
498
- instance.__r3f = {
499
- type: '',
500
- root: null,
501
- previousAttach: null,
502
- memoizedProps: {},
503
- eventCount: 0,
504
- handlers: {},
505
- objects: [],
506
- parent: null,
507
- ...state
508
- };
509
- }
500
+ instance.__r3f = {
501
+ type: '',
502
+ root: null,
503
+ previousAttach: null,
504
+ memoizedProps: {},
505
+ eventCount: 0,
506
+ handlers: {},
507
+ objects: [],
508
+ parent: null,
509
+ ...state
510
+ };
510
511
  return object;
511
512
  }
512
513
  function resolve(instance, key) {
@@ -1200,6 +1201,8 @@ function createEvents(store) {
1200
1201
  };
1201
1202
  }
1202
1203
 
1204
+ // Keys that shouldn't be copied between R3F stores
1205
+ const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'size', 'viewport'];
1203
1206
  const isRenderer = def => !!(def != null && def.render);
1204
1207
  const context = /*#__PURE__*/React.createContext(null);
1205
1208
  const createStore = (invalidate, advance) => {
@@ -2029,6 +2032,7 @@ function unmountComponentAtNode(canvas, callback) {
2029
2032
  }
2030
2033
  function createPortal(children, container, state) {
2031
2034
  return /*#__PURE__*/React.createElement(Portal, {
2035
+ key: container.uuid,
2032
2036
  children: children,
2033
2037
  container: container,
2034
2038
  state: state
@@ -2052,9 +2056,26 @@ function Portal({
2052
2056
  const previousRoot = useStore();
2053
2057
  const [raycaster] = React.useState(() => new THREE.Raycaster());
2054
2058
  const [pointer] = React.useState(() => new THREE.Vector2());
2055
- const inject = useMutableCallback((rootState, injectState) => {
2056
- let viewport;
2057
- if (injectState.camera && size) {
2059
+ const inject = React.useCallback((rootState, injectState) => {
2060
+ const intersect = {
2061
+ ...rootState
2062
+ }; // all prev state props
2063
+
2064
+ // Only the fields of "rootState" that do not differ from injectState
2065
+ // Some props should be off-limits
2066
+ // Otherwise filter out the props that are different and let the inject layer take precedence
2067
+ Object.keys(rootState).forEach(key => {
2068
+ if (
2069
+ // Some props should be off-limits
2070
+ privateKeys.includes(key) ||
2071
+ // Otherwise filter out the props that are different and let the inject layer take precedence
2072
+ // Unless the inject layer props is undefined, then we keep the root layer
2073
+ rootState[key] !== injectState[key] && injectState[key]) {
2074
+ delete intersect[key];
2075
+ }
2076
+ });
2077
+ let viewport = undefined;
2078
+ if (injectState && size) {
2058
2079
  const camera = injectState.camera;
2059
2080
  // Calculate the override viewport, if present
2060
2081
  viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size);
@@ -2063,9 +2084,7 @@ function Portal({
2063
2084
  }
2064
2085
  return {
2065
2086
  // The intersect consists of the previous root state
2066
- ...rootState,
2067
- get: injectState.get,
2068
- set: injectState.set,
2087
+ ...intersect,
2069
2088
  // Portals have their own scene, which forms the root, a raycaster and a pointer
2070
2089
  scene: container,
2071
2090
  raycaster,
@@ -2076,7 +2095,7 @@ function Portal({
2076
2095
  // Events, size and viewport can be overridden by the inject layer
2077
2096
  events: {
2078
2097
  ...rootState.events,
2079
- ...injectState.events,
2098
+ ...(injectState == null ? void 0 : injectState.events),
2080
2099
  ...events
2081
2100
  },
2082
2101
  size: {
@@ -2087,33 +2106,53 @@ function Portal({
2087
2106
  ...rootState.viewport,
2088
2107
  ...viewport
2089
2108
  },
2109
+ ...rest
2110
+ };
2111
+ }, [state]);
2112
+ const [usePortalStore] = React.useState(() => {
2113
+ // Create a mirrored store, based on the previous root with a few overrides ...
2114
+ const previousState = previousRoot.getState();
2115
+ const store = create((set, get) => ({
2116
+ ...previousState,
2117
+ scene: container,
2118
+ raycaster,
2119
+ pointer,
2120
+ mouse: pointer,
2121
+ previousRoot,
2122
+ events: {
2123
+ ...previousState.events,
2124
+ ...events
2125
+ },
2126
+ size: {
2127
+ ...previousState.size,
2128
+ ...size
2129
+ },
2130
+ ...rest,
2131
+ // Set and get refer to this root-state
2132
+ set,
2133
+ get,
2090
2134
  // Layers are allowed to override events
2091
- setEvents: events => injectState.set(state => ({
2135
+ setEvents: events => set(state => ({
2092
2136
  ...state,
2093
2137
  events: {
2094
2138
  ...state.events,
2095
2139
  ...events
2096
2140
  }
2097
2141
  }))
2098
- };
2099
- });
2100
- const usePortalStore = React.useMemo(() => {
2101
- const store = create((set, get) => ({
2102
- ...rest,
2103
- set,
2104
- get
2105
2142
  }));
2106
-
2107
- // Subscribe to previous root-state and copy changes over to the mirrored portal-state
2108
- const onMutate = prev => store.setState(state => inject.current(prev, state));
2109
- onMutate(previousRoot.getState());
2110
- previousRoot.subscribe(onMutate);
2111
2143
  return store;
2112
- // eslint-disable-next-line react-hooks/exhaustive-deps
2113
- }, [previousRoot, container]);
2144
+ });
2145
+ React.useEffect(() => {
2146
+ // Subscribe to previous root-state and copy changes over to the mirrored portal-state
2147
+ const unsub = previousRoot.subscribe(prev => usePortalStore.setState(state => inject(prev, state)));
2148
+ return () => {
2149
+ unsub();
2150
+ usePortalStore.destroy();
2151
+ };
2152
+ }, []);
2114
2153
  React.useEffect(() => {
2115
- return () => usePortalStore.destroy();
2116
- }, [usePortalStore]);
2154
+ usePortalStore.setState(injectState => inject(previousRoot.getState(), injectState));
2155
+ }, [inject]);
2117
2156
  return /*#__PURE__*/React.createElement(React.Fragment, null, reconciler.createPortal( /*#__PURE__*/React.createElement(context.Provider, {
2118
2157
  value: usePortalStore
2119
2158
  }, children), usePortalStore, null));
@@ -278,8 +278,11 @@ function createRenderer(_roots, _getEventPriority) {
278
278
  return Boolean(localState.handlers);
279
279
  },
280
280
  prepareUpdate(instance, _type, oldProps, newProps) {
281
+ var _instance$__r3f3;
282
+ const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
283
+
281
284
  // Create diff-sets
282
- if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
285
+ if (localState.primitive && newProps.object && newProps.object !== instance) {
283
286
  return [true];
284
287
  } else {
285
288
  // This is a data object, let's extract critical information about it
@@ -314,10 +317,10 @@ function createRenderer(_roots, _getEventPriority) {
314
317
  else applyProps$1(instance, diff);
315
318
  },
316
319
  commitMount(instance, _type, _props, _int) {
317
- var _instance$__r3f3;
320
+ var _instance$__r3f4;
318
321
  // https://github.com/facebook/react/issues/20271
319
322
  // This will make sure events are only added once to the central container
320
- const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
323
+ const localState = (_instance$__r3f4 = instance.__r3f) != null ? _instance$__r3f4 : {};
321
324
  if (instance.raycast && localState.handlers && localState.eventCount) {
322
325
  instance.__r3f.root.getState().internal.interaction.push(instance);
323
326
  }
@@ -329,23 +332,23 @@ function createRenderer(_roots, _getEventPriority) {
329
332
  shouldSetTextContent: () => false,
330
333
  clearContainer: () => false,
331
334
  hideInstance(instance) {
332
- var _instance$__r3f4;
335
+ var _instance$__r3f5;
333
336
  // Detach while the instance is hidden
334
337
  const {
335
338
  attach: type,
336
339
  parent
337
- } = (_instance$__r3f4 = instance.__r3f) != null ? _instance$__r3f4 : {};
340
+ } = (_instance$__r3f5 = instance.__r3f) != null ? _instance$__r3f5 : {};
338
341
  if (type && parent) detach(parent, instance, type);
339
342
  if (instance.isObject3D) instance.visible = false;
340
343
  invalidateInstance(instance);
341
344
  },
342
345
  unhideInstance(instance, props) {
343
- var _instance$__r3f5;
346
+ var _instance$__r3f6;
344
347
  // Re-attach when the instance is unhidden
345
348
  const {
346
349
  attach: type,
347
350
  parent
348
- } = (_instance$__r3f5 = instance.__r3f) != null ? _instance$__r3f5 : {};
351
+ } = (_instance$__r3f6 = instance.__r3f) != null ? _instance$__r3f6 : {};
349
352
  if (type && parent) attach(parent, instance, type);
350
353
  if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
351
354
  invalidateInstance(instance);
@@ -521,19 +524,17 @@ function dispose(obj) {
521
524
  // Each object in the scene carries a small LocalState descriptor
522
525
  function prepare(object, state) {
523
526
  const instance = object;
524
- if (state != null && state.primitive || !instance.__r3f) {
525
- instance.__r3f = {
526
- type: '',
527
- root: null,
528
- previousAttach: null,
529
- memoizedProps: {},
530
- eventCount: 0,
531
- handlers: {},
532
- objects: [],
533
- parent: null,
534
- ...state
535
- };
536
- }
527
+ instance.__r3f = {
528
+ type: '',
529
+ root: null,
530
+ previousAttach: null,
531
+ memoizedProps: {},
532
+ eventCount: 0,
533
+ handlers: {},
534
+ objects: [],
535
+ parent: null,
536
+ ...state
537
+ };
537
538
  return object;
538
539
  }
539
540
  function resolve(instance, key) {
@@ -1227,6 +1228,8 @@ function createEvents(store) {
1227
1228
  };
1228
1229
  }
1229
1230
 
1231
+ // Keys that shouldn't be copied between R3F stores
1232
+ const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'size', 'viewport'];
1230
1233
  const isRenderer = def => !!(def != null && def.render);
1231
1234
  const context = /*#__PURE__*/React__namespace.createContext(null);
1232
1235
  const createStore = (invalidate, advance) => {
@@ -2056,6 +2059,7 @@ function unmountComponentAtNode(canvas, callback) {
2056
2059
  }
2057
2060
  function createPortal(children, container, state) {
2058
2061
  return /*#__PURE__*/React__namespace.createElement(Portal, {
2062
+ key: container.uuid,
2059
2063
  children: children,
2060
2064
  container: container,
2061
2065
  state: state
@@ -2079,9 +2083,26 @@ function Portal({
2079
2083
  const previousRoot = useStore();
2080
2084
  const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
2081
2085
  const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
2082
- const inject = useMutableCallback((rootState, injectState) => {
2083
- let viewport;
2084
- if (injectState.camera && size) {
2086
+ const inject = React__namespace.useCallback((rootState, injectState) => {
2087
+ const intersect = {
2088
+ ...rootState
2089
+ }; // all prev state props
2090
+
2091
+ // Only the fields of "rootState" that do not differ from injectState
2092
+ // Some props should be off-limits
2093
+ // Otherwise filter out the props that are different and let the inject layer take precedence
2094
+ Object.keys(rootState).forEach(key => {
2095
+ if (
2096
+ // Some props should be off-limits
2097
+ privateKeys.includes(key) ||
2098
+ // Otherwise filter out the props that are different and let the inject layer take precedence
2099
+ // Unless the inject layer props is undefined, then we keep the root layer
2100
+ rootState[key] !== injectState[key] && injectState[key]) {
2101
+ delete intersect[key];
2102
+ }
2103
+ });
2104
+ let viewport = undefined;
2105
+ if (injectState && size) {
2085
2106
  const camera = injectState.camera;
2086
2107
  // Calculate the override viewport, if present
2087
2108
  viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
@@ -2090,9 +2111,7 @@ function Portal({
2090
2111
  }
2091
2112
  return {
2092
2113
  // The intersect consists of the previous root state
2093
- ...rootState,
2094
- get: injectState.get,
2095
- set: injectState.set,
2114
+ ...intersect,
2096
2115
  // Portals have their own scene, which forms the root, a raycaster and a pointer
2097
2116
  scene: container,
2098
2117
  raycaster,
@@ -2103,7 +2122,7 @@ function Portal({
2103
2122
  // Events, size and viewport can be overridden by the inject layer
2104
2123
  events: {
2105
2124
  ...rootState.events,
2106
- ...injectState.events,
2125
+ ...(injectState == null ? void 0 : injectState.events),
2107
2126
  ...events
2108
2127
  },
2109
2128
  size: {
@@ -2114,33 +2133,53 @@ function Portal({
2114
2133
  ...rootState.viewport,
2115
2134
  ...viewport
2116
2135
  },
2136
+ ...rest
2137
+ };
2138
+ }, [state]);
2139
+ const [usePortalStore] = React__namespace.useState(() => {
2140
+ // Create a mirrored store, based on the previous root with a few overrides ...
2141
+ const previousState = previousRoot.getState();
2142
+ const store = create__default["default"]((set, get) => ({
2143
+ ...previousState,
2144
+ scene: container,
2145
+ raycaster,
2146
+ pointer,
2147
+ mouse: pointer,
2148
+ previousRoot,
2149
+ events: {
2150
+ ...previousState.events,
2151
+ ...events
2152
+ },
2153
+ size: {
2154
+ ...previousState.size,
2155
+ ...size
2156
+ },
2157
+ ...rest,
2158
+ // Set and get refer to this root-state
2159
+ set,
2160
+ get,
2117
2161
  // Layers are allowed to override events
2118
- setEvents: events => injectState.set(state => ({
2162
+ setEvents: events => set(state => ({
2119
2163
  ...state,
2120
2164
  events: {
2121
2165
  ...state.events,
2122
2166
  ...events
2123
2167
  }
2124
2168
  }))
2125
- };
2126
- });
2127
- const usePortalStore = React__namespace.useMemo(() => {
2128
- const store = create__default["default"]((set, get) => ({
2129
- ...rest,
2130
- set,
2131
- get
2132
2169
  }));
2133
-
2134
- // Subscribe to previous root-state and copy changes over to the mirrored portal-state
2135
- const onMutate = prev => store.setState(state => inject.current(prev, state));
2136
- onMutate(previousRoot.getState());
2137
- previousRoot.subscribe(onMutate);
2138
2170
  return store;
2139
- // eslint-disable-next-line react-hooks/exhaustive-deps
2140
- }, [previousRoot, container]);
2171
+ });
2172
+ React__namespace.useEffect(() => {
2173
+ // Subscribe to previous root-state and copy changes over to the mirrored portal-state
2174
+ const unsub = previousRoot.subscribe(prev => usePortalStore.setState(state => inject(prev, state)));
2175
+ return () => {
2176
+ unsub();
2177
+ usePortalStore.destroy();
2178
+ };
2179
+ }, []);
2141
2180
  React__namespace.useEffect(() => {
2142
- return () => usePortalStore.destroy();
2143
- }, [usePortalStore]);
2181
+ usePortalStore.setState(injectState => inject(previousRoot.getState(), injectState));
2182
+ }, [inject]);
2144
2183
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, reconciler.createPortal( /*#__PURE__*/React__namespace.createElement(context.Provider, {
2145
2184
  value: usePortalStore
2146
2185
  }, children), usePortalStore, null));