@react-three/fiber 9.0.0-alpha.3 → 9.0.0-alpha.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.
@@ -9,7 +9,7 @@ import type { Instance } from "./reconciler.js";
9
9
  *
10
10
  * **Note**: this is an escape hatch to react-internal fields. Expect this to change significantly between versions.
11
11
  */
12
- export declare function useInstanceHandle<O>(ref: React.MutableRefObject<O>): React.MutableRefObject<Instance>;
12
+ export declare function useInstanceHandle<O>(ref: React.RefObject<O>): React.RefObject<Instance>;
13
13
  export declare function useStore(): RootStore;
14
14
  /**
15
15
  * Accesses R3F's internal state, containing renderer, canvas, scene, etc.
@@ -9,7 +9,7 @@ export type { ReconcilerRoot, GLProps, CameraProps, RenderProps, InjectState } f
9
9
  export { _roots, render, createRoot, unmountComponentAtNode, createPortal } from "./renderer.js";
10
10
  export type { UpdateSubscription } from "./stages.js";
11
11
  export { Stage, FixedStage, Stages } from "./stages.js";
12
- export type { Subscription, Dpr, Size, Viewport, RenderCallback, UpdateCallback, LegacyAlways, FrameloopMode, FrameloopRender, FrameloopLegacy, Frameloop, Performance, Renderer, StageTypes, XRManager, RootState, RootStore, } from "./store.js";
12
+ export type { Subscription, Dpr, Size, RenderCallback, UpdateCallback, LegacyAlways, FrameloopMode, FrameloopRender, FrameloopLegacy, Frameloop, Performance, Renderer, StageTypes, XRManager, RootState, RootStore, } from "./store.js";
13
13
  export { context } from "./store.js";
14
14
  export type { ObjectMap, Camera, Disposable, Act } from "./utils.js";
15
15
  export { applyProps, getRootState, dispose, act, buildGraph } from "./utils.js";
@@ -35,7 +35,6 @@ export interface Instance<O = any> {
35
35
  handlers: Partial<EventHandlers>;
36
36
  attach?: AttachType<O>;
37
37
  previousAttach?: any;
38
- isHidden: boolean;
39
38
  autoRemovedBeforeAppend?: boolean;
40
39
  }
41
40
  export declare const catalogue: Catalogue;
@@ -6,16 +6,15 @@ import { Root } from "./reconciler.js";
6
6
  import { EventManager, ComputeFunction } from "./events.js";
7
7
  import { Camera } from "./utils.js";
8
8
  import { Stage } from "./stages.js";
9
- declare var OffscreenCanvas: any;
10
- type OffscreenCanvas = any;
11
- type Canvas = HTMLCanvasElement | OffscreenCanvas;
12
- export declare const _roots: Map<any, Root>;
13
- export type GLProps = Renderer | ((canvas: Canvas) => Renderer) | Partial<Properties<THREE.WebGLRenderer> | THREE.WebGLRendererParameters>;
9
+ interface OffscreenCanvas extends EventTarget {
10
+ }
11
+ export declare const _roots: Map<HTMLCanvasElement | OffscreenCanvas, Root>;
12
+ export type GLProps = Renderer | ((canvas: HTMLCanvasElement | OffscreenCanvas) => Renderer) | Partial<Properties<THREE.WebGLRenderer> | THREE.WebGLRendererParameters>;
14
13
  export type CameraProps = (Camera | Partial<ThreeElement<typeof THREE.Camera> & ThreeElement<typeof THREE.PerspectiveCamera> & ThreeElement<typeof THREE.OrthographicCamera>>) & {
15
14
  /** Flags the camera as manual, putting projection into your own hands */
16
15
  manual?: boolean;
17
16
  };
