@kushagradhawan/kookie-ui 0.1.18 → 0.1.20
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/components.css +0 -1417
- package/dist/cjs/components/index.d.ts +0 -1
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/components/index.js +1 -1
- package/dist/cjs/components/index.js.map +3 -3
- package/dist/esm/components/index.d.ts +0 -1
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/index.js.map +3 -3
- package/package.json +1 -1
- package/src/components/index.css +0 -1
- package/src/components/index.tsx +1 -1
- package/styles.css +0 -1417
- package/dist/cjs/components/sidebar.d.ts +0 -157
- package/dist/cjs/components/sidebar.d.ts.map +0 -1
- package/dist/cjs/components/sidebar.js +0 -2
- package/dist/cjs/components/sidebar.js.map +0 -7
- package/dist/cjs/components/sidebar.props.d.ts +0 -60
- package/dist/cjs/components/sidebar.props.d.ts.map +0 -1
- package/dist/cjs/components/sidebar.props.js +0 -2
- package/dist/cjs/components/sidebar.props.js.map +0 -7
- package/dist/esm/components/sidebar.d.ts +0 -157
- package/dist/esm/components/sidebar.d.ts.map +0 -1
- package/dist/esm/components/sidebar.js +0 -2
- package/dist/esm/components/sidebar.js.map +0 -7
- package/dist/esm/components/sidebar.props.d.ts +0 -60
- package/dist/esm/components/sidebar.props.d.ts.map +0 -1
- package/dist/esm/components/sidebar.props.js +0 -2
- package/dist/esm/components/sidebar.props.js.map +0 -7
- package/src/components/sidebar.css +0 -1043
- package/src/components/sidebar.props.tsx +0 -54
- package/src/components/sidebar.tsx +0 -740
|
@@ -1,740 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import classNames from 'classnames';
|
|
5
|
-
import { Slot } from './slot';
|
|
6
|
-
import { Accordion } from 'radix-ui';
|
|
7
|
-
|
|
8
|
-
import { sidebarPropDefs } from './sidebar.props';
|
|
9
|
-
import { Theme, useThemeContext } from './theme';
|
|
10
|
-
import { IconButton } from './icon-button';
|
|
11
|
-
import { ScrollArea } from './scroll-area.js';
|
|
12
|
-
import { Separator } from './separator.js';
|
|
13
|
-
import { ChevronDownIcon, ThickChevronRightIcon } from './icons.js';
|
|
14
|
-
import { extractProps } from '../helpers/extract-props.js';
|
|
15
|
-
import { Kbd } from './kbd.js';
|
|
16
|
-
import { Badge } from './badge.js';
|
|
17
|
-
|
|
18
|
-
import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props';
|
|
19
|
-
import type { GetPropDefTypes } from '../props/prop-def';
|
|
20
|
-
import type { BadgeProps } from './badge.js';
|
|
21
|
-
|
|
22
|
-
// Badge configuration type for sidebar menu buttons
|
|
23
|
-
type BadgeConfig = {
|
|
24
|
-
content: React.ReactNode;
|
|
25
|
-
variant?: BadgeProps['variant'];
|
|
26
|
-
size?: BadgeProps['size'];
|
|
27
|
-
color?: BadgeProps['color'];
|
|
28
|
-
highContrast?: BadgeProps['highContrast'];
|
|
29
|
-
radius?: BadgeProps['radius'];
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Sidebar context for state management
|
|
33
|
-
type SidebarContextProps = {
|
|
34
|
-
state: 'expanded' | 'collapsed';
|
|
35
|
-
open: boolean;
|
|
36
|
-
setOpen: (open: boolean) => void;
|
|
37
|
-
openMobile: boolean;
|
|
38
|
-
setOpenMobile: (open: boolean) => void;
|
|
39
|
-
isMobile: boolean;
|
|
40
|
-
toggleSidebar: () => void;
|
|
41
|
-
side: 'left' | 'right';
|
|
42
|
-
type: 'sidebar' | 'floating';
|
|
43
|
-
variant: 'soft' | 'surface' | 'ghost';
|
|
44
|
-
menuVariant: 'solid' | 'soft';
|
|
45
|
-
collapsible: 'offcanvas' | 'icon' | 'none';
|
|
46
|
-
size: '1' | '2';
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const SidebarContext = React.createContext<SidebarContextProps | null>(null);
|
|
50
|
-
|
|
51
|
-
function useSidebar() {
|
|
52
|
-
const context = React.useContext(SidebarContext);
|
|
53
|
-
if (!context) {
|
|
54
|
-
throw new Error('useSidebar must be used within a SidebarProvider.');
|
|
55
|
-
}
|
|
56
|
-
return context;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Hook to detect mobile (simplified version)
|
|
60
|
-
function useIsMobile() {
|
|
61
|
-
const [isMobile, setIsMobile] = React.useState(false);
|
|
62
|
-
|
|
63
|
-
React.useEffect(() => {
|
|
64
|
-
const checkIsMobile = () => {
|
|
65
|
-
setIsMobile(window.innerWidth < 768);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
checkIsMobile();
|
|
69
|
-
window.addEventListener('resize', checkIsMobile);
|
|
70
|
-
return () => window.removeEventListener('resize', checkIsMobile);
|
|
71
|
-
}, []);
|
|
72
|
-
|
|
73
|
-
return isMobile;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Provider component
|
|
77
|
-
interface SidebarProviderProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
78
|
-
defaultOpen?: boolean;
|
|
79
|
-
open?: boolean;
|
|
80
|
-
onOpenChange?: (open: boolean) => void;
|
|
81
|
-
side?: 'left' | 'right';
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const SidebarProvider = React.forwardRef<HTMLDivElement, SidebarProviderProps>(
|
|
85
|
-
(
|
|
86
|
-
{
|
|
87
|
-
defaultOpen = true,
|
|
88
|
-
open: openProp,
|
|
89
|
-
onOpenChange: setOpenProp,
|
|
90
|
-
side = 'left',
|
|
91
|
-
className,
|
|
92
|
-
children,
|
|
93
|
-
...props
|
|
94
|
-
},
|
|
95
|
-
forwardedRef,
|
|
96
|
-
) => {
|
|
97
|
-
const isMobile = useIsMobile();
|
|
98
|
-
const [openMobile, setOpenMobile] = React.useState(false);
|
|
99
|
-
|
|
100
|
-
// Internal state for uncontrolled mode
|
|
101
|
-
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
102
|
-
|
|
103
|
-
// Use controlled state if provided, otherwise internal state
|
|
104
|
-
const open = openProp ?? internalOpen;
|
|
105
|
-
|
|
106
|
-
const setOpen = React.useCallback(
|
|
107
|
-
(value: boolean | ((value: boolean) => boolean)) => {
|
|
108
|
-
const openState = typeof value === 'function' ? value(open) : value;
|
|
109
|
-
if (setOpenProp) {
|
|
110
|
-
setOpenProp(openState);
|
|
111
|
-
} else {
|
|
112
|
-
setInternalOpen(openState);
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
[setOpenProp, open],
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Helper to toggle the sidebar
|
|
119
|
-
const toggleSidebar = React.useCallback(() => {
|
|
120
|
-
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
121
|
-
}, [isMobile, setOpen, setOpenMobile]);
|
|
122
|
-
|
|
123
|
-
// State for data attributes
|
|
124
|
-
const state = open ? 'expanded' : 'collapsed';
|
|
125
|
-
|
|
126
|
-
const contextValue = React.useMemo<Partial<SidebarContextProps>>(
|
|
127
|
-
() => ({
|
|
128
|
-
state,
|
|
129
|
-
open,
|
|
130
|
-
setOpen,
|
|
131
|
-
isMobile,
|
|
132
|
-
openMobile,
|
|
133
|
-
setOpenMobile,
|
|
134
|
-
toggleSidebar,
|
|
135
|
-
side,
|
|
136
|
-
}),
|
|
137
|
-
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, side],
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<div
|
|
142
|
-
{...props}
|
|
143
|
-
ref={forwardedRef}
|
|
144
|
-
className={classNames('rt-SidebarProvider', className)}
|
|
145
|
-
data-state={state}
|
|
146
|
-
data-side={side}
|
|
147
|
-
>
|
|
148
|
-
<SidebarContext.Provider value={contextValue as SidebarContextProps}>
|
|
149
|
-
{children}
|
|
150
|
-
</SidebarContext.Provider>
|
|
151
|
-
</div>
|
|
152
|
-
);
|
|
153
|
-
},
|
|
154
|
-
);
|
|
155
|
-
SidebarProvider.displayName = 'Sidebar.Provider';
|
|
156
|
-
|
|
157
|
-
// Main Sidebar component
|
|
158
|
-
type SidebarOwnProps = GetPropDefTypes<typeof sidebarPropDefs>;
|
|
159
|
-
interface SidebarProps extends ComponentPropsWithout<'div', RemovedProps>, SidebarOwnProps {}
|
|
160
|
-
|
|
161
|
-
const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>((props, forwardedRef) => {
|
|
162
|
-
const themeContext = useThemeContext();
|
|
163
|
-
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
164
|
-
|
|
165
|
-
const {
|
|
166
|
-
size = sidebarPropDefs.size.default,
|
|
167
|
-
variant = sidebarPropDefs.variant.default,
|
|
168
|
-
menuVariant = sidebarPropDefs.menuVariant.default,
|
|
169
|
-
type = sidebarPropDefs.type.default,
|
|
170
|
-
side = sidebarPropDefs.side.default,
|
|
171
|
-
collapsible = sidebarPropDefs.collapsible.default,
|
|
172
|
-
panelBackground,
|
|
173
|
-
color,
|
|
174
|
-
highContrast = sidebarPropDefs.highContrast.default,
|
|
175
|
-
asChild,
|
|
176
|
-
} = props;
|
|
177
|
-
|
|
178
|
-
const { className, children, ...rootProps } = extractProps(props, sidebarPropDefs);
|
|
179
|
-
const { asChild: _, panelBackground: __, ...safeRootProps } = rootProps; // Remove asChild and panelBackground from DOM props
|
|
180
|
-
const resolvedColor = color || themeContext.accentColor;
|
|
181
|
-
|
|
182
|
-
// Update context with current props - we'll pass the resolved values
|
|
183
|
-
const resolvedSize = typeof size === 'object' ? size.initial || '2' : size;
|
|
184
|
-
const context = React.useContext(SidebarContext);
|
|
185
|
-
if (context) {
|
|
186
|
-
context.side = side;
|
|
187
|
-
context.type = type;
|
|
188
|
-
context.variant = variant;
|
|
189
|
-
context.menuVariant = menuVariant;
|
|
190
|
-
context.collapsible = collapsible;
|
|
191
|
-
context.size = resolvedSize;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (collapsible === 'none') {
|
|
195
|
-
return (
|
|
196
|
-
<div
|
|
197
|
-
{...safeRootProps}
|
|
198
|
-
ref={forwardedRef}
|
|
199
|
-
data-accent-color={resolvedColor}
|
|
200
|
-
data-state={state}
|
|
201
|
-
data-side={side}
|
|
202
|
-
data-type={type}
|
|
203
|
-
data-collapsible={collapsible}
|
|
204
|
-
className={classNames('rt-SidebarRoot', `rt-r-size-${size}`, className)}
|
|
205
|
-
>
|
|
206
|
-
<Theme>
|
|
207
|
-
<div
|
|
208
|
-
className={classNames('rt-SidebarContainer', `rt-variant-${variant}`)}
|
|
209
|
-
data-accent-color={resolvedColor}
|
|
210
|
-
data-high-contrast={highContrast || undefined}
|
|
211
|
-
data-side={side}
|
|
212
|
-
data-panel-background={panelBackground}
|
|
213
|
-
>
|
|
214
|
-
{children}
|
|
215
|
-
</div>
|
|
216
|
-
</Theme>
|
|
217
|
-
</div>
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (isMobile) {
|
|
222
|
-
return (
|
|
223
|
-
<div
|
|
224
|
-
{...safeRootProps}
|
|
225
|
-
ref={forwardedRef}
|
|
226
|
-
data-accent-color={resolvedColor}
|
|
227
|
-
data-state={openMobile ? 'open' : 'closed'}
|
|
228
|
-
data-side={side}
|
|
229
|
-
data-type={type}
|
|
230
|
-
data-collapsible={collapsible}
|
|
231
|
-
className={classNames('rt-SidebarRoot', 'rt-SidebarRoot--mobile', className)}
|
|
232
|
-
>
|
|
233
|
-
<Theme>
|
|
234
|
-
<div
|
|
235
|
-
className={classNames(
|
|
236
|
-
'rt-SidebarContainer',
|
|
237
|
-
`rt-variant-${variant}`,
|
|
238
|
-
`rt-r-size-${size}`,
|
|
239
|
-
)}
|
|
240
|
-
data-accent-color={resolvedColor}
|
|
241
|
-
data-high-contrast={highContrast || undefined}
|
|
242
|
-
data-side={side}
|
|
243
|
-
data-panel-background={panelBackground}
|
|
244
|
-
>
|
|
245
|
-
{children}
|
|
246
|
-
</div>
|
|
247
|
-
</Theme>
|
|
248
|
-
</div>
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<div
|
|
254
|
-
{...safeRootProps}
|
|
255
|
-
ref={forwardedRef}
|
|
256
|
-
data-accent-color={resolvedColor}
|
|
257
|
-
data-state={state}
|
|
258
|
-
data-side={side}
|
|
259
|
-
data-type={type}
|
|
260
|
-
data-collapsible={collapsible}
|
|
261
|
-
className={classNames('rt-SidebarRoot', className)}
|
|
262
|
-
>
|
|
263
|
-
<Theme>
|
|
264
|
-
<div
|
|
265
|
-
className={classNames(
|
|
266
|
-
'rt-SidebarContainer',
|
|
267
|
-
`rt-variant-${variant}`,
|
|
268
|
-
`rt-r-size-${size}`,
|
|
269
|
-
)}
|
|
270
|
-
data-accent-color={resolvedColor}
|
|
271
|
-
data-high-contrast={highContrast || undefined}
|
|
272
|
-
data-side={side}
|
|
273
|
-
data-panel-background={panelBackground}
|
|
274
|
-
>
|
|
275
|
-
{children}
|
|
276
|
-
</div>
|
|
277
|
-
</Theme>
|
|
278
|
-
</div>
|
|
279
|
-
);
|
|
280
|
-
});
|
|
281
|
-
Sidebar.displayName = 'Sidebar.Root';
|
|
282
|
-
|
|
283
|
-
// Sidebar content area
|
|
284
|
-
interface SidebarContentProps extends React.ComponentPropsWithoutRef<'div'> {}
|
|
285
|
-
|
|
286
|
-
const SidebarContent = React.forwardRef<HTMLDivElement, SidebarContentProps>(
|
|
287
|
-
({ className, children, ...props }, forwardedRef) => {
|
|
288
|
-
const context = React.useContext(SidebarContext);
|
|
289
|
-
const { size = '2', menuVariant = 'soft' } = context || {};
|
|
290
|
-
|
|
291
|
-
return (
|
|
292
|
-
<ScrollArea type="auto">
|
|
293
|
-
<div
|
|
294
|
-
{...props}
|
|
295
|
-
ref={forwardedRef}
|
|
296
|
-
className={classNames(
|
|
297
|
-
'rt-SidebarContent',
|
|
298
|
-
`rt-r-size-${size}`,
|
|
299
|
-
`rt-menu-variant-${menuVariant}`,
|
|
300
|
-
className,
|
|
301
|
-
)}
|
|
302
|
-
>
|
|
303
|
-
{children}
|
|
304
|
-
</div>
|
|
305
|
-
</ScrollArea>
|
|
306
|
-
);
|
|
307
|
-
},
|
|
308
|
-
);
|
|
309
|
-
SidebarContent.displayName = 'Sidebar.Content';
|
|
310
|
-
|
|
311
|
-
// Sidebar header
|
|
312
|
-
interface SidebarHeaderProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
313
|
-
/**
|
|
314
|
-
* Whether to use the default flex container layout.
|
|
315
|
-
* @default true
|
|
316
|
-
*/
|
|
317
|
-
asContainer?: boolean;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const SidebarHeader = React.forwardRef<HTMLDivElement, SidebarHeaderProps>(
|
|
321
|
-
({ className, asContainer = true, ...props }, forwardedRef) => {
|
|
322
|
-
const context = React.useContext(SidebarContext);
|
|
323
|
-
const { size = '2', menuVariant = 'soft' } = context || {};
|
|
324
|
-
|
|
325
|
-
return (
|
|
326
|
-
<div
|
|
327
|
-
{...props}
|
|
328
|
-
ref={forwardedRef}
|
|
329
|
-
className={classNames(
|
|
330
|
-
'rt-SidebarHeader',
|
|
331
|
-
`rt-r-size-${size}`,
|
|
332
|
-
`rt-menu-variant-${menuVariant}`,
|
|
333
|
-
{
|
|
334
|
-
'rt-SidebarHeader--container': asContainer,
|
|
335
|
-
},
|
|
336
|
-
className,
|
|
337
|
-
)}
|
|
338
|
-
/>
|
|
339
|
-
);
|
|
340
|
-
},
|
|
341
|
-
);
|
|
342
|
-
SidebarHeader.displayName = 'Sidebar.Header';
|
|
343
|
-
|
|
344
|
-
// Sidebar footer
|
|
345
|
-
interface SidebarFooterProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
346
|
-
/**
|
|
347
|
-
* Whether to use the default flex container layout.
|
|
348
|
-
* @default true
|
|
349
|
-
*/
|
|
350
|
-
asContainer?: boolean;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const SidebarFooter = React.forwardRef<HTMLDivElement, SidebarFooterProps>(
|
|
354
|
-
({ className, asContainer = true, ...props }, forwardedRef) => {
|
|
355
|
-
const context = React.useContext(SidebarContext);
|
|
356
|
-
const { size = '2', menuVariant = 'soft' } = context || {};
|
|
357
|
-
|
|
358
|
-
return (
|
|
359
|
-
<div
|
|
360
|
-
{...props}
|
|
361
|
-
ref={forwardedRef}
|
|
362
|
-
className={classNames(
|
|
363
|
-
'rt-SidebarFooter',
|
|
364
|
-
`rt-r-size-${size}`,
|
|
365
|
-
`rt-menu-variant-${menuVariant}`,
|
|
366
|
-
{
|
|
367
|
-
'rt-SidebarFooter--container': asContainer,
|
|
368
|
-
},
|
|
369
|
-
className,
|
|
370
|
-
)}
|
|
371
|
-
/>
|
|
372
|
-
);
|
|
373
|
-
},
|
|
374
|
-
);
|
|
375
|
-
SidebarFooter.displayName = 'Sidebar.Footer';
|
|
376
|
-
|
|
377
|
-
// Sidebar trigger button
|
|
378
|
-
interface SidebarTriggerProps extends ComponentPropsWithout<typeof IconButton, RemovedProps> {}
|
|
379
|
-
|
|
380
|
-
const SidebarTrigger = React.forwardRef<React.ElementRef<typeof IconButton>, SidebarTriggerProps>(
|
|
381
|
-
({ onClick, children, ...props }, forwardedRef) => {
|
|
382
|
-
const { toggleSidebar } = useSidebar();
|
|
383
|
-
|
|
384
|
-
return (
|
|
385
|
-
<IconButton
|
|
386
|
-
{...props}
|
|
387
|
-
ref={forwardedRef}
|
|
388
|
-
variant="ghost"
|
|
389
|
-
onClick={(event) => {
|
|
390
|
-
onClick?.(event);
|
|
391
|
-
toggleSidebar();
|
|
392
|
-
}}
|
|
393
|
-
>
|
|
394
|
-
{children || <ChevronDownIcon />}
|
|
395
|
-
</IconButton>
|
|
396
|
-
);
|
|
397
|
-
},
|
|
398
|
-
);
|
|
399
|
-
SidebarTrigger.displayName = 'Sidebar.Trigger';
|
|
400
|
-
|
|
401
|
-
// Removed SidebarInset - not needed
|
|
402
|
-
|
|
403
|
-
// Sidebar separator
|
|
404
|
-
interface SidebarSeparatorProps extends ComponentPropsWithout<typeof Separator, RemovedProps> {}
|
|
405
|
-
|
|
406
|
-
const SidebarSeparator = React.forwardRef<
|
|
407
|
-
React.ComponentRef<typeof Separator>,
|
|
408
|
-
SidebarSeparatorProps
|
|
409
|
-
>(({ className, ...props }, forwardedRef) => (
|
|
410
|
-
<Separator
|
|
411
|
-
{...props}
|
|
412
|
-
ref={forwardedRef}
|
|
413
|
-
className={classNames('rt-SidebarSeparator', className)}
|
|
414
|
-
/>
|
|
415
|
-
));
|
|
416
|
-
SidebarSeparator.displayName = 'Sidebar.Separator';
|
|
417
|
-
|
|
418
|
-
// Menu components - reusing dropdown menu structure
|
|
419
|
-
interface SidebarMenuProps extends React.ComponentPropsWithoutRef<'ul'> {}
|
|
420
|
-
|
|
421
|
-
const SidebarMenu = React.forwardRef<HTMLUListElement, SidebarMenuProps>(
|
|
422
|
-
({ className, ...props }, forwardedRef) => (
|
|
423
|
-
<ul {...props} ref={forwardedRef} className={classNames('rt-SidebarMenu', className)} />
|
|
424
|
-
),
|
|
425
|
-
);
|
|
426
|
-
SidebarMenu.displayName = 'Sidebar.Menu';
|
|
427
|
-
|
|
428
|
-
interface SidebarMenuItemProps extends React.ComponentPropsWithoutRef<'li'> {}
|
|
429
|
-
|
|
430
|
-
const SidebarMenuItem = React.forwardRef<HTMLLIElement, SidebarMenuItemProps>(
|
|
431
|
-
({ className, ...props }, forwardedRef) => (
|
|
432
|
-
<li {...props} ref={forwardedRef} className={classNames('rt-SidebarMenuItem', className)} />
|
|
433
|
-
),
|
|
434
|
-
);
|
|
435
|
-
SidebarMenuItem.displayName = 'Sidebar.MenuItem';
|
|
436
|
-
|
|
437
|
-
interface SidebarMenuButtonProps extends React.ComponentPropsWithoutRef<'button'> {
|
|
438
|
-
asChild?: boolean;
|
|
439
|
-
isActive?: boolean;
|
|
440
|
-
shortcut?: React.ReactNode;
|
|
441
|
-
badge?: string | BadgeConfig;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
const SidebarMenuButton = React.forwardRef<HTMLButtonElement, SidebarMenuButtonProps>(
|
|
445
|
-
(
|
|
446
|
-
{
|
|
447
|
-
asChild = false,
|
|
448
|
-
isActive = false,
|
|
449
|
-
shortcut,
|
|
450
|
-
badge,
|
|
451
|
-
className,
|
|
452
|
-
children,
|
|
453
|
-
onMouseEnter,
|
|
454
|
-
onMouseLeave,
|
|
455
|
-
...props
|
|
456
|
-
},
|
|
457
|
-
forwardedRef,
|
|
458
|
-
) => {
|
|
459
|
-
const [isHighlighted, setIsHighlighted] = React.useState(false);
|
|
460
|
-
const context = React.useContext(SidebarContext);
|
|
461
|
-
const { size: sidebarSize = '2' } = context || {};
|
|
462
|
-
|
|
463
|
-
const Comp = asChild ? Slot : 'button';
|
|
464
|
-
|
|
465
|
-
return (
|
|
466
|
-
<Comp
|
|
467
|
-
{...props}
|
|
468
|
-
ref={forwardedRef}
|
|
469
|
-
className={classNames('rt-reset', 'rt-SidebarMenuButton', className)}
|
|
470
|
-
data-active={isActive || undefined}
|
|
471
|
-
data-highlighted={isHighlighted || undefined}
|
|
472
|
-
onMouseEnter={(event) => {
|
|
473
|
-
setIsHighlighted(true);
|
|
474
|
-
onMouseEnter?.(event);
|
|
475
|
-
}}
|
|
476
|
-
onMouseLeave={(event) => {
|
|
477
|
-
setIsHighlighted(false);
|
|
478
|
-
onMouseLeave?.(event);
|
|
479
|
-
}}
|
|
480
|
-
>
|
|
481
|
-
{asChild ? (
|
|
482
|
-
children
|
|
483
|
-
) : (
|
|
484
|
-
<>
|
|
485
|
-
{children}
|
|
486
|
-
{/* Badge with soft variant default and size mapping to sidebar size */}
|
|
487
|
-
{badge && (
|
|
488
|
-
<div className="rt-SidebarMenuBadge">
|
|
489
|
-
{typeof badge === 'string' ? (
|
|
490
|
-
<Badge size={sidebarSize} variant="soft">
|
|
491
|
-
{badge}
|
|
492
|
-
</Badge>
|
|
493
|
-
) : (
|
|
494
|
-
<Badge
|
|
495
|
-
size={badge.size || sidebarSize}
|
|
496
|
-
variant={badge.variant || 'soft'}
|
|
497
|
-
color={badge.color}
|
|
498
|
-
highContrast={badge.highContrast}
|
|
499
|
-
radius={badge.radius}
|
|
500
|
-
>
|
|
501
|
-
{badge.content}
|
|
502
|
-
</Badge>
|
|
503
|
-
)}
|
|
504
|
-
</div>
|
|
505
|
-
)}
|
|
506
|
-
{shortcut && (
|
|
507
|
-
<div className="rt-BaseMenuShortcut rt-SidebarMenuShortcut">
|
|
508
|
-
<Kbd size={sidebarSize}>{shortcut}</Kbd>
|
|
509
|
-
</div>
|
|
510
|
-
)}
|
|
511
|
-
</>
|
|
512
|
-
)}
|
|
513
|
-
</Comp>
|
|
514
|
-
);
|
|
515
|
-
},
|
|
516
|
-
);
|
|
517
|
-
SidebarMenuButton.displayName = 'Sidebar.MenuButton';
|
|
518
|
-
|
|
519
|
-
// Sub-menu components using Radix Accordion
|
|
520
|
-
interface SidebarMenuSubProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
521
|
-
defaultOpen?: boolean;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const SidebarMenuSub = React.forwardRef<HTMLDivElement, SidebarMenuSubProps>(
|
|
525
|
-
({ defaultOpen = false, children, ...props }, forwardedRef) => {
|
|
526
|
-
return (
|
|
527
|
-
<div {...props} ref={forwardedRef}>
|
|
528
|
-
<Accordion.Root type="single" collapsible defaultValue={defaultOpen ? 'item' : undefined}>
|
|
529
|
-
<Accordion.Item value="item">{children}</Accordion.Item>
|
|
530
|
-
</Accordion.Root>
|
|
531
|
-
</div>
|
|
532
|
-
);
|
|
533
|
-
},
|
|
534
|
-
);
|
|
535
|
-
SidebarMenuSub.displayName = 'Sidebar.MenuSub';
|
|
536
|
-
|
|
537
|
-
interface SidebarMenuSubTriggerProps
|
|
538
|
-
extends React.ComponentPropsWithoutRef<typeof Accordion.Trigger> {
|
|
539
|
-
asChild?: boolean;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const SidebarMenuSubTrigger = React.forwardRef<
|
|
543
|
-
React.ElementRef<typeof Accordion.Trigger>,
|
|
544
|
-
SidebarMenuSubTriggerProps
|
|
545
|
-
>(
|
|
546
|
-
(
|
|
547
|
-
{ asChild = false, className, children, onMouseEnter, onMouseLeave, ...props },
|
|
548
|
-
forwardedRef,
|
|
549
|
-
) => {
|
|
550
|
-
const [isHighlighted, setIsHighlighted] = React.useState(false);
|
|
551
|
-
|
|
552
|
-
return (
|
|
553
|
-
<Accordion.Header asChild>
|
|
554
|
-
<div>
|
|
555
|
-
<Accordion.Trigger
|
|
556
|
-
{...props}
|
|
557
|
-
ref={forwardedRef}
|
|
558
|
-
asChild={asChild}
|
|
559
|
-
className={classNames(
|
|
560
|
-
'rt-reset',
|
|
561
|
-
'rt-SidebarMenuButton',
|
|
562
|
-
'rt-SidebarMenuSubTrigger',
|
|
563
|
-
className,
|
|
564
|
-
)}
|
|
565
|
-
data-highlighted={isHighlighted || undefined}
|
|
566
|
-
onMouseEnter={(event) => {
|
|
567
|
-
setIsHighlighted(true);
|
|
568
|
-
onMouseEnter?.(event);
|
|
569
|
-
}}
|
|
570
|
-
onMouseLeave={(event) => {
|
|
571
|
-
setIsHighlighted(false);
|
|
572
|
-
onMouseLeave?.(event);
|
|
573
|
-
}}
|
|
574
|
-
>
|
|
575
|
-
{asChild ? (
|
|
576
|
-
children
|
|
577
|
-
) : (
|
|
578
|
-
<>
|
|
579
|
-
{children}
|
|
580
|
-
<ThickChevronRightIcon
|
|
581
|
-
className={classNames(
|
|
582
|
-
'rt-BaseMenuSubTriggerIcon',
|
|
583
|
-
'rt-SidebarMenuSubTriggerIcon',
|
|
584
|
-
)}
|
|
585
|
-
/>
|
|
586
|
-
</>
|
|
587
|
-
)}
|
|
588
|
-
</Accordion.Trigger>
|
|
589
|
-
</div>
|
|
590
|
-
</Accordion.Header>
|
|
591
|
-
);
|
|
592
|
-
},
|
|
593
|
-
);
|
|
594
|
-
SidebarMenuSubTrigger.displayName = 'Sidebar.MenuSubTrigger';
|
|
595
|
-
|
|
596
|
-
interface SidebarMenuSubContentProps
|
|
597
|
-
extends React.ComponentPropsWithoutRef<typeof Accordion.Content> {}
|
|
598
|
-
|
|
599
|
-
const SidebarMenuSubContent = React.forwardRef<
|
|
600
|
-
React.ElementRef<typeof Accordion.Content>,
|
|
601
|
-
SidebarMenuSubContentProps
|
|
602
|
-
>(({ className, children, ...props }, forwardedRef) => {
|
|
603
|
-
return (
|
|
604
|
-
<Accordion.Content
|
|
605
|
-
{...props}
|
|
606
|
-
ref={forwardedRef}
|
|
607
|
-
className={classNames('rt-SidebarMenuSubContent', className)}
|
|
608
|
-
>
|
|
609
|
-
<div className="rt-SidebarMenuSubList">{children}</div>
|
|
610
|
-
</Accordion.Content>
|
|
611
|
-
);
|
|
612
|
-
});
|
|
613
|
-
SidebarMenuSubContent.displayName = 'Sidebar.MenuSubContent';
|
|
614
|
-
|
|
615
|
-
// Group components
|
|
616
|
-
interface SidebarGroupProps extends React.ComponentPropsWithoutRef<'div'> {}
|
|
617
|
-
|
|
618
|
-
const SidebarGroup = React.forwardRef<HTMLDivElement, SidebarGroupProps>(
|
|
619
|
-
({ className, ...props }, forwardedRef) => (
|
|
620
|
-
<div {...props} ref={forwardedRef} className={classNames('rt-SidebarGroup', className)} />
|
|
621
|
-
),
|
|
622
|
-
);
|
|
623
|
-
SidebarGroup.displayName = 'Sidebar.Group';
|
|
624
|
-
|
|
625
|
-
interface SidebarGroupLabelProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
626
|
-
asChild?: boolean;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
const SidebarGroupLabel = React.forwardRef<HTMLDivElement, SidebarGroupLabelProps>(
|
|
630
|
-
({ asChild = false, className, ...props }, forwardedRef) => {
|
|
631
|
-
const Comp = asChild ? Slot : 'div';
|
|
632
|
-
|
|
633
|
-
return (
|
|
634
|
-
<Comp
|
|
635
|
-
{...props}
|
|
636
|
-
ref={forwardedRef}
|
|
637
|
-
className={classNames('rt-SidebarGroupLabel', className)}
|
|
638
|
-
/>
|
|
639
|
-
);
|
|
640
|
-
},
|
|
641
|
-
);
|
|
642
|
-
SidebarGroupLabel.displayName = 'Sidebar.GroupLabel';
|
|
643
|
-
|
|
644
|
-
interface SidebarGroupContentProps extends React.ComponentPropsWithoutRef<'div'> {}
|
|
645
|
-
|
|
646
|
-
const SidebarGroupContent = React.forwardRef<HTMLDivElement, SidebarGroupContentProps>(
|
|
647
|
-
({ className, ...props }, forwardedRef) => (
|
|
648
|
-
<div
|
|
649
|
-
{...props}
|
|
650
|
-
ref={forwardedRef}
|
|
651
|
-
className={classNames('rt-SidebarGroupContent', className)}
|
|
652
|
-
/>
|
|
653
|
-
),
|
|
654
|
-
);
|
|
655
|
-
SidebarGroupContent.displayName = 'Sidebar.GroupContent';
|
|
656
|
-
|
|
657
|
-
// Export all components following shadcn's pattern
|
|
658
|
-
export {
|
|
659
|
-
SidebarProvider as Provider,
|
|
660
|
-
Sidebar as Root,
|
|
661
|
-
SidebarContent as Content,
|
|
662
|
-
SidebarHeader as Header,
|
|
663
|
-
SidebarFooter as Footer,
|
|
664
|
-
SidebarTrigger as Trigger,
|
|
665
|
-
SidebarSeparator as Separator,
|
|
666
|
-
SidebarMenu as Menu,
|
|
667
|
-
SidebarMenuItem as MenuItem,
|
|
668
|
-
SidebarMenuButton as MenuButton,
|
|
669
|
-
SidebarMenuSub as MenuSub,
|
|
670
|
-
SidebarMenuSubTrigger as MenuSubTrigger,
|
|
671
|
-
SidebarMenuSubContent as MenuSubContent,
|
|
672
|
-
SidebarGroup as Group,
|
|
673
|
-
SidebarGroupLabel as GroupLabel,
|
|
674
|
-
SidebarGroupContent as GroupContent,
|
|
675
|
-
// Export hook
|
|
676
|
-
useSidebar,
|
|
677
|
-
};
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* Enhanced Sidebar Header and Footer Usage Examples:
|
|
681
|
-
*
|
|
682
|
-
* 1. Simple default container (backwards compatible):
|
|
683
|
-
* <Sidebar.Header>
|
|
684
|
-
* <Logo />
|
|
685
|
-
* <span>App Name</span>
|
|
686
|
-
* </Sidebar.Header>
|
|
687
|
-
*
|
|
688
|
-
* 2. Custom flex layout:
|
|
689
|
-
* <Sidebar.Header className="rt-justify-between rt-gap-3">
|
|
690
|
-
* <Logo />
|
|
691
|
-
* <Sidebar.MenuButton>
|
|
692
|
-
* <SettingsIcon />
|
|
693
|
-
* </Sidebar.MenuButton>
|
|
694
|
-
* </Sidebar.Header>
|
|
695
|
-
*
|
|
696
|
-
* 3. Column layout for multiple rows:
|
|
697
|
-
* <Sidebar.Header className="rt-flex-col rt-gap-2" asContainer={false}>
|
|
698
|
-
* <div className="rt-flex rt-items-center rt-gap-2">
|
|
699
|
-
* <Logo />
|
|
700
|
-
* <span>App Name</span>
|
|
701
|
-
* </div>
|
|
702
|
-
* <Sidebar.MenuButton>
|
|
703
|
-
* <UserAvatar />
|
|
704
|
-
* <span>John Doe</span>
|
|
705
|
-
* </Sidebar.MenuButton>
|
|
706
|
-
* </Sidebar.Header>
|
|
707
|
-
*
|
|
708
|
-
* 4. Interactive footer with menu button:
|
|
709
|
-
* <Sidebar.Footer>
|
|
710
|
-
* <Sidebar.MenuButton>
|
|
711
|
-
* <UserIcon />
|
|
712
|
-
* <span>Settings</span>
|
|
713
|
-
* <ChevronUpIcon />
|
|
714
|
-
* </Sidebar.MenuButton>
|
|
715
|
-
* </Sidebar.Footer>
|
|
716
|
-
*
|
|
717
|
-
* 5. Custom footer layout:
|
|
718
|
-
* <Sidebar.Footer className="rt-justify-between">
|
|
719
|
-
* <span>v1.0.0</span>
|
|
720
|
-
* <Sidebar.MenuButton>
|
|
721
|
-
* <HelpIcon />
|
|
722
|
-
* </Sidebar.MenuButton>
|
|
723
|
-
* </Sidebar.Footer>
|
|
724
|
-
*
|
|
725
|
-
* Available utility classes:
|
|
726
|
-
* - Layout: rt-flex-row, rt-flex-col
|
|
727
|
-
* - Alignment: rt-items-center, rt-items-start, rt-items-end
|
|
728
|
-
* - Justification: rt-justify-between, rt-justify-center, rt-justify-start, rt-justify-end
|
|
729
|
-
* - Gap: rt-gap-1, rt-gap-2, rt-gap-3, rt-gap-4
|
|
730
|
-
*/
|
|
731
|
-
|
|
732
|
-
export type {
|
|
733
|
-
SidebarProviderProps as ProviderProps,
|
|
734
|
-
SidebarProps as RootProps,
|
|
735
|
-
SidebarContentProps as ContentProps,
|
|
736
|
-
SidebarHeaderProps as HeaderProps,
|
|
737
|
-
SidebarFooterProps as FooterProps,
|
|
738
|
-
SidebarTriggerProps as TriggerProps,
|
|
739
|
-
BadgeConfig,
|
|
740
|
-
};
|