@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.
Files changed (135) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +18 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/add.d.ts +3 -0
  6. package/dist/commands/add.d.ts.map +1 -0
  7. package/dist/commands/add.js +86 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/list.d.ts +3 -0
  10. package/dist/commands/list.d.ts.map +1 -0
  11. package/dist/commands/list.js +36 -0
  12. package/dist/commands/list.js.map +1 -0
  13. package/dist/registry.d.ts +18 -0
  14. package/dist/registry.d.ts.map +1 -0
  15. package/dist/registry.js +712 -0
  16. package/dist/registry.js.map +1 -0
  17. package/package.json +40 -0
  18. package/templates/accordion.tsx +77 -0
  19. package/templates/alert-dialog.tsx +66 -0
  20. package/templates/alert.tsx +41 -0
  21. package/templates/aspect-ratio.tsx +15 -0
  22. package/templates/avatar.tsx +27 -0
  23. package/templates/badge.tsx +1 -0
  24. package/templates/block-loader.tsx +1 -0
  25. package/templates/breadcrumb.tsx +31 -0
  26. package/templates/button.tsx +1 -0
  27. package/templates/calendar.tsx +45 -0
  28. package/templates/card.tsx +35 -0
  29. package/templates/carousel.tsx +39 -0
  30. package/templates/checkbox.tsx +50 -0
  31. package/templates/code-block.tsx +1 -0
  32. package/templates/collapsible.tsx +35 -0
  33. package/templates/combobox.tsx +154 -0
  34. package/templates/command.tsx +50 -0
  35. package/templates/contact-footer.tsx +193 -0
  36. package/templates/context-menu.tsx +16 -0
  37. package/templates/dialog.tsx +67 -0
  38. package/templates/drawer.tsx +12 -0
  39. package/templates/dropdown-menu.tsx +95 -0
  40. package/templates/form-input.tsx +64 -0
  41. package/templates/form.tsx +10 -0
  42. package/templates/hover-card.tsx +5 -0
  43. package/templates/input-otp.tsx +6 -0
  44. package/templates/label.tsx +1 -0
  45. package/templates/layout-primitives.tsx +11 -0
  46. package/templates/layouts.tsx +346 -0
  47. package/templates/lib/utils.ts +49 -0
  48. package/templates/list-item.tsx +1 -0
  49. package/templates/list-items.tsx +41 -0
  50. package/templates/list.tsx +89 -0
  51. package/templates/logo.tsx +12 -0
  52. package/templates/marketing-footer.tsx +33 -0
  53. package/templates/marketing-header.tsx +46 -0
  54. package/templates/menubar.tsx +16 -0
  55. package/templates/navigation-menu.tsx +11 -0
  56. package/templates/pagination.tsx +86 -0
  57. package/templates/popover.tsx +8 -0
  58. package/templates/pricing-receipt.tsx +71 -0
  59. package/templates/pricing-tabs.tsx +60 -0
  60. package/templates/progress.tsx +29 -0
  61. package/templates/radio-group.tsx +58 -0
  62. package/templates/receipt-card.tsx +1 -0
  63. package/templates/receipt.tsx +269 -0
  64. package/templates/resizable.tsx +1 -0
  65. package/templates/scroll-area.tsx +1 -0
  66. package/templates/select.tsx +110 -0
  67. package/templates/separator.tsx +1 -0
  68. package/templates/sheet.tsx +12 -0
  69. package/templates/sidebar.tsx +15 -0
  70. package/templates/simple-footer.tsx +43 -0
  71. package/templates/simple-header.tsx +77 -0
  72. package/templates/skeleton.tsx +33 -0
  73. package/templates/slider.tsx +55 -0
  74. package/templates/styles/dockets.css +104 -0
  75. package/templates/switch.tsx +49 -0
  76. package/templates/table.tsx +73 -0
  77. package/templates/tabs.tsx +61 -0
  78. package/templates/theme-toggle.tsx +46 -0
  79. package/templates/toast.tsx +1 -0
  80. package/templates/toggle-group.tsx +1 -0
  81. package/templates/toggle.tsx +1 -0
  82. package/templates/tooltip.tsx +31 -0
  83. package/templates/tree-view.tsx +1 -0
  84. package/templates/ui/accordion.tsx +73 -0
  85. package/templates/ui/alert-dialog.tsx +128 -0
  86. package/templates/ui/alert.tsx +56 -0
  87. package/templates/ui/aspect-ratio.tsx +19 -0
  88. package/templates/ui/avatar.tsx +74 -0
  89. package/templates/ui/badge.tsx +48 -0
  90. package/templates/ui/block-loader.tsx +40 -0
  91. package/templates/ui/button.tsx +77 -0
  92. package/templates/ui/calendar.tsx +160 -0
  93. package/templates/ui/card.tsx +73 -0
  94. package/templates/ui/carousel.tsx +149 -0
  95. package/templates/ui/checkbox.tsx +33 -0
  96. package/templates/ui/code-block.tsx +36 -0
  97. package/templates/ui/collapsible.tsx +48 -0
  98. package/templates/ui/combobox.tsx +295 -0
  99. package/templates/ui/command.tsx +148 -0
  100. package/templates/ui/context-menu.tsx +212 -0
  101. package/templates/ui/dialog.tsx +138 -0
  102. package/templates/ui/drawer.tsx +134 -0
  103. package/templates/ui/dropdown-menu.tsx +254 -0
  104. package/templates/ui/form.tsx +122 -0
  105. package/templates/ui/hover-card.tsx +44 -0
  106. package/templates/ui/input-group.tsx +148 -0
  107. package/templates/ui/input-otp.tsx +153 -0
  108. package/templates/ui/input.tsx +20 -0
  109. package/templates/ui/label.tsx +17 -0
  110. package/templates/ui/layout.tsx +252 -0
  111. package/templates/ui/list-item.tsx +50 -0
  112. package/templates/ui/menubar.tsx +225 -0
  113. package/templates/ui/navigation-menu.tsx +117 -0
  114. package/templates/ui/pagination.tsx +110 -0
  115. package/templates/ui/popover.tsx +77 -0
  116. package/templates/ui/progress.tsx +37 -0
  117. package/templates/ui/radio-group.tsx +41 -0
  118. package/templates/ui/receipt-card.tsx +70 -0
  119. package/templates/ui/resizable.tsx +140 -0
  120. package/templates/ui/scroll-area.tsx +64 -0
  121. package/templates/ui/select.tsx +186 -0
  122. package/templates/ui/separator.tsx +21 -0
  123. package/templates/ui/sheet.tsx +134 -0
  124. package/templates/ui/sidebar.tsx +222 -0
  125. package/templates/ui/skeleton.tsx +35 -0
  126. package/templates/ui/slider.tsx +60 -0
  127. package/templates/ui/switch.tsx +33 -0
  128. package/templates/ui/table.tsx +114 -0
  129. package/templates/ui/tabs.tsx +79 -0
  130. package/templates/ui/textarea.tsx +18 -0
  131. package/templates/ui/toast.tsx +139 -0
  132. package/templates/ui/toggle-group.tsx +68 -0
  133. package/templates/ui/toggle.tsx +47 -0
  134. package/templates/ui/tooltip.tsx +53 -0
  135. package/templates/ui/tree-view.tsx +76 -0
