@pago-sh/ui 1.0.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 (229) hide show
  1. package/.turbo/turbo-build.log +195 -0
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +22 -0
  4. package/components.json +17 -0
  5. package/dist/chunk-2RCGDEGJ.mjs +1 -0
  6. package/dist/chunk-3GDNSYGJ.mjs +1 -0
  7. package/dist/chunk-4TCUGB6E.mjs +1 -0
  8. package/dist/chunk-6XCXQA5L.mjs +1 -0
  9. package/dist/chunk-BBYR3CIF.mjs +1 -0
  10. package/dist/chunk-CFBUY7KY.mjs +1 -0
  11. package/dist/chunk-CHG2VB73.mjs +1 -0
  12. package/dist/chunk-GCVBVZU7.mjs +1 -0
  13. package/dist/chunk-HRGUR4R2.mjs +1 -0
  14. package/dist/chunk-IVU4SSCD.mjs +1 -0
  15. package/dist/chunk-N6WI5TGM.mjs +1 -0
  16. package/dist/chunk-OTKGECM3.mjs +1 -0
  17. package/dist/chunk-SRZFZUN4.mjs +1 -0
  18. package/dist/chunk-VPECET7P.mjs +1 -0
  19. package/dist/chunk-WQPSZXQS.mjs +1 -0
  20. package/dist/chunk-YXNT3UEO.mjs +1 -0
  21. package/dist/components/atoms/Accordion.d.mts +20 -0
  22. package/dist/components/atoms/Accordion.d.ts +20 -0
  23. package/dist/components/atoms/Accordion.js +1 -0
  24. package/dist/components/atoms/Accordion.mjs +1 -0
  25. package/dist/components/atoms/Card.d.mts +18 -0
  26. package/dist/components/atoms/Card.d.ts +18 -0
  27. package/dist/components/atoms/Card.js +1 -0
  28. package/dist/components/atoms/Card.mjs +1 -0
  29. package/dist/components/atoms/Combobox.d.mts +24 -0
  30. package/dist/components/atoms/Combobox.d.ts +24 -0
  31. package/dist/components/atoms/Combobox.js +1 -0
  32. package/dist/components/atoms/Combobox.mjs +1 -0
  33. package/dist/components/atoms/CopyToClipboardInput.d.mts +12 -0
  34. package/dist/components/atoms/CopyToClipboardInput.d.ts +12 -0
  35. package/dist/components/atoms/CopyToClipboardInput.js +1 -0
  36. package/dist/components/atoms/CopyToClipboardInput.mjs +1 -0
  37. package/dist/components/atoms/CountryPicker.d.mts +16 -0
  38. package/dist/components/atoms/CountryPicker.d.ts +16 -0
  39. package/dist/components/atoms/CountryPicker.js +1 -0
  40. package/dist/components/atoms/CountryPicker.mjs +1 -0
  41. package/dist/components/atoms/CountryStatePicker.d.mts +18 -0
  42. package/dist/components/atoms/CountryStatePicker.d.ts +18 -0
  43. package/dist/components/atoms/CountryStatePicker.js +1 -0
  44. package/dist/components/atoms/CountryStatePicker.mjs +1 -0
  45. package/dist/components/atoms/DateTimePicker.d.mts +10 -0
  46. package/dist/components/atoms/DateTimePicker.d.ts +10 -0
  47. package/dist/components/atoms/DateTimePicker.js +1 -0
  48. package/dist/components/atoms/DateTimePicker.mjs +1 -0
  49. package/dist/components/atoms/DropdownMenu.d.mts +22 -0
  50. package/dist/components/atoms/DropdownMenu.d.ts +22 -0
  51. package/dist/components/atoms/DropdownMenu.js +1 -0
  52. package/dist/components/atoms/DropdownMenu.mjs +1 -0
  53. package/dist/components/atoms/FormattedDateTime.d.mts +10 -0
  54. package/dist/components/atoms/FormattedDateTime.d.ts +10 -0
  55. package/dist/components/atoms/FormattedDateTime.js +1 -0
  56. package/dist/components/atoms/FormattedDateTime.mjs +1 -0
  57. package/dist/components/atoms/FormattedInterval.d.mts +9 -0
  58. package/dist/components/atoms/FormattedInterval.d.ts +9 -0
  59. package/dist/components/atoms/FormattedInterval.js +1 -0
  60. package/dist/components/atoms/FormattedInterval.mjs +1 -0
  61. package/dist/components/atoms/InputOTP.d.mts +4 -0
  62. package/dist/components/atoms/InputOTP.d.ts +4 -0
  63. package/dist/components/atoms/InputOTP.js +1 -0
  64. package/dist/components/atoms/InputOTP.mjs +1 -0
  65. package/dist/components/atoms/MoneyInput.d.mts +21 -0
  66. package/dist/components/atoms/MoneyInput.d.ts +21 -0
  67. package/dist/components/atoms/MoneyInput.js +1 -0
  68. package/dist/components/atoms/MoneyInput.mjs +1 -0
  69. package/dist/components/atoms/Paginator.d.mts +21 -0
  70. package/dist/components/atoms/Paginator.d.ts +21 -0
  71. package/dist/components/atoms/Paginator.js +1 -0
  72. package/dist/components/atoms/Paginator.mjs +1 -0
  73. package/dist/components/atoms/PagoTimeAgo.d.mts +8 -0
  74. package/dist/components/atoms/PagoTimeAgo.d.ts +8 -0
  75. package/dist/components/atoms/PagoTimeAgo.js +1 -0
  76. package/dist/components/atoms/PagoTimeAgo.mjs +1 -0
  77. package/dist/components/atoms/PercentageInput.d.mts +19 -0
  78. package/dist/components/atoms/PercentageInput.d.ts +19 -0
  79. package/dist/components/atoms/PercentageInput.js +1 -0
  80. package/dist/components/atoms/PercentageInput.mjs +1 -0
  81. package/dist/components/atoms/ShadowBox.d.mts +14 -0
  82. package/dist/components/atoms/ShadowBox.d.ts +14 -0
  83. package/dist/components/atoms/ShadowBox.js +1 -0
  84. package/dist/components/atoms/ShadowBox.mjs +1 -0
  85. package/dist/components/atoms/ShadowBoxOnMd.d.mts +6 -0
  86. package/dist/components/atoms/ShadowBoxOnMd.d.ts +6 -0
  87. package/dist/components/atoms/ShadowBoxOnMd.js +1 -0
  88. package/dist/components/atoms/ShadowBoxOnMd.mjs +1 -0
  89. package/dist/components/atoms/Sidebar.d.mts +11 -0
  90. package/dist/components/atoms/Sidebar.d.ts +11 -0
  91. package/dist/components/atoms/Sidebar.js +1 -0
  92. package/dist/components/atoms/Sidebar.mjs +1 -0
  93. package/dist/components/molecules/Banner.d.mts +11 -0
  94. package/dist/components/molecules/Banner.d.ts +11 -0
  95. package/dist/components/molecules/Banner.js +1 -0
  96. package/dist/components/molecules/Banner.mjs +1 -0
  97. package/dist/components/ui/accordion.d.mts +19 -0
  98. package/dist/components/ui/accordion.d.ts +19 -0
  99. package/dist/components/ui/accordion.js +1 -0
  100. package/dist/components/ui/accordion.mjs +1 -0
  101. package/dist/components/ui/alert-dialog.d.mts +41 -0
  102. package/dist/components/ui/alert-dialog.d.ts +41 -0
  103. package/dist/components/ui/alert-dialog.js +1 -0
  104. package/dist/components/ui/alert-dialog.mjs +1 -0
  105. package/dist/components/ui/calendar.d.mts +12 -0
  106. package/dist/components/ui/calendar.d.ts +12 -0
  107. package/dist/components/ui/calendar.js +1 -0
  108. package/dist/components/ui/calendar.mjs +1 -0
  109. package/dist/components/ui/card.d.mts +23 -0
  110. package/dist/components/ui/card.d.ts +23 -0
  111. package/dist/components/ui/card.js +1 -0
  112. package/dist/components/ui/card.mjs +1 -0
  113. package/dist/components/ui/chart.d.mts +55 -0
  114. package/dist/components/ui/chart.d.ts +55 -0
  115. package/dist/components/ui/chart.js +7 -0
  116. package/dist/components/ui/chart.mjs +7 -0
  117. package/dist/components/ui/checkbox.d.mts +2 -0
  118. package/dist/components/ui/checkbox.d.ts +2 -0
  119. package/dist/components/ui/checkbox.js +1 -0
  120. package/dist/components/ui/checkbox.mjs +1 -0
  121. package/dist/components/ui/command.d.mts +36 -0
  122. package/dist/components/ui/command.d.ts +36 -0
  123. package/dist/components/ui/command.js +1 -0
  124. package/dist/components/ui/command.mjs +1 -0
  125. package/dist/components/ui/dialog.d.mts +34 -0
  126. package/dist/components/ui/dialog.d.ts +34 -0
  127. package/dist/components/ui/dialog.js +1 -0
  128. package/dist/components/ui/dialog.mjs +1 -0
  129. package/dist/components/ui/dropdown-menu.d.mts +23 -0
  130. package/dist/components/ui/dropdown-menu.d.ts +23 -0
  131. package/dist/components/ui/dropdown-menu.js +1 -0
  132. package/dist/components/ui/dropdown-menu.mjs +1 -0
  133. package/dist/components/ui/form.d.mts +43 -0
  134. package/dist/components/ui/form.d.ts +43 -0
  135. package/dist/components/ui/form.js +1 -0
  136. package/dist/components/ui/form.mjs +1 -0
  137. package/dist/components/ui/input-otp.d.mts +21 -0
  138. package/dist/components/ui/input-otp.d.ts +21 -0
  139. package/dist/components/ui/input-otp.js +1 -0
  140. package/dist/components/ui/input-otp.mjs +1 -0
  141. package/dist/components/ui/label.d.mts +9 -0
  142. package/dist/components/ui/label.d.ts +9 -0
  143. package/dist/components/ui/label.js +1 -0
  144. package/dist/components/ui/label.mjs +1 -0
  145. package/dist/components/ui/popover.d.mts +12 -0
  146. package/dist/components/ui/popover.d.ts +12 -0
  147. package/dist/components/ui/popover.js +1 -0
  148. package/dist/components/ui/popover.mjs +1 -0
  149. package/dist/components/ui/radio-group.d.mts +14 -0
  150. package/dist/components/ui/radio-group.d.ts +14 -0
  151. package/dist/components/ui/radio-group.js +1 -0
  152. package/dist/components/ui/radio-group.mjs +1 -0
  153. package/dist/components/ui/separator.d.mts +10 -0
  154. package/dist/components/ui/separator.d.ts +10 -0
  155. package/dist/components/ui/separator.js +1 -0
  156. package/dist/components/ui/separator.mjs +1 -0
  157. package/dist/components/ui/sheet.d.mts +43 -0
  158. package/dist/components/ui/sheet.d.ts +43 -0
  159. package/dist/components/ui/sheet.js +1 -0
  160. package/dist/components/ui/sheet.mjs +1 -0
  161. package/dist/components/ui/sidebar.d.mts +149 -0
  162. package/dist/components/ui/sidebar.d.ts +149 -0
  163. package/dist/components/ui/sidebar.js +1 -0
  164. package/dist/components/ui/sidebar.mjs +1 -0
  165. package/dist/components/ui/tooltip.d.mts +1 -0
  166. package/dist/components/ui/tooltip.d.ts +1 -0
  167. package/dist/components/ui/tooltip.js +1 -0
  168. package/dist/components/ui/tooltip.mjs +1 -0
  169. package/dist/hooks/theming.d.mts +76 -0
  170. package/dist/hooks/theming.d.ts +76 -0
  171. package/dist/hooks/theming.js +1 -0
  172. package/dist/hooks/theming.mjs +1 -0
  173. package/dist/hooks/use-mobile.d.mts +3 -0
  174. package/dist/hooks/use-mobile.d.ts +3 -0
  175. package/dist/hooks/use-mobile.js +1 -0
  176. package/dist/hooks/use-mobile.mjs +1 -0
  177. package/dist/lib/meterUnit.d.mts +34 -0
  178. package/dist/lib/meterUnit.d.ts +34 -0
  179. package/dist/lib/meterUnit.js +1 -0
  180. package/dist/lib/meterUnit.mjs +1 -0
  181. package/dist/lib/utils.d.mts +5 -0
  182. package/dist/lib/utils.d.ts +5 -0
  183. package/dist/lib/utils.js +1 -0
  184. package/dist/lib/utils.mjs +1 -0
  185. package/eslint.config.mjs +18 -0
  186. package/package.json +74 -0
  187. package/src/components/atoms/Accordion.tsx +56 -0
  188. package/src/components/atoms/Card.tsx +52 -0
  189. package/src/components/atoms/Combobox.tsx +166 -0
  190. package/src/components/atoms/CopyToClipboardInput.tsx +72 -0
  191. package/src/components/atoms/CountryPicker.tsx +81 -0
  192. package/src/components/atoms/CountryStatePicker.tsx +155 -0
  193. package/src/components/atoms/DateTimePicker.tsx +69 -0
  194. package/src/components/atoms/DropdownMenu.tsx +68 -0
  195. package/src/components/atoms/FormattedDateTime.tsx +58 -0
  196. package/src/components/atoms/FormattedInterval.tsx +81 -0
  197. package/src/components/atoms/InputOTP.tsx +7 -0
  198. package/src/components/atoms/MoneyInput.tsx +297 -0
  199. package/src/components/atoms/Paginator.tsx +227 -0
  200. package/src/components/atoms/PagoTimeAgo.tsx +19 -0
  201. package/src/components/atoms/PercentageInput.tsx +97 -0
  202. package/src/components/atoms/ShadowBox.tsx +26 -0
  203. package/src/components/atoms/ShadowBoxOnMd.tsx +20 -0
  204. package/src/components/atoms/Sidebar.tsx +1 -0
  205. package/src/components/molecules/Banner.tsx +42 -0
  206. package/src/components/ui/accordion.tsx +63 -0
  207. package/src/components/ui/alert-dialog.tsx +147 -0
  208. package/src/components/ui/calendar.tsx +81 -0
  209. package/src/components/ui/card.tsx +47 -0
  210. package/src/components/ui/chart.tsx +372 -0
  211. package/src/components/ui/checkbox.tsx +3 -0
  212. package/src/components/ui/command.tsx +133 -0
  213. package/src/components/ui/dialog.tsx +127 -0
  214. package/src/components/ui/dropdown-menu.tsx +74 -0
  215. package/src/components/ui/form.tsx +180 -0
  216. package/src/components/ui/input-otp.tsx +68 -0
  217. package/src/components/ui/label.tsx +25 -0
  218. package/src/components/ui/popover.tsx +34 -0
  219. package/src/components/ui/radio-group.tsx +46 -0
  220. package/src/components/ui/separator.tsx +29 -0
  221. package/src/components/ui/sheet.tsx +149 -0
  222. package/src/components/ui/sidebar.tsx +742 -0
  223. package/src/components/ui/tooltip.tsx +8 -0
  224. package/src/hooks/theming.ts +87 -0
  225. package/src/hooks/use-mobile.ts +19 -0
  226. package/src/lib/meterUnit.ts +52 -0
  227. package/src/lib/utils.ts +6 -0
  228. package/tsconfig.json +15 -0
  229. package/tsup.config.ts +11 -0
