@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.
- package/CHANGELOG.md +62 -0
- package/index.css +3 -0
- package/package.json +59 -0
- package/src/_old/_table/index.ts +5 -0
- package/src/_old/_table/table-advanced.constants.tsx +24 -0
- package/src/_old/_table/table-advanced.tsx +311 -0
- package/src/_old/_table/table-advanced.types.ts +272 -0
- package/src/_old/_table/table.constants.ts +2 -0
- package/src/_old/_table/table.hook.tsx +115 -0
- package/src/_old/_table/table.lib.ts +85 -0
- package/src/_old/_table/table.tsx +916 -0
- package/src/_old/_table/table.types.ts +118 -0
- package/src/_old/_table/todo.md +11 -0
- package/src/_old/_upload/index.ts +9 -0
- package/src/_old/_upload/todo.md +38 -0
- package/src/_old/_upload/upload-advanced-chunks.tsx +1624 -0
- package/src/_old/_upload/upload-advanced.tsx +507 -0
- package/src/_old/_upload/upload-sonner.tsx +58 -0
- package/src/_old/_upload/upload.assets.tsx +239 -0
- package/src/_old/_upload/upload.constants.tsx +75 -0
- package/src/_old/_upload/upload.dto.ts +19 -0
- package/src/_old/_upload/upload.lib.tsx +630 -0
- package/src/_old/_upload/upload.tsx +491 -0
- package/src/_old/_upload/upload.types.ts +436 -0
- package/src/accordion/accordion.tsx +247 -0
- package/src/accordion/index.ts +1 -0
- package/src/alert/alert.constants.ts +17 -0
- package/src/alert/alert.tsx +52 -0
- package/src/alert/index.ts +2 -0
- package/src/alert-dialog/alert-dialog.tsx +107 -0
- package/src/alert-dialog/index.ts +1 -0
- package/src/aspect-ratio/aspect-ratio.tsx +33 -0
- package/src/aspect-ratio/index.ts +1 -0
- package/src/audio/audio-record.tsx +776 -0
- package/src/audio/audio-visualizer.tsx +377 -0
- package/src/audio/audio.libs.ts +5 -0
- package/src/audio/audio.types.ts +50 -0
- package/src/audio/index.ts +2 -0
- package/src/avatar/avatar.tsx +78 -0
- package/src/avatar/index.ts +1 -0
- package/src/badge/badge.constants.ts +38 -0
- package/src/badge/badge.tsx +19 -0
- package/src/badge/index.ts +2 -0
- package/src/breadcrumb/breadcrumb.tsx +119 -0
- package/src/breadcrumb/index.ts +1 -0
- package/src/button/button.constants.ts +44 -0
- package/src/button/button.tsx +79 -0
- package/src/button/button.types.ts +38 -0
- package/src/button/index.ts +3 -0
- package/src/button-group/button-group.constants.ts +26 -0
- package/src/button-group/button-group.tsx +65 -0
- package/src/button-group/index.ts +2 -0
- package/src/calendar/calendar.tsx +191 -0
- package/src/calendar/index.ts +1 -0
- package/src/card/card.tsx +81 -0
- package/src/card/index.ts +1 -0
- package/src/carousel/carousel.tsx +211 -0
- package/src/carousel/carousel.types.ts +23 -0
- package/src/carousel/index.ts +2 -0
- package/src/chart/chart.libs.ts +27 -0
- package/src/chart/chart.tsx +260 -0
- package/src/chart/chart.types.ts +38 -0
- package/src/chart/index.ts +3 -0
- package/src/checkbox/checkbox.tsx +144 -0
- package/src/checkbox/checkbox.types.ts +24 -0
- package/src/checkbox/index.ts +2 -0
- package/src/collapsible/collapsible.tsx +151 -0
- package/src/collapsible/index.ts +1 -0
- package/src/combobox/combobox.tsx +132 -0
- package/src/combobox/index.ts +1 -0
- package/src/command/command.tsx +192 -0
- package/src/command/command.types.ts +11 -0
- package/src/command/index.ts +2 -0
- package/src/context-menu/context-menu.tsx +178 -0
- package/src/context-menu/index.ts +1 -0
- package/src/dialog/dialog-responsive.tsx +137 -0
- package/src/dialog/dialog.tsx +97 -0
- package/src/dialog/index.ts +2 -0
- package/src/direction/direction.tsx +13 -0
- package/src/direction/index.ts +1 -0
- package/src/drawer/drawer.tsx +185 -0
- package/src/drawer/index.ts +1 -0
- package/src/dropdown-menu/dropdown-menu.tsx +181 -0
- package/src/dropdown-menu/index.ts +1 -0
- package/src/empty/empty.constants.ts +15 -0
- package/src/empty/empty.tsx +73 -0
- package/src/empty/index.ts +2 -0
- package/src/field/field.constants.ts +22 -0
- package/src/field/field.tsx +203 -0
- package/src/field/index.ts +2 -0
- package/src/hover-card/hover-card.tsx +79 -0
- package/src/hover-card/index.ts +1 -0
- package/src/input/index.ts +1 -0
- package/src/input/input.tsx +45 -0
- package/src/input-group/index.ts +1 -0
- package/src/input-group/input-group.tsx +170 -0
- package/src/input-otp/index.ts +1 -0
- package/src/input-otp/input-otp.tsx +66 -0
- package/src/item/index.ts +2 -0
- package/src/item/item.constants.ts +22 -0
- package/src/item/item.tsx +185 -0
- package/src/json-editor/index.ts +4 -0
- package/src/json-editor/json-editor.hooks.ts +21 -0
- package/src/json-editor/json-editor.libs.ts +34 -0
- package/src/json-editor/json-editor.tsx +425 -0
- package/src/json-editor/json-editor.types.ts +80 -0
- package/src/json-editor/json-editor.view.tsx +110 -0
- package/src/json-editor/json-text-area.tsx +7 -0
- package/src/kbd/index.ts +1 -0
- package/src/kbd/kbd.tsx +39 -0
- package/src/label/index.ts +1 -0
- package/src/label/label.tsx +28 -0
- package/src/menubar/index.ts +1 -0
- package/src/menubar/menubar.tsx +213 -0
- package/src/navigation-menu/index.ts +1 -0
- package/src/navigation-menu/navigation-menu.tsx +152 -0
- package/src/pagination/index.ts +2 -0
- package/src/pagination/pagination.tsx +191 -0
- package/src/pagination/pagination.types.ts +17 -0
- package/src/popover/index.ts +1 -0
- package/src/popover/popover.tsx +35 -0
- package/src/preview-panel/index.ts +3 -0
- package/src/preview-panel/preview-panel-dialog.tsx +99 -0
- package/src/preview-panel/preview-panel.tsx +389 -0
- package/src/preview-panel/preview-panel.types.ts +49 -0
- package/src/progress/index.ts +1 -0
- package/src/progress/progress.tsx +32 -0
- package/src/radio-group/index.ts +1 -0
- package/src/radio-group/radio-group.tsx +92 -0
- package/src/resizable/index.ts +1 -0
- package/src/resizable/resizable.tsx +52 -0
- package/src/scroll-area/index.ts +1 -0
- package/src/scroll-area/scroll-area.tsx +30 -0
- package/src/select/index.ts +1 -0
- package/src/select/select.tsx +138 -0
- package/src/separator/index.ts +1 -0
- package/src/separator/separator.tsx +28 -0
- package/src/sheet/index.ts +2 -0
- package/src/sheet/sheet.constants.tsx +20 -0
- package/src/sheet/sheet.tsx +92 -0
- package/src/sidebar/index.ts +4 -0
- package/src/sidebar/sidebar.constants.ts +30 -0
- package/src/sidebar/sidebar.hooks.ts +13 -0
- package/src/sidebar/sidebar.tsx +676 -0
- package/src/sidebar/sidebar.types.ts +28 -0
- package/src/skeleton/index.ts +1 -0
- package/src/skeleton/skeleton.tsx +22 -0
- package/src/slider/index.ts +1 -0
- package/src/slider/slider.tsx +57 -0
- package/src/sonner/index.ts +4 -0
- package/src/sonner/sonner.chunks.tsx +80 -0
- package/src/sonner/sonner.libs.ts +13 -0
- package/src/sonner/sonner.tsx +31 -0
- package/src/sonner/sonner.types.ts +9 -0
- package/src/switch/index.ts +1 -0
- package/src/switch/switch.tsx +63 -0
- package/src/table/index.ts +1 -0
- package/src/table/table.tsx +95 -0
- package/src/tabs/index.ts +1 -0
- package/src/tabs/tabs.tsx +151 -0
- package/src/textarea/index.ts +1 -0
- package/src/textarea/textarea.tsx +24 -0
- package/src/toggle/index.ts +2 -0
- package/src/toggle/toggle.constants.ts +22 -0
- package/src/toggle/toggle.tsx +24 -0
- package/src/toggle-group/index.ts +1 -0
- package/src/toggle-group/toggle-group.tsx +69 -0
- package/src/tooltip/index.ts +1 -0
- package/src/tooltip/tooltip.tsx +32 -0
- package/src/upload/index.ts +1 -0
- package/src/upload/upload.constants.tsx +19 -0
- package/src/upload/upload.libs.ts +97 -0
- package/src/upload/upload.tsx +340 -0
- package/src/upload/upload.types.ts +44 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@gentleduck/libs/cn'
|
|
4
|
+
import * as DropdownMenuPrimitive from '@gentleduck/primitives/dropdown-menu'
|
|
5
|
+
import { Check, ChevronRight, Circle } from 'lucide-react'
|
|
6
|
+
import * as React from 'react'
|
|
7
|
+
|
|
8
|
+
const DropdownMenu = DropdownMenuPrimitive.Root
|
|
9
|
+
|
|
10
|
+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
|
11
|
+
|
|
12
|
+
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
|
13
|
+
|
|
14
|
+
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
|
15
|
+
|
|
16
|
+
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
|
17
|
+
|
|
18
|
+
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
|
19
|
+
|
|
20
|
+
const DropdownMenuSubTrigger = React.forwardRef<
|
|
21
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
22
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
23
|
+
inset?: boolean
|
|
24
|
+
}
|
|
25
|
+
>(({ className, inset, children, ...props }, ref) => (
|
|
26
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={cn(
|
|
29
|
+
'flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
|
30
|
+
inset && 'ps-8',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}>
|
|
34
|
+
{children}
|
|
35
|
+
<ChevronRight aria-hidden="true" className="ms-auto rtl:rotate-180" />
|
|
36
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
37
|
+
))
|
|
38
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName
|
|
39
|
+
|
|
40
|
+
const DropdownMenuSubContent = React.forwardRef<
|
|
41
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,
|
|
42
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
|
43
|
+
>(({ className, ...props }, ref) => (
|
|
44
|
+
<DropdownMenuPrimitive.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-dropdown-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
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName
|
|
55
|
+
|
|
56
|
+
const DropdownMenuContent = React.forwardRef<
|
|
57
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.Content>,
|
|
58
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
|
59
|
+
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
60
|
+
<DropdownMenuPrimitive.Portal>
|
|
61
|
+
<DropdownMenuPrimitive.Content
|
|
62
|
+
ref={ref}
|
|
63
|
+
sideOffset={sideOffset}
|
|
64
|
+
className={cn(
|
|
65
|
+
'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-dropdown-menu-content-available-height) min-w-32 origin-(--gentleduck-dropdown-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',
|
|
66
|
+
'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
</DropdownMenuPrimitive.Portal>
|
|
72
|
+
))
|
|
73
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
|
74
|
+
|
|
75
|
+
const DropdownMenuItem = React.forwardRef<
|
|
76
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.Item>,
|
|
77
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
|
78
|
+
inset?: boolean
|
|
79
|
+
variant?: 'default' | 'destructive'
|
|
80
|
+
}
|
|
81
|
+
>(({ className, inset, variant = 'default', ...props }, ref) => (
|
|
82
|
+
<DropdownMenuPrimitive.Item
|
|
83
|
+
ref={ref}
|
|
84
|
+
className={cn(
|
|
85
|
+
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
86
|
+
inset && 'ps-8',
|
|
87
|
+
variant === 'destructive' && 'text-destructive focus:text-destructive',
|
|
88
|
+
className,
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
))
|
|
93
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
|
94
|
+
|
|
95
|
+
const DropdownMenuCheckboxItem = React.forwardRef<
|
|
96
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
|
97
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
|
98
|
+
>(({ className, children, checked, ...props }, ref) => (
|
|
99
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
100
|
+
ref={ref}
|
|
101
|
+
className={cn(
|
|
102
|
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
|
|
103
|
+
className,
|
|
104
|
+
)}
|
|
105
|
+
checked={checked}
|
|
106
|
+
{...props}>
|
|
107
|
+
<span className="absolute start-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
108
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
109
|
+
<Check aria-hidden="true" className="h-4 w-4" />
|
|
110
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
111
|
+
</span>
|
|
112
|
+
{children}
|
|
113
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
114
|
+
))
|
|
115
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName
|
|
116
|
+
|
|
117
|
+
const DropdownMenuRadioItem = React.forwardRef<
|
|
118
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,
|
|
119
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
|
120
|
+
>(({ className, children, ...props }, ref) => (
|
|
121
|
+
<DropdownMenuPrimitive.RadioItem
|
|
122
|
+
ref={ref}
|
|
123
|
+
className={cn(
|
|
124
|
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
|
|
125
|
+
className,
|
|
126
|
+
)}
|
|
127
|
+
{...props}>
|
|
128
|
+
<span className="absolute start-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
129
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
130
|
+
<Circle aria-hidden="true" className="h-2 w-2 fill-current" />
|
|
131
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
132
|
+
</span>
|
|
133
|
+
{children}
|
|
134
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
135
|
+
))
|
|
136
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
|
137
|
+
|
|
138
|
+
const DropdownMenuLabel = React.forwardRef<
|
|
139
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.Label>,
|
|
140
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
|
141
|
+
inset?: boolean
|
|
142
|
+
}
|
|
143
|
+
>(({ className, inset, ...props }, ref) => (
|
|
144
|
+
<DropdownMenuPrimitive.Label
|
|
145
|
+
ref={ref}
|
|
146
|
+
className={cn('px-2 py-1.5 font-semibold text-sm', inset && 'ps-8', className)}
|
|
147
|
+
{...props}
|
|
148
|
+
/>
|
|
149
|
+
))
|
|
150
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
|
151
|
+
|
|
152
|
+
const DropdownMenuSeparator = React.forwardRef<
|
|
153
|
+
React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,
|
|
154
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
|
155
|
+
>(({ className, ...props }, ref) => (
|
|
156
|
+
<DropdownMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-muted', className)} {...props} />
|
|
157
|
+
))
|
|
158
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
|
159
|
+
|
|
160
|
+
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
|
161
|
+
return <span className={cn('ms-auto text-xs tracking-widest opacity-60', className)} {...props} />
|
|
162
|
+
}
|
|
163
|
+
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
|
|
164
|
+
|
|
165
|
+
export {
|
|
166
|
+
DropdownMenu,
|
|
167
|
+
DropdownMenuTrigger,
|
|
168
|
+
DropdownMenuContent,
|
|
169
|
+
DropdownMenuItem,
|
|
170
|
+
DropdownMenuCheckboxItem,
|
|
171
|
+
DropdownMenuRadioItem,
|
|
172
|
+
DropdownMenuLabel,
|
|
173
|
+
DropdownMenuSeparator,
|
|
174
|
+
DropdownMenuShortcut,
|
|
175
|
+
DropdownMenuGroup,
|
|
176
|
+
DropdownMenuPortal,
|
|
177
|
+
DropdownMenuSub,
|
|
178
|
+
DropdownMenuSubContent,
|
|
179
|
+
DropdownMenuSubTrigger,
|
|
180
|
+
DropdownMenuRadioGroup,
|
|
181
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dropdown-menu'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cva } from '@gentleduck/variants'
|
|
2
|
+
export const emptyMediaVariants = cva(
|
|
3
|
+
'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
4
|
+
{
|
|
5
|
+
defaultVariants: {
|
|
6
|
+
variant: 'default',
|
|
7
|
+
},
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: 'bg-transparent',
|
|
11
|
+
icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { cn } from '@gentleduck/libs/cn'
|
|
2
|
+
import { type Direction, useDirection } from '@gentleduck/primitives/direction'
|
|
3
|
+
import type { VariantProps } from '@gentleduck/variants'
|
|
4
|
+
import { emptyMediaVariants } from './empty.constants'
|
|
5
|
+
|
|
6
|
+
function Empty({ className, dir, ...props }: React.ComponentProps<'div'>) {
|
|
7
|
+
const direction = useDirection(dir as Direction)
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className={cn(
|
|
11
|
+
'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12',
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
dir={direction}
|
|
15
|
+
data-slot="empty"
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={cn('flex max-w-sm flex-col items-center gap-2 text-center', className)}
|
|
25
|
+
data-slot="empty-header"
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function EmptyMedia({
|
|
32
|
+
className,
|
|
33
|
+
variant = 'default',
|
|
34
|
+
...props
|
|
35
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
className={cn(emptyMediaVariants({ className, variant }))}
|
|
39
|
+
data-slot="empty-icon"
|
|
40
|
+
data-variant={variant}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
47
|
+
return <div className={cn('font-medium text-lg tracking-tight', className)} data-slot="empty-title" {...props} />
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
className={cn(
|
|
54
|
+
'text-muted-foreground text-sm/relaxed [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
data-slot="empty-description"
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
className={cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm', className)}
|
|
67
|
+
data-slot="empty-content"
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cva } from '@gentleduck/variants'
|
|
2
|
+
|
|
3
|
+
export const fieldVariants = cva('group/field flex w-full gap-3 data-[invalid=true]:text-destructive', {
|
|
4
|
+
defaultVariants: {
|
|
5
|
+
orientation: 'vertical',
|
|
6
|
+
},
|
|
7
|
+
variants: {
|
|
8
|
+
orientation: {
|
|
9
|
+
horizontal: [
|
|
10
|
+
'flex-row items-center',
|
|
11
|
+
'[&>[data-slot=field-label]]:flex-auto',
|
|
12
|
+
'has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
13
|
+
],
|
|
14
|
+
responsive: [
|
|
15
|
+
'@md/field-group:flex-row flex-col @md/field-group:items-center @md/field-group:[&>*]:w-auto [&>*]:w-full [&>.sr-only]:w-auto',
|
|
16
|
+
'@md/field-group:[&>[data-slot=field-label]]:flex-auto',
|
|
17
|
+
'@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
18
|
+
],
|
|
19
|
+
vertical: ['flex-col [&>*]:w-full [&>.sr-only]:w-auto'],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
})
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@gentleduck/libs/cn'
|
|
4
|
+
import { type Direction, useDirection } from '@gentleduck/primitives/direction'
|
|
5
|
+
import type { VariantProps } from '@gentleduck/variants'
|
|
6
|
+
import { useMemo } from 'react'
|
|
7
|
+
import { Label } from '../label'
|
|
8
|
+
import { Separator } from '../separator'
|
|
9
|
+
import { fieldVariants } from './field.constants'
|
|
10
|
+
|
|
11
|
+
function FieldSet({ className, dir, ...props }: React.ComponentProps<'fieldset'>) {
|
|
12
|
+
const direction = useDirection(dir as Direction)
|
|
13
|
+
return (
|
|
14
|
+
<fieldset
|
|
15
|
+
className={cn(
|
|
16
|
+
'flex flex-col gap-6',
|
|
17
|
+
'has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
dir={direction}
|
|
21
|
+
data-slot="field-set"
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function FieldLegend({
|
|
28
|
+
className,
|
|
29
|
+
variant = 'legend',
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {
|
|
32
|
+
return (
|
|
33
|
+
<legend
|
|
34
|
+
className={cn('mb-3 font-medium', 'data-[variant=legend]:text-base', 'data-[variant=label]:text-sm', className)}
|
|
35
|
+
data-slot="field-legend"
|
|
36
|
+
data-variant={variant}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
43
|
+
return (
|
|
44
|
+
<div
|
|
45
|
+
className={cn(
|
|
46
|
+
'group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',
|
|
47
|
+
className,
|
|
48
|
+
)}
|
|
49
|
+
data-slot="field-group"
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function Field({
|
|
56
|
+
className,
|
|
57
|
+
orientation = 'vertical',
|
|
58
|
+
...props
|
|
59
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof fieldVariants>) {
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
className={cn(fieldVariants({ orientation }), className)}
|
|
63
|
+
data-orientation={orientation}
|
|
64
|
+
data-slot="field"
|
|
65
|
+
role="group"
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function FieldContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
className={cn('group/field-content flex flex-1 flex-col gap-1.5 leading-snug', className)}
|
|
75
|
+
data-slot="field-content"
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
|
|
82
|
+
return (
|
|
83
|
+
<Label
|
|
84
|
+
className={cn(
|
|
85
|
+
'group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50',
|
|
86
|
+
'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4',
|
|
87
|
+
'has-data-[state=checked]:border-primary has-data-[state=checked]:bg-primary/5 dark:has-data-[state=checked]:bg-primary/10',
|
|
88
|
+
className,
|
|
89
|
+
)}
|
|
90
|
+
data-slot="field-label"
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
className={cn(
|
|
100
|
+
'flex w-fit items-center gap-2 font-medium text-sm leading-snug group-data-[disabled=true]/field:opacity-50',
|
|
101
|
+
className,
|
|
102
|
+
)}
|
|
103
|
+
data-slot="field-label"
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function FieldDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
110
|
+
return (
|
|
111
|
+
<p
|
|
112
|
+
className={cn(
|
|
113
|
+
'font-normal text-muted-foreground text-sm leading-normal group-has-[[data-orientation=horizontal]]/field:text-balance',
|
|
114
|
+
'nth-last-2:-mt-1 last:mt-0 [[data-variant=legend]+&]:-mt-1.5',
|
|
115
|
+
'[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
118
|
+
data-slot="field-description"
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function FieldSeparator({
|
|
125
|
+
children,
|
|
126
|
+
className,
|
|
127
|
+
...props
|
|
128
|
+
}: React.ComponentProps<'div'> & {
|
|
129
|
+
children?: React.ReactNode
|
|
130
|
+
}) {
|
|
131
|
+
return (
|
|
132
|
+
<div
|
|
133
|
+
className={cn('relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2', className)}
|
|
134
|
+
data-content={!!children}
|
|
135
|
+
data-slot="field-separator"
|
|
136
|
+
{...props}>
|
|
137
|
+
<Separator className="absolute inset-0 top-1/2" />
|
|
138
|
+
{children && (
|
|
139
|
+
<span
|
|
140
|
+
className="relative mx-auto block w-fit bg-background px-2 text-muted-foreground"
|
|
141
|
+
data-slot="field-separator-content">
|
|
142
|
+
{children}
|
|
143
|
+
</span>
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function FieldError({
|
|
150
|
+
className,
|
|
151
|
+
children,
|
|
152
|
+
errors,
|
|
153
|
+
...props
|
|
154
|
+
}: React.ComponentProps<'div'> & {
|
|
155
|
+
errors?: Array<{ message?: string } | undefined>
|
|
156
|
+
}) {
|
|
157
|
+
const content = useMemo(() => {
|
|
158
|
+
if (children) {
|
|
159
|
+
return children
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!errors) {
|
|
163
|
+
return null
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (errors?.length === 1 && errors[0]?.message) {
|
|
167
|
+
return errors[0].message
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<ul className="ms-4 flex list-disc flex-col gap-1">
|
|
172
|
+
{errors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
|
|
173
|
+
</ul>
|
|
174
|
+
)
|
|
175
|
+
}, [children, errors])
|
|
176
|
+
|
|
177
|
+
if (!content) {
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div
|
|
183
|
+
className={cn('font-normal text-destructive text-sm', className)}
|
|
184
|
+
data-slot="field-error"
|
|
185
|
+
role="alert"
|
|
186
|
+
{...props}>
|
|
187
|
+
{content}
|
|
188
|
+
</div>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export {
|
|
193
|
+
Field,
|
|
194
|
+
FieldLabel,
|
|
195
|
+
FieldDescription,
|
|
196
|
+
FieldError,
|
|
197
|
+
FieldGroup,
|
|
198
|
+
FieldLegend,
|
|
199
|
+
FieldSeparator,
|
|
200
|
+
FieldSet,
|
|
201
|
+
FieldContent,
|
|
202
|
+
FieldTitle,
|
|
203
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@gentleduck/libs/cn'
|
|
4
|
+
import * as HoverCardPrimitive from '@gentleduck/primitives/hover-card'
|
|
5
|
+
import type { VariantProps } from '@gentleduck/variants'
|
|
6
|
+
import * as React from 'react'
|
|
7
|
+
import { buttonVariants } from '../button'
|
|
8
|
+
|
|
9
|
+
const HoverCardPlacementContext =
|
|
10
|
+
React.createContext<React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>['side']>('top')
|
|
11
|
+
|
|
12
|
+
const HoverCard = React.forwardRef<
|
|
13
|
+
React.ComponentRef<typeof HoverCardPrimitive.Root>,
|
|
14
|
+
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root> & {
|
|
15
|
+
delayDuration?: number
|
|
16
|
+
skipDelayDuration?: number
|
|
17
|
+
placement?: React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>['side']
|
|
18
|
+
}
|
|
19
|
+
>(({ closeDelay, openDelay, placement = 'top', delayDuration, skipDelayDuration, ...props }, _ref) => {
|
|
20
|
+
void skipDelayDuration
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<HoverCardPlacementContext.Provider value={placement}>
|
|
24
|
+
<HoverCardPrimitive.Root
|
|
25
|
+
closeDelay={closeDelay}
|
|
26
|
+
data-slot="hover-card"
|
|
27
|
+
openDelay={openDelay ?? delayDuration}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
</HoverCardPlacementContext.Provider>
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
HoverCard.displayName = 'HoverCard'
|
|
34
|
+
|
|
35
|
+
const HoverCardTrigger = React.forwardRef<
|
|
36
|
+
React.ComponentRef<typeof HoverCardPrimitive.Trigger>,
|
|
37
|
+
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger> & VariantProps<typeof buttonVariants>
|
|
38
|
+
>(({ children, className, variant = 'outline', size = 'default', border = 'default', ...props }, ref) => {
|
|
39
|
+
return (
|
|
40
|
+
<HoverCardPrimitive.Trigger
|
|
41
|
+
ref={ref}
|
|
42
|
+
className={cn(buttonVariants({ variant, size, border }), className)}
|
|
43
|
+
data-slot="hover-card-trigger"
|
|
44
|
+
{...props}>
|
|
45
|
+
{children}
|
|
46
|
+
</HoverCardPrimitive.Trigger>
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
HoverCardTrigger.displayName = HoverCardPrimitive.Trigger.displayName
|
|
50
|
+
|
|
51
|
+
const HoverCardContent = React.forwardRef<
|
|
52
|
+
React.ComponentRef<typeof HoverCardPrimitive.Content>,
|
|
53
|
+
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
|
|
54
|
+
>(({ className, children, side, align = 'center', sideOffset = 4, ...props }, ref) => {
|
|
55
|
+
const defaultSide = React.useContext(HoverCardPlacementContext)
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<HoverCardPrimitive.Portal>
|
|
59
|
+
<HoverCardPrimitive.Content
|
|
60
|
+
ref={ref}
|
|
61
|
+
align={align}
|
|
62
|
+
className={cn(
|
|
63
|
+
'z-50 w-64 overflow-hidden rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden',
|
|
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 origin-(--gentleduck-hover-card-content-transform-origin) 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
|
+
data-slot="hover-card-content"
|
|
69
|
+
side={side ?? defaultSide}
|
|
70
|
+
sideOffset={sideOffset}
|
|
71
|
+
{...props}>
|
|
72
|
+
{children}
|
|
73
|
+
</HoverCardPrimitive.Content>
|
|
74
|
+
</HoverCardPrimitive.Portal>
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
|
|
78
|
+
|
|
79
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './hover-card'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './input'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cn } from '@gentleduck/libs/cn'
|
|
2
|
+
import { type Direction, useDirection } from '@gentleduck/primitives/direction'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
|
|
6
|
+
({ className, type, dir, ...props }, ref) => {
|
|
7
|
+
const direction = useDirection(dir as Direction)
|
|
8
|
+
return (
|
|
9
|
+
<input
|
|
10
|
+
dir={direction}
|
|
11
|
+
type={type}
|
|
12
|
+
className={cn(
|
|
13
|
+
// base
|
|
14
|
+
'h-8 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base outline-none transition-colors',
|
|
15
|
+
// file
|
|
16
|
+
'file:inline-flex file:h-6 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm',
|
|
17
|
+
// placeholder
|
|
18
|
+
'placeholder:text-muted-foreground',
|
|
19
|
+
// focus
|
|
20
|
+
'focus-visible:ring-1 focus-visible:ring-ring',
|
|
21
|
+
// disabled
|
|
22
|
+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50',
|
|
23
|
+
// responsive
|
|
24
|
+
'md:text-sm',
|
|
25
|
+
// dark
|
|
26
|
+
// 'dark:bg-input/30 dark:disabled:bg-input/80',
|
|
27
|
+
// aria-invalid
|
|
28
|
+
'aria-invalid:border-destructive aria-invalid:text-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',
|
|
29
|
+
// aria-disabled
|
|
30
|
+
'aria-disabled:pointer-events-none aria-disabled:opacity-50',
|
|
31
|
+
// aria-warning
|
|
32
|
+
'aria-warning:border-warning aria-warning:text-warning aria-warning:ring-warning/20 dark:aria-warning:border-warning/50 dark:aria-warning:ring-warning/40',
|
|
33
|
+
className,
|
|
34
|
+
)}
|
|
35
|
+
ref={ref}
|
|
36
|
+
data-slot="input"
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
Input.displayName = 'Input'
|
|
44
|
+
|
|
45
|
+
export { Input }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './input-group'
|