@gentleduck/registry-ui 0.2.1

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 (175) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/index.css +3 -0
  3. package/package.json +59 -0
  4. package/src/_old/_table/index.ts +5 -0
  5. package/src/_old/_table/table-advanced.constants.tsx +24 -0
  6. package/src/_old/_table/table-advanced.tsx +311 -0
  7. package/src/_old/_table/table-advanced.types.ts +272 -0
  8. package/src/_old/_table/table.constants.ts +2 -0
  9. package/src/_old/_table/table.hook.tsx +115 -0
  10. package/src/_old/_table/table.lib.ts +85 -0
  11. package/src/_old/_table/table.tsx +916 -0
  12. package/src/_old/_table/table.types.ts +118 -0
  13. package/src/_old/_table/todo.md +11 -0
  14. package/src/_old/_upload/index.ts +9 -0
  15. package/src/_old/_upload/todo.md +38 -0
  16. package/src/_old/_upload/upload-advanced-chunks.tsx +1624 -0
  17. package/src/_old/_upload/upload-advanced.tsx +507 -0
  18. package/src/_old/_upload/upload-sonner.tsx +58 -0
  19. package/src/_old/_upload/upload.assets.tsx +239 -0
  20. package/src/_old/_upload/upload.constants.tsx +75 -0
  21. package/src/_old/_upload/upload.dto.ts +19 -0
  22. package/src/_old/_upload/upload.lib.tsx +630 -0
  23. package/src/_old/_upload/upload.tsx +491 -0
  24. package/src/_old/_upload/upload.types.ts +436 -0
  25. package/src/accordion/accordion.tsx +247 -0
  26. package/src/accordion/index.ts +1 -0
  27. package/src/alert/alert.constants.ts +17 -0
  28. package/src/alert/alert.tsx +52 -0
  29. package/src/alert/index.ts +2 -0
  30. package/src/alert-dialog/alert-dialog.tsx +107 -0
  31. package/src/alert-dialog/index.ts +1 -0
  32. package/src/aspect-ratio/aspect-ratio.tsx +33 -0
  33. package/src/aspect-ratio/index.ts +1 -0
  34. package/src/audio/audio-record.tsx +776 -0
  35. package/src/audio/audio-visualizer.tsx +377 -0
  36. package/src/audio/audio.libs.ts +5 -0
  37. package/src/audio/audio.types.ts +50 -0
  38. package/src/audio/index.ts +2 -0
  39. package/src/avatar/avatar.tsx +78 -0
  40. package/src/avatar/index.ts +1 -0
  41. package/src/badge/badge.constants.ts +38 -0
  42. package/src/badge/badge.tsx +19 -0
  43. package/src/badge/index.ts +2 -0
  44. package/src/breadcrumb/breadcrumb.tsx +119 -0
  45. package/src/breadcrumb/index.ts +1 -0
  46. package/src/button/button.constants.ts +44 -0
  47. package/src/button/button.tsx +79 -0
  48. package/src/button/button.types.ts +38 -0
  49. package/src/button/index.ts +3 -0
  50. package/src/button-group/button-group.constants.ts +26 -0
  51. package/src/button-group/button-group.tsx +65 -0
  52. package/src/button-group/index.ts +2 -0
  53. package/src/calendar/calendar.tsx +191 -0
  54. package/src/calendar/index.ts +1 -0
  55. package/src/card/card.tsx +81 -0
  56. package/src/card/index.ts +1 -0
  57. package/src/carousel/carousel.tsx +211 -0
  58. package/src/carousel/carousel.types.ts +23 -0
  59. package/src/carousel/index.ts +2 -0
  60. package/src/chart/chart.libs.ts +27 -0
  61. package/src/chart/chart.tsx +260 -0
  62. package/src/chart/chart.types.ts +38 -0
  63. package/src/chart/index.ts +3 -0
  64. package/src/checkbox/checkbox.tsx +144 -0
  65. package/src/checkbox/checkbox.types.ts +24 -0
  66. package/src/checkbox/index.ts +2 -0
  67. package/src/collapsible/collapsible.tsx +151 -0
  68. package/src/collapsible/index.ts +1 -0
  69. package/src/combobox/combobox.tsx +132 -0
  70. package/src/combobox/index.ts +1 -0
  71. package/src/command/command.tsx +192 -0
  72. package/src/command/command.types.ts +11 -0
  73. package/src/command/index.ts +2 -0
  74. package/src/context-menu/context-menu.tsx +178 -0
  75. package/src/context-menu/index.ts +1 -0
  76. package/src/dialog/dialog-responsive.tsx +137 -0
  77. package/src/dialog/dialog.tsx +97 -0
  78. package/src/dialog/index.ts +2 -0
  79. package/src/direction/direction.tsx +13 -0
  80. package/src/direction/index.ts +1 -0
  81. package/src/drawer/drawer.tsx +185 -0
  82. package/src/drawer/index.ts +1 -0
  83. package/src/dropdown-menu/dropdown-menu.tsx +181 -0
  84. package/src/dropdown-menu/index.ts +1 -0
  85. package/src/empty/empty.constants.ts +15 -0
  86. package/src/empty/empty.tsx +73 -0
  87. package/src/empty/index.ts +2 -0
  88. package/src/field/field.constants.ts +22 -0
  89. package/src/field/field.tsx +203 -0
  90. package/src/field/index.ts +2 -0
  91. package/src/hover-card/hover-card.tsx +79 -0
  92. package/src/hover-card/index.ts +1 -0
  93. package/src/input/index.ts +1 -0
  94. package/src/input/input.tsx +45 -0
  95. package/src/input-group/index.ts +1 -0
  96. package/src/input-group/input-group.tsx +170 -0
  97. package/src/input-otp/index.ts +1 -0
  98. package/src/input-otp/input-otp.tsx +66 -0
  99. package/src/item/index.ts +2 -0
  100. package/src/item/item.constants.ts +22 -0
  101. package/src/item/item.tsx +185 -0
  102. package/src/json-editor/index.ts +4 -0
  103. package/src/json-editor/json-editor.hooks.ts +21 -0
  104. package/src/json-editor/json-editor.libs.ts +34 -0
  105. package/src/json-editor/json-editor.tsx +425 -0
  106. package/src/json-editor/json-editor.types.ts +80 -0
  107. package/src/json-editor/json-editor.view.tsx +110 -0
  108. package/src/json-editor/json-text-area.tsx +7 -0
  109. package/src/kbd/index.ts +1 -0
  110. package/src/kbd/kbd.tsx +39 -0
  111. package/src/label/index.ts +1 -0
  112. package/src/label/label.tsx +28 -0
  113. package/src/menubar/index.ts +1 -0
  114. package/src/menubar/menubar.tsx +213 -0
  115. package/src/navigation-menu/index.ts +1 -0
  116. package/src/navigation-menu/navigation-menu.tsx +152 -0
  117. package/src/pagination/index.ts +2 -0
  118. package/src/pagination/pagination.tsx +191 -0
  119. package/src/pagination/pagination.types.ts +17 -0
  120. package/src/popover/index.ts +1 -0
  121. package/src/popover/popover.tsx +35 -0
  122. package/src/preview-panel/index.ts +3 -0
  123. package/src/preview-panel/preview-panel-dialog.tsx +99 -0
  124. package/src/preview-panel/preview-panel.tsx +389 -0
  125. package/src/preview-panel/preview-panel.types.ts +49 -0
  126. package/src/progress/index.ts +1 -0
  127. package/src/progress/progress.tsx +32 -0
  128. package/src/radio-group/index.ts +1 -0
  129. package/src/radio-group/radio-group.tsx +92 -0
  130. package/src/resizable/index.ts +1 -0
  131. package/src/resizable/resizable.tsx +52 -0
  132. package/src/scroll-area/index.ts +1 -0
  133. package/src/scroll-area/scroll-area.tsx +30 -0
  134. package/src/select/index.ts +1 -0
  135. package/src/select/select.tsx +138 -0
  136. package/src/separator/index.ts +1 -0
  137. package/src/separator/separator.tsx +28 -0
  138. package/src/sheet/index.ts +2 -0
  139. package/src/sheet/sheet.constants.tsx +20 -0
  140. package/src/sheet/sheet.tsx +92 -0
  141. package/src/sidebar/index.ts +4 -0
  142. package/src/sidebar/sidebar.constants.ts +30 -0
  143. package/src/sidebar/sidebar.hooks.ts +13 -0
  144. package/src/sidebar/sidebar.tsx +676 -0
  145. package/src/sidebar/sidebar.types.ts +28 -0
  146. package/src/skeleton/index.ts +1 -0
  147. package/src/skeleton/skeleton.tsx +22 -0
  148. package/src/slider/index.ts +1 -0
  149. package/src/slider/slider.tsx +57 -0
  150. package/src/sonner/index.ts +4 -0
  151. package/src/sonner/sonner.chunks.tsx +80 -0
  152. package/src/sonner/sonner.libs.ts +13 -0
  153. package/src/sonner/sonner.tsx +31 -0
  154. package/src/sonner/sonner.types.ts +9 -0
  155. package/src/switch/index.ts +1 -0
  156. package/src/switch/switch.tsx +63 -0
  157. package/src/table/index.ts +1 -0
  158. package/src/table/table.tsx +95 -0
  159. package/src/tabs/index.ts +1 -0
  160. package/src/tabs/tabs.tsx +151 -0
  161. package/src/textarea/index.ts +1 -0
  162. package/src/textarea/textarea.tsx +24 -0
  163. package/src/toggle/index.ts +2 -0
  164. package/src/toggle/toggle.constants.ts +22 -0
  165. package/src/toggle/toggle.tsx +24 -0
  166. package/src/toggle-group/index.ts +1 -0
  167. package/src/toggle-group/toggle-group.tsx +69 -0
  168. package/src/tooltip/index.ts +1 -0
  169. package/src/tooltip/tooltip.tsx +32 -0
  170. package/src/upload/index.ts +1 -0
  171. package/src/upload/upload.constants.tsx +19 -0
  172. package/src/upload/upload.libs.ts +97 -0
  173. package/src/upload/upload.tsx +340 -0
  174. package/src/upload/upload.types.ts +44 -0
  175. package/tsconfig.json +25 -0
