@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.
- package/dist/components/accordion-card.d.mts +1 -1
- package/dist/components/accordion.d.mts +1 -1
- package/dist/components/alert.d.mts +2 -2
- package/dist/components/attachment-tile.mjs +1 -1
- package/dist/components/avatar.d.mts +2 -2
- package/dist/components/badge.d.mts +1 -1
- package/dist/components/breadcrumb.d.mts +1 -1
- package/dist/components/button.d.mts +5 -3
- package/dist/components/button.mjs +20 -6
- package/dist/components/card.d.mts +1 -1
- package/dist/components/checkbox.d.mts +1 -1
- package/dist/components/collapsible.d.mts +1 -1
- package/dist/components/combobox.d.mts +1 -1
- package/dist/components/combobox.mjs +1 -1
- package/dist/components/command.d.mts +1 -1
- package/dist/components/copyable.d.mts +1 -1
- package/dist/components/copyable.mjs +1 -1
- package/dist/components/description-list.d.mts +1 -1
- package/dist/components/dialog.d.mts +1 -1
- package/dist/components/dropdown-menu.d.mts +2 -2
- package/dist/components/form.d.mts +1 -1
- package/dist/components/form.mjs +1 -1
- package/dist/components/github-button.d.mts +13 -0
- package/dist/components/github-button.mjs +24 -0
- package/dist/components/input-group.d.mts +1 -1
- package/dist/components/input.d.mts +1 -1
- package/dist/components/input.mjs +1 -1
- package/dist/components/label.d.mts +1 -1
- package/dist/components/pagination.d.mts +1 -1
- package/dist/components/popover.d.mts +1 -1
- package/dist/components/radio-group.d.mts +1 -1
- package/dist/components/scroll-area.d.mts +1 -1
- package/dist/components/select.d.mts +1 -1
- package/dist/components/separator.d.mts +1 -1
- package/dist/components/sheet.d.mts +1 -1
- package/dist/components/sidebar.d.mts +1 -1
- package/dist/components/sidebar.mjs +41 -12
- package/dist/components/skeleton.d.mts +1 -1
- package/dist/components/sonner.d.mts +1 -1
- package/dist/components/spinner.d.mts +1 -1
- package/dist/components/status-dot.d.mts +1 -1
- package/dist/components/switch.d.mts +1 -1
- package/dist/components/table.d.mts +1 -1
- package/dist/components/tabs.d.mts +2 -2
- package/dist/components/tabs.mjs +1 -1
- package/dist/components/textarea.d.mts +1 -1
- package/dist/components/textarea.mjs +1 -1
- package/dist/components/toggle-group.d.mts +1 -1
- package/dist/components/toggle-group.mjs +1 -1
- package/dist/components/tooltip-icon-button.mjs +1 -1
- package/dist/components/tooltip.d.mts +1 -1
- package/dist/components/typography.d.mts +1 -1
- package/package.json +6 -6
- package/src/components/button.tsx +13 -9
- package/src/components/combobox.tsx +18 -6
- package/src/components/github-button.tsx +34 -0
- package/src/components/sidebar.tsx +48 -10
- package/src/hooks/use-copy-to-clipboard.ts +6 -2
- package/src/stories/button.stories.tsx +23 -1
- package/src/stories/sidebar.stories.tsx +6 -3
- 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" | "
|
|
9
|
+
variant?: "default" | "pill" | "line" | null | undefined;
|
|
10
10
|
} & _$class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
11
11
|
declare function Tabs({
|
|
12
12
|
className,
|
package/dist/components/tabs.mjs
CHANGED
|
@@ -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
|
|
@@ -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) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alpic-ai/ui",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
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.
|
|
29
|
+
"react-hook-form": "^7.73.1",
|
|
30
30
|
"sonner": "^2.0.7",
|
|
31
|
-
"tailwindcss": "^4.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.
|
|
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.
|
|
63
|
+
"react-hook-form": "^7.73.1",
|
|
64
64
|
"shx": "^0.4.0",
|
|
65
65
|
"sonner": "^2.0.7",
|
|
66
|
-
"tailwindcss": "^4.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
|
-
{
|
|
94
|
-
|
|
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)
|
|
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)
|
|
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)
|
|
130
|
+
if (!isControlledMulti) {
|
|
131
|
+
setUncontrolledMultiValue(next);
|
|
132
|
+
}
|
|
127
133
|
onValueChangeMulti?.(next);
|
|
128
134
|
// Stay open in multi mode
|
|
129
135
|
} else {
|
|
130
|
-
if (!isControlledSingle)
|
|
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)
|
|
156
|
+
if (!multiple) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
149
159
|
const next = multiValues.filter((val) => val !== itemValue);
|
|
150
|
-
if (!isControlledMulti)
|
|
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
|
-
"
|
|
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
|
|
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
|
-
<
|
|
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)
|
|
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)
|
|
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>
|