feat(web): add ScrollFade component for improved horizontal scrolling experience
This commit is contained in:
54
apps/web/components/scroll-fade.tsx
Normal file
54
apps/web/components/scroll-fade.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useState, useEffect, type ReactNode } from "react";
|
||||
|
||||
interface ScrollFadeProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
/** Tailwind max-width class, e.g. "max-w-2xs". Defaults to none. */
|
||||
maxWidth?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps children in a horizontally-scrollable container that shows left/right
|
||||
* gradient fade indicators when there is overflowed content in that direction.
|
||||
*/
|
||||
export function ScrollFade({ children, className, maxWidth }: ScrollFadeProps) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const [showLeft, setShowLeft] = useState(false);
|
||||
const [showRight, setShowRight] = useState(false);
|
||||
|
||||
const update = () => {
|
||||
const el = scrollRef.current;
|
||||
if (!el) return;
|
||||
setShowLeft(el.scrollLeft > 0);
|
||||
setShowRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
const el = scrollRef.current;
|
||||
if (!el) return;
|
||||
const ro = new ResizeObserver(update);
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
}, [children]);
|
||||
|
||||
return (
|
||||
<div className={`relative ${maxWidth ?? ""}`}>
|
||||
<div
|
||||
ref={scrollRef}
|
||||
onScroll={update}
|
||||
className={`flex gap-1.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden ${className ?? ""}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
{showLeft && (
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-8 bg-linear-to-r from-surface to-transparent group-hover:from-surface-hover" />
|
||||
)}
|
||||
{showRight && (
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-8 bg-linear-to-l from-surface to-transparent group-hover:from-surface-secondary" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user