From d283901cb537c3e7bf6f5500e9f52f47f452cf10 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Wed, 21 Aug 2024 15:59:08 +0200 Subject: [PATCH] Loading an overlay page directly would animate in the overlay instead of directly showing it. --- .changeset/fuzzy-hornets-remain.md | 6 +++ .../framer-next-pages/components/Pages.tsx | 5 ++- .../framer-next-pages/context/pageContext.ts | 12 +++++- .../Overlay/components/OverlayBase.tsx | 37 ++++++++++++++++--- 4 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 .changeset/fuzzy-hornets-remain.md diff --git a/.changeset/fuzzy-hornets-remain.md b/.changeset/fuzzy-hornets-remain.md new file mode 100644 index 0000000000..519f300e45 --- /dev/null +++ b/.changeset/fuzzy-hornets-remain.md @@ -0,0 +1,6 @@ +--- +'@graphcommerce/framer-next-pages': patch +'@graphcommerce/next-ui': patch +--- + +Loading an overlay page directly would animate in the overlay instead of directly showing it. diff --git a/packages/framer-next-pages/components/Pages.tsx b/packages/framer-next-pages/components/Pages.tsx index 562da5ad43..c63f179be4 100644 --- a/packages/framer-next-pages/components/Pages.tsx +++ b/packages/framer-next-pages/components/Pages.tsx @@ -5,7 +5,7 @@ import { PrivateRouteInfo } from 'next/dist/shared/lib/router/router' import { AppPropsType } from 'next/dist/shared/lib/utils' import { NextRouter, Router } from 'next/router' import { useEffect, useRef, useState } from 'react' -import { pageContext } from '../context/pageContext' +import { Direction, pageContext } from '../context/pageContext' import type { PageComponent, PageItem, UpPage } from '../types' import { Page } from './Page' import { PageRenderer } from './PageRenderer' @@ -56,7 +56,8 @@ export function FramerNextPages(props: PagesProps) { const idx = routerKeys.indexOf(key) const prevHistory = useRef(-1) - const direction = idx >= prevHistory.current ? 1 : -1 + let direction: Direction = idx >= prevHistory.current ? 1 : -1 + if (prevHistory.current === -1) direction = 0 prevHistory.current = idx diff --git a/packages/framer-next-pages/context/pageContext.ts b/packages/framer-next-pages/context/pageContext.ts index 9ecc85f2eb..5cb618f7ea 100644 --- a/packages/framer-next-pages/context/pageContext.ts +++ b/packages/framer-next-pages/context/pageContext.ts @@ -1,9 +1,17 @@ import { createContext } from 'react' -export type Direction = 1 | -1 +/** + * - `-1` -> Navigated back + * - `0` -> Loaded the page + * - `1` -> Navigated forward + */ +export type Direction = -1 | 0 | 1 export type PageContext = { - /** Number of steps we need to navigate back to go to the last non-overlay page and thus close the overlay */ + /** + * Number of steps we need to navigate back to go to the last non-overlay page and thus close the + * overlay + */ closeSteps: number /** Number of steps we can go back inside the the current overlay */ diff --git a/packages/next-ui/Overlay/components/OverlayBase.tsx b/packages/next-ui/Overlay/components/OverlayBase.tsx index 001ff22d67..747be45ae0 100644 --- a/packages/next-ui/Overlay/components/OverlayBase.tsx +++ b/packages/next-ui/Overlay/components/OverlayBase.tsx @@ -1,3 +1,4 @@ +import { Direction } from '@graphcommerce/framer-next-pages' import { Scroller, useScrollerContext, useScrollTo } from '@graphcommerce/framer-scroller' import { dvh, @@ -46,7 +47,7 @@ export type LayoutOverlayBaseProps = { sx?: SxProps sxBackdrop?: SxProps active: boolean - direction?: 1 | -1 + direction?: Direction onClosed: () => void offsetPageY?: number isPresent: boolean @@ -123,7 +124,8 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) { props.smSpacingTop ?? ((theme) => `calc(${theme.appShell.headerHeightSm} * 0.5)`) )(th) - const { scrollerRef, snap, scroll, getScrollSnapPositions, disableSnap } = useScrollerContext() + const { scrollerRef, snap, scroll, getScrollSnapPositions, disableSnap, enableSnap } = + useScrollerContext() const scrollTo = useScrollTo() const beforeRef = useRef(null) @@ -137,7 +139,7 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) { const match = useMatchMedia() const positions = useConstant(() => ({ - open: { x: motionValue(0), y: motionValue(0), visible: motionValue(0) }, + open: { x: motionValue(0), y: motionValue(0), visible: motionValue(direction === 0 ? 1 : 0) }, closed: { x: motionValue(0), y: motionValue(0) }, })) @@ -277,17 +279,40 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) { useIsomorphicLayoutEffect(() => { const scroller = scrollerRef.current - if (!scroller || !isPresent) return + if (!scroller || !isPresent || position.get() === OverlayPosition.OPENED) return if (variant() === 'right') document.body.style.overflow = 'hidden' - if (position.get() !== OverlayPosition.OPENED && !scroll.animating.get()) { + if (direction === 0) { + disableSnap() + scroller.scrollTop = positions.open.y.get() + scroller.scrollLeft = positions.open.x.get() + scroll.y.set(positions.open.y.get()) + scroll.x.set(positions.open.x.get()) + position.set(OverlayPosition.OPENED) + enableSnap() + } else if (!scroll.animating.get()) { // eslint-disable-next-line @typescript-eslint/no-floating-promises scrollTo(openClosePositions().open, { stopAnimationOnScroll: false }).then(() => position.set(OverlayPosition.OPENED), ) } - }, [isPresent, openClosePositions, position, scroll.animating, scrollTo, scrollerRef, variant]) + }, [ + direction, + disableSnap, + enableSnap, + isPresent, + openClosePositions, + position, + positions.open.x, + positions.open.y, + scroll.animating, + scroll.x, + scroll.y, + scrollTo, + scrollerRef, + variant, + ]) // When the overlay is closed by navigating away, we're closing the overlay. useEffect(() => {