@bupple/vss-ui 1.0.0

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.
Files changed (65) hide show
  1. package/.turbo/turbo-lint.log +4 -0
  2. package/components.json +21 -0
  3. package/eslint.config.js +4 -0
  4. package/index.ts +2 -0
  5. package/package.json +67 -0
  6. package/postcss.config.mjs +6 -0
  7. package/src/components/accordion.tsx +84 -0
  8. package/src/components/alert-dialog.tsx +198 -0
  9. package/src/components/alert.tsx +77 -0
  10. package/src/components/aspect-ratio.tsx +11 -0
  11. package/src/components/avatar.tsx +109 -0
  12. package/src/components/badge.tsx +50 -0
  13. package/src/components/breadcrumb.tsx +118 -0
  14. package/src/components/button-group.tsx +84 -0
  15. package/src/components/button.tsx +68 -0
  16. package/src/components/calendar.tsx +223 -0
  17. package/src/components/card.tsx +102 -0
  18. package/src/components/carousel.tsx +241 -0
  19. package/src/components/chart.tsx +373 -0
  20. package/src/components/checkbox.tsx +32 -0
  21. package/src/components/collapsible.tsx +33 -0
  22. package/src/components/combobox.tsx +299 -0
  23. package/src/components/command.tsx +194 -0
  24. package/src/components/context-menu.tsx +272 -0
  25. package/src/components/dialog.tsx +171 -0
  26. package/src/components/direction.tsx +20 -0
  27. package/src/components/drawer.tsx +130 -0
  28. package/src/components/dropdown-menu.tsx +278 -0
  29. package/src/components/empty.tsx +102 -0
  30. package/src/components/field.tsx +237 -0
  31. package/src/components/hover-card.tsx +43 -0
  32. package/src/components/input-group.tsx +157 -0
  33. package/src/components/input.tsx +18 -0
  34. package/src/components/item.tsx +197 -0
  35. package/src/components/kbd.tsx +26 -0
  36. package/src/components/label.tsx +21 -0
  37. package/src/components/menubar.tsx +283 -0
  38. package/src/components/native-select.tsx +64 -0
  39. package/src/components/navigation-menu.tsx +166 -0
  40. package/src/components/pagination.tsx +131 -0
  41. package/src/components/popover.tsx +88 -0
  42. package/src/components/progress.tsx +30 -0
  43. package/src/components/radio-group.tsx +46 -0
  44. package/src/components/resizable.tsx +49 -0
  45. package/src/components/scroll-area.tsx +52 -0
  46. package/src/components/select.tsx +209 -0
  47. package/src/components/separator.tsx +25 -0
  48. package/src/components/sheet.tsx +152 -0
  49. package/src/components/sidebar.tsx +703 -0
  50. package/src/components/skeleton.tsx +13 -0
  51. package/src/components/slider.tsx +58 -0
  52. package/src/components/sonner.tsx +45 -0
  53. package/src/components/spinner.tsx +15 -0
  54. package/src/components/switch.tsx +32 -0
  55. package/src/components/table.tsx +115 -0
  56. package/src/components/tabs.tsx +89 -0
  57. package/src/components/textarea.tsx +17 -0
  58. package/src/components/toggle-group.tsx +86 -0
  59. package/src/components/toggle.tsx +48 -0
  60. package/src/components/tooltip.tsx +56 -0
  61. package/src/hooks/use-mobile.ts +19 -0
  62. package/src/lib/portal-container.ts +11 -0
  63. package/src/lib/utils.ts +8 -0
  64. package/src/theme.css +125 -0
  65. package/tsconfig.json +15 -0
