@moloodev/ui 0.0.0-stage → 0.2.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 (93) hide show
  1. package/package.json +139 -3
  2. package/registry/components.ts +135 -0
  3. package/registry/fonts.css +81 -0
  4. package/registry/suit-OFL.txt +94 -0
  5. package/registry/wanted-sans-OFL.txt +93 -0
  6. package/src/components/ui/accordion.tsx +74 -0
  7. package/src/components/ui/alert-dialog.tsx +187 -0
  8. package/src/components/ui/alert.tsx +83 -0
  9. package/src/components/ui/aspect-ratio.tsx +22 -0
  10. package/src/components/ui/attachment.tsx +207 -0
  11. package/src/components/ui/avatar.tsx +109 -0
  12. package/src/components/ui/badge.tsx +54 -0
  13. package/src/components/ui/breadcrumb.tsx +126 -0
  14. package/src/components/ui/bubble.tsx +128 -0
  15. package/src/components/ui/button-group.tsx +103 -0
  16. package/src/components/ui/button.tsx +68 -0
  17. package/src/components/ui/calendar.tsx +222 -0
  18. package/src/components/ui/card.tsx +103 -0
  19. package/src/components/ui/carousel.tsx +242 -0
  20. package/src/components/ui/chart.tsx +398 -0
  21. package/src/components/ui/checkbox.tsx +28 -0
  22. package/src/components/ui/collapsible.tsx +40 -0
  23. package/src/components/ui/combobox.tsx +299 -0
  24. package/src/components/ui/command.tsx +218 -0
  25. package/src/components/ui/context-menu.tsx +271 -0
  26. package/src/components/ui/data-table.tsx +919 -0
  27. package/src/components/ui/date-picker.tsx +65 -0
  28. package/src/components/ui/dialog.tsx +224 -0
  29. package/src/components/ui/drawer.tsx +231 -0
  30. package/src/components/ui/dropdown-menu.tsx +268 -0
  31. package/src/components/ui/dropzone.tsx +186 -0
  32. package/src/components/ui/empty.tsx +101 -0
  33. package/src/components/ui/field.tsx +238 -0
  34. package/src/components/ui/form.tsx +83 -0
  35. package/src/components/ui/highlighted-source.tsx +200 -0
  36. package/src/components/ui/hover-card.tsx +51 -0
  37. package/src/components/ui/image-field.tsx +796 -0
  38. package/src/components/ui/input-group.tsx +149 -0
  39. package/src/components/ui/input-otp.tsx +86 -0
  40. package/src/components/ui/input-step.ts +19 -0
  41. package/src/components/ui/input.tsx +100 -0
  42. package/src/components/ui/item.tsx +201 -0
  43. package/src/components/ui/kbd.tsx +91 -0
  44. package/src/components/ui/kind-icon-glob.ts +24 -0
  45. package/src/components/ui/kind-icon-load.ts +52 -0
  46. package/src/components/ui/kind-icon-static.ts +46 -0
  47. package/src/components/ui/kind-icon.tsx +84 -0
  48. package/src/components/ui/kind-mark.tsx +65 -0
  49. package/src/components/ui/label.tsx +29 -0
  50. package/src/components/ui/marker.tsx +71 -0
  51. package/src/components/ui/menubar.tsx +277 -0
  52. package/src/components/ui/message-scroller.tsx +137 -0
  53. package/src/components/ui/message.tsx +92 -0
  54. package/src/components/ui/moloo-logo.tsx +45 -0
  55. package/src/components/ui/native-select.tsx +61 -0
  56. package/src/components/ui/navigation-menu.tsx +168 -0
  57. package/src/components/ui/outline-list.tsx +73 -0
  58. package/src/components/ui/pagination.tsx +130 -0
  59. package/src/components/ui/panel.tsx +108 -0
  60. package/src/components/ui/popover.tsx +90 -0
  61. package/src/components/ui/progress.tsx +117 -0
  62. package/src/components/ui/radio-group.tsx +38 -0
  63. package/src/components/ui/resizable.tsx +52 -0
  64. package/src/components/ui/scroll-area.tsx +54 -0
  65. package/src/components/ui/select.tsx +205 -0
  66. package/src/components/ui/separator.tsx +25 -0
  67. package/src/components/ui/sheet.tsx +140 -0
  68. package/src/components/ui/sidebar.tsx +746 -0
  69. package/src/components/ui/skeleton.tsx +13 -0
  70. package/src/components/ui/slider.tsx +52 -0
  71. package/src/components/ui/spinner.tsx +18 -0
  72. package/src/components/ui/switch.tsx +32 -0
  73. package/src/components/ui/table.tsx +116 -0
  74. package/src/components/ui/tabs.tsx +83 -0
  75. package/src/components/ui/tag-list-input.tsx +194 -0
  76. package/src/components/ui/textarea.tsx +18 -0
  77. package/src/components/ui/timeline.tsx +265 -0
  78. package/src/components/ui/toast.tsx +237 -0
  79. package/src/components/ui/toggle-group.tsx +90 -0
  80. package/src/components/ui/toggle.tsx +45 -0
  81. package/src/components/ui/tooltip.tsx +66 -0
  82. package/src/css.d.ts +1 -0
  83. package/src/hooks/use-clipboard.ts +82 -0
  84. package/src/hooks/use-mobile.ts +21 -0
  85. package/src/index.ts +106 -0
  86. package/src/kind-icon.ts +4 -0
  87. package/src/lib/format-relative-time.ts +41 -0
  88. package/src/lib/list-selection.ts +61 -0
  89. package/src/lib/utils.ts +6 -0
  90. package/src/moloo.css +360 -0
  91. package/src/styles.css +36 -0
  92. package/src/typeset.css +518 -0
  93. package/README.md +0 -3
