Skip to content

Commit 5db83f5

Browse files
committed
feat: add component scroll-area
1 parent bd1711a commit 5db83f5

File tree

12 files changed

+340
-0
lines changed

12 files changed

+340
-0
lines changed

packages/ui-variants/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export * from './types';
55
export * from './variants/button';
66
export * from './variants/button-group';
77
export * from './variants/card';
8+
export * from './variants/scroll-area';
89
export * from './variants/tabs';
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { tv } from 'tailwind-variants';
2+
3+
export const scrollAreaVariants = tv({
4+
slots: {
5+
root: 'relative overflow-hidden',
6+
viewport: 'size-full rounded-inherit',
7+
scrollbar: 'flex touch-none select-none transition-colors-200',
8+
thumb: 'relative flex-1 rounded-full bg-border',
9+
corner: ''
10+
},
11+
variants: {
12+
size: {
13+
xs: {},
14+
sm: {},
15+
md: {},
16+
lg: {},
17+
xl: {},
18+
'2xl': {}
19+
},
20+
orientation: {
21+
horizontal: {
22+
scrollbar: 'flex-col p-px border-t border-t-transparent'
23+
},
24+
vertical: {
25+
scrollbar: 'h-full p-px border-l border-l-transparent'
26+
}
27+
}
28+
},
29+
compoundVariants: [
30+
{
31+
size: 'xs',
32+
orientation: 'horizontal',
33+
class: {
34+
scrollbar: 'h-1.5'
35+
}
36+
},
37+
{
38+
size: 'xs',
39+
orientation: 'vertical',
40+
class: {
41+
scrollbar: 'w-1.5'
42+
}
43+
},
44+
{
45+
size: 'sm',
46+
orientation: 'horizontal',
47+
class: {
48+
scrollbar: 'h-2'
49+
}
50+
},
51+
{
52+
size: 'sm',
53+
orientation: 'vertical',
54+
class: {
55+
scrollbar: 'w-2'
56+
}
57+
},
58+
{
59+
size: 'md',
60+
orientation: 'horizontal',
61+
class: {
62+
scrollbar: 'h-2.5'
63+
}
64+
},
65+
{
66+
size: 'md',
67+
orientation: 'vertical',
68+
class: {
69+
scrollbar: 'w-2.5'
70+
}
71+
},
72+
{
73+
size: 'lg',
74+
orientation: 'horizontal',
75+
class: {
76+
scrollbar: 'h-3'
77+
}
78+
},
79+
{
80+
size: 'lg',
81+
orientation: 'vertical',
82+
class: {
83+
scrollbar: 'w-3'
84+
}
85+
},
86+
{
87+
size: 'xl',
88+
orientation: 'horizontal',
89+
class: {
90+
scrollbar: 'h-3.5'
91+
}
92+
},
93+
{
94+
size: 'xl',
95+
orientation: 'vertical',
96+
class: {
97+
scrollbar: 'w-3.5'
98+
}
99+
},
100+
{
101+
size: '2xl',
102+
orientation: 'horizontal',
103+
class: {
104+
scrollbar: 'h-4'
105+
}
106+
},
107+
{
108+
size: '2xl',
109+
orientation: 'vertical',
110+
class: {
111+
scrollbar: 'w-4'
112+
}
113+
}
114+
],
115+
defaultVariants: {
116+
size: 'md',
117+
orientation: 'vertical'
118+
}
119+
});
120+
121+
export type ScrollAreaSlots = keyof typeof scrollAreaVariants.slots;

