@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.
Files changed (207) hide show
  1. package/dist/chunk-2CUFS5LF.js +80 -0
  2. package/dist/chunk-3GWWZKX7.js +33 -0
  3. package/dist/chunk-3VMDCCCX.js +10 -0
  4. package/dist/chunk-4AVS6CV4.js +89 -0
  5. package/dist/chunk-4JOV7FXW.js +17 -0
  6. package/dist/chunk-4KOMHDZD.js +89 -0
  7. package/dist/chunk-4UO73SKC.js +26 -0
  8. package/dist/chunk-7H54PTVH.js +116 -0
  9. package/dist/chunk-CW24PLDW.js +24 -0
  10. package/dist/chunk-EBAMCZDW.js +112 -0
  11. package/dist/chunk-ERMIA7NP.js +106 -0
  12. package/dist/chunk-ESO2EM3L.js +46 -0
  13. package/dist/chunk-EUHEIWHZ.js +32 -0
  14. package/dist/chunk-FEK5XGZW.js +8 -0
  15. package/dist/chunk-NKHH23YK.js +31 -0
  16. package/dist/chunk-R47NEOSI.js +78 -0
  17. package/dist/chunk-UXAYXRFN.js +69 -0
  18. package/dist/chunk-X6GATUI2.js +19 -0
  19. package/dist/components/accordion.d.ts +9 -0
  20. package/dist/components/accordion.js +53 -0
  21. package/dist/components/alert-dialog.d.ts +23 -0
  22. package/dist/components/alert-dialog.js +98 -0
  23. package/dist/components/alert.d.ts +11 -0
  24. package/dist/components/alert.js +52 -0
  25. package/dist/components/aspect-ratio.d.ts +6 -0
  26. package/dist/components/aspect-ratio.js +2 -0
  27. package/dist/components/avatar.d.ts +8 -0
  28. package/dist/components/avatar.js +47 -0
  29. package/dist/components/badge.d.ts +13 -0
  30. package/dist/components/badge.js +3 -0
  31. package/dist/components/breadcrumb.d.ts +14 -0
  32. package/dist/components/breadcrumb.js +96 -0
  33. package/dist/components/button.d.ts +16 -0
  34. package/dist/components/button.js +4 -0
  35. package/dist/components/calendar.d.ts +11 -0
  36. package/dist/components/calendar.js +56 -0
  37. package/dist/components/card.d.ts +13 -0
  38. package/dist/components/card.js +4 -0
  39. package/dist/components/carousel.d.ts +24 -0
  40. package/dist/components/carousel.js +198 -0
  41. package/dist/components/checkbox.d.ts +6 -0
  42. package/dist/components/checkbox.js +25 -0
  43. package/dist/components/collapsible.d.ts +8 -0
  44. package/dist/components/collapsible.js +26 -0
  45. package/dist/components/command.d.ts +84 -0
  46. package/dist/components/command.js +4 -0
  47. package/dist/components/currency-input.d.ts +17 -0
  48. package/dist/components/currency-input.js +121 -0
  49. package/dist/components/dialog.d.ts +22 -0
  50. package/dist/components/dialog.js +3 -0
  51. package/dist/components/drawer.d.ts +27 -0
  52. package/dist/components/drawer.js +85 -0
  53. package/dist/components/dropdown-menu.d.ts +28 -0
  54. package/dist/components/dropdown-menu.js +211 -0
  55. package/dist/components/empty-state.d.ts +22 -0
  56. package/dist/components/empty-state.js +81 -0
  57. package/dist/components/form.d.ts +28 -0
  58. package/dist/components/form.js +97 -0
  59. package/dist/components/haptic-button.d.ts +12 -0
  60. package/dist/components/haptic-button.js +17 -0
  61. package/dist/components/input-otp.d.ts +14 -0
  62. package/dist/components/input-otp.js +62 -0
  63. package/dist/components/input.d.ts +6 -0
  64. package/dist/components/input.js +3 -0
  65. package/dist/components/label.d.ts +8 -0
  66. package/dist/components/label.js +3 -0
  67. package/dist/components/lazy-markdown.d.ts +11 -0
  68. package/dist/components/lazy-markdown.js +13 -0
  69. package/dist/components/link-button.d.ts +30 -0
  70. package/dist/components/link-button.js +17 -0
  71. package/dist/components/markdown-renderer.d.ts +11 -0
  72. package/dist/components/markdown-renderer.js +10 -0
  73. package/dist/components/multi-select-combobox.d.ts +23 -0
  74. package/dist/components/multi-select-combobox.js +114 -0
  75. package/dist/components/pagination.d.ts +18 -0
  76. package/dist/components/pagination.js +101 -0
  77. package/dist/components/popover.d.ts +8 -0
  78. package/dist/components/popover.js +3 -0
  79. package/dist/components/progress.d.ts +6 -0
  80. package/dist/components/progress.js +30 -0
  81. package/dist/components/radio-group.d.ts +7 -0
  82. package/dist/components/radio-group.js +30 -0
  83. package/dist/components/rating.d.ts +15 -0
  84. package/dist/components/rating.js +120 -0
  85. package/dist/components/scroll-area.d.ts +7 -0
  86. package/dist/components/scroll-area.js +44 -0
  87. package/dist/components/search-bar.d.ts +17 -0
  88. package/dist/components/search-bar.js +92 -0
  89. package/dist/components/searchable-select.d.ts +22 -0
  90. package/dist/components/searchable-select.js +104 -0
  91. package/dist/components/select.d.ts +15 -0
  92. package/dist/components/select.js +129 -0
  93. package/dist/components/separator.d.ts +6 -0
  94. package/dist/components/separator.js +25 -0
  95. package/dist/components/sheet.d.ts +29 -0
  96. package/dist/components/sheet.js +96 -0
  97. package/dist/components/skeleton-card.d.ts +13 -0
  98. package/dist/components/skeleton-card.js +154 -0
  99. package/dist/components/skeleton.d.ts +6 -0
  100. package/dist/components/skeleton.js +3 -0
  101. package/dist/components/slider.d.ts +6 -0
  102. package/dist/components/slider.js +24 -0
  103. package/dist/components/sliding-panels.d.ts +19 -0
  104. package/dist/components/sliding-panels.js +75 -0
  105. package/dist/components/sonner.d.ts +6 -0
  106. package/dist/components/sonner.js +23 -0
  107. package/dist/components/sticky-container.d.ts +44 -0
  108. package/dist/components/sticky-container.js +39 -0
  109. package/dist/components/switch.d.ts +6 -0
  110. package/dist/components/switch.js +31 -0
  111. package/dist/components/table.d.ts +12 -0
  112. package/dist/components/table.js +81 -0
  113. package/dist/components/tabs.d.ts +12 -0
  114. package/dist/components/tabs.js +55 -0
  115. package/dist/components/text.d.ts +31 -0
  116. package/dist/components/text.js +3 -0
  117. package/dist/components/textarea.d.ts +6 -0
  118. package/dist/components/textarea.js +23 -0
  119. package/dist/components/toast.d.ts +18 -0
  120. package/dist/components/toast.js +3 -0
  121. package/dist/components/toaster.d.ts +5 -0
  122. package/dist/components/toaster.js +25 -0
  123. package/dist/components/toggle-group.d.ts +12 -0
  124. package/dist/components/toggle-group.js +72 -0
  125. package/dist/components/toggle.d.ts +13 -0
  126. package/dist/components/toggle.js +3 -0
  127. package/dist/components/tooltip.d.ts +9 -0
  128. package/dist/components/tooltip.js +26 -0
  129. package/dist/components/use-mobile.d.ts +3 -0
  130. package/dist/components/use-mobile.js +19 -0
  131. package/dist/components/use-toast.d.ts +42 -0
  132. package/dist/components/use-toast.js +2 -0
  133. package/dist/hooks/use-haptic.d.ts +22 -0
  134. package/dist/hooks/use-haptic.js +2 -0
  135. package/dist/hooks/use-mobile.d.ts +3 -0
  136. package/dist/hooks/use-mobile.js +19 -0
  137. package/dist/hooks/use-mounted-theme.d.ts +6 -0
  138. package/dist/hooks/use-mounted-theme.js +18 -0
  139. package/dist/hooks/use-sticky.d.ts +18 -0
  140. package/dist/hooks/use-sticky.js +2 -0
  141. package/dist/lib/utils.d.ts +5 -0
  142. package/dist/lib/utils.js +2 -0
  143. package/package.json +203 -0
  144. package/src/components/accordion.tsx +57 -0
  145. package/src/components/alert-dialog.tsx +116 -0
  146. package/src/components/alert.tsx +57 -0
  147. package/src/components/aspect-ratio.tsx +9 -0
  148. package/src/components/avatar.tsx +49 -0
  149. package/src/components/badge.tsx +38 -0
  150. package/src/components/breadcrumb.tsx +102 -0
  151. package/src/components/button.tsx +94 -0
  152. package/src/components/calendar.tsx +60 -0
  153. package/src/components/card.tsx +67 -0
  154. package/src/components/carousel.tsx +230 -0
  155. package/src/components/checkbox.tsx +27 -0
  156. package/src/components/collapsible.tsx +28 -0
  157. package/src/components/command.tsx +148 -0
  158. package/src/components/currency-input.tsx +158 -0
  159. package/src/components/dialog.tsx +103 -0
  160. package/src/components/drawer.tsx +99 -0
  161. package/src/components/dropdown-menu.tsx +228 -0
  162. package/src/components/empty-state.tsx +118 -0
  163. package/src/components/form.tsx +152 -0
  164. package/src/components/haptic-button.tsx +19 -0
  165. package/src/components/input-otp.tsx +70 -0
  166. package/src/components/input.tsx +23 -0
  167. package/src/components/label.tsx +20 -0
  168. package/src/components/lazy-markdown.tsx +20 -0
  169. package/src/components/link-button.tsx +40 -0
  170. package/src/components/markdown-renderer.tsx +20 -0
  171. package/src/components/multi-select-combobox.tsx +148 -0
  172. package/src/components/pagination.tsx +106 -0
  173. package/src/components/popover.tsx +30 -0
  174. package/src/components/progress.tsx +27 -0
  175. package/src/components/radio-group.tsx +37 -0
  176. package/src/components/rating.tsx +136 -0
  177. package/src/components/scroll-area.tsx +45 -0
  178. package/src/components/search-bar.tsx +113 -0
  179. package/src/components/searchable-select.tsx +134 -0
  180. package/src/components/select.tsx +152 -0
  181. package/src/components/separator.tsx +25 -0
  182. package/src/components/sheet.tsx +121 -0
  183. package/src/components/skeleton-card.tsx +282 -0
  184. package/src/components/skeleton.tsx +17 -0
  185. package/src/components/slider.tsx +24 -0
  186. package/src/components/sliding-panels.tsx +99 -0
  187. package/src/components/sonner.tsx +25 -0
  188. package/src/components/sticky-container.tsx +88 -0
  189. package/src/components/switch.tsx +28 -0
  190. package/src/components/table.tsx +90 -0
  191. package/src/components/tabs.tsx +72 -0
  192. package/src/components/text.test.tsx +192 -0
  193. package/src/components/text.tsx +114 -0
  194. package/src/components/textarea.tsx +22 -0
  195. package/src/components/toast.tsx +129 -0
  196. package/src/components/toaster.tsx +31 -0
  197. package/src/components/toggle-group.tsx +69 -0
  198. package/src/components/toggle.tsx +46 -0
  199. package/src/components/tooltip.tsx +29 -0
  200. package/src/components/use-mobile.tsx +19 -0
  201. package/src/components/use-toast.ts +180 -0
  202. package/src/globals.css +409 -0
  203. package/src/hooks/use-haptic.ts +118 -0
  204. package/src/hooks/use-mobile.ts +19 -0
  205. package/src/hooks/use-mounted-theme.ts +20 -0
  206. package/src/hooks/use-sticky.ts +47 -0
  207. package/src/lib/utils.ts +6 -0
