framer-motion 5.4.4 → 5.5.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.
Files changed (29) hide show
  1. package/dist/cjs/index.js +2 -1
  2. package/dist/cjs/three-entry.js +154 -23
  3. package/dist/cjs/{use-motion-value-73ed7c77.js → use-motion-value-28b1fded.js} +3 -1
  4. package/dist/es/components/three/LayoutCamera.mjs +21 -0
  5. package/dist/es/components/three/LayoutOrthographicCamera.mjs +21 -0
  6. package/dist/es/components/three/MotionCanvas.mjs +90 -0
  7. package/dist/es/components/three/MotionCanvasContext.mjs +5 -0
  8. package/dist/es/components/three/use-layout-camera.mjs +87 -0
  9. package/dist/es/context/MotionContext/index.mjs +1 -1
  10. package/dist/es/index.mjs +1 -0
  11. package/dist/es/projection/node/create-projection-node.mjs +3 -1
  12. package/dist/es/render/three/create-visual-element.mjs +3 -1
  13. package/dist/es/render/three/utils/read-value.mjs +3 -2
  14. package/dist/es/three-entry.mjs +3 -1
  15. package/dist/framer-motion.dev.js +4 -1
  16. package/dist/framer-motion.js +1 -1
  17. package/dist/projection.dev.js +3 -1
  18. package/dist/size-rollup-dom-max.js +1 -1
  19. package/package.json +6 -5
  20. package/types/components/three/LayoutCamera.d.ts +26 -0
  21. package/types/components/three/LayoutOrthographicCamera.d.ts +23 -0
  22. package/types/components/{MotionCanvas/index.d.ts → three/MotionCanvas.d.ts} +1 -1
  23. package/types/components/three/MotionCanvasContext.d.ts +11 -0
  24. package/types/components/three/types.d.ts +6 -0
  25. package/types/components/three/use-layout-camera.d.ts +10 -0
  26. package/types/index.d.ts +1 -0
  27. package/types/projection/node/types.d.ts +2 -2
  28. package/types/three-entry.d.ts +3 -1
  29. package/dist/es/components/MotionCanvas/index.mjs +0 -68
package/dist/cjs/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
- var useMotionValue = require('./use-motion-value-73ed7c77.js');
6
+ var useMotionValue = require('./use-motion-value-28b1fded.js');
7
7
  var React = require('react');
8
8
  var styleValueTypes = require('style-value-types');
9
9
  var popmotion = require('popmotion');
