@alpic-ai/ui 0.0.0-dev.ea71979 → 0.0.0-dev.eaf64f5

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.
@@ -5,7 +5,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
5
5
 
6
6
  //#region src/components/alert.d.ts
7
7
  declare const alertVariants: (props?: ({
8
- variant?: "default" | "destructive" | "warning" | "success" | null | undefined;
8
+ variant?: "destructive" | "default" | "success" | "warning" | null | undefined;
9
9
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  interface AlertProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {}
11
11
  declare function Alert({
@@ -6,7 +6,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
6
6
 
7
7
  //#region src/components/avatar.d.ts
8
8
  declare const avatarVariants: (props?: ({
9
- size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
9
+ size?: "sm" | "lg" | "md" | "xs" | "xl" | null | undefined;
10
10
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
11
11
  type AvatarSize = NonNullable<VariantProps<typeof avatarVariants>["size"]>;
12
12
  type AvatarStatus = "online";
@@ -4,7 +4,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
4
4
 
5
5
  //#region src/components/badge.d.ts
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "warning" | "success" | "secondary" | "primary" | "error" | null | undefined;
7
+ variant?: "primary" | "secondary" | "success" | "warning" | "error" | null | undefined;
8
8
  size?: "sm" | "md" | null | undefined;
9
9
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}
@@ -5,7 +5,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
5
5
 
6
6
  //#region src/components/button.d.ts
7
7
  declare const buttonVariants: (props?: ({
8
- variant?: "destructive" | "secondary" | "primary" | "tertiary" | "link" | "link-muted" | null | undefined;
8
+ variant?: "link" | "primary" | "secondary" | "tertiary" | "link-muted" | "destructive" | null | undefined;
9
9
  size?: "default" | "icon" | "icon-rounded" | "pill" | null | undefined;
10
10
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
11
11
  interface ButtonProps extends React.ComponentProps<"button">, VariantProps<typeof buttonVariants> {
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { Loader2 } from "lucide-react";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { cva } from "class-variance-authority";
6
- import { Slot } from "@radix-ui/react-slot";
6
+ import { Slot, Slottable } from "@radix-ui/react-slot";
7
7
  //#region src/components/button.tsx
8
8
  const buttonVariants = cva([
9
9
  "inline-flex items-center justify-center gap-1 whitespace-nowrap",
@@ -50,7 +50,7 @@ const buttonVariants = cva([
50
50
  }
51
51
  });
52
52
  function Button({ className, variant, size, type = "button", asChild = false, loading = false, icon, disabled, children, ...props }) {
53
- return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
53
+ return /* @__PURE__ */ jsxs(asChild ? Slot : "button", {
54
54
  "data-slot": "button",
55
55
  className: cn(buttonVariants({
56
56
  variant,
@@ -60,7 +60,7 @@ function Button({ className, variant, size, type = "button", asChild = false, lo
60
60
  disabled: disabled || loading,
61
61
  "aria-busy": loading || void 0,
62
62
  ...props,
63
- children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [loading ? /* @__PURE__ */ jsx(Loader2, { className: "motion-safe:animate-spin" }) : icon, children] })
63
+ children: [loading ? /* @__PURE__ */ jsx(Loader2, { className: "motion-safe:animate-spin" }) : icon, asChild ? /* @__PURE__ */ jsx(Slottable, { children }) : children]
64
64
  });
65
65
  }
66
66
  //#endregion
@@ -23,7 +23,7 @@ declare function DropdownMenuGroup({
23
23
  ...props
24
24
  }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): _$react_jsx_runtime0.JSX.Element;
25
25
  declare const dropdownMenuItemVariants: (props?: ({
26
- variant?: "default" | "destructive" | null | undefined;
26
+ variant?: "destructive" | "default" | null | undefined;
27
27
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
28
28
  declare function DropdownMenuItem({
29
29
  className,
@@ -0,0 +1,13 @@
1
+ import { Button } from "./button.mjs";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { ComponentProps } from "react";
4
+
5
+ //#region src/components/github-button.d.ts
6
+ type GitHubButtonProps = Omit<ComponentProps<typeof Button>, "variant" | "icon">;
7
+ declare function GitHubButton({
8
+ className,
9
+ children,
10
+ ...props
11
+ }: GitHubButtonProps): _$react_jsx_runtime0.JSX.Element;
12
+ //#endregion
13
+ export { GitHubButton, type GitHubButtonProps };
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.mjs";
3
+ import { Button } from "./button.mjs";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/github-button.tsx
6
+ const GITHUB_ICON_PATH = "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12";
7
+ function GitHubIcon() {
8
+ return /* @__PURE__ */ jsx("svg", {
9
+ fill: "currentColor",
10
+ viewBox: "0 0 24 24",
11
+ "aria-hidden": "true",
12
+ children: /* @__PURE__ */ jsx("path", { d: GITHUB_ICON_PATH })
13
+ });
14
+ }
15
+ function GitHubButton({ className, children, ...props }) {
16
+ return /* @__PURE__ */ jsx(Button, {
17
+ ...props,
18
+ icon: /* @__PURE__ */ jsx(GitHubIcon, {}),
19
+ className: cn("bg-foreground text-background [@media(hover:hover)]:hover:bg-foreground/90", className),
20
+ children
21
+ });
22
+ }
23
+ //#endregion
24
+ export { GitHubButton };
@@ -17,6 +17,18 @@ const SIDEBAR_WIDTH = "15rem";
17
17
  const SIDEBAR_WIDTH_MOBILE = "16rem";
18
18
  const SIDEBAR_WIDTH_ICON = "3.5rem";
19
19
  const SIDEBAR_KEYBOARD_SHORTCUT = "b";
20
+ const INTERACTIVE_SIDEBAR_ELEMENT_SELECTOR = [
21
+ "a",
22
+ "button",
23
+ "input",
24
+ "select",
25
+ "textarea",
26
+ "[role='button']",
27
+ "[role='link']",
28
+ "[role='menuitem']",
29
+ "[contenteditable='true']",
30
+ "[tabindex]:not([tabindex='-1'])"
31
+ ].join(", ");
20
32
  const SidebarContext = React.createContext(null);
21
33
  function useSidebar() {
22
34
  const context = React.useContext(SidebarContext);
@@ -80,7 +92,17 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: set
80
92
  });
81
93
  }
82
94
  function Sidebar({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, ...props }) {
83
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
95
+ const { isMobile, state, openMobile, setOpenMobile, open, setOpen } = useSidebar();
96
+ function handleSurfaceClickCapture(event) {
97
+ if (event.target instanceof Element && event.target.closest(INTERACTIVE_SIDEBAR_ELEMENT_SELECTOR)) return;
98
+ if (!open) {
99
+ event.preventDefault();
100
+ event.stopPropagation();
101
+ setOpen(true);
102
+ return;
103
+ }
104
+ setOpen(false);
105
+ }
84
106
  if (collapsible === "none") return /* @__PURE__ */ jsx("div", {
85
107
  "data-slot": "sidebar",
86
108
  className: cn("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col", className),
@@ -124,7 +146,8 @@ function Sidebar({ side = "left", variant = "sidebar", collapsible = "offcanvas"
124
146
  children: /* @__PURE__ */ jsx("div", {
125
147
  "data-sidebar": "sidebar",
126
148
  "data-slot": "sidebar-inner",
127
- className: "bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",
149
+ className: "bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full cursor-pointer flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",
150
+ onClickCapture: handleSurfaceClickCapture,
128
151
  children
129
152
  })
130
153
  })]
@@ -181,7 +204,7 @@ function SidebarRail({ className, ...props }) {
181
204
  tabIndex: -1,
182
205
  onClick: toggleSidebar,
183
206
  title: "Toggle Sidebar",
184
- className: cn("[@media(hover:hover)]:hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "[@media(hover:hover)]:hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className),
207
+ className: cn("absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex", "[@media(hover:hover)]:hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className),
185
208
  ...props
186
209
  });
187
210
  }
@@ -203,14 +226,20 @@ function SidebarHeader({ className, icon, title, children, ...props }) {
203
226
  return /* @__PURE__ */ jsxs("div", {
204
227
  "data-slot": "sidebar-header",
205
228
  "data-sidebar": "header",
206
- className: cn("flex flex-col gap-2 p-2", className),
229
+ className: cn("flex flex-col gap-2 py-2", className),
207
230
  ...props,
208
231
  children: [/* @__PURE__ */ jsxs("div", {
209
232
  className: "flex h-8 items-center gap-2 px-3",
210
233
  children: [
211
- /* @__PURE__ */ jsx("div", {
212
- className: "shrink-0",
213
- children: icon
234
+ /* @__PURE__ */ jsxs("span", {
235
+ className: "relative flex size-8 shrink-0 items-center justify-center",
236
+ children: [/* @__PURE__ */ jsx("span", {
237
+ className: "transition-opacity duration-200 group-data-[collapsible=icon]:group-hover:opacity-0",
238
+ children: icon
239
+ }), /* @__PURE__ */ jsx(SidebarTrigger, {
240
+ tabIndex: -1,
241
+ className: "absolute inset-0 opacity-0 transition-opacity duration-200 group-data-[collapsible=icon]:group-hover:opacity-100"
242
+ })]
214
243
  }),
215
244
  /* @__PURE__ */ jsx("span", {
216
245
  className: "text-foreground text-md min-w-0 truncate font-medium group-data-[collapsible=icon]:hidden",
@@ -4,7 +4,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
4
4
 
5
5
  //#region src/components/skeleton.d.ts
6
6
  declare const skeletonVariants: (props?: ({
7
- shape?: "rectangle" | "circle" | null | undefined;
7
+ shape?: "circle" | "rectangle" | null | undefined;
8
8
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
9
9
  interface SkeletonProps extends React.ComponentProps<"div">, VariantProps<typeof skeletonVariants> {}
10
10
  declare function Skeleton({
@@ -4,8 +4,8 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
4
4
 
5
5
  //#region src/components/spinner.d.ts
6
6
  declare const spinnerVariants: (props?: ({
7
- variant?: "secondary" | "primary" | null | undefined;
8
- size?: "sm" | "md" | "lg" | "xl" | null | undefined;
7
+ variant?: "primary" | "secondary" | null | undefined;
8
+ size?: "sm" | "lg" | "md" | "xl" | null | undefined;
9
9
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  interface SpinnerProps extends Omit<React.ComponentProps<"svg">, "children">, VariantProps<typeof spinnerVariants> {}
11
11
  declare function Spinner({
@@ -4,7 +4,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
4
4
 
5
5
  //#region src/components/status-dot.d.ts
6
6
  declare const statusDotVariants: (props?: ({
7
- variant?: "destructive" | "warning" | "success" | "muted" | null | undefined;
7
+ variant?: "destructive" | "success" | "warning" | "muted" | null | undefined;
8
8
  pulse?: boolean | null | undefined;
9
9
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  interface StatusDotProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof statusDotVariants> {}
@@ -6,7 +6,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
6
6
 
7
7
  //#region src/components/tabs.d.ts
8
8
  declare const tabsTriggerVariants: (props?: ({
9
- variant?: "default" | "pill" | "line" | null | undefined;
9
+ variant?: "line" | "default" | "pill" | null | undefined;
10
10
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
11
11
  declare function Tabs({
12
12
  className,
@@ -14,7 +14,7 @@ declare function Tabs({
14
14
  ...props
15
15
  }: React.ComponentProps<typeof TabsPrimitive.Root>): _$react_jsx_runtime0.JSX.Element;
16
16
  declare const tabsListVariants: (props?: ({
17
- variant?: "default" | "line" | null | undefined;
17
+ variant?: "line" | "default" | null | undefined;
18
18
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
19
19
  declare function TabsList({
20
20
  className,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpic-ai/ui",
3
- "version": "0.0.0-dev.ea71979",
3
+ "version": "0.0.0-dev.eaf64f5",
4
4
  "description": "Alpic design system — shared UI components",
5
5
  "type": "module",
6
6
  "exports": {
@@ -26,9 +26,9 @@
26
26
  "lucide-react": "^1.8.0",
27
27
  "react": "^19.2.5",
28
28
  "react-dom": "^19.2.5",
29
- "react-hook-form": "^7.72.1",
29
+ "react-hook-form": "^7.73.1",
30
30
  "sonner": "^2.0.7",
31
- "tailwindcss": "^4.2.2",
31
+ "tailwindcss": "^4.2.3",
32
32
  "tw-animate-css": "^1.4.0"
33
33
  },
34
34
  "dependencies": {
@@ -56,17 +56,17 @@
56
56
  },
57
57
  "devDependencies": {
58
58
  "@ladle/react": "^5.1.1",
59
- "@tailwindcss/postcss": "^4.2.2",
59
+ "@tailwindcss/postcss": "^4.2.3",
60
60
  "@types/react": "19.2.14",
61
61
  "@types/react-dom": "19.2.3",
62
62
  "lucide-react": "^1.8.0",
63
- "react-hook-form": "^7.72.1",
63
+ "react-hook-form": "^7.73.1",
64
64
  "shx": "^0.4.0",
65
65
  "sonner": "^2.0.7",
66
- "tailwindcss": "^4.2.2",
67
- "tsdown": "^0.21.8",
66
+ "tailwindcss": "^4.2.3",
67
+ "tsdown": "^0.21.9",
68
68
  "tw-animate-css": "^1.4.0",
69
- "typescript": "^6.0.2"
69
+ "typescript": "^6.0.3"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "shx rm -rf dist && tsdown",
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Slot } from "@radix-ui/react-slot";
3
+ import { Slot, Slottable } from "@radix-ui/react-slot";
4
4
  import { cva, type VariantProps } from "class-variance-authority";
5
5
  import { Loader2 } from "lucide-react";
6
6
  import type * as React from "react";
@@ -90,14 +90,8 @@ function Button({
90
90
  aria-busy={loading || undefined}
91
91
  {...props}
92
92
  >
93
- {asChild ? (
94
- children
95
- ) : (
96
- <>
97
- {loading ? <Loader2 className="motion-safe:animate-spin" /> : icon}
98
- {children}
99
- </>
100
- )}
93
+ {loading ? <Loader2 className="motion-safe:animate-spin" /> : icon}
94
+ {asChild ? <Slottable>{children}</Slottable> : children}
101
95
  </Comp>
102
96
  );
103
97
  }
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+ import type { ComponentProps } from "react";
4
+
5
+ import { cn } from "../lib/cn";
6
+ import { Button } from "./button";
7
+
8
+ const GITHUB_ICON_PATH =
9
+ "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12";
10
+
11
+ function GitHubIcon() {
12
+ return (
13
+ <svg fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
14
+ <path d={GITHUB_ICON_PATH} />
15
+ </svg>
16
+ );
17
+ }
18
+
19
+ type GitHubButtonProps = Omit<ComponentProps<typeof Button>, "variant" | "icon">;
20
+
21
+ function GitHubButton({ className, children, ...props }: GitHubButtonProps) {
22
+ return (
23
+ <Button
24
+ {...props}
25
+ icon={<GitHubIcon />}
26
+ className={cn("bg-foreground text-background [@media(hover:hover)]:hover:bg-foreground/90", className)}
27
+ >
28
+ {children}
29
+ </Button>
30
+ );
31
+ }
32
+
33
+ export type { GitHubButtonProps };
34
+ export { GitHubButton };
@@ -19,6 +19,19 @@ const SIDEBAR_WIDTH_MOBILE = "16rem";
19
19
  const SIDEBAR_WIDTH_ICON = "3.5rem";
20
20
  const SIDEBAR_KEYBOARD_SHORTCUT = "b";
21
21
 
22
+ const INTERACTIVE_SIDEBAR_ELEMENT_SELECTOR = [
23
+ "a",
24
+ "button",
25
+ "input",
26
+ "select",
27
+ "textarea",
28
+ "[role='button']",
29
+ "[role='link']",
30
+ "[role='menuitem']",
31
+ "[contenteditable='true']",
32
+ "[tabindex]:not([tabindex='-1'])",
33
+ ].join(", ");
34
+
22
35
  type SidebarContextProps = {
23
36
  state: "expanded" | "collapsed";
24
37
  open: boolean;
@@ -142,7 +155,25 @@ function Sidebar({
142
155
  variant?: "sidebar" | "floating" | "inset";
143
156
  collapsible?: "offcanvas" | "icon" | "none";
144
157
  }) {
145
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
158
+ const { isMobile, state, openMobile, setOpenMobile, open, setOpen } = useSidebar();
159
+
160
+ function handleSurfaceClickCapture(event: React.MouseEvent<HTMLDivElement>) {
161
+ const clickedInteractiveElement =
162
+ event.target instanceof Element && event.target.closest(INTERACTIVE_SIDEBAR_ELEMENT_SELECTOR);
163
+
164
+ if (clickedInteractiveElement) {
165
+ return;
166
+ }
167
+
168
+ if (!open) {
169
+ event.preventDefault();
170
+ event.stopPropagation();
171
+ setOpen(true);
172
+ return;
173
+ }
174
+
175
+ setOpen(false);
176
+ }
146
177
 
147
178
  if (collapsible === "none") {
148
179
  return (
@@ -220,7 +251,8 @@ function Sidebar({
220
251
  <div
221
252
  data-sidebar="sidebar"
222
253
  data-slot="sidebar-inner"
223
- className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
254
+ className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full cursor-pointer flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
255
+ onClickCapture={handleSurfaceClickCapture}
224
256
  >
225
257
  {children}
226
258
  </div>
@@ -272,9 +304,7 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
272
304
  onClick={toggleSidebar}
273
305
  title="Toggle Sidebar"
274
306
  className={cn(
275
- "[@media(hover:hover)]:hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
276
- "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
277
- "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
307
+ "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
278
308
  "[@media(hover:hover)]:hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
279
309
  "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
280
310
  "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
@@ -322,11 +352,19 @@ function SidebarHeader({ className, icon, title, children, ...props }: SidebarHe
322
352
  <div
323
353
  data-slot="sidebar-header"
324
354
  data-sidebar="header"
325
- className={cn("flex flex-col gap-2 p-2", className)}
355
+ className={cn("flex flex-col gap-2 py-2", className)}
326
356
  {...props}
327
357
  >
328
358
  <div className="flex h-8 items-center gap-2 px-3">
329
- <div className="shrink-0">{icon}</div>
359
+ <span className="relative flex size-8 shrink-0 items-center justify-center">
360
+ <span className="transition-opacity duration-200 group-data-[collapsible=icon]:group-hover:opacity-0">
361
+ {icon}
362
+ </span>
363
+ <SidebarTrigger
364
+ tabIndex={-1}
365
+ className="absolute inset-0 opacity-0 transition-opacity duration-200 group-data-[collapsible=icon]:group-hover:opacity-100"
366
+ />
367
+ </span>
330
368
  <span className="text-foreground text-md min-w-0 truncate font-medium group-data-[collapsible=icon]:hidden">
331
369
  {title}
332
370
  </span>
@@ -107,7 +107,8 @@ export const AllVariants: Story = () => (
107
107
  <UserFooter />
108
108
  </Sidebar>
109
109
  <SidebarInset>
110
- <div className="p-4">
110
+ <div className="flex items-center gap-2 p-4">
111
+ <SidebarTrigger />
111
112
  <span className="type-text-sm text-muted-foreground">Sub-menus expand inline under their parent</span>
112
113
  </div>
113
114
  </SidebarInset>
@@ -169,7 +170,8 @@ export const AllVariants: Story = () => (
169
170
  <UserFooter />
170
171
  </Sidebar>
171
172
  <SidebarInset>
172
- <div className="p-4">
173
+ <div className="flex items-center gap-2 p-4">
174
+ <SidebarTrigger />
173
175
  <span className="type-text-sm text-muted-foreground">Groups with labels, badges, and separator</span>
174
176
  </div>
175
177
  </SidebarInset>
@@ -195,7 +197,8 @@ export const AllVariants: Story = () => (
195
197
  <UserFooter />
196
198
  </Sidebar>
197
199
  <SidebarInset>
198
- <div className="p-4">
200
+ <div className="flex items-center gap-2 p-4">
201
+ <SidebarTrigger />
199
202
  <span className="type-text-sm text-muted-foreground">Loading state with skeleton placeholders</span>
200
203
  </div>
201
204
  </SidebarInset>