@@ -0,0 +1,102 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { ChevronRight, MoreHorizontal } from "lucide-react";
4
+
5
+ import { cn } from "../lib/utils";
6
+
7
+ function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
8
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
9
+ }
10
+
11
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
12
+ return (
13
+ <ol
14
+ data-slot="breadcrumb-list"
15
+ className={cn(
16
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ );
22
+ }
23
+
24
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
25
+ return (
26
+ <li
27
+ data-slot="breadcrumb-item"
28
+ className={cn("inline-flex items-center gap-1.5", className)}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+
34
+ function BreadcrumbLink({
35
+ asChild,
36
+ className,
37
+ ...props
38
+ }: React.ComponentProps<"a"> & {
39
+ asChild?: boolean;
40
+ }) {
41
+ const Comp = asChild ? Slot : "a";
42
+
43
+ return (
44
+ <Comp
45
+ data-slot="breadcrumb-link"
46
+ className={cn("hover:text-foreground transition-colors", className)}
47
+ {...props}
48
+ />
49
+ );
50
+ }
51
+
52
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
53
+ return (
54
+ <span
55
+ data-slot="breadcrumb-page"
56
+ role="link"
57
+ aria-disabled="true"
58
+ aria-current="page"
59
+ className={cn("text-foreground font-normal", className)}
60
+ {...props}
61
+ />
62
+ );
63
+ }
64
+
65
+ function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">) {
66
+ return (
67
+ <li
68
+ data-slot="breadcrumb-separator"
69
+ role="presentation"
70
+ aria-hidden="true"
71
+ className={cn("[&>svg]:size-3.5", className)}
72
+ {...props}
73
+ >
74
+ {children ?? <ChevronRight />}
75
+ </li>
76
+ );
77
+ }
78
+
79
+ function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">) {
80
+ return (
81
+ <span
82
+ data-slot="breadcrumb-ellipsis"
83
+ role="presentation"
84
+ aria-hidden="true"
85
+ className={cn("flex size-9 items-center justify-center", className)}
86
+ {...props}
87
+ >
88
+ <MoreHorizontal className="size-4" />
89
+ <span className="sr-only">More</span>
90
+ </span>
91
+ );
92
+ }
93
+
94
+ export {
95
+ Breadcrumb,
96
+ BreadcrumbList,
97
+ BreadcrumbItem,
98
+ BreadcrumbLink,
99
+ BreadcrumbPage,
100
+ BreadcrumbSeparator,
101
+ BreadcrumbEllipsis,
102
+ };
@@ -0,0 +1,94 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "../lib/utils";
5
+ import { useHaptic } from "../hooks/use-haptic";
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-3xl text-sm font-medium 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 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer [@media(pointer:coarse)]:active:scale-95",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary backdrop-blur-sm text-primary-foreground shadow-lg hover:bg-primary/85 border border-primary/20 transition-colors duration-200",
14
+ destructive:
15
+ "bg-destructive text-destructive-foreground shadow-lg hover:bg-destructive/90 hover:shadow-destructive/20 backdrop-blur-sm border border-destructive/20",
16
+ outline:
17
+ "border border-border bg-card/70 backdrop-blur-md hover:bg-accent hover:text-accent-foreground hover:border-accent-foreground/20 hover:shadow-lg glass-hover",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-lg hover:bg-secondary/90 hover:shadow-secondary/20 backdrop-blur-sm border border-secondary/20",
20
+ ghost: "hover:bg-foreground/10 hover:text-foreground transition-colors duration-200",
21
+ link: "text-primary underline-offset-4 hover:underline hover:text-primary/80",
22
+ glass: "glass glass-hover text-foreground hover:text-accent-foreground",
23
+ brown:
24
+ "bg-[#482E1F] text-white shadow-lg hover:bg-[#352317] hover:shadow-[#482E1F]/20 backdrop-blur-sm border border-[#482E1F]/30 transition-all duration-300",
25
+ antagonist:
26
+ "bg-primary-foreground text-primary shadow-lg hover:bg-primary-foreground/90 hover:shadow-primary-foreground/20 backdrop-blur-sm border border-primary-foreground/20 transition-all duration-300",
27
+ },
28
+ size: {
29
+ default: "h-11 px-6 py-2",
30
+ sm: "h-9 rounded-lg px-4",
31
+ lg: "h-12 rounded-xl px-8",
32
+ icon: "h-11 w-11",
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ variant: "default",
37
+ size: "default",
38
+ },
39
+ }
40
+ );
41
+
42
+ export interface ButtonProps
43
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
44
+ asChild?: boolean;
45
+ haptic?: boolean;
46
+ hapticStyle?: "light" | "medium" | "heavy";
47
+ }
48
+
49
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
50
+ (
51
+ {
52
+ className,
53
+ variant,
54
+ size,
55
+ asChild = false,
56
+ haptic = true,
57
+ hapticStyle = "light",
58
+ onClick,
59
+ ...props
60
+ },
61
+ ref
62
+ ) => {
63
+ const Comp = asChild ? Slot : "button";
64
+ const { trigger } = useHaptic();
65
+ const [isMounted, setIsMounted] = React.useState(false);
66
+
67
+ // Track mounted state to prevent hydration issues
68
+ React.useEffect(() => {
69
+ setIsMounted(true);
70
+ }, []);
71
+
72
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
73
+ // Only trigger haptic feedback after component has mounted to prevent hydration issues
74
+ if (haptic && isMounted) {
75
+ trigger(hapticStyle);
76
+ }
77
+
78
+ // Call the original onClick handler
79
+ onClick?.(event);
80
+ };
81
+
82
+ return (
83
+ <Comp
84
+ className={cn(buttonVariants({ variant, size, className }))}
85
+ ref={ref}
86
+ onClick={handleClick}
87
+ {...props}
88
+ />
89
+ );
90
+ }
91
+ );
92
+ Button.displayName = "Button";
93
+
94
+ export { Button, buttonVariants };
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import type * as React from "react";
4
+ import { ChevronLeft, ChevronRight } from "lucide-react";
5
+ import { DayPicker } from "react-day-picker";
6
+ import { cn } from "../lib/utils";
7
+ import { buttonVariants } from "./button";
8
+
9
+ export type CalendarProps = React.ComponentProps<typeof DayPicker>;
10
+
11
+ function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
12
+ return (
13
+ <DayPicker
14
+ showOutsideDays={showOutsideDays}
15
+ className={cn("p-3", className)}
16
+ classNames={{
17
+ months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
18
+ month: "space-y-4",
19
+ caption: "flex justify-center pt-1 relative items-center",
20
+ caption_label: "text-sm font-medium",
21
+ nav: "space-x-1 flex items-center",
22
+ nav_button: cn(
23
+ buttonVariants({ variant: "outline" }),
24
+ "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 glass-hover"
25
+ ),
26
+ nav_button_previous: "absolute left-1",
27
+ nav_button_next: "absolute right-1",
28
+ table: "w-full border-collapse space-y-1",
29
+ head_row: "flex",
30
+ head_cell: "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
31
+ row: "flex w-full mt-2",
32
+ cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
33
+ day: cn(
34
+ buttonVariants({ variant: "ghost" }),
35
+ "h-9 w-9 p-0 font-normal aria-selected:opacity-100 glass-hover"
36
+ ),
37
+ day_range_end: "day-range-end",
38
+ day_selected:
39
+ "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground glass-glow",
40
+ day_today: "bg-accent text-accent-foreground",
41
+ day_outside:
42
+ "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
43
+ day_disabled: "text-muted-foreground opacity-50",
44
+ day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
45
+ day_hidden: "invisible",
46
+ ...classNames,
47
+ }}
48
+ components={{
49
+ Chevron: (props) => {
50
+ if (props.orientation === "left") return <ChevronLeft className="h-4 w-4" />;
51
+ return <ChevronRight className="h-4 w-4" />;
52
+ },
53
+ }}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+ Calendar.displayName = "Calendar";
59
+
60
+ export { Calendar };
@@ -0,0 +1,67 @@
1
+ import * as React from "react";
2
+ import { cn } from "../lib/utils";
3
+ import { textVariants } from "./text";
4
+
5
+ type CardVariant = "glass" | "surface";
6
+
7
+ const Card = React.forwardRef<
8
+ HTMLDivElement,
9
+ React.HTMLAttributes<HTMLDivElement> & { variant?: CardVariant }
10
+ >(({ className, variant = "glass", ...props }, ref) => (
11
+ <div
12
+ ref={ref}
13
+ className={cn(
14
+ variant === "glass"
15
+ ? "glass rounded-[22px] border border-transparent text-card-foreground transition-[transform,border-color] duration-300 [@media(hover:hover)]:hover:-translate-y-0.5 hover:border-primary/40"
16
+ : "bg-surface rounded-[22px] border border-border text-card-foreground transition-all duration-200 hover:border-primary/40 hover:-translate-y-0.5",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ ));
22
+ Card.displayName = "Card";
23
+
24
+ const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
25
+ ({ className, ...props }, ref) => (
26
+ <div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
27
+ )
28
+ );
29
+ CardHeader.displayName = "CardHeader";
30
+
31
+ const CardTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
32
+ ({ className, ...props }, ref) => (
33
+ <div
34
+ ref={ref}
35
+ className={cn(textVariants({ variant: "h4", wrap: "balance" }), className)}
36
+ {...props}
37
+ />
38
+ )
39
+ );
40
+ CardTitle.displayName = "CardTitle";
41
+
42
+ const CardDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
43
+ ({ className, ...props }, ref) => (
44
+ <div
45
+ ref={ref}
46
+ className={cn("text-sm", textVariants({ color: "muted", wrap: "pretty" }), className)}
47
+ {...props}
48
+ />
49
+ )
50
+ );
51
+ CardDescription.displayName = "CardDescription";
52
+
53
+ const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
54
+ ({ className, ...props }, ref) => (
55
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
56
+ )
57
+ );
58
+ CardContent.displayName = "CardContent";
59
+
60
+ const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
61
+ ({ className, ...props }, ref) => (
62
+ <div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
63
+ )
64
+ );
65
+ CardFooter.displayName = "CardFooter";
66
+
67
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
@@ -0,0 +1,230 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react";
5
+ import { ArrowLeft, ArrowRight } from "lucide-react";
6
+
7
+ import { cn } from "../lib/utils";
8
+ import { Button } from "./button";
9
+
10
+ type CarouselApi = UseEmblaCarouselType[1];
11
+ type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
12
+ type CarouselOptions = UseCarouselParameters[0];
13
+ type CarouselPlugin = UseCarouselParameters[1];
14
+
15
+ type CarouselProps = {
16
+ opts?: CarouselOptions;
17
+ plugins?: CarouselPlugin;
18
+ orientation?: "horizontal" | "vertical";
19
+ setApi?: (api: CarouselApi) => void;
20
+ };
21
+
22
+ type CarouselContextProps = {
23
+ carouselRef: ReturnType<typeof useEmblaCarousel>[0];
24
+ api: ReturnType<typeof useEmblaCarousel>[1];
25
+ scrollPrev: () => void;
26
+ scrollNext: () => void;
27
+ canScrollPrev: boolean;
28
+ canScrollNext: boolean;
29
+ } & CarouselProps;
30
+
31
+ const CarouselContext = React.createContext<CarouselContextProps | null>(null);
32
+
33
+ function useCarousel() {
34
+ const context = React.useContext(CarouselContext);
35
+
36
+ if (!context) {
37
+ throw new Error("useCarousel must be used within a <Carousel />");
38
+ }
39
+
40
+ return context;
41
+ }
42
+
43
+ function Carousel({
44
+ orientation = "horizontal",
45
+ opts,
46
+ setApi,
47
+ plugins,
48
+ className,
49
+ children,
50
+ ...props
51
+ }: React.ComponentProps<"div"> & CarouselProps) {
52
+ const [carouselRef, api] = useEmblaCarousel(
53
+ {
54
+ ...opts,
55
+ axis: orientation === "horizontal" ? "x" : "y",
56
+ },
57
+ plugins
58
+ );
59
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false);
60
+ const [canScrollNext, setCanScrollNext] = React.useState(false);
61
+
62
+ const onSelect = React.useCallback((api: CarouselApi) => {
63
+ if (!api) return;
64
+ setCanScrollPrev(api.canScrollPrev());
65
+ setCanScrollNext(api.canScrollNext());
66
+ }, []);
67
+
68
+ const scrollPrev = React.useCallback(() => {
69
+ api?.scrollPrev();
70
+ }, [api]);
71
+
72
+ const scrollNext = React.useCallback(() => {
73
+ api?.scrollNext();
74
+ }, [api]);
75
+
76
+ const handleKeyDown = React.useCallback(
77
+ (event: React.KeyboardEvent<HTMLDivElement>) => {
78
+ if (event.key === "ArrowLeft") {
79
+ event.preventDefault();
80
+ scrollPrev();
81
+ } else if (event.key === "ArrowRight") {
82
+ event.preventDefault();
83
+ scrollNext();
84
+ }
85
+ },
86
+ [scrollPrev, scrollNext]
87
+ );
88
+
89
+ React.useEffect(() => {
90
+ if (!api || !setApi) return;
91
+ setApi(api);
92
+ }, [api, setApi]);
93
+
94
+ React.useEffect(() => {
95
+ if (!api) return;
96
+ onSelect(api);
97
+ api.on("reInit", onSelect);
98
+ api.on("select", onSelect);
99
+
100
+ return () => {
101
+ api?.off("select", onSelect);
102
+ };
103
+ }, [api, onSelect]);
104
+
105
+ return (
106
+ <CarouselContext.Provider
107
+ value={{
108
+ carouselRef,
109
+ api: api,
110
+ opts,
111
+ orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
112
+ scrollPrev,
113
+ scrollNext,
114
+ canScrollPrev,
115
+ canScrollNext,
116
+ }}
117
+ >
118
+ <div
119
+ onKeyDownCapture={handleKeyDown}
120
+ className={cn("relative", className)}
121
+ role="region"
122
+ aria-roledescription="carousel"
123
+ data-slot="carousel"
124
+ {...props}
125
+ >
126
+ {children}
127
+ </div>
128
+ </CarouselContext.Provider>
129
+ );
130
+ }
131
+
132
+ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
133
+ const { carouselRef, orientation } = useCarousel();
134
+
135
+ return (
136
+ <div ref={carouselRef} className="overflow-hidden" data-slot="carousel-content">
137
+ <div
138
+ className={cn("flex", orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col", className)}
139
+ {...props}
140
+ />
141
+ </div>
142
+ );
143
+ }
144
+
145
+ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
146
+ const { orientation } = useCarousel();
147
+
148
+ return (
149
+ <div
150
+ role="group"
151
+ aria-roledescription="slide"
152
+ data-slot="carousel-item"
153
+ className={cn(
154
+ "min-w-0 shrink-0 grow-0 basis-full",
155
+ orientation === "horizontal" ? "pl-4" : "pt-4",
156
+ className
157
+ )}
158
+ {...props}
159
+ />
160
+ );
161
+ }
162
+
163
+ function CarouselPrevious({
164
+ className,
165
+ variant = "outline",
166
+ size = "icon",
167
+ ...props
168
+ }: React.ComponentProps<typeof Button>) {
169
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel();
170
+
171
+ return (
172
+ <Button
173
+ data-slot="carousel-previous"
174
+ variant={variant}
175
+ size={size}
176
+ className={cn(
177
+ "absolute size-8 rounded-full",
178
+ orientation === "horizontal"
179
+ ? "top-1/2 -left-12 -translate-y-1/2"
180
+ : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
181
+ className
182
+ )}
183
+ disabled={!canScrollPrev}
184
+ onClick={scrollPrev}
185
+ {...props}
186
+ >
187
+ <ArrowLeft />
188
+ <span className="sr-only">Previous slide</span>
189
+ </Button>
190
+ );
191
+ }
192
+
193
+ function CarouselNext({
194
+ className,
195
+ variant = "outline",
196
+ size = "icon",
197
+ ...props
198
+ }: React.ComponentProps<typeof Button>) {
199
+ const { orientation, scrollNext, canScrollNext } = useCarousel();
200
+
201
+ return (
202
+ <Button
203
+ data-slot="carousel-next"
204
+ variant={variant}
205
+ size={size}
206
+ className={cn(
207
+ "absolute size-8 rounded-full",
208
+ orientation === "horizontal"
209
+ ? "top-1/2 -right-12 -translate-y-1/2"
210
+ : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
211
+ className
212
+ )}
213
+ disabled={!canScrollNext}
214
+ onClick={scrollNext}
215
+ {...props}
216
+ >
217
+ <ArrowRight />
218
+ <span className="sr-only">Next slide</span>
219
+ </Button>
220
+ );
221
+ }
222
+
223
+ export {
224
+ type CarouselApi,
225
+ Carousel,
226
+ CarouselContent,
227
+ CarouselItem,
228
+ CarouselPrevious,
229
+ CarouselNext,
230
+ };
@@ -0,0 +1,27 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
5
+ import { Check } from "lucide-react";
6
+ import { cn } from "../lib/utils";
7
+
8
+ const Checkbox = React.forwardRef<
9
+ React.ElementRef<typeof CheckboxPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <CheckboxPrimitive.Root
13
+ ref={ref}
14
+ className={cn(
15
+ "peer h-5 w-5 shrink-0 rounded-md border border-border glass transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=checked]:shadow-lg data-[state=checked]:shadow-primary/20 hover:border-accent/50 hover:shadow-md",
16
+ className
17
+ )}
18
+ {...props}
19
+ >
20
+ <CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
21
+ <Check className="h-3.5 w-3.5 animate-in zoom-in-50 duration-200" />
22
+ </CheckboxPrimitive.Indicator>
23
+ </CheckboxPrimitive.Root>
24
+ ));
25
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
26
+
27
+ export { Checkbox };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
5
+ import { cn } from "../lib/utils";
6
+
7
+ const Collapsible = CollapsiblePrimitive.Root;
8
+
9
+ const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
10
+
11
+ const CollapsibleContent = React.forwardRef<
12
+ React.ElementRef<typeof CollapsiblePrimitive.CollapsibleContent>,
13
+ React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>
14
+ >(({ className, children, ...props }, ref) => (
15
+ <CollapsiblePrimitive.CollapsibleContent
16
+ ref={ref}
17
+ className={cn(
18
+ "transition-all data-[state=closed]:overflow-hidden data-[state=open]:overflow-visible data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down",
19
+ className
20
+ )}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </CollapsiblePrimitive.CollapsibleContent>
25
+ ));
26
+ CollapsibleContent.displayName = CollapsiblePrimitive.CollapsibleContent.displayName;
27
+
28
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };