@exegia/corpora-ui 0.9.0 → 0.11.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-lib/components/agents/ai-sidebar.d.ts +2 -0
- package/dist-lib/components/agents/index.d.ts +12 -0
- package/dist-lib/components/agents/marquee-label.d.ts +4 -0
- package/dist-lib/components/agents/sidebar-icon.d.ts +2 -0
- package/dist-lib/components/agents/sidebar-row.d.ts +2 -0
- package/dist-lib/components/agents/type.d.ts +77 -0
- package/dist-lib/components/agents/use-ai-sidebar.d.ts +31 -0
- package/dist-lib/components/agents/utils.d.ts +16 -0
- package/dist-lib/components/beste/piece/browser-frame.d.ts +2 -0
- package/dist-lib/components/beste/piece/type.d.ts +9 -0
- package/dist-lib/components/beste/piece/utils.d.ts +3 -0
- package/dist-lib/components/blocks/auth/linked-accounts-block.d.ts +7 -1
- package/dist-lib/components/blocks/auth/signup-block.d.ts +5 -5
- package/dist-lib/components/blocks/nav/sidebar-block.d.ts +3 -56
- package/dist-lib/components/blocks/nav/sidebar-nav-row.d.ts +3 -0
- package/dist-lib/components/blocks/nav/types.d.ts +60 -0
- package/dist-lib/components/blocks/nav/utils.d.ts +1 -0
- package/dist-lib/components/blocks/profile/profile-card-block.d.ts +6 -1
- package/dist-lib/components/blocks/shell/index.d.ts +1 -0
- package/dist-lib/components/blocks/shell/shell-layout.d.ts +3 -0
- package/dist-lib/components/blocks/shell/type.d.ts +26 -0
- package/dist-lib/components/blocks/shell/utils.d.ts +1 -0
- package/dist-lib/components/composed/social-providers.d.ts +9 -1
- package/dist-lib/components/docs/demo-controls.d.ts +4 -4
- package/dist-lib/components/motion/animated-sidebar.d.ts +12 -1
- package/dist-lib/components/motion/popover-morph.d.ts +35 -0
- package/dist-lib/components/motion/popover-position.d.ts +15 -0
- package/dist-lib/components/ui/badge.d.ts +7 -0
- package/dist-lib/components/ui/select.d.ts +30 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.js +669 -549
- package/dist-lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/agents/ai-sidebar.tsx +116 -0
- package/src/components/agents/index.ts +14 -0
- package/src/components/agents/marquee-label.tsx +59 -0
- package/src/components/agents/sidebar-icon.tsx +14 -0
- package/src/components/agents/sidebar-row.tsx +271 -0
- package/src/components/agents/type.ts +89 -0
- package/src/components/agents/use-ai-sidebar.ts +386 -0
- package/src/components/agents/utils.ts +142 -0
- package/src/components/beste/piece/browser-frame.tsx +55 -0
- package/src/components/beste/piece/type.ts +11 -0
- package/src/components/beste/piece/utils.ts +21 -0
- package/src/components/blocks/auth/__tests__/linked-accounts-block.test.tsx +18 -0
- package/src/components/blocks/auth/linked-accounts-block.tsx +63 -57
- package/src/components/blocks/auth/passkey-manager-block.tsx +88 -81
- package/src/components/blocks/auth/signup-block.tsx +6 -6
- package/src/components/blocks/nav/sidebar-block.tsx +25 -155
- package/src/components/blocks/nav/sidebar-nav-row.tsx +79 -0
- package/src/components/blocks/nav/types.ts +65 -0
- package/src/components/blocks/nav/utils.ts +4 -0
- package/src/components/blocks/profile/profile-card-block.tsx +17 -6
- package/src/components/blocks/shell/index.ts +1 -0
- package/src/components/blocks/shell/shell-layout.tsx +115 -0
- package/src/components/blocks/shell/type.ts +50 -0
- package/src/components/blocks/shell/utils.ts +2 -0
- package/src/components/composed/social-providers.tsx +83 -27
- package/src/components/docs/component-preview.tsx +13 -12
- package/src/components/docs/demo-controls.tsx +37 -21
- package/src/components/motion/animated-sidebar.tsx +392 -364
- package/src/components/motion/popover-morph.tsx +292 -0
- package/src/components/motion/popover-position.ts +86 -0
- package/src/components/ui/badge.tsx +52 -0
- package/src/components/ui/select.tsx +257 -0
- package/src/index.css +18 -0
- package/src/index.ts +1 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client"
|
|
2
2
|
// beui.dev/components/motion/animated-sidebar
|
|
3
3
|
|
|
4
|
-
import { ChevronRight } from "lucide-react"
|
|
4
|
+
import { ChevronRight } from "lucide-react"
|
|
5
5
|
import {
|
|
6
6
|
AnimatePresence,
|
|
7
7
|
type HTMLMotionProps,
|
|
8
8
|
motion,
|
|
9
9
|
useReducedMotion,
|
|
10
10
|
type Variants,
|
|
11
|
-
} from "motion/react"
|
|
11
|
+
} from "motion/react"
|
|
12
12
|
import {
|
|
13
13
|
type ButtonHTMLAttributes,
|
|
14
14
|
type CSSProperties,
|
|
@@ -23,29 +23,24 @@ import {
|
|
|
23
23
|
useRef,
|
|
24
24
|
useState,
|
|
25
25
|
useSyncExternalStore,
|
|
26
|
-
} from "react"
|
|
27
|
-
import { createPortal } from "react-dom"
|
|
28
|
-
import { SharedLayoutBg } from "@/components/motion/shared-layout-bg"
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
EASE_OUT,
|
|
32
|
-
SPRING_LAYOUT,
|
|
33
|
-
SPRING_PRESS,
|
|
34
|
-
} from "@/lib/ease";
|
|
35
|
-
import { cn } from "@/lib/utils";
|
|
26
|
+
} from "react"
|
|
27
|
+
import { createPortal } from "react-dom"
|
|
28
|
+
import { SharedLayoutBg } from "@/components/motion/shared-layout-bg"
|
|
29
|
+
import { EASE_DRAWER, EASE_OUT, SPRING_LAYOUT, SPRING_PRESS } from "@/lib/ease"
|
|
30
|
+
import { cn } from "@/lib/utils"
|
|
36
31
|
|
|
37
|
-
type SidebarState = "expanded" | "collapsed"
|
|
38
|
-
type SidebarSide = "left" | "right"
|
|
39
|
-
type SidebarVariant = "sidebar" | "floating" | "inset"
|
|
40
|
-
type SidebarCollapsible = "offcanvas" | "icon" | "none"
|
|
32
|
+
type SidebarState = "expanded" | "collapsed"
|
|
33
|
+
type SidebarSide = "left" | "right"
|
|
34
|
+
type SidebarVariant = "sidebar" | "floating" | "inset"
|
|
35
|
+
type SidebarCollapsible = "offcanvas" | "icon" | "none"
|
|
41
36
|
|
|
42
|
-
const MOBILE_QUERY = "(max-width: 767px)"
|
|
43
|
-
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
|
37
|
+
const MOBILE_QUERY = "(max-width: 767px)"
|
|
38
|
+
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
|
44
39
|
|
|
45
40
|
const PANEL_TRANSITION = {
|
|
46
41
|
duration: 0.36,
|
|
47
42
|
ease: EASE_DRAWER,
|
|
48
|
-
} as const
|
|
43
|
+
} as const
|
|
49
44
|
|
|
50
45
|
// The desktop rail settles at a hard zero-width boundary. Keep the spring
|
|
51
46
|
// critically damped so it cannot overshoot, pause against that boundary, and
|
|
@@ -55,23 +50,23 @@ const SIDEBAR_MORPH_TRANSITION = {
|
|
|
55
50
|
stiffness: 380,
|
|
56
51
|
damping: 35,
|
|
57
52
|
mass: 0.75,
|
|
58
|
-
} as const
|
|
53
|
+
} as const
|
|
59
54
|
|
|
60
55
|
const LABEL_ENTER_TRANSITION = {
|
|
61
56
|
duration: 0.2,
|
|
62
57
|
delay: 0.08,
|
|
63
58
|
ease: EASE_OUT,
|
|
64
|
-
} as const
|
|
59
|
+
} as const
|
|
65
60
|
|
|
66
61
|
const LABEL_EXIT_TRANSITION = {
|
|
67
62
|
duration: 0.12,
|
|
68
63
|
ease: EASE_OUT,
|
|
69
|
-
} as const
|
|
64
|
+
} as const
|
|
70
65
|
|
|
71
66
|
const SUBMENU_TRANSITION = {
|
|
72
67
|
duration: 0.18,
|
|
73
68
|
ease: EASE_OUT,
|
|
74
|
-
} as const
|
|
69
|
+
} as const
|
|
75
70
|
|
|
76
71
|
const SUBMENU_VARIANTS: Variants = {
|
|
77
72
|
closed: {
|
|
@@ -94,7 +89,7 @@ const SUBMENU_VARIANTS: Variants = {
|
|
|
94
89
|
staggerChildren: 0.045,
|
|
95
90
|
},
|
|
96
91
|
},
|
|
97
|
-
}
|
|
92
|
+
}
|
|
98
93
|
|
|
99
94
|
const SUBMENU_ITEM_VARIANTS: Variants = {
|
|
100
95
|
closed: {
|
|
@@ -108,12 +103,12 @@ const SUBMENU_ITEM_VARIANTS: Variants = {
|
|
|
108
103
|
filter: "blur(0px)",
|
|
109
104
|
transition: SUBMENU_TRANSITION,
|
|
110
105
|
},
|
|
111
|
-
}
|
|
106
|
+
}
|
|
112
107
|
|
|
113
108
|
const REDUCED_TRANSITION = {
|
|
114
109
|
duration: 0.16,
|
|
115
110
|
ease: EASE_OUT,
|
|
116
|
-
} as const
|
|
111
|
+
} as const
|
|
117
112
|
|
|
118
113
|
const FOCUSABLE_SELECTOR = [
|
|
119
114
|
"a[href]",
|
|
@@ -122,90 +117,98 @@ const FOCUSABLE_SELECTOR = [
|
|
|
122
117
|
"select:not([disabled])",
|
|
123
118
|
"textarea:not([disabled])",
|
|
124
119
|
"[tabindex]:not([tabindex='-1'])",
|
|
125
|
-
].join(",")
|
|
120
|
+
].join(",")
|
|
126
121
|
|
|
127
122
|
function subscribeToMobileQuery(callback: () => void) {
|
|
128
|
-
const query = window.matchMedia(MOBILE_QUERY)
|
|
129
|
-
query.addEventListener("change", callback)
|
|
130
|
-
return () => query.removeEventListener("change", callback)
|
|
123
|
+
const query = window.matchMedia(MOBILE_QUERY)
|
|
124
|
+
query.addEventListener("change", callback)
|
|
125
|
+
return () => query.removeEventListener("change", callback)
|
|
131
126
|
}
|
|
132
127
|
|
|
133
128
|
function getMobileSnapshot() {
|
|
134
|
-
return window.matchMedia(MOBILE_QUERY).matches
|
|
129
|
+
return window.matchMedia(MOBILE_QUERY).matches
|
|
135
130
|
}
|
|
136
131
|
|
|
137
132
|
function getServerMobileSnapshot() {
|
|
138
|
-
return false
|
|
133
|
+
return false
|
|
139
134
|
}
|
|
140
135
|
|
|
141
136
|
function useIsMobile() {
|
|
142
137
|
return useSyncExternalStore(
|
|
143
138
|
subscribeToMobileQuery,
|
|
144
139
|
getMobileSnapshot,
|
|
145
|
-
getServerMobileSnapshot
|
|
146
|
-
)
|
|
140
|
+
getServerMobileSnapshot
|
|
141
|
+
)
|
|
147
142
|
}
|
|
148
143
|
|
|
149
144
|
interface AnimatedSidebarContextValue {
|
|
150
|
-
isMobile: boolean
|
|
151
|
-
layoutId: string
|
|
152
|
-
open: boolean
|
|
153
|
-
openMobile: boolean
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
145
|
+
isMobile: boolean
|
|
146
|
+
layoutId: string
|
|
147
|
+
open: boolean
|
|
148
|
+
openMobile: boolean
|
|
149
|
+
/** The right panel is a single hidden/shown state — no icon rail, no
|
|
150
|
+
* separate mobile state. */
|
|
151
|
+
openRight: boolean
|
|
152
|
+
reduce: boolean
|
|
153
|
+
setOpen: (open: boolean) => void
|
|
154
|
+
setOpenMobile: (open: boolean) => void
|
|
155
|
+
setOpenRight: (open: boolean) => void
|
|
156
|
+
state: SidebarState
|
|
157
|
+
toggleSidebar: () => void
|
|
158
|
+
toggleRightSidebar: () => void
|
|
159
|
+
triggerRef: React.RefObject<HTMLButtonElement | null>
|
|
160
|
+
rightTriggerRef: React.RefObject<HTMLButtonElement | null>
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
const AnimatedSidebarContext =
|
|
163
|
-
createContext<AnimatedSidebarContextValue | null>(null)
|
|
164
|
+
createContext<AnimatedSidebarContextValue | null>(null)
|
|
164
165
|
|
|
165
166
|
interface AnimatedSidebarPanelContextValue {
|
|
166
|
-
collapsed: boolean
|
|
167
|
-
collapsible: SidebarCollapsible
|
|
168
|
-
side: SidebarSide
|
|
167
|
+
collapsed: boolean
|
|
168
|
+
collapsible: SidebarCollapsible
|
|
169
|
+
side: SidebarSide
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
const AnimatedSidebarPanelContext =
|
|
172
|
-
createContext<AnimatedSidebarPanelContextValue | null>(null)
|
|
173
|
+
createContext<AnimatedSidebarPanelContextValue | null>(null)
|
|
173
174
|
|
|
174
175
|
export function useAnimatedSidebar() {
|
|
175
|
-
const context = useContext(AnimatedSidebarContext)
|
|
176
|
+
const context = useContext(AnimatedSidebarContext)
|
|
176
177
|
if (!context) {
|
|
177
178
|
throw new Error(
|
|
178
|
-
"useAnimatedSidebar must be used inside AnimatedSidebarProvider."
|
|
179
|
-
)
|
|
179
|
+
"useAnimatedSidebar must be used inside AnimatedSidebarProvider."
|
|
180
|
+
)
|
|
180
181
|
}
|
|
181
|
-
return context
|
|
182
|
+
return context
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
function useAnimatedSidebarPanel() {
|
|
185
|
-
const context = useContext(AnimatedSidebarPanelContext)
|
|
186
|
+
const context = useContext(AnimatedSidebarPanelContext)
|
|
186
187
|
if (!context) {
|
|
187
188
|
throw new Error(
|
|
188
|
-
"Animated Sidebar parts must be used inside AnimatedSidebar."
|
|
189
|
-
)
|
|
189
|
+
"Animated Sidebar parts must be used inside AnimatedSidebar."
|
|
190
|
+
)
|
|
190
191
|
}
|
|
191
|
-
return context
|
|
192
|
+
return context
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
type SidebarProviderStyle = CSSProperties & {
|
|
195
|
-
"--sidebar-width"?: string
|
|
196
|
-
"--sidebar-width-icon"?: string
|
|
197
|
-
"--sidebar-width-mobile"?: string
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export interface AnimatedSidebarProviderProps
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
196
|
+
"--sidebar-width"?: string
|
|
197
|
+
"--sidebar-width-icon"?: string
|
|
198
|
+
"--sidebar-width-mobile"?: string
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface AnimatedSidebarProviderProps extends HTMLAttributes<HTMLDivElement> {
|
|
202
|
+
open?: boolean
|
|
203
|
+
defaultOpen?: boolean
|
|
204
|
+
onOpenChange?: (open: boolean) => void
|
|
205
|
+
openMobile?: boolean
|
|
206
|
+
defaultOpenMobile?: boolean
|
|
207
|
+
onOpenMobileChange?: (open: boolean) => void
|
|
208
|
+
openRight?: boolean
|
|
209
|
+
defaultOpenRight?: boolean
|
|
210
|
+
onOpenRightChange?: (open: boolean) => void
|
|
211
|
+
style?: SidebarProviderStyle
|
|
209
212
|
}
|
|
210
213
|
|
|
211
214
|
export function AnimatedSidebarProvider({
|
|
@@ -216,40 +219,58 @@ export function AnimatedSidebarProvider({
|
|
|
216
219
|
openMobile,
|
|
217
220
|
defaultOpenMobile = false,
|
|
218
221
|
onOpenMobileChange,
|
|
222
|
+
openRight,
|
|
223
|
+
defaultOpenRight = false,
|
|
224
|
+
onOpenRightChange,
|
|
219
225
|
className,
|
|
220
226
|
style,
|
|
221
227
|
...props
|
|
222
228
|
}: AnimatedSidebarProviderProps) {
|
|
223
|
-
const [internalOpen, setInternalOpen] = useState(defaultOpen)
|
|
229
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen)
|
|
224
230
|
const [internalOpenMobile, setInternalOpenMobile] =
|
|
225
|
-
useState(defaultOpenMobile)
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
const
|
|
231
|
+
useState(defaultOpenMobile)
|
|
232
|
+
const [internalOpenRight, setInternalOpenRight] = useState(defaultOpenRight)
|
|
233
|
+
const isMobile = useIsMobile()
|
|
234
|
+
const reduce = useReducedMotion() ?? false
|
|
235
|
+
const generatedId = useId()
|
|
236
|
+
const triggerRef = useRef<HTMLButtonElement>(null)
|
|
237
|
+
const rightTriggerRef = useRef<HTMLButtonElement>(null)
|
|
238
|
+
const desktopOpen = open ?? internalOpen
|
|
239
|
+
const mobileOpen = openMobile ?? internalOpenMobile
|
|
240
|
+
const rightOpen = openRight ?? internalOpenRight
|
|
232
241
|
|
|
233
242
|
const setOpen = useCallback(
|
|
234
243
|
(nextOpen: boolean) => {
|
|
235
|
-
if (open === undefined) setInternalOpen(nextOpen)
|
|
236
|
-
onOpenChange?.(nextOpen)
|
|
244
|
+
if (open === undefined) setInternalOpen(nextOpen)
|
|
245
|
+
onOpenChange?.(nextOpen)
|
|
237
246
|
},
|
|
238
|
-
[onOpenChange, open]
|
|
239
|
-
)
|
|
247
|
+
[onOpenChange, open]
|
|
248
|
+
)
|
|
240
249
|
|
|
241
250
|
const setOpenMobile = useCallback(
|
|
242
251
|
(nextOpen: boolean) => {
|
|
243
|
-
if (openMobile === undefined) setInternalOpenMobile(nextOpen)
|
|
244
|
-
onOpenMobileChange?.(nextOpen)
|
|
252
|
+
if (openMobile === undefined) setInternalOpenMobile(nextOpen)
|
|
253
|
+
onOpenMobileChange?.(nextOpen)
|
|
245
254
|
},
|
|
246
|
-
[onOpenMobileChange, openMobile]
|
|
247
|
-
)
|
|
255
|
+
[onOpenMobileChange, openMobile]
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
const setOpenRight = useCallback(
|
|
259
|
+
(nextOpen: boolean) => {
|
|
260
|
+
if (openRight === undefined) setInternalOpenRight(nextOpen)
|
|
261
|
+
onOpenRightChange?.(nextOpen)
|
|
262
|
+
},
|
|
263
|
+
[onOpenRightChange, openRight]
|
|
264
|
+
)
|
|
248
265
|
|
|
249
266
|
const toggleSidebar = useCallback(() => {
|
|
250
|
-
if (isMobile) setOpenMobile(!mobileOpen)
|
|
251
|
-
else setOpen(!desktopOpen)
|
|
252
|
-
}, [desktopOpen, isMobile, mobileOpen, setOpen, setOpenMobile])
|
|
267
|
+
if (isMobile) setOpenMobile(!mobileOpen)
|
|
268
|
+
else setOpen(!desktopOpen)
|
|
269
|
+
}, [desktopOpen, isMobile, mobileOpen, setOpen, setOpenMobile])
|
|
270
|
+
|
|
271
|
+
const toggleRightSidebar = useCallback(() => {
|
|
272
|
+
setOpenRight(!rightOpen)
|
|
273
|
+
}, [rightOpen, setOpenRight])
|
|
253
274
|
|
|
254
275
|
useEffect(() => {
|
|
255
276
|
const handleShortcut = (event: KeyboardEvent) => {
|
|
@@ -257,14 +278,14 @@ export function AnimatedSidebarProvider({
|
|
|
257
278
|
event.key.toLowerCase() === SIDEBAR_KEYBOARD_SHORTCUT &&
|
|
258
279
|
(event.metaKey || event.ctrlKey)
|
|
259
280
|
) {
|
|
260
|
-
event.preventDefault()
|
|
261
|
-
toggleSidebar()
|
|
281
|
+
event.preventDefault()
|
|
282
|
+
toggleSidebar()
|
|
262
283
|
}
|
|
263
|
-
}
|
|
284
|
+
}
|
|
264
285
|
|
|
265
|
-
window.addEventListener("keydown", handleShortcut)
|
|
266
|
-
return () => window.removeEventListener("keydown", handleShortcut)
|
|
267
|
-
}, [toggleSidebar])
|
|
286
|
+
window.addEventListener("keydown", handleShortcut)
|
|
287
|
+
return () => window.removeEventListener("keydown", handleShortcut)
|
|
288
|
+
}, [toggleSidebar])
|
|
268
289
|
|
|
269
290
|
return (
|
|
270
291
|
<AnimatedSidebarContext.Provider
|
|
@@ -273,33 +294,38 @@ export function AnimatedSidebarProvider({
|
|
|
273
294
|
layoutId: `${generatedId}-active`,
|
|
274
295
|
open: desktopOpen,
|
|
275
296
|
openMobile: mobileOpen,
|
|
297
|
+
openRight: rightOpen,
|
|
276
298
|
reduce,
|
|
277
299
|
setOpen,
|
|
278
300
|
setOpenMobile,
|
|
301
|
+
setOpenRight,
|
|
279
302
|
state: desktopOpen ? "expanded" : "collapsed",
|
|
280
303
|
toggleSidebar,
|
|
304
|
+
toggleRightSidebar,
|
|
281
305
|
triggerRef,
|
|
306
|
+
rightTriggerRef,
|
|
282
307
|
}}
|
|
283
308
|
>
|
|
284
309
|
<div
|
|
285
310
|
{...props}
|
|
286
311
|
data-slot="sidebar-wrapper"
|
|
287
312
|
data-state={desktopOpen ? "expanded" : "collapsed"}
|
|
313
|
+
data-right-state={rightOpen ? "expanded" : "collapsed"}
|
|
288
314
|
style={{
|
|
289
|
-
"--sidebar-width": "
|
|
315
|
+
"--sidebar-width": "19rem",
|
|
290
316
|
"--sidebar-width-icon": "4.25rem",
|
|
291
317
|
"--sidebar-width-mobile": "18rem",
|
|
292
318
|
...style,
|
|
293
319
|
}}
|
|
294
320
|
className={cn(
|
|
295
321
|
"group/sidebar-wrapper flex min-h-svh w-full min-w-0",
|
|
296
|
-
className
|
|
322
|
+
className
|
|
297
323
|
)}
|
|
298
324
|
>
|
|
299
325
|
{children}
|
|
300
326
|
</div>
|
|
301
327
|
</AnimatedSidebarContext.Provider>
|
|
302
|
-
)
|
|
328
|
+
)
|
|
303
329
|
}
|
|
304
330
|
|
|
305
331
|
function MobileSidebar({
|
|
@@ -308,78 +334,79 @@ function MobileSidebar({
|
|
|
308
334
|
className,
|
|
309
335
|
side,
|
|
310
336
|
}: {
|
|
311
|
-
ariaLabel: string
|
|
312
|
-
children: ReactNode
|
|
313
|
-
className?: string
|
|
314
|
-
side: SidebarSide
|
|
337
|
+
ariaLabel: string
|
|
338
|
+
children: ReactNode
|
|
339
|
+
className?: string
|
|
340
|
+
side: SidebarSide
|
|
315
341
|
}) {
|
|
316
|
-
const context = useAnimatedSidebar()
|
|
317
|
-
const
|
|
318
|
-
const
|
|
342
|
+
const context = useAnimatedSidebar()
|
|
343
|
+
const isRight = side === "right"
|
|
344
|
+
const open = isRight ? context.openRight : context.openMobile
|
|
345
|
+
const setOpen = isRight ? context.setOpenRight : context.setOpenMobile
|
|
346
|
+
const triggerRef = isRight ? context.rightTriggerRef : context.triggerRef
|
|
347
|
+
const panelRef = useRef<HTMLDivElement>(null)
|
|
348
|
+
const [mounted, setMounted] = useState(false)
|
|
319
349
|
|
|
320
|
-
useEffect(() => setMounted(true), [])
|
|
350
|
+
useEffect(() => setMounted(true), [])
|
|
321
351
|
|
|
322
352
|
useEffect(() => {
|
|
323
|
-
if (!
|
|
353
|
+
if (!open) return
|
|
324
354
|
|
|
325
|
-
const body = document.body
|
|
326
|
-
const scrollY = window.scrollY
|
|
355
|
+
const body = document.body
|
|
356
|
+
const scrollY = window.scrollY
|
|
357
|
+
const trigger = triggerRef.current
|
|
327
358
|
const previousBodyStyles = {
|
|
328
359
|
left: body.style.left,
|
|
329
360
|
overflow: body.style.overflow,
|
|
330
361
|
position: body.style.position,
|
|
331
362
|
right: body.style.right,
|
|
332
363
|
top: body.style.top,
|
|
333
|
-
}
|
|
364
|
+
}
|
|
334
365
|
|
|
335
|
-
body.style.position = "fixed"
|
|
336
|
-
body.style.top = `-${scrollY}px
|
|
337
|
-
body.style.left = "0"
|
|
338
|
-
body.style.right = "0"
|
|
339
|
-
body.style.overflow = "hidden"
|
|
366
|
+
body.style.position = "fixed"
|
|
367
|
+
body.style.top = `-${scrollY}px`
|
|
368
|
+
body.style.left = "0"
|
|
369
|
+
body.style.right = "0"
|
|
370
|
+
body.style.overflow = "hidden"
|
|
340
371
|
|
|
341
372
|
const focusFrame = requestAnimationFrame(() => {
|
|
342
373
|
const firstFocusable =
|
|
343
|
-
panelRef.current?.querySelector<HTMLElement>(FOCUSABLE_SELECTOR)
|
|
344
|
-
(firstFocusable ?? panelRef.current)?.focus({ preventScroll: true })
|
|
345
|
-
})
|
|
374
|
+
panelRef.current?.querySelector<HTMLElement>(FOCUSABLE_SELECTOR)
|
|
375
|
+
;(firstFocusable ?? panelRef.current)?.focus({ preventScroll: true })
|
|
376
|
+
})
|
|
346
377
|
|
|
347
378
|
return () => {
|
|
348
|
-
cancelAnimationFrame(focusFrame)
|
|
349
|
-
body.style.position = previousBodyStyles.position
|
|
350
|
-
body.style.top = previousBodyStyles.top
|
|
351
|
-
body.style.left = previousBodyStyles.left
|
|
352
|
-
body.style.right = previousBodyStyles.right
|
|
353
|
-
body.style.overflow = previousBodyStyles.overflow
|
|
354
|
-
window.scrollTo(0, scrollY)
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}, [
|
|
358
|
-
|
|
359
|
-
if (!mounted) return null
|
|
379
|
+
cancelAnimationFrame(focusFrame)
|
|
380
|
+
body.style.position = previousBodyStyles.position
|
|
381
|
+
body.style.top = previousBodyStyles.top
|
|
382
|
+
body.style.left = previousBodyStyles.left
|
|
383
|
+
body.style.right = previousBodyStyles.right
|
|
384
|
+
body.style.overflow = previousBodyStyles.overflow
|
|
385
|
+
window.scrollTo(0, scrollY)
|
|
386
|
+
trigger?.focus({ preventScroll: true })
|
|
387
|
+
}
|
|
388
|
+
}, [open, triggerRef])
|
|
389
|
+
|
|
390
|
+
if (!mounted) return null
|
|
360
391
|
|
|
361
392
|
return createPortal(
|
|
362
393
|
<div
|
|
363
394
|
className={cn(
|
|
364
395
|
"pointer-events-none fixed inset-0 z-50 md:hidden",
|
|
365
|
-
|
|
396
|
+
open ? "visible" : "invisible"
|
|
366
397
|
)}
|
|
367
398
|
>
|
|
368
399
|
<motion.button
|
|
369
400
|
type="button"
|
|
370
401
|
aria-label="Close sidebar"
|
|
371
|
-
tabIndex={
|
|
402
|
+
tabIndex={open ? 0 : -1}
|
|
372
403
|
initial={false}
|
|
373
|
-
animate={{ opacity:
|
|
374
|
-
transition={
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
onClick={() => context.setOpenMobile(false)}
|
|
404
|
+
animate={{ opacity: open ? 1 : 0 }}
|
|
405
|
+
transition={context.reduce ? REDUCED_TRANSITION : PANEL_TRANSITION}
|
|
406
|
+
onClick={() => setOpen(false)}
|
|
378
407
|
className={cn(
|
|
379
|
-
"absolute inset-0
|
|
380
|
-
|
|
381
|
-
? "pointer-events-auto"
|
|
382
|
-
: "pointer-events-none",
|
|
408
|
+
"absolute inset-0",
|
|
409
|
+
open ? "pointer-events-auto" : "pointer-events-none"
|
|
383
410
|
)}
|
|
384
411
|
/>
|
|
385
412
|
|
|
@@ -388,68 +415,62 @@ function MobileSidebar({
|
|
|
388
415
|
role="dialog"
|
|
389
416
|
aria-modal="true"
|
|
390
417
|
aria-label={ariaLabel}
|
|
391
|
-
aria-hidden={!
|
|
392
|
-
inert={!
|
|
418
|
+
aria-hidden={!open}
|
|
419
|
+
inert={!open}
|
|
393
420
|
tabIndex={-1}
|
|
394
421
|
data-mobile="true"
|
|
395
|
-
data-state={
|
|
422
|
+
data-state={open ? "expanded" : "collapsed"}
|
|
396
423
|
data-side={side}
|
|
397
424
|
initial={false}
|
|
398
425
|
animate={{
|
|
399
|
-
opacity: context.reduce
|
|
400
|
-
? context.openMobile
|
|
401
|
-
? 1
|
|
402
|
-
: 0
|
|
403
|
-
: 1,
|
|
426
|
+
opacity: context.reduce ? (open ? 1 : 0) : 1,
|
|
404
427
|
x: context.reduce
|
|
405
428
|
? 0
|
|
406
|
-
:
|
|
429
|
+
: open
|
|
407
430
|
? "0%"
|
|
408
431
|
: side === "left"
|
|
409
432
|
? "-100%"
|
|
410
433
|
: "100%",
|
|
411
434
|
}}
|
|
412
|
-
transition={
|
|
413
|
-
context.reduce ? REDUCED_TRANSITION : PANEL_TRANSITION
|
|
414
|
-
}
|
|
435
|
+
transition={context.reduce ? REDUCED_TRANSITION : PANEL_TRANSITION}
|
|
415
436
|
onKeyDown={(event) => {
|
|
416
437
|
if (event.key === "Escape") {
|
|
417
|
-
event.preventDefault()
|
|
418
|
-
|
|
419
|
-
return
|
|
438
|
+
event.preventDefault()
|
|
439
|
+
setOpen(false)
|
|
440
|
+
return
|
|
420
441
|
}
|
|
421
442
|
|
|
422
|
-
if (event.key !== "Tab") return
|
|
443
|
+
if (event.key !== "Tab") return
|
|
423
444
|
const focusable = panelRef.current
|
|
424
445
|
? Array.from(
|
|
425
446
|
panelRef.current.querySelectorAll<HTMLElement>(
|
|
426
|
-
FOCUSABLE_SELECTOR
|
|
427
|
-
)
|
|
447
|
+
FOCUSABLE_SELECTOR
|
|
448
|
+
)
|
|
428
449
|
)
|
|
429
|
-
: []
|
|
450
|
+
: []
|
|
430
451
|
|
|
431
452
|
if (focusable.length === 0) {
|
|
432
|
-
event.preventDefault()
|
|
433
|
-
panelRef.current?.focus()
|
|
434
|
-
return
|
|
453
|
+
event.preventDefault()
|
|
454
|
+
panelRef.current?.focus()
|
|
455
|
+
return
|
|
435
456
|
}
|
|
436
457
|
|
|
437
|
-
const first = focusable[0]
|
|
438
|
-
const last = focusable[focusable.length - 1]
|
|
458
|
+
const first = focusable[0]
|
|
459
|
+
const last = focusable[focusable.length - 1]
|
|
439
460
|
if (event.shiftKey && document.activeElement === first) {
|
|
440
|
-
event.preventDefault()
|
|
441
|
-
last.focus()
|
|
461
|
+
event.preventDefault()
|
|
462
|
+
last.focus()
|
|
442
463
|
} else if (!event.shiftKey && document.activeElement === last) {
|
|
443
|
-
event.preventDefault()
|
|
444
|
-
first.focus()
|
|
464
|
+
event.preventDefault()
|
|
465
|
+
first.focus()
|
|
445
466
|
}
|
|
446
467
|
}}
|
|
447
468
|
className={cn(
|
|
448
469
|
"pointer-events-auto absolute inset-y-0 flex h-dvh w-(--sidebar-width-mobile) max-w-[88vw] flex-col overflow-hidden",
|
|
449
|
-
"
|
|
450
|
-
side === "left" ? "left-0 border-r" : "right-0
|
|
451
|
-
!
|
|
452
|
-
className
|
|
470
|
+
"will-change-transform",
|
|
471
|
+
side === "left" ? "left-0 border-r" : "right-0",
|
|
472
|
+
!open && "pointer-events-none",
|
|
473
|
+
className
|
|
453
474
|
)}
|
|
454
475
|
>
|
|
455
476
|
<AnimatedSidebarPanelContext.Provider
|
|
@@ -459,18 +480,20 @@ function MobileSidebar({
|
|
|
459
480
|
</AnimatedSidebarPanelContext.Provider>
|
|
460
481
|
</motion.div>
|
|
461
482
|
</div>,
|
|
462
|
-
document.body
|
|
463
|
-
)
|
|
483
|
+
document.body
|
|
484
|
+
)
|
|
464
485
|
}
|
|
465
486
|
|
|
466
|
-
export interface AnimatedSidebarProps
|
|
467
|
-
|
|
468
|
-
children
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
487
|
+
export interface AnimatedSidebarProps extends Omit<
|
|
488
|
+
HTMLMotionProps<"aside">,
|
|
489
|
+
"children"
|
|
490
|
+
> {
|
|
491
|
+
children?: ReactNode
|
|
492
|
+
side?: SidebarSide
|
|
493
|
+
variant?: SidebarVariant
|
|
494
|
+
collapsible?: SidebarCollapsible
|
|
495
|
+
ariaLabel?: string
|
|
496
|
+
panelClassName?: string
|
|
474
497
|
}
|
|
475
498
|
|
|
476
499
|
export const AnimatedSidebar = forwardRef<HTMLElement, AnimatedSidebarProps>(
|
|
@@ -486,27 +509,24 @@ export const AnimatedSidebar = forwardRef<HTMLElement, AnimatedSidebarProps>(
|
|
|
486
509
|
style,
|
|
487
510
|
...props
|
|
488
511
|
},
|
|
489
|
-
forwardedRef
|
|
512
|
+
forwardedRef
|
|
490
513
|
) {
|
|
491
|
-
const context = useAnimatedSidebar()
|
|
492
|
-
const
|
|
493
|
-
const
|
|
514
|
+
const context = useAnimatedSidebar()
|
|
515
|
+
const sideOpen = side === "right" ? context.openRight : context.open
|
|
516
|
+
const collapsed = collapsible !== "none" && !sideOpen
|
|
517
|
+
const offcanvas = collapsed && collapsible === "offcanvas"
|
|
494
518
|
const width = offcanvas
|
|
495
519
|
? "0px"
|
|
496
520
|
: collapsed
|
|
497
521
|
? "var(--sidebar-width-icon)"
|
|
498
|
-
: "var(--sidebar-width)"
|
|
522
|
+
: "var(--sidebar-width)"
|
|
499
523
|
|
|
500
524
|
if (context.isMobile) {
|
|
501
525
|
return (
|
|
502
|
-
<MobileSidebar
|
|
503
|
-
ariaLabel={ariaLabel}
|
|
504
|
-
className={className}
|
|
505
|
-
side={side}
|
|
506
|
-
>
|
|
526
|
+
<MobileSidebar ariaLabel={ariaLabel} className={className} side={side}>
|
|
507
527
|
{children}
|
|
508
528
|
</MobileSidebar>
|
|
509
|
-
)
|
|
529
|
+
)
|
|
510
530
|
}
|
|
511
531
|
|
|
512
532
|
return (
|
|
@@ -521,35 +541,38 @@ export const AnimatedSidebar = forwardRef<HTMLElement, AnimatedSidebarProps>(
|
|
|
521
541
|
data-variant={variant}
|
|
522
542
|
data-side={side}
|
|
523
543
|
animate={{ width }}
|
|
524
|
-
transition={
|
|
525
|
-
context.reduce ? { duration: 0 } : SIDEBAR_MORPH_TRANSITION
|
|
526
|
-
}
|
|
544
|
+
transition={context.reduce ? { duration: 0 } : SIDEBAR_MORPH_TRANSITION}
|
|
527
545
|
style={style}
|
|
528
546
|
className={cn(
|
|
529
|
-
"group/sidebar relative hidden h-auto shrink-0
|
|
530
|
-
"peer",
|
|
547
|
+
"group/sidebar relative hidden h-auto shrink-0 will-change-[width] md:block",
|
|
548
|
+
"peer flex!",
|
|
549
|
+
// The offcanvas panel keeps its full width and slides out of the
|
|
550
|
+
// zero-width rail, so clip it rather than letting it bleed past the
|
|
551
|
+
// shell edge. The clip margin lets the panel's own shadow escape
|
|
552
|
+
// without letting the slid-out panel escape with it
|
|
553
|
+
collapsible === "offcanvas" &&
|
|
554
|
+
"overflow-x-visible [overflow-clip-margin:1rem]",
|
|
531
555
|
side === "right" && "order-last",
|
|
532
|
-
className
|
|
556
|
+
className
|
|
533
557
|
)}
|
|
534
558
|
>
|
|
559
|
+
{side === "right" && !collapsed && (
|
|
560
|
+
<motion.div className="h-full p-0.5 flex flex-1 bg-radial/decreasing from-amber-400 to-0% hover:to-50% ease-smooth-out to-amber-500/0 cursor-col-resize transition-colors duration-1000 animate-in" />
|
|
561
|
+
)}
|
|
535
562
|
<motion.div
|
|
536
563
|
initial={false}
|
|
537
564
|
animate={{
|
|
538
565
|
opacity: offcanvas ? 0 : 1,
|
|
539
566
|
x: offcanvas ? (side === "left" ? "-100%" : "100%") : "0%",
|
|
540
567
|
}}
|
|
541
|
-
transition={
|
|
542
|
-
context.reduce ? REDUCED_TRANSITION : PANEL_TRANSITION
|
|
543
|
-
}
|
|
568
|
+
transition={context.reduce ? REDUCED_TRANSITION : PANEL_TRANSITION}
|
|
544
569
|
className={cn(
|
|
545
|
-
"sticky top-0 flex h-svh w-full flex-col overflow-hidden
|
|
570
|
+
"sticky top-0 flex h-svh w-full flex-col overflow-hidden",
|
|
546
571
|
collapsible === "offcanvas" && "w-[var(--sidebar-width)]",
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
variant === "
|
|
550
|
-
|
|
551
|
-
variant === "inset" && "m-2 h-[calc(100svh-1rem)] rounded-2xl",
|
|
552
|
-
panelClassName,
|
|
572
|
+
|
|
573
|
+
variant === "floating" && "m-2 h-[calc(100svh-1rem)]",
|
|
574
|
+
variant === "inset" && "m-2 h-[calc(100svh-1rem)]",
|
|
575
|
+
panelClassName
|
|
553
576
|
)}
|
|
554
577
|
>
|
|
555
578
|
<AnimatedSidebarPanelContext.Provider
|
|
@@ -559,94 +582,106 @@ export const AnimatedSidebar = forwardRef<HTMLElement, AnimatedSidebarProps>(
|
|
|
559
582
|
</AnimatedSidebarPanelContext.Provider>
|
|
560
583
|
</motion.div>
|
|
561
584
|
</motion.aside>
|
|
562
|
-
)
|
|
563
|
-
}
|
|
564
|
-
)
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
)
|
|
565
588
|
|
|
566
|
-
export interface AnimatedSidebarTriggerProps
|
|
567
|
-
|
|
589
|
+
export interface AnimatedSidebarTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
590
|
+
side?: SidebarSide
|
|
591
|
+
}
|
|
568
592
|
|
|
569
593
|
export const AnimatedSidebarTrigger = forwardRef<
|
|
570
594
|
HTMLButtonElement,
|
|
571
595
|
AnimatedSidebarTriggerProps
|
|
572
596
|
>(function AnimatedSidebarTrigger(
|
|
573
|
-
{ className, onClick, type = "button", ...props },
|
|
574
|
-
forwardedRef
|
|
597
|
+
{ className, onClick, side = "left", type = "button", ...props },
|
|
598
|
+
forwardedRef
|
|
575
599
|
) {
|
|
576
|
-
const context = useAnimatedSidebar()
|
|
577
|
-
const
|
|
600
|
+
const context = useAnimatedSidebar()
|
|
601
|
+
const isRight = side === "right"
|
|
602
|
+
const expanded = isRight
|
|
603
|
+
? context.openRight
|
|
604
|
+
: context.isMobile
|
|
605
|
+
? context.openMobile
|
|
606
|
+
: context.open
|
|
607
|
+
const triggerRef = isRight ? context.rightTriggerRef : context.triggerRef
|
|
578
608
|
|
|
579
609
|
return (
|
|
580
610
|
<button
|
|
581
611
|
{...props}
|
|
582
612
|
ref={(node) => {
|
|
583
|
-
|
|
584
|
-
if (typeof forwardedRef === "function") forwardedRef(node)
|
|
585
|
-
else if (forwardedRef) forwardedRef.current = node
|
|
613
|
+
triggerRef.current = node
|
|
614
|
+
if (typeof forwardedRef === "function") forwardedRef(node)
|
|
615
|
+
else if (forwardedRef) forwardedRef.current = node
|
|
586
616
|
}}
|
|
587
617
|
type={type}
|
|
588
618
|
aria-label={props["aria-label"] ?? "Toggle sidebar"}
|
|
589
619
|
aria-expanded={expanded}
|
|
590
620
|
data-slot="sidebar-trigger"
|
|
621
|
+
data-side={side}
|
|
591
622
|
data-state={expanded ? "expanded" : "collapsed"}
|
|
592
623
|
onClick={(event) => {
|
|
593
|
-
onClick?.(event)
|
|
594
|
-
if (
|
|
624
|
+
onClick?.(event)
|
|
625
|
+
if (event.defaultPrevented) return
|
|
626
|
+
if (isRight) context.toggleRightSidebar()
|
|
627
|
+
else context.toggleSidebar()
|
|
595
628
|
}}
|
|
596
629
|
className={cn(
|
|
597
630
|
"inline-flex size-10 shrink-0 items-center justify-center rounded-xl outline-none",
|
|
598
631
|
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
599
|
-
className
|
|
632
|
+
className
|
|
600
633
|
)}
|
|
601
634
|
/>
|
|
602
|
-
)
|
|
603
|
-
})
|
|
635
|
+
)
|
|
636
|
+
})
|
|
604
637
|
|
|
605
|
-
export interface AnimatedSidebarCloseProps
|
|
606
|
-
|
|
638
|
+
export interface AnimatedSidebarCloseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
639
|
+
side?: SidebarSide
|
|
640
|
+
}
|
|
607
641
|
|
|
608
642
|
export const AnimatedSidebarClose = forwardRef<
|
|
609
643
|
HTMLButtonElement,
|
|
610
644
|
AnimatedSidebarCloseProps
|
|
611
645
|
>(function AnimatedSidebarClose(
|
|
612
|
-
{ className, onClick, type = "button", ...props },
|
|
613
|
-
forwardedRef
|
|
646
|
+
{ className, onClick, side = "left", type = "button", ...props },
|
|
647
|
+
forwardedRef
|
|
614
648
|
) {
|
|
615
|
-
const context = useAnimatedSidebar()
|
|
649
|
+
const context = useAnimatedSidebar()
|
|
616
650
|
|
|
617
651
|
return (
|
|
618
652
|
<button
|
|
619
653
|
{...props}
|
|
620
654
|
ref={forwardedRef}
|
|
621
655
|
type={type}
|
|
656
|
+
data-side={side}
|
|
622
657
|
aria-label={props["aria-label"] ?? "Close sidebar"}
|
|
623
658
|
onClick={(event) => {
|
|
624
|
-
onClick?.(event)
|
|
625
|
-
if (event.defaultPrevented) return
|
|
626
|
-
if (
|
|
627
|
-
else context.
|
|
659
|
+
onClick?.(event)
|
|
660
|
+
if (event.defaultPrevented) return
|
|
661
|
+
if (side === "right") context.setOpenRight(false)
|
|
662
|
+
else if (context.isMobile) context.setOpenMobile(false)
|
|
663
|
+
else context.setOpen(false)
|
|
628
664
|
}}
|
|
629
665
|
className={cn(
|
|
630
666
|
"inline-flex size-10 shrink-0 items-center justify-center rounded-xl outline-none",
|
|
631
667
|
"focus-visible:ring-2 focus-visible:ring-ring",
|
|
632
|
-
className
|
|
668
|
+
className
|
|
633
669
|
)}
|
|
634
670
|
/>
|
|
635
|
-
)
|
|
636
|
-
})
|
|
671
|
+
)
|
|
672
|
+
})
|
|
637
673
|
|
|
638
|
-
export interface AnimatedSidebarRailProps
|
|
639
|
-
extends ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
674
|
+
export interface AnimatedSidebarRailProps extends ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
640
675
|
|
|
641
676
|
export const AnimatedSidebarRail = forwardRef<
|
|
642
677
|
HTMLButtonElement,
|
|
643
678
|
AnimatedSidebarRailProps
|
|
644
679
|
>(function AnimatedSidebarRail(
|
|
645
680
|
{ className, onClick, type = "button", ...props },
|
|
646
|
-
forwardedRef
|
|
681
|
+
forwardedRef
|
|
647
682
|
) {
|
|
648
|
-
const context = useAnimatedSidebar()
|
|
649
|
-
const panel = useAnimatedSidebarPanel()
|
|
683
|
+
const context = useAnimatedSidebar()
|
|
684
|
+
const panel = useAnimatedSidebarPanel()
|
|
650
685
|
|
|
651
686
|
return (
|
|
652
687
|
<button
|
|
@@ -658,21 +693,22 @@ export const AnimatedSidebarRail = forwardRef<
|
|
|
658
693
|
title="Toggle sidebar"
|
|
659
694
|
tabIndex={-1}
|
|
660
695
|
onClick={(event) => {
|
|
661
|
-
onClick?.(event)
|
|
662
|
-
if (
|
|
696
|
+
onClick?.(event)
|
|
697
|
+
if (event.defaultPrevented) return
|
|
698
|
+
if (panel.side === "right") context.toggleRightSidebar()
|
|
699
|
+
else context.toggleSidebar()
|
|
663
700
|
}}
|
|
664
701
|
className={cn(
|
|
665
702
|
"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 outline-none md:block",
|
|
666
703
|
"after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-transparent after:transition-colors hover:after:bg-border",
|
|
667
|
-
"data-[side=right]:right-0 data-[side=right]:translate-x-1/2
|
|
668
|
-
className
|
|
704
|
+
"data-[side=left]:left-full data-[side=right]:right-0 data-[side=right]:translate-x-1/2",
|
|
705
|
+
className
|
|
669
706
|
)}
|
|
670
707
|
/>
|
|
671
|
-
)
|
|
672
|
-
})
|
|
708
|
+
)
|
|
709
|
+
})
|
|
673
710
|
|
|
674
|
-
export interface AnimatedSidebarInsetProps
|
|
675
|
-
extends HTMLMotionProps<"main"> {}
|
|
711
|
+
export interface AnimatedSidebarInsetProps extends HTMLMotionProps<"main"> {}
|
|
676
712
|
|
|
677
713
|
export const AnimatedSidebarInset = forwardRef<
|
|
678
714
|
HTMLElement,
|
|
@@ -684,13 +720,13 @@ export const AnimatedSidebarInset = forwardRef<
|
|
|
684
720
|
ref={forwardedRef}
|
|
685
721
|
data-slot="sidebar-inset"
|
|
686
722
|
className={cn(
|
|
687
|
-
"relative flex min-
|
|
688
|
-
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-
|
|
689
|
-
className
|
|
723
|
+
"relative flex min-w-0 flex-1 flex-col bg-background",
|
|
724
|
+
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:mr-1.5 md:peer-data-[variant=inset]:rounded-md md:peer-data-[variant=inset]:shadow-md",
|
|
725
|
+
className
|
|
690
726
|
)}
|
|
691
727
|
/>
|
|
692
|
-
)
|
|
693
|
-
})
|
|
728
|
+
)
|
|
729
|
+
})
|
|
694
730
|
|
|
695
731
|
export const AnimatedSidebarHeader = forwardRef<
|
|
696
732
|
HTMLDivElement,
|
|
@@ -703,8 +739,8 @@ export const AnimatedSidebarHeader = forwardRef<
|
|
|
703
739
|
data-slot="sidebar-header"
|
|
704
740
|
className={cn("flex shrink-0 flex-col gap-2 p-3", className)}
|
|
705
741
|
/>
|
|
706
|
-
)
|
|
707
|
-
})
|
|
742
|
+
)
|
|
743
|
+
})
|
|
708
744
|
|
|
709
745
|
export const AnimatedSidebarContent = forwardRef<
|
|
710
746
|
HTMLDivElement,
|
|
@@ -716,12 +752,12 @@ export const AnimatedSidebarContent = forwardRef<
|
|
|
716
752
|
ref={forwardedRef}
|
|
717
753
|
data-slot="sidebar-content"
|
|
718
754
|
className={cn(
|
|
719
|
-
"flex min-h-0 flex-1 flex-col gap-2 overflow-
|
|
720
|
-
className
|
|
755
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-x-hidden overflow-y-auto overscroll-contain px-2 py-2",
|
|
756
|
+
className
|
|
721
757
|
)}
|
|
722
758
|
/>
|
|
723
|
-
)
|
|
724
|
-
})
|
|
759
|
+
)
|
|
760
|
+
})
|
|
725
761
|
|
|
726
762
|
export const AnimatedSidebarFooter = forwardRef<
|
|
727
763
|
HTMLDivElement,
|
|
@@ -733,12 +769,12 @@ export const AnimatedSidebarFooter = forwardRef<
|
|
|
733
769
|
ref={forwardedRef}
|
|
734
770
|
data-slot="sidebar-footer"
|
|
735
771
|
className={cn(
|
|
736
|
-
"flex shrink-0 flex-col gap-2 border-
|
|
737
|
-
className
|
|
772
|
+
"flex shrink-0 flex-col gap-2 border-t border-border p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]",
|
|
773
|
+
className
|
|
738
774
|
)}
|
|
739
775
|
/>
|
|
740
|
-
)
|
|
741
|
-
})
|
|
776
|
+
)
|
|
777
|
+
})
|
|
742
778
|
|
|
743
779
|
export const AnimatedSidebarGroup = forwardRef<
|
|
744
780
|
HTMLDivElement,
|
|
@@ -751,17 +787,17 @@ export const AnimatedSidebarGroup = forwardRef<
|
|
|
751
787
|
data-slot="sidebar-group"
|
|
752
788
|
className={cn("flex w-full min-w-0 flex-col px-1 py-1.5", className)}
|
|
753
789
|
/>
|
|
754
|
-
)
|
|
755
|
-
})
|
|
790
|
+
)
|
|
791
|
+
})
|
|
756
792
|
|
|
757
793
|
export const AnimatedSidebarGroupLabel = forwardRef<
|
|
758
794
|
HTMLDivElement,
|
|
759
795
|
HTMLAttributes<HTMLDivElement>
|
|
760
796
|
>(function AnimatedSidebarGroupLabel(
|
|
761
797
|
{ children, className, ...props },
|
|
762
|
-
forwardedRef
|
|
798
|
+
forwardedRef
|
|
763
799
|
) {
|
|
764
|
-
const { collapsed } = useAnimatedSidebarPanel()
|
|
800
|
+
const { collapsed } = useAnimatedSidebarPanel()
|
|
765
801
|
|
|
766
802
|
return (
|
|
767
803
|
<div
|
|
@@ -770,23 +806,20 @@ export const AnimatedSidebarGroupLabel = forwardRef<
|
|
|
770
806
|
aria-hidden={collapsed}
|
|
771
807
|
data-slot="sidebar-group-label"
|
|
772
808
|
className={cn(
|
|
773
|
-
"mb-1 h-7 overflow-hidden px-2 text-[10px] font-medium
|
|
809
|
+
"mb-1 h-7 overflow-hidden px-2 text-[10px] font-medium tracking-[0.14em] text-muted-foreground uppercase transition-opacity",
|
|
774
810
|
collapsed ? "opacity-0" : "opacity-100",
|
|
775
|
-
className
|
|
811
|
+
className
|
|
776
812
|
)}
|
|
777
813
|
>
|
|
778
814
|
{children}
|
|
779
815
|
</div>
|
|
780
|
-
)
|
|
781
|
-
})
|
|
816
|
+
)
|
|
817
|
+
})
|
|
782
818
|
|
|
783
819
|
export const AnimatedSidebarGroupContent = forwardRef<
|
|
784
820
|
HTMLDivElement,
|
|
785
821
|
HTMLAttributes<HTMLDivElement>
|
|
786
|
-
>(function AnimatedSidebarGroupContent(
|
|
787
|
-
{ className, ...props },
|
|
788
|
-
forwardedRef,
|
|
789
|
-
) {
|
|
822
|
+
>(function AnimatedSidebarGroupContent({ className, ...props }, forwardedRef) {
|
|
790
823
|
return (
|
|
791
824
|
<div
|
|
792
825
|
{...props}
|
|
@@ -794,15 +827,15 @@ export const AnimatedSidebarGroupContent = forwardRef<
|
|
|
794
827
|
data-slot="sidebar-group-content"
|
|
795
828
|
className={cn("w-full min-w-0", className)}
|
|
796
829
|
/>
|
|
797
|
-
)
|
|
798
|
-
})
|
|
830
|
+
)
|
|
831
|
+
})
|
|
799
832
|
|
|
800
833
|
export const AnimatedSidebarMenu = forwardRef<
|
|
801
834
|
HTMLUListElement,
|
|
802
835
|
HTMLAttributes<HTMLUListElement>
|
|
803
836
|
>(function AnimatedSidebarMenu(
|
|
804
837
|
{ children, className, ...props },
|
|
805
|
-
forwardedRef
|
|
838
|
+
forwardedRef
|
|
806
839
|
) {
|
|
807
840
|
return (
|
|
808
841
|
<SharedLayoutBg
|
|
@@ -813,12 +846,15 @@ export const AnimatedSidebarMenu = forwardRef<
|
|
|
813
846
|
pillClassName="rounded-xl bg-muted/70"
|
|
814
847
|
pillContainerClassName="inset-y-auto top-0 h-9"
|
|
815
848
|
data-slot="sidebar-menu"
|
|
816
|
-
className={cn(
|
|
849
|
+
className={cn(
|
|
850
|
+
"flex w-full min-w-0 list-none flex-col gap-0.5",
|
|
851
|
+
className
|
|
852
|
+
)}
|
|
817
853
|
>
|
|
818
854
|
{children}
|
|
819
855
|
</SharedLayoutBg>
|
|
820
|
-
)
|
|
821
|
-
})
|
|
856
|
+
)
|
|
857
|
+
})
|
|
822
858
|
|
|
823
859
|
export const AnimatedSidebarMenuItem = forwardRef<
|
|
824
860
|
HTMLLIElement,
|
|
@@ -833,13 +869,15 @@ export const AnimatedSidebarMenuItem = forwardRef<
|
|
|
833
869
|
data-slot="sidebar-menu-item"
|
|
834
870
|
className={cn("relative", className)}
|
|
835
871
|
/>
|
|
836
|
-
)
|
|
837
|
-
})
|
|
838
|
-
|
|
839
|
-
export interface AnimatedSidebarMenuSubProps
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
872
|
+
)
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
export interface AnimatedSidebarMenuSubProps extends Omit<
|
|
876
|
+
HTMLMotionProps<"ul">,
|
|
877
|
+
"children"
|
|
878
|
+
> {
|
|
879
|
+
open: boolean
|
|
880
|
+
children?: ReactNode
|
|
843
881
|
}
|
|
844
882
|
|
|
845
883
|
export const AnimatedSidebarMenuSub = forwardRef<
|
|
@@ -847,10 +885,10 @@ export const AnimatedSidebarMenuSub = forwardRef<
|
|
|
847
885
|
AnimatedSidebarMenuSubProps
|
|
848
886
|
>(function AnimatedSidebarMenuSub(
|
|
849
887
|
{ open, children, className, ...props },
|
|
850
|
-
forwardedRef
|
|
888
|
+
forwardedRef
|
|
851
889
|
) {
|
|
852
|
-
const context = useAnimatedSidebar()
|
|
853
|
-
const panel = useAnimatedSidebarPanel()
|
|
890
|
+
const context = useAnimatedSidebar()
|
|
891
|
+
const panel = useAnimatedSidebarPanel()
|
|
854
892
|
|
|
855
893
|
return (
|
|
856
894
|
<AnimatePresence initial={false} mode="popLayout">
|
|
@@ -866,24 +904,21 @@ export const AnimatedSidebarMenuSub = forwardRef<
|
|
|
866
904
|
transition={context.reduce ? { duration: 0.12 } : undefined}
|
|
867
905
|
data-slot="sidebar-menu-sub"
|
|
868
906
|
className={cn(
|
|
869
|
-
"relative mt-1 ml-5 flex min-w-0 flex-col gap-0.5 border-
|
|
870
|
-
className
|
|
907
|
+
"relative mt-1 ml-5 flex min-w-0 flex-col gap-0.5 border-l border-border pl-3",
|
|
908
|
+
className
|
|
871
909
|
)}
|
|
872
910
|
>
|
|
873
911
|
{children}
|
|
874
912
|
</motion.ul>
|
|
875
913
|
) : null}
|
|
876
914
|
</AnimatePresence>
|
|
877
|
-
)
|
|
878
|
-
})
|
|
915
|
+
)
|
|
916
|
+
})
|
|
879
917
|
|
|
880
918
|
export const AnimatedSidebarMenuSubItem = forwardRef<
|
|
881
919
|
HTMLLIElement,
|
|
882
920
|
HTMLMotionProps<"li">
|
|
883
|
-
>(function AnimatedSidebarMenuSubItem(
|
|
884
|
-
{ className, ...props },
|
|
885
|
-
forwardedRef,
|
|
886
|
-
) {
|
|
921
|
+
>(function AnimatedSidebarMenuSubItem({ className, ...props }, forwardedRef) {
|
|
887
922
|
return (
|
|
888
923
|
<motion.li
|
|
889
924
|
{...props}
|
|
@@ -892,20 +927,20 @@ export const AnimatedSidebarMenuSubItem = forwardRef<
|
|
|
892
927
|
data-slot="sidebar-menu-sub-item"
|
|
893
928
|
className={cn("relative min-w-0", className)}
|
|
894
929
|
/>
|
|
895
|
-
)
|
|
896
|
-
})
|
|
930
|
+
)
|
|
931
|
+
})
|
|
897
932
|
|
|
898
933
|
export interface AnimatedSidebarMenuSubButtonProps {
|
|
899
|
-
children: ReactNode
|
|
900
|
-
icon?: ReactNode
|
|
901
|
-
href?: string
|
|
902
|
-
isActive?: boolean
|
|
903
|
-
disabled?: boolean
|
|
904
|
-
closeOnSelect?: boolean
|
|
905
|
-
target?: "_blank" | "_self" | "_parent" | "_top"
|
|
906
|
-
rel?: string
|
|
907
|
-
onSelect?: () => void
|
|
908
|
-
className?: string
|
|
934
|
+
children: ReactNode
|
|
935
|
+
icon?: ReactNode
|
|
936
|
+
href?: string
|
|
937
|
+
isActive?: boolean
|
|
938
|
+
disabled?: boolean
|
|
939
|
+
closeOnSelect?: boolean
|
|
940
|
+
target?: "_blank" | "_self" | "_parent" | "_top"
|
|
941
|
+
rel?: string
|
|
942
|
+
onSelect?: () => void
|
|
943
|
+
className?: string
|
|
909
944
|
}
|
|
910
945
|
|
|
911
946
|
export function AnimatedSidebarMenuSubButton({
|
|
@@ -920,18 +955,18 @@ export function AnimatedSidebarMenuSubButton({
|
|
|
920
955
|
onSelect,
|
|
921
956
|
className,
|
|
922
957
|
}: AnimatedSidebarMenuSubButtonProps) {
|
|
923
|
-
const context = useAnimatedSidebar()
|
|
958
|
+
const context = useAnimatedSidebar()
|
|
924
959
|
|
|
925
960
|
const select = (
|
|
926
|
-
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement
|
|
961
|
+
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
927
962
|
) => {
|
|
928
963
|
if (disabled) {
|
|
929
|
-
event.preventDefault()
|
|
930
|
-
return
|
|
964
|
+
event.preventDefault()
|
|
965
|
+
return
|
|
931
966
|
}
|
|
932
|
-
onSelect?.()
|
|
933
|
-
if (context.isMobile && closeOnSelect) context.setOpenMobile(false)
|
|
934
|
-
}
|
|
967
|
+
onSelect?.()
|
|
968
|
+
if (context.isMobile && closeOnSelect) context.setOpenMobile(false)
|
|
969
|
+
}
|
|
935
970
|
|
|
936
971
|
const content = (
|
|
937
972
|
<>
|
|
@@ -943,7 +978,7 @@ export function AnimatedSidebarMenuSubButton({
|
|
|
943
978
|
</span>
|
|
944
979
|
<span className="min-w-0 flex-1 truncate">{children}</span>
|
|
945
980
|
</>
|
|
946
|
-
)
|
|
981
|
+
)
|
|
947
982
|
|
|
948
983
|
const interactiveClassName = cn(
|
|
949
984
|
"flex min-h-8 w-full min-w-0 items-center gap-2 rounded-lg px-2 text-left text-xs outline-none",
|
|
@@ -951,17 +986,14 @@ export function AnimatedSidebarMenuSubButton({
|
|
|
951
986
|
"focus-visible:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring",
|
|
952
987
|
isActive && "bg-muted/70 text-foreground",
|
|
953
988
|
disabled && "cursor-not-allowed opacity-40",
|
|
954
|
-
className
|
|
955
|
-
)
|
|
989
|
+
className
|
|
990
|
+
)
|
|
956
991
|
|
|
957
992
|
return href ? (
|
|
958
993
|
<motion.a
|
|
959
994
|
href={href}
|
|
960
995
|
target={target}
|
|
961
|
-
rel={
|
|
962
|
-
rel ??
|
|
963
|
-
(target === "_blank" ? "noreferrer noopener" : undefined)
|
|
964
|
-
}
|
|
996
|
+
rel={rel ?? (target === "_blank" ? "noreferrer noopener" : undefined)}
|
|
965
997
|
aria-current={isActive ? "page" : undefined}
|
|
966
998
|
aria-disabled={disabled || undefined}
|
|
967
999
|
tabIndex={disabled ? -1 : undefined}
|
|
@@ -984,22 +1016,22 @@ export function AnimatedSidebarMenuSubButton({
|
|
|
984
1016
|
>
|
|
985
1017
|
{content}
|
|
986
1018
|
</motion.button>
|
|
987
|
-
)
|
|
1019
|
+
)
|
|
988
1020
|
}
|
|
989
1021
|
|
|
990
1022
|
export interface AnimatedSidebarMenuButtonProps {
|
|
991
|
-
children: ReactNode
|
|
992
|
-
icon?: ReactNode
|
|
993
|
-
badge?: ReactNode
|
|
994
|
-
href?: string
|
|
995
|
-
isActive?: boolean
|
|
996
|
-
ariaExpanded?: boolean
|
|
997
|
-
disabled?: boolean
|
|
998
|
-
closeOnSelect?: boolean
|
|
999
|
-
target?: "_blank" | "_self" | "_parent" | "_top"
|
|
1000
|
-
rel?: string
|
|
1001
|
-
onSelect?: () => void
|
|
1002
|
-
className?: string
|
|
1023
|
+
children: ReactNode
|
|
1024
|
+
icon?: ReactNode
|
|
1025
|
+
badge?: ReactNode
|
|
1026
|
+
href?: string
|
|
1027
|
+
isActive?: boolean
|
|
1028
|
+
ariaExpanded?: boolean
|
|
1029
|
+
disabled?: boolean
|
|
1030
|
+
closeOnSelect?: boolean
|
|
1031
|
+
target?: "_blank" | "_self" | "_parent" | "_top"
|
|
1032
|
+
rel?: string
|
|
1033
|
+
onSelect?: () => void
|
|
1034
|
+
className?: string
|
|
1003
1035
|
}
|
|
1004
1036
|
|
|
1005
1037
|
export function AnimatedSidebarMenuButton({
|
|
@@ -1016,24 +1048,23 @@ export function AnimatedSidebarMenuButton({
|
|
|
1016
1048
|
onSelect,
|
|
1017
1049
|
className,
|
|
1018
1050
|
}: AnimatedSidebarMenuButtonProps) {
|
|
1019
|
-
const context = useAnimatedSidebar()
|
|
1020
|
-
const panel = useAnimatedSidebarPanel()
|
|
1021
|
-
const textLabel = typeof children === "string" ? children : undefined
|
|
1051
|
+
const context = useAnimatedSidebar()
|
|
1052
|
+
const panel = useAnimatedSidebarPanel()
|
|
1053
|
+
const textLabel = typeof children === "string" ? children : undefined
|
|
1022
1054
|
|
|
1023
1055
|
const select = (
|
|
1024
|
-
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement
|
|
1056
|
+
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
1025
1057
|
) => {
|
|
1026
1058
|
if (disabled) {
|
|
1027
|
-
event.preventDefault()
|
|
1028
|
-
return
|
|
1059
|
+
event.preventDefault()
|
|
1060
|
+
return
|
|
1029
1061
|
}
|
|
1030
|
-
onSelect?.()
|
|
1031
|
-
const shouldCloseOnSelect =
|
|
1032
|
-
closeOnSelect ?? ariaExpanded === undefined;
|
|
1062
|
+
onSelect?.()
|
|
1063
|
+
const shouldCloseOnSelect = closeOnSelect ?? ariaExpanded === undefined
|
|
1033
1064
|
if (context.isMobile && shouldCloseOnSelect) {
|
|
1034
|
-
context.setOpenMobile(false)
|
|
1065
|
+
context.setOpenMobile(false)
|
|
1035
1066
|
}
|
|
1036
|
-
}
|
|
1067
|
+
}
|
|
1037
1068
|
|
|
1038
1069
|
const content = (
|
|
1039
1070
|
<>
|
|
@@ -1068,7 +1099,7 @@ export function AnimatedSidebarMenuButton({
|
|
|
1068
1099
|
aria-hidden={panel.collapsed}
|
|
1069
1100
|
className={cn(
|
|
1070
1101
|
"relative z-10 min-w-0 flex-1 truncate",
|
|
1071
|
-
panel.collapsed && "pointer-events-none"
|
|
1102
|
+
panel.collapsed && "pointer-events-none"
|
|
1072
1103
|
)}
|
|
1073
1104
|
>
|
|
1074
1105
|
{children}
|
|
@@ -1094,7 +1125,7 @@ export function AnimatedSidebarMenuButton({
|
|
|
1094
1125
|
</motion.span>
|
|
1095
1126
|
) : null}
|
|
1096
1127
|
</>
|
|
1097
|
-
)
|
|
1128
|
+
)
|
|
1098
1129
|
|
|
1099
1130
|
const interactiveClassName = cn(
|
|
1100
1131
|
"relative flex min-h-9 w-full min-w-0 items-center gap-2.5 overflow-hidden rounded-xl px-3 text-left text-sm font-medium outline-none",
|
|
@@ -1102,17 +1133,14 @@ export function AnimatedSidebarMenuButton({
|
|
|
1102
1133
|
"focus-visible:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring",
|
|
1103
1134
|
isActive && "text-foreground",
|
|
1104
1135
|
disabled && "cursor-not-allowed opacity-40",
|
|
1105
|
-
className
|
|
1106
|
-
)
|
|
1136
|
+
className
|
|
1137
|
+
)
|
|
1107
1138
|
|
|
1108
1139
|
return href ? (
|
|
1109
1140
|
<motion.a
|
|
1110
1141
|
href={href}
|
|
1111
1142
|
target={target}
|
|
1112
|
-
rel={
|
|
1113
|
-
rel ??
|
|
1114
|
-
(target === "_blank" ? "noreferrer noopener" : undefined)
|
|
1115
|
-
}
|
|
1143
|
+
rel={rel ?? (target === "_blank" ? "noreferrer noopener" : undefined)}
|
|
1116
1144
|
aria-current={isActive ? "page" : undefined}
|
|
1117
1145
|
aria-expanded={ariaExpanded}
|
|
1118
1146
|
aria-disabled={disabled || undefined}
|
|
@@ -1141,5 +1169,5 @@ export function AnimatedSidebarMenuButton({
|
|
|
1141
1169
|
>
|
|
1142
1170
|
{content}
|
|
1143
1171
|
</motion.button>
|
|
1144
|
-
)
|
|
1172
|
+
)
|
|
1145
1173
|
}
|