@@ -0,0 +1,178 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@gentleduck/libs/cn'
4
+ import * as ContextMenuPrimitive from '@gentleduck/primitives/context-menu'
5
+ import { Check, ChevronRight, Circle } from 'lucide-react'
6
+ import * as React from 'react'
7
+
8
+ const ContextMenu = ContextMenuPrimitive.Root
9
+
10
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger
11
+
12
+ const ContextMenuGroup = ContextMenuPrimitive.Group
13
+
14
+ const ContextMenuPortal = ContextMenuPrimitive.Portal
15
+
16
+ const ContextMenuSub = ContextMenuPrimitive.Sub
17
+
18
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
19
+
20
+ const ContextMenuSubTrigger = React.forwardRef<
21
+ React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>,
22
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
23
+ inset?: boolean
24
+ }
25
+ >(({ className, inset, children, ...props }, ref) => (
26
+ <ContextMenuPrimitive.SubTrigger
27
+ ref={ref}
28
+ className={cn(
29
+ 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
30
+ inset && 'ps-8',
31
+ className,
32
+ )}
33
+ {...props}>
34
+ {children}
35
+ <ChevronRight aria-hidden="true" className="ms-auto h-4 w-4 rtl:rotate-180" />
36
+ </ContextMenuPrimitive.SubTrigger>
37
+ ))
38
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
39
+
40
+ const ContextMenuSubContent = React.forwardRef<
41
+ React.ComponentRef<typeof ContextMenuPrimitive.SubContent>,
42
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
43
+ >(({ className, ...props }, ref) => (
44
+ <ContextMenuPrimitive.SubContent
45
+ ref={ref}
46
+ className={cn(
47
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 z-50 min-w-32 origin-(--gentleduck-context-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in',
48
+ 'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
49
+ className,
50
+ )}
51
+ {...props}
52
+ />
53
+ ))
54
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
55
+
56
+ const ContextMenuContent = React.forwardRef<
57
+ React.ComponentRef<typeof ContextMenuPrimitive.Content>,
58
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
59
+ >(({ className, ...props }, ref) => (
60
+ <ContextMenuPrimitive.Portal>
61
+ <ContextMenuPrimitive.Content
62
+ ref={ref}
63
+ className={cn(
64
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 z-50 max-h-(--gentleduck-context-menu-content-available-height) min-w-32 origin-(--gentleduck-context-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
65
+ 'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
66
+ className,
67
+ )}
68
+ {...props}
69
+ />
70
+ </ContextMenuPrimitive.Portal>
71
+ ))
72
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
73
+
74
+ const ContextMenuItem = React.forwardRef<
75
+ React.ComponentRef<typeof ContextMenuPrimitive.Item>,
76
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
77
+ inset?: boolean
78
+ }
79
+ >(({ className, inset, ...props }, ref) => (
80
+ <ContextMenuPrimitive.Item
81
+ ref={ref}
82
+ className={cn(
83
+ 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
84
+ inset && 'ps-8',
85
+ className,
86
+ )}
87
+ {...props}
88
+ />
89
+ ))
90
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
91
+
92
+ const ContextMenuCheckboxItem = React.forwardRef<
93
+ React.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,
94
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
95
+ >(({ className, children, checked, ...props }, ref) => (
96
+ <ContextMenuPrimitive.CheckboxItem
97
+ ref={ref}
98
+ className={cn(
99
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
100
+ className,
101
+ )}
102
+ checked={checked}
103
+ {...props}>
104
+ <span className="absolute start-2 flex h-3.5 w-3.5 items-center justify-center">
105
+ <ContextMenuPrimitive.ItemIndicator>
106
+ <Check aria-hidden="true" className="h-4 w-4" />
107
+ </ContextMenuPrimitive.ItemIndicator>
108
+ </span>
109
+ {children}
110
+ </ContextMenuPrimitive.CheckboxItem>
111
+ ))
112
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName
113
+
114
+ const ContextMenuRadioItem = React.forwardRef<
115
+ React.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,
116
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
117
+ >(({ className, children, ...props }, ref) => (
118
+ <ContextMenuPrimitive.RadioItem
119
+ ref={ref}
120
+ className={cn(
121
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
122
+ className,
123
+ )}
124
+ {...props}>
125
+ <span className="absolute start-2 flex h-3.5 w-3.5 items-center justify-center">
126
+ <ContextMenuPrimitive.ItemIndicator>
127
+ <Circle aria-hidden="true" className="size-2 fill-current" />
128
+ </ContextMenuPrimitive.ItemIndicator>
129
+ </span>
130
+ {children}
131
+ </ContextMenuPrimitive.RadioItem>
132
+ ))
133
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
134
+
135
+ const ContextMenuLabel = React.forwardRef<
136
+ React.ComponentRef<typeof ContextMenuPrimitive.Label>,
137
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
138
+ inset?: boolean
139
+ }
140
+ >(({ className, inset, ...props }, ref) => (
141
+ <ContextMenuPrimitive.Label
142
+ ref={ref}
143
+ className={cn('px-2 py-1.5 font-semibold text-foreground text-sm', inset && 'ps-8', className)}
144
+ {...props}
145
+ />
146
+ ))
147
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
148
+
149
+ const ContextMenuSeparator = React.forwardRef<
150
+ React.ComponentRef<typeof ContextMenuPrimitive.Separator>,
151
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
152
+ >(({ className, ...props }, ref) => (
153
+ <ContextMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-border', className)} {...props} />
154
+ ))
155
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
156
+
157
+ const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
158
+ return <span className={cn('ms-auto text-muted-foreground text-xs tracking-widest', className)} {...props} />
159
+ }
160
+ ContextMenuShortcut.displayName = 'ContextMenuShortcut'
161
+
162
+ export {
163
+ ContextMenu,
164
+ ContextMenuTrigger,
165
+ ContextMenuContent,
166
+ ContextMenuItem,
167
+ ContextMenuCheckboxItem,
168
+ ContextMenuRadioItem,
169
+ ContextMenuLabel,
170
+ ContextMenuSeparator,
171
+ ContextMenuShortcut,
172
+ ContextMenuGroup,
173
+ ContextMenuPortal,
174
+ ContextMenuSub,
175
+ ContextMenuSubContent,
176
+ ContextMenuSubTrigger,
177
+ ContextMenuRadioGroup,
178
+ }
@@ -0,0 +1 @@
1
+ export * from './context-menu'
@@ -0,0 +1,137 @@
1
+ 'use client'
2
+ import { useMediaQuery } from '@gentleduck/hooks/use-media-query'
3
+ import type React from 'react'
4
+ import {
5
+ Drawer,
6
+ DrawerClose,
7
+ DrawerContent,
8
+ DrawerDescription,
9
+ DrawerFooter,
10
+ DrawerHeader,
11
+ DrawerTitle,
12
+ DrawerTrigger,
13
+ } from '../drawer'
14
+ import {
15
+ Dialog,
16
+ DialogClose,
17
+ DialogContent,
18
+ DialogDescription,
19
+ DialogFooter,
20
+ DialogHeader,
21
+ DialogTitle,
22
+ DialogTrigger,
23
+ } from './dialog'
24
+
25
+ function DialogResponsive({ children, ...props }: React.ComponentPropsWithoutRef<typeof Dialog>): React.JSX.Element {
26
+ const isDesktop = useMediaQuery('(min-width: 768px)')
27
+
28
+ if (isDesktop) {
29
+ return <Dialog {...props}>{children}</Dialog>
30
+ }
31
+
32
+ return <Drawer {...props}>{children}</Drawer>
33
+ }
34
+
35
+ function DialogTriggerResponsive({
36
+ children,
37
+ ...props
38
+ }: React.ComponentPropsWithoutRef<typeof DialogTrigger> &
39
+ React.ComponentPropsWithoutRef<typeof DrawerTrigger>): React.JSX.Element {
40
+ const isDesktop = useMediaQuery('(min-width: 768px)')
41
+
42
+ if (isDesktop) {
43
+ return <DialogTrigger {...props}>{children}</DialogTrigger>
44
+ }
45
+
46
+ return <DrawerTrigger {...props}>{children}</DrawerTrigger>
47
+ }
48
+
49
+ function DialogContentResponsive({
50
+ children,
51
+ ...props
52
+ }: React.ComponentPropsWithoutRef<typeof DialogContent>): React.JSX.Element {
53
+ const isDesktop = useMediaQuery('(min-width: 768px)')
54
+
55
+ if (isDesktop) {
56
+ return <DialogContent {...(props as any)}>{children}</DialogContent>
57
+ }
58
+
59
+ return <DrawerContent {...(props as React.ComponentPropsWithoutRef<typeof DrawerContent>)}>{children}</DrawerContent>
60
+ }
61
+
62
+ function DialogHeaderResponsive({
63
+ children,
64
+ ...props
65
+ }: React.ComponentPropsWithoutRef<typeof DialogHeader>): React.JSX.Element {
66
+ const isDesktop = useMediaQuery('(min-width: 768px)')
67
+
68
+ if (isDesktop) {
69
+ return <DialogHeader {...props}>{children}</DialogHeader>
70
+ }
71
+
72
+ return <DrawerHeader {...props}>{children}</DrawerHeader>
73
+ }
74
+
75
+ function DialogFooterResponsive({
76
+ children,
77
+ ...props
78
+ }: React.ComponentPropsWithoutRef<typeof DialogFooter>): React.JSX.Element {
79
+ const isDesktop = useMediaQuery('(min-width: 768px)')
80
+
81
+ if (isDesktop) {
82
+ return <DialogFooter {...props}>{children}</DialogFooter>
83
+ }
84
+
85
+ return <DrawerFooter {...(props as {})}>{children}</DrawerFooter>
86
+ }
87
+
88
+ function DialogTitleResponsive({
89
+ children,
90
+ ...props
91
+ }: React.ComponentPropsWithoutRef<typeof DialogTitle>): React.JSX.Element {
92
+ const isDesktop = useMediaQuery('(min-width: 768px)')
93
+
94
+ if (isDesktop) {
95
+ return <DialogTitle {...props}>{children}</DialogTitle>
96
+ }
97
+
98
+ return <DrawerTitle {...(props as {})}>{children}</DrawerTitle>
99
+ }
100
+
101
+ function DialogDescriptionResponsive({
102
+ children,
103
+ ...props
104
+ }: React.ComponentPropsWithoutRef<typeof DialogDescription>): React.JSX.Element {
105
+ const isDesktop = useMediaQuery('(min-width: 768px)')
106
+
107
+ if (isDesktop) {
108
+ return <DialogDescription {...props}>{children}</DialogDescription>
109
+ }
110
+
111
+ return <DrawerDescription {...(props as {})}>{children}</DrawerDescription>
112
+ }
113
+
114
+ function DialogCloseResponsive({
115
+ children,
116
+ ...props
117
+ }: React.ComponentPropsWithoutRef<typeof DialogClose> &
118
+ React.ComponentPropsWithoutRef<typeof DrawerClose>): React.JSX.Element {
119
+ const isDesktop = useMediaQuery('(min-width: 768px)')
120
+
121
+ if (isDesktop) {
122
+ return <DialogClose {...props}>{children}</DialogClose>
123
+ }
124
+
125
+ return <DrawerClose {...props}>{children}</DrawerClose>
126
+ }
127
+
128
+ export {
129
+ DialogResponsive,
130
+ DialogTriggerResponsive,
131
+ DialogContentResponsive,
132
+ DialogHeaderResponsive,
133
+ DialogFooterResponsive,
134
+ DialogTitleResponsive,
135
+ DialogDescriptionResponsive,
136
+ DialogCloseResponsive,
137
+ }
@@ -0,0 +1,97 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@gentleduck/libs/cn'
4
+ import * as DialogPrimitive from '@gentleduck/primitives/dialog'
5
+ import { X } from 'lucide-react'
6
+ import * as React from 'react'
7
+
8
+ const Dialog = DialogPrimitive.Root
9
+
10
+ const DialogTrigger = DialogPrimitive.Trigger
11
+
12
+ const DialogPortal = DialogPrimitive.Portal
13
+
14
+ const DialogClose = DialogPrimitive.Close
15
+
16
+ const DialogOverlay = React.forwardRef<
17
+ React.ComponentRef<typeof DialogPrimitive.Overlay>,
18
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
19
+ >(({ className, ...props }, ref) => (
20
+ <DialogPrimitive.Overlay
21
+ ref={ref}
22
+ className={cn(
23
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=open]:animate-in',
24
+ 'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
25
+ className,
26
+ )}
27
+ {...props}
28
+ />
29
+ ))
30
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31
+
32
+ const DialogContent = React.forwardRef<
33
+ React.ComponentRef<typeof DialogPrimitive.Content>,
34
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { closeText?: string }
35
+ >(({ className, children, closeText = 'Close', ...props }, ref) => (
36
+ <DialogPortal>
37
+ <DialogOverlay />
38
+ <DialogPrimitive.Content
39
+ ref={ref}
40
+ className={cn(
41
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-1/2 left-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg',
42
+ 'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
43
+ className,
44
+ )}
45
+ {...props}>
46
+ {children}
47
+ <DialogPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
48
+ <X aria-hidden="true" className="h-4 w-4" />
49
+ <span className="sr-only">{closeText}</span>
50
+ </DialogPrimitive.Close>
51
+ </DialogPrimitive.Content>
52
+ </DialogPortal>
53
+ ))
54
+ DialogContent.displayName = DialogPrimitive.Content.displayName
55
+
56
+ const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
57
+ <div className={cn('flex flex-col space-y-1.5 text-center sm:text-start', className)} {...props} />
58
+ )
59
+ DialogHeader.displayName = 'DialogHeader'
60
+
61
+ const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
62
+ <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)} {...props} />
63
+ )
64
+ DialogFooter.displayName = 'DialogFooter'
65
+
66
+ const DialogTitle = React.forwardRef<
67
+ React.ComponentRef<typeof DialogPrimitive.Title>,
68
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
69
+ >(({ className, ...props }, ref) => (
70
+ <DialogPrimitive.Title
71
+ ref={ref}
72
+ className={cn('font-semibold text-lg leading-none tracking-tight', className)}
73
+ {...props}
74
+ />
75
+ ))
76
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
77
+
78
+ const DialogDescription = React.forwardRef<
79
+ React.ComponentRef<typeof DialogPrimitive.Description>,
80
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
81
+ >(({ className, ...props }, ref) => (
82
+ <DialogPrimitive.Description ref={ref} className={cn('text-muted-foreground text-sm', className)} {...props} />
83
+ ))
84
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
85
+
86
+ export {
87
+ Dialog,
88
+ DialogPortal,
89
+ DialogOverlay,
90
+ DialogTrigger,
91
+ DialogClose,
92
+ DialogContent,
93
+ DialogHeader,
94
+ DialogFooter,
95
+ DialogTitle,
96
+ DialogDescription,
97
+ }
@@ -0,0 +1,2 @@
1
+ export * from './dialog'
2
+ export * from './dialog-responsive'
@@ -0,0 +1,13 @@
1
+ 'use client'
2
+
3
+ import {
4
+ DIRECTION_DICTIONARY,
5
+ type Direction,
6
+ DirectionContext,
7
+ DirectionProvider,
8
+ type DirectionProviderProps,
9
+ Provider,
10
+ useDirection,
11
+ } from '@gentleduck/primitives/direction'
12
+ export type { Direction, DirectionProviderProps }
13
+ export { useDirection, Provider, DirectionProvider, DirectionContext, DIRECTION_DICTIONARY }
@@ -0,0 +1 @@
1
+ export * from './direction'
@@ -0,0 +1,185 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@gentleduck/libs/cn'
4
+ import { type Direction, useDirection } from '@gentleduck/primitives/direction'
5
+ import * as React from 'react'
6
+ import { Drawer as DrawerPrimitive } from 'vaul'
7
+
8
+ type DrawerProps = React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Root> & {
9
+ dir?: Direction
10
+ }
11
+
12
+ function resolveDrawerDirection(
13
+ direction: NonNullable<React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Root>['direction']>,
14
+ dir: Direction,
15
+ ) {
16
+ if (dir !== 'rtl') return direction
17
+ if (direction === 'left') return 'right'
18
+ if (direction === 'right') return 'left'
19
+ return direction
20
+ }
21
+
22
+ function Drawer({ direction: drawerDirection = 'bottom', shouldScaleBackground = true, dir, ...props }: DrawerProps) {
23
+ const direction = useDirection(dir)
24
+ const resolvedDirection = resolveDrawerDirection(drawerDirection, direction)
25
+
26
+ return (
27
+ <DrawerPrimitive.Root
28
+ data-slot="drawer"
29
+ direction={resolvedDirection}
30
+ shouldScaleBackground={shouldScaleBackground}
31
+ {...props}
32
+ />
33
+ )
34
+ }
35
+ Drawer.displayName = 'Drawer'
36
+
37
+ const DrawerTrigger: React.ForwardRefExoticComponent<
38
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Trigger> &
39
+ React.RefAttributes<React.ComponentRef<typeof DrawerPrimitive.Trigger>>
40
+ > = React.forwardRef((props, ref) => <DrawerPrimitive.Trigger ref={ref} {...props} data-slot="drawer-trigger" />)
41
+ DrawerTrigger.displayName = 'DrawerTrigger'
42
+
43
+ const DrawerPortal: React.FC<React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Portal>> = (props) => (
44
+ <DrawerPrimitive.Portal {...props} data-slot="drawer-portal" />
45
+ )
46
+ DrawerPortal.displayName = 'DrawerPortal'
47
+
48
+ const DrawerClose: React.ForwardRefExoticComponent<
49
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Close> &
50
+ React.RefAttributes<React.ComponentRef<typeof DrawerPrimitive.Close>>
51
+ > = React.forwardRef((props, ref) => <DrawerPrimitive.Close ref={ref} {...props} data-slot="drawer-close" />)
52
+ DrawerClose.displayName = 'DrawerClose'
53
+
54
+ const DrawerOverlay: React.ForwardRefExoticComponent<
55
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay> &
56
+ React.RefAttributes<React.ComponentRef<typeof DrawerPrimitive.Overlay>>
57
+ > = React.forwardRef(({ className, ...props }, ref) => (
58
+ <DrawerPrimitive.Overlay
59
+ ref={ref}
60
+ className={cn('fixed inset-0 bg-black/80', className)}
61
+ {...props}
62
+ data-slot="drawer-overlay"
63
+ />
64
+ ))
65
+ DrawerOverlay.displayName = 'DrawerOverlay'
66
+
67
+ type DrawerContentProps = React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content> & {
68
+ dir?: Direction
69
+ overlayProps?: React.ComponentPropsWithoutRef<typeof DrawerOverlay>
70
+ }
71
+
72
+ const DrawerContent: React.ForwardRefExoticComponent<
73
+ DrawerContentProps & React.RefAttributes<React.ComponentRef<typeof DrawerPrimitive.Content>>
74
+ > = React.forwardRef(({ className, children, dir, overlayProps, ...props }, ref) => {
75
+ const direction = useDirection(dir)
76
+
77
+ return (
78
+ <DrawerPortal>
79
+ <DrawerOverlay {...overlayProps} />
80
+ <DrawerPrimitive.Content
81
+ ref={ref}
82
+ dir={direction}
83
+ data-slot="drawer-content"
84
+ className={cn(
85
+ 'group/drawer-content fixed z-50 flex h-auto flex-col bg-background',
86
+
87
+ // top
88
+ 'data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b',
89
+
90
+ // bottom
91
+ 'data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t',
92
+
93
+ // right
94
+ 'data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm',
95
+
96
+ // left
97
+ 'data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm',
98
+
99
+ className,
100
+ )}
101
+ {...props}>
102
+ <div className="mx-auto mt-4 hidden h-2 w-25 shrink-0 rounded-full bg-muted group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
103
+ {children}
104
+ </DrawerPrimitive.Content>
105
+ </DrawerPortal>
106
+ )
107
+ })
108
+ DrawerContent.displayName = 'DrawerContent'
109
+
110
+ const DrawerHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
111
+ ({ className, ...props }, ref) => (
112
+ <div
113
+ ref={ref}
114
+ className={cn('grid gap-1.5 p-4 **:text-center sm:**:text-start', className)}
115
+ {...props}
116
+ data-slot="drawer-header"
117
+ />
118
+ ),
119
+ )
120
+ DrawerHeader.displayName = 'DrawerHeader'
121
+
122
+ const DrawerFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & { dir?: Direction }>(
123
+ ({ className, dir, ...props }, ref) => {
124
+ const direction = useDirection(dir)
125
+ return (
126
+ <div
127
+ ref={ref}
128
+ dir={direction}
129
+ className={cn('mt-auto flex flex-col gap-2 p-4', className)}
130
+ {...props}
131
+ data-slot="drawer-footer"
132
+ />
133
+ )
134
+ },
135
+ )
136
+ DrawerFooter.displayName = 'DrawerFooter'
137
+
138
+ const DrawerTitle: React.ForwardRefExoticComponent<
139
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title> & { dir?: Direction } & React.RefAttributes<
140
+ React.ComponentRef<typeof DrawerPrimitive.Title>
141
+ >
142
+ > = React.forwardRef(({ className, dir, ...props }, ref) => {
143
+ const direction = useDirection(dir)
144
+ return (
145
+ <DrawerPrimitive.Title
146
+ ref={ref}
147
+ dir={direction}
148
+ className={cn('font-semibold text-lg leading-none tracking-tight', className)}
149
+ data-slot="drawer-title"
150
+ {...props}
151
+ />
152
+ )
153
+ })
154
+ DrawerTitle.displayName = 'DrawerTitle'
155
+
156
+ const DrawerDescription: React.ForwardRefExoticComponent<
157
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description> & { dir?: Direction } & React.RefAttributes<
158
+ React.ComponentRef<typeof DrawerPrimitive.Description>
159
+ >
160
+ > = React.forwardRef(({ className, dir, ...props }, ref) => {
161
+ const direction = useDirection(dir)
162
+ return (
163
+ <DrawerPrimitive.Description
164
+ ref={ref}
165
+ dir={direction}
166
+ className={cn('text-muted-foreground text-sm', className)}
167
+ data-slot="drawer-description"
168
+ {...props}
169
+ />
170
+ )
171
+ })
172
+ DrawerDescription.displayName = 'DrawerDescription'
173
+
174
+ export {
175
+ Drawer,
176
+ DrawerPortal,
177
+ DrawerOverlay,
178
+ DrawerTrigger,
179
+ DrawerClose,
180
+ DrawerContent,
181
+ DrawerHeader,
182
+ DrawerFooter,
183
+ DrawerTitle,
184
+ DrawerDescription,
185
+ }
@@ -0,0 +1 @@
1
+ export * from './drawer'