@@ -0,0 +1,140 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { GripVerticalIcon } from 'lucide-react'
5
+ import { cn } from '@/lib/utils'
6
+
7
+ // Resizable panels implemented with pointer events — no heavy dependency.
8
+ // "Borders never stack" rule: the handle IS the border, so panels have no border of their own.
9
+
10
+ interface ResizablePanelGroupProps extends React.ComponentProps<'div'> {
11
+ direction?: 'horizontal' | 'vertical'
12
+ }
13
+
14
+ function ResizablePanelGroup({
15
+ className,
16
+ direction = 'horizontal',
17
+ children,
18
+ ...props
19
+ }: ResizablePanelGroupProps) {
20
+ return (
21
+ <div
22
+ data-slot="resizable-panel-group"
23
+ data-direction={direction}
24
+ className={cn(
25
+ 'flex w-full rounded-[var(--radius)]',
26
+ direction === 'horizontal' ? 'flex-row' : 'flex-col',
27
+ className,
28
+ )}
29
+ {...props}
30
+ >
31
+ {children}
32
+ </div>
33
+ )
34
+ }
35
+
36
+ interface ResizablePanelProps extends React.ComponentProps<'div'> {
37
+ defaultSize?: number
38
+ minSize?: number
39
+ }
40
+
41
+ function ResizablePanel({
42
+ className,
43
+ defaultSize,
44
+ style,
45
+ ...props
46
+ }: ResizablePanelProps) {
47
+ return (
48
+ <div
49
+ data-slot="resizable-panel"
50
+ style={{ flexBasis: defaultSize ? `${defaultSize}%` : undefined, flexGrow: defaultSize ? 0 : 1, ...style }}
51
+ className={cn('overflow-hidden', className)}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ interface ResizableHandleProps extends React.ComponentProps<'div'> {
58
+ withHandle?: boolean
59
+ direction?: 'horizontal' | 'vertical'
60
+ }
61
+
62
+ function ResizableHandle({
63
+ className,
64
+ withHandle = false,
65
+ direction = 'horizontal',
66
+ ...props
67
+ }: ResizableHandleProps) {
68
+ const handleRef = React.useRef<HTMLDivElement>(null)
69
+
70
+ const onPointerDown = React.useCallback(
71
+ (e: React.PointerEvent<HTMLDivElement>) => {
72
+ e.preventDefault()
73
+ const handle = handleRef.current
74
+ if (!handle) return
75
+
76
+ const prev = handle.previousElementSibling as HTMLElement | null
77
+ const next = handle.nextElementSibling as HTMLElement | null
78
+ if (!prev || !next) return
79
+
80
+ const startX = e.clientX
81
+ const startY = e.clientY
82
+ const prevSize = direction === 'horizontal' ? prev.offsetWidth : prev.offsetHeight
83
+ const nextSize = direction === 'horizontal' ? next.offsetWidth : next.offsetHeight
84
+ const total = prevSize + nextSize
85
+
86
+ handle.setPointerCapture(e.pointerId)
87
+
88
+ const onMove = (moveEvent: PointerEvent) => {
89
+ const delta =
90
+ direction === 'horizontal'
91
+ ? moveEvent.clientX - startX
92
+ : moveEvent.clientY - startY
93
+ const newPrev = Math.min(Math.max(prevSize + delta, 80), total - 80)
94
+ const newNext = total - newPrev
95
+ prev.style.flexBasis = `${newPrev}px`
96
+ next.style.flexBasis = `${newNext}px`
97
+ prev.style.flexGrow = '0'
98
+ next.style.flexGrow = '0'
99
+ }
100
+
101
+ const onUp = () => {
102
+ handle.removeEventListener('pointermove', onMove as EventListener)
103
+ handle.removeEventListener('pointerup', onUp)
104
+ }
105
+
106
+ handle.addEventListener('pointermove', onMove as EventListener)
107
+ handle.addEventListener('pointerup', onUp)
108
+ },
109
+ [direction],
110
+ )
111
+
112
+ return (
113
+ <div
114
+ ref={handleRef}
115
+ data-slot="resizable-handle"
116
+ onPointerDown={onPointerDown}
117
+ className={cn(
118
+ 'relative flex shrink-0 items-center justify-center bg-border',
119
+ direction === 'horizontal'
120
+ ? 'w-[length:var(--border-width)] cursor-col-resize'
121
+ : 'h-[length:var(--border-width)] cursor-row-resize',
122
+ 'after:absolute after:z-10',
123
+ direction === 'horizontal'
124
+ ? 'after:inset-y-0 after:w-3 after:-translate-x-1/2'
125
+ : 'after:inset-x-0 after:h-3 after:-translate-y-1/2',
126
+ 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',
127
+ className,
128
+ )}
129
+ {...props}
130
+ >
131
+ {withHandle && (
132
+ <div className="z-10 flex h-6 w-3 items-center justify-center rounded-[var(--radius)] border-[length:var(--border-width)] border-foreground bg-card">
133
+ <GripVerticalIcon className="size-2.5" />
134
+ </div>
135
+ )}
136
+ </div>
137
+ )
138
+ }
139
+
140
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
@@ -0,0 +1,64 @@
1
+ import * as React from 'react'
2
+ import { cn } from '@/lib/utils'
3
+
4
+ // Custom scrollbar via CSS — no heavy dependency.
5
+ // Uses scrollbar-width: thin + custom track/thumb colours via @layer utilities
6
+ // or explicit inline styles.
7
+
8
+ function ScrollArea({
9
+ className,
10
+ children,
11
+ orientation = 'vertical',
12
+ ...props
13
+ }: React.ComponentProps<'div'> & {
14
+ orientation?: 'vertical' | 'horizontal' | 'both'
15
+ }) {
16
+ const overflowClass =
17
+ orientation === 'both'
18
+ ? 'overflow-auto'
19
+ : orientation === 'horizontal'
20
+ ? 'overflow-x-auto overflow-y-hidden'
21
+ : 'overflow-y-auto overflow-x-hidden'
22
+
23
+ return (
24
+ <div
25
+ data-slot="scroll-area"
26
+ className={cn(
27
+ 'relative rounded-[var(--radius)]',
28
+ overflowClass,
29
+ // Thin system scrollbar
30
+ '[scrollbar-width:thin] [scrollbar-color:hsl(var(--foreground)/0.3)_transparent]',
31
+ // Webkit
32
+ '[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5',
33
+ '[&::-webkit-scrollbar-track]:bg-transparent',
34
+ '[&::-webkit-scrollbar-thumb]:rounded-[var(--radius)] [&::-webkit-scrollbar-thumb]:bg-foreground/30 [&::-webkit-scrollbar-thumb]:hover:bg-foreground/50',
35
+ className,
36
+ )}
37
+ {...props}
38
+ >
39
+ {children}
40
+ </div>
41
+ )
42
+ }
43
+
44
+ function ScrollBar({ className, orientation = 'vertical', ...props }: React.ComponentProps<'div'> & {
45
+ orientation?: 'vertical' | 'horizontal'
46
+ }) {
47
+ return (
48
+ <div
49
+ data-slot="scroll-bar"
50
+ data-orientation={orientation}
51
+ className={cn(
52
+ 'flex touch-none select-none bg-transparent',
53
+ orientation === 'vertical' && 'h-full w-1.5 border-l-[length:var(--border-width)] border-l-transparent p-px',
54
+ orientation === 'horizontal' && 'h-1.5 w-full border-t-[length:var(--border-width)] border-t-transparent p-px flex-col',
55
+ className,
56
+ )}
57
+ {...props}
58
+ >
59
+ <div className="relative flex-1 rounded-[var(--radius)] bg-foreground/30 hover:bg-foreground/50" />
60
+ </div>
61
+ )
62
+ }
63
+
64
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,186 @@
1
+ import { Select as SelectPrimitive } from '@base-ui/react/select'
2
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
3
+ import type * as React from 'react'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const Select = SelectPrimitive.Root
7
+
8
+ function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
9
+ return (
10
+ <SelectPrimitive.Group
11
+ data-slot="select-group"
12
+ className={cn('scroll-my-1', className)}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
19
+ return (
20
+ <SelectPrimitive.Value
21
+ data-slot="select-value"
22
+ className={cn('flex flex-1 text-left', className)}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ function SelectTrigger({
29
+ className,
30
+ size = 'default',
31
+ children,
32
+ ...props
33
+ }: SelectPrimitive.Trigger.Props & {
34
+ size?: 'sm' | 'default'
35
+ }) {
36
+ return (
37
+ <SelectPrimitive.Trigger
38
+ data-slot="select-trigger"
39
+ data-size={size}
40
+ className={cn(
41
+ "flex w-fit items-center justify-between gap-1.5 rounded-[var(--radius)] border-[length:var(--border-width)] border-input bg-transparent py-2 pr-2 pl-2.5 text-xs whitespace-nowrap select-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[var(--radius)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <SelectPrimitive.Icon
48
+ render={<ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />}
49
+ />
50
+ </SelectPrimitive.Trigger>
51
+ )
52
+ }
53
+
54
+ function SelectContent({
55
+ className,
56
+ children,
57
+ side = 'bottom',
58
+ sideOffset = 6,
59
+ align = 'start',
60
+ alignOffset = 0,
61
+ alignItemWithTrigger = false,
62
+ ...props
63
+ }: SelectPrimitive.Popup.Props &
64
+ Pick<
65
+ SelectPrimitive.Positioner.Props,
66
+ 'align' | 'alignOffset' | 'side' | 'sideOffset' | 'alignItemWithTrigger'
67
+ >) {
68
+ return (
69
+ <SelectPrimitive.Portal>
70
+ <SelectPrimitive.Positioner
71
+ side={side}
72
+ sideOffset={sideOffset}
73
+ align={align}
74
+ alignOffset={alignOffset}
75
+ alignItemWithTrigger={alignItemWithTrigger}
76
+ className="isolate z-50"
77
+ >
78
+ <SelectPrimitive.Popup
79
+ data-slot="select-content"
80
+ className={cn(
81
+ 'relative isolate z-50 max-h-(--available-height) min-w-(--anchor-width) w-max 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 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:fade-out-0 data-closed:zoom-out-95',
82
+ className,
83
+ )}
84
+ {...props}
85
+ >
86
+ <SelectScrollUpButton />
87
+ <SelectPrimitive.List>{children}</SelectPrimitive.List>
88
+ <SelectScrollDownButton />
89
+ </SelectPrimitive.Popup>
90
+ </SelectPrimitive.Positioner>
91
+ </SelectPrimitive.Portal>
92
+ )
93
+ }
94
+
95
+ function SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {
96
+ return (
97
+ <SelectPrimitive.GroupLabel
98
+ data-slot="select-label"
99
+ className={cn('px-2 py-2 text-xs text-muted-foreground', className)}
100
+ {...props}
101
+ />
102
+ )
103
+ }
104
+
105
+ function SelectItem({ className, children, ...props }: SelectPrimitive.Item.Props) {
106
+ return (
107
+ <SelectPrimitive.Item
108
+ data-slot="select-item"
109
+ className={cn(
110
+ "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 focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**: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 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
111
+ className,
112
+ )}
113
+ {...props}
114
+ >
115
+ <SelectPrimitive.ItemText className="flex flex-1 shrink-0 gap-2 whitespace-nowrap">
116
+ {children}
117
+ </SelectPrimitive.ItemText>
118
+ <SelectPrimitive.ItemIndicator
119
+ render={
120
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
121
+ }
122
+ >
123
+ <CheckIcon className="pointer-events-none" />
124
+ </SelectPrimitive.ItemIndicator>
125
+ </SelectPrimitive.Item>
126
+ )
127
+ }
128
+
129
+ function SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {
130
+ return (
131
+ <SelectPrimitive.Separator
132
+ data-slot="select-separator"
133
+ className={cn('pointer-events-none -mx-1 h-[length:var(--border-width)] bg-border', className)}
134
+ {...props}
135
+ />
136
+ )
137
+ }
138
+
139
+ function SelectScrollUpButton({
140
+ className,
141
+ ...props
142
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
143
+ return (
144
+ <SelectPrimitive.ScrollUpArrow
145
+ data-slot="select-scroll-up-button"
146
+ className={cn(
147
+ "top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
148
+ className,
149
+ )}
150
+ {...props}
151
+ >
152
+ <ChevronUpIcon />
153
+ </SelectPrimitive.ScrollUpArrow>
154
+ )
155
+ }
156
+
157
+ function SelectScrollDownButton({
158
+ className,
159
+ ...props
160
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
161
+ return (
162
+ <SelectPrimitive.ScrollDownArrow
163
+ data-slot="select-scroll-down-button"
164
+ className={cn(
165
+ "bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
166
+ className,
167
+ )}
168
+ {...props}
169
+ >
170
+ <ChevronDownIcon />
171
+ </SelectPrimitive.ScrollDownArrow>
172
+ )
173
+ }
174
+
175
+ export {
176
+ Select,
177
+ SelectContent,
178
+ SelectGroup,
179
+ SelectItem,
180
+ SelectLabel,
181
+ SelectScrollDownButton,
182
+ SelectScrollUpButton,
183
+ SelectSeparator,
184
+ SelectTrigger,
185
+ SelectValue,
186
+ }
@@ -0,0 +1,21 @@
1
+ 'use client'
2
+
3
+ import { Separator as SeparatorPrimitive } from '@base-ui/react/separator'
4
+
5
+ import { cn } from '@/lib/utils'
6
+
7
+ function Separator({ className, orientation = 'horizontal', ...props }: SeparatorPrimitive.Props) {
8
+ return (
9
+ <SeparatorPrimitive
10
+ data-slot="separator"
11
+ orientation={orientation}
12
+ className={cn(
13
+ 'shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch',
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ export { Separator }
@@ -0,0 +1,134 @@
1
+ 'use client'
2
+
3
+ import { Dialog as DialogPrimitive } from '@base-ui/react/dialog'
4
+ import { XIcon } from 'lucide-react'
5
+ import * as React from 'react'
6
+ import { cn } from '@/lib/utils'
7
+
8
+ type SheetSide = 'top' | 'bottom' | 'left' | 'right'
9
+
10
+ function Sheet({ ...props }: DialogPrimitive.Root.Props) {
11
+ return <DialogPrimitive.Root data-slot="sheet" {...props} />
12
+ }
13
+
14
+ function SheetTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
15
+ return <DialogPrimitive.Trigger data-slot="sheet-trigger" {...props} />
16
+ }
17
+
18
+ function SheetClose({ ...props }: DialogPrimitive.Close.Props) {
19
+ return <DialogPrimitive.Close data-slot="sheet-close" {...props} />
20
+ }
21
+
22
+ function SheetPortal({ ...props }: DialogPrimitive.Portal.Props) {
23
+ return <DialogPrimitive.Portal data-slot="sheet-portal" {...props} />
24
+ }
25
+
26
+ function SheetOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {
27
+ return (
28
+ <DialogPrimitive.Backdrop
29
+ data-slot="sheet-overlay"
30
+ className={cn(
31
+ 'fixed inset-0 z-50 bg-black/20 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
32
+ className,
33
+ )}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ const sheetSideClasses: Record<SheetSide, string> = {
40
+ top: 'inset-x-0 top-0 border-b-[length:var(--border-width)] data-open:slide-in-from-top data-closed:slide-out-to-top',
41
+ bottom: 'inset-x-0 bottom-0 border-t-[length:var(--border-width)] data-open:slide-in-from-bottom data-closed:slide-out-to-bottom',
42
+ left: 'inset-y-0 left-0 h-full w-3/4 sm:max-w-sm border-r-[length:var(--border-width)] data-open:slide-in-from-left data-closed:slide-out-to-left',
43
+ right: 'inset-y-0 right-0 h-full w-3/4 sm:max-w-sm border-l-[length:var(--border-width)] data-open:slide-in-from-right data-closed:slide-out-to-right',
44
+ }
45
+
46
+ function SheetContent({
47
+ side = 'right',
48
+ className,
49
+ children,
50
+ showCloseButton = true,
51
+ ...props
52
+ }: DialogPrimitive.Popup.Props & {
53
+ side?: SheetSide
54
+ showCloseButton?: boolean
55
+ }) {
56
+ return (
57
+ <SheetPortal>
58
+ <SheetOverlay />
59
+ <DialogPrimitive.Popup
60
+ data-slot="sheet-content"
61
+ className={cn(
62
+ 'fixed z-50 flex flex-col gap-4 rounded-[var(--radius)] border-foreground bg-card p-6 text-xs/relaxed text-card-foreground duration-200 outline-none data-open:animate-in data-closed:animate-out',
63
+ sheetSideClasses[side],
64
+ className,
65
+ )}
66
+ {...props}
67
+ >
68
+ {showCloseButton && (
69
+ <DialogPrimitive.Close
70
+ data-slot="sheet-close"
71
+ className="absolute top-4 right-4 flex size-6 items-center justify-center text-muted-foreground hover:text-foreground"
72
+ aria-label="Close"
73
+ >
74
+ <XIcon className="size-4" />
75
+ </DialogPrimitive.Close>
76
+ )}
77
+ {children}
78
+ </DialogPrimitive.Popup>
79
+ </SheetPortal>
80
+ )
81
+ }
82
+
83
+ function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
84
+ return (
85
+ <div
86
+ data-slot="sheet-header"
87
+ className={cn('flex flex-col gap-1', className)}
88
+ {...props}
89
+ />
90
+ )
91
+ }
92
+
93
+ function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
94
+ return (
95
+ <div
96
+ data-slot="sheet-footer"
97
+ className={cn('mt-auto flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
98
+ {...props}
99
+ />
100
+ )
101
+ }
102
+
103
+ function SheetTitle({ className, ...props }: DialogPrimitive.Title.Props) {
104
+ return (
105
+ <DialogPrimitive.Title
106
+ data-slot="sheet-title"
107
+ className={cn('text-sm font-medium uppercase tracking-wider', className)}
108
+ {...props}
109
+ />
110
+ )
111
+ }
112
+
113
+ function SheetDescription({ className, ...props }: DialogPrimitive.Description.Props) {
114
+ return (
115
+ <DialogPrimitive.Description
116
+ data-slot="sheet-description"
117
+ className={cn('text-xs/relaxed text-muted-foreground', className)}
118
+ {...props}
119
+ />
120
+ )
121
+ }
122
+
123
+ export {
124
+ Sheet,
125
+ SheetTrigger,
126
+ SheetClose,
127
+ SheetPortal,
128
+ SheetOverlay,
129
+ SheetContent,
130
+ SheetHeader,
131
+ SheetFooter,
132
+ SheetTitle,
133
+ SheetDescription,
134
+ }