"use client"; import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"; import { cn } from "~/lib/utils"; function getVirtualizedScrollFadeClassName({ top, bottom }: { top: boolean; bottom: boolean }) { if (!top && !bottom) return undefined; return cn( "virtualized-scroll-fade [--fade-size:1.5rem]", top && bottom && "[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,transparent,black_var(--fade-size),black_calc(100%-var(--fade-size)),transparent)]", top && !bottom && "[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,transparent,black_var(--fade-size))]", !top && bottom && "[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,black_calc(100%-var(--fade-size)),transparent)]", );} function ScrollArea({ className, children, scrollFade = false, scrollbarGutter = false, hideScrollbars = false, chainVerticalScroll = false, ...props}: ScrollAreaPrimitive.Root.Props & { scrollFade?: boolean; scrollbarGutter?: boolean; hideScrollbars?: boolean; chainVerticalScroll?: boolean;}) { return ( <ScrollAreaPrimitive.Root className={cn("relative size-full min-h-0 overflow-hidden rounded-[inherit]", className)} {...props} > <ScrollAreaPrimitive.Viewport className={cn( "h-full max-h-[inherit] overflow-auto overscroll-contain rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain", chainVerticalScroll && "overscroll-y-auto", scrollFade && "scroll-p-[var(--fade-size)] mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]", scrollbarGutter && "scrollbar-gutter-stable", hideScrollbars && "[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", )} data-slot="scroll-area-viewport" > {children} </ScrollAreaPrimitive.Viewport> {!hideScrollbars && ( <> <ScrollBar orientation="vertical" /> <ScrollBar orientation="horizontal" /> <ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" /> </> )} </ScrollAreaPrimitive.Root> );} function ScrollBar({ className, orientation = "vertical", ...props}: ScrollAreaPrimitive.Scrollbar.Props) { return ( <ScrollAreaPrimitive.Scrollbar className={cn( "flex opacity-0 transition-opacity delay-300 data-[orientation=horizontal]:mx-1 data-[orientation=horizontal]:mb-px data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:my-1 data-[orientation=vertical]:mr-px data-[orientation=vertical]:w-1.5 data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100 data-hovering:delay-0 data-scrolling:delay-0 data-hovering:duration-100 data-scrolling:duration-100", className, )} data-slot="scroll-area-scrollbar" orientation={orientation} {...props} > <ScrollAreaPrimitive.Thumb className="relative flex-1 rounded-full bg-[var(--app-scrollbar-thumb)] transition-colors hover:bg-[var(--app-scrollbar-thumb-hover)]" data-slot="scroll-area-thumb" /> </ScrollAreaPrimitive.Scrollbar> );} export { getVirtualizedScrollFadeClassName, ScrollArea, ScrollBar };
"use client";
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
import { cn } from "~/lib/utils";
function getVirtualizedScrollFadeClassName({ top, bottom }: { top: boolean; bottom: boolean }) {
if (!top && !bottom) return undefined;
return cn(
"virtualized-scroll-fade [--fade-size:1.5rem]",
top &&
bottom &&
"[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,transparent,black_var(--fade-size),black_calc(100%-var(--fade-size)),transparent)]",
top &&
!bottom &&
"[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,transparent,black_var(--fade-size))]",
!top &&
bottom &&
"[--virtualized-scroll-fade-mask:linear-gradient(to_bottom,black_calc(100%-var(--fade-size)),transparent)]",
);
}
function ScrollArea({
className,
children,
scrollFade = false,
scrollbarGutter = false,
hideScrollbars = false,
chainVerticalScroll = false,
...props
}: ScrollAreaPrimitive.Root.Props & {
scrollFade?: boolean;
scrollbarGutter?: boolean;
hideScrollbars?: boolean;
chainVerticalScroll?: boolean;
}) {
return (
<ScrollAreaPrimitive.Root
className={cn("relative size-full min-h-0 overflow-hidden rounded-[inherit]", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
className={cn(
"h-full max-h-[inherit] overflow-auto overscroll-contain rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain",
chainVerticalScroll && "overscroll-y-auto",
scrollFade &&
"scroll-p-[var(--fade-size)] mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
scrollbarGutter && "scrollbar-gutter-stable",
hideScrollbars &&
"[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
)}
data-slot="scroll-area-viewport"
>
{children}
</ScrollAreaPrimitive.Viewport>
{!hideScrollbars && (
<>
<ScrollBar orientation="vertical" />
<ScrollBar orientation="horizontal" />
<ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" />
</>
)}
</ScrollAreaPrimitive.Root>
);
}
function ScrollBar({
className,
orientation = "vertical",
...props
}: ScrollAreaPrimitive.Scrollbar.Props) {
return (
<ScrollAreaPrimitive.Scrollbar
className={cn(
"flex opacity-0 transition-opacity delay-300 data-[orientation=horizontal]:mx-1 data-[orientation=horizontal]:mb-px data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:my-1 data-[orientation=vertical]:mr-px data-[orientation=vertical]:w-1.5 data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100 data-hovering:delay-0 data-scrolling:delay-0 data-hovering:duration-100 data-scrolling:duration-100",
className,
)}
data-slot="scroll-area-scrollbar"
orientation={orientation}
{...props}
>
<ScrollAreaPrimitive.Thumb
className="relative flex-1 rounded-full bg-[var(--app-scrollbar-thumb)] transition-colors hover:bg-[var(--app-scrollbar-thumb-hover)]"
data-slot="scroll-area-thumb"
/>
</ScrollAreaPrimitive.Scrollbar>
);
}
export { getVirtualizedScrollFadeClassName, ScrollArea, ScrollBar };