@bearmenu/ui 0.1.0
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/chunk-2CUFS5LF.js +80 -0
- package/dist/chunk-3GWWZKX7.js +33 -0
- package/dist/chunk-3VMDCCCX.js +10 -0
- package/dist/chunk-4AVS6CV4.js +89 -0
- package/dist/chunk-4JOV7FXW.js +17 -0
- package/dist/chunk-4KOMHDZD.js +89 -0
- package/dist/chunk-4UO73SKC.js +26 -0
- package/dist/chunk-7H54PTVH.js +116 -0
- package/dist/chunk-CW24PLDW.js +24 -0
- package/dist/chunk-EBAMCZDW.js +112 -0
- package/dist/chunk-ERMIA7NP.js +106 -0
- package/dist/chunk-ESO2EM3L.js +46 -0
- package/dist/chunk-EUHEIWHZ.js +32 -0
- package/dist/chunk-FEK5XGZW.js +8 -0
- package/dist/chunk-NKHH23YK.js +31 -0
- package/dist/chunk-R47NEOSI.js +78 -0
- package/dist/chunk-UXAYXRFN.js +69 -0
- package/dist/chunk-X6GATUI2.js +19 -0
- package/dist/components/accordion.d.ts +9 -0
- package/dist/components/accordion.js +53 -0
- package/dist/components/alert-dialog.d.ts +23 -0
- package/dist/components/alert-dialog.js +98 -0
- package/dist/components/alert.d.ts +11 -0
- package/dist/components/alert.js +52 -0
- package/dist/components/aspect-ratio.d.ts +6 -0
- package/dist/components/aspect-ratio.js +2 -0
- package/dist/components/avatar.d.ts +8 -0
- package/dist/components/avatar.js +47 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.js +3 -0
- package/dist/components/breadcrumb.d.ts +14 -0
- package/dist/components/breadcrumb.js +96 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.js +4 -0
- package/dist/components/calendar.d.ts +11 -0
- package/dist/components/calendar.js +56 -0
- package/dist/components/card.d.ts +13 -0
- package/dist/components/card.js +4 -0
- package/dist/components/carousel.d.ts +24 -0
- package/dist/components/carousel.js +198 -0
- package/dist/components/checkbox.d.ts +6 -0
- package/dist/components/checkbox.js +25 -0
- package/dist/components/collapsible.d.ts +8 -0
- package/dist/components/collapsible.js +26 -0
- package/dist/components/command.d.ts +84 -0
- package/dist/components/command.js +4 -0
- package/dist/components/currency-input.d.ts +17 -0
- package/dist/components/currency-input.js +121 -0
- package/dist/components/dialog.d.ts +22 -0
- package/dist/components/dialog.js +3 -0
- package/dist/components/drawer.d.ts +27 -0
- package/dist/components/drawer.js +85 -0
- package/dist/components/dropdown-menu.d.ts +28 -0
- package/dist/components/dropdown-menu.js +211 -0
- package/dist/components/empty-state.d.ts +22 -0
- package/dist/components/empty-state.js +81 -0
- package/dist/components/form.d.ts +28 -0
- package/dist/components/form.js +97 -0
- package/dist/components/haptic-button.d.ts +12 -0
- package/dist/components/haptic-button.js +17 -0
- package/dist/components/input-otp.d.ts +14 -0
- package/dist/components/input-otp.js +62 -0
- package/dist/components/input.d.ts +6 -0
- package/dist/components/input.js +3 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.js +3 -0
- package/dist/components/lazy-markdown.d.ts +11 -0
- package/dist/components/lazy-markdown.js +13 -0
- package/dist/components/link-button.d.ts +30 -0
- package/dist/components/link-button.js +17 -0
- package/dist/components/markdown-renderer.d.ts +11 -0
- package/dist/components/markdown-renderer.js +10 -0
- package/dist/components/multi-select-combobox.d.ts +23 -0
- package/dist/components/multi-select-combobox.js +114 -0
- package/dist/components/pagination.d.ts +18 -0
- package/dist/components/pagination.js +101 -0
- package/dist/components/popover.d.ts +8 -0
- package/dist/components/popover.js +3 -0
- package/dist/components/progress.d.ts +6 -0
- package/dist/components/progress.js +30 -0
- package/dist/components/radio-group.d.ts +7 -0
- package/dist/components/radio-group.js +30 -0
- package/dist/components/rating.d.ts +15 -0
- package/dist/components/rating.js +120 -0
- package/dist/components/scroll-area.d.ts +7 -0
- package/dist/components/scroll-area.js +44 -0
- package/dist/components/search-bar.d.ts +17 -0
- package/dist/components/search-bar.js +92 -0
- package/dist/components/searchable-select.d.ts +22 -0
- package/dist/components/searchable-select.js +104 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.js +129 -0
- package/dist/components/separator.d.ts +6 -0
- package/dist/components/separator.js +25 -0
- package/dist/components/sheet.d.ts +29 -0
- package/dist/components/sheet.js +96 -0
- package/dist/components/skeleton-card.d.ts +13 -0
- package/dist/components/skeleton-card.js +154 -0
- package/dist/components/skeleton.d.ts +6 -0
- package/dist/components/skeleton.js +3 -0
- package/dist/components/slider.d.ts +6 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/sliding-panels.d.ts +19 -0
- package/dist/components/sliding-panels.js +75 -0
- package/dist/components/sonner.d.ts +6 -0
- package/dist/components/sonner.js +23 -0
- package/dist/components/sticky-container.d.ts +44 -0
- package/dist/components/sticky-container.js +39 -0
- package/dist/components/switch.d.ts +6 -0
- package/dist/components/switch.js +31 -0
- package/dist/components/table.d.ts +12 -0
- package/dist/components/table.js +81 -0
- package/dist/components/tabs.d.ts +12 -0
- package/dist/components/tabs.js +55 -0
- package/dist/components/text.d.ts +31 -0
- package/dist/components/text.js +3 -0
- package/dist/components/textarea.d.ts +6 -0
- package/dist/components/textarea.js +23 -0
- package/dist/components/toast.d.ts +18 -0
- package/dist/components/toast.js +3 -0
- package/dist/components/toaster.d.ts +5 -0
- package/dist/components/toaster.js +25 -0
- package/dist/components/toggle-group.d.ts +12 -0
- package/dist/components/toggle-group.js +72 -0
- package/dist/components/toggle.d.ts +13 -0
- package/dist/components/toggle.js +3 -0
- package/dist/components/tooltip.d.ts +9 -0
- package/dist/components/tooltip.js +26 -0
- package/dist/components/use-mobile.d.ts +3 -0
- package/dist/components/use-mobile.js +19 -0
- package/dist/components/use-toast.d.ts +42 -0
- package/dist/components/use-toast.js +2 -0
- package/dist/hooks/use-haptic.d.ts +22 -0
- package/dist/hooks/use-haptic.js +2 -0
- package/dist/hooks/use-mobile.d.ts +3 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-mounted-theme.d.ts +6 -0
- package/dist/hooks/use-mounted-theme.js +18 -0
- package/dist/hooks/use-sticky.d.ts +18 -0
- package/dist/hooks/use-sticky.js +2 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +2 -0
- package/package.json +203 -0
- package/src/components/accordion.tsx +57 -0
- package/src/components/alert-dialog.tsx +116 -0
- package/src/components/alert.tsx +57 -0
- package/src/components/aspect-ratio.tsx +9 -0
- package/src/components/avatar.tsx +49 -0
- package/src/components/badge.tsx +38 -0
- package/src/components/breadcrumb.tsx +102 -0
- package/src/components/button.tsx +94 -0
- package/src/components/calendar.tsx +60 -0
- package/src/components/card.tsx +67 -0
- package/src/components/carousel.tsx +230 -0
- package/src/components/checkbox.tsx +27 -0
- package/src/components/collapsible.tsx +28 -0
- package/src/components/command.tsx +148 -0
- package/src/components/currency-input.tsx +158 -0
- package/src/components/dialog.tsx +103 -0
- package/src/components/drawer.tsx +99 -0
- package/src/components/dropdown-menu.tsx +228 -0
- package/src/components/empty-state.tsx +118 -0
- package/src/components/form.tsx +152 -0
- package/src/components/haptic-button.tsx +19 -0
- package/src/components/input-otp.tsx +70 -0
- package/src/components/input.tsx +23 -0
- package/src/components/label.tsx +20 -0
- package/src/components/lazy-markdown.tsx +20 -0
- package/src/components/link-button.tsx +40 -0
- package/src/components/markdown-renderer.tsx +20 -0
- package/src/components/multi-select-combobox.tsx +148 -0
- package/src/components/pagination.tsx +106 -0
- package/src/components/popover.tsx +30 -0
- package/src/components/progress.tsx +27 -0
- package/src/components/radio-group.tsx +37 -0
- package/src/components/rating.tsx +136 -0
- package/src/components/scroll-area.tsx +45 -0
- package/src/components/search-bar.tsx +113 -0
- package/src/components/searchable-select.tsx +134 -0
- package/src/components/select.tsx +152 -0
- package/src/components/separator.tsx +25 -0
- package/src/components/sheet.tsx +121 -0
- package/src/components/skeleton-card.tsx +282 -0
- package/src/components/skeleton.tsx +17 -0
- package/src/components/slider.tsx +24 -0
- package/src/components/sliding-panels.tsx +99 -0
- package/src/components/sonner.tsx +25 -0
- package/src/components/sticky-container.tsx +88 -0
- package/src/components/switch.tsx +28 -0
- package/src/components/table.tsx +90 -0
- package/src/components/tabs.tsx +72 -0
- package/src/components/text.test.tsx +192 -0
- package/src/components/text.tsx +114 -0
- package/src/components/textarea.tsx +22 -0
- package/src/components/toast.tsx +129 -0
- package/src/components/toaster.tsx +31 -0
- package/src/components/toggle-group.tsx +69 -0
- package/src/components/toggle.tsx +46 -0
- package/src/components/tooltip.tsx +29 -0
- package/src/components/use-mobile.tsx +19 -0
- package/src/components/use-toast.ts +180 -0
- package/src/globals.css +409 -0
- package/src/hooks/use-haptic.ts +118 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-mounted-theme.ts +20 -0
- package/src/hooks/use-sticky.ts +47 -0
- package/src/lib/utils.ts +6 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
|
|
7
|
+
type TabsVariant = "pill" | "underline";
|
|
8
|
+
|
|
9
|
+
const TabsVariantContext = React.createContext<TabsVariant>("pill");
|
|
10
|
+
|
|
11
|
+
const Tabs = TabsPrimitive.Root;
|
|
12
|
+
|
|
13
|
+
const TabsList = React.forwardRef<
|
|
14
|
+
React.ElementRef<typeof TabsPrimitive.List>,
|
|
15
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {
|
|
16
|
+
variant?: TabsVariant;
|
|
17
|
+
}
|
|
18
|
+
>(({ className, variant = "pill", children, ...props }, ref) => (
|
|
19
|
+
<TabsVariantContext.Provider value={variant}>
|
|
20
|
+
<TabsPrimitive.List
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={cn(
|
|
23
|
+
variant === "pill"
|
|
24
|
+
? "inline-flex h-12 items-center justify-center gap-2 rounded-3xl glass p-1 text-muted-foreground border border-border/50 shadow-lg"
|
|
25
|
+
: "inline-flex h-auto items-center gap-0 rounded-none bg-transparent border-b border-border p-0 shadow-none text-muted-foreground",
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</TabsPrimitive.List>
|
|
32
|
+
</TabsVariantContext.Provider>
|
|
33
|
+
));
|
|
34
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
35
|
+
|
|
36
|
+
const TabsTrigger = React.forwardRef<
|
|
37
|
+
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
|
38
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
39
|
+
>(({ className, ...props }, ref) => {
|
|
40
|
+
const variant = React.useContext(TabsVariantContext);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<TabsPrimitive.Trigger
|
|
44
|
+
ref={ref}
|
|
45
|
+
className={cn(
|
|
46
|
+
variant === "pill"
|
|
47
|
+
? "inline-flex items-center justify-center whitespace-nowrap rounded-2xl px-4 py-2 text-sm font-medium ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-primary/90 data-[state=active]:text-primary-foreground data-[state=active]:shadow-lg data-[state=active]:backdrop-blur-md data-[state=active]:border data-[state=active]:border-border/50 hover:bg-accent/50 hover:text-accent-foreground [@media(pointer:coarse)]:active:scale-95"
|
|
48
|
+
: "relative inline-flex items-center justify-center whitespace-nowrap rounded-none px-4 h-12 text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:text-foreground data-[state=active]:bg-transparent data-[state=active]:shadow-none text-muted-foreground hover:text-foreground/80 cursor-pointer",
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
56
|
+
|
|
57
|
+
const TabsContent = React.forwardRef<
|
|
58
|
+
React.ElementRef<typeof TabsPrimitive.Content>,
|
|
59
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
60
|
+
>(({ className, ...props }, ref) => (
|
|
61
|
+
<TabsPrimitive.Content
|
|
62
|
+
ref={ref}
|
|
63
|
+
className={cn(
|
|
64
|
+
"mt-4 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
65
|
+
className
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
));
|
|
70
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
71
|
+
|
|
72
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { Text, textVariants } from "./text";
|
|
4
|
+
|
|
5
|
+
// ─── textVariants utility ────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
describe("textVariants", () => {
|
|
8
|
+
it("returns empty string with no arguments (color:inherit default)", () => {
|
|
9
|
+
const result = textVariants({});
|
|
10
|
+
// color:inherit maps to "" so the full output should be empty/whitespace
|
|
11
|
+
expect(result.trim()).toBe("");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("maps color tokens to correct classes", () => {
|
|
15
|
+
expect(textVariants({ color: "default" })).toContain("text-foreground");
|
|
16
|
+
expect(textVariants({ color: "muted" })).toContain("text-muted-foreground");
|
|
17
|
+
expect(textVariants({ color: "primary" })).toContain("text-primary");
|
|
18
|
+
expect(textVariants({ color: "destructive" })).toContain("text-destructive");
|
|
19
|
+
expect(textVariants({ color: "inherit" }).trim()).toBe("");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("maps variant to correct class bundles", () => {
|
|
23
|
+
expect(textVariants({ variant: "display" })).toContain("text-5xl");
|
|
24
|
+
expect(textVariants({ variant: "h1" })).toContain("text-3xl");
|
|
25
|
+
expect(textVariants({ variant: "h2" })).toContain("text-2xl");
|
|
26
|
+
expect(textVariants({ variant: "h3" })).toContain("text-xl");
|
|
27
|
+
expect(textVariants({ variant: "h4" })).toContain("text-lg");
|
|
28
|
+
expect(textVariants({ variant: "body-lg" })).toContain("text-base");
|
|
29
|
+
expect(textVariants({ variant: "body" })).toContain("text-sm");
|
|
30
|
+
expect(textVariants({ variant: "body-sm" })).toContain("text-sm");
|
|
31
|
+
expect(textVariants({ variant: "caption" })).toContain("text-xs");
|
|
32
|
+
expect(textVariants({ variant: "label" })).toContain("font-medium");
|
|
33
|
+
expect(textVariants({ variant: "overline" })).toContain("uppercase");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("maps weight props", () => {
|
|
37
|
+
expect(textVariants({ weight: "normal" })).toContain("font-normal");
|
|
38
|
+
expect(textVariants({ weight: "medium" })).toContain("font-medium");
|
|
39
|
+
expect(textVariants({ weight: "semibold" })).toContain("font-semibold");
|
|
40
|
+
expect(textVariants({ weight: "bold" })).toContain("font-bold");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("maps leading props", () => {
|
|
44
|
+
expect(textVariants({ leading: "none" })).toContain("leading-none");
|
|
45
|
+
expect(textVariants({ leading: "tight" })).toContain("leading-tight");
|
|
46
|
+
expect(textVariants({ leading: "snug" })).toContain("leading-snug");
|
|
47
|
+
expect(textVariants({ leading: "normal" })).toContain("leading-normal");
|
|
48
|
+
expect(textVariants({ leading: "relaxed" })).toContain("leading-relaxed");
|
|
49
|
+
expect(textVariants({ leading: "loose" })).toContain("leading-loose");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("maps tracking props", () => {
|
|
53
|
+
expect(textVariants({ tracking: "tight" })).toContain("tracking-tight");
|
|
54
|
+
expect(textVariants({ tracking: "normal" })).toContain("tracking-normal");
|
|
55
|
+
expect(textVariants({ tracking: "wide" })).toContain("tracking-wide");
|
|
56
|
+
expect(textVariants({ tracking: "wider" })).toContain("tracking-wider");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("maps wrap props", () => {
|
|
60
|
+
expect(textVariants({ wrap: "balance" })).toContain("text-balance");
|
|
61
|
+
expect(textVariants({ wrap: "pretty" })).toContain("text-pretty");
|
|
62
|
+
expect(textVariants({ wrap: "nowrap" })).toContain("whitespace-nowrap");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("combines multiple props without conflict", () => {
|
|
66
|
+
const result = textVariants({
|
|
67
|
+
weight: "semibold",
|
|
68
|
+
leading: "none",
|
|
69
|
+
tracking: "tight",
|
|
70
|
+
wrap: "balance",
|
|
71
|
+
});
|
|
72
|
+
expect(result).toContain("font-semibold");
|
|
73
|
+
expect(result).toContain("leading-none");
|
|
74
|
+
expect(result).toContain("tracking-tight");
|
|
75
|
+
expect(result).toContain("text-balance");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ─── <Text> component ─────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
describe("Text component", () => {
|
|
82
|
+
// Happy path — renders with correct element and content
|
|
83
|
+
|
|
84
|
+
it("renders as <p> by default", () => {
|
|
85
|
+
render(<Text>hello</Text>);
|
|
86
|
+
const el = screen.getByText("hello");
|
|
87
|
+
expect(el.tagName).toBe("P");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("renders the correct tag when as= is specified", () => {
|
|
91
|
+
render(<Text as="h1">Heading</Text>);
|
|
92
|
+
expect(screen.getByText("Heading").tagName).toBe("H1");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("renders as span", () => {
|
|
96
|
+
render(<Text as="span">inline</Text>);
|
|
97
|
+
expect(screen.getByText("inline").tagName).toBe("SPAN");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("renders as label with htmlFor", () => {
|
|
101
|
+
render(
|
|
102
|
+
<Text as="label" htmlFor="my-input">
|
|
103
|
+
Label
|
|
104
|
+
</Text>
|
|
105
|
+
);
|
|
106
|
+
const el = screen.getByText("Label");
|
|
107
|
+
expect(el.tagName).toBe("LABEL");
|
|
108
|
+
expect(el.getAttribute("for")).toBe("my-input");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("renders children correctly", () => {
|
|
112
|
+
render(<Text>test content</Text>);
|
|
113
|
+
expect(screen.getByText("test content")).toBeDefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Class output
|
|
117
|
+
|
|
118
|
+
it("applies color class from color prop", () => {
|
|
119
|
+
render(<Text color="muted">muted text</Text>);
|
|
120
|
+
expect(screen.getByText("muted text").className).toContain("text-muted-foreground");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("applies weight class from weight prop", () => {
|
|
124
|
+
render(<Text weight="bold">bold text</Text>);
|
|
125
|
+
expect(screen.getByText("bold text").className).toContain("font-bold");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("applies leading class from leading prop", () => {
|
|
129
|
+
render(<Text leading="relaxed">relaxed</Text>);
|
|
130
|
+
expect(screen.getByText("relaxed").className).toContain("leading-relaxed");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("applies wrap class from wrap prop", () => {
|
|
134
|
+
render(<Text wrap="balance">balanced</Text>);
|
|
135
|
+
expect(screen.getByText("balanced").className).toContain("text-balance");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("applies variant class bundle", () => {
|
|
139
|
+
render(<Text variant="h4">heading</Text>);
|
|
140
|
+
const el = screen.getByText("heading");
|
|
141
|
+
expect(el.className).toContain("text-lg");
|
|
142
|
+
expect(el.className).toContain("font-semibold");
|
|
143
|
+
expect(el.className).toContain("leading-none");
|
|
144
|
+
expect(el.className).toContain("tracking-tight");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("passes through className and merges via twMerge", () => {
|
|
148
|
+
render(
|
|
149
|
+
<Text color="muted" className="mb-4 text-red-500">
|
|
150
|
+
override
|
|
151
|
+
</Text>
|
|
152
|
+
);
|
|
153
|
+
const el = screen.getByText("override");
|
|
154
|
+
// twMerge: text-red-500 overrides text-muted-foreground
|
|
155
|
+
expect(el.className).toContain("text-red-500");
|
|
156
|
+
expect(el.className).not.toContain("text-muted-foreground");
|
|
157
|
+
expect(el.className).toContain("mb-4");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("passes through arbitrary HTML attributes", () => {
|
|
161
|
+
render(
|
|
162
|
+
<Text id="my-id" data-testid="text-el">
|
|
163
|
+
content
|
|
164
|
+
</Text>
|
|
165
|
+
);
|
|
166
|
+
const el = screen.getByTestId("text-el");
|
|
167
|
+
expect(el.id).toBe("my-id");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Edge cases
|
|
171
|
+
|
|
172
|
+
it("renders with no props (no classes, pure element)", () => {
|
|
173
|
+
render(<Text>bare</Text>);
|
|
174
|
+
const el = screen.getByText("bare");
|
|
175
|
+
// color:inherit emits empty string, no variant = no variant classes
|
|
176
|
+
expect(el.className.trim()).toBe("");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("renders children including nested elements", () => {
|
|
180
|
+
render(
|
|
181
|
+
<Text as="p">
|
|
182
|
+
Text with <strong>bold</strong> inside
|
|
183
|
+
</Text>
|
|
184
|
+
);
|
|
185
|
+
expect(screen.getByText("bold").tagName).toBe("STRONG");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("renders div correctly", () => {
|
|
189
|
+
render(<Text as="div">block</Text>);
|
|
190
|
+
expect(screen.getByText("block").tagName).toBe("DIV");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
const textVariants = cva("", {
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
display: "text-5xl font-bold tracking-tight",
|
|
9
|
+
h1: "text-3xl font-bold tracking-tight",
|
|
10
|
+
h2: "text-2xl font-semibold tracking-tight",
|
|
11
|
+
h3: "text-xl font-semibold",
|
|
12
|
+
h4: "text-lg font-semibold leading-none tracking-tight",
|
|
13
|
+
"body-lg": "text-base leading-relaxed",
|
|
14
|
+
body: "text-sm leading-normal",
|
|
15
|
+
"body-sm": "text-sm leading-relaxed",
|
|
16
|
+
caption: "text-xs leading-normal",
|
|
17
|
+
label: "text-sm font-medium",
|
|
18
|
+
overline: "text-xs font-semibold uppercase tracking-wider",
|
|
19
|
+
},
|
|
20
|
+
color: {
|
|
21
|
+
default: "text-foreground",
|
|
22
|
+
muted: "text-muted-foreground",
|
|
23
|
+
primary: "text-primary",
|
|
24
|
+
destructive: "text-destructive",
|
|
25
|
+
"primary-foreground": "text-primary-foreground",
|
|
26
|
+
inherit: "",
|
|
27
|
+
},
|
|
28
|
+
weight: {
|
|
29
|
+
normal: "font-normal",
|
|
30
|
+
medium: "font-medium",
|
|
31
|
+
semibold: "font-semibold",
|
|
32
|
+
bold: "font-bold",
|
|
33
|
+
},
|
|
34
|
+
leading: {
|
|
35
|
+
none: "leading-none",
|
|
36
|
+
tight: "leading-tight",
|
|
37
|
+
snug: "leading-snug",
|
|
38
|
+
normal: "leading-normal",
|
|
39
|
+
relaxed: "leading-relaxed",
|
|
40
|
+
loose: "leading-loose",
|
|
41
|
+
},
|
|
42
|
+
tracking: {
|
|
43
|
+
tight: "tracking-tight",
|
|
44
|
+
normal: "tracking-normal",
|
|
45
|
+
wide: "tracking-wide",
|
|
46
|
+
wider: "tracking-wider",
|
|
47
|
+
},
|
|
48
|
+
wrap: {
|
|
49
|
+
balance: "text-balance",
|
|
50
|
+
pretty: "text-pretty",
|
|
51
|
+
nowrap: "whitespace-nowrap",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
defaultVariants: {
|
|
55
|
+
color: "inherit",
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export type TextTag =
|
|
60
|
+
| "h1"
|
|
61
|
+
| "h2"
|
|
62
|
+
| "h3"
|
|
63
|
+
| "h4"
|
|
64
|
+
| "h5"
|
|
65
|
+
| "h6"
|
|
66
|
+
| "p"
|
|
67
|
+
| "span"
|
|
68
|
+
| "div"
|
|
69
|
+
| "label"
|
|
70
|
+
| "strong"
|
|
71
|
+
| "em"
|
|
72
|
+
| "small"
|
|
73
|
+
| "li"
|
|
74
|
+
| "dt"
|
|
75
|
+
| "dd";
|
|
76
|
+
|
|
77
|
+
type TextOwnProps<T extends TextTag = "p"> = {
|
|
78
|
+
as?: T;
|
|
79
|
+
variant?: VariantProps<typeof textVariants>["variant"];
|
|
80
|
+
color?: VariantProps<typeof textVariants>["color"];
|
|
81
|
+
weight?: VariantProps<typeof textVariants>["weight"];
|
|
82
|
+
leading?: VariantProps<typeof textVariants>["leading"];
|
|
83
|
+
tracking?: VariantProps<typeof textVariants>["tracking"];
|
|
84
|
+
wrap?: VariantProps<typeof textVariants>["wrap"];
|
|
85
|
+
className?: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Omit HTML's deprecated `color` attribute so it doesn't conflict with our color prop
|
|
89
|
+
type TextProps<T extends TextTag = "p"> = TextOwnProps<T> &
|
|
90
|
+
Omit<React.ComponentPropsWithoutRef<T>, keyof TextOwnProps<T> | "color">;
|
|
91
|
+
|
|
92
|
+
function Text<T extends TextTag = "p">({
|
|
93
|
+
as,
|
|
94
|
+
variant,
|
|
95
|
+
color,
|
|
96
|
+
weight,
|
|
97
|
+
leading,
|
|
98
|
+
tracking,
|
|
99
|
+
wrap,
|
|
100
|
+
className,
|
|
101
|
+
...props
|
|
102
|
+
}: TextProps<T>) {
|
|
103
|
+
const Comp = (as ?? "p") as React.ElementType;
|
|
104
|
+
return (
|
|
105
|
+
<Comp
|
|
106
|
+
className={cn(textVariants({ variant, color, weight, leading, tracking, wrap }), className)}
|
|
107
|
+
{...(props as React.HTMLAttributes<HTMLElement>)}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
Text.displayName = "Text";
|
|
113
|
+
|
|
114
|
+
export { Text, textVariants };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../lib/utils";
|
|
3
|
+
|
|
4
|
+
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
|
5
|
+
|
|
6
|
+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
7
|
+
({ className, ...props }, ref) => {
|
|
8
|
+
return (
|
|
9
|
+
<textarea
|
|
10
|
+
className={cn(
|
|
11
|
+
"flex min-h-[80px] w-full rounded-xl border border-border bg-input/50 backdrop-blur-md px-4 py-3 text-base transition-all duration-300 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:bg-input focus-visible:border-accent-foreground/30 focus-visible:shadow-lg focus-visible:shadow-accent/10 disabled:cursor-not-allowed disabled:opacity-50 resize-none",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
ref={ref}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
Textarea.displayName = "Textarea";
|
|
21
|
+
|
|
22
|
+
export { Textarea };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as ToastPrimitives from "@radix-ui/react-toast";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
import { X } from "lucide-react";
|
|
7
|
+
import { cn } from "../lib/utils";
|
|
8
|
+
|
|
9
|
+
const ToastProvider = ToastPrimitives.Provider;
|
|
10
|
+
|
|
11
|
+
const ToastViewport = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<ToastPrimitives.Viewport
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn(
|
|
18
|
+
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
));
|
|
24
|
+
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
|
|
25
|
+
|
|
26
|
+
const toastVariants = cva(
|
|
27
|
+
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-xl glass p-6 pr-8 shadow-2xl transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full border border-border/50",
|
|
28
|
+
{
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
default: "border bg-background text-foreground",
|
|
32
|
+
destructive: "destructive border-destructive/50 bg-destructive text-destructive-foreground",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
variant: "default",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const Toast = React.forwardRef<
|
|
42
|
+
React.ElementRef<typeof ToastPrimitives.Root>,
|
|
43
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
|
|
44
|
+
>(({ className, variant, ...props }, ref) => {
|
|
45
|
+
return (
|
|
46
|
+
<ToastPrimitives.Root
|
|
47
|
+
ref={ref}
|
|
48
|
+
className={cn(toastVariants({ variant }), className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
Toast.displayName = ToastPrimitives.Root.displayName;
|
|
54
|
+
|
|
55
|
+
const ToastAction = React.forwardRef<
|
|
56
|
+
React.ElementRef<typeof ToastPrimitives.Action>,
|
|
57
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
|
|
58
|
+
>(({ className, ...props }, ref) => (
|
|
59
|
+
<ToastPrimitives.Action
|
|
60
|
+
ref={ref}
|
|
61
|
+
className={cn(
|
|
62
|
+
"inline-flex h-8 shrink-0 items-center justify-center rounded-lg border border-muted bg-transparent px-3 text-xs font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
|
63
|
+
className
|
|
64
|
+
)}
|
|
65
|
+
{...props}
|
|
66
|
+
/>
|
|
67
|
+
));
|
|
68
|
+
ToastAction.displayName = ToastPrimitives.Action.displayName;
|
|
69
|
+
|
|
70
|
+
const ToastClose = React.forwardRef<
|
|
71
|
+
React.ElementRef<typeof ToastPrimitives.Close>,
|
|
72
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
|
|
73
|
+
>(({ className, ...props }, ref) => (
|
|
74
|
+
<ToastPrimitives.Close
|
|
75
|
+
ref={ref}
|
|
76
|
+
className={cn(
|
|
77
|
+
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-white group-[.destructive]:opacity-100 group-[.destructive]:hover:text-white group-[.destructive]:focus:ring-white/50 group-[.destructive]:focus:ring-offset-destructive",
|
|
78
|
+
className
|
|
79
|
+
)}
|
|
80
|
+
toast-close=""
|
|
81
|
+
{...props}
|
|
82
|
+
>
|
|
83
|
+
<X className="h-4 w-4" />
|
|
84
|
+
</ToastPrimitives.Close>
|
|
85
|
+
));
|
|
86
|
+
ToastClose.displayName = ToastPrimitives.Close.displayName;
|
|
87
|
+
|
|
88
|
+
const ToastTitle = React.forwardRef<
|
|
89
|
+
React.ElementRef<typeof ToastPrimitives.Title>,
|
|
90
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<ToastPrimitives.Title
|
|
93
|
+
ref={ref}
|
|
94
|
+
className={cn(
|
|
95
|
+
"text-sm font-semibold group-[.destructive]:text-destructive-foreground",
|
|
96
|
+
className
|
|
97
|
+
)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
));
|
|
101
|
+
ToastTitle.displayName = ToastPrimitives.Title.displayName;
|
|
102
|
+
|
|
103
|
+
const ToastDescription = React.forwardRef<
|
|
104
|
+
React.ElementRef<typeof ToastPrimitives.Description>,
|
|
105
|
+
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
|
|
106
|
+
>(({ className, ...props }, ref) => (
|
|
107
|
+
<ToastPrimitives.Description
|
|
108
|
+
ref={ref}
|
|
109
|
+
className={cn("text-sm opacity-90 group-[.destructive]:text-white", className)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
));
|
|
113
|
+
ToastDescription.displayName = ToastPrimitives.Description.displayName;
|
|
114
|
+
|
|
115
|
+
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
|
|
116
|
+
|
|
117
|
+
type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
type ToastProps,
|
|
121
|
+
type ToastActionElement,
|
|
122
|
+
ToastProvider,
|
|
123
|
+
ToastViewport,
|
|
124
|
+
Toast,
|
|
125
|
+
ToastTitle,
|
|
126
|
+
ToastDescription,
|
|
127
|
+
ToastClose,
|
|
128
|
+
ToastAction,
|
|
129
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Toast,
|
|
5
|
+
ToastClose,
|
|
6
|
+
ToastDescription,
|
|
7
|
+
ToastProvider,
|
|
8
|
+
ToastTitle,
|
|
9
|
+
ToastViewport,
|
|
10
|
+
} from "./toast";
|
|
11
|
+
import { useToast } from "./use-toast";
|
|
12
|
+
|
|
13
|
+
export function Toaster() {
|
|
14
|
+
const { toasts } = useToast();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<ToastProvider>
|
|
18
|
+
{toasts.map(({ id, title, description, action, ...props }) => (
|
|
19
|
+
<Toast key={id} {...props}>
|
|
20
|
+
<div className="grid gap-1">
|
|
21
|
+
{title && <ToastTitle>{title}</ToastTitle>}
|
|
22
|
+
{description && <ToastDescription>{description}</ToastDescription>}
|
|
23
|
+
</div>
|
|
24
|
+
{action}
|
|
25
|
+
<ToastClose />
|
|
26
|
+
</Toast>
|
|
27
|
+
))}
|
|
28
|
+
<ToastViewport />
|
|
29
|
+
</ToastProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
|
5
|
+
import { type VariantProps } from "class-variance-authority";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../lib/utils";
|
|
8
|
+
import { toggleVariants } from "./toggle";
|
|
9
|
+
|
|
10
|
+
const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
|
|
11
|
+
size: "default",
|
|
12
|
+
variant: "default",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function ToggleGroup({
|
|
16
|
+
className,
|
|
17
|
+
variant,
|
|
18
|
+
size,
|
|
19
|
+
children,
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> & VariantProps<typeof toggleVariants>) {
|
|
22
|
+
return (
|
|
23
|
+
<ToggleGroupPrimitive.Root
|
|
24
|
+
data-slot="toggle-group"
|
|
25
|
+
data-variant={variant}
|
|
26
|
+
data-size={size}
|
|
27
|
+
className={cn(
|
|
28
|
+
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
<ToggleGroupContext.Provider value={{ variant, size }}>
|
|
34
|
+
{children}
|
|
35
|
+
</ToggleGroupContext.Provider>
|
|
36
|
+
</ToggleGroupPrimitive.Root>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ToggleGroupItem({
|
|
41
|
+
className,
|
|
42
|
+
children,
|
|
43
|
+
variant,
|
|
44
|
+
size,
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>) {
|
|
47
|
+
const context = React.useContext(ToggleGroupContext);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<ToggleGroupPrimitive.Item
|
|
51
|
+
data-slot="toggle-group-item"
|
|
52
|
+
data-variant={context.variant || variant}
|
|
53
|
+
data-size={context.size || size}
|
|
54
|
+
className={cn(
|
|
55
|
+
toggleVariants({
|
|
56
|
+
variant: context.variant || variant,
|
|
57
|
+
size: context.size || size,
|
|
58
|
+
}),
|
|
59
|
+
"min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
|
60
|
+
className
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</ToggleGroupPrimitive.Item>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { ToggleGroup, ToggleGroupItem };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../lib/utils";
|
|
8
|
+
|
|
9
|
+
const toggleVariants = cva(
|
|
10
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: "bg-transparent",
|
|
15
|
+
outline:
|
|
16
|
+
"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
default: "h-9 px-2 min-w-9",
|
|
20
|
+
sm: "h-8 px-1.5 min-w-8",
|
|
21
|
+
lg: "h-10 px-2.5 min-w-10",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: "default",
|
|
26
|
+
size: "default",
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function Toggle({
|
|
32
|
+
className,
|
|
33
|
+
variant,
|
|
34
|
+
size,
|
|
35
|
+
...props
|
|
36
|
+
}: React.ComponentProps<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>) {
|
|
37
|
+
return (
|
|
38
|
+
<TogglePrimitive.Root
|
|
39
|
+
data-slot="toggle"
|
|
40
|
+
className={cn(toggleVariants({ variant, size, className }))}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { Toggle, toggleVariants };
|