framer-motion 5.4.3 → 5.5.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 (30) hide show
  1. package/dist/cjs/index.js +2 -1
  2. package/dist/cjs/three-entry.js +193 -10
  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 +82 -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 +8 -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/three/MotionCanvas.d.ts +5 -0
  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 -14
  30. package/types/components/MotionCanvas/index.d.ts +0 -4
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,18 @@
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
+ var mergeRefs = require('react-merge-refs');
10
11
  var fiber = require('@react-three/fiber');
11
- require('hey-listen');
12
- require('framesync');
12
+ var heyListen = require('hey-listen');
13
+ var sync = require('framesync');
13
14
  require('style-value-types');
14
15
 
16
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
17
+
15
18
  function _interopNamespace(e) {
16
19
  if (e && e.__esModule) return e;
17
20
  var n = Object.create(null);
@@ -31,6 +34,7 @@ function _interopNamespace(e) {
31
34
  }
32
35
 
33
36
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
37
+ var mergeRefs__default = /*#__PURE__*/_interopDefaultLegacy(mergeRefs);
34
38
 
35
39
  function useHover(isStatic, _a, visualElement) {
36
40
  var whileHover = _a.whileHover, onHoverStart = _a.onHoverStart, onHoverEnd = _a.onHoverEnd, onPointerOver = _a.onPointerOver, onPointerOut = _a.onPointerOut;
@@ -183,9 +187,10 @@ var readers = {
183
187
  rotateZ: readRotation("z"),
184
188
  };
185
189
  function readAnimatableValue(value) {
186
- if (!value)
190
+ if (value === undefined) {
187
191
  return;
188
- if (value instanceof three.Color) {
192
+ }
193
+ else if (value instanceof three.Color) {
189
194
  return value.getStyle();
190
195
  }
191
196
  else {
@@ -241,7 +246,8 @@ var threeVisualElement = useMotionValue.visualElement({
241
246
  sortNodePosition: function (a, b) {
242
247
  return a.id - b.id;
243
248
  },
244
- makeTargetAnimatable: function (element, target) {
249
+ makeTargetAnimatable: function (element, _a) {
250
+ _a.transition; var target = tslib.__rest(_a, ["transition"]);
245
251
  useMotionValue.checkTargetForNewValues(element, target, {});
246
252
  return target;
247
253
  },
@@ -287,12 +293,187 @@ var motion = new Proxy(custom, {
287
293
  },
288
294
  });
289
295
 
290
- function MotionCanvas(_a) {
291
- var children = _a.children, props = tslib.__rest(_a, ["children"]);
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
+ */
305
+ function Block(_a) {
306
+ var set = _a.set;
307
+ useMotionValue.useIsomorphicLayoutEffect(function () {
308
+ set(new Promise(function () { return null; }));
309
+ return function () { return set(false); };
310
+ }, []);
311
+ return null;
312
+ }
313
+ var ErrorBoundary = /** @class */ (function (_super) {
314
+ tslib.__extends(ErrorBoundary, _super);
315
+ function ErrorBoundary() {
316
+ var _this = _super !== null && _super.apply(this, arguments) || this;
317
+ _this.state = { error: false };
318
+ return _this;
319
+ }
320
+ ErrorBoundary.prototype.componentDidCatch = function (error) {
321
+ this.props.set(error);
322
+ };
323
+ ErrorBoundary.prototype.render = function () {
324
+ return this.state.error ? null : this.props.children;
325
+ };
326
+ ErrorBoundary.getDerivedStateFromError = function () { return ({ error: true }); };
327
+ return ErrorBoundary;
328
+ }(React__namespace.Component));
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
+ */
292
337
  var motionContext = React.useContext(useMotionValue.MotionContext);
293
- return (React__namespace.createElement(fiber.Canvas, tslib.__assign({}, props),
294
- React__namespace.createElement(useMotionValue.MotionContext.Provider, { value: motionContext }, children)));
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, []);
351
+ var canvasRef = React__namespace.useRef(null);
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];
354
+ // Suspend this component if block is a promise (2nd run)
355
+ if (block)
356
+ throw block;
357
+ // Throw exception outwards if anything within canvas throws
358
+ if (error)
359
+ throw error;
360
+ // Only render the R3F tree once we have recorded dimensions for the canvas.
361
+ if (size.width > 0 && size.height > 0) {
362
+ fiber.render(React__namespace.createElement(ErrorBoundary, { set: setError },
363
+ React__namespace.createElement(React__namespace.Suspense, { fallback: React__namespace.createElement(Block, { set: setBlock }) },
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 }));
367
+ }
368
+ useMotionValue.useIsomorphicLayoutEffect(function () {
369
+ var container = canvasRef.current;
370
+ return function () { return fiber.unmountComponentAtNode(container); };
371
+ }, []);
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) },
373
+ React__namespace.createElement("canvas", { ref: mergeRefs__default["default"]([canvasRef, forwardedRef]), style: { display: "block" } }, fallback)));
295
374
  }
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
+ if (latestLayout.current) {
407
+ var _a = latestLayout.current, x = _a.x, y = _a.y;
408
+ var xRatio = useMotionValue.calcLength(newProjection.x) / useMotionValue.calcLength(x);
409
+ var yRatio = useMotionValue.calcLength(newProjection.y) / useMotionValue.calcLength(y);
410
+ gl.setPixelRatio(Math.max(xRatio, yRatio) * window.devicePixelRatio);
411
+ }
412
+ updateCamera(calcBoxSize(newProjection));
413
+ advance(sync.getFrameData().timestamp);
414
+ });
415
+ /**
416
+ * When the layout of an element changes we want to update the renderer
417
+ * output to match the layout dimensions.
418
+ */
419
+ var removeLayoutMeasureListener = projection.addEventListener("measure", function (newLayout) {
420
+ latestLayout.current = newLayout;
421
+ var newSize = calcBoxSize(newLayout);
422
+ gl.setSize(newSize.width, newSize.height);
423
+ setSize(newSize);
424
+ });
425
+ /**
426
+ * When a projection animation completes we want to update the camera to
427
+ * match the recorded layout of the element.
428
+ */
429
+ var removeAnimationCompleteListener = projection.addEventListener("animationComplete", function () {
430
+ var actual = (projection.layout || {}).actual;
431
+ actual && updateCamera(calcBoxSize(actual));
432
+ });
433
+ return function () {
434
+ removeProjectionUpdateListener();
435
+ removeLayoutMeasureListener();
436
+ removeAnimationCompleteListener();
437
+ };
438
+ }, []);
439
+ React.useLayoutEffect(function () {
440
+ var cam = layoutCamera.current;
441
+ if (makeDefault && cam) {
442
+ var oldCam_1 = camera;
443
+ set(function () { return ({ camera: cam }); });
444
+ return function () { return set(function () { return ({ camera: oldCam_1 }); }); };
445
+ }
446
+ }, [camera, layoutCamera, makeDefault, set]);
447
+ return { size: size, camera: camera, cameraRef: layoutCamera };
448
+ }
449
+
450
+ /**
451
+ * Adapted from https://github.com/pmndrs/drei/blob/master/src/core/PerspectiveCamera.tsx
452
+ */
453
+ var LayoutCamera = React__namespace.forwardRef(function (props, ref) {
454
+ var cameraRef = useLayoutCamera(props, function (size) {
455
+ var cam = cameraRef.current;
456
+ if (cam && !props.manual) {
457
+ cam.aspect = size.width / size.height;
458
+ cam.updateProjectionMatrix();
459
+ }
460
+ }).cameraRef;
461
+ return (React__namespace.createElement(motion.perspectiveCamera, tslib.__assign({ ref: mergeRefs__default["default"]([cameraRef, ref]) }, props)));
462
+ });
463
+
464
+ var LayoutOrthographicCamera = React__namespace.forwardRef(function (props, ref) {
465
+ var _a = useLayoutCamera(props, function (newSize) {
466
+ var cam = cameraRef.current;
467
+ if (cam) {
468
+ cam.left = newSize.width / -2;
469
+ cam.right = newSize.width / 2;
470
+ cam.top = newSize.height / 2;
471
+ cam.bottom = newSize.height / -2;
472
+ cam.updateProjectionMatrix();
473
+ }
474
+ }), size = _a.size, cameraRef = _a.cameraRef;
475
+ 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)));
476
+ });
296
477
 
