@alpic-ai/ui 0.0.0-dev.d4f6edf → 0.0.0-dev.d783e71

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 (61) hide show
  1. package/dist/components/accordion-card.d.mts +1 -1
  2. package/dist/components/accordion.d.mts +1 -1
  3. package/dist/components/alert.d.mts +2 -2
  4. package/dist/components/attachment-tile.mjs +1 -1
  5. package/dist/components/avatar.d.mts +2 -2
  6. package/dist/components/badge.d.mts +1 -1
  7. package/dist/components/breadcrumb.d.mts +1 -1
  8. package/dist/components/button.d.mts +5 -3
  9. package/dist/components/button.mjs +20 -6
  10. package/dist/components/card.d.mts +1 -1
  11. package/dist/components/checkbox.d.mts +1 -1
  12. package/dist/components/collapsible.d.mts +1 -1
  13. package/dist/components/combobox.d.mts +1 -1
  14. package/dist/components/combobox.mjs +1 -1
  15. package/dist/components/command.d.mts +1 -1
  16. package/dist/components/copyable.d.mts +1 -1
  17. package/dist/components/copyable.mjs +1 -1
  18. package/dist/components/description-list.d.mts +1 -1
  19. package/dist/components/dialog.d.mts +1 -1
  20. package/dist/components/dropdown-menu.d.mts +2 -2
  21. package/dist/components/form.d.mts +1 -1
  22. package/dist/components/form.mjs +1 -1
  23. package/dist/components/github-button.d.mts +13 -0
  24. package/dist/components/github-button.mjs +24 -0
  25. package/dist/components/input-group.d.mts +1 -1
  26. package/dist/components/input.d.mts +1 -1
  27. package/dist/components/input.mjs +1 -1
  28. package/dist/components/label.d.mts +1 -1
  29. package/dist/components/pagination.d.mts +1 -1
  30. package/dist/components/popover.d.mts +1 -1
  31. package/dist/components/radio-group.d.mts +1 -1
  32. package/dist/components/scroll-area.d.mts +1 -1
  33. package/dist/components/select.d.mts +1 -1
  34. package/dist/components/separator.d.mts +1 -1
  35. package/dist/components/sheet.d.mts +1 -1
  36. package/dist/components/sidebar.d.mts +1 -1
  37. package/dist/components/sidebar.mjs +41 -12
  38. package/dist/components/skeleton.d.mts +1 -1
  39. package/dist/components/sonner.d.mts +1 -1
  40. package/dist/components/spinner.d.mts +1 -1
  41. package/dist/components/status-dot.d.mts +1 -1
  42. package/dist/components/switch.d.mts +1 -1
  43. package/dist/components/table.d.mts +1 -1
  44. package/dist/components/tabs.d.mts +2 -2
  45. package/dist/components/tabs.mjs +1 -1
  46. package/dist/components/textarea.d.mts +1 -1
  47. package/dist/components/textarea.mjs +1 -1
  48. package/dist/components/toggle-group.d.mts +1 -1
  49. package/dist/components/toggle-group.mjs +1 -1
  50. package/dist/components/tooltip-icon-button.mjs +1 -1
  51. package/dist/components/tooltip.d.mts +1 -1
  52. package/dist/components/typography.d.mts +1 -1
  53. package/package.json +6 -6
  54. package/src/components/button.tsx +13 -9
  55. package/src/components/combobox.tsx +18 -6
  56. package/src/components/github-button.tsx +34 -0
  57. package/src/components/sidebar.tsx +48 -10
  58. package/src/hooks/use-copy-to-clipboard.ts +6 -2
  59. package/src/stories/button.stories.tsx +23 -1
  60. package/src/stories/sidebar.stories.tsx +6 -3
  61. package/src/styles/tokens.css +173 -0
@@ -1,12 +1,12 @@
1
- import * as React from "react";
2
1
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
2
  import { VariantProps } from "class-variance-authority";
3
+ import * as React from "react";
4
4
  import * as TabsPrimitive from "@radix-ui/react-tabs";
5
5
  import * as _$class_variance_authority_types0 from "class-variance-authority/types";
6
6
 
7
7
  //#region src/components/tabs.d.ts
