@mbao01/common 0.0.47 → 0.0.49
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/types/components/Command/Command.d.ts +6 -6
- package/dist/types/components/Form/MultiSelect/MultiSelect.d.ts +2 -2
- package/dist/types/components/Sidebar/Sidebar.d.ts +39 -0
- package/dist/types/components/Sidebar/SidebarContext.d.ts +2 -0
- package/dist/types/components/Sidebar/SidebarGroup.d.ts +13 -0
- package/dist/types/components/Sidebar/SidebarMenu.d.ts +30 -0
- package/dist/types/components/Sidebar/constants.d.ts +48 -0
- package/dist/types/components/Sidebar/hooks/index.d.ts +1 -0
- package/dist/types/components/Sidebar/hooks/useSidebar/index.d.ts +1 -0
- package/dist/types/components/Sidebar/hooks/useSidebar/useSidebar.d.ts +1 -0
- package/dist/types/components/Sidebar/index.d.ts +4 -0
- package/dist/types/components/Sidebar/stories/examples/Sidebar.example.d.ts +57 -0
- package/dist/types/components/Sidebar/stories/examples/components/AppMain.d.ts +3 -0
- package/dist/types/components/Sidebar/stories/examples/components/AppSidebar.d.ts +6 -0
- package/dist/types/components/Sidebar/stories/examples/components/SearchForm.d.ts +1 -0
- package/dist/types/components/Sidebar/stories/examples/components/VersionSwitcher.d.ts +4 -0
- package/dist/types/components/Sidebar/types.d.ts +55 -0
- package/dist/types/hooks/index.d.ts +1 -0
- package/dist/types/hooks/useIsMobile/index.d.ts +1 -0
- package/dist/types/hooks/useIsMobile/useIsMobile.d.ts +1 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +6 -6
- package/src/components/Anchor/Anchor.tsx +2 -2
- package/src/components/Calendar/Calendar.tsx +1 -1
- package/src/components/Carousel/Carousel.tsx +1 -1
- package/src/components/Chart/stories/examples/LineChart.tsx +2 -2
- package/src/components/Combobox/Combobox.tsx +2 -2
- package/src/components/Command/Command.tsx +2 -2
- package/src/components/DatePicker/DatePicker.tsx +2 -2
- package/src/components/DatePicker/DateRangePicker.tsx +2 -2
- package/src/components/DatePicker/MultipleDatesPicker.tsx +2 -2
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/FileUploader/FileUploader.tsx +2 -2
- package/src/components/Form/DatetimeInput/DatetimeCalendar.tsx +2 -2
- package/src/components/Form/MultiSelect/MultiSelect.tsx +2 -2
- package/src/components/Form/Select/Select.tsx +1 -1
- package/src/components/Form/TagsInput/TagsInput.tsx +2 -2
- package/src/components/Menu/ContextMenu/ContextMenu.tsx +2 -2
- package/src/components/Menu/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/components/Menu/Menubar/Menubar.tsx +2 -2
- package/src/components/Menu/NavigationMenu/NavigationMenu.tsx +1 -1
- package/src/components/Pagination/Pagination.tsx +2 -2
- package/src/components/Sidebar/Sidebar.tsx +326 -0
- package/src/components/Sidebar/SidebarContext.tsx +6 -0
- package/src/components/Sidebar/SidebarGroup.tsx +72 -0
- package/src/components/Sidebar/SidebarMenu.tsx +205 -0
- package/src/components/Sidebar/constants.ts +206 -0
- package/src/components/Sidebar/hooks/index.ts +1 -0
- package/src/components/Sidebar/hooks/useSidebar/index.ts +1 -0
- package/src/components/Sidebar/hooks/useSidebar/useSidebar.ts +11 -0
- package/src/components/Sidebar/index.ts +4 -0
- package/src/components/Sidebar/stories/examples/Sidebar.example.tsx +155 -0
- package/src/components/Sidebar/stories/examples/components/AppMain.tsx +36 -0
- package/src/components/Sidebar/stories/examples/components/AppSidebar.tsx +531 -0
- package/src/components/Sidebar/stories/examples/components/SearchForm.tsx +26 -0
- package/src/components/Sidebar/stories/examples/components/VersionSwitcher.tsx +45 -0
- package/src/components/Sidebar/types.ts +74 -0
- package/src/components/Widget/Widgets.example.tsx +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useIsMobile/index.ts +1 -0
- package/src/hooks/useIsMobile/useIsMobile.ts +19 -0
- package/src/index.ts +3 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { FileRejection, useDropzone } from "react-dropzone";
|
|
5
|
-
import {
|
|
5
|
+
import { DeleteIcon } from "lucide-react";
|
|
6
6
|
import { toast } from "sonner";
|
|
7
7
|
import type { DirectionOptions, FileUploaderInputProps, FileUploaderProps } from "./types";
|
|
8
8
|
import { cn } from "../../utilities";
|
|
@@ -268,7 +268,7 @@ const FileUploaderItem = forwardRef<
|
|
|
268
268
|
onClick={() => removeFileFromSet(index)}
|
|
269
269
|
>
|
|
270
270
|
<span className="sr-only">remove item {index}</span>
|
|
271
|
-
<
|
|
271
|
+
<DeleteIcon
|
|
272
272
|
className={cn("w-4 h-4 shrink-0 hover:stroke-destructive duration-200 ease-in-out", {
|
|
273
273
|
"text-error": isSelected,
|
|
274
274
|
})}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { CalendarDaysIcon } from "lucide-react";
|
|
3
3
|
import { cn } from "../../../utilities";
|
|
4
4
|
import { Button } from "../../Button";
|
|
5
5
|
import { Calendar } from "../../Calendar";
|
|
@@ -43,7 +43,7 @@ export const DatetimeCalendar = ({
|
|
|
43
43
|
disabled={disabled}
|
|
44
44
|
className={cn(getDatetimeCalendarTriggerClasses({ size }))}
|
|
45
45
|
>
|
|
46
|
-
<
|
|
46
|
+
<CalendarDaysIcon className={getDatetimeCalendarIconClasses({ size })} />
|
|
47
47
|
<span className="sr-only">calendar</span>
|
|
48
48
|
</Button>
|
|
49
49
|
</Popover.Trigger>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ComponentRef, KeyboardEvent, MouseEvent, SyntheticEvent } from "react";
|
|
4
4
|
import { forwardRef, useCallback, useRef, useState } from "react";
|
|
5
|
-
import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons";
|
|
6
5
|
import { Command as CommandPrimitive } from "cmdk";
|
|
6
|
+
import { CheckIcon, XIcon } from "lucide-react";
|
|
7
7
|
import type {
|
|
8
8
|
Item,
|
|
9
9
|
MultiSelectContentProps,
|
|
@@ -235,7 +235,7 @@ export const MultiSelectTrigger = ({
|
|
|
235
235
|
disabled={disabled}
|
|
236
236
|
>
|
|
237
237
|
<span className="sr-only">Remove {label} option</span>
|
|
238
|
-
<
|
|
238
|
+
<XIcon className="h-4 w-4 hover:stroke-destructive" />
|
|
239
239
|
</button>
|
|
240
240
|
</Badge>
|
|
241
241
|
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "@radix-ui/react-icons";
|
|
5
4
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
5
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
6
6
|
import type { SelectContentProps, SelectItemProps, SelectTriggerProps } from "./types";
|
|
7
7
|
import { cn } from "../../../utilities";
|
|
8
8
|
import {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ChangeEvent, ClipboardEvent, KeyboardEvent, MouseEvent, SyntheticEvent } from "react";
|
|
4
4
|
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { XIcon } from "lucide-react";
|
|
6
6
|
import type { TagsInputProps } from "./types";
|
|
7
7
|
import { cn } from "../../../utilities";
|
|
8
8
|
import { Badge } from "../../Badge";
|
|
@@ -250,7 +250,7 @@ export const TagsInput = forwardRef<HTMLDivElement, TagsInputProps>(
|
|
|
250
250
|
className={cn(getTagDeleteClasses())}
|
|
251
251
|
>
|
|
252
252
|
<span className="sr-only">Remove {tag} option</span>
|
|
253
|
-
<
|
|
253
|
+
<XIcon className="h-4 w-4" />
|
|
254
254
|
</button>
|
|
255
255
|
</Badge>
|
|
256
256
|
))}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
|
5
|
-
import { CheckIcon, ChevronRightIcon,
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, DotIcon } from "lucide-react";
|
|
6
6
|
import type {
|
|
7
7
|
ContextMenuCheckboxItemProps,
|
|
8
8
|
ContextMenuContentProps,
|
|
@@ -113,7 +113,7 @@ const ContextMenuRadioItem = forwardRef<
|
|
|
113
113
|
>
|
|
114
114
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
115
115
|
<ContextMenuPrimitive.ItemIndicator>
|
|
116
|
-
<
|
|
116
|
+
<DotIcon className="h-4 w-4 fill-current" />
|
|
117
117
|
</ContextMenuPrimitive.ItemIndicator>
|
|
118
118
|
</span>
|
|
119
119
|
{children}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
5
|
-
import { CheckIcon, ChevronRightIcon,
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, DotIcon } from "lucide-react";
|
|
6
6
|
import type {
|
|
7
7
|
DropdownMenuCheckboxItemProps,
|
|
8
8
|
DropdownMenuContentProps,
|
|
@@ -114,7 +114,7 @@ const DropdownMenuRadioItem = forwardRef<
|
|
|
114
114
|
>
|
|
115
115
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
116
116
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
117
|
-
<
|
|
117
|
+
<DotIcon className="h-4 w-4 fill-current" />
|
|
118
118
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
119
119
|
</span>
|
|
120
120
|
{children}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
|
-
import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons";
|
|
5
4
|
import * as MenubarPrimitive from "@radix-ui/react-menubar";
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, DotIcon } from "lucide-react";
|
|
6
6
|
import type {
|
|
7
7
|
MenubarCheckboxItemProps,
|
|
8
8
|
MenubarContentProps,
|
|
@@ -137,7 +137,7 @@ const MenubarRadioItem = forwardRef<
|
|
|
137
137
|
>
|
|
138
138
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
139
139
|
<MenubarPrimitive.ItemIndicator>
|
|
140
|
-
<
|
|
140
|
+
<DotIcon className="h-4 w-4 fill-current" />
|
|
141
141
|
</MenubarPrimitive.ItemIndicator>
|
|
142
142
|
</span>
|
|
143
143
|
{children}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { forwardRef } from "react";
|
|
2
|
-
import { ChevronDownIcon } from "@radix-ui/react-icons";
|
|
3
2
|
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
|
3
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
4
4
|
import type {
|
|
5
5
|
NavigationMenuContentProps,
|
|
6
6
|
NavigationMenuIndicatorProps,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { forwardRef } from "react";
|
|
2
|
-
import { ChevronLeftIcon, ChevronRightIcon,
|
|
2
|
+
import { ChevronLeftIcon, ChevronRightIcon, EllipsisIcon } from "lucide-react";
|
|
3
3
|
import type { PaginationProps } from "./types";
|
|
4
4
|
import { cn } from "../../utilities";
|
|
5
5
|
import { getButtonClasses } from "../Button/constants";
|
|
@@ -92,7 +92,7 @@ PaginationNext.displayName = "PaginationNext";
|
|
|
92
92
|
|
|
93
93
|
const PaginationEllipsis = ({ className, ...props }: PaginationEllipsisProps) => (
|
|
94
94
|
<span aria-hidden className={cn(getPaginationEllipsisClasses(), className)} {...props}>
|
|
95
|
-
<
|
|
95
|
+
<EllipsisIcon className="h-4 w-4" />
|
|
96
96
|
<span className="sr-only">More pages</span>
|
|
97
97
|
</span>
|
|
98
98
|
);
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ComponentProps, CSSProperties, ElementRef, HTMLAttributes, MouseEvent } from "react";
|
|
4
|
+
import { forwardRef, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { PanelLeftIcon } from "lucide-react";
|
|
6
|
+
import type { ButtonProps } from "../Button/types";
|
|
7
|
+
import type { InputProps } from "../Form/Input/types";
|
|
8
|
+
import type { SeparatorProps } from "../Separator/types";
|
|
9
|
+
import type { SidebarContextProps, SidebarProps, SidebarProviderProps } from "./types";
|
|
10
|
+
import { useIsMobile } from "../../hooks";
|
|
11
|
+
import { cn } from "../../utilities";
|
|
12
|
+
import { Button } from "../Button";
|
|
13
|
+
import { Dialog } from "../Dialog";
|
|
14
|
+
import { Input } from "../Form";
|
|
15
|
+
import { Separator } from "../Separator";
|
|
16
|
+
import { Tooltip } from "../Tooltip";
|
|
17
|
+
import {
|
|
18
|
+
getSidebarClasses,
|
|
19
|
+
getSidebarContentClasses,
|
|
20
|
+
getSidebarFooterClasses,
|
|
21
|
+
getSidebarGapClasses,
|
|
22
|
+
getSidebarHeaderClasses,
|
|
23
|
+
getSidebarInnerClasses,
|
|
24
|
+
getSidebarInputClasses,
|
|
25
|
+
getSidebarInsetClasses,
|
|
26
|
+
getSidebarMobileClasses,
|
|
27
|
+
getSidebarOuterClasses,
|
|
28
|
+
getSidebarProviderClasses,
|
|
29
|
+
getSidebarRailClasses,
|
|
30
|
+
getSidebarSeparatorClasses,
|
|
31
|
+
getSidebarTriggerClasses,
|
|
32
|
+
SIDEBAR_COOKIE_MAX_AGE,
|
|
33
|
+
SIDEBAR_COOKIE_NAME,
|
|
34
|
+
SIDEBAR_KEYBOARD_SHORTCUT,
|
|
35
|
+
SIDEBAR_WIDTH,
|
|
36
|
+
SIDEBAR_WIDTH_ICON,
|
|
37
|
+
SIDEBAR_WIDTH_MOBILE,
|
|
38
|
+
} from "./constants";
|
|
39
|
+
import { useSidebar } from "./hooks";
|
|
40
|
+
import { SidebarContext } from "./SidebarContext";
|
|
41
|
+
|
|
42
|
+
const Sidebar = ({
|
|
43
|
+
side = "left",
|
|
44
|
+
variant = "sidebar",
|
|
45
|
+
collapsible = "offcanvas",
|
|
46
|
+
className,
|
|
47
|
+
children,
|
|
48
|
+
...props
|
|
49
|
+
}: SidebarProps) => {
|
|
50
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
51
|
+
|
|
52
|
+
if (collapsible === "none") {
|
|
53
|
+
return (
|
|
54
|
+
<div className={cn(getSidebarClasses({ collapsible }), className)} {...props}>
|
|
55
|
+
{children}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isMobile) {
|
|
61
|
+
return (
|
|
62
|
+
<Dialog open={openMobile} onOpenChange={setOpenMobile} {...props}>
|
|
63
|
+
<Dialog.Content
|
|
64
|
+
side={side}
|
|
65
|
+
variant="sheet"
|
|
66
|
+
data-mobile="true"
|
|
67
|
+
data-sidebar="sidebar"
|
|
68
|
+
className={cn(getSidebarMobileClasses({ isMobile }), className)}
|
|
69
|
+
style={
|
|
70
|
+
{
|
|
71
|
+
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
|
|
72
|
+
} as CSSProperties
|
|
73
|
+
}
|
|
74
|
+
>
|
|
75
|
+
<div className="flex h-full w-full flex-col">{children}</div>
|
|
76
|
+
</Dialog.Content>
|
|
77
|
+
</Dialog>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div
|
|
83
|
+
data-side={side}
|
|
84
|
+
data-state={state}
|
|
85
|
+
data-collapsible={state === "collapsed" ? collapsible : ""}
|
|
86
|
+
data-variant={variant}
|
|
87
|
+
className={getSidebarOuterClasses()}
|
|
88
|
+
>
|
|
89
|
+
{/* This is what handles the sidebar gap on desktop */}
|
|
90
|
+
<div className={getSidebarGapClasses({ variant })} />
|
|
91
|
+
<div className={getSidebarInnerClasses({ side, variant })} {...props}>
|
|
92
|
+
<div
|
|
93
|
+
data-sidebar="sidebar"
|
|
94
|
+
className={cn(getSidebarMobileClasses({ isMobile }), className)}
|
|
95
|
+
>
|
|
96
|
+
{children}
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
Sidebar.displayName = "Sidebar";
|
|
103
|
+
|
|
104
|
+
const SidebarTrigger = forwardRef<ElementRef<typeof Button>, ButtonProps>(
|
|
105
|
+
({ className, onClick, ...props }, ref) => {
|
|
106
|
+
const { toggleSidebar } = useSidebar();
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<Button
|
|
110
|
+
ref={ref}
|
|
111
|
+
variant="ghost"
|
|
112
|
+
data-sidebar="trigger"
|
|
113
|
+
className={cn(getSidebarTriggerClasses(), className)}
|
|
114
|
+
onClick={(event: MouseEvent<HTMLButtonElement>) => {
|
|
115
|
+
onClick?.(event);
|
|
116
|
+
toggleSidebar();
|
|
117
|
+
}}
|
|
118
|
+
{...props}
|
|
119
|
+
>
|
|
120
|
+
<PanelLeftIcon className="w-4 h-4" />
|
|
121
|
+
<span className="sr-only">Toggle Sidebar</span>
|
|
122
|
+
</Button>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
SidebarTrigger.displayName = "SidebarTrigger";
|
|
127
|
+
|
|
128
|
+
const SidebarRail = forwardRef<HTMLButtonElement, ComponentProps<"button">>(
|
|
129
|
+
({ className, ...props }, ref) => {
|
|
130
|
+
const { toggleSidebar } = useSidebar();
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<button
|
|
134
|
+
ref={ref}
|
|
135
|
+
data-sidebar="rail"
|
|
136
|
+
aria-label="Toggle Sidebar"
|
|
137
|
+
tabIndex={-1}
|
|
138
|
+
onClick={toggleSidebar}
|
|
139
|
+
title="Toggle Sidebar"
|
|
140
|
+
className={cn(getSidebarRailClasses(), className)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
SidebarRail.displayName = "SidebarRail";
|
|
147
|
+
|
|
148
|
+
const SidebarInset = forwardRef<HTMLDivElement, ComponentProps<"main">>(
|
|
149
|
+
({ className, ...props }, ref) => {
|
|
150
|
+
return <main ref={ref} className={cn(getSidebarInsetClasses(), className)} {...props} />;
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
SidebarInset.displayName = "SidebarInset";
|
|
154
|
+
|
|
155
|
+
const SidebarInput = forwardRef<ElementRef<typeof Input>, InputProps>(
|
|
156
|
+
({ className, ...props }, ref) => {
|
|
157
|
+
return (
|
|
158
|
+
<Input
|
|
159
|
+
ref={ref}
|
|
160
|
+
data-sidebar="input"
|
|
161
|
+
className={cn(getSidebarInputClasses(), className)}
|
|
162
|
+
{...props}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
SidebarInput.displayName = "SidebarInput";
|
|
168
|
+
|
|
169
|
+
const SidebarHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
170
|
+
({ className, ...props }, ref) => {
|
|
171
|
+
return (
|
|
172
|
+
<div
|
|
173
|
+
ref={ref}
|
|
174
|
+
data-sidebar="header"
|
|
175
|
+
className={cn(getSidebarHeaderClasses(), className)}
|
|
176
|
+
{...props}
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
SidebarHeader.displayName = "SidebarHeader";
|
|
182
|
+
|
|
183
|
+
const SidebarFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
184
|
+
({ className, ...props }, ref) => {
|
|
185
|
+
return (
|
|
186
|
+
<div
|
|
187
|
+
ref={ref}
|
|
188
|
+
data-sidebar="footer"
|
|
189
|
+
className={cn(getSidebarFooterClasses(), className)}
|
|
190
|
+
{...props}
|
|
191
|
+
/>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
SidebarFooter.displayName = "SidebarFooter";
|
|
196
|
+
|
|
197
|
+
const SidebarSeparator = ({ className, ...props }: SeparatorProps) => {
|
|
198
|
+
return (
|
|
199
|
+
<Separator
|
|
200
|
+
data-sidebar="separator"
|
|
201
|
+
className={cn(getSidebarSeparatorClasses(), className)}
|
|
202
|
+
{...props}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
SidebarSeparator.displayName = "SidebarSeparator";
|
|
207
|
+
|
|
208
|
+
const SidebarContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
209
|
+
({ className, ...props }, ref) => {
|
|
210
|
+
return (
|
|
211
|
+
<div
|
|
212
|
+
ref={ref}
|
|
213
|
+
data-sidebar="content"
|
|
214
|
+
className={cn(getSidebarContentClasses(), className)}
|
|
215
|
+
{...props}
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
SidebarContent.displayName = "SidebarContent";
|
|
221
|
+
|
|
222
|
+
const SidebarProvider = forwardRef<HTMLDivElement, SidebarProviderProps>(
|
|
223
|
+
(
|
|
224
|
+
{
|
|
225
|
+
defaultOpen = true,
|
|
226
|
+
open: openProp,
|
|
227
|
+
onOpenChange: setOpenProp,
|
|
228
|
+
className,
|
|
229
|
+
style,
|
|
230
|
+
children,
|
|
231
|
+
tooltipProvider,
|
|
232
|
+
...props
|
|
233
|
+
},
|
|
234
|
+
ref
|
|
235
|
+
) => {
|
|
236
|
+
const isMobile = useIsMobile();
|
|
237
|
+
const [openMobile, setOpenMobile] = useState(false);
|
|
238
|
+
|
|
239
|
+
// This is the internal state of the sidebar.
|
|
240
|
+
// We use openProp and setOpenProp for control from outside the component.
|
|
241
|
+
const [_open, _setOpen] = useState(defaultOpen);
|
|
242
|
+
const open = openProp ?? _open;
|
|
243
|
+
const setOpen = useCallback(
|
|
244
|
+
(value: boolean | ((value: boolean) => boolean)) => {
|
|
245
|
+
if (setOpenProp) {
|
|
246
|
+
return setOpenProp?.(typeof value === "function" ? value(open) : value);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
_setOpen(value);
|
|
250
|
+
|
|
251
|
+
// This sets the cookie to keep the sidebar state.
|
|
252
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
253
|
+
},
|
|
254
|
+
[setOpenProp, open]
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// Helper to toggle the sidebar.
|
|
258
|
+
const toggleSidebar = useCallback(() => {
|
|
259
|
+
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
260
|
+
}, [isMobile, setOpen, setOpenMobile]);
|
|
261
|
+
|
|
262
|
+
// Adds a keyboard shortcut to toggle the sidebar.
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
265
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
266
|
+
event.preventDefault();
|
|
267
|
+
toggleSidebar();
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
272
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
273
|
+
}, [toggleSidebar]);
|
|
274
|
+
|
|
275
|
+
// We add a state so that we can do data-state="expanded" or "collapsed".
|
|
276
|
+
// This makes it easier to style the sidebar with Tailwind classes.
|
|
277
|
+
const state = open ? "expanded" : "collapsed";
|
|
278
|
+
|
|
279
|
+
const contextValue = useMemo<SidebarContextProps>(
|
|
280
|
+
() => ({
|
|
281
|
+
state,
|
|
282
|
+
open,
|
|
283
|
+
setOpen,
|
|
284
|
+
isMobile,
|
|
285
|
+
openMobile,
|
|
286
|
+
setOpenMobile,
|
|
287
|
+
toggleSidebar,
|
|
288
|
+
}),
|
|
289
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<SidebarContext.Provider value={contextValue}>
|
|
294
|
+
<Tooltip.Provider delayDuration={0} {...tooltipProvider}>
|
|
295
|
+
<div
|
|
296
|
+
style={
|
|
297
|
+
{
|
|
298
|
+
"--sidebar-width": SIDEBAR_WIDTH,
|
|
299
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
300
|
+
...style,
|
|
301
|
+
} as CSSProperties
|
|
302
|
+
}
|
|
303
|
+
className={cn(getSidebarProviderClasses(), className)}
|
|
304
|
+
ref={ref}
|
|
305
|
+
{...props}
|
|
306
|
+
>
|
|
307
|
+
{children}
|
|
308
|
+
</div>
|
|
309
|
+
</Tooltip.Provider>
|
|
310
|
+
</SidebarContext.Provider>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
SidebarProvider.displayName = "SidebarProvider";
|
|
315
|
+
|
|
316
|
+
Sidebar.Content = SidebarContent;
|
|
317
|
+
Sidebar.Footer = SidebarFooter;
|
|
318
|
+
Sidebar.Header = SidebarHeader;
|
|
319
|
+
Sidebar.Input = SidebarInput;
|
|
320
|
+
Sidebar.Inset = SidebarInset;
|
|
321
|
+
Sidebar.Provider = SidebarProvider;
|
|
322
|
+
Sidebar.Rail = SidebarRail;
|
|
323
|
+
Sidebar.Separator = SidebarSeparator;
|
|
324
|
+
Sidebar.Trigger = SidebarTrigger;
|
|
325
|
+
|
|
326
|
+
export { Sidebar };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import type {
|
|
4
|
+
SidebarGroupActionProps,
|
|
5
|
+
SidebarGroupContentProps,
|
|
6
|
+
SidebarGroupLabelProps,
|
|
7
|
+
SidebarGroupProps,
|
|
8
|
+
} from "./types";
|
|
9
|
+
import { cn } from "../../utilities";
|
|
10
|
+
import {
|
|
11
|
+
getSidebarGroupActionClasses,
|
|
12
|
+
getSidebarGroupClasses,
|
|
13
|
+
getSidebarGroupContentClasses,
|
|
14
|
+
getSidebarGroupLabelClasses,
|
|
15
|
+
} from "./constants";
|
|
16
|
+
|
|
17
|
+
const SidebarGroup = ({ className, ...props }: SidebarGroupProps) => {
|
|
18
|
+
return (
|
|
19
|
+
<div data-sidebar="group" className={cn(getSidebarGroupClasses(), className)} {...props} />
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
SidebarGroup.displayName = "SidebarGroup";
|
|
23
|
+
|
|
24
|
+
const SidebarGroupLabel = forwardRef<HTMLDivElement, SidebarGroupLabelProps>(
|
|
25
|
+
({ className, asChild = false, ...props }, ref) => {
|
|
26
|
+
const Comp = asChild ? Slot : "div";
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Comp
|
|
30
|
+
ref={ref}
|
|
31
|
+
data-sidebar="group-label"
|
|
32
|
+
className={cn(getSidebarGroupLabelClasses(), className)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
SidebarGroupLabel.displayName = "SidebarGroupLabel";
|
|
39
|
+
|
|
40
|
+
const SidebarGroupAction = forwardRef<HTMLButtonElement, SidebarGroupActionProps>(
|
|
41
|
+
({ className, asChild = false, ...props }, ref) => {
|
|
42
|
+
const Comp = asChild ? Slot : "button";
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Comp
|
|
46
|
+
ref={ref}
|
|
47
|
+
data-sidebar="group-action"
|
|
48
|
+
className={cn(getSidebarGroupActionClasses(), className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
SidebarGroupAction.displayName = "SidebarGroupAction";
|
|
55
|
+
|
|
56
|
+
const SidebarGroupContent = forwardRef<HTMLDivElement, SidebarGroupContentProps>(
|
|
57
|
+
({ className, ...props }, ref) => (
|
|
58
|
+
<div
|
|
59
|
+
ref={ref}
|
|
60
|
+
data-sidebar="group-content"
|
|
61
|
+
className={cn(getSidebarGroupContentClasses(), className)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
SidebarGroupContent.displayName = "SidebarGroupContent";
|
|
67
|
+
|
|
68
|
+
SidebarGroup.Action = SidebarGroupAction;
|
|
69
|
+
SidebarGroup.Content = SidebarGroupContent;
|
|
70
|
+
SidebarGroup.Label = SidebarGroupLabel;
|
|
71
|
+
|
|
72
|
+
export { SidebarGroup };
|