297
478
  function useTime() {
298
479
  var time = useMotionValue.useMotionValue(0);
@@ -300,6 +481,8 @@ function useTime() {
300
481
  return time;
301
482
  }
302
483
 
484
+ exports.LayoutCamera = LayoutCamera;
485
+ exports.LayoutOrthographicCamera = LayoutOrthographicCamera;
303
486
  exports.MotionCanvas = MotionCanvas;
304
487
  exports.motion = motion;
305
488
  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,82 @@
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
+ if (latestLayout.current) {
39
+ var _a = latestLayout.current, x = _a.x, y = _a.y;
40
+ var xRatio = calcLength(newProjection.x) / calcLength(x);
41
+ var yRatio = calcLength(newProjection.y) / calcLength(y);
42
+ gl.setPixelRatio(Math.max(xRatio, yRatio) * window.devicePixelRatio);
43
+ }
44
+ updateCamera(calcBoxSize(newProjection));
45
+ advance(getFrameData().timestamp);
46
+ });
47
+ /**
48
+ * When the layout of an element changes we want to update the renderer
49
+ * output to match the layout dimensions.
50
+ */
51
+ var removeLayoutMeasureListener = projection.addEventListener("measure", function (newLayout) {
52
+ latestLayout.current = newLayout;
53
+ var newSize = calcBoxSize(newLayout);
54
+ gl.setSize(newSize.width, newSize.height);
55
+ setSize(newSize);
56
+ });
57
+ /**
58
+ * When a projection animation completes we want to update the camera to
59
+ * match the recorded layout of the element.
60
+ */
61
+ var removeAnimationCompleteListener = projection.addEventListener("animationComplete", function () {
62
+ var actual = (projection.layout || {}).actual;
63
+ actual && updateCamera(calcBoxSize(actual));
64
+ });
65
+ return function () {
66
+ removeProjectionUpdateListener();
67
+ removeLayoutMeasureListener();
68
+ removeAnimationCompleteListener();
69
+ };
70
+ }, []);
71
+ useLayoutEffect(function () {
72
+ var cam = layoutCamera.current;
73
+ if (makeDefault && cam) {
74
+ var oldCam_1 = camera;
75
+ set(function () { return ({ camera: cam }); });
76
+ return function () { return set(function () { return ({ camera: oldCam_1 }); }); };
77
+ }
78
+ }, [camera, layoutCamera, makeDefault, set]);
79
+ return { size: size, camera: camera, cameraRef: layoutCamera };
80
+ }
81
+
82
+ 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;