@graphcommerce/framer-next-pages 3.2.3 → 3.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1602](https://github.com/graphcommerce-org/graphcommerce/pull/1602) [`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Default styles and layout fixes
8
+
9
+ - Scaled icons and fonts down. Size in typography is now more gradual: https://graphcommerce.vercel.app/test/typography
10
+ - Multiple accessibility fixes. Missing button/input labels, and fixed spacing issues resulting in high % appropriately sized tap targets
11
+ - Replaced responsiveVal usage with better performaning breakpointVal where possible
12
+ - All buttons are now Pill by default.
13
+ - Cleaned up checkout styles
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [[`01372b918`](https://github.com/graphcommerce-org/graphcommerce/commit/01372b918a291e01cbf5db40edcb40fb1c2af313)]:
18
+ - @graphcommerce/framer-utils@3.2.0
19
+
20
+ ## 3.2.5
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [[`707dbc73d`](https://github.com/graphcommerce-org/graphcommerce/commit/707dbc73d181204d88fdbbd2e09340e25b2b5f7b), [`5c5645e6e`](https://github.com/graphcommerce-org/graphcommerce/commit/5c5645e6eaf5314c063f05547707fcd4b34a8717)]:
25
+ - @graphcommerce/framer-utils@3.1.5
26
+
27
+ ## 3.2.4
28
+
29
+ ### Patch Changes
30
+
31
+ - [#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
32
+
33
+ * [#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
34
+
3
35
  ## 3.2.3
4
36
 
5
37
  ### Patch Changes
@@ -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, 'historyIdx'> & {
6
+ export type PageProps = Pick<PageItem, 'routerKey'> & {
7
7
  active: boolean
8
8
  children: React.ReactNode
9
9
  }
10
10
 
11
- export function scrollPos(idx: number): { x: number; y: number } {
12
- const scroll = global.window?.sessionStorage[`__next_scroll_${idx}`]
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, historyIdx, children } = props
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(historyIdx).y * -1
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(historyIdx).y
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}
@@ -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
- const idx = Number(global.window?.history.state?.idx ?? 0)
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,
@@ -192,7 +211,7 @@ and pass it as a param in <FramerNextPages fallbackRoute='/[...url]' /> in your
192
211
  />
193
212
  <AnimatePresence initial={false}>
194
213
  {renderItems.map((item, itemIdx) => {
195
- const { historyIdx, sharedKey, overlayGroup } = item
214
+ const { historyIdx, sharedKey, overlayGroup, routerKey } = item
196
215
  const active = itemIdx === renderItems.length - 1
197
216
  const depth = itemIdx - (renderItems.length - 1)
198
217
  const closeIdx = renderItems[itemIdx - 1]?.historyIdx ?? -1
@@ -204,9 +223,9 @@ and pass it as a param in <FramerNextPages fallbackRoute='/[...url]' /> in your
204
223
  key={sharedKey}
205
224
  // We're actually rerendering here but since the actual page renderer is memoized we can safely do this
206
225
  // eslint-disable-next-line react/jsx-no-constructed-context-values
207
- value={{ depth, active, direction, closeSteps, backSteps, historyIdx, overlayGroup }}
226
+ value={{ depth, active, direction, closeSteps, backSteps, routerKey, overlayGroup }}
208
227
  >
209
- <Page active={active} historyIdx={historyIdx}>
228
+ <Page active={active} routerKey={routerKey}>
210
229
  <PageRenderer {...item} />
211
230
  </Page>
212
231
  </pageContext.Provider>
@@ -39,7 +39,7 @@ export type PageContext = {
39
39
  overlayGroup?: string
40
40
 
41
41
  /** @private */
42
- historyIdx: number
42
+ routerKey: string
43
43
  }
44
44
 
45
45
  export const pageContext = createContext(undefined as unknown as PageContext)
@@ -1,4 +1,5 @@
1
- import { useMemo } from 'react'
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, historyIdx } = usePageContext()
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 useMemo(() => (active ? { x: 0, y: 0 } : scrollPos(historyIdx)), [active, historyIdx])
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.3",
5
+ "version": "3.3.0",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,12 +12,12 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@graphcommerce/framer-utils": "3.1.4"
15
+ "@graphcommerce/framer-utils": "3.2.0"
16
16
  },
17
17
  "devDependencies": {
18
- "@graphcommerce/eslint-config-pwa": "^4.1.8",
18
+ "@graphcommerce/eslint-config-pwa": "^4.1.10",
19
19
  "@graphcommerce/prettier-config-pwa": "^4.0.6",
20
- "@graphcommerce/typescript-config-pwa": "^4.0.2",
20
+ "@graphcommerce/typescript-config-pwa": "^4.0.4",
21
21
  "@playwright/test": "^1.21.1"
22
22
  },
23
23
  "peerDependencies": {
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
- * *In React, changing a component's key makes React treat it as an entirely new component. So the
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