@@ -0,0 +1,130 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "../../lib/utils"
4
+ import { Button } from "./button"
5
+ import { IconChevronLeft, IconChevronRight, IconDots } from "@tabler/icons-react"
6
+
7
+ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
8
+ return (
9
+ <nav
10
+ role="navigation"
11
+ aria-label="pagination"
12
+ data-slot="pagination"
13
+ className={cn("mx-auto flex w-full justify-center", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function PaginationContent({
20
+ className,
21
+ ...props
22
+ }: React.ComponentProps<"ul">) {
23
+ return (
24
+ <ul
25
+ data-slot="pagination-content"
26
+ className={cn("flex items-center gap-0.5", className)}
27
+ {...props}
28
+ />
29
+ )
30
+ }
31
+
32
+ function PaginationItem({ ...props }: React.ComponentProps<"li">) {
33
+ return <li data-slot="pagination-item" {...props} />
34
+ }
35
+
36
+ type PaginationLinkProps = {
37
+ isActive?: boolean
38
+ } & Pick<React.ComponentProps<typeof Button>, "size"> &
39
+ React.ComponentProps<"a">
40
+
41
+ function PaginationLink({
42
+ className,
43
+ isActive,
44
+ size = "icon",
45
+ ...props
46
+ }: PaginationLinkProps) {
47
+ return (
48
+ <Button
49
+ variant={isActive ? "outline" : "ghost"}
50
+ size={size}
51
+ className={cn(className)}
52
+ nativeButton={false}
53
+ render={
54
+ <a
55
+ aria-current={isActive ? "page" : undefined}
56
+ data-slot="pagination-link"
57
+ data-active={isActive}
58
+ {...props}
59
+ />
60
+ }
61
+ />
62
+ )
63
+ }
64
+
65
+ function PaginationPrevious({
66
+ className,
67
+ text = "Previous",
68
+ ...props
69
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
70
+ return (
71
+ <PaginationLink
72
+ aria-label="Go to previous page"
73
+ size="default"
74
+ className={cn("pl-1.5!", className)}
75
+ {...props}
76
+ >
77
+ <IconChevronLeft data-icon="inline-start" />
78
+ <span className="hidden sm:block">{text}</span>
79
+ </PaginationLink>
80
+ )
81
+ }
82
+
83
+ function PaginationNext({
84
+ className,
85
+ text = "Next",
86
+ ...props
87
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
88
+ return (
89
+ <PaginationLink
90
+ aria-label="Go to next page"
91
+ size="default"
92
+ className={cn("pr-1.5!", className)}
93
+ {...props}
94
+ >
95
+ <span className="hidden sm:block">{text}</span>
96
+ <IconChevronRight data-icon="inline-end" />
97
+ </PaginationLink>
98
+ )
99
+ }
100
+
101
+ function PaginationEllipsis({
102
+ className,
103
+ ...props
104
+ }: React.ComponentProps<"span">) {
105
+ return (
106
+ <span
107
+ aria-hidden
108
+ data-slot="pagination-ellipsis"
109
+ className={cn(
110
+ "flex size-8 items-center justify-center [&_svg:not([class*='size-'])]:size-4",
111
+ className
112
+ )}
113
+ {...props}
114
+ >
115
+ <IconDots
116
+ />
117
+ <span className="sr-only">More pages</span>
118
+ </span>
119
+ )
120
+ }
121
+
122
+ export {
123
+ Pagination,
124
+ PaginationContent,
125
+ PaginationEllipsis,
126
+ PaginationItem,
127
+ PaginationLink,
128
+ PaginationNext,
129
+ PaginationPrevious,
130
+ }
@@ -0,0 +1,108 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "../../lib/utils"
4
+
5
+ const PanelContext = React.createContext<string | null>(null)
6
+
7
+ function Panel({
8
+ className,
9
+ size = "default",
10
+ children,
11
+ ...props
12
+ }: React.ComponentProps<"section"> & { size?: "default" | "compact" }) {
13
+ const titleId = React.useId()
14
+
15
+ return (
16
+ <section
17
+ data-slot="panel"
18
+ data-size={size}
19
+ className={cn(
20
+ "group/panel flex min-h-0 flex-col overflow-hidden rounded-md border-2 border-border bg-card text-sm text-card-foreground shadow-moloo [--panel-spacing:--spacing(4)] data-[size=compact]:[--panel-spacing:--spacing(2.5)]",
21
+ className
22
+ )}
23
+ {...props}
24
+ aria-labelledby={titleId}
25
+ >
26
+ <PanelContext.Provider value={titleId}>{children}</PanelContext.Provider>
27
+ </section>
28
+ )
29
+ }
30
+
31
+ function PanelHeader({ className, ...props }: React.ComponentProps<"div">) {
32
+ return (
33
+ <div
34
+ data-slot="panel-header"
35
+ className={cn(
36
+ "grid shrink-0 auto-rows-min grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-y-1 border-b-2 bg-muted px-(--panel-spacing) py-(--panel-spacing)",
37
+ "*:data-[slot=panel-title]:col-start-2 *:data-[slot=panel-title]:row-start-1 *:data-[slot=panel-title]:min-w-0",
38
+ "*:data-[slot=panel-description]:col-start-2 *:data-[slot=panel-description]:row-start-2 *:data-[slot=panel-description]:min-w-0",
39
+ "*:data-[slot=panel-action]:col-start-3 *:data-[slot=panel-action]:row-span-2 *:data-[slot=panel-action]:row-start-1 *:data-[slot=panel-action]:ml-2.5 *:data-[slot=panel-action]:justify-self-end *:data-[slot=panel-action]:self-center",
40
+ "[&>svg]:pointer-events-none [&>svg]:col-start-1 [&>svg]:row-span-2 [&>svg]:row-start-1 [&>svg]:mr-2.5 [&>svg]:shrink-0 [&>svg]:self-center [&>svg:not([class*='size-'])]:size-4",
41
+ "group-data-[size=compact]/panel:flex group-data-[size=compact]/panel:h-12 group-data-[size=compact]/panel:max-h-12 group-data-[size=compact]/panel:gap-2 group-data-[size=compact]/panel:py-0",
42
+ "group-data-[size=compact]/panel:*:data-[slot=panel-description]:shrink-0 group-data-[size=compact]/panel:*:data-[slot=panel-description]:min-w-min",
43
+ "group-data-[size=compact]/panel:*:data-[slot=panel-action]:ml-auto group-data-[size=compact]/panel:*:data-[slot=panel-action]:shrink-0",
44
+ "group-data-[size=compact]/panel:[&>svg]:mr-0",
45
+ className
46
+ )}
47
+ {...props}
48
+ />
49
+ )
50
+ }
51
+
52
+ function PanelTitle({ className, ...props }: React.ComponentProps<"h2">) {
53
+ const titleId = React.useContext(PanelContext)
54
+ if (!titleId) {
55
+ throw new Error("PanelTitle must be used within Panel.")
56
+ }
57
+
58
+ return (
59
+ <h2
60
+ data-slot="panel-title"
61
+ className={cn(
62
+ "font-display text-base leading-tight font-bold tracking-[-0.02em] group-data-[size=compact]/panel:truncate group-data-[size=compact]/panel:text-sm",
63
+ className
64
+ )}
65
+ {...props}
66
+ id={titleId}
67
+ />
68
+ )
69
+ }
70
+
71
+ function PanelDescription({ className, ...props }: React.ComponentProps<"p">) {
72
+ return (
73
+ <p
74
+ data-slot="panel-description"
75
+ className={cn(
76
+ "text-sm/relaxed text-pretty text-muted-foreground group-data-[size=compact]/panel:text-xs/4 group-data-[size=compact]/panel:whitespace-nowrap",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ function PanelAction({ className, ...props }: React.ComponentProps<"div">) {
85
+ return <div data-slot="panel-action" className={className} {...props} />
86
+ }
87
+
88
+ function PanelBody({ className, ...props }: React.ComponentProps<"div">) {
89
+ return (
90
+ <div
91
+ data-slot="panel-body"
92
+ className={cn(
93
+ "min-h-0 flex-1 overflow-auto px-(--panel-spacing) py-(--panel-spacing)",
94
+ className
95
+ )}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ export {
102
+ Panel,
103
+ PanelHeader,
104
+ PanelTitle,
105
+ PanelDescription,
106
+ PanelAction,
107
+ PanelBody,
108
+ }
@@ -0,0 +1,90 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ function Popover({ ...props }: PopoverPrimitive.Root.Props) {
9
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
10
+ }
11
+
12
+ function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
13
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
14
+ }
15
+
16
+ function PopoverContent({
17
+ className,
18
+ align = "center",
19
+ alignOffset = 0,
20
+ side = "bottom",
21
+ sideOffset = 4,
22
+ ...props
23
+ }: PopoverPrimitive.Popup.Props &
24
+ Pick<
25
+ PopoverPrimitive.Positioner.Props,
26
+ "align" | "alignOffset" | "side" | "sideOffset"
27
+ >) {
28
+ return (
29
+ <PopoverPrimitive.Portal>
30
+ <PopoverPrimitive.Positioner
31
+ align={align}
32
+ alignOffset={alignOffset}
33
+ side={side}
34
+ sideOffset={sideOffset}
35
+ className="isolate z-50"
36
+ >
37
+ <PopoverPrimitive.Popup
38
+ data-slot="popover-content"
39
+ className={cn(
40
+ "z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-md moloo-surface bg-popover p-2.5 text-sm text-popover-foreground shadow-moloo-lg outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ </PopoverPrimitive.Positioner>
46
+ </PopoverPrimitive.Portal>
47
+ )
48
+ }
49
+
50
+ function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
51
+ return (
52
+ <div
53
+ data-slot="popover-header"
54
+ className={cn("flex flex-col gap-1 text-sm", className)}
55
+ {...props}
56
+ />
57
+ )
58
+ }
59
+
60
+ function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
61
+ return (
62
+ <PopoverPrimitive.Title
63
+ data-slot="popover-title"
64
+ className={cn("text-sm font-medium", className)}
65
+ {...props}
66
+ />
67
+ )
68
+ }
69
+
70
+ function PopoverDescription({
71
+ className,
72
+ ...props
73
+ }: PopoverPrimitive.Description.Props) {
74
+ return (
75
+ <PopoverPrimitive.Description
76
+ data-slot="popover-description"
77
+ className={cn("text-sm/relaxed text-muted-foreground", className)}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ export {
84
+ Popover,
85
+ PopoverContent,
86
+ PopoverDescription,
87
+ PopoverHeader,
88
+ PopoverTitle,
89
+ PopoverTrigger,
90
+ }
@@ -0,0 +1,117 @@
1
+ "use client"
2
+
3
+ import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ const PROGRESS_MAX = 100
8
+
9
+ function isOverLimit(value: number | null, max: number) {
10
+ if (typeof value !== "number" || !Number.isFinite(value)) return false
11
+ if (!Number.isFinite(max)) return false
12
+ return value > max
13
+ }
14
+
15
+ function overLimitAriaValueText(max: number) {
16
+ return (formattedValue: string | null, value: number | null) => {
17
+ const shown = formattedValue || `${value}`
18
+ return `${shown}, over the limit of ${max}`
19
+ }
20
+ }
21
+
22
+ function Progress({
23
+ className,
24
+ children,
25
+ value,
26
+ max,
27
+ getAriaValueText,
28
+ "aria-valuetext": ariaValueText,
29
+ ...props
30
+ }: ProgressPrimitive.Root.Props) {
31
+ const upper = max ?? PROGRESS_MAX
32
+ const overLimit = isOverLimit(value, upper)
33
+ const hint =
34
+ overLimit && ariaValueText == null && getAriaValueText == null
35
+ ? overLimitAriaValueText(upper)
36
+ : getAriaValueText
37
+
38
+ return (
39
+ <ProgressPrimitive.Root
40
+ {...props}
41
+ value={value}
42
+ max={max}
43
+ getAriaValueText={hint}
44
+ {...(ariaValueText != null ? { "aria-valuetext": ariaValueText } : {})}
45
+ data-slot="progress"
46
+ data-over-limit={overLimit ? true : undefined}
47
+ className={cn("group/progress flex flex-wrap items-center gap-3", className)}
48
+ >
49
+ {children}
50
+ <ProgressTrack>
51
+ <ProgressIndicator
52
+ className={overLimit ? "bg-none bg-destructive-fill" : undefined}
53
+ />
54
+ </ProgressTrack>
55
+ </ProgressPrimitive.Root>
56
+ )
57
+ }
58
+
59
+ function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
60
+ return (
61
+ <ProgressPrimitive.Track
62
+ className={cn(
63
+ "relative flex h-[0.55rem] w-full items-center overflow-hidden rounded-full bg-card shadow-[var(--moloo-progress-shadow)]",
64
+ className
65
+ )}
66
+ data-slot="progress-track"
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ function ProgressIndicator({
73
+ className,
74
+ ...props
75
+ }: ProgressPrimitive.Indicator.Props) {
76
+ return (
77
+ <ProgressPrimitive.Indicator
78
+ data-slot="progress-indicator"
79
+ className={cn(
80
+ "h-full rounded-full bg-linear-to-r from-primary to-accent transition-all",
81
+ className
82
+ )}
83
+ {...props}
84
+ />
85
+ )
86
+ }
87
+
88
+ function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
89
+ return (
90
+ <ProgressPrimitive.Label
91
+ className={cn("label text-foreground", className)}
92
+ data-slot="progress-label"
93
+ {...props}
94
+ />
95
+ )
96
+ }
97
+
98
+ function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
99
+ return (
100
+ <ProgressPrimitive.Value
101
+ className={cn(
102
+ "ml-auto font-display text-sm font-bold tracking-[-0.02em] text-muted-foreground tabular-nums group-data-[over-limit=true]/progress:text-destructive",
103
+ className
104
+ )}
105
+ data-slot="progress-value"
106
+ {...props}
107
+ />
108
+ )
109
+ }
110
+
111
+ export {
112
+ Progress,
113
+ ProgressTrack,
114
+ ProgressIndicator,
115
+ ProgressLabel,
116
+ ProgressValue,
117
+ }
@@ -0,0 +1,38 @@
1
+ "use client"
2
+
3
+ import { Radio as RadioPrimitive } from "@base-ui/react/radio"
4
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
9
+ return (
10
+ <RadioGroupPrimitive
11
+ data-slot="radio-group"
12
+ className={cn("grid w-full gap-2", className)}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
19
+ return (
20
+ <RadioPrimitive.Root
21
+ data-slot="radio-group-item"
22
+ className={cn(
23
+ "group/radio-group-item moloo-focus peer relative flex aspect-square size-4 shrink-0 rounded-full border-2 border-input bg-[var(--field-bg)] transition-colors outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:aria-checked:border-primary dark:bg-input/30 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
24
+ className
25
+ )}
26
+ {...props}
27
+ >
28
+ <RadioPrimitive.Indicator
29
+ data-slot="radio-group-indicator"
30
+ className="absolute inset-0 grid place-items-center"
31
+ >
32
+ <span className="size-2 rounded-full bg-primary-foreground animate-in zoom-in-50 duration-150" />
33
+ </RadioPrimitive.Indicator>
34
+ </RadioPrimitive.Root>
35
+ )
36
+ }
37
+
38
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1,52 @@
1
+ "use client"
2
+
3
+ import * as ResizablePrimitive from "react-resizable-panels"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function ResizablePanelGroup({
8
+ className,
9
+ ...props
10
+ }: ResizablePrimitive.GroupProps) {
11
+ return (
12
+ <ResizablePrimitive.Group
13
+ data-slot="resizable-panel-group"
14
+ className={cn(
15
+ "flex h-full w-full aria-[orientation=vertical]:flex-col",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+
23
+ function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
24
+ return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
25
+ }
26
+
27
+ function ResizableHandle({
28
+ withHandle,
29
+ className,
30
+ ...props
31
+ }: ResizablePrimitive.SeparatorProps & {
32
+ withHandle?: boolean
33
+ }) {
34
+ return (
35
+ <ResizablePrimitive.Separator
36
+ data-slot="resizable-handle"
37
+ className={cn(
38
+ "relative flex w-px items-center justify-center bg-border outline-none moloo-focus after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 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",
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ {withHandle && (
44
+ <div className="z-10 flex h-6 w-1 shrink-0 rounded-md bg-border" />
45
+ )}
46
+ </ResizablePrimitive.Separator>
47
+ )
48
+ }
49
+
50
+ const usePanelRef = ResizablePrimitive.usePanelRef
51
+
52
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup, usePanelRef }
@@ -0,0 +1,54 @@
1
+ "use client"
2
+
3
+ import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function ScrollArea({
8
+ className,
9
+ children,
10
+ ...props
11
+ }: ScrollAreaPrimitive.Root.Props) {
12
+ return (
13
+ <ScrollAreaPrimitive.Root
14
+ data-slot="scroll-area"
15
+ className={cn("relative", className)}
16
+ {...props}
17
+ >
18
+ <ScrollAreaPrimitive.Viewport
19
+ data-slot="scroll-area-viewport"
20
+ className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none moloo-focus"
21
+ >
22
+ {children}
23
+ </ScrollAreaPrimitive.Viewport>
24
+ <ScrollBar />
25
+ <ScrollAreaPrimitive.Corner />
26
+ </ScrollAreaPrimitive.Root>
27
+ )
28
+ }
29
+
30
+ function ScrollBar({
31
+ className,
32
+ orientation = "vertical",
33
+ ...props
34
+ }: ScrollAreaPrimitive.Scrollbar.Props) {
35
+ return (
36
+ <ScrollAreaPrimitive.Scrollbar
37
+ data-slot="scroll-area-scrollbar"
38
+ data-orientation={orientation}
39
+ orientation={orientation}
40
+ className={cn(
41
+ "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",
42
+ className
43
+ )}
44
+ {...props}
45
+ >
46
+ <ScrollAreaPrimitive.Thumb
47
+ data-slot="scroll-area-thumb"
48
+ className="relative flex-1 rounded-md bg-border"
49
+ />
50
+ </ScrollAreaPrimitive.Scrollbar>
51
+ )
52
+ }
53
+
54
+ export { ScrollArea, ScrollBar }