@moloodev/ui 0.0.0-stage → 0.1.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,65 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { format } from "date-fns"
5
+ import { IconCalendar } from "@tabler/icons-react"
6
+
7
+ import { cn } from "../../lib/utils"
8
+ import { Button } from "./button"
9
+ import { Calendar } from "./calendar"
10
+ import {
11
+ Popover,
12
+ PopoverContent,
13
+ PopoverTrigger,
14
+ } from "./popover"
15
+
16
+ function DatePicker({
17
+ value: controlledValue,
18
+ defaultValue,
19
+ onValueChange,
20
+ placeholder = "Pick a date",
21
+ className,
22
+ }: {
23
+ value?: Date
24
+ defaultValue?: Date
25
+ onValueChange?: (date: Date | undefined) => void
26
+ placeholder?: string
27
+ className?: string
28
+ }) {
29
+ const [open, setOpen] = React.useState(false)
30
+ const [uncontrolled, setUncontrolled] = React.useState<Date | undefined>(
31
+ defaultValue
32
+ )
33
+ const date = controlledValue ?? uncontrolled
34
+
35
+ const setDate = (next: Date | undefined) => {
36
+ if (controlledValue === undefined) setUncontrolled(next)
37
+ onValueChange?.(next)
38
+ setOpen(false)
39
+ }
40
+
41
+ return (
42
+ <Popover open={open} onOpenChange={setOpen}>
43
+ <PopoverTrigger
44
+ render={
45
+ <Button
46
+ variant="outline"
47
+ className={cn(
48
+ "w-56 justify-start gap-2 font-normal normal-case",
49
+ !date && "text-muted-foreground",
50
+ className
51
+ )}
52
+ />
53
+ }
54
+ >
55
+ <IconCalendar className="size-4" />
56
+ {date ? format(date, "PPP") : placeholder}
57
+ </PopoverTrigger>
58
+ <PopoverContent className="w-auto p-0" align="start">
59
+ <Calendar mode="single" selected={date} onSelect={setDate} autoFocus />
60
+ </PopoverContent>
61
+ </Popover>
62
+ )
63
+ }
64
+
65
+ export { DatePicker }
@@ -0,0 +1,224 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
5
+
6
+ import { cn } from "../../lib/utils"
7
+ import { Button } from "./button"
8
+ import { IconX } from "@tabler/icons-react"
9
+
10
+ function Dialog({ ...props }: DialogPrimitive.Root.Props) {
11
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
12
+ }
13
+
14
+ function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
15
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
16
+ }
17
+
18
+ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
19
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
20
+ }
21
+
22
+ function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
23
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
24
+ }
25
+
26
+ function DialogOverlay({
27
+ className,
28
+ ...props
29
+ }: DialogPrimitive.Backdrop.Props) {
30
+ return (
31
+ <DialogPrimitive.Backdrop
32
+ data-slot="dialog-overlay"
33
+ className={cn(
34
+ "fixed inset-0 isolate z-50 bg-black/40 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
35
+ className
36
+ )}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ function DialogContent({
43
+ className,
44
+ children,
45
+ showCloseButton = true,
46
+ showOverlay = true,
47
+ closeLabel = "Close",
48
+ ...props
49
+ }: DialogPrimitive.Popup.Props & {
50
+ showCloseButton?: boolean
51
+ showOverlay?: boolean
52
+ closeLabel?: string
53
+ }) {
54
+ return (
55
+ <DialogPortal>
56
+ {showOverlay ? <DialogOverlay /> : null}
57
+ <DialogPrimitive.Popup
58
+ data-slot="dialog-content"
59
+ className={cn(
60
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 moloo-surface bg-popover p-4 text-sm text-popover-foreground duration-100 outline-none sm:max-w-sm 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",
61
+ className
62
+ )}
63
+ {...props}
64
+ >
65
+ {children}
66
+ {showCloseButton && (
67
+ <DialogPrimitive.Close
68
+ data-slot="dialog-close"
69
+ render={
70
+ <Button
71
+ variant="ghost"
72
+ className="absolute top-2 right-2"
73
+ size="icon-sm"
74
+ />
75
+ }
76
+ >
77
+ <IconX
78
+ />
79
+ <span className="sr-only">{closeLabel}</span>
80
+ </DialogPrimitive.Close>
81
+ )}
82
+ </DialogPrimitive.Popup>
83
+ </DialogPortal>
84
+ )
85
+ }
86
+
87
+ function DialogSplitContent({
88
+ className,
89
+ ...props
90
+ }: React.ComponentProps<typeof DialogContent>) {
91
+ return (
92
+ <DialogContent
93
+ className={cn(
94
+ "flex h-[min(88vh,42rem)] max-h-[calc(100dvh-2rem)] w-full flex-col gap-0 overflow-hidden p-0 sm:max-w-4xl",
95
+ "*:data-[slot=dialog-header]:shrink-0 *:data-[slot=dialog-header]:border-b *:data-[slot=dialog-header]:border-border *:data-[slot=dialog-header]:px-4 *:data-[slot=dialog-header]:py-3 *:data-[slot=dialog-header]:pr-12",
96
+ "*:data-[slot=dialog-footer]:shrink-0 *:data-[slot=dialog-footer]:border-t *:data-[slot=dialog-footer]:border-border *:data-[slot=dialog-footer]:px-4 *:data-[slot=dialog-footer]:py-3",
97
+ className
98
+ )}
99
+ {...props}
100
+ data-layout="split"
101
+ />
102
+ )
103
+ }
104
+
105
+ function DialogSplit({ className, ...props }: React.ComponentProps<"div">) {
106
+ return (
107
+ <div
108
+ data-slot="dialog-split"
109
+ className={cn(
110
+ "grid min-h-0 flex-1 grid-cols-1 overflow-hidden max-md:grid-rows-[minmax(0,1fr)_minmax(0,1fr)] max-md:divide-y max-md:divide-border md:grid-cols-[minmax(18rem,22rem)_minmax(0,1fr)] md:divide-x md:divide-border",
111
+ className
112
+ )}
113
+ {...props}
114
+ />
115
+ )
116
+ }
117
+
118
+ function DialogSplitStart({
119
+ className,
120
+ ...props
121
+ }: React.ComponentProps<"div">) {
122
+ return (
123
+ <div
124
+ data-slot="dialog-split-start"
125
+ className={cn("flex min-h-0 flex-col gap-4 overflow-y-auto p-4", className)}
126
+ {...props}
127
+ />
128
+ )
129
+ }
130
+
131
+ function DialogSplitEnd({ className, ...props }: React.ComponentProps<"div">) {
132
+ return (
133
+ <div
134
+ data-slot="dialog-split-end"
135
+ className={cn(
136
+ "flex min-h-0 min-w-0 flex-col overflow-y-auto p-4",
137
+ className
138
+ )}
139
+ {...props}
140
+ />
141
+ )
142
+ }
143
+
144
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
145
+ return (
146
+ <div
147
+ data-slot="dialog-header"
148
+ className={cn("flex flex-col gap-1 text-left", className)}
149
+ {...props}
150
+ />
151
+ )
152
+ }
153
+
154
+ function DialogFooter({
155
+ className,
156
+ showCloseButton = false,
157
+ closeLabel = "Close",
158
+ children,
159
+ ...props
160
+ }: React.ComponentProps<"div"> & {
161
+ showCloseButton?: boolean
162
+ closeLabel?: string
163
+ }) {
164
+ return (
165
+ <div
166
+ data-slot="dialog-footer"
167
+ className={cn(
168
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
169
+ className
170
+ )}
171
+ {...props}
172
+ >
173
+ {children}
174
+ {showCloseButton && (
175
+ <DialogPrimitive.Close render={<Button variant="outline" />}>
176
+ {closeLabel}
177
+ </DialogPrimitive.Close>
178
+ )}
179
+ </div>
180
+ )
181
+ }
182
+
183
+ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
184
+ return (
185
+ <DialogPrimitive.Title
186
+ data-slot="dialog-title"
187
+ className={cn("font-display text-base font-bold tracking-[-0.02em]", className)}
188
+ {...props}
189
+ />
190
+ )
191
+ }
192
+
193
+ function DialogDescription({
194
+ className,
195
+ ...props
196
+ }: DialogPrimitive.Description.Props) {
197
+ return (
198
+ <DialogPrimitive.Description
199
+ data-slot="dialog-description"
200
+ className={cn(
201
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
202
+ className
203
+ )}
204
+ {...props}
205
+ />
206
+ )
207
+ }
208
+
209
+ export {
210
+ Dialog,
211
+ DialogClose,
212
+ DialogContent,
213
+ DialogDescription,
214
+ DialogFooter,
215
+ DialogHeader,
216
+ DialogOverlay,
217
+ DialogPortal,
218
+ DialogSplit,
219
+ DialogSplitContent,
220
+ DialogSplitEnd,
221
+ DialogSplitStart,
222
+ DialogTitle,
223
+ DialogTrigger,
224
+ }
@@ -0,0 +1,231 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ type DrawerContextProps = {
9
+ hasSnapPoints: boolean
10
+ modal: DrawerPrimitive.Root.Props["modal"]
11
+ showSwipeHandle: boolean
12
+ swipeDirection: NonNullable<DrawerPrimitive.Root.Props["swipeDirection"]>
13
+ }
14
+
15
+ const DrawerContext = React.createContext<DrawerContextProps | null>(null)
16
+
17
+ function useDrawer() {
18
+ const context = React.useContext(DrawerContext)
19
+
20
+ if (!context) {
21
+ throw new Error("useDrawer must be used within a Drawer.")
22
+ }
23
+
24
+ return context
25
+ }
26
+
27
+ function Drawer({
28
+ modal = true,
29
+ showSwipeHandle = false,
30
+ snapPoints,
31
+ swipeDirection = "down",
32
+ ...props
33
+ }: DrawerPrimitive.Root.Props & {
34
+ showSwipeHandle?: boolean
35
+ }) {
36
+ const hasSnapPoints = snapPoints != null && snapPoints.length > 0
37
+ const contextValue = React.useMemo(
38
+ () => ({ hasSnapPoints, modal, showSwipeHandle, swipeDirection }),
39
+ [hasSnapPoints, modal, showSwipeHandle, swipeDirection]
40
+ )
41
+
42
+ return (
43
+ <DrawerContext.Provider value={contextValue}>
44
+ <DrawerPrimitive.Root
45
+ data-slot="drawer"
46
+ modal={modal}
47
+ snapPoints={snapPoints}
48
+ swipeDirection={swipeDirection}
49
+ {...props}
50
+ />
51
+ </DrawerContext.Provider>
52
+ )
53
+ }
54
+
55
+ function DrawerTrigger({ ...props }: DrawerPrimitive.Trigger.Props) {
56
+ return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />
57
+ }
58
+
59
+ function DrawerPortal({ ...props }: DrawerPrimitive.Portal.Props) {
60
+ return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />
61
+ }
62
+
63
+ function DrawerClose({ ...props }: DrawerPrimitive.Close.Props) {
64
+ return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />
65
+ }
66
+
67
+ function DrawerOverlay({
68
+ className,
69
+ ...props
70
+ }: DrawerPrimitive.Backdrop.Props) {
71
+ return (
72
+ <DrawerPrimitive.Backdrop
73
+ data-slot="drawer-overlay"
74
+ className={cn(
75
+ "fixed inset-0 z-50 min-h-dvh bg-black/40 opacity-[max(var(--drawer-overlay-min-opacity,0),calc(1-var(--drawer-swipe-progress)))] transition-opacity duration-450 ease-[cubic-bezier(0.32,0.72,0,1)] select-none data-ending-style:pointer-events-none data-ending-style:opacity-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-snap-points:[--drawer-overlay-min-opacity:0.5] data-starting-style:opacity-0 data-swiping:duration-0 supports-backdrop-filter:backdrop-blur-xs supports-[-webkit-touch-callout:none]:absolute",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function DrawerSwipeHandle({
84
+ className,
85
+ ...props
86
+ }: React.ComponentProps<"div">) {
87
+ return (
88
+ <div
89
+ data-slot="drawer-swipe-handle"
90
+ aria-hidden="true"
91
+ className={cn(
92
+ "relative z-10 flex shrink-0 cursor-grab transition-opacity duration-200 group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-[swipe-axis=x]/drawer-popup:h-full group-data-[swipe-axis=x]/drawer-popup:w-3 group-data-[swipe-axis=x]/drawer-popup:items-center group-data-[swipe-axis=y]/drawer-popup:h-3 group-data-[swipe-axis=y]/drawer-popup:w-full group-data-[swipe-axis=y]/drawer-popup:justify-center group-data-[swipe-direction=down]/drawer-popup:items-end group-data-[swipe-direction=left]/drawer-popup:order-last group-data-[swipe-direction=left]/drawer-popup:justify-start group-data-[swipe-direction=right]/drawer-popup:justify-end group-data-[swipe-direction=up]/drawer-popup:order-last group-data-[swipe-direction=up]/drawer-popup:items-start after:block after:shrink-0 after:rounded-md after:bg-muted group-data-[swipe-axis=x]/drawer-popup:after:h-12 group-data-[swipe-axis=x]/drawer-popup:after:w-1 group-data-[swipe-axis=y]/drawer-popup:after:h-1 group-data-[swipe-axis=y]/drawer-popup:after:w-12 active:cursor-grabbing",
93
+ className
94
+ )}
95
+ {...props}
96
+ />
97
+ )
98
+ }
99
+
100
+ function DrawerContent({
101
+ className,
102
+ children,
103
+ ...props
104
+ }: DrawerPrimitive.Popup.Props) {
105
+ const { hasSnapPoints, modal, showSwipeHandle, swipeDirection } = useDrawer()
106
+ const swipeAxis =
107
+ swipeDirection === "down" || swipeDirection === "up" ? "y" : "x"
108
+
109
+ return (
110
+ <DrawerPortal data-slot="drawer-portal">
111
+ {modal === true && (
112
+ <DrawerOverlay data-snap-points={hasSnapPoints ? "" : undefined} />
113
+ )}
114
+ <DrawerPrimitive.Viewport
115
+ data-slot="drawer-viewport"
116
+ data-modal={modal}
117
+ className="pointer-events-none fixed inset-0 z-50 select-none data-[modal=true]:pointer-events-auto"
118
+ >
119
+ <DrawerPrimitive.Popup
120
+ data-slot="drawer-popup"
121
+ data-swipe-axis={swipeAxis}
122
+ data-snap-points={hasSnapPoints ? "" : undefined}
123
+ className={cn(
124
+ // Base.
125
+ "group/drawer-popup pointer-events-auto fixed z-50 m-(--drawer-inset,0px) flex h-(--drawer-content-height) max-h-(--drawer-content-max-height,none) min-h-0 w-(--drawer-content-width,auto) transform-[translate3d(var(--translate-x,0px),var(--translate-y,0px),0)_scale(var(--stack-scale))] flex-col moloo-surface bg-popover text-sm/relaxed text-popover-foreground transition-[transform,height,opacity,filter] duration-450 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform outline-none select-none [interpolate-size:allow-keywords] data-[swipe-direction=down]:rounded-md data-[swipe-direction=down]:border-t data-[swipe-direction=left]:rounded-md data-[swipe-direction=left]:border-r data-[swipe-direction=right]:rounded-md data-[swipe-direction=right]:border-l data-[swipe-direction=up]:rounded-md data-[swipe-direction=up]:border-b",
126
+ // Nested.
127
+ "data-nested-drawer-open:overflow-hidden data-nested-drawer-open:brightness-95",
128
+ // Bleed.
129
+ "after:pointer-events-none after:absolute after:bg-(--drawer-bleed-background,var(--color-popover)) data-[swipe-axis=x]:after:inset-y-0 data-[swipe-axis=x]:after:w-(--bleed) data-[swipe-axis=y]:after:inset-x-0 data-[swipe-axis=y]:after:h-(--bleed) data-[swipe-direction=down]:after:top-full data-[swipe-direction=left]:after:right-full data-[swipe-direction=right]:after:left-full data-[swipe-direction=up]:after:bottom-full",
130
+ // Sizing.
131
+ "[--drawer-content-height:var(--drawer-height,auto)] data-[swipe-axis=x]:[--drawer-content-width:75%] data-[swipe-axis=y]:[--drawer-content-max-height:calc(100dvh-6rem)] data-[swipe-axis=y]:data-snap-points:[--drawer-content-height:100dvh] data-[swipe-axis=x]:sm:[--drawer-content-width:24rem]",
132
+ // Stack.
133
+ "[--bleed:3rem] [--peek:1rem] [--stack-height:var(--drawer-frontmost-height,var(--drawer-height,0px))] [--stack-peek-offset:max(0px,calc((var(--nested-drawers)-var(--stack-progress))*var(--peek)))] [--stack-progress:clamp(0,var(--drawer-swipe-progress),1)] [--stack-scale-base:max(0,calc(1-(var(--nested-drawers)*var(--stack-step))))] [--stack-scale:clamp(0,calc(var(--stack-scale-base)+(var(--stack-step)*var(--stack-progress))),1)] [--stack-shrink:calc(1-var(--stack-scale))] [--stack-step:0.05]",
134
+ // Transitions.
135
+ "data-ending-style:transform-(--closed-transform) data-ending-style:opacity-[0.9999] data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-nested-drawer-swiping:duration-0 data-ending-style:data-nested-drawer-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-starting-style:transform-(--closed-transform) data-swiping:duration-0 data-ending-style:data-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)]",
136
+ // Axis: y.
137
+ "data-[swipe-axis=y]:inset-x-0 data-[swipe-axis=y]:data-nested-drawer-open:h-(--stack-height)",
138
+ // Axis: x.
139
+ "data-[swipe-axis=x]:inset-y-0 data-[swipe-axis=x]:flex-row",
140
+ // Direction: down.
141
+ "data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:origin-bottom data-[swipe-direction=down]:[--closed-transform:translate3d(0,calc(100%+var(--drawer-inset,0px)+2px),0)] data-[swipe-direction=down]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)-var(--stack-peek-offset)-(var(--stack-shrink)*var(--stack-height)))]",
142
+ // Direction: up.
143
+ "data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:origin-top data-[swipe-direction=up]:[--closed-transform:translate3d(0,calc(-100%-var(--drawer-inset,0px)-2px),0)] data-[swipe-direction=up]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)+var(--stack-peek-offset)+(var(--stack-shrink)*var(--stack-height)))]",
144
+ // Direction: left.
145
+ "data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:origin-left data-[swipe-direction=left]:[--closed-transform:translate3d(calc(-100%-var(--drawer-inset,0px)-2px),0,0)] data-[swipe-direction=left]:[--translate-x:calc(var(--drawer-swipe-movement-x)+var(--stack-peek-offset)+(var(--stack-shrink)*100%))]",
146
+ // Direction: right.
147
+ "data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:origin-right data-[swipe-direction=right]:[--closed-transform:translate3d(calc(100%+var(--drawer-inset,0px)+2px),0,0)] data-[swipe-direction=right]:[--translate-x:calc(var(--drawer-swipe-movement-x)-var(--stack-peek-offset)-(var(--stack-shrink)*100%))]",
148
+ className
149
+ )}
150
+ {...props}
151
+ >
152
+ {showSwipeHandle && <DrawerSwipeHandle />}
153
+ <DrawerPrimitive.Content
154
+ data-slot="drawer-content"
155
+ className={cn(
156
+ "flex min-h-0 flex-1 flex-col overflow-hidden overscroll-contain rounded-[inherit] transition-opacity duration-300 ease-[cubic-bezier(0.45,1.005,0,1.005)] select-text group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-swiping/drawer-popup:select-none"
157
+ )}
158
+ >
159
+ {children}
160
+ </DrawerPrimitive.Content>
161
+ </DrawerPrimitive.Popup>
162
+ </DrawerPrimitive.Viewport>
163
+ </DrawerPortal>
164
+ )
165
+ }
166
+
167
+ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
168
+ return (
169
+ <div
170
+ data-slot="drawer-header"
171
+ className={cn(
172
+ "flex shrink-0 flex-col gap-0.5 p-4 pb-0 group-data-[swipe-axis=y]/drawer-popup:text-center md:gap-0.5 md:text-left",
173
+ className
174
+ )}
175
+ {...props}
176
+ />
177
+ )
178
+ }
179
+
180
+ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
181
+ return (
182
+ <div
183
+ data-slot="drawer-footer"
184
+ className={cn("mt-auto flex shrink-0 flex-col gap-2 p-4 pt-0", className)}
185
+ {...props}
186
+ />
187
+ )
188
+ }
189
+
190
+ function DrawerTitle({ className, ...props }: DrawerPrimitive.Title.Props) {
191
+ return (
192
+ <DrawerPrimitive.Title
193
+ data-slot="drawer-title"
194
+ className={cn(
195
+ "font-heading text-sm font-medium text-foreground",
196
+ className
197
+ )}
198
+ {...props}
199
+ />
200
+ )
201
+ }
202
+
203
+ function DrawerDescription({
204
+ className,
205
+ ...props
206
+ }: DrawerPrimitive.Description.Props) {
207
+ return (
208
+ <DrawerPrimitive.Description
209
+ data-slot="drawer-description"
210
+ className={cn(
211
+ "text-sm/relaxed text-balance text-muted-foreground",
212
+ className
213
+ )}
214
+ {...props}
215
+ />
216
+ )
217
+ }
218
+
219
+ export {
220
+ Drawer,
221
+ DrawerPortal,
222
+ DrawerOverlay,
223
+ DrawerSwipeHandle,
224
+ DrawerTrigger,
225
+ DrawerClose,
226
+ DrawerContent,
227
+ DrawerHeader,
228
+ DrawerFooter,
229
+ DrawerTitle,
230
+ DrawerDescription,
231
+ }