18
- export interface RenderProps<TCanvas extends Canvas> {
17
+ export interface RenderProps<TCanvas extends HTMLCanvasElement | OffscreenCanvas> {
19
18
  /** A threejs renderer instance or props that go into the default renderer */
20
19
  gl?: GLProps;
21
20
  /** Dimensions to fit the renderer to. Will measure canvas dimensions if omitted */
@@ -65,14 +64,14 @@ export interface RenderProps<TCanvas extends Canvas> {
65
64
  stages?: Stage[];
66
65
  render?: 'auto' | 'manual';
67
66
  }
68
- export interface ReconcilerRoot<TCanvas extends Canvas> {
67
+ export interface ReconcilerRoot<TCanvas extends HTMLCanvasElement | OffscreenCanvas> {
69
68
  configure: (config?: RenderProps<TCanvas>) => ReconcilerRoot<TCanvas>;
70
69
  render: (element: React.ReactNode) => RootStore;
71
70
  unmount: () => void;
72
71
  }
73
- export declare function createRoot<TCanvas extends Canvas>(canvas: TCanvas): ReconcilerRoot<TCanvas>;
74
- export declare function render<TCanvas extends Canvas>(children: React.ReactNode, canvas: TCanvas, config: RenderProps<TCanvas>): RootStore;
75
- export declare function unmountComponentAtNode<TCanvas extends Canvas>(canvas: TCanvas, callback?: (canvas: TCanvas) => void): void;
72
+ export declare function createRoot<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(canvas: TCanvas): ReconcilerRoot<TCanvas>;
73
+ export declare function render<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(children: React.ReactNode, canvas: TCanvas, config: RenderProps<TCanvas>): RootStore;
74
+ export declare function unmountComponentAtNode<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(canvas: TCanvas, callback?: (canvas: TCanvas) => void): void;
76
75
  export type InjectState = Partial<Omit<RootState, 'events'> & {
77
76
  events?: {
78
77
  enabled?: boolean;
@@ -1,7 +1,8 @@
1
1
  /// <reference types="webxr" />
2
2
  import * as THREE from 'three';
3
3
  import * as React from 'react';
4
- import { type StoreApi, type UseBoundStore } from 'zustand';
4
+ import { type StoreApi } from 'zustand';
5
+ import { type UseBoundStoreWithEqualityFn } from 'zustand/traditional';
5
6
  import type { DomEvent, EventManager, PointerCaptureTarget, ThreeEvent } from "./events.js";
6
7
  import { type Camera } from "./utils.js";
7
8
  import type { FixedStage, Stage } from "./stages.js";
@@ -9,7 +10,7 @@ export interface Intersection extends THREE.Intersection {
9
10
  eventObject: THREE.Object3D;
10
11
  }
11
12
  export type Subscription = {
12
- ref: React.MutableRefObject<RenderCallback>;
13
+ ref: React.RefObject<RenderCallback>;
13
14
  priority: number;
14
15
  store: RootStore;
15
16
  };
@@ -20,18 +21,6 @@ export interface Size {
20
21
  top: number;
21
22
  left: number;
22
23
  }
23
- export interface Viewport extends Size {
24
- /** The initial pixel ratio */
25
- initialDpr: number;
26
- /** Current pixel ratio */
27
- dpr: number;
28
- /** size.width / viewport.width */
29
- factor: number;
30
- /** Camera distance */
31
- distance: number;
32
- /** Camera aspect ratio: width / height */
33
- aspect: number;
34
- }
35
24
  export type RenderCallback = (state: RootState, delta: number, frame?: XRFrame) => void;
36
25
  export type UpdateCallback = RenderCallback;
37
26
  export type LegacyAlways = 'always';
@@ -67,7 +56,7 @@ export interface InternalState {
67
56
  capturedMap: Map<number, Map<THREE.Object3D, PointerCaptureTarget>>;
68
57
  initialClick: [x: number, y: number];
69
58
  initialHits: THREE.Object3D[];
70
- lastEvent: React.MutableRefObject<DomEvent | null>;
59
+ lastEvent: React.RefObject<DomEvent | null>;
71
60
  active: boolean;
72
61
  priority: number;
73
62
  frames: number;
@@ -77,7 +66,7 @@ export interface InternalState {
77
66
  render: 'auto' | 'manual';
78
67
  /** The max delta time between two frames. */
79
68
  maxDelta: number;
80
- subscribe: (callback: React.MutableRefObject<RenderCallback>, priority: number, store: RootStore) => () => void;
69
+ subscribe: (callback: React.RefObject<RenderCallback>, priority: number, store: RootStore) => () => void;
81
70
  }
82
71
  export interface XRManager {
83
72
  connect: () => void;
@@ -117,12 +106,10 @@ export interface RootState {
117
106
  frameloop: FrameloopLegacy;
118
107
  /** Adaptive performance interface */
119
108
  performance: Performance;
109
+ /** The current pixel ratio */
110
+ dpr: number;
120
111
  /** Reactive pixel-size of the canvas */
121
112
  size: Size;
122
- /** Reactive size of the viewport in threejs units */
123
- viewport: Viewport & {
124
- getCurrentViewport: (camera?: Camera, target?: THREE.Vector3 | Parameters<THREE.Vector3['set']>, size?: Size) => Omit<Viewport, 'dpr' | 'initialDpr'>;
125
- };
126
113
  /** Flags the canvas for render, but doesn't render in itself */
127
114
  invalidate: (frames?: number) => void;
128
115
  /** Advance (render) one step */
@@ -142,6 +129,6 @@ export interface RootState {
142
129
  /** Internals */
143
130
  internal: InternalState;
144
131
  }
145
- export type RootStore = UseBoundStore<StoreApi<RootState>>;
132
+ export type RootStore = UseBoundStoreWithEqualityFn<StoreApi<RootState>>;
146
133
  export declare const context: React.Context<RootStore>;
147
134
  export declare const createStore: (invalidate: (state?: RootState, frames?: number) => void, advance: (timestamp: number, runGlobalEffects?: boolean, state?: RootState, frame?: XRFrame) => void) => RootStore;
@@ -33,7 +33,7 @@ export type Camera = (THREE.OrthographicCamera | THREE.PerspectiveCamera) & {
33
33
  manual?: boolean;
34
34
  };
35
35
  export declare const isOrthographicCamera: (def: Camera) => def is THREE.OrthographicCamera;
36
- export declare const isRef: (obj: any) => obj is React.MutableRefObject<unknown>;
36
+ export declare const isRef: (obj: any) => obj is React.RefObject<unknown>;
37
37
  /**
38
38
  * An SSR-friendly useLayoutEffect.
39
39
  *
@@ -44,7 +44,7 @@ export declare const isRef: (obj: any) => obj is React.MutableRefObject<unknown>
44
44
  * @see https://github.com/facebook/react/issues/14927
45
45
  */
46
46
  export declare const useIsomorphicLayoutEffect: typeof React.useLayoutEffect;
47
- export declare function useMutableCallback<T>(fn: T): React.MutableRefObject<T>;
47
+ export declare function useMutableCallback<T>(fn: T): React.RefObject<T>;
48
48
  export type Bridge = React.FC<{
49
49
  children?: React.ReactNode;
50
50
  }>;
@@ -121,7 +121,7 @@ export declare function resolve(root: any, key: string): {
121
121
  export declare function attach(parent: Instance, child: Instance): void;
122
122
  export declare function detach(parent: Instance, child: Instance): void;
123
123
  export declare const RESERVED_PROPS: string[];
124
- export declare function diffProps<T = any>(instance: Instance<T>, newProps: Instance<T>['props'], resetRemoved?: boolean): Instance<T>['props'];
124
+ export declare function diffProps<T = any>(instance: Instance<T>, newProps: Instance<T>['props']): Instance<T>['props'];
125
125
  export declare function applyProps<T = any>(object: Instance<T>['object'], props: Instance<T>['props']): Instance<T>['object'];
126
126
  export declare function invalidateInstance(instance: Instance): void;
127
127
  export declare function updateCamera(camera: Camera, size: Size): void;
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { View, ViewProps, ViewStyle } from 'react-native';
3
3
  import { RenderProps } from "../core/index.js";
4
- export interface CanvasProps extends Omit<RenderProps<HTMLCanvasElement>, 'size' | 'dpr'>, ViewProps {
4
+ export interface CanvasProps extends Omit<RenderProps<HTMLCanvasElement>, 'size' | 'dpr'>, Omit<ViewProps, 'children'> {
5
5
  children: React.ReactNode;
6
6
  style?: ViewStyle;
7
7
  }
@@ -47,7 +47,7 @@ export interface ThreeElements extends ThreeElementsImpl {
47
47
  object: object;
48
48
  };
49
49
  }
50
- declare global {
50
+ declare module 'react' {
51
51
  namespace JSX {
52
52
  interface IntrinsicElements extends ThreeElements {
53
53
  }
@@ -11,7 +11,7 @@ export interface CanvasProps extends Omit<RenderProps<HTMLCanvasElement>, 'size'
11
11
  */
12
12
  resize?: ResizeOptions;
13
13
  /** The target where events are being subscribed to, default: the div that wraps canvas */
14
- eventSource?: HTMLElement | React.MutableRefObject<HTMLElement>;
14
+ eventSource?: HTMLElement | React.RefObject<HTMLElement>;
15
15
  /** The event prefix that is cast into canvas pointer x/y events, default: "offset" */
16
16
  eventPrefix?: 'offset' | 'client' | 'page' | 'layer' | 'screen';
17
17
  }
@@ -3,7 +3,7 @@
3
3
  var THREE = require('three');
4
4
  var React = require('react');
5
5
  var constants = require('react-reconciler/constants');
6
- var zustand = require('zustand');
6
+ var traditional = require('zustand/traditional');
7
7
  var itsFine = require('its-fine');
8
8
  var _extends = require('@babel/runtime/helpers/extends');
9
9
  var Reconciler = require('react-reconciler');
@@ -50,7 +50,7 @@ const extend = objects => {
50
50
  catalogue[Component] = objects;
51
51
 
52
52
  // Returns a component whose name will be inferred in devtools
53
- // @ts-ignore
53
+ // @ts-expect-error
54
54
  return /*#__PURE__*/React__namespace.forwardRef({
55
55
  [objects.name]: (props, ref) => /*#__PURE__*/React__namespace.createElement(Component, _extends({}, props, {
56
56
  ref: ref
@@ -256,31 +256,6 @@ function switchInstance(oldInstance, type, props, fiber) {
256
256
  const handleTextInstance = () => console.warn('R3F: Text is not allowed in JSX! This could be stray whitespace or characters.');
257
257
  const NO_CONTEXT = {};
258
258
  let currentUpdatePriority = constants.NoEventPriority;
259
-
260
- // Effectively removed to diff in commit phase
261
- // https://github.com/facebook/react/pull/27409
262
- function prepareUpdate(instance, _type, oldProps, newProps) {
263
- var _newProps$args, _oldProps$args, _newProps$args2;
264
- // Reconstruct primitives if object prop changes
265
- if (instance.type === 'primitive' && oldProps.object !== newProps.object) return [true];
266
-
267
- // Throw if an object or literal was passed for args
268
- if (newProps.args !== undefined && !Array.isArray(newProps.args)) throw new Error('R3F: The args prop must be an array!');
269
-
270
- // Reconstruct instance if args change
271
- if (((_newProps$args = newProps.args) == null ? void 0 : _newProps$args.length) !== ((_oldProps$args = oldProps.args) == null ? void 0 : _oldProps$args.length)) return [true];
272
- if ((_newProps$args2 = newProps.args) != null && _newProps$args2.some((value, index) => {
273
- var _oldProps$args2;
274
- return value !== ((_oldProps$args2 = oldProps.args) == null ? void 0 : _oldProps$args2[index]);
275
- })) return [true];
276
-
277
- // Create a diff-set, flag if there are any changes
278
- const changedProps = diffProps(instance, newProps, true);
279
- if (Object.keys(changedProps).length) return [false, changedProps];
280
-
281
- // Otherwise do not touch the instance
282
- return null;
283
- }
284
259
  const reconciler = Reconciler__default["default"]({
285
260
  isPrimaryRenderer: false,
286
261
  warnsIfNotActing: false,
@@ -309,18 +284,32 @@ const reconciler = Reconciler__default["default"]({
309
284
  },
310
285
  getRootHostContext: () => NO_CONTEXT,
311
286
  getChildHostContext: () => NO_CONTEXT,
312
- // @ts-ignore prepareUpdate and updatePayload removed with React 19
287
+ // @ts-expect-error prepareUpdate and updatePayload removed with React 19
313
288
  commitUpdate(instance, type, oldProps, newProps, fiber) {
314
- const diff = prepareUpdate(instance, type, oldProps, newProps);
315
- if (diff === null) return;
316
- const [reconstruct, changedProps] = diff;
289
+ var _newProps$args, _oldProps$args, _newProps$args2;
290
+ let reconstruct = false;
291
+
292
+ // Reconstruct primitives if object prop changes
293
+ if (instance.type === 'primitive' && oldProps.object !== newProps.object) reconstruct = true;
294
+ // Reconstruct instance if args was changed to an invalid value
295
+ else if (newProps.args !== undefined && !Array.isArray(newProps.args)) reconstruct = true;
296
+ // Reconstruct instance if args were added or removed
297
+ else if (((_newProps$args = newProps.args) == null ? void 0 : _newProps$args.length) !== ((_oldProps$args = oldProps.args) == null ? void 0 : _oldProps$args.length)) reconstruct = true;
298
+ // Reconstruct instance if args were changed
299
+ else if ((_newProps$args2 = newProps.args) != null && _newProps$args2.some((value, index) => {
300
+ var _oldProps$args2;
301
+ return value !== ((_oldProps$args2 = oldProps.args) == null ? void 0 : _oldProps$args2[index]);
302
+ })) reconstruct = true;
317
303
 
318
304
  // Reconstruct when args or <primitive object={...} have changes
319
305
  if (reconstruct) return switchInstance(instance, type, newProps, fiber);
320
306
 
321
- // Otherwise just overwrite props
322
- Object.assign(instance.props, changedProps);
323
- applyProps(instance.object, changedProps);
307
+ // Create a diff-set, flag if there are any changes
308
+ const changedProps = diffProps(instance, newProps);
309
+ if (Object.keys(changedProps).length) {
310
+ Object.assign(instance.props, changedProps);
311
+ applyProps(instance.object, changedProps);
312
+ }
324
313
  },
325
314
  finalizeInitialChildren: () => false,
326
315
  commitMount() {},
@@ -330,28 +319,8 @@ const reconciler = Reconciler__default["default"]({
330
319
  resetAfterCommit: () => {},
331
320
  shouldSetTextContent: () => false,
332
321
  clearContainer: () => false,
333
- hideInstance(instance) {
334
- var _instance$parent;
335
- if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
336
- detach(instance.parent, instance);
337
- } else if (isObject3D(instance.object)) {
338
- instance.object.visible = false;
339
- }
340
- instance.isHidden = true;
341
- invalidateInstance(instance);
342
- },
343
- unhideInstance(instance) {
344
- if (instance.isHidden) {
345
- var _instance$parent2;
346
- if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
347
- attach(instance.parent, instance);
348
- } else if (isObject3D(instance.object) && instance.props.visible !== false) {
349
- instance.object.visible = true;
350
- }
351
- }
352
- instance.isHidden = false;
353
- invalidateInstance(instance);
354
- },
322
+ hideInstance() {},
323
+ unhideInstance() {},
355
324
  createTextInstance: handleTextInstance,
356
325
  hideTextInstance: handleTextInstance,
357
326
  unhideTextInstance: handleTextInstance,
@@ -362,7 +331,6 @@ const reconciler = Reconciler__default["default"]({
362
331
  beforeActiveInstanceBlur() {},
363
332
  afterActiveInstanceBlur() {},
364
333
  detachDeletedInstance() {},
365
- // @ts-ignore untyped react-experimental options inspired by react-art
366
334
  // TODO: add shell types for these and upstream to DefinitelyTyped
367
335
  // https://github.com/facebook/react/blob/main/packages/react-art/src/ReactFiberConfigART.js
368
336
  shouldAttemptEagerTransition() {
@@ -417,8 +385,7 @@ var _window$document, _window$navigator;
417
385
  */
418
386
  function findInitialRoot(instance) {
419
387
  let root = instance.root;
420
- // TODO: this needs testing https://github.com/pmndrs/react-three-fiber/commit/a4a31ed93c48d1e6dac91329bb5f2ca6a25e5f9c
421
- // while (root.getState().previousRoot) root = root.getState().previousRoot!
388
+ while (root.getState().previousRoot) root = root.getState().previousRoot;
422
389
  return root;
423
390
  }
424
391
 
@@ -608,8 +575,7 @@ function prepare(target, root, type, props) {
608
575
  props: getInstanceProps(props),
609
576
  object,
610
577
  eventCount: 0,
611
- handlers: {},
612
- isHidden: false
578
+ handlers: {}
613
579
  };
614
580
  if (object) {
615
581
  object.__r3f = instance;
@@ -688,7 +654,7 @@ const RESERVED_PROPS = [...REACT_INTERNAL_PROPS,
688
654
  const MEMOIZED_PROTOTYPES = new Map();
689
655
 
690
656
  // This function prepares a set of changes to be applied to the instance
691
- function diffProps(instance, newProps, resetRemoved = false) {
657
+ function diffProps(instance, newProps) {
692
658
  const changedProps = {};
693
659
 
694
660
  // Sort through props
@@ -708,31 +674,29 @@ function diffProps(instance, newProps, resetRemoved = false) {
708
674
  }
709
675
 
710
676
  // Reset removed props for HMR
711
- if (resetRemoved) {
712
- for (const prop in instance.props) {
713
- if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
714
- const {
715
- root,
716
- key
717
- } = resolve(instance.object, prop);
718
-
719
- // https://github.com/mrdoob/three.js/issues/21209
720
- // HMR/fast-refresh relies on the ability to cancel out props, but threejs
721
- // has no means to do this. Hence we curate a small collection of value-classes
722
- // with their respective constructor/set arguments
723
- // For removed props, try to set default values, if possible
724
- if (root.constructor && root.constructor.length === 0) {
725
- // create a blank slate of the instance and copy the particular parameter.
726
- let ctor = MEMOIZED_PROTOTYPES.get(root.constructor);
727
- if (!ctor) {
728
- ctor = new root.constructor();
729
- MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
730
- }
731
- changedProps[key] = ctor[key];
732
- } else {
733
- // instance does not have constructor, just set it to 0
734
- changedProps[key] = 0;
677
+ for (const prop in instance.props) {
678
+ if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
679
+ const {
680
+ root,
681
+ key
682
+ } = resolve(instance.object, prop);
683
+
684
+ // https://github.com/mrdoob/three.js/issues/21209
685
+ // HMR/fast-refresh relies on the ability to cancel out props, but threejs
686
+ // has no means to do this. Hence we curate a small collection of value-classes
687
+ // with their respective constructor/set arguments
688
+ // For removed props, try to set default values, if possible
689
+ if (root.constructor && root.constructor.length === 0) {
690
+ // create a blank slate of the instance and copy the particular parameter.
691
+ let ctor = MEMOIZED_PROTOTYPES.get(root.constructor);
692
+ if (!ctor) {
693
+ ctor = new root.constructor();
694
+ MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
735
695
  }
696
+ changedProps[key] = ctor[key];
697
+ } else {
698
+ // instance does not have constructor, just set it to 0
699
+ changedProps[key] = 0;
736
700
  }
737
701
  }
738
702
  return changedProps;
@@ -1282,45 +1246,7 @@ function createEvents(store) {
1282
1246
  const isRenderer = def => !!(def != null && def.render);
1283
1247
  const context = /*#__PURE__*/React__namespace.createContext(null);
1284
1248
  const createStore = (invalidate, advance) => {
1285
- const rootStore = zustand.create((set, get) => {
1286
- const position = new THREE__namespace.Vector3();
1287
- const defaultTarget = new THREE__namespace.Vector3();
1288
- const tempTarget = new THREE__namespace.Vector3();
1289
- function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
1290
- const {
1291
- width,
1292
- height,
1293
- top,
1294
- left
1295
- } = size;
1296
- const aspect = width / height;
1297
- if (target instanceof THREE__namespace.Vector3) tempTarget.copy(target);else tempTarget.set(...target);
1298
- const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
1299
- if (isOrthographicCamera(camera)) {
1300
- return {
1301
- width: width / camera.zoom,
1302
- height: height / camera.zoom,
1303
- top,
1304
- left,
1305
- factor: 1,
1306
- distance,
1307
- aspect
1308
- };
1309
- } else {
1310
- const fov = camera.fov * Math.PI / 180; // convert vertical fov to radians
1311
- const h = 2 * Math.tan(fov / 2) * distance; // visible height
1312
- const w = h * (width / height);
1313
- return {
1314
- width: w,
1315
- height: h,
1316
- top,
1317
- left,
1318
- factor: width / w,
1319
- distance,
1320
- aspect
1321
- };
1322
- }
1323
- }
1249
+ const rootStore = traditional.createWithEqualityFn((set, get) => {
1324
1250
  let performanceTimeout = undefined;
1325
1251
  const setPerformanceCurrent = current => set(state => ({
1326
1252
  performance: {
@@ -1369,24 +1295,13 @@ const createStore = (invalidate, advance) => {
1369
1295
  performanceTimeout = setTimeout(() => setPerformanceCurrent(get().performance.max), state.performance.debounce);
1370
1296
  }
1371
1297
  },
1298
+ dpr: 1,
1372
1299
  size: {
1373
1300
  width: 0,
1374
1301
  height: 0,
1375
1302
  top: 0,
1376
1303
  left: 0
1377
1304
  },
1378
- viewport: {
1379
- initialDpr: 0,
1380
- dpr: 0,
1381
- width: 0,
1382
- height: 0,
1383
- top: 0,
1384
- left: 0,
1385
- aspect: 0,
1386
- distance: 0,
1387
- factor: 0,
1388
- getCurrentViewport
1389
- },
1390
1305
  setEvents: events => set(state => ({
1391
1306
  ...state,
1392
1307
  events: {
@@ -1395,30 +1310,17 @@ const createStore = (invalidate, advance) => {
1395
1310
  }
1396
1311
  })),
1397
1312
  setSize: (width, height, top = 0, left = 0) => {
1398
- const camera = get().camera;
1399
- const size = {
1400
- width,
1401
- height,
1402
- top,
1403
- left
1404
- };
1405
- set(state => ({
1406
- size,
1407
- viewport: {
1408
- ...state.viewport,
1409
- ...getCurrentViewport(camera, defaultTarget, size)
1313
+ set({
1314
+ size: {
1315
+ width,
1316
+ height,
1317
+ top,
1318
+ left
1410
1319
  }
1411
- }));
1320
+ });
1412
1321
  },
1413
- setDpr: dpr => set(state => {
1414
- const resolved = calculateDpr(dpr);
1415
- return {
1416
- viewport: {
1417
- ...state.viewport,
1418
- dpr: resolved,
1419
- initialDpr: state.viewport.initialDpr || resolved
1420
- }
1421
- };
1322
+ setDpr: dpr => set({
1323
+ dpr: calculateDpr(dpr)
1422
1324
  }),
1423
1325
  setFrameloop: frameloop => {
1424
1326
  var _frameloop$mode, _frameloop$render, _frameloop$maxDelta;
@@ -1507,39 +1409,23 @@ const createStore = (invalidate, advance) => {
1507
1409
  });
1508
1410
  const state = rootStore.getState();
1509
1411
  let oldSize = state.size;
1510
- let oldDpr = state.viewport.dpr;
1511
- let oldCamera = state.camera;
1512
- rootStore.subscribe(() => {
1513
- const {
1514
- camera,
1515
- size,
1516
- viewport,
1517
- gl,
1518
- set
1519
- } = rootStore.getState();
1520
-
1412
+ let oldDpr = state.dpr;
1413
+ rootStore.subscribe(({
1414
+ camera,
1415
+ size,
1416
+ dpr,
1417
+ gl
1418
+ }) => {
1521
1419
  // Resize camera and renderer on changes to size and pixelratio
1522
- if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
1420
+ if (size !== oldSize || dpr !== oldDpr) {
1523
1421
  oldSize = size;
1524
- oldDpr = viewport.dpr;
1422
+ oldDpr = dpr;
1525
1423
  // Update camera & renderer
1526
1424
  updateCamera(camera, size);
1527
- gl.setPixelRatio(viewport.dpr);
1425
+ gl.setPixelRatio(dpr);
1528
1426
  const updateStyle = typeof HTMLCanvasElement !== 'undefined' && gl.domElement instanceof HTMLCanvasElement;
1529
1427
  gl.setSize(size.width, size.height, updateStyle);
1530
1428
  }
1531
-
1532
- // Update viewport once the camera changes
1533
- if (camera !== oldCamera) {
1534
- oldCamera = camera;
1535
- // Update viewport
1536
- set(state => ({
1537
- viewport: {
1538
- ...state.viewport,
1539
- ...state.viewport.getCurrentViewport(camera)
1540
- }
1541
- }));
1542
- }
1543
1429
  });
1544
1430
 
1545
1431
  // Invalidate on any change
@@ -1704,7 +1590,6 @@ function useStore() {
1704
1590
  * @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usethree
1705
1591
  */
1706
1592
  function useThree(selector = state => state, equalityFn) {
1707
- // TODO: fix this type
1708
1593
  return useStore()(selector, equalityFn);
1709
1594
  }
1710
1595
 
@@ -1804,7 +1689,8 @@ useLoader.clear = function (loader, input) {
1804
1689
  return suspendReact.clear([loader, ...keys]);
1805
1690
  };
1806
1691
 
1807
- // TODO: fix type resolve
1692
+ // Shim for OffscreenCanvas since it was removed from DOM types
1693
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/54988
1808
1694
 
1809
1695
  const _roots = new Map();
1810
1696
  const shallowLoose = {
@@ -2123,7 +2009,7 @@ function createRoot(canvas) {
2123
2009
  state.setSize(size.width, size.height, size.top, size.left);
2124
2010
  }
2125
2011
  // Check pixelratio
2126
- if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
2012
+ if (dpr && state.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
2127
2013
  // Check frameloop
2128
2014
  if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
2129
2015
  // Check pointer missed
@@ -2246,11 +2132,8 @@ function Portal({
2246
2132
  const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
2247
2133
  const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
2248
2134
  const inject = useMutableCallback((rootState, injectState) => {
2249
- let viewport;
2250
2135
  if (injectState.camera && size) {
2251
2136
  const camera = injectState.camera;
2252
- // Calculate the override viewport, if present
2253
- viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
2254
2137
  // Update the portal camera, if it differs from the previous layer
2255
2138
  if (camera !== rootState.camera) updateCamera(camera, size);
2256
2139
  }
@@ -2266,7 +2149,7 @@ function Portal({
2266
2149
  mouse: pointer,
2267
2150
  // Their previous root is the layer before it
2268
2151
  previousRoot,
2269
- // Events, size and viewport can be overridden by the inject layer
2152
+ // Events and size can be overridden by the inject layer
2270
2153
  events: {
2271
2154
  ...rootState.events,
2272
2155
  ...injectState.events,
@@ -2276,10 +2159,6 @@ function Portal({
2276
2159
  ...rootState.size,
2277
2160
  ...size
2278
2161
  },
2279
- viewport: {
2280
- ...rootState.viewport,
2281
- ...viewport
2282
- },
2283
2162
  // Layers are allowed to override events
2284
2163
  setEvents: events => injectState.set(state => ({
2285
2164
  ...state,
@@ -2291,7 +2170,7 @@ function Portal({
2291
2170
  };
2292
2171
  });
2293
2172
  const usePortalStore = React__namespace.useMemo(() => {
2294
- const store = zustand.create((set, get) => ({
2173
+ const store = traditional.createWithEqualityFn((set, get) => ({
2295
2174
  ...rest,
2296
2175
  set,
2297
2176
  get