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