@leitware/dockets 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.
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +86 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +36 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/registry.d.ts +18 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +712 -0
- package/dist/registry.js.map +1 -0
- package/package.json +40 -0
- package/templates/accordion.tsx +77 -0
- package/templates/alert-dialog.tsx +66 -0
- package/templates/alert.tsx +41 -0
- package/templates/aspect-ratio.tsx +15 -0
- package/templates/avatar.tsx +27 -0
- package/templates/badge.tsx +1 -0
- package/templates/block-loader.tsx +1 -0
- package/templates/breadcrumb.tsx +31 -0
- package/templates/button.tsx +1 -0
- package/templates/calendar.tsx +45 -0
- package/templates/card.tsx +35 -0
- package/templates/carousel.tsx +39 -0
- package/templates/checkbox.tsx +50 -0
- package/templates/code-block.tsx +1 -0
- package/templates/collapsible.tsx +35 -0
- package/templates/combobox.tsx +154 -0
- package/templates/command.tsx +50 -0
- package/templates/contact-footer.tsx +193 -0
- package/templates/context-menu.tsx +16 -0
- package/templates/dialog.tsx +67 -0
- package/templates/drawer.tsx +12 -0
- package/templates/dropdown-menu.tsx +95 -0
- package/templates/form-input.tsx +64 -0
- package/templates/form.tsx +10 -0
- package/templates/hover-card.tsx +5 -0
- package/templates/input-otp.tsx +6 -0
- package/templates/label.tsx +1 -0
- package/templates/layout-primitives.tsx +11 -0
- package/templates/layouts.tsx +346 -0
- package/templates/lib/utils.ts +49 -0
- package/templates/list-item.tsx +1 -0
- package/templates/list-items.tsx +41 -0
- package/templates/list.tsx +89 -0
- package/templates/logo.tsx +12 -0
- package/templates/marketing-footer.tsx +33 -0
- package/templates/marketing-header.tsx +46 -0
- package/templates/menubar.tsx +16 -0
- package/templates/navigation-menu.tsx +11 -0
- package/templates/pagination.tsx +86 -0
- package/templates/popover.tsx +8 -0
- package/templates/pricing-receipt.tsx +71 -0
- package/templates/pricing-tabs.tsx +60 -0
- package/templates/progress.tsx +29 -0
- package/templates/radio-group.tsx +58 -0
- package/templates/receipt-card.tsx +1 -0
- package/templates/receipt.tsx +269 -0
- package/templates/resizable.tsx +1 -0
- package/templates/scroll-area.tsx +1 -0
- package/templates/select.tsx +110 -0
- package/templates/separator.tsx +1 -0
- package/templates/sheet.tsx +12 -0
- package/templates/sidebar.tsx +15 -0
- package/templates/simple-footer.tsx +43 -0
- package/templates/simple-header.tsx +77 -0
- package/templates/skeleton.tsx +33 -0
- package/templates/slider.tsx +55 -0
- package/templates/styles/dockets.css +104 -0
- package/templates/switch.tsx +49 -0
- package/templates/table.tsx +73 -0
- package/templates/tabs.tsx +61 -0
- package/templates/theme-toggle.tsx +46 -0
- package/templates/toast.tsx +1 -0
- package/templates/toggle-group.tsx +1 -0
- package/templates/toggle.tsx +1 -0
- package/templates/tooltip.tsx +31 -0
- package/templates/tree-view.tsx +1 -0
- package/templates/ui/accordion.tsx +73 -0
- package/templates/ui/alert-dialog.tsx +128 -0
- package/templates/ui/alert.tsx +56 -0
- package/templates/ui/aspect-ratio.tsx +19 -0
- package/templates/ui/avatar.tsx +74 -0
- package/templates/ui/badge.tsx +48 -0
- package/templates/ui/block-loader.tsx +40 -0
- package/templates/ui/button.tsx +77 -0
- package/templates/ui/calendar.tsx +160 -0
- package/templates/ui/card.tsx +73 -0
- package/templates/ui/carousel.tsx +149 -0
- package/templates/ui/checkbox.tsx +33 -0
- package/templates/ui/code-block.tsx +36 -0
- package/templates/ui/collapsible.tsx +48 -0
- package/templates/ui/combobox.tsx +295 -0
- package/templates/ui/command.tsx +148 -0
- package/templates/ui/context-menu.tsx +212 -0
- package/templates/ui/dialog.tsx +138 -0
- package/templates/ui/drawer.tsx +134 -0
- package/templates/ui/dropdown-menu.tsx +254 -0
- package/templates/ui/form.tsx +122 -0
- package/templates/ui/hover-card.tsx +44 -0
- package/templates/ui/input-group.tsx +148 -0
- package/templates/ui/input-otp.tsx +153 -0
- package/templates/ui/input.tsx +20 -0
- package/templates/ui/label.tsx +17 -0
- package/templates/ui/layout.tsx +252 -0
- package/templates/ui/list-item.tsx +50 -0
- package/templates/ui/menubar.tsx +225 -0
- package/templates/ui/navigation-menu.tsx +117 -0
- package/templates/ui/pagination.tsx +110 -0
- package/templates/ui/popover.tsx +77 -0
- package/templates/ui/progress.tsx +37 -0
- package/templates/ui/radio-group.tsx +41 -0
- package/templates/ui/receipt-card.tsx +70 -0
- package/templates/ui/resizable.tsx +140 -0
- package/templates/ui/scroll-area.tsx +64 -0
- package/templates/ui/select.tsx +186 -0
- package/templates/ui/separator.tsx +21 -0
- package/templates/ui/sheet.tsx +134 -0
- package/templates/ui/sidebar.tsx +222 -0
- package/templates/ui/skeleton.tsx +35 -0
- package/templates/ui/slider.tsx +60 -0
- package/templates/ui/switch.tsx +33 -0
- package/templates/ui/table.tsx +114 -0
- package/templates/ui/tabs.tsx +79 -0
- package/templates/ui/textarea.tsx +18 -0
- package/templates/ui/toast.tsx +139 -0
- package/templates/ui/toggle-group.tsx +68 -0
- package/templates/ui/toggle.tsx +47 -0
- package/templates/ui/tooltip.tsx +53 -0
- package/templates/ui/tree-view.tsx +76 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Menu as MenuPrimitive } from '@base-ui/react/menu'
|
|
4
|
+
import { CheckIcon, ChevronRightIcon } from 'lucide-react'
|
|
5
|
+
import type * as React from 'react'
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
|
|
8
|
+
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
|
|
9
|
+
return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
|
|
13
|
+
return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
|
|
17
|
+
return <MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function DropdownMenuContent({
|
|
21
|
+
align = 'start',
|
|
22
|
+
alignOffset = 0,
|
|
23
|
+
side = 'bottom',
|
|
24
|
+
sideOffset = 6,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}: MenuPrimitive.Popup.Props &
|
|
28
|
+
Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
29
|
+
return (
|
|
30
|
+
<MenuPrimitive.Portal>
|
|
31
|
+
<MenuPrimitive.Positioner
|
|
32
|
+
className="isolate z-50 outline-none"
|
|
33
|
+
align={align}
|
|
34
|
+
alignOffset={alignOffset}
|
|
35
|
+
side={side}
|
|
36
|
+
sideOffset={sideOffset}
|
|
37
|
+
>
|
|
38
|
+
<MenuPrimitive.Popup
|
|
39
|
+
data-slot="dropdown-menu-content"
|
|
40
|
+
className={cn(
|
|
41
|
+
'z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-[var(--radius)] border-[length:var(--border-width)] border-foreground bg-popover text-popover-foreground shadow-none duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
</MenuPrimitive.Positioner>
|
|
47
|
+
</MenuPrimitive.Portal>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
|
|
52
|
+
return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function DropdownMenuLabel({
|
|
56
|
+
className,
|
|
57
|
+
inset,
|
|
58
|
+
...props
|
|
59
|
+
}: MenuPrimitive.GroupLabel.Props & {
|
|
60
|
+
inset?: boolean
|
|
61
|
+
}) {
|
|
62
|
+
return (
|
|
63
|
+
<MenuPrimitive.GroupLabel
|
|
64
|
+
data-slot="dropdown-menu-label"
|
|
65
|
+
data-inset={inset}
|
|
66
|
+
className={cn('px-2 py-2 text-xs text-muted-foreground data-inset:pl-7', className)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function DropdownMenuItem({
|
|
73
|
+
className,
|
|
74
|
+
inset,
|
|
75
|
+
variant = 'default',
|
|
76
|
+
...props
|
|
77
|
+
}: MenuPrimitive.Item.Props & {
|
|
78
|
+
inset?: boolean
|
|
79
|
+
variant?: 'default' | 'destructive'
|
|
80
|
+
}) {
|
|
81
|
+
return (
|
|
82
|
+
<MenuPrimitive.Item
|
|
83
|
+
data-slot="dropdown-menu-item"
|
|
84
|
+
data-inset={inset}
|
|
85
|
+
data-variant={variant}
|
|
86
|
+
className={cn(
|
|
87
|
+
"group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-[var(--radius)] px-2 py-2 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
88
|
+
className,
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
|
|
96
|
+
return <MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function DropdownMenuSubTrigger({
|
|
100
|
+
className,
|
|
101
|
+
inset,
|
|
102
|
+
children,
|
|
103
|
+
...props
|
|
104
|
+
}: MenuPrimitive.SubmenuTrigger.Props & {
|
|
105
|
+
inset?: boolean
|
|
106
|
+
}) {
|
|
107
|
+
return (
|
|
108
|
+
<MenuPrimitive.SubmenuTrigger
|
|
109
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
110
|
+
data-inset={inset}
|
|
111
|
+
className={cn(
|
|
112
|
+
"flex cursor-default items-center gap-2 rounded-[var(--radius)] px-2 py-2 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
113
|
+
className,
|
|
114
|
+
)}
|
|
115
|
+
{...props}
|
|
116
|
+
>
|
|
117
|
+
{children}
|
|
118
|
+
<ChevronRightIcon className="ml-auto" />
|
|
119
|
+
</MenuPrimitive.SubmenuTrigger>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function DropdownMenuSubContent({
|
|
124
|
+
align = 'start',
|
|
125
|
+
alignOffset = -3,
|
|
126
|
+
side = 'right',
|
|
127
|
+
sideOffset = 0,
|
|
128
|
+
className,
|
|
129
|
+
...props
|
|
130
|
+
}: React.ComponentProps<typeof DropdownMenuContent>) {
|
|
131
|
+
return (
|
|
132
|
+
<DropdownMenuContent
|
|
133
|
+
data-slot="dropdown-menu-sub-content"
|
|
134
|
+
className={cn(
|
|
135
|
+
'w-auto min-w-[96px] rounded-[var(--radius)] border-[length:var(--border-width)] bg-popover text-popover-foreground duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
136
|
+
className,
|
|
137
|
+
)}
|
|
138
|
+
align={align}
|
|
139
|
+
alignOffset={alignOffset}
|
|
140
|
+
side={side}
|
|
141
|
+
sideOffset={sideOffset}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function DropdownMenuCheckboxItem({
|
|
148
|
+
className,
|
|
149
|
+
children,
|
|
150
|
+
checked,
|
|
151
|
+
inset,
|
|
152
|
+
...props
|
|
153
|
+
}: MenuPrimitive.CheckboxItem.Props & {
|
|
154
|
+
inset?: boolean
|
|
155
|
+
}) {
|
|
156
|
+
return (
|
|
157
|
+
<MenuPrimitive.CheckboxItem
|
|
158
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
159
|
+
data-inset={inset}
|
|
160
|
+
className={cn(
|
|
161
|
+
"relative flex cursor-default items-center gap-2 rounded-[var(--radius)] py-2 pr-8 pl-2 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
162
|
+
className,
|
|
163
|
+
)}
|
|
164
|
+
checked={checked}
|
|
165
|
+
{...props}
|
|
166
|
+
>
|
|
167
|
+
<span
|
|
168
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
169
|
+
data-slot="dropdown-menu-checkbox-item-indicator"
|
|
170
|
+
>
|
|
171
|
+
<MenuPrimitive.CheckboxItemIndicator>
|
|
172
|
+
<CheckIcon />
|
|
173
|
+
</MenuPrimitive.CheckboxItemIndicator>
|
|
174
|
+
</span>
|
|
175
|
+
{children}
|
|
176
|
+
</MenuPrimitive.CheckboxItem>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
|
|
181
|
+
return <MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function DropdownMenuRadioItem({
|
|
185
|
+
className,
|
|
186
|
+
children,
|
|
187
|
+
inset,
|
|
188
|
+
...props
|
|
189
|
+
}: MenuPrimitive.RadioItem.Props & {
|
|
190
|
+
inset?: boolean
|
|
191
|
+
}) {
|
|
192
|
+
return (
|
|
193
|
+
<MenuPrimitive.RadioItem
|
|
194
|
+
data-slot="dropdown-menu-radio-item"
|
|
195
|
+
data-inset={inset}
|
|
196
|
+
className={cn(
|
|
197
|
+
"relative flex cursor-default items-center gap-2 rounded-[var(--radius)] py-2 pr-8 pl-2 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
198
|
+
className,
|
|
199
|
+
)}
|
|
200
|
+
{...props}
|
|
201
|
+
>
|
|
202
|
+
<span
|
|
203
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
204
|
+
data-slot="dropdown-menu-radio-item-indicator"
|
|
205
|
+
>
|
|
206
|
+
<MenuPrimitive.RadioItemIndicator>
|
|
207
|
+
<CheckIcon />
|
|
208
|
+
</MenuPrimitive.RadioItemIndicator>
|
|
209
|
+
</span>
|
|
210
|
+
{children}
|
|
211
|
+
</MenuPrimitive.RadioItem>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
|
|
216
|
+
return (
|
|
217
|
+
<MenuPrimitive.Separator
|
|
218
|
+
data-slot="dropdown-menu-separator"
|
|
219
|
+
className={cn('-mx-1 h-[length:var(--border-width)] bg-border', className)}
|
|
220
|
+
{...props}
|
|
221
|
+
/>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
226
|
+
return (
|
|
227
|
+
<span
|
|
228
|
+
data-slot="dropdown-menu-shortcut"
|
|
229
|
+
className={cn(
|
|
230
|
+
'ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground',
|
|
231
|
+
className,
|
|
232
|
+
)}
|
|
233
|
+
{...props}
|
|
234
|
+
/>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export {
|
|
239
|
+
DropdownMenu,
|
|
240
|
+
DropdownMenuPortal,
|
|
241
|
+
DropdownMenuTrigger,
|
|
242
|
+
DropdownMenuContent,
|
|
243
|
+
DropdownMenuGroup,
|
|
244
|
+
DropdownMenuLabel,
|
|
245
|
+
DropdownMenuItem,
|
|
246
|
+
DropdownMenuCheckboxItem,
|
|
247
|
+
DropdownMenuRadioGroup,
|
|
248
|
+
DropdownMenuRadioItem,
|
|
249
|
+
DropdownMenuSeparator,
|
|
250
|
+
DropdownMenuShortcut,
|
|
251
|
+
DropdownMenuSub,
|
|
252
|
+
DropdownMenuSubTrigger,
|
|
253
|
+
DropdownMenuSubContent,
|
|
254
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
// Lightweight form context — no react-hook-form dependency.
|
|
7
|
+
// Pass your own errors/touched state in or wire to your form library.
|
|
8
|
+
|
|
9
|
+
interface FormFieldContextValue {
|
|
10
|
+
id: string
|
|
11
|
+
name: string
|
|
12
|
+
error?: string
|
|
13
|
+
required?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const FormFieldContext = React.createContext<FormFieldContextValue>({
|
|
17
|
+
id: '',
|
|
18
|
+
name: '',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
function useFormField() {
|
|
22
|
+
return React.useContext(FormFieldContext)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function Form({ className, ...props }: React.ComponentProps<'form'>) {
|
|
26
|
+
return (
|
|
27
|
+
<form
|
|
28
|
+
data-slot="form"
|
|
29
|
+
className={cn('space-y-4', className)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface FormFieldProps {
|
|
36
|
+
name: string
|
|
37
|
+
error?: string
|
|
38
|
+
required?: boolean
|
|
39
|
+
children: React.ReactNode
|
|
40
|
+
className?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function FormField({ name, error, required, children, className }: FormFieldProps) {
|
|
44
|
+
const id = React.useId()
|
|
45
|
+
return (
|
|
46
|
+
<FormFieldContext.Provider value={{ id, name, error, required }}>
|
|
47
|
+
<div data-slot="form-field" className={cn('flex flex-col gap-1', className)}>
|
|
48
|
+
{children}
|
|
49
|
+
</div>
|
|
50
|
+
</FormFieldContext.Provider>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function FormLabel({ className, children, ...props }: React.ComponentProps<'label'>) {
|
|
55
|
+
const { id, required, error } = useFormField()
|
|
56
|
+
return (
|
|
57
|
+
<label
|
|
58
|
+
data-slot="form-label"
|
|
59
|
+
htmlFor={id}
|
|
60
|
+
className={cn(
|
|
61
|
+
'text-xs font-medium uppercase tracking-wider',
|
|
62
|
+
error && 'text-destructive',
|
|
63
|
+
className,
|
|
64
|
+
)}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
{required && <span className="ml-0.5 text-destructive">*</span>}
|
|
69
|
+
</label>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function FormControl({ className, ...props }: React.ComponentProps<'div'>) {
|
|
74
|
+
const { id, error } = useFormField()
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
data-slot="form-control"
|
|
78
|
+
id={id}
|
|
79
|
+
aria-invalid={!!error}
|
|
80
|
+
className={cn('', className)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
87
|
+
return (
|
|
88
|
+
<p
|
|
89
|
+
data-slot="form-description"
|
|
90
|
+
className={cn('text-xs/relaxed text-muted-foreground', className)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function FormMessage({ className, children, ...props }: React.ComponentProps<'p'>) {
|
|
97
|
+
const { error } = useFormField()
|
|
98
|
+
const message = children ?? error
|
|
99
|
+
if (!message) return null
|
|
100
|
+
return (
|
|
101
|
+
<p
|
|
102
|
+
data-slot="form-message"
|
|
103
|
+
role="alert"
|
|
104
|
+
className={cn('text-xs text-destructive', className)}
|
|
105
|
+
{...props}
|
|
106
|
+
>
|
|
107
|
+
{message}
|
|
108
|
+
</p>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
|
|
113
|
+
return (
|
|
114
|
+
<div
|
|
115
|
+
data-slot="form-item"
|
|
116
|
+
className={cn('flex flex-col gap-1', className)}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { Form, FormField, FormLabel, FormControl, FormDescription, FormMessage, FormItem, useFormField }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card'
|
|
4
|
+
import type * as React from 'react'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
|
|
8
|
+
return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function HoverCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {
|
|
12
|
+
return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function HoverCardContent({
|
|
16
|
+
className,
|
|
17
|
+
side = 'bottom',
|
|
18
|
+
sideOffset = 6,
|
|
19
|
+
align = 'center',
|
|
20
|
+
...props
|
|
21
|
+
}: PreviewCardPrimitive.Popup.Props &
|
|
22
|
+
Pick<PreviewCardPrimitive.Positioner.Props, 'side' | 'sideOffset' | 'align'>) {
|
|
23
|
+
return (
|
|
24
|
+
<PreviewCardPrimitive.Portal>
|
|
25
|
+
<PreviewCardPrimitive.Positioner
|
|
26
|
+
side={side}
|
|
27
|
+
sideOffset={sideOffset}
|
|
28
|
+
align={align}
|
|
29
|
+
className="isolate z-50"
|
|
30
|
+
>
|
|
31
|
+
<PreviewCardPrimitive.Popup
|
|
32
|
+
data-slot="hover-card-content"
|
|
33
|
+
className={cn(
|
|
34
|
+
'z-50 w-64 origin-(--transform-origin) rounded-[var(--radius)] border-[length:var(--border-width)] border-dashed border-foreground bg-popover p-3 text-xs/relaxed text-popover-foreground shadow-none duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</PreviewCardPrimitive.Positioner>
|
|
40
|
+
</PreviewCardPrimitive.Portal>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
import { Button } from '@/components/ui/button'
|
|
8
|
+
import { Input } from '@/components/ui/input'
|
|
9
|
+
import { Textarea } from '@/components/ui/textarea'
|
|
10
|
+
|
|
11
|
+
function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
data-slot="input-group"
|
|
15
|
+
role="group"
|
|
16
|
+
className={cn(
|
|
17
|
+
'group/input-group relative flex h-8 w-full min-w-0 items-center rounded-[var(--radius)] border-[length:var(--border-width)] border-input outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-1 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const inputGroupAddonVariants = cva(
|
|
26
|
+
"flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-xs font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[var(--radius)] [&>svg:not([class*='size-'])]:size-4",
|
|
27
|
+
{
|
|
28
|
+
variants: {
|
|
29
|
+
align: {
|
|
30
|
+
'inline-start':
|
|
31
|
+
'order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]',
|
|
32
|
+
'inline-end':
|
|
33
|
+
'order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]',
|
|
34
|
+
'block-start':
|
|
35
|
+
'order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2',
|
|
36
|
+
'block-end':
|
|
37
|
+
'order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
align: 'inline-start',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
function InputGroupAddon({
|
|
47
|
+
className,
|
|
48
|
+
align = 'inline-start',
|
|
49
|
+
...props
|
|
50
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
role="group"
|
|
54
|
+
data-slot="input-group-addon"
|
|
55
|
+
data-align={align}
|
|
56
|
+
className={cn(inputGroupAddonVariants({ align }), className)}
|
|
57
|
+
onClick={(e) => {
|
|
58
|
+
if ((e.target as HTMLElement).closest('button')) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
e.currentTarget.parentElement?.querySelector('input')?.focus()
|
|
62
|
+
}}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const inputGroupButtonVariants = cva('flex items-center gap-2 text-xs shadow-none', {
|
|
69
|
+
variants: {
|
|
70
|
+
size: {
|
|
71
|
+
xs: "h-6 gap-1 rounded-[var(--radius)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
|
|
72
|
+
sm: '',
|
|
73
|
+
'icon-xs': 'size-6 rounded-[var(--radius)] p-0 has-[>svg]:p-0',
|
|
74
|
+
'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
defaultVariants: {
|
|
78
|
+
size: 'xs',
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
function InputGroupButton({
|
|
83
|
+
className,
|
|
84
|
+
type = 'button',
|
|
85
|
+
variant = 'ghost',
|
|
86
|
+
size = 'xs',
|
|
87
|
+
...props
|
|
88
|
+
}: Omit<React.ComponentProps<typeof Button>, 'size' | 'type'> &
|
|
89
|
+
VariantProps<typeof inputGroupButtonVariants> & {
|
|
90
|
+
type?: 'button' | 'submit' | 'reset'
|
|
91
|
+
}) {
|
|
92
|
+
return (
|
|
93
|
+
<Button
|
|
94
|
+
type={type}
|
|
95
|
+
data-size={size}
|
|
96
|
+
variant={variant}
|
|
97
|
+
className={cn(inputGroupButtonVariants({ size }), className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
|
|
104
|
+
return (
|
|
105
|
+
<span
|
|
106
|
+
className={cn(
|
|
107
|
+
"flex items-center gap-2 text-xs text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
108
|
+
className,
|
|
109
|
+
)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>) {
|
|
116
|
+
return (
|
|
117
|
+
<Input
|
|
118
|
+
data-slot="input-group-control"
|
|
119
|
+
className={cn(
|
|
120
|
+
'flex-1 rounded-[var(--radius)] border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function InputGroupTextarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|
129
|
+
return (
|
|
130
|
+
<Textarea
|
|
131
|
+
data-slot="input-group-control"
|
|
132
|
+
className={cn(
|
|
133
|
+
'flex-1 resize-none rounded-[var(--radius)] border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
|
|
134
|
+
className,
|
|
135
|
+
)}
|
|
136
|
+
{...props}
|
|
137
|
+
/>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
InputGroup,
|
|
143
|
+
InputGroupAddon,
|
|
144
|
+
InputGroupButton,
|
|
145
|
+
InputGroupText,
|
|
146
|
+
InputGroupInput,
|
|
147
|
+
InputGroupTextarea,
|
|
148
|
+
}
|