@chat-js/cli 0.6.1 → 0.6.2

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