8
8
  declare const tabsTriggerVariants: (props?: ({
9
- variant?: "default" | "line" | "pill" | null | undefined;
9
+ variant?: "default" | "pill" | "line" | null | undefined;
10
10
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
11
11
  declare function Tabs({
12
12
  className,
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
- import { createContext, use } from "react";
4
3
  import { jsx } from "react/jsx-runtime";
5
4
  import { cva } from "class-variance-authority";
5
+ import { createContext, use } from "react";
6
6
  import { Slot } from "@radix-ui/react-slot";
7
7
  import * as TabsPrimitive from "@radix-ui/react-tabs";
8
8
  //#region src/components/tabs.tsx
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
1
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
2
+ import * as React from "react";
3
3
 
4
4
  //#region src/components/textarea.d.ts
5
5
  interface TextareaProps extends React.ComponentProps<"textarea"> {
@@ -2,9 +2,9 @@
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
4
4
  import { Label } from "./label.mjs";
5
- import * as React from "react";
6
5
  import { Info } from "lucide-react";
7
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
+ import * as React from "react";
8
8
  //#region src/components/textarea.tsx
9
9
  function Textarea({ className, id, label, required, hint, error, tooltip, ...props }) {
10
10
  const generatedId = React.useId();
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
1
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
2
  import { VariantProps } from "class-variance-authority";
3
+ import * as React from "react";
4
4
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
5
5
  import * as _$class_variance_authority_types0 from "class-variance-authority/types";
6
6
 
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
- import * as React from "react";
4
3
  import { jsx } from "react/jsx-runtime";
5
4
  import { cva } from "class-variance-authority";
5
+ import * as React from "react";
6
6
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
7
7
  //#region src/components/toggle-group.tsx
8
8
  const toggleGroupItemVariants = cva([
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { Button } from "./button.mjs";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
4
- import { forwardRef } from "react";
5
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { forwardRef } from "react";
6
6
  import { Slottable } from "@radix-ui/react-slot";
7
7
  //#region src/components/tooltip-icon-button.tsx
8
8
  const TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", ...rest }, ref) => {
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
1
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
2
+ import * as React from "react";
3
3
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
4
4
 
5
5
  //#region src/components/tooltip.d.ts
@@ -1,5 +1,5 @@
1
- import { ReactNode } from "react";
2
1
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
2
+ import { ReactNode } from "react";
3
3
 
4
4
  //#region src/components/typography.d.ts
5
5
  declare function H1({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpic-ai/ui",
3
- "version": "0.0.0-dev.d4f6edf",
3
+ "version": "0.0.0-dev.d783e71",
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,14 +56,14 @@
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",
66
+ "tailwindcss": "^4.2.3",
67
67
  "tsdown": "^0.21.9",
68
68
  "tw-animate-css": "^1.4.0",
69
69
  "typescript": "^6.0.3"
@@ -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";
@@ -46,6 +46,13 @@ const buttonVariants = cva(
46
46
  "bg-destructive text-destructive-foreground",
47
47
  "[@media(hover:hover)]:hover:bg-destructive-hover",
48
48
  ].join(" "),
49
+ cta: [
50
+ "button-cta",
51
+ "h-9 px-4 gap-2 rounded-md",
52
+ "dark:bg-inverted text-foreground",
53
+ "transition-[transform,filter] duration-300 ease-out",
54
+ "active:scale-[0.99]",
55
+ ].join(" "),
49
56
  },
50
57
  size: {
51
58
  default: "type-text-sm",
@@ -65,6 +72,7 @@ interface ButtonProps extends React.ComponentProps<"button">, VariantProps<typeo
65
72
  asChild?: boolean;
66
73
  loading?: boolean;
67
74
  icon?: React.ReactNode;
75
+ iconTrailing?: React.ReactNode;
68
76
  }
69
77
 
70
78
  function Button({
@@ -75,6 +83,7 @@ function Button({
75
83
  asChild = false,
76
84
  loading = false,
77
85
  icon,
86
+ iconTrailing,
78
87
  disabled,
79
88
  children,
80
89
  ...props
@@ -90,14 +99,9 @@ function Button({
90
99
  aria-busy={loading || undefined}
91
100
  {...props}
92
101
  >
93
- {asChild ? (
94
- children
95
- ) : (
96
- <>
97
- {loading ? <Loader2 className="motion-safe:animate-spin" /> : icon}
98
- {children}
99
- </>
100
- )}
102
+ {loading ? <Loader2 className="motion-safe:animate-spin" /> : icon}
103
+ {asChild ? <Slottable>{children}</Slottable> : children}
104
+ {!loading && iconTrailing ? <span data-cta-icon-trailing>{iconTrailing}</span> : null}
101
105
  </Comp>
102
106
  );
103
107
  }
@@ -84,7 +84,9 @@ function Combobox(props: ComboboxProps) {
84
84
 
85
85
  const onOpenChange = useCallback(
86
86
  (newOpen: boolean) => {
87
- if (!isOpenControlled) setUncontrolledOpen(newOpen);
87
+ if (!isOpenControlled) {
88
+ setUncontrolledOpen(newOpen);
89
+ }
88
90
  controlledOnOpenChange?.(newOpen);
89
91
  },
90
92
  [isOpenControlled, controlledOnOpenChange],
@@ -105,7 +107,9 @@ function Combobox(props: ComboboxProps) {
105
107
 
106
108
  const isSelected = useCallback(
107
109
  (itemValue: string) => {
108
- if (multiple) return multiValues.includes(itemValue);
110
+ if (multiple) {
111
+ return multiValues.includes(itemValue);
112
+ }
109
113
  return singleValue === itemValue;
110
114
  },
111
115
  [multiple, singleValue, multiValues],
@@ -123,11 +127,15 @@ function Combobox(props: ComboboxProps) {
123
127
  const next = multiValues.includes(itemValue)
124
128
  ? multiValues.filter((val) => val !== itemValue)
125
129
  : [...multiValues, itemValue];
126
- if (!isControlledMulti) setUncontrolledMultiValue(next);
130
+ if (!isControlledMulti) {
131
+ setUncontrolledMultiValue(next);
132
+ }
127
133
  onValueChangeMulti?.(next);
128
134
  // Stay open in multi mode
129
135
  } else {
130
- if (!isControlledSingle) setUncontrolledSingleValue(itemValue);
136
+ if (!isControlledSingle) {
137
+ setUncontrolledSingleValue(itemValue);
138
+ }
131
139
  onValueChangeSingle?.(itemValue);
132
140
  onOpenChange(false);
133
141
  }
@@ -145,9 +153,13 @@ function Combobox(props: ComboboxProps) {
145
153
 
146
154
  const onDeselect = useCallback(
147
155
  (itemValue: string) => {
148
- if (!multiple) return;
156
+ if (!multiple) {
157
+ return;
158
+ }
149
159
  const next = multiValues.filter((val) => val !== itemValue);
150
- if (!isControlledMulti) setUncontrolledMultiValue(next);
160
+ if (!isControlledMulti) {
161
+ setUncontrolledMultiValue(next);
162
+ }
151
163
  onValueChangeMulti?.(next);
152
164
  },
153
165
  [multiple, isControlledMulti, onValueChangeMulti, multiValues],
@@ -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,13 +155,31 @@ 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 (
149
180
  <div
150
181
  data-slot="sidebar"
151
- className={cn("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col", className)}
182
+ className={cn("bg-sidebar-surface text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col", className)}
152
183
  {...props}
153
184
  >
154
185
  {children}
@@ -163,7 +194,7 @@ function Sidebar({
163
194
  data-sidebar="sidebar"
164
195
  data-slot="sidebar"
165
196
  data-mobile="true"
166
- className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
197
+ className="bg-sidebar-surface text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
167
198
  style={
168
199
  {
169
200
  "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
@@ -212,7 +243,7 @@ function Sidebar({
212
243
  // Adjust the padding for floating and inset variants.
213
244
  variant === "floating" || variant === "inset"
214
245
  ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
215
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
246
+ : "border-sidebar-border group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
216
247
  className,
217
248
  )}
218
249
  {...props}
@@ -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-surface 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>
@@ -8,7 +8,9 @@ export function useCopyToClipboard({ resetDelay = 2000 }: { resetDelay?: number
8
8
 
9
9
  useEffect(() => {
10
10
  return () => {
11
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
11
+ if (timeoutRef.current) {
12
+ clearTimeout(timeoutRef.current);
13
+ }
12
14
  };
13
15
  }, []);
14
16
 
@@ -16,7 +18,9 @@ export function useCopyToClipboard({ resetDelay = 2000 }: { resetDelay?: number
16
18
  (text: string) => {
17
19
  navigator.clipboard.writeText(text).then(() => {
18
20
  setIsCopied(true);
19
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
21
+ if (timeoutRef.current) {
22
+ clearTimeout(timeoutRef.current);
23
+ }
20
24
  timeoutRef.current = setTimeout(() => setIsCopied(false), resetDelay);
21
25
  });
22
26
  },
@@ -1,4 +1,4 @@
1
- import { Plus } from "lucide-react";
1
+ import { ArrowRight, Plus, Sparkles } from "lucide-react";
2
2
 
3
3
  import { Button } from "../components/button";
4
4
 
@@ -323,6 +323,28 @@ export const AllVariants = () => {
323
323
  </Button>
324
324
  </div>
325
325
 
326
+ {/* ── CTA (animated gradient ring) ────────────────────────────────── */}
327
+ <span className={SECTION_HEADER}>CTA — animated</span>
328
+ <p className="type-text-xs text-muted-foreground -mt-2 max-w-md">
329
+ Hover to rotate the conic gradient around the border and ignite the soft halo.
330
+ </p>
331
+
332
+ <div className="flex items-center gap-6">
333
+ <Button variant="cta" iconTrailing={<ArrowRight />}>
334
+ Get started
335
+ </Button>
336
+ <Button variant="cta" icon={<Sparkles />} iconTrailing={<ArrowRight />}>
337
+ Launch server
338
+ </Button>
339
+ <Button variant="cta">Deploy now</Button>
340
+ <Button variant="cta" iconTrailing={<ArrowRight />} disabled>
341
+ Disabled
342
+ </Button>
343
+ <Button variant="cta" iconTrailing={<ArrowRight />} loading>
344
+ Deploying
345
+ </Button>
346
+ </div>
347
+
326
348
  {/* ── asChild ─────────────────────────────────────────────────────── */}
327
349
  <span className={SECTION_HEADER}>asChild</span>
328
350
 
@@ -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>