From 8700a6a36b65ccf468a27658d7b1a425a3fb4821 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 21 Jun 2022 14:16:54 +0200 Subject: [PATCH 1/3] Test file --- .../single-element-page-scroll-overlay.html | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 dev/projection/single-element-page-scroll-overlay.html diff --git a/dev/projection/single-element-page-scroll-overlay.html b/dev/projection/single-element-page-scroll-overlay.html new file mode 100644 index 0000000000..e88778cfea --- /dev/null +++ b/dev/projection/single-element-page-scroll-overlay.html @@ -0,0 +1,68 @@ + + + + + +
+
+
+
+ + + + + + + From dde34b67a10fcf0b5ddf684fd76d0e5cfdc444d5 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Thu, 23 Jun 2022 15:30:16 +0200 Subject: [PATCH 2/3] Fixing layout animations within position: fixed --- .../single-element-page-scroll-overlay.html | 2 +- .../projection/node/DocumentProjectionNode.ts | 1 + .../src/projection/node/HTMLProjectionNode.ts | 2 ++ .../node/__tests__/TestProjectionNode.ts | 1 + .../projection/node/create-projection-node.ts | 26 ++++++++++++++++++- .../src/projection/node/types.ts | 2 ++ 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/dev/projection/single-element-page-scroll-overlay.html b/dev/projection/single-element-page-scroll-overlay.html index e88778cfea..1e80495bd7 100644 --- a/dev/projection/single-element-page-scroll-overlay.html +++ b/dev/projection/single-element-page-scroll-overlay.html @@ -46,7 +46,7 @@ const overlay = document.getElementById("overlay") const overlayProjection = createNode(overlay, undefined, { - layoutScroll: "root", + layoutScroll: true, layout: false, }) diff --git a/packages/framer-motion/src/projection/node/DocumentProjectionNode.ts b/packages/framer-motion/src/projection/node/DocumentProjectionNode.ts index 4e8b44d9bd..cb3a696e66 100644 --- a/packages/framer-motion/src/projection/node/DocumentProjectionNode.ts +++ b/packages/framer-motion/src/projection/node/DocumentProjectionNode.ts @@ -10,4 +10,5 @@ export const DocumentProjectionNode = createProjectionNode({ x: document.documentElement.scrollLeft || document.body.scrollLeft, y: document.documentElement.scrollTop || document.body.scrollTop, }), + checkIsScrollRoot: () => true, }) diff --git a/packages/framer-motion/src/projection/node/HTMLProjectionNode.ts b/packages/framer-motion/src/projection/node/HTMLProjectionNode.ts index 0edb76bf36..b5eae94244 100644 --- a/packages/framer-motion/src/projection/node/HTMLProjectionNode.ts +++ b/packages/framer-motion/src/projection/node/HTMLProjectionNode.ts @@ -23,4 +23,6 @@ export const HTMLProjectionNode = createProjectionNode({ resetTransform: (instance, value) => { instance.style.transform = value ?? "none" }, + checkIsScrollRoot: (instance) => + Boolean(window.getComputedStyle(instance).position === "fixed"), }) diff --git a/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts b/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts index 1605cadc11..331ad30385 100644 --- a/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts +++ b/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts @@ -23,6 +23,7 @@ export const TestProjectionNode = createProjectionNode({ return rootNode }, resetTransform: (instance) => instance.resetTransform?.(), + checkIsScrollRoot: () => false, }) let id = 0 diff --git a/packages/framer-motion/src/projection/node/create-projection-node.ts b/packages/framer-motion/src/projection/node/create-projection-node.ts index fc79499195..f7067ff6b9 100644 --- a/packages/framer-motion/src/projection/node/create-projection-node.ts +++ b/packages/framer-motion/src/projection/node/create-projection-node.ts @@ -71,6 +71,7 @@ export function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, + checkIsScrollRoot, resetTransform, }: ProjectionNodeConfig) { return class ProjectionNode implements IProjectionNode { @@ -212,6 +213,11 @@ export function createProjectionNode({ */ scroll?: Point + /** + * If this element is a scroll root, we ignore scrolls up the tree. + */ + isScrollRoot?: boolean + /** * Flag to true if we think this layout has been changed. We can't always know this, * currently we set it to true every time a component renders, or if it has a layoutDependency @@ -718,6 +724,7 @@ export function createProjectionNode({ updateScroll() { if (this.options.layoutScroll && this.instance) { + this.isScrollRoot = checkIsScrollRoot(this.instance) this.scroll = measureScroll(this.instance) } } @@ -776,9 +783,26 @@ export function createProjectionNode({ */ for (let i = 0; i < this.path.length; i++) { const node = this.path[i] - const { scroll, options } = node + const { scroll, options, isScrollRoot } = node if (node !== this.root && scroll && options.layoutScroll) { + /** + * If this is a new scroll root, we want to remove all previous scrolls + * from the viewport box. + */ + if (isScrollRoot) { + copyBoxInto(boxWithoutScroll, box) + const { scroll: rootScroll } = this.root + /** + * Undo the application of page scroll that was originally added + * to the measured bounding box. + */ + if (rootScroll) { + translateAxis(boxWithoutScroll.x, -rootScroll.x) + translateAxis(boxWithoutScroll.y, -rootScroll.y) + } + } + translateAxis(boxWithoutScroll.x, scroll.x) translateAxis(boxWithoutScroll.y, scroll.y) } diff --git a/packages/framer-motion/src/projection/node/types.ts b/packages/framer-motion/src/projection/node/types.ts index 6d84f3976e..b253ad56e0 100644 --- a/packages/framer-motion/src/projection/node/types.ts +++ b/packages/framer-motion/src/projection/node/types.ts @@ -50,6 +50,7 @@ export interface IProjectionNode { targetDelta?: Delta targetWithTransforms?: Box scroll?: Point + isScrollRoot?: boolean treeScale?: Point projectionDelta?: Delta latestValues: ResolvedValues @@ -141,6 +142,7 @@ export interface ProjectionNodeConfig { notifyResize: VoidFunction ) => VoidFunction measureScroll: (instance: I) => Point + checkIsScrollRoot: (instance: I) => boolean resetTransform?: (instance: I, value?: string) => void } From 665af9944a50a29dbdd25de52e890f9b5b6dbf90 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Thu, 23 Jun 2022 15:44:45 +0200 Subject: [PATCH 3/3] Updating test --- .../src/projection/node/__tests__/TestProjectionNode.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts b/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts index 331ad30385..f51497ffe7 100644 --- a/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts +++ b/packages/framer-motion/src/projection/node/__tests__/TestProjectionNode.ts @@ -6,6 +6,7 @@ let rootNode: IProjectionNode export const TestRootNode = createProjectionNode<{}>({ measureScroll: (_instance) => ({ x: 0, y: 0 }), + checkIsScrollRoot: () => true, }) interface TestInstance {