@pradip1995/segment-product-card 0.3.16 → 0.3.17
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/package.json
CHANGED
|
@@ -111,6 +111,7 @@ export function ProductRailByVariant({
|
|
|
111
111
|
wishlistProductIds,
|
|
112
112
|
productCardVariant,
|
|
113
113
|
showNavButtons,
|
|
114
|
+
autoScroll,
|
|
114
115
|
}: {
|
|
115
116
|
variant: ProductRailVariant
|
|
116
117
|
products: HttpTypes.StoreProduct[]
|
|
@@ -123,6 +124,7 @@ export function ProductRailByVariant({
|
|
|
123
124
|
wishlistProductIds?: string[]
|
|
124
125
|
productCardVariant?: ProductCardVariant
|
|
125
126
|
showNavButtons?: boolean
|
|
127
|
+
autoScroll?: boolean
|
|
126
128
|
}) {
|
|
127
129
|
return (
|
|
128
130
|
<>
|
|
@@ -136,6 +138,7 @@ export function ProductRailByVariant({
|
|
|
136
138
|
wishlistProductIds={wishlistProductIds}
|
|
137
139
|
productCardVariant={productCardVariant}
|
|
138
140
|
showNavButtons={showNavButtons}
|
|
141
|
+
autoScroll={autoScroll}
|
|
139
142
|
/>
|
|
140
143
|
) : variant === "featured" ? (
|
|
141
144
|
<ProductRailFeatured
|
package/src/product-scroll.tsx
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { useRef } from "react"
|
|
3
|
+
import { useEffect, useRef, useState } from "react"
|
|
4
4
|
import ProductCard, { type ProductCardVariant } from "./segment"
|
|
5
5
|
import type { HttpTypes } from "@medusajs/types"
|
|
6
6
|
|
|
7
|
+
/** Auto-scroll only when the rail has more cards than fit in one row. */
|
|
8
|
+
const VISIBLE_CARDS = 4
|
|
9
|
+
const AUTO_SCROLL_MS = 3200
|
|
10
|
+
|
|
7
11
|
type ProductScrollProps = {
|
|
8
12
|
products: HttpTypes.StoreProduct[]
|
|
9
13
|
region?: HttpTypes.StoreRegion | null
|
|
@@ -12,6 +16,8 @@ type ProductScrollProps = {
|
|
|
12
16
|
wishlistProductIds?: string[]
|
|
13
17
|
productCardVariant?: ProductCardVariant
|
|
14
18
|
showNavButtons?: boolean
|
|
19
|
+
/** When true and there are more than 4 products, advance the rail automatically. */
|
|
20
|
+
autoScroll?: boolean
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
export default function ProductScroll({
|
|
@@ -22,8 +28,13 @@ export default function ProductScroll({
|
|
|
22
28
|
wishlistProductIds,
|
|
23
29
|
productCardVariant,
|
|
24
30
|
showNavButtons = true,
|
|
31
|
+
autoScroll = false,
|
|
25
32
|
}: ProductScrollProps) {
|
|
26
33
|
const viewportRef = useRef<HTMLDivElement>(null)
|
|
34
|
+
const pauseUntilRef = useRef(0)
|
|
35
|
+
const [paused, setPaused] = useState(false)
|
|
36
|
+
|
|
37
|
+
const shouldAutoScroll = autoScroll && products.length > VISIBLE_CARDS
|
|
27
38
|
|
|
28
39
|
const scroll = (direction: "prev" | "next") => {
|
|
29
40
|
const viewport = viewportRef.current
|
|
@@ -35,15 +46,75 @@ export default function ProductScroll({
|
|
|
35
46
|
})
|
|
36
47
|
}
|
|
37
48
|
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!shouldAutoScroll) return
|
|
51
|
+
if (
|
|
52
|
+
typeof window !== "undefined" &&
|
|
53
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
54
|
+
) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const tick = () => {
|
|
59
|
+
const viewport = viewportRef.current
|
|
60
|
+
if (!viewport || paused) return
|
|
61
|
+
if (Date.now() < pauseUntilRef.current) return
|
|
62
|
+
|
|
63
|
+
const maxScroll = viewport.scrollWidth - viewport.clientWidth
|
|
64
|
+
if (maxScroll <= 4) return
|
|
65
|
+
|
|
66
|
+
const slide = viewport.querySelector(
|
|
67
|
+
".product-scroll__slide, .bestsellers-carousel__slide"
|
|
68
|
+
) as HTMLElement | null
|
|
69
|
+
const styles = getComputedStyle(viewport.querySelector(".product-scroll__track, .bestsellers-carousel__track") || viewport)
|
|
70
|
+
const gap = parseFloat(styles.columnGap || styles.gap || "16") || 16
|
|
71
|
+
const step = (slide?.offsetWidth || viewport.clientWidth / VISIBLE_CARDS) + gap
|
|
72
|
+
const next = viewport.scrollLeft + step
|
|
73
|
+
|
|
74
|
+
if (next >= maxScroll - 2) {
|
|
75
|
+
viewport.scrollTo({ left: 0, behavior: "smooth" })
|
|
76
|
+
} else {
|
|
77
|
+
viewport.scrollBy({ left: step, behavior: "smooth" })
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const id = window.setInterval(tick, AUTO_SCROLL_MS)
|
|
82
|
+
return () => window.clearInterval(id)
|
|
83
|
+
}, [shouldAutoScroll, paused, products.length])
|
|
84
|
+
|
|
85
|
+
const pauseAutoScroll = (ms = AUTO_SCROLL_MS * 2) => {
|
|
86
|
+
pauseUntilRef.current = Date.now() + ms
|
|
87
|
+
}
|
|
88
|
+
|
|
38
89
|
if (products.length === 0) return null
|
|
39
90
|
|
|
40
91
|
return (
|
|
41
|
-
<div
|
|
92
|
+
<div
|
|
93
|
+
className="product-scroll bestsellers-carousel"
|
|
94
|
+
onMouseEnter={() => {
|
|
95
|
+
if (shouldAutoScroll) setPaused(true)
|
|
96
|
+
}}
|
|
97
|
+
onMouseLeave={() => {
|
|
98
|
+
if (shouldAutoScroll) {
|
|
99
|
+
setPaused(false)
|
|
100
|
+
pauseAutoScroll(800)
|
|
101
|
+
}
|
|
102
|
+
}}
|
|
103
|
+
onFocusCapture={() => {
|
|
104
|
+
if (shouldAutoScroll) pauseAutoScroll()
|
|
105
|
+
}}
|
|
106
|
+
onPointerDown={() => {
|
|
107
|
+
if (shouldAutoScroll) pauseAutoScroll()
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
42
110
|
{showNavButtons ? (
|
|
43
111
|
<button
|
|
44
112
|
type="button"
|
|
45
113
|
className="product-scroll__nav bestsellers-carousel__nav product-scroll__nav--prev bestsellers-carousel__nav--prev"
|
|
46
|
-
onClick={() =>
|
|
114
|
+
onClick={() => {
|
|
115
|
+
pauseAutoScroll()
|
|
116
|
+
scroll("prev")
|
|
117
|
+
}}
|
|
47
118
|
aria-label="Previous products"
|
|
48
119
|
>
|
|
49
120
|
‹
|
|
@@ -75,7 +146,10 @@ export default function ProductScroll({
|
|
|
75
146
|
<button
|
|
76
147
|
type="button"
|
|
77
148
|
className="product-scroll__nav bestsellers-carousel__nav product-scroll__nav--next bestsellers-carousel__nav--next"
|
|
78
|
-
onClick={() =>
|
|
149
|
+
onClick={() => {
|
|
150
|
+
pauseAutoScroll()
|
|
151
|
+
scroll("next")
|
|
152
|
+
}}
|
|
79
153
|
aria-label="Next products"
|
|
80
154
|
>
|
|
81
155
|
›
|