@graphcommerce/framer-scroller 2.1.40 → 2.1.42

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,27 @@
1
1
  # Change Log
2
2
 
3
+ ## 2.1.42
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`e76df6dc3`](https://github.com/graphcommerce-org/graphcommerce/commit/e76df6dc37c11c793a5d008ba36932d17dc23855), [`0bd9ea582`](https://github.com/graphcommerce-org/graphcommerce/commit/0bd9ea58230dde79c5fe2cdb07e9860151460270)]:
8
+ - @graphcommerce/next-ui@4.29.0
9
+
10
+ ## 2.1.41
11
+
12
+ ### Patch Changes
13
+
14
+ - [#1675](https://github.com/graphcommerce-org/graphcommerce/pull/1675) [`81f31d1e5`](https://github.com/graphcommerce-org/graphcommerce/commit/81f31d1e54397368088a4289aaddd29facfceeef) Thanks [@paales](https://github.com/paales)! - Make sure we can only drag in the current Scroller to prevent overscroll issues
15
+
16
+ - [#1675](https://github.com/graphcommerce-org/graphcommerce/pull/1675) [`a8905d263`](https://github.com/graphcommerce-org/graphcommerce/commit/a8905d263273cb9322583d5759a5fdc66eceb8e4) Thanks [@paales](https://github.com/paales)! - The duration of the animation should be based on the distance the animation has to go
17
+
18
+ - [#1675](https://github.com/graphcommerce-org/graphcommerce/pull/1675) [`1b1504c9b`](https://github.com/graphcommerce-org/graphcommerce/commit/1b1504c9b0e51f2787bce91e1ff1940f540411d6) Thanks [@paales](https://github.com/paales)! - Added crosssel functionality
19
+
20
+ - Updated dependencies [[`9e630670f`](https://github.com/graphcommerce-org/graphcommerce/commit/9e630670ff6c952ab7b938d890b5509804985cf3), [`2e9fa5984`](https://github.com/graphcommerce-org/graphcommerce/commit/2e9fa5984a07ff14fc1b3a4f62189a26e8e3ecdd), [`adf13069a`](https://github.com/graphcommerce-org/graphcommerce/commit/adf13069af6460c960276b402237371c12fc6dec), [`1b1504c9b`](https://github.com/graphcommerce-org/graphcommerce/commit/1b1504c9b0e51f2787bce91e1ff1940f540411d6), [`6c2e27b1b`](https://github.com/graphcommerce-org/graphcommerce/commit/6c2e27b1be4aaa888e65a2bd69eaeb467a54a023)]:
21
+ - @graphcommerce/next-ui@4.28.1
22
+ - @graphcommerce/framer-utils@3.2.1
23
+ - @graphcommerce/image@3.1.10
24
+
3
25
  ## 2.1.40
4
26
 
5
27
  ### Patch Changes
@@ -21,6 +21,9 @@ export type ScrollerProviderProps = {
21
21
  scrollSnapTypeMd?: ScrollSnapType
22
22
  scrollSnapAlign?: ScrollSnapAlign
23
23
  scrollSnapStop?: ScrollSnapStop
24
+
25
+ /** @private */
26
+ _inititalSnap?: boolean
24
27
  }
25
28
 
26
29
  function useObserveItems(scrollerRef: ReactHtmlRefObject, items: MotionValue<ItemState[]>) {
@@ -71,6 +74,7 @@ export function ScrollerProvider(props: ScrollerProviderProps) {
71
74
  scrollSnapStop = 'normal',
72
75
  scrollSnapTypeSm = 'inline mandatory',
73
76
  scrollSnapTypeMd = 'inline mandatory',
77
+ _inititalSnap = true,
74
78
  ...providerProps
75
79
  } = props
76
80
 
@@ -79,7 +83,7 @@ export function ScrollerProvider(props: ScrollerProviderProps) {
79
83
  [scrollSnapAlign, scrollSnapStop, scrollSnapTypeMd, scrollSnapTypeSm],
80
84
  )
81
85
 
82
- const snap = useMotionValue(true)
86
+ const snap = useMotionValue(_inititalSnap)
83
87
 
84
88
  // Monitor the visbility of all elements and store them for later use.
85
89
  const items = useMotionValue<ItemState[]>([])
@@ -190,7 +194,9 @@ export function ScrollerProvider(props: ScrollerProviderProps) {
190
194
  continue
191
195
  }
192
196
 
193
- const align = getComputedStyle(child).scrollSnapAlign
197
+ const { scrollSnapAlign: align } = getComputedStyle(child)
198
+
199
+ // console.trace(scrollPaddingTop, scrollPaddingRight, scrollPaddingBottom, scrollPaddingLeft)
194
200
  let [childAlignY, childAlignX] = align.split(' ') as [
195
201
  ScrollSnapAlignAxis,
196
202
  ScrollSnapAlignAxis | undefined,
@@ -266,20 +272,32 @@ export function ScrollerProvider(props: ScrollerProviderProps) {
266
272
  }
267
273
 
268
274
  const clamp = (min: number, max: number) => (value: number) =>
269
- Math.max(min, Math.min(max, value))
275
+ Math.round(Math.max(min, Math.min(max, value)))
270
276
 
271
277
  return {
272
278
  x: [
273
- ...snapPositions.x.start.map((v) => v - scrollPadding.x.before),
274
- ...snapPositions.x.center.map((v) => v - rect.width / 2),
275
- ...snapPositions.x.end.map((v) => v - rect.width + scrollPadding.x.after),
276
- ].map(clamp(0, maxScroll.x)),
279
+ ...new Set(
280
+ [
281
+ ...snapPositions.x.start.map((v) => v - scrollPadding.x.before),
282
+ ...snapPositions.x.center.map((v) => v - rect.width / 2),
283
+ ...snapPositions.x.end.map((v) => v - rect.width + scrollPadding.x.after),
284
+ ]
285
+ .map(clamp(0, maxScroll.x))
286
+ .sort((a, b) => a - b),
287
+ ),
288
+ ],
277
289
 
278
290
  y: [
279
- ...snapPositions.y.start.map((v) => v - scrollPadding.y.before),
280
- ...snapPositions.y.center.map((v) => v - rect.height / 2),
281
- ...snapPositions.y.end.map((v) => v - rect.height + scrollPadding.y.after),
282
- ].map(clamp(0, maxScroll.y)),
291
+ ...new Set(
292
+ [
293
+ ...snapPositions.y.start.map((v) => v - scrollPadding.y.before),
294
+ ...snapPositions.y.center.map((v) => v - rect.height / 2),
295
+ ...snapPositions.y.end.map((v) => v - rect.height + scrollPadding.y.after),
296
+ ]
297
+ .map(clamp(0, maxScroll.y))
298
+ .sort((a, b) => a - b),
299
+ ),
300
+ ],
283
301
  }
284
302
  }
285
303
 
@@ -2,29 +2,20 @@ import { useElementScroll } from '@graphcommerce/framer-utils'
2
2
  import { MotionConfigContext, Point, Tween } from 'framer-motion'
3
3
  import { animate } from 'popmotion'
4
4
  import { useCallback, useContext } from 'react'
5
+ import { distanceAnimationDuration } from '../utils/distanceAnimationDuration'
5
6
  import { useScrollerContext } from './useScrollerContext'
6
7
 
7
8
  export function useScrollTo() {
8
9
  const { scrollerRef, register, disableSnap, enableSnap } = useScrollerContext()
9
10
  const scroll = useElementScroll(scrollerRef)
10
11
 
11
- const duration =
12
- ((useContext(MotionConfigContext).transition as Tween | undefined)?.duration ?? 0.375) * 1000
12
+ const duration = (useContext(MotionConfigContext).transition as Tween | undefined)?.duration ?? 0
13
13
 
14
14
  const scrollTo = useCallback(
15
15
  async (to: Point) => {
16
16
  const ref = scrollerRef.current
17
17
  if (!ref) return
18
18
 
19
- // In the future we want to move to browser native scrolling behavior, but since the animation timing isn't configurable we can't use it.
20
- // if ('scrollBehavior' in document.documentElement.style) {
21
- // scrollerRef.current.scrollTo({ left: to.x, top: to.y, behavior: 'smooth' })
22
- // await new Promise((onComplete) => {
23
- // setTimeout(onComplete, 2000)
24
- // })
25
- // return
26
- // }
27
-
28
19
  // @ts-expect-error private api, but we're updating the animation value here manually instead of relying on the event listener.
29
20
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
30
21
  scroll.scroll.start(() => () => {})
@@ -43,7 +34,7 @@ export function useScrollTo() {
43
34
  },
44
35
  onComplete,
45
36
  onStop: onComplete,
46
- duration,
37
+ duration: duration * 1000 || distanceAnimationDuration(ref.scrollLeft, to.x),
47
38
  }),
48
39
  )
49
40
  } else onComplete()
@@ -63,7 +54,7 @@ export function useScrollTo() {
63
54
  },
64
55
  onComplete,
65
56
  onStop: onComplete,
66
- duration,
57
+ duration: duration * 1000 || distanceAnimationDuration(ref.scrollTop, to.y),
67
58
  }),
68
59
  )
69
60
  } else {
@@ -83,6 +83,7 @@ export function useScroller<
83
83
  const onPanStart: PanHandlers['onPanStart'] = (event) => {
84
84
  // If we're not dealing with the mouse we don't need to do anything
85
85
  if (!isHTMLMousePointerEvent(event)) return
86
+ if (event.target.closest('.Scroller-root') !== scrollerRef.current) return
86
87
 
87
88
  scrollStart.x.set(scroll.x.get())
88
89
  scrollStart.y.set(scroll.y.get())
@@ -95,6 +96,7 @@ export function useScroller<
95
96
 
96
97
  // If we're not dealing with the mouse we don't need to do anything
97
98
  if (!isHTMLMousePointerEvent(event)) return
99
+ if (event.target.closest('.Scroller-root') !== scrollerRef.current) return
98
100
 
99
101
  scrollerRef.current.scrollLeft = scrollStart.x.get() - info.offset.x
100
102
  scrollerRef.current.scrollTop = scrollStart.y.get() - info.offset.y
@@ -103,6 +105,7 @@ export function useScroller<
103
105
  const onPanEnd: PanHandlers['onPanEnd'] = (event, info) => {
104
106
  // If we're not dealing with the mouse we don't need to do anything
105
107
  if (!isHTMLMousePointerEvent(event)) return
108
+ if (event.target.closest('.Scroller-root') !== scrollerRef.current) return
106
109
 
107
110
  setPanning(false)
108
111
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/framer-scroller",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "2.1.40",
5
+ "version": "2.1.42",
6
6
  "sideEffects": false,
7
7
  "scripts": {
8
8
  "dev": "tsc -W"
@@ -15,9 +15,9 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@graphcommerce/framer-utils": "3.2.0",
19
- "@graphcommerce/image": "3.1.9",
20
- "@graphcommerce/next-ui": "4.28.0"
18
+ "@graphcommerce/framer-utils": "3.2.1",
19
+ "@graphcommerce/image": "3.1.10",
20
+ "@graphcommerce/next-ui": "4.29.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@graphcommerce/eslint-config-pwa": "^4.1.10",
@@ -0,0 +1,8 @@
1
+ /** Get the duration in ms of the animation depending upon the distance provided in pixels */
2
+ export function distanceAnimationDuration(fromPx: number, toPx: number): number {
3
+ const height = Math.abs(fromPx - toPx)
4
+ if (!height) return 0
5
+
6
+ const constant = Math.abs(fromPx - toPx) / 36
7
+ return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10)
8
+ }
@@ -1,6 +1,6 @@
1
1
  export function isHTMLMousePointerEvent(
2
2
  event: MouseEvent | TouchEvent | PointerEvent,
3
- ): event is PointerEvent {
3
+ ): event is PointerEvent & { target: HTMLElement } {
4
4
  return (
5
5
  event instanceof PointerEvent &&
6
6
  event.pointerType === 'mouse' &&
@@ -1,6 +1,6 @@
1
1
  import { ScrollSnapType } from '../types'
2
2
 
3
- export type SnapTypeDirection = 'block' | 'inline' | 'both' | 'inline'
3
+ export type SnapTypeDirection = 'block' | 'inline' | 'both'
4
4
  export function scrollSnapTypeDirection(scrollSnapType: ScrollSnapType): SnapTypeDirection {
5
5
  let snapDir = scrollSnapType.split(' ')[0]
6
6
  snapDir = snapDir.replace('y', 'block')