@graphcommerce/framer-next-pages 3.2.2 → 3.2.5
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.
- package/CHANGELOG.md +24 -0
- package/components/Page.tsx +7 -6
- package/components/PageRenderer.tsx +1 -1
- package/components/Pages.tsx +56 -35
- package/context/pageContext.ts +1 -1
- package/hooks/useScrollOffsetY.ts +11 -3
- package/package.json +7 -7
- package/types.ts +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 3.2.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`707dbc73d`](https://github.com/graphcommerce-org/graphcommerce/commit/707dbc73d181204d88fdbbd2e09340e25b2b5f7b), [`5c5645e6e`](https://github.com/graphcommerce-org/graphcommerce/commit/5c5645e6eaf5314c063f05547707fcd4b34a8717)]:
|
|
8
|
+
- @graphcommerce/framer-utils@3.1.5
|
|
9
|
+
|
|
10
|
+
## 3.2.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`18054c441`](https://github.com/graphcommerce-org/graphcommerce/commit/18054c441962ba750bed3acc39ab46c8d3a341ce) Thanks [@paales](https://github.com/paales)! - Updated to Next.js v12.2.2 and other packages and made compatible
|
|
15
|
+
|
|
16
|
+
* [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`21886d6fa`](https://github.com/graphcommerce-org/graphcommerce/commit/21886d6fa64a48d9e932bfaf8d138c9b13c36e43) Thanks [@paales](https://github.com/paales)! - Fix page stacking and scroll restoration when navigating
|
|
17
|
+
|
|
18
|
+
## 3.2.3
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#1490](https://github.com/graphcommerce-org/graphcommerce/pull/1490) [`d311ef48b`](https://github.com/graphcommerce-org/graphcommerce/commit/d311ef48bb3e97806d992af5516d6b7f183ec9cb) Thanks [@paales](https://github.com/paales)! - upgraded packages
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [[`d311ef48b`](https://github.com/graphcommerce-org/graphcommerce/commit/d311ef48bb3e97806d992af5516d6b7f183ec9cb)]:
|
|
25
|
+
- @graphcommerce/framer-utils@3.1.4
|
|
26
|
+
|
|
3
27
|
## 3.2.2
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/components/Page.tsx
CHANGED
|
@@ -3,38 +3,39 @@ import { m, useIsPresent } from 'framer-motion'
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import type { PageItem } from '../types'
|
|
5
5
|
|
|
6
|
-
export type PageProps = Pick<PageItem, '
|
|
6
|
+
export type PageProps = Pick<PageItem, 'routerKey'> & {
|
|
7
7
|
active: boolean
|
|
8
8
|
children: React.ReactNode
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function scrollPos(
|
|
12
|
-
const scroll = global.window?.sessionStorage[`__next_scroll_${
|
|
11
|
+
export function scrollPos(key: string): { x: number; y: number } {
|
|
12
|
+
const scroll = global.window?.sessionStorage[`__next_scroll_${key}`]
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
14
14
|
return scroll ? JSON.parse(scroll) : { x: 0, y: 0 }
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function Page(props: PageProps) {
|
|
18
|
-
const { active,
|
|
18
|
+
const { active, routerKey, children } = props
|
|
19
19
|
const isPresent = useIsPresent()
|
|
20
20
|
|
|
21
21
|
/** The active Page doesn't get any special treatment */
|
|
22
22
|
let top: number | undefined
|
|
23
23
|
|
|
24
24
|
/** If the Page isn't active, we offset the page */
|
|
25
|
-
if (!active) top = scrollPos(
|
|
25
|
+
if (!active) top = scrollPos(routerKey).y * -1
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* If the Page isn't present as a child of <AnimatePresence/>, but it is still present in the DOM,
|
|
29
29
|
* we're navigating back, so we need to offset it.
|
|
30
30
|
*/
|
|
31
|
-
if (!isPresent) top = scrollPos(
|
|
31
|
+
if (!isPresent) top = scrollPos(routerKey).y
|
|
32
32
|
|
|
33
33
|
const position = active && isPresent ? 'absolute' : 'fixed'
|
|
34
34
|
const zIndex = active ? 1 : undefined
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<m.div
|
|
38
|
+
layoutScroll
|
|
38
39
|
style={{ position, top, zIndex, minHeight: clientSizeCssVar.y, left: 0, right: 0 }}
|
|
39
40
|
// @ts-expect-error inert is not in the type definition yet
|
|
40
41
|
inert={!active ? 'true' : undefined}
|
|
@@ -5,7 +5,7 @@ import React, { useMemo } from 'react'
|
|
|
5
5
|
import { pageRouterContext } from '../context/pageRouterContext'
|
|
6
6
|
import { PageItem } from '../types'
|
|
7
7
|
|
|
8
|
-
const NoLayout: React.FC = ({ children }) => <>{children}</>
|
|
8
|
+
const NoLayout: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>
|
|
9
9
|
|
|
10
10
|
export type PageRendererProps = Omit<AppPropsType, 'router'> & {
|
|
11
11
|
Layout: React.ComponentType<AppPropsType>
|
package/components/Pages.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { clientSizeCssVar, useClientSizeCssVar } from '@graphcommerce/framer-utils'
|
|
2
2
|
import { AnimatePresence, m } from 'framer-motion'
|
|
3
3
|
import { requestIdleCallback, cancelIdleCallback } from 'next/dist/client/request-idle-callback'
|
|
4
|
+
import { HistoryState, PrivateRouteInfo } from 'next/dist/shared/lib/router/router'
|
|
4
5
|
import { AppPropsType } from 'next/dist/shared/lib/utils'
|
|
5
6
|
import { NextRouter, Router } from 'next/router'
|
|
6
7
|
import { useEffect, useRef, useState } from 'react'
|
|
@@ -44,14 +45,23 @@ function getPageInfo(router: NextRouter) {
|
|
|
44
45
|
export function FramerNextPages(props: PagesProps) {
|
|
45
46
|
const { router, Component, pageProps: incomingProps, fallback = '/', fallbackRoute = '/' } = props
|
|
46
47
|
|
|
48
|
+
// @ts-expect-error Key of the route is still private, should be fixed in https://github.com/vercel/next.js/pull/37192
|
|
49
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
50
|
+
const key = router._key as string
|
|
51
|
+
|
|
47
52
|
useClientSizeCssVar()
|
|
48
53
|
const items = useRef<PageItem[]>([])
|
|
49
|
-
|
|
54
|
+
|
|
55
|
+
const routerKeys = items.current.map((item) => item.routerKey)
|
|
56
|
+
if (routerKeys.indexOf(key) === -1) routerKeys.push(key)
|
|
57
|
+
const idx = routerKeys.indexOf(key)
|
|
58
|
+
|
|
50
59
|
const prevHistory = useRef<number>(-1)
|
|
51
|
-
const [fb, setFallback] = useState<PageItem>()
|
|
52
60
|
const direction = idx > prevHistory.current ? 1 : -1
|
|
53
61
|
prevHistory.current = idx
|
|
54
62
|
|
|
63
|
+
const [fb, setFallback] = useState<PageItem>()
|
|
64
|
+
|
|
55
65
|
/** We never need to render anything beyong the current idx and we can safely omit everything */
|
|
56
66
|
items.current = items.current.slice(0, idx + 1)
|
|
57
67
|
|
|
@@ -76,6 +86,7 @@ export function FramerNextPages(props: PagesProps) {
|
|
|
76
86
|
sharedKey: Component.pageOptions?.sharedKey?.(pageInfo) ?? pageInfo.pathname,
|
|
77
87
|
overlayGroup: Component.pageOptions?.overlayGroup,
|
|
78
88
|
historyIdx: idx,
|
|
89
|
+
routerKey: key,
|
|
79
90
|
routerContext: {
|
|
80
91
|
pageInfo,
|
|
81
92
|
prevPage: items.current[idx - 1]?.routerContext,
|
|
@@ -102,16 +113,23 @@ export function FramerNextPages(props: PagesProps) {
|
|
|
102
113
|
// todo: implement fallback loading for up property
|
|
103
114
|
// const up = items.current[0].PageComponent.pageOptions?.up?.href ?? '/'
|
|
104
115
|
const up = '/'
|
|
105
|
-
const info = await (router as Router).getRouteInfo(
|
|
106
|
-
fallbackRoute,
|
|
107
|
-
fallback,
|
|
108
|
-
{},
|
|
109
|
-
fallback,
|
|
110
|
-
fallback,
|
|
111
|
-
{ shallow: false },
|
|
112
|
-
router.locale,
|
|
113
|
-
false,
|
|
114
|
-
|
|
116
|
+
const info = await (router as Router).getRouteInfo({
|
|
117
|
+
route: fallbackRoute,
|
|
118
|
+
pathname: fallback,
|
|
119
|
+
query: {},
|
|
120
|
+
as: fallback,
|
|
121
|
+
resolvedAs: fallback,
|
|
122
|
+
routeProps: { shallow: false },
|
|
123
|
+
locale: router.locale,
|
|
124
|
+
hasMiddleware: false,
|
|
125
|
+
isPreview: false,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const isPrivateRouteInfo = (
|
|
129
|
+
infoResult: Awaited<ReturnType<Router['getRouteInfo']>>,
|
|
130
|
+
): infoResult is PrivateRouteInfo => 'Component' in infoResult
|
|
131
|
+
|
|
132
|
+
if (!isPrivateRouteInfo(info)) return
|
|
115
133
|
|
|
116
134
|
const pageInfo = { asPath: up, pathname: up, locale: router.locale, query: {} }
|
|
117
135
|
const Fallback = info.Component as PageComponent
|
|
@@ -122,6 +140,7 @@ export function FramerNextPages(props: PagesProps) {
|
|
|
122
140
|
sharedKey: Fallback.pageOptions?.sharedKey?.(pageInfo) ?? pageInfo.pathname,
|
|
123
141
|
overlayGroup: Fallback.pageOptions?.overlayGroup,
|
|
124
142
|
historyIdx: -1,
|
|
143
|
+
routerKey: 'fallback',
|
|
125
144
|
routerContext: {
|
|
126
145
|
pageInfo,
|
|
127
146
|
up: Fallback.pageOptions?.up ?? info.props?.pageProps?.up,
|
|
@@ -186,31 +205,33 @@ and pass it as a param in <FramerNextPages fallbackRoute='/[...url]' /> in your
|
|
|
186
205
|
.reverse()
|
|
187
206
|
|
|
188
207
|
return (
|
|
189
|
-
|
|
208
|
+
<>
|
|
190
209
|
<m.div
|
|
191
210
|
style={{ position: 'absolute', top: 0, minHeight: clientSizeCssVar.y, left: 0, right: 0 }}
|
|
192
211
|
/>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
<AnimatePresence initial={false}>
|
|
213
|
+
{renderItems.map((item, itemIdx) => {
|
|
214
|
+
const { historyIdx, sharedKey, overlayGroup, routerKey } = item
|
|
215
|
+
const active = itemIdx === renderItems.length - 1
|
|
216
|
+
const depth = itemIdx - (renderItems.length - 1)
|
|
217
|
+
const closeIdx = renderItems[itemIdx - 1]?.historyIdx ?? -1
|
|
218
|
+
const closeSteps = closeIdx > -1 ? historyIdx - closeIdx : 0
|
|
219
|
+
const backSteps = historyIdx - closeIdx - 1
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<pageContext.Provider
|
|
223
|
+
key={sharedKey}
|
|
224
|
+
// We're actually rerendering here but since the actual page renderer is memoized we can safely do this
|
|
225
|
+
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
226
|
+
value={{ depth, active, direction, closeSteps, backSteps, routerKey, overlayGroup }}
|
|
227
|
+
>
|
|
228
|
+
<Page active={active} routerKey={routerKey}>
|
|
229
|
+
<PageRenderer {...item} />
|
|
230
|
+
</Page>
|
|
231
|
+
</pageContext.Provider>
|
|
232
|
+
)
|
|
233
|
+
})}
|
|
234
|
+
</AnimatePresence>
|
|
235
|
+
</>
|
|
215
236
|
)
|
|
216
237
|
}
|
package/context/pageContext.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMotionValue } from 'framer-motion'
|
|
2
|
+
import { useEffect, useMemo } from 'react'
|
|
2
3
|
import { scrollPos } from '../components/Page'
|
|
3
4
|
import { usePageContext } from './usePageContext'
|
|
4
5
|
|
|
@@ -7,8 +8,15 @@ import { usePageContext } from './usePageContext'
|
|
|
7
8
|
* scroll based elements.
|
|
8
9
|
*/
|
|
9
10
|
export function useScrollOffset() {
|
|
10
|
-
const { active,
|
|
11
|
+
const { active, routerKey } = usePageContext()
|
|
12
|
+
|
|
13
|
+
const scrolloffset = useMotionValue(0)
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (active) scrolloffset.set(0)
|
|
17
|
+
else scrolloffset.set(scrollPos(routerKey).y)
|
|
18
|
+
}, [active, routerKey, scrolloffset])
|
|
11
19
|
|
|
12
20
|
// When the page is rendered in the background we should use it's scroll offset while rendering
|
|
13
|
-
return
|
|
21
|
+
return scrolloffset
|
|
14
22
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/framer-next-pages",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "3.2.
|
|
5
|
+
"version": "3.2.5",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@graphcommerce/framer-utils": "3.1.
|
|
15
|
+
"@graphcommerce/framer-utils": "3.1.5"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@graphcommerce/eslint-config-pwa": "^4.1.
|
|
18
|
+
"@graphcommerce/eslint-config-pwa": "^4.1.10",
|
|
19
19
|
"@graphcommerce/prettier-config-pwa": "^4.0.6",
|
|
20
|
-
"@graphcommerce/typescript-config-pwa": "^4.0.
|
|
20
|
+
"@graphcommerce/typescript-config-pwa": "^4.0.4",
|
|
21
21
|
"@playwright/test": "^1.21.1"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"framer-motion": "^6.2.4",
|
|
25
|
-
"next": "12.1.2",
|
|
26
|
-
"react": "^
|
|
27
|
-
"react-dom": "^
|
|
25
|
+
"next": "^12.1.2",
|
|
26
|
+
"react": "^18.0.0",
|
|
27
|
+
"react-dom": "^18.0.0",
|
|
28
28
|
"@emotion/react": "^11.8.2"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/types.ts
CHANGED
|
@@ -80,9 +80,9 @@ export type PageOptions<T extends Record<string, unknown> = Record<string, unkno
|
|
|
80
80
|
* FramerNextPages uses Framer Motion's <AnimatePresence/> to animate pages in and out. From the
|
|
81
81
|
* [docs](https://www.framer.com/api/motion/animate-presence/#usage):
|
|
82
82
|
*
|
|
83
|
-
*
|
|
83
|
+
* _In React, changing a component's key makes React treat it as an entirely new component. So the
|
|
84
84
|
* old one is unmounted before the new one is mounted. So by changing the key of a single child of
|
|
85
|
-
* AnimatePresence, we can easily make animated page transitions!
|
|
85
|
+
* AnimatePresence, we can easily make animated page transitions! 🎉_
|
|
86
86
|
*
|
|
87
87
|
* To create transitions we need to let React know if we should create a new component. We do this
|
|
88
88
|
* by specifying a 'sharedKey'. By default this key is the same as the pathname:
|
|
@@ -143,6 +143,7 @@ export type PageItem = {
|
|
|
143
143
|
routerOverride?: Partial<NextRouter>
|
|
144
144
|
PageComponent: PageComponent
|
|
145
145
|
historyIdx: number
|
|
146
|
+
routerKey: string
|
|
146
147
|
sharedKey: string
|
|
147
148
|
pageProps?: Record<string, unknown>
|
|
148
149
|
routerContext: PageContext
|