@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,73 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
|
|
4
|
+
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
data-slot="card"
|
|
8
|
+
className={cn(
|
|
9
|
+
'rounded-[var(--radius)] border-[length:var(--border-width)] border-foreground bg-card text-card-foreground',
|
|
10
|
+
className,
|
|
11
|
+
)}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
data-slot="card-header"
|
|
21
|
+
className={cn(
|
|
22
|
+
'flex flex-col gap-1 border-b-[length:var(--border-width)] border-foreground px-4 py-3',
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
data-slot="card-title"
|
|
34
|
+
className={cn('text-xs font-medium uppercase tracking-wider', className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
data-slot="card-description"
|
|
44
|
+
className={cn('text-xs/relaxed text-muted-foreground', className)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
data-slot="card-content"
|
|
54
|
+
className={cn('px-4 py-3 text-xs/relaxed', className)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
61
|
+
return (
|
|
62
|
+
<div
|
|
63
|
+
data-slot="card-footer"
|
|
64
|
+
className={cn(
|
|
65
|
+
'flex items-center border-t-[length:var(--border-width)] border-foreground px-4 py-3',
|
|
66
|
+
className,
|
|
67
|
+
)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
interface CarouselContextValue {
|
|
8
|
+
scrollPrev: () => void
|
|
9
|
+
scrollNext: () => void
|
|
10
|
+
canScrollPrev: boolean
|
|
11
|
+
canScrollNext: boolean
|
|
12
|
+
listRef: React.RefObject<HTMLDivElement | null>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CarouselContext = React.createContext<CarouselContextValue | null>(null)
|
|
16
|
+
|
|
17
|
+
function useCarousel() {
|
|
18
|
+
const ctx = React.useContext(CarouselContext)
|
|
19
|
+
if (!ctx) throw new Error('useCarousel must be used within <Carousel>')
|
|
20
|
+
return ctx
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CarouselProps extends React.ComponentProps<'div'> {
|
|
24
|
+
orientation?: 'horizontal' | 'vertical'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function Carousel({ className, orientation = 'horizontal', children, ...props }: CarouselProps) {
|
|
28
|
+
const listRef = React.useRef<HTMLDivElement>(null)
|
|
29
|
+
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
|
30
|
+
const [canScrollNext, setCanScrollNext] = React.useState(true)
|
|
31
|
+
|
|
32
|
+
const updateScroll = React.useCallback(() => {
|
|
33
|
+
const el = listRef.current
|
|
34
|
+
if (!el) return
|
|
35
|
+
if (orientation === 'horizontal') {
|
|
36
|
+
setCanScrollPrev(el.scrollLeft > 0)
|
|
37
|
+
setCanScrollNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 1)
|
|
38
|
+
} else {
|
|
39
|
+
setCanScrollPrev(el.scrollTop > 0)
|
|
40
|
+
setCanScrollNext(el.scrollTop + el.clientHeight < el.scrollHeight - 1)
|
|
41
|
+
}
|
|
42
|
+
}, [orientation])
|
|
43
|
+
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
const el = listRef.current
|
|
46
|
+
if (!el) return
|
|
47
|
+
el.addEventListener('scroll', updateScroll, { passive: true })
|
|
48
|
+
updateScroll()
|
|
49
|
+
return () => el.removeEventListener('scroll', updateScroll)
|
|
50
|
+
}, [updateScroll])
|
|
51
|
+
|
|
52
|
+
const scrollPrev = React.useCallback(() => {
|
|
53
|
+
const el = listRef.current
|
|
54
|
+
if (!el) return
|
|
55
|
+
const amount = orientation === 'horizontal' ? el.clientWidth : el.clientHeight
|
|
56
|
+
el.scrollBy({ [orientation === 'horizontal' ? 'left' : 'top']: -amount, behavior: 'smooth' })
|
|
57
|
+
}, [orientation])
|
|
58
|
+
|
|
59
|
+
const scrollNext = React.useCallback(() => {
|
|
60
|
+
const el = listRef.current
|
|
61
|
+
if (!el) return
|
|
62
|
+
const amount = orientation === 'horizontal' ? el.clientWidth : el.clientHeight
|
|
63
|
+
el.scrollBy({ [orientation === 'horizontal' ? 'left' : 'top']: amount, behavior: 'smooth' })
|
|
64
|
+
}, [orientation])
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<CarouselContext.Provider value={{ scrollPrev, scrollNext, canScrollPrev, canScrollNext, listRef }}>
|
|
68
|
+
<div
|
|
69
|
+
data-slot="carousel"
|
|
70
|
+
data-orientation={orientation}
|
|
71
|
+
className={cn('relative', className)}
|
|
72
|
+
{...props}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</div>
|
|
76
|
+
</CarouselContext.Provider>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
81
|
+
const { listRef } = useCarousel()
|
|
82
|
+
return (
|
|
83
|
+
<div className="overflow-hidden">
|
|
84
|
+
<div
|
|
85
|
+
ref={listRef}
|
|
86
|
+
data-slot="carousel-content"
|
|
87
|
+
className={cn(
|
|
88
|
+
'flex scroll-smooth',
|
|
89
|
+
'overflow-x-auto snap-x snap-mandatory scrollbar-none',
|
|
90
|
+
'data-[orientation=vertical]:flex-col data-[orientation=vertical]:overflow-y-auto data-[orientation=vertical]:overflow-x-hidden',
|
|
91
|
+
className,
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
data-slot="carousel-item"
|
|
103
|
+
className={cn('min-w-0 shrink-0 grow-0 basis-full snap-start', className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function CarouselPrevious({ className, ...props }: React.ComponentProps<'button'>) {
|
|
110
|
+
const { scrollPrev, canScrollPrev } = useCarousel()
|
|
111
|
+
return (
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
data-slot="carousel-previous"
|
|
115
|
+
onClick={scrollPrev}
|
|
116
|
+
disabled={!canScrollPrev}
|
|
117
|
+
className={cn(
|
|
118
|
+
'absolute left-2 top-1/2 -translate-y-1/2 flex size-8 items-center justify-center rounded-[var(--radius)] border-[length:var(--border-width)] border-dashed border-foreground bg-card text-card-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-30',
|
|
119
|
+
className,
|
|
120
|
+
)}
|
|
121
|
+
aria-label="Previous slide"
|
|
122
|
+
{...props}
|
|
123
|
+
>
|
|
124
|
+
<ChevronLeftIcon className="size-4" />
|
|
125
|
+
</button>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function CarouselNext({ className, ...props }: React.ComponentProps<'button'>) {
|
|
130
|
+
const { scrollNext, canScrollNext } = useCarousel()
|
|
131
|
+
return (
|
|
132
|
+
<button
|
|
133
|
+
type="button"
|
|
134
|
+
data-slot="carousel-next"
|
|
135
|
+
onClick={scrollNext}
|
|
136
|
+
disabled={!canScrollNext}
|
|
137
|
+
className={cn(
|
|
138
|
+
'absolute right-2 top-1/2 -translate-y-1/2 flex size-8 items-center justify-center rounded-[var(--radius)] border-[length:var(--border-width)] border-dashed border-foreground bg-card text-card-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-30',
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
aria-label="Next slide"
|
|
142
|
+
{...props}
|
|
143
|
+
>
|
|
144
|
+
<ChevronRightIcon className="size-4" />
|
|
145
|
+
</button>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'
|
|
4
|
+
import { CheckIcon, MinusIcon } from 'lucide-react'
|
|
5
|
+
import * as React from 'react'
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
|
|
8
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
9
|
+
return (
|
|
10
|
+
<CheckboxPrimitive.Root
|
|
11
|
+
data-slot="checkbox"
|
|
12
|
+
className={cn(
|
|
13
|
+
'peer flex size-4 shrink-0 items-center justify-center rounded-[var(--radius)] border-[length:var(--border-width)] border-foreground bg-transparent',
|
|
14
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
15
|
+
'data-checked:bg-foreground data-checked:border-foreground data-checked:text-background',
|
|
16
|
+
'data-indeterminate:bg-foreground data-indeterminate:border-foreground data-indeterminate:text-background',
|
|
17
|
+
'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',
|
|
18
|
+
'aria-invalid:border-destructive',
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
<CheckboxPrimitive.Indicator className="flex items-center justify-center">
|
|
24
|
+
{/* indeterminate */}
|
|
25
|
+
<MinusIcon className="hidden size-3 data-indeterminate:block" />
|
|
26
|
+
{/* checked */}
|
|
27
|
+
<CheckIcon className="size-3 data-indeterminate:hidden" />
|
|
28
|
+
</CheckboxPrimitive.Indicator>
|
|
29
|
+
</CheckboxPrimitive.Root>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { Checkbox }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cn, leftPad } from '@/lib/utils'
|
|
3
|
+
|
|
4
|
+
interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {}
|
|
5
|
+
|
|
6
|
+
const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>(
|
|
7
|
+
({ children, className, ...props }, ref) => {
|
|
8
|
+
return (
|
|
9
|
+
<pre
|
|
10
|
+
data-slot="code-block"
|
|
11
|
+
ref={ref}
|
|
12
|
+
className={cn(
|
|
13
|
+
'block font-normal overflow-auto bg-[var(--receipt-bg)] scrollbar-none',
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
{String(children)
|
|
19
|
+
.split('\n')
|
|
20
|
+
.map((line, index) => (
|
|
21
|
+
<div key={index} className="flex justify-between items-start">
|
|
22
|
+
<span className="inline-flex w-[3ch] text-right pr-[1ch] select-none bg-[var(--bg-color)] opacity-50">
|
|
23
|
+
{leftPad(String(index + 1), 3)}
|
|
24
|
+
</span>
|
|
25
|
+
<span className="min-w-[10%] w-full whitespace-pre bg-[var(--receipt-bg)] pl-[2ch]">
|
|
26
|
+
{line}
|
|
27
|
+
</span>
|
|
28
|
+
</div>
|
|
29
|
+
))}
|
|
30
|
+
</pre>
|
|
31
|
+
)
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
CodeBlock.displayName = 'CodeBlock'
|
|
35
|
+
|
|
36
|
+
export { CodeBlock }
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Collapsible as CollapsiblePrimitive } from '@base-ui/react/collapsible'
|
|
4
|
+
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
|
|
5
|
+
import * as React from 'react'
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
|
|
8
|
+
function Collapsible({ className, ...props }: CollapsiblePrimitive.Root.Props) {
|
|
9
|
+
return (
|
|
10
|
+
<CollapsiblePrimitive.Root
|
|
11
|
+
data-slot="collapsible"
|
|
12
|
+
className={cn('rounded-[var(--radius)]', className)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CollapsibleTrigger({ className, children, ...props }: CollapsiblePrimitive.Trigger.Props) {
|
|
19
|
+
return (
|
|
20
|
+
<CollapsiblePrimitive.Trigger
|
|
21
|
+
data-slot="collapsible-trigger"
|
|
22
|
+
className={cn(
|
|
23
|
+
'group/collapsible-trigger flex w-full items-center justify-between rounded-[var(--radius)] py-2 text-xs font-medium uppercase tracking-wider hover:underline disabled:pointer-events-none disabled:opacity-50',
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
{children}
|
|
29
|
+
<ChevronDownIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-open/collapsible-trigger:hidden" />
|
|
30
|
+
<ChevronUpIcon className="hidden size-4 shrink-0 text-muted-foreground transition-transform group-data-open/collapsible-trigger:block" />
|
|
31
|
+
</CollapsiblePrimitive.Trigger>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function CollapsibleContent({ className, ...props }: CollapsiblePrimitive.Panel.Props) {
|
|
36
|
+
return (
|
|
37
|
+
<CollapsiblePrimitive.Panel
|
|
38
|
+
data-slot="collapsible-content"
|
|
39
|
+
className={cn(
|
|
40
|
+
'overflow-hidden text-xs/relaxed data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Combobox as ComboboxPrimitive } from "@base-ui/react"
|
|
3
|
+
|
|
4
|
+
import { cn } from "~/lib/utils"
|
|
5
|
+
import { Button } from "~/components/ui/button"
|
|
6
|
+
import {
|
|
7
|
+
InputGroup,
|
|
8
|
+
InputGroupAddon,
|
|
9
|
+
InputGroupButton,
|
|
10
|
+
InputGroupInput,
|
|
11
|
+
} from "~/components/ui/input-group"
|
|
12
|
+
import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"
|
|
13
|
+
|
|
14
|
+
const Combobox = ComboboxPrimitive.Root
|
|
15
|
+
|
|
16
|
+
function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
|
|
17
|
+
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ComboboxTrigger({
|
|
21
|
+
className,
|
|
22
|
+
children,
|
|
23
|
+
...props
|
|
24
|
+
}: ComboboxPrimitive.Trigger.Props) {
|
|
25
|
+
return (
|
|
26
|
+
<ComboboxPrimitive.Trigger
|
|
27
|
+
data-slot="combobox-trigger"
|
|
28
|
+
className={cn("[&_svg:not([class*='size-'])]:size-4", className)}
|
|
29
|
+
{...props}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
<ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
|
|
33
|
+
</ComboboxPrimitive.Trigger>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
|
|
38
|
+
return (
|
|
39
|
+
<ComboboxPrimitive.Clear
|
|
40
|
+
data-slot="combobox-clear"
|
|
41
|
+
render={<InputGroupButton variant="ghost" size="icon-xs" />}
|
|
42
|
+
className={cn(className)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<XIcon className="pointer-events-none" />
|
|
46
|
+
</ComboboxPrimitive.Clear>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function ComboboxInput({
|
|
51
|
+
className,
|
|
52
|
+
children,
|
|
53
|
+
disabled = false,
|
|
54
|
+
showTrigger = true,
|
|
55
|
+
showClear = false,
|
|
56
|
+
...props
|
|
57
|
+
}: ComboboxPrimitive.Input.Props & {
|
|
58
|
+
showTrigger?: boolean
|
|
59
|
+
showClear?: boolean
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
<InputGroup className={cn("w-auto", className)}>
|
|
63
|
+
<ComboboxPrimitive.Input
|
|
64
|
+
render={<InputGroupInput disabled={disabled} />}
|
|
65
|
+
{...props}
|
|
66
|
+
/>
|
|
67
|
+
<InputGroupAddon align="inline-end">
|
|
68
|
+
{showTrigger && (
|
|
69
|
+
<InputGroupButton
|
|
70
|
+
size="icon-xs"
|
|
71
|
+
variant="ghost"
|
|
72
|
+
render={<ComboboxTrigger />}
|
|
73
|
+
data-slot="input-group-button"
|
|
74
|
+
className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
|
|
75
|
+
disabled={disabled}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
{showClear && <ComboboxClear disabled={disabled} />}
|
|
79
|
+
</InputGroupAddon>
|
|
80
|
+
{children}
|
|
81
|
+
</InputGroup>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function ComboboxContent({
|
|
86
|
+
className,
|
|
87
|
+
side = "bottom",
|
|
88
|
+
sideOffset = 6,
|
|
89
|
+
align = "start",
|
|
90
|
+
alignOffset = 0,
|
|
91
|
+
anchor,
|
|
92
|
+
...props
|
|
93
|
+
}: ComboboxPrimitive.Popup.Props &
|
|
94
|
+
Pick<
|
|
95
|
+
ComboboxPrimitive.Positioner.Props,
|
|
96
|
+
"side" | "align" | "sideOffset" | "alignOffset" | "anchor"
|
|
97
|
+
>) {
|
|
98
|
+
return (
|
|
99
|
+
<ComboboxPrimitive.Portal>
|
|
100
|
+
<ComboboxPrimitive.Positioner
|
|
101
|
+
side={side}
|
|
102
|
+
sideOffset={sideOffset}
|
|
103
|
+
align={align}
|
|
104
|
+
alignOffset={alignOffset}
|
|
105
|
+
anchor={anchor}
|
|
106
|
+
className="isolate z-50"
|
|
107
|
+
>
|
|
108
|
+
<ComboboxPrimitive.Popup
|
|
109
|
+
data-slot="combobox-content"
|
|
110
|
+
data-chips={!!anchor}
|
|
111
|
+
className={cn("group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-[var(--radius)] bg-popover text-popover-foreground shadow-none border border-foreground duration-100 data-[chips=true]:min-w-(--anchor-width) 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-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none 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", className )}
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
</ComboboxPrimitive.Positioner>
|
|
115
|
+
</ComboboxPrimitive.Portal>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
|
|
120
|
+
return (
|
|
121
|
+
<ComboboxPrimitive.List
|
|
122
|
+
data-slot="combobox-list"
|
|
123
|
+
className={cn(
|
|
124
|
+
"no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain data-empty:p-0",
|
|
125
|
+
className
|
|
126
|
+
)}
|
|
127
|
+
{...props}
|
|
128
|
+
/>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function ComboboxItem({
|
|
133
|
+
className,
|
|
134
|
+
children,
|
|
135
|
+
...props
|
|
136
|
+
}: ComboboxPrimitive.Item.Props) {
|
|
137
|
+
return (
|
|
138
|
+
<ComboboxPrimitive.Item
|
|
139
|
+
data-slot="combobox-item"
|
|
140
|
+
className={cn(
|
|
141
|
+
"relative flex w-full cursor-default items-center gap-2 rounded-[var(--radius)] py-2 pr-8 pl-2 text-xs outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
142
|
+
className
|
|
143
|
+
)}
|
|
144
|
+
{...props}
|
|
145
|
+
>
|
|
146
|
+
{children}
|
|
147
|
+
<ComboboxPrimitive.ItemIndicator
|
|
148
|
+
render={
|
|
149
|
+
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
|
|
150
|
+
}
|
|
151
|
+
>
|
|
152
|
+
<CheckIcon className="pointer-events-none" />
|
|
153
|
+
</ComboboxPrimitive.ItemIndicator>
|
|
154
|
+
</ComboboxPrimitive.Item>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
|
|
159
|
+
return (
|
|
160
|
+
<ComboboxPrimitive.Group
|
|
161
|
+
data-slot="combobox-group"
|
|
162
|
+
className={cn(className)}
|
|
163
|
+
{...props}
|
|
164
|
+
/>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function ComboboxLabel({
|
|
169
|
+
className,
|
|
170
|
+
...props
|
|
171
|
+
}: ComboboxPrimitive.GroupLabel.Props) {
|
|
172
|
+
return (
|
|
173
|
+
<ComboboxPrimitive.GroupLabel
|
|
174
|
+
data-slot="combobox-label"
|
|
175
|
+
className={cn("px-2 py-2 text-xs text-muted-foreground", className)}
|
|
176
|
+
{...props}
|
|
177
|
+
/>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
|
|
182
|
+
return (
|
|
183
|
+
<ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
|
|
188
|
+
return (
|
|
189
|
+
<ComboboxPrimitive.Empty
|
|
190
|
+
data-slot="combobox-empty"
|
|
191
|
+
className={cn(
|
|
192
|
+
"hidden w-full justify-center py-2 text-center text-xs text-muted-foreground group-data-empty/combobox-content:flex",
|
|
193
|
+
className
|
|
194
|
+
)}
|
|
195
|
+
{...props}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function ComboboxSeparator({
|
|
201
|
+
className,
|
|
202
|
+
...props
|
|
203
|
+
}: ComboboxPrimitive.Separator.Props) {
|
|
204
|
+
return (
|
|
205
|
+
<ComboboxPrimitive.Separator
|
|
206
|
+
data-slot="combobox-separator"
|
|
207
|
+
className={cn("-mx-1 h-px bg-border", className)}
|
|
208
|
+
{...props}
|
|
209
|
+
/>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function ComboboxChips({
|
|
214
|
+
className,
|
|
215
|
+
...props
|
|
216
|
+
}: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
|
|
217
|
+
ComboboxPrimitive.Chips.Props) {
|
|
218
|
+
return (
|
|
219
|
+
<ComboboxPrimitive.Chips
|
|
220
|
+
data-slot="combobox-chips"
|
|
221
|
+
className={cn(
|
|
222
|
+
"flex min-h-8 flex-wrap items-center gap-1 rounded-[var(--radius)] border border-input bg-transparent bg-clip-padding px-2.5 py-1 text-xs focus-within:border-ring focus-within:ring-1 focus-within:ring-ring/50 has-aria-invalid:border-destructive has-aria-invalid:ring-1 has-aria-invalid:ring-destructive/20 has-data-[slot=combobox-chip]:px-1 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40",
|
|
223
|
+
className
|
|
224
|
+
)}
|
|
225
|
+
{...props}
|
|
226
|
+
/>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function ComboboxChip({
|
|
231
|
+
className,
|
|
232
|
+
children,
|
|
233
|
+
showRemove = true,
|
|
234
|
+
...props
|
|
235
|
+
}: ComboboxPrimitive.Chip.Props & {
|
|
236
|
+
showRemove?: boolean
|
|
237
|
+
}) {
|
|
238
|
+
return (
|
|
239
|
+
<ComboboxPrimitive.Chip
|
|
240
|
+
data-slot="combobox-chip"
|
|
241
|
+
className={cn(
|
|
242
|
+
"flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 rounded-[var(--radius)] bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0",
|
|
243
|
+
className
|
|
244
|
+
)}
|
|
245
|
+
{...props}
|
|
246
|
+
>
|
|
247
|
+
{children}
|
|
248
|
+
{showRemove && (
|
|
249
|
+
<ComboboxPrimitive.ChipRemove
|
|
250
|
+
render={<Button variant="ghost" size="icon" />}
|
|
251
|
+
className="-ml-1 opacity-50 hover:opacity-100"
|
|
252
|
+
data-slot="combobox-chip-remove"
|
|
253
|
+
>
|
|
254
|
+
<XIcon className="pointer-events-none" />
|
|
255
|
+
</ComboboxPrimitive.ChipRemove>
|
|
256
|
+
)}
|
|
257
|
+
</ComboboxPrimitive.Chip>
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function ComboboxChipsInput({
|
|
262
|
+
className,
|
|
263
|
+
...props
|
|
264
|
+
}: ComboboxPrimitive.Input.Props) {
|
|
265
|
+
return (
|
|
266
|
+
<ComboboxPrimitive.Input
|
|
267
|
+
data-slot="combobox-chip-input"
|
|
268
|
+
className={cn("min-w-16 flex-1 outline-none", className)}
|
|
269
|
+
{...props}
|
|
270
|
+
/>
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function useComboboxAnchor() {
|
|
275
|
+
return React.useRef<HTMLDivElement | null>(null)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
Combobox,
|
|
280
|
+
ComboboxInput,
|
|
281
|
+
ComboboxContent,
|
|
282
|
+
ComboboxList,
|
|
283
|
+
ComboboxItem,
|
|
284
|
+
ComboboxGroup,
|
|
285
|
+
ComboboxLabel,
|
|
286
|
+
ComboboxCollection,
|
|
287
|
+
ComboboxEmpty,
|
|
288
|
+
ComboboxSeparator,
|
|
289
|
+
ComboboxChips,
|
|
290
|
+
ComboboxChip,
|
|
291
|
+
ComboboxChipsInput,
|
|
292
|
+
ComboboxTrigger,
|
|
293
|
+
ComboboxValue,
|
|
294
|
+
useComboboxAnchor,
|
|
295
|
+
}
|