@@ -0,0 +1,64 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import { ChevronDownIcon } from 'lucide-react'
3
+ import * as React from 'react'
4
+
5
+ type NativeSelectProps = Omit<React.ComponentProps<'select'>, 'size'> & {
6
+ size?: 'sm' | 'default'
7
+ }
8
+
9
+ function NativeSelect({
10
+ className,
11
+ size = 'default',
12
+ ...props
13
+ }: NativeSelectProps) {
14
+ return (
15
+ <div
16
+ className={cn(
17
+ 'group/native-select relative w-fit has-[select:disabled]:opacity-50',
18
+ className,
19
+ )}
20
+ data-slot='native-select-wrapper'
21
+ data-size={size}
22
+ >
23
+ <select
24
+ data-slot='native-select'
25
+ data-size={size}
26
+ className='h-8 w-full min-w-0 appearance-none rounded-lg border border-input bg-transparent py-1 pr-8 pl-2.5 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-[size=sm]:py-0.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40'
27
+ {...props}
28
+ />
29
+ <ChevronDownIcon
30
+ className='pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none'
31
+ aria-hidden='true'
32
+ data-slot='native-select-icon'
33
+ />
34
+ </div>
35
+ )
36
+ }
37
+
38
+ function NativeSelectOption({
39
+ className,
40
+ ...props
41
+ }: React.ComponentProps<'option'>) {
42
+ return (
43
+ <option
44
+ data-slot='native-select-option'
45
+ className={cn('bg-[Canvas] text-[CanvasText]', className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function NativeSelectOptGroup({
52
+ className,
53
+ ...props
54
+ }: React.ComponentProps<'optgroup'>) {
55
+ return (
56
+ <optgroup
57
+ data-slot='native-select-optgroup'
58
+ className={cn('bg-[Canvas] text-[CanvasText]', className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ export { NativeSelect, NativeSelectOptGroup, NativeSelectOption }
@@ -0,0 +1,166 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import { cva } from 'class-variance-authority'
3
+ import { ChevronDownIcon } from 'lucide-react'
4
+ import { NavigationMenu as NavigationMenuPrimitive } from 'radix-ui'
5
+ import * as React from 'react'
6
+
7
+ function NavigationMenu({
8
+ className,
9
+ children,
10
+ viewport = true,
11
+ ...props
12
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
13
+ viewport?: boolean
14
+ }) {
15
+ return (
16
+ <NavigationMenuPrimitive.Root
17
+ data-slot='navigation-menu'
18
+ data-viewport={viewport}
19
+ className={cn(
20
+ 'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',
21
+ className,
22
+ )}
23
+ {...props}
24
+ >
25
+ {children}
26
+ {viewport && <NavigationMenuViewport />}
27
+ </NavigationMenuPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ function NavigationMenuList({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
35
+ return (
36
+ <NavigationMenuPrimitive.List
37
+ data-slot='navigation-menu-list'
38
+ className={cn(
39
+ 'group flex flex-1 list-none items-center justify-center gap-0',
40
+ className,
41
+ )}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ function NavigationMenuItem({
48
+ className,
49
+ ...props
50
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
51
+ return (
52
+ <NavigationMenuPrimitive.Item
53
+ data-slot='navigation-menu-item'
54
+ className={cn('relative', className)}
55
+ {...props}
56
+ />
57
+ )
58
+ }
59
+
60
+ const navigationMenuTriggerStyle = cva(
61
+ 'group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted',
62
+ )
63
+
64
+ function NavigationMenuTrigger({
65
+ className,
66
+ children,
67
+ ...props
68
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
69
+ return (
70
+ <NavigationMenuPrimitive.Trigger
71
+ data-slot='navigation-menu-trigger'
72
+ className={cn(navigationMenuTriggerStyle(), 'group', className)}
73
+ {...props}
74
+ >
75
+ {children}{' '}
76
+ <ChevronDownIcon
77
+ className='relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180'
78
+ aria-hidden='true'
79
+ />
80
+ </NavigationMenuPrimitive.Trigger>
81
+ )
82
+ }
83
+
84
+ function NavigationMenuContent({
85
+ className,
86
+ ...props
87
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
88
+ return (
89
+ <NavigationMenuPrimitive.Content
90
+ data-slot='navigation-menu-content'
91
+ className={cn(
92
+ 'top-0 left-0 w-full p-1 ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none md:absolute md:w-auto group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95',
93
+ className,
94
+ )}
95
+ {...props}
96
+ />
97
+ )
98
+ }
99
+
100
+ function NavigationMenuViewport({
101
+ className,
102
+ ...props
103
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
104
+ return (
105
+ <div
106
+ className={cn(
107
+ 'absolute top-full left-0 isolate z-50 flex justify-center',
108
+ )}
109
+ >
110
+ <NavigationMenuPrimitive.Viewport
111
+ data-slot='navigation-menu-viewport'
112
+ className={cn(
113
+ 'origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 duration-100 md:w-(--radix-navigation-menu-viewport-width) data-open:animate-in data-open:zoom-in-90 data-closed:animate-out data-closed:zoom-out-90',
114
+ className,
115
+ )}
116
+ {...props}
117
+ />
118
+ </div>
119
+ )
120
+ }
121
+
122
+ function NavigationMenuLink({
123
+ className,
124
+ ...props
125
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
126
+ return (
127
+ <NavigationMenuPrimitive.Link
128
+ data-slot='navigation-menu-link'
129
+ className={cn(
130
+ "flex items-center gap-2 rounded-lg p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*='size-'])]:size-4",
131
+ className,
132
+ )}
133
+ {...props}
134
+ />
135
+ )
136
+ }
137
+
138
+ function NavigationMenuIndicator({
139
+ className,
140
+ ...props
141
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
142
+ return (
143
+ <NavigationMenuPrimitive.Indicator
144
+ data-slot='navigation-menu-indicator'
145
+ className={cn(
146
+ 'top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in',
147
+ className,
148
+ )}
149
+ {...props}
150
+ >
151
+ <div className='relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md' />
152
+ </NavigationMenuPrimitive.Indicator>
153
+ )
154
+ }
155
+
156
+ export {
157
+ NavigationMenu,
158
+ NavigationMenuList,
159
+ NavigationMenuItem,
160
+ NavigationMenuContent,
161
+ NavigationMenuTrigger,
162
+ NavigationMenuLink,
163
+ NavigationMenuIndicator,
164
+ NavigationMenuViewport,
165
+ navigationMenuTriggerStyle,
166
+ }
@@ -0,0 +1,131 @@
1
+ import { Button } from '@bupple/vss-ui/components/button'
2
+ import { cn } from '@bupple/vss-ui/lib/utils'
3
+ import {
4
+ ChevronLeftIcon,
5
+ ChevronRightIcon,
6
+ MoreHorizontalIcon,
7
+ } from 'lucide-react'
8
+ import * as React from 'react'
9
+
10
+ function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
11
+ return (
12
+ <nav
13
+ role='navigation'
14
+ aria-label='pagination'
15
+ data-slot='pagination'
16
+ className={cn('mx-auto flex w-full justify-center', className)}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ function PaginationContent({
23
+ className,
24
+ ...props
25
+ }: React.ComponentProps<'ul'>) {
26
+ return (
27
+ <ul
28
+ data-slot='pagination-content'
29
+ className={cn('flex items-center gap-0.5', className)}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
36
+ return <li data-slot='pagination-item' {...props} />
37
+ }
38
+
39
+ type PaginationLinkProps = {
40
+ isActive?: boolean
41
+ } & Pick<React.ComponentProps<typeof Button>, 'size'> &
42
+ React.ComponentProps<'a'>
43
+
44
+ function PaginationLink({
45
+ className,
46
+ isActive,
47
+ size = 'icon',
48
+ ...props
49
+ }: PaginationLinkProps) {
50
+ return (
51
+ <Button
52
+ asChild
53
+ variant={isActive ? 'outline' : 'ghost'}
54
+ size={size}
55
+ className={cn(className)}
56
+ >
57
+ <a
58
+ aria-current={isActive ? 'page' : undefined}
59
+ data-slot='pagination-link'
60
+ data-active={isActive}
61
+ {...props}
62
+ />
63
+ </Button>
64
+ )
65
+ }
66
+
67
+ function PaginationPrevious({
68
+ className,
69
+ text = 'Previous',
70
+ ...props
71
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
72
+ return (
73
+ <PaginationLink
74
+ aria-label='Go to previous page'
75
+ size='default'
76
+ className={cn('pl-1.5!', className)}
77
+ {...props}
78
+ >
79
+ <ChevronLeftIcon data-icon='inline-start' />
80
+ <span className='hidden sm:block'>{text}</span>
81
+ </PaginationLink>
82
+ )
83
+ }
84
+
85
+ function PaginationNext({
86
+ className,
87
+ text = 'Next',
88
+ ...props
89
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
90
+ return (
91
+ <PaginationLink
92
+ aria-label='Go to next page'
93
+ size='default'
94
+ className={cn('pr-1.5!', className)}
95
+ {...props}
96
+ >
97
+ <span className='hidden sm:block'>{text}</span>
98
+ <ChevronRightIcon data-icon='inline-end' />
99
+ </PaginationLink>
100
+ )
101
+ }
102
+
103
+ function PaginationEllipsis({
104
+ className,
105
+ ...props
106
+ }: React.ComponentProps<'span'>) {
107
+ return (
108
+ <span
109
+ aria-hidden
110
+ data-slot='pagination-ellipsis'
111
+ className={cn(
112
+ "flex size-8 items-center justify-center [&_svg:not([class*='size-'])]:size-4",
113
+ className,
114
+ )}
115
+ {...props}
116
+ >
117
+ <MoreHorizontalIcon />
118
+ <span className='sr-only'>More pages</span>
119
+ </span>
120
+ )
121
+ }
122
+
123
+ export {
124
+ Pagination,
125
+ PaginationContent,
126
+ PaginationEllipsis,
127
+ PaginationItem,
128
+ PaginationLink,
129
+ PaginationNext,
130
+ PaginationPrevious,
131
+ }
@@ -0,0 +1,88 @@
1
+ import { usePortalContainer } from '@bupple/vss-ui/lib/portal-container'
2
+ import { cn } from '@bupple/vss-ui/lib/utils'
3
+ import { Popover as PopoverPrimitive } from 'radix-ui'
4
+ import * as React from 'react'
5
+
6
+ function Popover({
7
+ ...props
8
+ }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
9
+ return <PopoverPrimitive.Root data-slot='popover' {...props} />
10
+ }
11
+
12
+ function PopoverTrigger({
13
+ ...props
14
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
15
+ return <PopoverPrimitive.Trigger data-slot='popover-trigger' {...props} />
16
+ }
17
+
18
+ function PopoverContent({
19
+ className,
20
+ align = 'center',
21
+ sideOffset = 4,
22
+ ...props
23
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
24
+ const container = usePortalContainer()
25
+ return (
26
+ <PopoverPrimitive.Portal container={container ?? undefined}>
27
+ <PopoverPrimitive.Content
28
+ data-slot='popover-content'
29
+ align={align}
30
+ sideOffset={sideOffset}
31
+ className={cn(
32
+ 'z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ </PopoverPrimitive.Portal>
38
+ )
39
+ }
40
+
41
+ function PopoverAnchor({
42
+ ...props
43
+ }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
44
+ return <PopoverPrimitive.Anchor data-slot='popover-anchor' {...props} />
45
+ }
46
+
47
+ function PopoverHeader({ className, ...props }: React.ComponentProps<'div'>) {
48
+ return (
49
+ <div
50
+ data-slot='popover-header'
51
+ className={cn('flex flex-col gap-0.5 text-sm', className)}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function PopoverTitle({ className, ...props }: React.ComponentProps<'h2'>) {
58
+ return (
59
+ <div
60
+ data-slot='popover-title'
61
+ className={cn('font-medium', className)}
62
+ {...props}
63
+ />
64
+ )
65
+ }
66
+
67
+ function PopoverDescription({
68
+ className,
69
+ ...props
70
+ }: React.ComponentProps<'p'>) {
71
+ return (
72
+ <p
73
+ data-slot='popover-description'
74
+ className={cn('text-muted-foreground', className)}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ export {
81
+ Popover,
82
+ PopoverAnchor,
83
+ PopoverContent,
84
+ PopoverDescription,
85
+ PopoverHeader,
86
+ PopoverTitle,
87
+ PopoverTrigger,
88
+ }
@@ -0,0 +1,30 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@bupple/vss-ui/lib/utils'
4
+ import { Progress as ProgressPrimitive } from 'radix-ui'
5
+ import * as React from 'react'
6
+
7
+ function Progress({
8
+ className,
9
+ value,
10
+ ...props
11
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
12
+ return (
13
+ <ProgressPrimitive.Root
14
+ data-slot='progress'
15
+ className={cn(
16
+ 'relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted',
17
+ className,
18
+ )}
19
+ {...props}
20
+ >
21
+ <ProgressPrimitive.Indicator
22
+ data-slot='progress-indicator'
23
+ className='size-full flex-1 bg-primary transition-all'
24
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
25
+ />
26
+ </ProgressPrimitive.Root>
27
+ )
28
+ }
29
+
30
+ export { Progress }
@@ -0,0 +1,46 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import { RadioGroup as RadioGroupPrimitive } from 'radix-ui'
3
+ import * as React from 'react'
4
+
5
+ function RadioGroup({
6
+ className,
7
+ ...props
8
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
9
+ return (
10
+ <RadioGroupPrimitive.Root
11
+ data-slot='radio-group'
12
+ className={cn('grid w-full gap-2', className)}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function RadioGroupItem({
19
+ className,
20
+ indicatorIcon,
21
+ ...props
22
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Item> & {
23
+ indicatorIcon?: React.ReactNode
24
+ }) {
25
+ return (
26
+ <RadioGroupPrimitive.Item
27
+ data-slot='radio-group-item'
28
+ className={cn(
29
+ 'group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary',
30
+ className,
31
+ )}
32
+ {...props}
33
+ >
34
+ <RadioGroupPrimitive.Indicator
35
+ data-slot='radio-group-indicator'
36
+ className='flex size-4 items-center justify-center'
37
+ >
38
+ {indicatorIcon ?? (
39
+ <span className='absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary-foreground' />
40
+ )}
41
+ </RadioGroupPrimitive.Indicator>
42
+ </RadioGroupPrimitive.Item>
43
+ )
44
+ }
45
+
46
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1,49 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@bupple/vss-ui/lib/utils'
4
+ import * as ResizablePrimitive from 'react-resizable-panels'
5
+
6
+ function ResizablePanelGroup({
7
+ className,
8
+ ...props
9
+ }: ResizablePrimitive.GroupProps) {
10
+ return (
11
+ <ResizablePrimitive.Group
12
+ data-slot='resizable-panel-group'
13
+ className={cn(
14
+ 'flex h-full w-full aria-[orientation=vertical]:flex-col',
15
+ className,
16
+ )}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
23
+ return <ResizablePrimitive.Panel data-slot='resizable-panel' {...props} />
24
+ }
25
+
26
+ function ResizableHandle({
27
+ withHandle,
28
+ className,
29
+ ...props
30
+ }: ResizablePrimitive.SeparatorProps & {
31
+ withHandle?: boolean
32
+ }) {
33
+ return (
34
+ <ResizablePrimitive.Separator
35
+ data-slot='resizable-handle'
36
+ className={cn(
37
+ 'relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90',
38
+ className,
39
+ )}
40
+ {...props}
41
+ >
42
+ {withHandle && (
43
+ <div className='z-10 flex h-6 w-1 shrink-0 rounded-lg bg-border' />
44
+ )}
45
+ </ResizablePrimitive.Separator>
46
+ )
47
+ }
48
+
49
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
@@ -0,0 +1,52 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import { ScrollArea as ScrollAreaPrimitive } from 'radix-ui'
3
+ import * as React from 'react'
4
+
5
+ function ScrollArea({
6
+ className,
7
+ children,
8
+ ...props
9
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
10
+ return (
11
+ <ScrollAreaPrimitive.Root
12
+ data-slot='scroll-area'
13
+ className={cn('relative', className)}
14
+ {...props}
15
+ >
16
+ <ScrollAreaPrimitive.Viewport
17
+ data-slot='scroll-area-viewport'
18
+ className='size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1'
19
+ >
20
+ {children}
21
+ </ScrollAreaPrimitive.Viewport>
22
+ <ScrollBar />
23
+ <ScrollAreaPrimitive.Corner />
24
+ </ScrollAreaPrimitive.Root>
25
+ )
26
+ }
27
+
28
+ function ScrollBar({
29
+ className,
30
+ orientation = 'vertical',
31
+ ...props
32
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
33
+ return (
34
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
35
+ data-slot='scroll-area-scrollbar'
36
+ data-orientation={orientation}
37
+ orientation={orientation}
38
+ className={cn(
39
+ 'flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent',
40
+ className,
41
+ )}
42
+ {...props}
43
+ >
44
+ <ScrollAreaPrimitive.ScrollAreaThumb
45
+ data-slot='scroll-area-thumb'
46
+ className='relative flex-1 rounded-full bg-border'
47
+ />
48
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
49
+ )
50
+ }
51
+
52
+ export { ScrollArea, ScrollBar }