@mohasinac/appkit 4.0.0 → 4.0.3
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.
|
@@ -251,5 +251,16 @@ export const testerChecklistSeedData = [
|
|
|
251
251
|
{ key: "error-states", label: "Error states (404, form validation) look correct" },
|
|
252
252
|
],
|
|
253
253
|
},
|
|
254
|
+
{
|
|
255
|
+
pageKey: "homepage-carousels",
|
|
256
|
+
pageLabel: "Homepage Carousels",
|
|
257
|
+
cases: [
|
|
258
|
+
{ key: "carousel-loops", label: "Homepage carousels (Shop by Category, Top Brands, Featured Products, Live Auctions, Reserve Before It Ships, Verified Stores, Tournaments & Events, Collector Reviews) loop back to the first item after reaching the last instead of getting stuck at the end", href: "/" },
|
|
259
|
+
{ key: "carousel-no-flicker", label: "Homepage carousel auto-scroll does not flash/flicker when looping back to the first item" },
|
|
260
|
+
{ key: "carousel-pause-on-interaction", label: "Homepage carousel auto-scroll pauses while hovering, touching, keyboard-focusing (Tab + arrow keys), or scrolling it, and resumes afterward" },
|
|
261
|
+
{ key: "carousel-arrows-work", label: "Homepage carousel prev/next arrow buttons work and wrap around at both ends" },
|
|
262
|
+
{ key: "hero-banner-loops", label: "Hero banner at the top of the homepage rotates through all slides and loops back to the first without getting stuck" },
|
|
263
|
+
],
|
|
264
|
+
},
|
|
254
265
|
]),
|
|
255
266
|
];
|
|
@@ -29,7 +29,7 @@ export interface HorizontalScrollerProps<T = unknown> {
|
|
|
29
29
|
minItemWidth?: number;
|
|
30
30
|
pauseOnHover?: boolean;
|
|
31
31
|
itemClassName?: string;
|
|
32
|
-
/**
|
|
32
|
+
/** When the scroller reaches the last item, snap instantly back to the first instead of stopping. */
|
|
33
33
|
loop?: boolean;
|
|
34
34
|
}
|
|
35
35
|
export declare function HorizontalScroller<T = unknown>({ children, className, gap, snapToItems, showArrows, arrowSize, showScrollbar, showFadeEdges, scrollContainerRef: externalRef, onScroll, items, renderItem, keyExtractor, perView, rows, autoScroll, autoScrollInterval, minItemWidth, pauseOnHover, itemClassName, loop, }: HorizontalScrollerProps<T>): import("react").JSX.Element;
|
|
@@ -31,132 +31,60 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
|
|
|
31
31
|
const containerRef = (externalRef ??
|
|
32
32
|
internalRef);
|
|
33
33
|
const autoScrollTimer = useRef(undefined);
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
const
|
|
34
|
+
// Tracks the pending "restore smooth scrolling" rAF so a fast reset (autoScroll
|
|
35
|
+
// firing again, or a manual arrow click) can't leave a stale callback that fires
|
|
36
|
+
// after — and clobbers — a newer scroll-behavior change.
|
|
37
|
+
const instantScrollRaf = useRef(undefined);
|
|
38
38
|
const normalizedItems = Array.isArray(items) ? items : [];
|
|
39
39
|
const itemsMode = Array.isArray(items) && renderItem != null;
|
|
40
40
|
const itemCount = normalizedItems.length;
|
|
41
|
-
// Number of clone slots on each side — fixed size, computed once from perView hint.
|
|
42
|
-
// Using Math.min so tiny lists don't double-render more slots than they have items.
|
|
43
|
-
const loopCloneCount = loop && itemsMode && rows <= 1 && itemCount > 0
|
|
44
|
-
? Math.min(itemCount, typeof perView === "number" ? perView : 3)
|
|
45
|
-
: 0;
|
|
46
|
-
// Grid mode (rows > 1): items are grouped into full-width "slides". Looping here
|
|
47
|
-
// clones exactly one slide on each side (the slide itself is the full stride, so a
|
|
48
|
-
// single buffer slide is enough) and teleports across a full cycle at the boundary —
|
|
49
|
-
// same technique as the single-item loop above, just at slide granularity.
|
|
50
41
|
const gridMode = itemsMode && rows > 1;
|
|
51
42
|
const gridCols = colCount > 0 ? colCount : 3;
|
|
52
43
|
const gridCardsPerSlide = rows * gridCols;
|
|
53
44
|
const gridSlideCount = gridMode
|
|
54
45
|
? Math.ceil(itemCount / gridCardsPerSlide)
|
|
55
46
|
: 0;
|
|
56
|
-
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
loopInitialized.current = true;
|
|
66
|
-
el.style.scrollBehavior = "auto";
|
|
67
|
-
el.scrollLeft = loopCloneCount * (itemWidth + gap);
|
|
68
|
-
requestAnimationFrame(() => {
|
|
69
|
-
el.style.scrollBehavior = "";
|
|
70
|
-
});
|
|
71
|
-
}, [loop, loopCloneCount, itemWidth, gap, containerRef]);
|
|
72
|
-
// Circular teleporter: when scroll enters a clone zone, jump by exactly one
|
|
73
|
-
// full cycle so the viewport content is unchanged but we're back in real territory.
|
|
74
|
-
const handleScrollLoop = useCallback(() => {
|
|
75
|
-
if (!loop || loopCloneCount === 0 || itemWidth === undefined)
|
|
76
|
-
return;
|
|
77
|
-
const el = containerRef.current;
|
|
78
|
-
if (!el || isJumping.current)
|
|
79
|
-
return;
|
|
80
|
-
const stride = itemWidth + gap;
|
|
81
|
-
const cycleWidth = itemCount * stride;
|
|
82
|
-
// scrollLeft where real items start and end
|
|
83
|
-
const realStart = loopCloneCount * stride;
|
|
84
|
-
const realEnd = realStart + cycleWidth;
|
|
85
|
-
if (el.scrollLeft < realStart - stride * 0.5) {
|
|
86
|
-
// Entered left clone zone — jump forward one cycle
|
|
87
|
-
isJumping.current = true;
|
|
88
|
-
el.style.scrollBehavior = "auto";
|
|
89
|
-
el.scrollLeft += cycleWidth;
|
|
90
|
-
requestAnimationFrame(() => {
|
|
91
|
-
isJumping.current = false;
|
|
92
|
-
el.style.scrollBehavior = "";
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else if (el.scrollLeft > realEnd - el.clientWidth + stride * 0.5) {
|
|
96
|
-
// Entered right clone zone — jump backward one cycle
|
|
97
|
-
isJumping.current = true;
|
|
98
|
-
el.style.scrollBehavior = "auto";
|
|
99
|
-
el.scrollLeft -= cycleWidth;
|
|
100
|
-
requestAnimationFrame(() => {
|
|
101
|
-
isJumping.current = false;
|
|
102
|
-
el.style.scrollBehavior = "";
|
|
103
|
-
});
|
|
47
|
+
// Instantly jumps to a scroll position — used to wrap the loop back to the start
|
|
48
|
+
// (or to the end, for prev-at-start) instead of layering a teleport on top of an
|
|
49
|
+
// in-flight smooth scroll, which is what produced the old flicker/oscillation.
|
|
50
|
+
// Cancels any previously-scheduled "restore smooth scrolling" rAF first so a
|
|
51
|
+
// rapid-fire reset (autoScroll ticking again, or an arrow click) can't leave a
|
|
52
|
+
// stale callback that fires later and clobbers a newer scroll-behavior change.
|
|
53
|
+
const instantScrollTo = useCallback((el, left) => {
|
|
54
|
+
if (instantScrollRaf.current !== undefined) {
|
|
55
|
+
cancelAnimationFrame(instantScrollRaf.current);
|
|
104
56
|
}
|
|
105
|
-
}, [loop, loopCloneCount, itemWidth, gap, itemCount, containerRef]);
|
|
106
|
-
// Prevents re-running the initial scroll-to-real-start on every resize in grid loop mode
|
|
107
|
-
const gridLoopInitialized = useRef(false);
|
|
108
|
-
// On first paint, scroll past the prepended clone slide to the first *real* slide.
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (!gridLoopActive)
|
|
111
|
-
return;
|
|
112
|
-
const el = containerRef.current;
|
|
113
|
-
if (!el || gridLoopInitialized.current)
|
|
114
|
-
return;
|
|
115
|
-
gridLoopInitialized.current = true;
|
|
116
|
-
const stride = el.clientWidth + gap;
|
|
117
57
|
el.style.scrollBehavior = "auto";
|
|
118
|
-
el.scrollLeft =
|
|
119
|
-
requestAnimationFrame(() => {
|
|
58
|
+
el.scrollLeft = left;
|
|
59
|
+
instantScrollRaf.current = requestAnimationFrame(() => {
|
|
120
60
|
el.style.scrollBehavior = "";
|
|
61
|
+
instantScrollRaf.current = undefined;
|
|
121
62
|
});
|
|
122
|
-
}, [
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const cycleWidth = gridSlideCount * stride;
|
|
132
|
-
const realStart = stride; // after the 1 prepended clone slide
|
|
133
|
-
const realEnd = realStart + cycleWidth;
|
|
134
|
-
if (el.scrollLeft < realStart - stride * 0.5) {
|
|
135
|
-
isJumping.current = true;
|
|
136
|
-
el.style.scrollBehavior = "auto";
|
|
137
|
-
el.scrollLeft += cycleWidth;
|
|
138
|
-
requestAnimationFrame(() => {
|
|
139
|
-
isJumping.current = false;
|
|
140
|
-
el.style.scrollBehavior = "";
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
else if (el.scrollLeft > realEnd - el.clientWidth + stride * 0.5) {
|
|
144
|
-
isJumping.current = true;
|
|
145
|
-
el.style.scrollBehavior = "auto";
|
|
146
|
-
el.scrollLeft -= cycleWidth;
|
|
147
|
-
requestAnimationFrame(() => {
|
|
148
|
-
isJumping.current = false;
|
|
149
|
-
el.style.scrollBehavior = "";
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}, [gridLoopActive, gap, gridSlideCount, containerRef]);
|
|
63
|
+
}, []);
|
|
64
|
+
// Cancel any pending rAF on unmount so it never fires against a detached node.
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
return () => {
|
|
67
|
+
if (instantScrollRaf.current !== undefined) {
|
|
68
|
+
cancelAnimationFrame(instantScrollRaf.current);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, []);
|
|
153
72
|
const scrollBy = useCallback((direction) => {
|
|
154
73
|
const el = containerRef.current;
|
|
155
74
|
if (!el)
|
|
156
75
|
return;
|
|
157
76
|
const width = el.clientWidth;
|
|
77
|
+
const maxScroll = el.scrollWidth - width;
|
|
78
|
+
if (loop && direction === 1 && el.scrollLeft >= maxScroll - 1) {
|
|
79
|
+
instantScrollTo(el, 0);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (loop && direction === -1 && el.scrollLeft <= 1) {
|
|
83
|
+
instantScrollTo(el, maxScroll);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
158
86
|
el.scrollBy({ left: direction * width * 0.8, behavior: "smooth" });
|
|
159
|
-
}, [containerRef]);
|
|
87
|
+
}, [containerRef, loop, instantScrollTo]);
|
|
160
88
|
const updateExtents = useCallback(() => {
|
|
161
89
|
const el = containerRef.current;
|
|
162
90
|
if (!el)
|
|
@@ -188,98 +116,57 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
|
|
|
188
116
|
const el = containerRef.current;
|
|
189
117
|
if (!el)
|
|
190
118
|
return;
|
|
191
|
-
|
|
119
|
+
const maxScroll = el.scrollWidth - el.clientWidth;
|
|
120
|
+
const atRealEnd = maxScroll <= 1 || el.scrollLeft >= maxScroll - 1;
|
|
121
|
+
if (atRealEnd) {
|
|
122
|
+
if (loop)
|
|
123
|
+
instantScrollTo(el, 0);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
192
126
|
el.scrollBy({ left: el.clientWidth * 0.8, behavior: "smooth" });
|
|
193
127
|
}, autoScrollInterval);
|
|
194
128
|
return () => clearInterval(autoScrollTimer.current);
|
|
195
|
-
}, [autoScroll, isPaused, autoScrollInterval, containerRef]);
|
|
129
|
+
}, [autoScroll, isPaused, autoScrollInterval, loop, instantScrollTo, containerRef]);
|
|
196
130
|
useEffect(() => {
|
|
197
|
-
if (!perView
|
|
131
|
+
if (!perView)
|
|
198
132
|
return;
|
|
199
133
|
const el = containerRef.current;
|
|
200
134
|
if (!el)
|
|
201
135
|
return;
|
|
202
136
|
const observer = new ResizeObserver(([entry]) => {
|
|
203
137
|
const w = entry.contentRect.width;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
setItemWidth((w - (count - 1) * gap) / count);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
// loop is true but no perView hint was given: items render at their
|
|
213
|
-
// natural width, so measure a real rendered item to get the scroll
|
|
214
|
-
// stride the clone-buffer offset / edge teleporter need — without
|
|
215
|
-
// this, itemWidth never resolves and loop mode never initializes.
|
|
216
|
-
const item = el.querySelector(".appkit-hscroller__item");
|
|
217
|
-
if (item)
|
|
218
|
-
setItemWidth(item.getBoundingClientRect().width);
|
|
138
|
+
const count = resolvePerView(perView, w);
|
|
139
|
+
if (count > 0) {
|
|
140
|
+
setColCount(count);
|
|
141
|
+
setItemWidth((w - (count - 1) * gap) / count);
|
|
219
142
|
}
|
|
220
143
|
updateExtents();
|
|
221
144
|
});
|
|
222
145
|
observer.observe(el);
|
|
223
146
|
return () => observer.disconnect();
|
|
224
|
-
}, [perView,
|
|
147
|
+
}, [perView, gap, containerRef, updateExtents]);
|
|
225
148
|
// Recompute extents when content size changes (itemWidth resolved, items count changes).
|
|
226
149
|
useEffect(() => {
|
|
227
150
|
updateExtents();
|
|
228
151
|
}, [updateExtents, itemWidth, itemCount]);
|
|
229
152
|
const content = itemsMode ? (rows > 1 ? (
|
|
230
153
|
// Grid mode: group items into slides of (rows × colCount) cards.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
]
|
|
248
|
-
.filter(Boolean)
|
|
249
|
-
.join(" "), style: minItemWidth ? { minWidth: minItemWidth } : undefined, children: renderItem(item, slideIndex * gridCardsPerSlide + idx) }, keyExtractor ? keyExtractor(item, slideIndex * gridCardsPerSlide + idx) : slideIndex * gridCardsPerSlide + idx))) }, key));
|
|
250
|
-
};
|
|
251
|
-
const realSlides = Array.from({ length: gridSlideCount }, (_, slideIndex) => renderSlide(slideIndex, `slide-${slideIndex}`, false));
|
|
252
|
-
if (!gridLoopActive)
|
|
253
|
-
return realSlides;
|
|
254
|
-
return [
|
|
255
|
-
renderSlide(gridSlideCount - 1, "slide-clone-start", true),
|
|
256
|
-
...realSlides,
|
|
257
|
-
renderSlide(0, "slide-clone-end", true),
|
|
258
|
-
];
|
|
259
|
-
})()) : loop && itemCount > 0 ? (
|
|
260
|
-
// Circular loop: fixed (itemCount + 2×loopCloneCount) DOM slots.
|
|
261
|
-
// Each slot maps to a real item via modulo — no array cloning, no list growth.
|
|
262
|
-
// Left slots [0 .. loopCloneCount-1] → tail of real list (left buffer)
|
|
263
|
-
// Real slots [loopCloneCount .. loopCloneCount+n-1] → items[0..n-1]
|
|
264
|
-
// Right slots [loopCloneCount+n .. end] → head of real list (right buffer)
|
|
265
|
-
Array.from({ length: itemCount + 2 * loopCloneCount }, (_, i) => {
|
|
266
|
-
const realIndex = ((i - loopCloneCount) % itemCount + itemCount) % itemCount;
|
|
267
|
-
const item = normalizedItems[realIndex];
|
|
268
|
-
const isClone = i < loopCloneCount || i >= loopCloneCount + itemCount;
|
|
269
|
-
return (_jsx("div", { className: [
|
|
270
|
-
"appkit-hscroller__item",
|
|
271
|
-
snapToItems ? "appkit-hscroller__item--snap" : "",
|
|
272
|
-
itemClassName,
|
|
273
|
-
]
|
|
274
|
-
.filter(Boolean)
|
|
275
|
-
.join(" "), style: itemWidth !== undefined
|
|
276
|
-
? { width: itemWidth, flexShrink: 0 }
|
|
277
|
-
: minItemWidth
|
|
278
|
-
? { minWidth: minItemWidth }
|
|
279
|
-
: undefined, "aria-hidden": isClone ? true : undefined, children: renderItem(item, realIndex) }, `loop-slot-${i}`));
|
|
280
|
-
})) : (
|
|
281
|
-
// Normal single row (no loop)
|
|
282
|
-
normalizedItems.map((item, i) => (_jsx("div", { className: [
|
|
154
|
+
Array.from({ length: gridSlideCount }, (_, slideIndex) => {
|
|
155
|
+
const slideItems = normalizedItems.slice(slideIndex * gridCardsPerSlide, (slideIndex + 1) * gridCardsPerSlide);
|
|
156
|
+
return (_jsx("div", { className: "appkit-hscroller__slide", style: {
|
|
157
|
+
display: "grid",
|
|
158
|
+
gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
|
|
159
|
+
gap: `${gap}px`,
|
|
160
|
+
width: "100%",
|
|
161
|
+
flexShrink: 0,
|
|
162
|
+
}, children: slideItems.map((item, idx) => (_jsx("div", { className: [
|
|
163
|
+
"appkit-hscroller__item",
|
|
164
|
+
snapToItems ? "appkit-hscroller__item--snap" : "",
|
|
165
|
+
itemClassName,
|
|
166
|
+
]
|
|
167
|
+
.filter(Boolean)
|
|
168
|
+
.join(" "), style: minItemWidth ? { minWidth: minItemWidth } : undefined, children: renderItem(item, slideIndex * gridCardsPerSlide + idx) }, keyExtractor ? keyExtractor(item, slideIndex * gridCardsPerSlide + idx) : slideIndex * gridCardsPerSlide + idx))) }, `slide-${slideIndex}`));
|
|
169
|
+
})) : (normalizedItems.map((item, i) => (_jsx("div", { className: [
|
|
283
170
|
"appkit-hscroller__item",
|
|
284
171
|
snapToItems ? "appkit-hscroller__item--snap" : "",
|
|
285
172
|
itemClassName,
|
|
@@ -290,40 +177,34 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
|
|
|
290
177
|
: minItemWidth
|
|
291
178
|
? { minWidth: minItemWidth }
|
|
292
179
|
: undefined, children: renderItem(item, i) }, keyExtractor ? keyExtractor(item, i) : i))))) : (children);
|
|
293
|
-
|
|
180
|
+
// Pauses autoScroll for the duration of any user interaction — hover, touch,
|
|
181
|
+
// keyboard focus (arrow-key nav), or an active wheel/drag scroll — so autoplay
|
|
182
|
+
// never fights a scroll the user is in the middle of driving themselves.
|
|
183
|
+
const interactionHandlers = pauseOnHover
|
|
294
184
|
? {
|
|
295
185
|
onMouseEnter: () => setIsPaused(true),
|
|
296
186
|
onMouseLeave: () => setIsPaused(false),
|
|
297
187
|
onTouchStart: () => setIsPaused(true),
|
|
298
188
|
onTouchEnd: () => setIsPaused(false),
|
|
299
189
|
onTouchCancel: () => setIsPaused(false),
|
|
190
|
+
onFocus: () => setIsPaused(true),
|
|
191
|
+
onBlur: () => setIsPaused(false),
|
|
192
|
+
onWheel: () => setIsPaused(true),
|
|
300
193
|
}
|
|
301
194
|
: {};
|
|
302
195
|
const combinedOnScroll = () => {
|
|
303
|
-
|
|
304
|
-
if (gridLoopActive)
|
|
305
|
-
handleGridScrollLoop();
|
|
306
|
-
else
|
|
307
|
-
updateExtents();
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
if (loop)
|
|
311
|
-
handleScrollLoop();
|
|
312
|
-
if (!loop)
|
|
313
|
-
updateExtents();
|
|
314
|
-
}
|
|
196
|
+
updateExtents();
|
|
315
197
|
onScroll?.();
|
|
316
198
|
};
|
|
317
199
|
if (showArrows) {
|
|
318
|
-
const
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
const arrowsHidden = !effectiveLoop && atStart && atEnd; // no scrollable overflow
|
|
200
|
+
const prevDisabled = !loop && atStart;
|
|
201
|
+
const nextDisabled = !loop && atEnd;
|
|
202
|
+
const arrowsHidden = !loop && atStart && atEnd; // no scrollable overflow
|
|
322
203
|
return (_jsxs("div", { className: ["appkit-hscroller appkit-hscroller--with-arrows", className]
|
|
323
204
|
.filter(Boolean)
|
|
324
|
-
.join(" "), tabIndex: 0, onKeyDown: handleKeyDown, ...
|
|
205
|
+
.join(" "), tabIndex: 0, onKeyDown: handleKeyDown, ...interactionHandlers, "data-section": "horizontalscroller-div-511", children: [showFadeEdges && (_jsxs(_Fragment, { children: [_jsx("div", { className: "appkit-hscroller__fade appkit-hscroller__fade--left" }), _jsx("div", { className: "appkit-hscroller__fade appkit-hscroller__fade--right" })] })), !arrowsHidden && (_jsx("button", { type: "button", onClick: () => scrollBy(-1), "aria-label": "Previous", "aria-disabled": prevDisabled || undefined, disabled: prevDisabled, className: `appkit-hscroller__arrow appkit-hscroller__arrow--prev appkit-hscroller__arrow--${arrowSize}`, children: _jsx(ChevronLeft, { className: "w-4 h-4" }) })), _jsx("div", { ref: containerRef, onScroll: combinedOnScroll, className: scrollerCls(snapToItems, showScrollbar), style: { gap: `${gap}px`, paddingLeft: 36, paddingRight: 36 }, "data-section": "horizontalscroller-div-512", children: content }), !arrowsHidden && (_jsx("button", { type: "button", onClick: () => scrollBy(1), "aria-label": "Next", "aria-disabled": nextDisabled || undefined, disabled: nextDisabled, className: `appkit-hscroller__arrow appkit-hscroller__arrow--next appkit-hscroller__arrow--${arrowSize}`, children: _jsx(ChevronRight, { className: "w-4 h-4" }) }))] }));
|
|
325
206
|
}
|
|
326
|
-
return (_jsxs("div", { className: ["appkit-hscroller", className].filter(Boolean).join(" "), tabIndex: 0, onKeyDown: handleKeyDown, ...
|
|
207
|
+
return (_jsxs("div", { className: ["appkit-hscroller", className].filter(Boolean).join(" "), tabIndex: 0, onKeyDown: handleKeyDown, ...interactionHandlers, "data-section": "horizontalscroller-div-513", children: [showFadeEdges && (_jsxs(_Fragment, { children: [_jsx("div", { className: "appkit-hscroller__fade appkit-hscroller__fade--left" }), _jsx("div", { className: "appkit-hscroller__fade appkit-hscroller__fade--right" })] })), _jsx("div", { ref: containerRef, onScroll: combinedOnScroll, className: scrollerCls(snapToItems, showScrollbar), style: { gap: `${gap}px` }, "data-section": "horizontalscroller-div-514", children: content })] }));
|
|
327
208
|
}
|
|
328
209
|
function scrollerCls(snapToItems, showScrollbar) {
|
|
329
210
|
return [
|