From 82b76923f170e1d7a2e2d1542993ded47366b932 Mon Sep 17 00:00:00 2001 From: Edouard Wautier <4435185+Duncid@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:06:12 +0100 Subject: [PATCH] Fine tuning scrollBar --- sparkle/src/components/Container.tsx | 3 +- sparkle/src/components/ScrollArea.tsx | 129 ++++++++++++++++----- sparkle/src/stories/ScrollArea.stories.tsx | 26 ++++- 3 files changed, 120 insertions(+), 38 deletions(-) diff --git a/sparkle/src/components/Container.tsx b/sparkle/src/components/Container.tsx index 7fb6e9e5753c..c3fd68562338 100644 --- a/sparkle/src/components/Container.tsx +++ b/sparkle/src/components/Container.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { ScrollArea } from "@sparkle/components"; +import { ScrollArea, ScrollBar } from "@sparkle/components"; import { cn } from "@sparkle/lib"; interface ContainerProps extends React.HTMLAttributes { @@ -24,6 +24,7 @@ export const Container = React.forwardRef( > {children} + ); diff --git a/sparkle/src/components/ScrollArea.tsx b/sparkle/src/components/ScrollArea.tsx index 9ee3e36d41bf..4040448648b4 100644 --- a/sparkle/src/components/ScrollArea.tsx +++ b/sparkle/src/components/ScrollArea.tsx @@ -11,41 +11,108 @@ export interface ScrollAreaProps const ScrollArea = React.forwardRef< React.ElementRef, ScrollAreaProps ->(({ className, children, hideScrollBar = false, ...props }, ref) => ( - - - {children} - - {!hideScrollBar && } - - -)); +>(({ className, children, hideScrollBar = false, ...props }, ref) => { + const hasCustomScrollBar = React.Children.toArray(children).some( + (child) => + React.isValidElement(child) && + (child.type as typeof ScrollBar).displayName === ScrollBar.displayName + ); + + const shouldHideDefaultScrollBar = hideScrollBar || hasCustomScrollBar; + + return ( + + + {children} + + {!shouldHideDefaultScrollBar && } + + + ); +}); + ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; +const scrollBarSizes = { + compact: { + bar: { + vertical: "s-w-5", + horizontal: "s-h-5", + }, + padding: { + vertical: "s-pr-1 s-pl-2.5 s-py-2 hover:s-pl-2", + horizontal: "s-pb-1 s-pt-2.5 s-px-2", + }, + thumb: "s-bg-muted-foreground/40 hover:s-bg-muted-foreground/70", + }, + classic: { + bar: { + vertical: "s-w-5", + horizontal: "s-h-5", + }, + padding: { + vertical: "s-pl-2 s-pr-1 s-py-1", + horizontal: "s-py-0.5 s-px-1", + }, + thumb: "s-bg-muted-foreground/70 hover:s-bg-muted-foreground/80", + }, +} as const; + +type ScrollBarSize = keyof typeof scrollBarSizes; + +interface ScrollBarProps + extends React.ComponentPropsWithoutRef< + typeof ScrollAreaPrimitive.ScrollAreaScrollbar + > { + size?: ScrollBarSize; +} + const ScrollBar = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, orientation = "vertical", ...props }, ref) => ( - - - -)); + ScrollBarProps +>( + ( + { className, orientation = "vertical", size = "compact", ...props }, + ref + ) => { + const sizeConfig = scrollBarSizes[size]; + + return ( + + + + ); + } +); + ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; export { ScrollArea, ScrollBar }; +export type { ScrollBarSize }; diff --git a/sparkle/src/stories/ScrollArea.stories.tsx b/sparkle/src/stories/ScrollArea.stories.tsx index 194fe1e3dd87..b7b1973b15a9 100644 --- a/sparkle/src/stories/ScrollArea.stories.tsx +++ b/sparkle/src/stories/ScrollArea.stories.tsx @@ -17,11 +17,11 @@ const tags = Array.from({ length: 50 }).map( export function ScrollAreaDemo() { return ( -
- -
+
+
+

- Tags + Mini ScrollBar

{tags.map((tag) => ( @@ -29,8 +29,22 @@ export function ScrollAreaDemo() { ))} -
- + +
+
+ +

+ Classic ScrollBar +

+ {tags.map((tag) => ( + +
{tag}
+ +
+ ))} + +
+
); }