packages/ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"dependencies": {
1414
"@radix-ui/react-compose-refs": "1.1.2",
15+
"@radix-ui/react-scroll-area": "^1.2.9",
1516
"@radix-ui/react-slot": "1.2.3",
1617
"@radix-ui/react-tabs": "1.1.12",
1718
"@soybean-react-ui/variants": "workspace:*",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export { default as ScrollArea } from './source/ScrollArea';
2+
export { default as ScrollAreaRoot } from './source/ScrollAreaRoot';
3+
export { default as ScrollAreaScrollbar } from './source/ScrollAreaScrollbar';
4+
export { default as ScrollAreaThumb } from './source/ScrollAreaThumb';
5+
export { default as ScrollAreaViewport } from './source/ScrollAreaViewport';
6+
7+
export * from './types';
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { ScrollAreaCorner } from '@radix-ui/react-scroll-area';
2+
import { cn } from '@soybean-react-ui/variants';
3+
import { forwardRef } from 'react';
4+
5+
import type { ScrollAreaProps } from '../types';
6+
7+
import ScrollAreaRoot from './ScrollAreaRoot';
8+
import ScrollAreaScrollbar from './ScrollAreaScrollbar';
9+
import ScrollAreaThumb from './ScrollAreaThumb';
10+
import ScrollAreaViewport from './ScrollAreaViewport';
11+
12+
const ScrollArea = forwardRef<React.ElementRef<typeof ScrollAreaRoot>, ScrollAreaProps>((props, ref) => {
13+
const { children, className, classNames, forceMount, nonce, orientation, size, ...rest } = props;
14+
15+
return (
16+
<ScrollAreaRoot
17+
className={className}
18+
{...rest}
19+
ref={ref}
20+
>
21+
<ScrollAreaViewport
22+
className={classNames?.viewport}
23+
nonce={nonce}
24+
>
25+
{children}
26+
</ScrollAreaViewport>
27+
28+
<ScrollAreaScrollbar
29+
className={classNames?.scrollbar}
30+
forceMount={forceMount}
31+
orientation={orientation}
32+
size={size}
33+
>
34+
<ScrollAreaThumb className={classNames?.thumb} />
35+
</ScrollAreaScrollbar>
36+
37+
<ScrollAreaCorner className={cn(classNames?.corner)} />
38+
</ScrollAreaRoot>
39+
);
40+
});
41+
42+
ScrollArea.displayName = 'ScrollArea';
43+
44+
export default ScrollArea;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Root } from '@radix-ui/react-scroll-area';
2+
import { cn, scrollAreaVariants } from '@soybean-react-ui/variants';
3+
import { forwardRef } from 'react';
4+
5+
import type { ScrollAreaRootProps } from '../types';
6+
7+
const ScrollAreaRoot = forwardRef<React.ElementRef<typeof Root>, ScrollAreaRootProps>((props, ref) => {
8+
const { className, ...rest } = props;
9+
10+
const { root } = scrollAreaVariants();
11+
12+
const mergedCls = cn(root(), className);
13+
14+
return (
15+
<Root
16+
className={mergedCls}
17+
{...rest}
18+
ref={ref}
19+
/>
20+
);
21+
});
22+
23+
ScrollAreaRoot.displayName = 'ScrollAreaRoot';
24+
25+
export default ScrollAreaRoot;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Scrollbar } from '@radix-ui/react-scroll-area';
2+
import { cn, scrollAreaVariants } from '@soybean-react-ui/variants';
3+
import { forwardRef } from 'react';
4+
5+
import type { ScrollAreaScrollbarProps } from '../types';
6+
7+
const ScrollAreaScrollbar = forwardRef<React.ElementRef<typeof Scrollbar>, ScrollAreaScrollbarProps>((props, ref) => {
8+
const { className, orientation, size, ...rest } = props;
9+
10+
const { scrollbar } = scrollAreaVariants({ orientation, size });
11+
12+
const mergedCls = cn(scrollbar(), className);
13+
14+
return (
15+
<Scrollbar
16+
className={mergedCls}
17+
orientation={orientation}
18+
{...rest}
19+
ref={ref}
20+
/>
21+
);
22+
});
23+
24+
ScrollAreaScrollbar.displayName = 'ScrollAreaScrollbar';
25+
26+
export default ScrollAreaScrollbar;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Thumb } from '@radix-ui/react-scroll-area';
2+
import { cn, scrollAreaVariants } from '@soybean-react-ui/variants';
3+
import { forwardRef } from 'react';
4+
5+
import type { ScrollAreaThumbProps } from '../types';
6+
7+
const ScrollAreaScrollbar = forwardRef<React.ElementRef<typeof Thumb>, ScrollAreaThumbProps>((props, ref) => {
8+
const { className, ...rest } = props;
9+
10+
const { thumb } = scrollAreaVariants();
11+
12+
const mergedCls = cn(thumb(), className);
13+
14+
return (
15+
<Thumb
16+
className={mergedCls}
17+
{...rest}
18+
ref={ref}
19+
/>
20+
);
21+
});
22+
23+
ScrollAreaScrollbar.displayName = 'ScrollAreaScrollbar';
24+
25+
export default ScrollAreaScrollbar;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Viewport } from '@radix-ui/react-scroll-area';
2+
import { cn, scrollAreaVariants } from '@soybean-react-ui/variants';
3+
import { forwardRef } from 'react';
4+
5+
import type { ScrollAreaViewportProps } from '../types';
6+
7+
const ScrollAreaViewport = forwardRef<React.ElementRef<typeof Viewport>, ScrollAreaViewportProps>((props, ref) => {
8+
const { className, ...rest } = props;
9+
10+
const { viewport } = scrollAreaVariants();
11+
12+
const mergedCls = cn(viewport(), className);
13+
14+
return (
15+
<Viewport
16+
className={mergedCls}
17+
{...rest}
18+
ref={ref}
19+
/>
20+
);
21+
});
22+
23+
ScrollAreaViewport.displayName = 'ScrollAreaViewport';
24+
25+
export default ScrollAreaViewport;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type {
2+
ScrollAreaProps as _ScrollAreaProps,
3+
ScrollAreaScrollbarProps as _ScrollAreaScrollbarProps,
4+
ScrollAreaViewportProps as _ScrollAreaViewportProps
5+
} from '@radix-ui/react-scroll-area';
6+
import type { ClassValue, ClassValueProp, ScrollAreaSlots } from '@soybean-react-ui/variants';
7+
8+
import type { BaseNodeProps } from '../../types/other';
9+
10+
export type ScrollAreaUi = Partial<Record<ScrollAreaSlots, ClassValue>>;
11+
12+
export type ScrollAreaRootProps = BaseNodeProps<_ScrollAreaProps>;
13+
14+
export type ScrollAreaScrollbarProps = BaseNodeProps<_ScrollAreaScrollbarProps>;
15+
16+
export type ScrollAreaThumbProps = ClassValueProp;
17+
18+
export type ScrollAreaViewportProps = BaseNodeProps<_ScrollAreaViewportProps>;
19+
20+
export interface ScrollAreaProps
21+
extends ScrollAreaRootProps,
22+
Omit<ScrollAreaScrollbarProps, 'dir'>,
23+
Omit<ScrollAreaViewportProps, 'dir'> {
24+
classNames?: ScrollAreaUi;
25+
}

0 commit comments

Comments
 (0)