@@ -0,0 +1,742 @@
1
+ 'use client'
2
+
3
+ import { Slot } from '@radix-ui/react-slot'
4
+ import { cva } from 'class-variance-authority'
5
+ import { PanelLeft } from 'lucide-react'
6
+ import * as React from 'react'
7
+
8
+ import { Button } from '@pago-sh/orbit/ui/button'
9
+ import { Input } from '@pago-sh/orbit/ui/input'
10
+ import { Separator } from '@/components/ui/separator'
11
+ import { Sheet, SheetContent } from '@/components/ui/sheet'
12
+ import {
13
+ Tooltip,
14
+ TooltipContent,
15
+ TooltipProvider,
16
+ TooltipTrigger,
17
+ } from '@/components/ui/tooltip'
18
+ import { useIsMobile } from '@/hooks/use-mobile'
19
+ import { cn } from '@/lib/utils'
20
+ import { ComponentProps } from 'react'
21
+
22
+ const SIDEBAR_COOKIE_NAME = 'sidebar_state'
23
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
24
+ const SIDEBAR_WIDTH = '14rem'
25
+ const SIDEBAR_WIDTH_MOBILE = '18rem'
26
+ const SIDEBAR_WIDTH_ICON = '3rem'
27
+ const SIDEBAR_KEYBOARD_SHORTCUT = 'b'
28
+
29
+ type SidebarContext = {
30
+ state: 'expanded' | 'collapsed'
31
+ open: boolean
32
+ setOpen: (open: boolean) => void
33
+ openMobile: boolean
34
+ setOpenMobile: (open: boolean) => void
35
+ isMobile: boolean
36
+ toggleSidebar: () => void
37
+ }
38
+
39
+ const SidebarContext = React.createContext<SidebarContext | null>(null)
40
+
41
+ function useSidebar() {
42
+ const context = React.useContext(SidebarContext)
43
+ if (!context) {
44
+ throw new Error('useSidebar must be used within a SidebarProvider.')
45
+ }
46
+
47
+ return context
48
+ }
49
+
50
+ const SidebarProvider = ({
51
+ ref,
52
+ defaultOpen = true,
53
+ open: openProp,
54
+ onOpenChange: setOpenProp,
55
+ className,
56
+ style,
57
+ children,
58
+ ...props
59
+ }: {
60
+ ref?: React.RefObject<HTMLDivElement>
61
+ defaultOpen?: boolean
62
+ open?: boolean
63
+ onOpenChange?: (open: boolean) => void
64
+ className?: string
65
+ style?: React.CSSProperties
66
+ children: React.ReactNode
67
+ } & React.ComponentProps<'div'>) => {
68
+ const isMobile = useIsMobile()
69
+ const [openMobile, setOpenMobile] = React.useState(false)
70
+
71
+ // This is the internal state of the sidebar.
72
+ // We use openProp and setOpenProp for control from outside the component.
73
+ const [_open, _setOpen] = React.useState(defaultOpen)
74
+ const open = openProp ?? _open
75
+ const setOpen = React.useCallback(
76
+ (value: boolean | ((value: boolean) => boolean)) => {
77
+ const openState = typeof value === 'function' ? value(open) : value
78
+ if (setOpenProp) {
79
+ setOpenProp(openState)
80
+ } else {
81
+ _setOpen(openState)
82
+ }
83
+
84
+ // This sets the cookie to keep the sidebar state.
85
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
86
+ },
87
+ [setOpenProp, open],
88
+ )
89
+
90
+ // Helper to toggle the sidebar.
91
+ const toggleSidebar = React.useCallback(() => {
92
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
93
+ }, [isMobile, setOpen, setOpenMobile])
94
+
95
+ // Adds a keyboard shortcut to toggle the sidebar.
96
+ React.useEffect(() => {
97
+ const handleKeyDown = (event: KeyboardEvent) => {
98
+ if (
99
+ event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
100
+ (event.metaKey || event.ctrlKey)
101
+ ) {
102
+ event.preventDefault()
103
+ toggleSidebar()
104
+ }
105
+ }
106
+
107
+ window.addEventListener('keydown', handleKeyDown)
108
+ return () => window.removeEventListener('keydown', handleKeyDown)
109
+ }, [toggleSidebar])
110
+
111
+ // We add a state so that we can do data-state="expanded" or "collapsed".
112
+ // This makes it easier to style the sidebar with Tailwind classes.
113
+ const state = open ? 'expanded' : 'collapsed'
114
+
115
+ const contextValue = React.useMemo<SidebarContext>(
116
+ () => ({
117
+ state,
118
+ open,
119
+ setOpen,
120
+ isMobile,
121
+ openMobile,
122
+ setOpenMobile,
123
+ toggleSidebar,
124
+ }),
125
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
126
+ )
127
+
128
+ return (
129
+ <SidebarContext.Provider value={contextValue}>
130
+ <TooltipProvider delayDuration={0}>
131
+ <div
132
+ style={
133
+ {
134
+ '--sidebar-width': SIDEBAR_WIDTH,
135
+ '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
136
+ ...style,
137
+ } as React.CSSProperties
138
+ }
139
+ className={cn(
140
+ 'group/sidebar-wrapper has-[[data-variant=inset]]:bg-sidebar flex min-h-svh w-full lg:overflow-clip',
141
+ className,
142
+ )}
143
+ ref={ref}
144
+ {...props}
145
+ >
146
+ {children}
147
+ </div>
148
+ </TooltipProvider>
149
+ </SidebarContext.Provider>
150
+ )
151
+ }
152
+ SidebarProvider.displayName = 'SidebarProvider'
153
+
154
+ const Sidebar = ({
155
+ ref,
156
+ side = 'left',
157
+ variant = 'sidebar',
158
+ collapsible = 'offcanvas',
159
+ className,
160
+ children,
161
+ ...props
162
+ }: {
163
+ ref?: React.RefObject<HTMLDivElement>
164
+ side?: ComponentProps<typeof SheetContent>['side']
165
+ variant?: 'sidebar' | 'floating' | 'inset'
166
+ collapsible?: 'none' | 'offcanvas' | 'icon'
167
+ className?: string
168
+ children: React.ReactNode
169
+ } & React.ComponentProps<typeof Sheet>) => {
170
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
171
+
172
+ if (collapsible === 'none') {
173
+ return (
174
+ <div
175
+ className={cn(
176
+ 'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
177
+ className,
178
+ )}
179
+ ref={ref}
180
+ {...props}
181
+ >
182
+ {children}
183
+ </div>
184
+ )
185
+ }
186
+
187
+ if (isMobile) {
188
+ return (
189
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
190
+ <SheetContent
191
+ data-sidebar="sidebar"
192
+ data-mobile="true"
193
+ className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
194
+ style={
195
+ {
196
+ '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
197
+ } as React.CSSProperties
198
+ }
199
+ side={side}
200
+ >
201
+ <div className="flex h-full w-full flex-col">{children}</div>
202
+ </SheetContent>
203
+ </Sheet>
204
+ )
205
+ }
206
+
207
+ return (
208
+ <div
209
+ ref={ref}
210
+ className="text-sidebar-foreground group peer hidden md:block"
211
+ data-state={state}
212
+ data-collapsible={state === 'collapsed' ? collapsible : ''}
213
+ data-variant={variant}
214
+ data-side={side}
215
+ >
216
+ {/* This is what handles the sidebar gap on desktop */}
217
+ <div
218
+ className={cn(
219
+ 'relative h-svh w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
220
+ 'group-data-[collapsible=offcanvas]:w-0',
221
+ 'group-data-[side=right]:rotate-180',
222
+ variant === 'floating' || variant === 'inset'
223
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
224
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
225
+ )}
226
+ />
227
+ <div
228
+ className={cn(
229
+ 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
230
+ side === 'left'
231
+ ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
232
+ : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
233
+ // Adjust the padding for floating and inset variants.
234
+ variant === 'floating' || variant === 'inset'
235
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
236
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
237
+ className,
238
+ )}
239
+ {...props}
240
+ >
241
+ <div
242
+ data-sidebar="sidebar"
243
+ className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
244
+ >
245
+ {children}
246
+ </div>
247
+ </div>
248
+ </div>
249
+ )
250
+ }
251
+ Sidebar.displayName = 'Sidebar'
252
+
253
+ const SidebarTrigger = ({
254
+ ref,
255
+ className,
256
+ onClick,
257
+ ...props
258
+ }: React.ComponentProps<typeof Button>) => {
259
+ const { toggleSidebar } = useSidebar()
260
+
261
+ return (
262
+ <Button
263
+ ref={ref}
264
+ data-sidebar="trigger"
265
+ variant="ghost"
266
+ size="icon"
267
+ className={cn('h-7 w-7', className)}
268
+ onClick={(event) => {
269
+ onClick?.(event)
270
+ toggleSidebar()
271
+ }}
272
+ {...props}
273
+ >
274
+ <PanelLeft />
275
+ <span className="sr-only">Toggle Sidebar</span>
276
+ </Button>
277
+ )
278
+ }
279
+ SidebarTrigger.displayName = 'SidebarTrigger'
280
+
281
+ const SidebarRail = ({
282
+ ref,
283
+ className,
284
+ ...props
285
+ }: React.ComponentProps<'button'>) => {
286
+ const { toggleSidebar } = useSidebar()
287
+
288
+ return (
289
+ <button
290
+ ref={ref}
291
+ data-sidebar="rail"
292
+ aria-label="Toggle Sidebar"
293
+ tabIndex={-1}
294
+ onClick={toggleSidebar}
295
+ title="Toggle Sidebar"
296
+ className={cn(
297
+ 'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex',
298
+ 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
299
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
300
+ 'group-data-[collapsible=offcanvas]:hover:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
301
+ '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
302
+ '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
303
+ className,
304
+ )}
305
+ {...props}
306
+ />
307
+ )
308
+ }
309
+ SidebarRail.displayName = 'SidebarRail'
310
+
311
+ const SidebarInset = ({
312
+ ref,
313
+ className,
314
+ ...props
315
+ }: React.ComponentProps<'main'>) => {
316
+ return (
317
+ <main
318
+ ref={ref}
319
+ className={cn(
320
+ 'bg-background relative flex min-h-svh flex-1 flex-col',
321
+ 'peer-data-[variant=inset]:min-h-[calc(100svh-(--spacing(4)))] md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2',
322
+ className,
323
+ )}
324
+ {...props}
325
+ />
326
+ )
327
+ }
328
+ SidebarInset.displayName = 'SidebarInset'
329
+
330
+ const SidebarInput = ({
331
+ ref,
332
+ className,
333
+ ...props
334
+ }: React.ComponentProps<typeof Input>) => {
335
+ return (
336
+ <Input
337
+ ref={ref}
338
+ data-sidebar="input"
339
+ className={cn(
340
+ 'bg-background focus-visible:ring-sidebar-ring h-8 w-full shadow-none focus-visible:ring-2',
341
+ className,
342
+ )}
343
+ {...props}
344
+ />
345
+ )
346
+ }
347
+ SidebarInput.displayName = 'SidebarInput'
348
+
349
+ const SidebarHeader = ({
350
+ ref,
351
+ className,
352
+ ...props
353
+ }: React.ComponentProps<'div'>) => {
354
+ return (
355
+ <div
356
+ ref={ref}
357
+ data-sidebar="header"
358
+ className={cn('flex flex-col gap-2 p-2', className)}
359
+ {...props}
360
+ />
361
+ )
362
+ }
363
+ SidebarHeader.displayName = 'SidebarHeader'
364
+
365
+ const SidebarFooter = ({
366
+ ref,
367
+ className,
368
+ ...props
369
+ }: React.ComponentProps<'div'>) => {
370
+ return (
371
+ <div
372
+ ref={ref}
373
+ data-sidebar="footer"
374
+ className={cn('flex flex-col gap-2 p-2', className)}
375
+ {...props}
376
+ />
377
+ )
378
+ }
379
+ SidebarFooter.displayName = 'SidebarFooter'
380
+
381
+ const SidebarSeparator = ({
382
+ ref,
383
+ className,
384
+ ...props
385
+ }: React.ComponentProps<typeof Separator>) => {
386
+ return (
387
+ <Separator
388
+ ref={ref}
389
+ data-sidebar="separator"
390
+ className={cn('bg-sidebar-border mx-2 w-auto', className)}
391
+ {...props}
392
+ />
393
+ )
394
+ }
395
+ SidebarSeparator.displayName = 'SidebarSeparator'
396
+
397
+ const SidebarContent = ({
398
+ ref,
399
+ className,
400
+ ...props
401
+ }: React.ComponentProps<'div'>) => {
402
+ return (
403
+ <div
404
+ ref={ref}
405
+ data-sidebar="content"
406
+ className={cn(
407
+ 'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',
408
+ className,
409
+ )}
410
+ {...props}
411
+ />
412
+ )
413
+ }
414
+ SidebarContent.displayName = 'SidebarContent'
415
+
416
+ const SidebarGroup = ({
417
+ ref,
418
+ className,
419
+ ...props
420
+ }: React.ComponentProps<'div'>) => {
421
+ return (
422
+ <div
423
+ ref={ref}
424
+ data-sidebar="group"
425
+ className={cn('relative flex w-full min-w-0 flex-col p-2', className)}
426
+ {...props}
427
+ />
428
+ )
429
+ }
430
+ SidebarGroup.displayName = 'SidebarGroup'
431
+
432
+ const SidebarGroupLabel = ({
433
+ ref,
434
+ className,
435
+ asChild = false,
436
+ ...props
437
+ }: {
438
+ asChild?: boolean
439
+ } & React.ComponentProps<'div'>) => {
440
+ const Comp = asChild ? Slot : 'div'
441
+
442
+ return (
443
+ <Comp
444
+ ref={ref}
445
+ data-sidebar="group-label"
446
+ className={cn(
447
+ 'text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium transition-[margin,opacity] duration-200 ease-linear outline-none focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
448
+ 'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
449
+ className,
450
+ )}
451
+ {...props}
452
+ />
453
+ )
454
+ }
455
+ SidebarGroupLabel.displayName = 'SidebarGroupLabel'
456
+
457
+ const SidebarGroupAction = ({
458
+ ref,
459
+ className,
460
+ asChild = false,
461
+ ...props
462
+ }: {
463
+ asChild?: boolean
464
+ } & React.ComponentProps<'button'>) => {
465
+ const Comp = asChild ? Slot : 'button'
466
+
467
+ return (
468
+ <Comp
469
+ ref={ref}
470
+ data-sidebar="group-action"
471
+ className={cn(
472
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
473
+ // Increases the hit area of the button on mobile.
474
+ 'after:absolute after:-inset-2 after:md:hidden',
475
+ 'group-data-[collapsible=icon]:hidden',
476
+ className,
477
+ )}
478
+ {...props}
479
+ />
480
+ )
481
+ }
482
+ SidebarGroupAction.displayName = 'SidebarGroupAction'
483
+
484
+ const SidebarGroupContent = ({
485
+ ref,
486
+ className,
487
+ ...props
488
+ }: React.ComponentProps<'div'>) => (
489
+ <div
490
+ ref={ref}
491
+ data-sidebar="group-content"
492
+ className={cn('w-full text-sm', className)}
493
+ {...props}
494
+ />
495
+ )
496
+ SidebarGroupContent.displayName = 'SidebarGroupContent'
497
+
498
+ const SidebarMenu = ({
499
+ ref,
500
+ className,
501
+ ...props
502
+ }: React.ComponentProps<'ul'>) => (
503
+ <ul
504
+ ref={ref}
505
+ data-sidebar="menu"
506
+ className={cn('flex w-full min-w-0 flex-col gap-1', className)}
507
+ {...props}
508
+ />
509
+ )
510
+ SidebarMenu.displayName = 'SidebarMenu'
511
+
512
+ const SidebarMenuItem = ({
513
+ ref,
514
+ className,
515
+ ...props
516
+ }: React.ComponentProps<'li'> & {
517
+ ref?: React.RefObject<HTMLLIElement>
518
+ }) => (
519
+ <li
520
+ ref={ref}
521
+ data-sidebar="menu-item"
522
+ className={cn('group/menu-item relative', className)}
523
+ {...props}
524
+ />
525
+ )
526
+ SidebarMenuItem.displayName = 'SidebarMenuItem'
527
+
528
+ const sidebarMenuButtonVariants = cva(
529
+ 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-white dark:data-[active=true]:bg-transparent dark:data-[active=true]:border-transparent dark:data-[active=true]:text-white data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
530
+ {
531
+ variants: {
532
+ variant: {
533
+ default:
534
+ '[&:not([data-active=true])]:hover:bg-sidebar-accent [&:not([data-active=true])]:hover:text-sidebar-accent-foreground',
535
+ outline:
536
+ 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
537
+ },
538
+ size: {
539
+ default: 'h-8 text-sm',
540
+ sm: 'h-7 text-xs',
541
+ lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
542
+ },
543
+ },
544
+ defaultVariants: {
545
+ variant: 'default',
546
+ size: 'default',
547
+ },
548
+ },
549
+ )
550
+
551
+ const SidebarMenuButton = ({
552
+ ref,
553
+ asChild = false,
554
+ isActive = false,
555
+ variant = 'default',
556
+ size = 'default',
557
+ tooltip,
558
+ className,
559
+ ...props
560
+ }: {
561
+ asChild?: boolean
562
+ isActive?: boolean
563
+ variant?: 'default' | 'outline'
564
+ size?: 'default' | 'sm' | 'lg'
565
+ tooltip?: string | { children: string }
566
+ } & React.ComponentProps<'button'>) => {
567
+ const Comp = asChild ? Slot : 'button'
568
+ const { isMobile, state } = useSidebar()
569
+
570
+ const button = (
571
+ <Comp
572
+ ref={ref}
573
+ data-sidebar="menu-button"
574
+ data-size={size}
575
+ data-active={isActive}
576
+ className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
577
+ {...props}
578
+ />
579
+ )
580
+
581
+ if (!tooltip) {
582
+ return button
583
+ }
584
+
585
+ if (typeof tooltip === 'string') {
586
+ tooltip = {
587
+ children: tooltip,
588
+ }
589
+ }
590
+
591
+ return (
592
+ <Tooltip>
593
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
594
+ <TooltipContent
595
+ side="right"
596
+ align="center"
597
+ hidden={state !== 'collapsed' || isMobile}
598
+ {...tooltip}
599
+ />
600
+ </Tooltip>
601
+ )
602
+ }
603
+ SidebarMenuButton.displayName = 'SidebarMenuButton'
604
+
605
+ const SidebarMenuAction = ({
606
+ ref,
607
+ className,
608
+ asChild = false,
609
+ showOnHover = false,
610
+ ...props
611
+ }: {
612
+ asChild?: boolean
613
+ showOnHover?: boolean
614
+ } & React.ComponentProps<'button'>) => {
615
+ const Comp = asChild ? Slot : 'button'
616
+
617
+ return (
618
+ <Comp
619
+ ref={ref}
620
+ data-sidebar="menu-action"
621
+ className={cn(
622
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
623
+ // Increases the hit area of the button on mobile.
624
+ 'after:absolute after:-inset-2 after:md:hidden',
625
+ 'peer-data-[size=sm]/menu-button:top-1',
626
+ 'peer-data-[size=default]/menu-button:top-1.5',
627
+ 'peer-data-[size=lg]/menu-button:top-2.5',
628
+ 'group-data-[collapsible=icon]:hidden',
629
+ showOnHover &&
630
+ 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
631
+ className,
632
+ )}
633
+ {...props}
634
+ />
635
+ )
636
+ }
637
+ SidebarMenuAction.displayName = 'SidebarMenuAction'
638
+
639
+ const SidebarMenuBadge = ({
640
+ ref,
641
+ className,
642
+ ...props
643
+ }: React.ComponentProps<'div'>) => (
644
+ <div
645
+ ref={ref}
646
+ data-sidebar="menu-badge"
647
+ className={cn(
648
+ 'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none',
649
+ 'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
650
+ 'peer-data-[size=sm]/menu-button:top-1',
651
+ 'peer-data-[size=default]/menu-button:top-1.5',
652
+ 'peer-data-[size=lg]/menu-button:top-2.5',
653
+ 'group-data-[collapsible=icon]:hidden',
654
+ className,
655
+ )}
656
+ {...props}
657
+ />
658
+ )
659
+ SidebarMenuBadge.displayName = 'SidebarMenuBadge'
660
+
661
+ const SidebarMenuSub = ({
662
+ ref,
663
+ className,
664
+ ...props
665
+ }: React.ComponentProps<'ul'>) => (
666
+ <ul
667
+ ref={ref}
668
+ data-sidebar="menu-sub"
669
+ className={cn(
670
+ 'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
671
+ 'group-data-[collapsible=icon]:hidden',
672
+ className,
673
+ )}
674
+ {...props}
675
+ />
676
+ )
677
+ SidebarMenuSub.displayName = 'SidebarMenuSub'
678
+
679
+ const SidebarMenuSubItem = ({ ref, ...props }: React.ComponentProps<'li'>) => (
680
+ <li ref={ref} {...props} />
681
+ )
682
+ SidebarMenuSubItem.displayName = 'SidebarMenuSubItem'
683
+
684
+ const SidebarMenuSubButton = ({
685
+ ref,
686
+ asChild = false,
687
+ size = 'md',
688
+ isActive,
689
+ className,
690
+ ...props
691
+ }: {
692
+ asChild?: boolean
693
+ size?: 'sm' | 'md'
694
+ isActive?: boolean
695
+ } & React.ComponentProps<'a'>) => {
696
+ const Comp = asChild ? Slot : 'a'
697
+
698
+ return (
699
+ <Comp
700
+ ref={ref}
701
+ data-sidebar="menu-sub-button"
702
+ data-size={size}
703
+ data-active={isActive}
704
+ className={cn(
705
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
706
+ 'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
707
+ size === 'sm' && 'text-xs',
708
+ size === 'md' && 'text-sm',
709
+ 'group-data-[collapsible=icon]:hidden',
710
+ className,
711
+ )}
712
+ {...props}
713
+ />
714
+ )
715
+ }
716
+ SidebarMenuSubButton.displayName = 'SidebarMenuSubButton'
717
+
718
+ export {
719
+ Sidebar,
720
+ SidebarContent,
721
+ SidebarFooter,
722
+ SidebarGroup,
723
+ SidebarGroupAction,
724
+ SidebarGroupContent,
725
+ SidebarGroupLabel,
726
+ SidebarHeader,
727
+ SidebarInput,
728
+ SidebarInset,
729
+ SidebarMenu,
730
+ SidebarMenuAction,
731
+ SidebarMenuBadge,
732
+ SidebarMenuButton,
733
+ SidebarMenuItem,
734
+ SidebarMenuSub,
735
+ SidebarMenuSubButton,
736
+ SidebarMenuSubItem,
737
+ SidebarProvider,
738
+ SidebarRail,
739
+ SidebarSeparator,
740
+ SidebarTrigger,
741
+ useSidebar,
742
+ }