@@ -3672,6 +3672,7 @@ function useInvertedScale(scale) {
3672
3672
  exports.FlatTree = useMotionValue.FlatTree;
3673
3673
  exports.LayoutGroupContext = useMotionValue.LayoutGroupContext;
3674
3674
  exports.MotionConfigContext = useMotionValue.MotionConfigContext;
3675
+ exports.MotionContext = useMotionValue.MotionContext;
3675
3676
  exports.MotionValue = useMotionValue.MotionValue;
3676
3677
  exports.PresenceContext = useMotionValue.PresenceContext;
3677
3678
  exports.SwitchLayoutGroupContext = useMotionValue.SwitchLayoutGroupContext;
@@ -3,15 +3,14 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
- var useMotionValue = require('./use-motion-value-73ed7c77.js');
6
+ var useMotionValue = require('./use-motion-value-28b1fded.js');
7
7
  var React = require('react');
8
8
  var popmotion = require('popmotion');
9
9
  var three = require('three');
10
10
  var mergeRefs = require('react-merge-refs');
11
- var useMeasure = require('react-use-measure');
12
11
  var fiber = require('@react-three/fiber');
13
- require('hey-listen');
14
- require('framesync');
12
+ var heyListen = require('hey-listen');
13
+ var sync = require('framesync');
15
14
  require('style-value-types');
16
15
 
17
16
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -36,7 +35,6 @@ function _interopNamespace(e) {
36
35
 
37
36
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
38
37
  var mergeRefs__default = /*#__PURE__*/_interopDefaultLegacy(mergeRefs);
39
- var useMeasure__default = /*#__PURE__*/_interopDefaultLegacy(useMeasure);
40
38
 
41
39
  function useHover(isStatic, _a, visualElement) {
42
40
  var whileHover = _a.whileHover, onHoverStart = _a.onHoverStart, onHoverEnd = _a.onHoverEnd, onPointerOver = _a.onPointerOver, onPointerOut = _a.onPointerOut;
@@ -189,9 +187,10 @@ var readers = {
189
187
  rotateZ: readRotation("z"),
190
188
  };
191
189
  function readAnimatableValue(value) {
192
- if (!value)
190
+ if (value === undefined) {
193
191
  return;
194
- if (value instanceof three.Color) {
192
+ }
193
+ else if (value instanceof three.Color) {
195
194
  return value.getStyle();
196
195
  }
197
196
  else {
@@ -247,7 +246,8 @@ var threeVisualElement = useMotionValue.visualElement({
247
246
  sortNodePosition: function (a, b) {
248
247
  return a.id - b.id;
249
248
  },
250
- makeTargetAnimatable: function (element, target) {
249
+ makeTargetAnimatable: function (element, _a) {
250
+ _a.transition; var target = tslib.__rest(_a, ["transition"]);
251
251
  useMotionValue.checkTargetForNewValues(element, target, {});
252
252
  return target;
253
253
  },
@@ -293,6 +293,15 @@ var motion = new Proxy(custom, {
293
293
  },
294
294
  });
295
295
 
296
+ var MotionCanvasContext = React.createContext(undefined);
297
+
298
+ /**
299
+ * This file contains a version of R3F's Canvas component that uses our projection
300
+ * system for layout measurements instead of use-react-measure so we can keep the
301
+ * projection and cameras in sync.
302
+ *
303
+ * https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/web/Canvas.tsx
304
+ */
296
305
  function Block(_a) {
297
306
  var set = _a.set;
298
307
  useMotionValue.useIsomorphicLayoutEffect(function () {
@@ -317,30 +326,44 @@ var ErrorBoundary = /** @class */ (function (_super) {
317
326
  ErrorBoundary.getDerivedStateFromError = function () { return ({ error: true }); };
318
327
  return ErrorBoundary;
319
328
  }(React__namespace.Component));
320
- /**
321
- * A synchronously rendering version of R3F's Canvas component. We call render
322
- * within the render function itself to ensure lifecycle events are called before
323
- * parent reconcilers. This can be replaced with a simple MotionContext provider
324
- * when R3F moves to the same model.
325
- */
326
- function SyncCanvasComponent(_a, forwardedRef) {
327
- var children = _a.children, fallback = _a.fallback, tabIndex = _a.tabIndex, resize = _a.resize, id = _a.id, style = _a.style, className = _a.className, events = _a.events, props = tslib.__rest(_a, ["children", "fallback", "tabIndex", "resize", "id", "style", "className", "events"]);
329
+ function CanvasComponent(_a, forwardedRef) {
330
+ var children = _a.children, fallback = _a.fallback, tabIndex = _a.tabIndex, id = _a.id, style = _a.style, className = _a.className, events = _a.events, props = tslib.__rest(_a, ["children", "fallback", "tabIndex", "id", "style", "className", "events"]);
331
+ /**
332
+ * Import existing contexts to pass through variants and MotionConfig from
333
+ * the DOM to the 3D tree. Shared variants aren't officially supported yet
334
+ * because the parent DOM tree fires effects before the 3D tree, whereas
335
+ * variants are expected to run from bottom-up in useEffect.
336
+ */
328
337
  var motionContext = React.useContext(useMotionValue.MotionContext);
329
- var _b = tslib.__read(useMeasure__default["default"](tslib.__assign({ scroll: true, debounce: { scroll: 50, resize: 0 } }, resize)), 2), containerRef = _b[0], _c = _b[1], width = _c.width, height = _c.height;
338
+ var configContext = React.useContext(useMotionValue.MotionConfigContext);
339
+ var layoutCamera = React.useRef(null);
340
+ var _b = tslib.__read(React.useState({ width: 0, height: 0 }), 2), size = _b[0], setSize = _b[1];
341
+ var containerRef = React.useRef(null);
342
+ var handleResize = function () {
343
+ var container = containerRef.current;
344
+ setSize({
345
+ width: container.offsetWidth,
346
+ height: container.offsetHeight,
347
+ });
348
+ };
349
+ // Set canvas size on mount
350
+ React.useLayoutEffect(handleResize, []);
330
351
  var canvasRef = React__namespace.useRef(null);
331
- var _d = tslib.__read(React__namespace.useState(false), 2), block = _d[0], setBlock = _d[1];
332
- var _e = tslib.__read(React__namespace.useState(false), 2), error = _e[0], setError = _e[1];
352
+ var _c = tslib.__read(React__namespace.useState(false), 2), block = _c[0], setBlock = _c[1];
353
+ var _d = tslib.__read(React__namespace.useState(false), 2), error = _d[0], setError = _d[1];
333
354
  // Suspend this component if block is a promise (2nd run)
334
355
  if (block)
335
356
  throw block;
336
357
  // Throw exception outwards if anything within canvas throws
337
358
  if (error)
338
359
  throw error;
339
- // Execute JSX in the reconciler as a layout-effect
340
- if (width > 0 && height > 0) {
360
+ // Only render the R3F tree once we have recorded dimensions for the canvas.
361
+ if (size.width > 0 && size.height > 0) {
341
362
  fiber.render(React__namespace.createElement(ErrorBoundary, { set: setError },
342
363
  React__namespace.createElement(React__namespace.Suspense, { fallback: React__namespace.createElement(Block, { set: setBlock }) },
343
- React__namespace.createElement(useMotionValue.MotionContext.Provider, { value: motionContext }, children))), canvasRef.current, tslib.__assign(tslib.__assign({}, props), { size: { width: width, height: height }, events: events || fiber.events }));
364
+ React__namespace.createElement(MotionCanvasContext.Provider, { value: { setSize: setSize, layoutCamera: layoutCamera } },
365
+ React__namespace.createElement(useMotionValue.MotionConfigContext.Provider, { value: configContext },
366
+ React__namespace.createElement(useMotionValue.MotionContext.Provider, { value: motionContext }, children))))), canvasRef.current, tslib.__assign(tslib.__assign({}, props), { size: size, events: events || fiber.events }));
344
367
  }
345
368
  useMotionValue.useIsomorphicLayoutEffect(function () {
346
369
  var container = canvasRef.current;
@@ -349,7 +372,113 @@ function SyncCanvasComponent(_a, forwardedRef) {
349
372
  return (React__namespace.createElement("div", { ref: containerRef, id: id, className: className, tabIndex: tabIndex, style: tslib.__assign({ position: "relative", width: "100%", height: "100%", overflow: "hidden" }, style) },
350
373
  React__namespace.createElement("canvas", { ref: mergeRefs__default["default"]([canvasRef, forwardedRef]), style: { display: "block" } }, fallback)));
351
374
  }
352
- var MotionCanvas = React.forwardRef(SyncCanvasComponent);
375
+ var MotionCanvas = React.forwardRef(CanvasComponent);
376
+
377
+ var calcBoxSize = function (_a) {
378
+ var x = _a.x, y = _a.y;
379
+ return ({
380
+ width: useMotionValue.calcLength(x),
381
+ height: useMotionValue.calcLength(y),
382
+ });
383
+ };
384
+ function useLayoutCamera(_a, updateCamera) {
385
+ var _b = _a.makeDefault, makeDefault = _b === void 0 ? true : _b;
386
+ var context = React.useContext(MotionCanvasContext);
387
+ heyListen.invariant(Boolean(context), "No MotionCanvas detected. Replace Canvas from @react-three/fiber with MotionCanvas from framer-motion.");
388
+ var _c = context, setSize = _c.setSize, layoutCamera = _c.layoutCamera;
389
+ var latestLayout = React.useRef(null);
390
+ var advance = fiber.useThree(function (three) { return three.advance; });
391
+ var set = fiber.useThree(function (three) { return three.set; });
392
+ var camera = fiber.useThree(function (three) { return three.camera; });
393
+ var size = fiber.useThree(function (three) { return three.size; });
394
+ var gl = fiber.useThree(function (three) { return three.gl; });
395
+ var parentVisualElement = useMotionValue.useVisualElementContext();
396
+ React.useLayoutEffect(function () {
397
+ updateCamera(size);
398
+ var projection = parentVisualElement === null || parentVisualElement === void 0 ? void 0 : parentVisualElement.projection;
399
+ if (!projection)
400
+ return;
401
+ /**
402
+ * When the projection of an element changes we want to update the camera
403
+ * with the projected dimensions.
404
+ */
405
+ var removeProjectionUpdateListener = projection.addEventListener("projectionUpdate", function (newProjection) {
406
+ // TODO: Removed to prevent iOS from crashing.
407
+ // Perhaps a better apporach is to set with setSize
408
+ // and then set to window native on animationComplete.
409
+ // if (latestLayout.current) {
410
+ // const { x, y } = latestLayout.current
411
+ // const xRatio = calcLength(newProjection.x) / calcLength(x)
412
+ // const yRatio = calcLength(newProjection.y) / calcLength(y)
413
+ // gl.setPixelRatio(
414
+ // Math.max(xRatio, yRatio) * window.devicePixelRatio
415
+ // )
416
+ // }
417
+ updateCamera(calcBoxSize(newProjection));
418
+ advance(sync.getFrameData().timestamp);
419
+ });
420
+ /**
421
+ * When the layout of an element changes we want to update the renderer
422
+ * output to match the layout dimensions.
423
+ */
424
+ var removeLayoutMeasureListener = projection.addEventListener("measure", function (newLayout) {
425
+ latestLayout.current = newLayout;
426
+ var newSize = calcBoxSize(newLayout);
427
+ gl.setSize(newSize.width, newSize.height);
428
+ setSize(newSize);
429
+ });
430
+ /**
431
+ * When a projection animation completes we want to update the camera to
432
+ * match the recorded layout of the element.
433
+ */
434
+ var removeAnimationCompleteListener = projection.addEventListener("animationComplete", function () {
435
+ var actual = (projection.layout || {}).actual;
436
+ actual && updateCamera(calcBoxSize(actual));
437
+ });
438
+ return function () {
439
+ removeProjectionUpdateListener();
440
+ removeLayoutMeasureListener();
441
+ removeAnimationCompleteListener();
442
+ };
443
+ }, []);
444
+ React.useLayoutEffect(function () {
445
+ var cam = layoutCamera.current;
446
+ if (makeDefault && cam) {
447
+ var oldCam_1 = camera;
448
+ set(function () { return ({ camera: cam }); });
449
+ return function () { return set(function () { return ({ camera: oldCam_1 }); }); };
450
+ }
451
+ }, [camera, layoutCamera, makeDefault, set]);
452
+ return { size: size, camera: camera, cameraRef: layoutCamera };
453
+ }
454
+
455
+ /**
456
+ * Adapted from https://github.com/pmndrs/drei/blob/master/src/core/PerspectiveCamera.tsx
457
+ */
458
+ var LayoutCamera = React__namespace.forwardRef(function (props, ref) {
459
+ var cameraRef = useLayoutCamera(props, function (size) {
460
+ var cam = cameraRef.current;
461
+ if (cam && !props.manual) {
462
+ cam.aspect = size.width / size.height;
463
+ cam.updateProjectionMatrix();
464
+ }
465
+ }).cameraRef;
466
+ return (React__namespace.createElement(motion.perspectiveCamera, tslib.__assign({ ref: mergeRefs__default["default"]([cameraRef, ref]) }, props)));
467
+ });
468
+
469
+ var LayoutOrthographicCamera = React__namespace.forwardRef(function (props, ref) {
470
+ var _a = useLayoutCamera(props, function (newSize) {
471
+ var cam = cameraRef.current;
472
+ if (cam) {
473
+ cam.left = newSize.width / -2;
474
+ cam.right = newSize.width / 2;
475
+ cam.top = newSize.height / 2;
476
+ cam.bottom = newSize.height / -2;
477
+ cam.updateProjectionMatrix();
478
+ }
479
+ }), size = _a.size, cameraRef = _a.cameraRef;
480
+ return (React__namespace.createElement(motion.orthographicCamera, tslib.__assign({ left: size.width / -2, right: size.width / 2, top: size.height / 2, bottom: size.height / -2, ref: mergeRefs__default["default"]([cameraRef, ref]) }, props)));
481
+ });
353
482
 
354
483
  function useTime() {
355
484
  var time = useMotionValue.useMotionValue(0);
@@ -357,6 +486,8 @@ function useTime() {
357
486
  return time;
358
487
  }
359
488
 
489
+ exports.LayoutCamera = LayoutCamera;
490
+ exports.LayoutOrthographicCamera = LayoutOrthographicCamera;
360
491
  exports.MotionCanvas = MotionCanvas;
361
492
  exports.motion = motion;
362
493
  exports.useTime = useTime;
@@ -2119,7 +2119,7 @@ function createProjectionNode(_a) {
2119
2119
  this.layoutCorrected = createBox();
2120
2120
  this.isLayoutDirty = false;
2121
2121
  this.projectionDelta = undefined;
2122
- this.notifyListeners("measure");
2122
+ this.notifyListeners("measure", this.layout.actual);
2123
2123
  (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notifyLayoutMeasure(this.layout.actual, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.actual);
2124
2124
  };
2125
2125
  ProjectionNode.prototype.updateScroll = function () {
@@ -2388,6 +2388,7 @@ function createProjectionNode(_a) {
2388
2388
  this.treeScale.y !== prevTreeScaleY) {
2389
2389
  this.hasProjected = true;
2390
2390
  this.scheduleRender();
2391
+ this.notifyListeners("projectionUpdate", target);
2391
2392
  }
2392
2393
  };
2393
2394
  ProjectionNode.prototype.hide = function () {
@@ -2490,6 +2491,7 @@ function createProjectionNode(_a) {
2490
2491
  this.currentAnimation =
2491
2492
  this.animationValues =
2492
2493
  undefined;
2494
+ this.notifyListeners("animationComplete");
2493
2495
  };
2494
2496
  ProjectionNode.prototype.finishAnimation = function () {
2495
2497
  var _a;
@@ -0,0 +1,21 @@
1
+ import { __assign } from 'tslib';
2
+ import * as React from 'react';
3
+ import mergeRefs from 'react-merge-refs';
4
+ import { motion } from '../../render/three/motion.mjs';
5
+ import { useLayoutCamera } from './use-layout-camera.mjs';
6
+
7
+ /**
8
+ * Adapted from https://github.com/pmndrs/drei/blob/master/src/core/PerspectiveCamera.tsx
9
+ */
10
+ var LayoutCamera = React.forwardRef(function (props, ref) {
11
+ var cameraRef = useLayoutCamera(props, function (size) {
12
+ var cam = cameraRef.current;
13
+ if (cam && !props.manual) {
14
+ cam.aspect = size.width / size.height;
15
+ cam.updateProjectionMatrix();
16
+ }
17
+ }).cameraRef;
18
+ return (React.createElement(motion.perspectiveCamera, __assign({ ref: mergeRefs([cameraRef, ref]) }, props)));
19
+ });
20
+
21
+ export { LayoutCamera };
@@ -0,0 +1,21 @@
1
+ import { __assign } from 'tslib';
2
+ import * as React from 'react';
3
+ import mergeRefs from 'react-merge-refs';
4
+ import { motion } from '../../render/three/motion.mjs';
5
+ import { useLayoutCamera } from './use-layout-camera.mjs';
6
+
7
+ var LayoutOrthographicCamera = React.forwardRef(function (props, ref) {
8
+ var _a = useLayoutCamera(props, function (newSize) {
9
+ var cam = cameraRef.current;
10
+ if (cam) {
11
+ cam.left = newSize.width / -2;
12
+ cam.right = newSize.width / 2;
13
+ cam.top = newSize.height / 2;
14
+ cam.bottom = newSize.height / -2;
15
+ cam.updateProjectionMatrix();
16
+ }
17
+ }), size = _a.size, cameraRef = _a.cameraRef;
18
+ return (React.createElement(motion.orthographicCamera, __assign({ left: size.width / -2, right: size.width / 2, top: size.height / 2, bottom: size.height / -2, ref: mergeRefs([cameraRef, ref]) }, props)));
19
+ });
20
+
21
+ export { LayoutOrthographicCamera };
@@ -0,0 +1,90 @@
1
+ import { __extends, __rest, __read, __assign } from 'tslib';
2
+ import * as React from 'react';
3
+ import { forwardRef, useContext, useRef, useState, useLayoutEffect } from 'react';
4
+ import { MotionContext } from '../../context/MotionContext/index.mjs';
5
+ import mergeRefs from 'react-merge-refs';
6
+ import { render, events, unmountComponentAtNode } from '@react-three/fiber';
7
+ import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
8
+ import { MotionConfigContext } from '../../context/MotionConfigContext.mjs';
9
+ import { MotionCanvasContext } from './MotionCanvasContext.mjs';
10
+
11
+ /**
12
+ * This file contains a version of R3F's Canvas component that uses our projection
13
+ * system for layout measurements instead of use-react-measure so we can keep the
14
+ * projection and cameras in sync.
15
+ *
16
+ * https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/web/Canvas.tsx
17
+ */
18
+ function Block(_a) {
19
+ var set = _a.set;
20
+ useIsomorphicLayoutEffect(function () {
21
+ set(new Promise(function () { return null; }));
22
+ return function () { return set(false); };
23
+ }, []);
24
+ return null;
25
+ }
26
+ var ErrorBoundary = /** @class */ (function (_super) {
27
+ __extends(ErrorBoundary, _super);
28
+ function ErrorBoundary() {
29
+ var _this = _super !== null && _super.apply(this, arguments) || this;
30
+ _this.state = { error: false };
31
+ return _this;
32
+ }
33
+ ErrorBoundary.prototype.componentDidCatch = function (error) {
34
+ this.props.set(error);
35
+ };
36
+ ErrorBoundary.prototype.render = function () {
37
+ return this.state.error ? null : this.props.children;
38
+ };
39
+ ErrorBoundary.getDerivedStateFromError = function () { return ({ error: true }); };
40
+ return ErrorBoundary;
41
+ }(React.Component));
42
+ function CanvasComponent(_a, forwardedRef) {
43
+ var children = _a.children, fallback = _a.fallback, tabIndex = _a.tabIndex, id = _a.id, style = _a.style, className = _a.className, events$1 = _a.events, props = __rest(_a, ["children", "fallback", "tabIndex", "id", "style", "className", "events"]);
44
+ /**
45
+ * Import existing contexts to pass through variants and MotionConfig from
46
+ * the DOM to the 3D tree. Shared variants aren't officially supported yet
47
+ * because the parent DOM tree fires effects before the 3D tree, whereas
48
+ * variants are expected to run from bottom-up in useEffect.
49
+ */
50
+ var motionContext = useContext(MotionContext);
51
+ var configContext = useContext(MotionConfigContext);
52
+ var layoutCamera = useRef(null);
53
+ var _b = __read(useState({ width: 0, height: 0 }), 2), size = _b[0], setSize = _b[1];
54
+ var containerRef = useRef(null);
55
+ var handleResize = function () {
56
+ var container = containerRef.current;
57
+ setSize({
58
+ width: container.offsetWidth,
59
+ height: container.offsetHeight,
60
+ });
61
+ };
62
+ // Set canvas size on mount
63
+ useLayoutEffect(handleResize, []);
64
+ var canvasRef = React.useRef(null);
65
+ var _c = __read(React.useState(false), 2), block = _c[0], setBlock = _c[1];
66
+ var _d = __read(React.useState(false), 2), error = _d[0], setError = _d[1];
67
+ // Suspend this component if block is a promise (2nd run)
68
+ if (block)
69
+ throw block;
70
+ // Throw exception outwards if anything within canvas throws
71
+ if (error)
72
+ throw error;
73
+ // Only render the R3F tree once we have recorded dimensions for the canvas.
74
+ if (size.width > 0 && size.height > 0) {
75
+ render(React.createElement(ErrorBoundary, { set: setError },
76
+ React.createElement(React.Suspense, { fallback: React.createElement(Block, { set: setBlock }) },
77
+ React.createElement(MotionCanvasContext.Provider, { value: { setSize: setSize, layoutCamera: layoutCamera } },
78
+ React.createElement(MotionConfigContext.Provider, { value: configContext },
79
+ React.createElement(MotionContext.Provider, { value: motionContext }, children))))), canvasRef.current, __assign(__assign({}, props), { size: size, events: events$1 || events }));
80
+ }
81
+ useIsomorphicLayoutEffect(function () {
82
+ var container = canvasRef.current;
83
+ return function () { return unmountComponentAtNode(container); };
84
+ }, []);
85
+ return (React.createElement("div", { ref: containerRef, id: id, className: className, tabIndex: tabIndex, style: __assign({ position: "relative", width: "100%", height: "100%", overflow: "hidden" }, style) },
86
+ React.createElement("canvas", { ref: mergeRefs([canvasRef, forwardedRef]), style: { display: "block" } }, fallback)));
87
+ }
88
+ var MotionCanvas = forwardRef(CanvasComponent);
89
+
90
+ export { MotionCanvas };
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+
3
+ var MotionCanvasContext = createContext(undefined);
4
+
5
+ export { MotionCanvasContext };
@@ -0,0 +1,87 @@
1
+ import { useContext, useRef, useLayoutEffect } from 'react';
2
+ import { useThree } from '@react-three/fiber';
3
+ import { useVisualElementContext } from '../../context/MotionContext/index.mjs';
4
+ import { MotionCanvasContext } from './MotionCanvasContext.mjs';
5
+ import { invariant } from 'hey-listen';
6
+ import { calcLength } from '../../projection/geometry/delta-calc.mjs';
7
+ import { getFrameData } from 'framesync';
8
+
9
+ var calcBoxSize = function (_a) {
10
+ var x = _a.x, y = _a.y;
11
+ return ({
12
+ width: calcLength(x),
13
+ height: calcLength(y),
14
+ });
15
+ };
16
+ function useLayoutCamera(_a, updateCamera) {
17
+ var _b = _a.makeDefault, makeDefault = _b === void 0 ? true : _b;
18
+ var context = useContext(MotionCanvasContext);
19
+ invariant(Boolean(context), "No MotionCanvas detected. Replace Canvas from @react-three/fiber with MotionCanvas from framer-motion.");
20
+ var _c = context, setSize = _c.setSize, layoutCamera = _c.layoutCamera;
21
+ var latestLayout = useRef(null);
22
+ var advance = useThree(function (three) { return three.advance; });
23
+ var set = useThree(function (three) { return three.set; });
24
+ var camera = useThree(function (three) { return three.camera; });
25
+ var size = useThree(function (three) { return three.size; });
26
+ var gl = useThree(function (three) { return three.gl; });
27
+ var parentVisualElement = useVisualElementContext();
28
+ useLayoutEffect(function () {
29
+ updateCamera(size);
30
+ var projection = parentVisualElement === null || parentVisualElement === void 0 ? void 0 : parentVisualElement.projection;
31
+ if (!projection)
32
+ return;
33
+ /**
34
+ * When the projection of an element changes we want to update the camera
35
+ * with the projected dimensions.
36
+ */
37
+ var removeProjectionUpdateListener = projection.addEventListener("projectionUpdate", function (newProjection) {
38
+ // TODO: Removed to prevent iOS from crashing.
39
+ // Perhaps a better apporach is to set with setSize
40
+ // and then set to window native on animationComplete.
41
+ // if (latestLayout.current) {
42
+ // const { x, y } = latestLayout.current
43
+ // const xRatio = calcLength(newProjection.x) / calcLength(x)
44
+ // const yRatio = calcLength(newProjection.y) / calcLength(y)
45
+ // gl.setPixelRatio(
46
+ // Math.max(xRatio, yRatio) * window.devicePixelRatio
47
+ // )
48
+ // }
49
+ updateCamera(calcBoxSize(newProjection));
50
+ advance(getFrameData().timestamp);
51
+ });
52
+ /**
53
+ * When the layout of an element changes we want to update the renderer
54
+ * output to match the layout dimensions.
55
+ */
56
+ var removeLayoutMeasureListener = projection.addEventListener("measure", function (newLayout) {
57
+ latestLayout.current = newLayout;
58
+ var newSize = calcBoxSize(newLayout);
59
+ gl.setSize(newSize.width, newSize.height);
60
+ setSize(newSize);
61
+ });
62
+ /**
63
+ * When a projection animation completes we want to update the camera to
64
+ * match the recorded layout of the element.
65
+ */
66
+ var removeAnimationCompleteListener = projection.addEventListener("animationComplete", function () {
67
+ var actual = (projection.layout || {}).actual;
68
+ actual && updateCamera(calcBoxSize(actual));
69
+ });
70
+ return function () {
71
+ removeProjectionUpdateListener();
72
+ removeLayoutMeasureListener();
73
+ removeAnimationCompleteListener();
74
+ };
75
+ }, []);
76
+ useLayoutEffect(function () {
77
+ var cam = layoutCamera.current;
78
+ if (makeDefault && cam) {
79
+ var oldCam_1 = camera;
80
+ set(function () { return ({ camera: cam }); });
81
+ return function () { return set(function () { return ({ camera: oldCam_1 }); }); };
82
+ }
83
+ }, [camera, layoutCamera, makeDefault, set]);
84
+ return { size: size, camera: camera, cameraRef: layoutCamera };
85
+ }
86
+
87
+ export { useLayoutCamera };
@@ -1,4 +1,4 @@
1
- import { useContext, createContext } from 'react';
1
+ import { createContext, useContext } from 'react';
2
2
 
3
3
  var MotionContext = createContext({});
4
4
  function useVisualElementContext() {
package/dist/es/index.mjs CHANGED
@@ -36,6 +36,7 @@ export { addScaleCorrector } from './projection/styles/scale-correction.mjs';
36
36
  export { useInstantTransition } from './utils/use-instant-transition.mjs';
37
37
  export { useInstantLayoutTransition } from './projection/use-instant-layout-transition.mjs';
38
38
  export { useResetProjection } from './projection/use-reset-projection.mjs';
39
+ export { MotionContext } from './context/MotionContext/index.mjs';
39
40
  export { MotionConfigContext } from './context/MotionConfigContext.mjs';
40
41
  export { PresenceContext } from './context/PresenceContext.mjs';
41
42
  export { LayoutGroupContext } from './context/LayoutGroupContext.mjs';
@@ -430,7 +430,7 @@ function createProjectionNode(_a) {
430
430
  this.layoutCorrected = createBox();
431
431
  this.isLayoutDirty = false;
432
432
  this.projectionDelta = undefined;
433
- this.notifyListeners("measure");
433
+ this.notifyListeners("measure", this.layout.actual);
434
434
  (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notifyLayoutMeasure(this.layout.actual, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.actual);
435
435
  };
436
436
  ProjectionNode.prototype.updateScroll = function () {
@@ -699,6 +699,7 @@ function createProjectionNode(_a) {
699
699
  this.treeScale.y !== prevTreeScaleY) {
700
700
  this.hasProjected = true;
701
701
  this.scheduleRender();
702
+ this.notifyListeners("projectionUpdate", target);
702
703
  }
703
704
  };
704
705
  ProjectionNode.prototype.hide = function () {
@@ -801,6 +802,7 @@ function createProjectionNode(_a) {
801
802
  this.currentAnimation =
802
803
  this.animationValues =
803
804
  undefined;
805
+ this.notifyListeners("animationComplete");
804
806
  };
805
807
  ProjectionNode.prototype.finishAnimation = function () {
806
808
  var _a;
@@ -1,3 +1,4 @@
1
+ import { __rest } from 'tslib';
1
2
  import { visualElement } from '../index.mjs';
2
3
  import { createBox } from '../../projection/geometry/models.mjs';
3
4
  import { checkTargetForNewValues } from '../utils/setters.mjs';
@@ -15,7 +16,8 @@ var threeVisualElement = visualElement({
15
16
  sortNodePosition: function (a, b) {
16
17
  return a.id - b.id;
17
18
  },
18
- makeTargetAnimatable: function (element, target) {
19
+ makeTargetAnimatable: function (element, _a) {
20
+ _a.transition; var target = __rest(_a, ["transition"]);
19
21
  checkTargetForNewValues(element, target, {});
20
22
  return target;
21
23
  },
@@ -24,9 +24,10 @@ var readers = {
24
24
  rotateZ: readRotation("z"),
25
25
  };
26
26
  function readAnimatableValue(value) {
27
- if (!value)
27
+ if (value === undefined) {
28
28
  return;
29
- if (value instanceof Color) {
29
+ }
30
+ else if (value instanceof Color) {
30
31
  return value.getStyle();
31
32
  }
32
33
  else {
@@ -1,3 +1,5 @@
1
1
  export { motion } from './render/three/motion.mjs';
2
- export { MotionCanvas } from './components/MotionCanvas/index.mjs';
2
+ export { MotionCanvas } from './components/three/MotionCanvas.mjs';
3
+ export { LayoutCamera } from './components/three/LayoutCamera.mjs';
4
+ export { LayoutOrthographicCamera } from './components/three/LayoutOrthographicCamera.mjs';
3
5
  export { useTime } from './render/three/utils/use-time.mjs';
@@ -3354,7 +3354,7 @@
3354
3354
  this.layoutCorrected = createBox();
3355
3355
  this.isLayoutDirty = false;
3356
3356
  this.projectionDelta = undefined;
3357
- this.notifyListeners("measure");
3357
+ this.notifyListeners("measure", this.layout.actual);
3358
3358
  (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notifyLayoutMeasure(this.layout.actual, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.actual);
3359
3359
  };
3360
3360
  ProjectionNode.prototype.updateScroll = function () {
@@ -3623,6 +3623,7 @@
3623
3623
  this.treeScale.y !== prevTreeScaleY) {
3624
3624
  this.hasProjected = true;
3625
3625
  this.scheduleRender();
3626
+ this.notifyListeners("projectionUpdate", target);
3626
3627
  }
3627
3628
  };
3628
3629
  ProjectionNode.prototype.hide = function () {
@@ -3725,6 +3726,7 @@
3725
3726
  this.currentAnimation =
3726
3727
  this.animationValues =
3727
3728
  undefined;
3729
+ this.notifyListeners("animationComplete");
3728
3730
  };
3729
3731
  ProjectionNode.prototype.finishAnimation = function () {
3730
3732
  var _a;
@@ -9530,6 +9532,7 @@
9530
9532
  exports.LazyMotion = LazyMotion;
9531
9533
  exports.MotionConfig = MotionConfig;
9532
9534
  exports.MotionConfigContext = MotionConfigContext;
9535
+ exports.MotionContext = MotionContext;
9533
9536
  exports.MotionValue = MotionValue;
9534
9537
  exports.PresenceContext = PresenceContext;
9535
9538
  exports.Reorder = Reorder;