@codefast/ui 0.3.16-canary.1 → 0.3.16-canary.3

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 (223) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/dist/components/accordion.mjs +2 -2
  4. package/dist/components/alert-dialog.d.mts +1 -1
  5. package/dist/components/alert-dialog.mjs +4 -4
  6. package/dist/components/alert.d.mts +3 -13
  7. package/dist/components/alert.mjs +3 -23
  8. package/dist/components/badge.d.mts +3 -15
  9. package/dist/components/badge.mjs +2 -44
  10. package/dist/components/breadcrumb.mjs +1 -1
  11. package/dist/components/button-group.d.mts +3 -13
  12. package/dist/components/button-group.mjs +3 -24
  13. package/dist/components/button.d.mts +3 -25
  14. package/dist/components/button.mjs +2 -72
  15. package/dist/components/calendar.mjs +2 -1
  16. package/dist/components/carousel.d.mts +1 -2
  17. package/dist/components/chart.d.mts +2 -4
  18. package/dist/components/checkbox.mjs +2 -2
  19. package/dist/components/context-menu.mjs +2 -2
  20. package/dist/components/dialog.d.mts +1 -1
  21. package/dist/components/dialog.mjs +4 -4
  22. package/dist/components/drawer.d.mts +1 -1
  23. package/dist/components/drawer.mjs +2 -2
  24. package/dist/components/dropdown-menu.mjs +2 -2
  25. package/dist/components/empty.d.mts +3 -13
  26. package/dist/components/empty.mjs +3 -18
  27. package/dist/components/field.d.mts +3 -14
  28. package/dist/components/field.mjs +3 -32
  29. package/dist/components/form.d.mts +2 -4
  30. package/dist/components/hover-card.mjs +1 -1
  31. package/dist/components/input-group.d.mts +4 -31
  32. package/dist/components/input-group.mjs +3 -90
  33. package/dist/components/input-number.mjs +4 -4
  34. package/dist/components/input-otp.mjs +2 -2
  35. package/dist/components/input.mjs +1 -1
  36. package/dist/components/item.d.mts +4 -29
  37. package/dist/components/item.mjs +3 -56
  38. package/dist/components/menubar.mjs +2 -2
  39. package/dist/components/native-select.mjs +1 -1
  40. package/dist/components/navigation-menu.d.mts +1 -6
  41. package/dist/components/navigation-menu.mjs +8 -15
  42. package/dist/components/pagination.d.mts +1 -1
  43. package/dist/components/pagination.mjs +1 -1
  44. package/dist/components/popover.mjs +1 -1
  45. package/dist/components/progress-circle.d.mts +3 -47
  46. package/dist/components/progress-circle.mjs +2 -47
  47. package/dist/components/progress.mjs +1 -1
  48. package/dist/components/radio-group.mjs +1 -1
  49. package/dist/components/radio.mjs +1 -1
  50. package/dist/components/scroll-area.d.mts +3 -19
  51. package/dist/components/scroll-area.mjs +4 -61
  52. package/dist/components/select.d.mts +1 -1
  53. package/dist/components/select.mjs +3 -3
  54. package/dist/components/separator.d.mts +3 -18
  55. package/dist/components/separator.mjs +3 -23
  56. package/dist/components/sheet.d.mts +6 -18
  57. package/dist/components/sheet.mjs +6 -49
  58. package/dist/components/sidebar.d.mts +4 -19
  59. package/dist/components/sidebar.mjs +10 -46
  60. package/dist/components/skeleton.mjs +1 -1
  61. package/dist/components/slider.mjs +1 -1
  62. package/dist/components/spinner.mjs +1 -1
  63. package/dist/components/switch.mjs +2 -2
  64. package/dist/components/table.mjs +1 -1
  65. package/dist/components/tabs.mjs +1 -1
  66. package/dist/components/textarea.mjs +1 -1
  67. package/dist/components/toggle-group.d.mts +3 -2
  68. package/dist/components/toggle-group.mjs +1 -1
  69. package/dist/components/toggle.d.mts +2 -21
  70. package/dist/components/toggle.mjs +2 -39
  71. package/dist/components/tooltip.mjs +1 -1
  72. package/dist/index.d.mts +31 -16
  73. package/dist/index.mjs +30 -15
  74. package/dist/lib/utils.d.mts +1 -12
  75. package/dist/lib/utils.mjs +1 -9
  76. package/dist/primitives/checkbox-group.d.mts +1 -2
  77. package/dist/primitives/input-number.d.mts +1 -2
  78. package/dist/primitives/input.d.mts +1 -2
  79. package/dist/primitives/progress-circle.d.mts +1 -2
  80. package/dist/variants/alert.d.mts +18 -0
  81. package/dist/variants/alert.mjs +25 -0
  82. package/dist/variants/badge.d.mts +20 -0
  83. package/dist/variants/badge.mjs +46 -0
  84. package/dist/variants/button-group.d.mts +18 -0
  85. package/dist/variants/button-group.mjs +26 -0
  86. package/dist/variants/button.d.mts +30 -0
  87. package/dist/variants/button.mjs +76 -0
  88. package/dist/variants/empty.d.mts +18 -0
  89. package/dist/variants/empty.mjs +20 -0
  90. package/dist/variants/field.d.mts +19 -0
  91. package/dist/variants/field.mjs +34 -0
  92. package/dist/variants/input-group.d.mts +43 -0
  93. package/dist/variants/input-group.mjs +93 -0
  94. package/dist/variants/item.d.mts +37 -0
  95. package/dist/variants/item.mjs +60 -0
  96. package/dist/variants/navigation-menu.d.mts +13 -0
  97. package/dist/variants/navigation-menu.mjs +12 -0
  98. package/dist/variants/progress-circle.d.mts +52 -0
  99. package/dist/variants/progress-circle.mjs +49 -0
  100. package/dist/variants/scroll-area.d.mts +24 -0
  101. package/dist/variants/scroll-area.mjs +63 -0
  102. package/dist/variants/separator.d.mts +23 -0
  103. package/dist/variants/separator.mjs +25 -0
  104. package/dist/variants/sheet.d.mts +20 -0
  105. package/dist/variants/sheet.mjs +50 -0
  106. package/dist/variants/sidebar.d.mts +23 -0
  107. package/dist/variants/sidebar.mjs +42 -0
  108. package/dist/variants/toggle.d.mts +23 -0
  109. package/dist/variants/toggle.mjs +43 -0
  110. package/package.json +169 -21
  111. package/src/components/accordion.tsx +156 -0
  112. package/src/components/alert-dialog.tsx +314 -0
  113. package/src/components/alert.tsx +86 -0
  114. package/src/components/aspect-ratio.tsx +28 -0
  115. package/src/components/avatar.tsx +84 -0
  116. package/src/components/badge.tsx +38 -0
  117. package/src/components/breadcrumb.tsx +197 -0
  118. package/src/components/button-group.tsx +107 -0
  119. package/src/components/button.tsx +66 -0
  120. package/src/components/calendar.tsx +277 -0
  121. package/src/components/card.tsx +175 -0
  122. package/src/components/carousel.tsx +367 -0
  123. package/src/components/chart.tsx +587 -0
  124. package/src/components/checkbox-cards.tsx +92 -0
  125. package/src/components/checkbox-group.tsx +83 -0
  126. package/src/components/checkbox.tsx +65 -0
  127. package/src/components/collapsible.tsx +60 -0
  128. package/src/components/command.tsx +311 -0
  129. package/src/components/context-menu.tsx +489 -0
  130. package/src/components/dialog.tsx +295 -0
  131. package/src/components/drawer.tsx +271 -0
  132. package/src/components/dropdown-menu.tsx +498 -0
  133. package/src/components/empty.tsx +169 -0
  134. package/src/components/field.tsx +362 -0
  135. package/src/components/form.tsx +300 -0
  136. package/src/components/hover-card.tsx +116 -0
  137. package/src/components/input-group.tsx +224 -0
  138. package/src/components/input-number.tsx +161 -0
  139. package/src/components/input-otp.tsx +151 -0
  140. package/src/components/input-password.tsx +74 -0
  141. package/src/components/input-search.tsx +98 -0
  142. package/src/components/input.tsx +52 -0
  143. package/src/components/item.tsx +280 -0
  144. package/src/components/kbd.tsx +59 -0
  145. package/src/components/label.tsx +44 -0
  146. package/src/components/menubar.tsx +531 -0
  147. package/src/components/native-select.tsx +96 -0
  148. package/src/components/navigation-menu.tsx +295 -0
  149. package/src/components/pagination.tsx +204 -0
  150. package/src/components/popover.tsx +139 -0
  151. package/src/components/progress-circle.tsx +203 -0
  152. package/src/components/progress.tsx +54 -0
  153. package/src/components/radio-cards.tsx +85 -0
  154. package/src/components/radio-group.tsx +79 -0
  155. package/src/components/radio.tsx +61 -0
  156. package/src/components/resizable.tsx +99 -0
  157. package/src/components/scroll-area.tsx +115 -0
  158. package/src/components/select.tsx +319 -0
  159. package/src/components/separator.tsx +74 -0
  160. package/src/components/sheet.tsx +278 -0
  161. package/src/components/sidebar.tsx +1056 -0
  162. package/src/components/skeleton.tsx +37 -0
  163. package/src/components/slider.tsx +95 -0
  164. package/src/components/sonner.tsx +47 -0
  165. package/src/components/spinner.tsx +75 -0
  166. package/src/components/switch.tsx +66 -0
  167. package/src/components/table.tsx +200 -0
  168. package/src/components/tabs.tsx +128 -0
  169. package/src/components/textarea.tsx +49 -0
  170. package/src/components/toggle-group.tsx +141 -0
  171. package/src/components/toggle.tsx +39 -0
  172. package/src/components/tooltip.tsx +141 -0
  173. package/src/css/amber.css +59 -22
  174. package/src/css/blue.css +59 -22
  175. package/src/css/cyan.css +59 -22
  176. package/src/css/emerald.css +59 -22
  177. package/src/css/fuchsia.css +59 -22
  178. package/src/css/gray.css +59 -22
  179. package/src/css/green.css +59 -22
  180. package/src/css/indigo.css +59 -22
  181. package/src/css/lime.css +59 -22
  182. package/src/css/neutral.css +59 -22
  183. package/src/css/orange.css +59 -22
  184. package/src/css/pink.css +59 -22
  185. package/src/css/preset.css +32 -13
  186. package/src/css/purple.css +59 -22
  187. package/src/css/red.css +59 -22
  188. package/src/css/rose.css +59 -22
  189. package/src/css/sky.css +59 -22
  190. package/src/css/slate.css +59 -22
  191. package/src/css/stone.css +59 -22
  192. package/src/css/teal.css +59 -22
  193. package/src/css/violet.css +59 -22
  194. package/src/css/yellow.css +59 -22
  195. package/src/css/zinc.css +59 -22
  196. package/src/hooks/use-animated-value.ts +97 -0
  197. package/src/hooks/use-copy-to-clipboard.ts +63 -0
  198. package/src/hooks/use-is-mobile.ts +27 -0
  199. package/src/hooks/use-media-query.ts +71 -0
  200. package/src/hooks/use-mutation-observer.ts +54 -0
  201. package/src/hooks/use-pagination.ts +166 -0
  202. package/src/index.ts +720 -0
  203. package/src/lib/utils.ts +5 -0
  204. package/src/primitives/checkbox-group.tsx +360 -0
  205. package/src/primitives/input-number.tsx +1013 -0
  206. package/src/primitives/input.tsx +243 -0
  207. package/src/primitives/progress-circle.tsx +537 -0
  208. package/src/variants/alert.ts +45 -0
  209. package/src/variants/badge.ts +66 -0
  210. package/src/variants/button-group.ts +49 -0
  211. package/src/variants/button.ts +93 -0
  212. package/src/variants/empty.ts +43 -0
  213. package/src/variants/field.ts +50 -0
  214. package/src/variants/input-group.ts +132 -0
  215. package/src/variants/item.ts +90 -0
  216. package/src/variants/navigation-menu.ts +32 -0
  217. package/src/variants/progress-circle.ts +47 -0
  218. package/src/variants/scroll-area.ts +79 -0
  219. package/src/variants/separator.ts +41 -0
  220. package/src/variants/sheet.ts +70 -0
  221. package/src/variants/sidebar.ts +61 -0
  222. package/src/variants/toggle.ts +59 -0
  223. package/dist/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/clsx.d.mts +0 -6
@@ -0,0 +1,197 @@
1
+ "use client";
2
+
3
+ import type { ComponentProps, JSX, ReactNode } from "react";
4
+
5
+ import { cn } from "#/lib/utils";
6
+ import { Slot } from "@radix-ui/react-slot";
7
+ import { ChevronRightIcon, EllipsisIcon } from "lucide-react";
8
+
9
+ /* -----------------------------------------------------------------------------
10
+ * Component: Breadcrumb
11
+ * -------------------------------------------------------------------------- */
12
+
13
+ /**
14
+ * @since 0.3.16-canary.0
15
+ */
16
+ interface BreadcrumbProps extends ComponentProps<"nav"> {
17
+ separator?: ReactNode;
18
+ }
19
+
20
+ /**
21
+ * @since 0.3.16-canary.0
22
+ */
23
+ function Breadcrumb({ ...props }: BreadcrumbProps): JSX.Element {
24
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
25
+ }
26
+
27
+ /* -----------------------------------------------------------------------------
28
+ * Component: BreadcrumbList
29
+ * -------------------------------------------------------------------------- */
30
+
31
+ /**
32
+ * @since 0.3.16-canary.0
33
+ */
34
+ type BreadcrumbListProps = ComponentProps<"ol">;
35
+
36
+ /**
37
+ * @since 0.3.16-canary.0
38
+ */
39
+ function BreadcrumbList({ className, ...props }: BreadcrumbListProps): JSX.Element {
40
+ return (
41
+ <ol
42
+ className={cn(
43
+ "flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground",
44
+ "sm:gap-2",
45
+ className,
46
+ )}
47
+ data-slot="breadcrumb-list"
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ /* -----------------------------------------------------------------------------
54
+ * Component: BreadcrumbItem
55
+ * -------------------------------------------------------------------------- */
56
+
57
+ /**
58
+ * @since 0.3.16-canary.0
59
+ */
60
+ type BreadcrumbItemProps = ComponentProps<"li">;
61
+
62
+ /**
63
+ * @since 0.3.16-canary.0
64
+ */
65
+ function BreadcrumbItem({ className, ...props }: BreadcrumbItemProps): JSX.Element {
66
+ return (
67
+ <li
68
+ className={cn("inline-flex items-center gap-1.5", className)}
69
+ data-slot="breadcrumb-item"
70
+ {...props}
71
+ />
72
+ );
73
+ }
74
+
75
+ /* -----------------------------------------------------------------------------
76
+ * Component: BreadcrumbLink
77
+ * -------------------------------------------------------------------------- */
78
+
79
+ /**
80
+ * @since 0.3.16-canary.0
81
+ */
82
+ interface BreadcrumbLinkProps extends ComponentProps<"a"> {
83
+ asChild?: boolean;
84
+ }
85
+
86
+ /**
87
+ * @since 0.3.16-canary.0
88
+ */
89
+ function BreadcrumbLink({ asChild, className, ...props }: BreadcrumbLinkProps): JSX.Element {
90
+ const Component = asChild ? Slot : "a";
91
+
92
+ return (
93
+ <Component
94
+ className={cn(
95
+ "transition-colors motion-reduce:transition-none",
96
+ "hover:text-foreground",
97
+ className,
98
+ )}
99
+ data-slot="breadcrumb-link"
100
+ {...props}
101
+ />
102
+ );
103
+ }
104
+
105
+ /* -----------------------------------------------------------------------------
106
+ * Component: BreadcrumbPage
107
+ * -------------------------------------------------------------------------- */
108
+
109
+ /**
110
+ * @since 0.3.16-canary.0
111
+ */
112
+ type BreadcrumbPageProps = ComponentProps<"span">;
113
+
114
+ /**
115
+ * @since 0.3.16-canary.0
116
+ */
117
+ function BreadcrumbPage({ className, ...props }: BreadcrumbPageProps): JSX.Element {
118
+ return (
119
+ <span
120
+ aria-current="page"
121
+ aria-disabled="true"
122
+ className={cn("font-normal text-foreground", className)}
123
+ data-slot="breadcrumb-page"
124
+ {...props}
125
+ />
126
+ );
127
+ }
128
+
129
+ /* -----------------------------------------------------------------------------
130
+ * Component: BreadcrumbSeparator
131
+ * -------------------------------------------------------------------------- */
132
+
133
+ /**
134
+ * @since 0.3.16-canary.0
135
+ */
136
+ type BreadcrumbSeparatorProps = ComponentProps<"li">;
137
+
138
+ /**
139
+ * @since 0.3.16-canary.0
140
+ */
141
+ function BreadcrumbSeparator({ children, ...props }: BreadcrumbSeparatorProps): JSX.Element {
142
+ return (
143
+ <li aria-hidden="true" data-slot="breadcrumb-separator" role="presentation" {...props}>
144
+ {children ?? <ChevronRightIcon className="size-3.5" />}
145
+ </li>
146
+ );
147
+ }
148
+
149
+ /* -----------------------------------------------------------------------------
150
+ * Component: BreadcrumbEllipsis
151
+ * -------------------------------------------------------------------------- */
152
+
153
+ /**
154
+ * @since 0.3.16-canary.0
155
+ */
156
+ type BreadcrumbEllipsisProps = ComponentProps<"span">;
157
+
158
+ /**
159
+ * @since 0.3.16-canary.0
160
+ */
161
+ function BreadcrumbEllipsis({ className, ...props }: BreadcrumbEllipsisProps): JSX.Element {
162
+ return (
163
+ <span
164
+ aria-hidden="true"
165
+ className={cn("flex size-4 items-center justify-center", className)}
166
+ data-slot="breadcrumb-ellipsis"
167
+ role="presentation"
168
+ {...props}
169
+ >
170
+ <EllipsisIcon className="size-4" />
171
+ <span className="sr-only">More</span>
172
+ </span>
173
+ );
174
+ }
175
+
176
+ /* -----------------------------------------------------------------------------
177
+ * Exports
178
+ * -------------------------------------------------------------------------- */
179
+
180
+ export {
181
+ Breadcrumb,
182
+ BreadcrumbEllipsis,
183
+ BreadcrumbItem,
184
+ BreadcrumbLink,
185
+ BreadcrumbList,
186
+ BreadcrumbPage,
187
+ BreadcrumbSeparator,
188
+ };
189
+ export type {
190
+ BreadcrumbEllipsisProps,
191
+ BreadcrumbItemProps,
192
+ BreadcrumbLinkProps,
193
+ BreadcrumbListProps,
194
+ BreadcrumbPageProps,
195
+ BreadcrumbProps,
196
+ BreadcrumbSeparatorProps,
197
+ };
@@ -0,0 +1,107 @@
1
+ "use client";
2
+
3
+ import type { ButtonGroupVariants } from "#/variants/button-group";
4
+ import type { ComponentProps, JSX } from "react";
5
+
6
+ import { cn } from "#/lib/utils";
7
+
8
+ import { buttonGroupVariants } from "#/variants/button-group";
9
+ import { Slot } from "@radix-ui/react-slot";
10
+
11
+ import { Separator } from "#/components/separator";
12
+
13
+ /* -----------------------------------------------------------------------------
14
+ * Component: ButtonGroup
15
+ * -------------------------------------------------------------------------- */
16
+
17
+ /**
18
+ * @since 0.3.16-canary.0
19
+ */
20
+ type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants;
21
+
22
+ /**
23
+ * @since 0.3.16-canary.0
24
+ */
25
+ function ButtonGroup({ className, orientation, ...props }: ButtonGroupProps): JSX.Element {
26
+ return (
27
+ <div
28
+ className={buttonGroupVariants({ orientation, className })}
29
+ data-orientation={orientation}
30
+ data-slot="button-group"
31
+ role="group"
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ /* -----------------------------------------------------------------------------
38
+ * Component: ButtonGroupText
39
+ * -------------------------------------------------------------------------- */
40
+
41
+ /**
42
+ * @since 0.3.16-canary.0
43
+ */
44
+ interface ButtonGroupTextProps extends ComponentProps<"div"> {
45
+ asChild?: boolean;
46
+ }
47
+
48
+ /**
49
+ * @since 0.3.16-canary.0
50
+ */
51
+ function ButtonGroupText({
52
+ asChild = false,
53
+ className,
54
+ ...props
55
+ }: ButtonGroupTextProps): JSX.Element {
56
+ const Component = asChild ? Slot : "div";
57
+
58
+ return (
59
+ <Component
60
+ className={cn(
61
+ "flex items-center gap-2",
62
+ "px-4",
63
+ "rounded-lg border",
64
+ "bg-muted shadow-xs",
65
+ "text-sm font-medium",
66
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
67
+ className,
68
+ )}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ /* -----------------------------------------------------------------------------
75
+ * Component: ButtonGroupSeparator
76
+ * -------------------------------------------------------------------------- */
77
+
78
+ /**
79
+ * @since 0.3.16-canary.0
80
+ */
81
+ type ButtonGroupSeparatorProps = ComponentProps<typeof Separator>;
82
+
83
+ /**
84
+ * @since 0.3.16-canary.0
85
+ */
86
+ function ButtonGroupSeparator({
87
+ className,
88
+ orientation = "vertical",
89
+ ...props
90
+ }: ButtonGroupSeparatorProps): JSX.Element {
91
+ return (
92
+ <Separator
93
+ className={cn("relative self-stretch", "bg-input", "data-vertical:h-auto", "!m-0", className)}
94
+ data-slot="button-group-separator"
95
+ orientation={orientation}
96
+ {...props}
97
+ />
98
+ );
99
+ }
100
+
101
+ /* -----------------------------------------------------------------------------
102
+ * Exports
103
+ * -------------------------------------------------------------------------- */
104
+
105
+ export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText };
106
+
107
+ export type { ButtonGroupProps, ButtonGroupSeparatorProps, ButtonGroupTextProps };
@@ -0,0 +1,66 @@
1
+ import type { ButtonVariants } from "#/variants/button";
2
+ import type { ComponentProps, JSX } from "react";
3
+
4
+ import { Slot } from "@radix-ui/react-slot";
5
+
6
+ import { buttonVariants } from "#/variants/button";
7
+
8
+ /* -----------------------------------------------------------------------------
9
+ * Component: Button
10
+ * -------------------------------------------------------------------------- */
11
+
12
+ /**
13
+ * @since 0.3.16-canary.0
14
+ */
15
+ type ButtonProps = ComponentProps<"button"> &
16
+ ButtonVariants & {
17
+ asChild?: boolean;
18
+ type?: ComponentProps<"button">["type"];
19
+ };
20
+
21
+ /**
22
+ * @since 0.3.16-canary.0
23
+ */
24
+ function Button({
25
+ asChild = false,
26
+ children,
27
+ className,
28
+ size,
29
+ type = "button",
30
+ variant,
31
+ ...props
32
+ }: ButtonProps): JSX.Element {
33
+ const Comp = asChild ? Slot : "button";
34
+
35
+ if (asChild) {
36
+ return (
37
+ <Comp
38
+ className={buttonVariants({ className, size, variant })}
39
+ data-slot="button"
40
+ data-variant={variant}
41
+ {...props}
42
+ >
43
+ {children}
44
+ </Comp>
45
+ );
46
+ }
47
+
48
+ return (
49
+ <button
50
+ className={buttonVariants({ className, size, variant })}
51
+ data-slot="button"
52
+ data-variant={variant}
53
+ type={type}
54
+ {...props}
55
+ >
56
+ {children}
57
+ </button>
58
+ );
59
+ }
60
+
61
+ /* -----------------------------------------------------------------------------
62
+ * Exports
63
+ * -------------------------------------------------------------------------- */
64
+
65
+ export { Button };
66
+ export type { ButtonProps };
@@ -0,0 +1,277 @@
1
+ "use client";
2
+
3
+ import type { ComponentProps, JSX } from "react";
4
+ import type { Chevron, DayButton, Root, WeekNumber } from "react-day-picker";
5
+
6
+ import { cn } from "#/lib/utils";
7
+ import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
8
+ import { useEffect, useRef } from "react";
9
+ import { DayPicker, getDefaultClassNames } from "react-day-picker";
10
+
11
+ import { Button } from "#/components/button";
12
+ import { buttonVariants } from "#/variants/button";
13
+
14
+ /* -----------------------------------------------------------------------------
15
+ * Component: Calendar
16
+ * -------------------------------------------------------------------------- */
17
+
18
+ /**
19
+ * @since 0.3.16-canary.0
20
+ */
21
+ type CalendarProps = ComponentProps<typeof DayPicker> & {
22
+ buttonVariant?: ComponentProps<typeof Button>["variant"];
23
+ };
24
+
25
+ /**
26
+ * @since 0.3.16-canary.0
27
+ */
28
+ function Calendar({
29
+ buttonVariant = "ghost",
30
+ captionLayout = "label",
31
+ className,
32
+ classNames,
33
+ components,
34
+ formatters,
35
+ showOutsideDays = true,
36
+ ...props
37
+ }: CalendarProps): JSX.Element {
38
+ const defaultClassNames = getDefaultClassNames();
39
+
40
+ return (
41
+ <DayPicker
42
+ captionLayout={captionLayout}
43
+ className={cn(
44
+ "group/calendar",
45
+ "p-3",
46
+ "bg-background",
47
+ "in-data-[slot=card-content]:bg-transparent",
48
+ "in-data-[slot=popover-content]:bg-transparent",
49
+ "rtl:**:[.rdp-button_next>svg]:rotate-180",
50
+ "rtl:**:[.rdp-button_previous>svg]:rotate-180",
51
+ "[--cell-size:--spacing(8)]",
52
+ className,
53
+ )}
54
+ classNames={{
55
+ button_next: buttonVariants({
56
+ variant: buttonVariant,
57
+ className: [
58
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
59
+ defaultClassNames.button_next,
60
+ ],
61
+ }),
62
+ button_previous: buttonVariants({
63
+ variant: buttonVariant,
64
+ className: [
65
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
66
+ defaultClassNames.button_previous,
67
+ ],
68
+ }),
69
+ caption_label: cn(
70
+ "font-medium",
71
+ "select-none",
72
+ captionLayout === "label"
73
+ ? "text-sm"
74
+ : "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
75
+ defaultClassNames.caption_label,
76
+ ),
77
+ day: cn(
78
+ "group/day relative",
79
+ "aspect-square h-full w-full p-0 text-center",
80
+ "select-none",
81
+ "[&:last-child[data-selected=true]_button]:rounded-r-md",
82
+ props.showWeekNumber
83
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
84
+ : "[&:first-child[data-selected=true]_button]:rounded-l-md",
85
+ defaultClassNames.day,
86
+ ),
87
+ disabled: cn("opacity-50", "text-muted-foreground", defaultClassNames.disabled),
88
+ dropdown: cn("absolute inset-0", "bg-popover", "opacity-0", defaultClassNames.dropdown),
89
+ dropdown_root: cn(
90
+ "relative",
91
+ "rounded-md border border-input shadow-xs",
92
+ "has-focus:border-ring has-focus:ring-3 has-focus:ring-ring/50",
93
+ defaultClassNames.dropdown_root,
94
+ ),
95
+ dropdowns: cn(
96
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5",
97
+ "text-sm font-medium",
98
+ defaultClassNames.dropdowns,
99
+ ),
100
+ hidden: cn("invisible", defaultClassNames.hidden),
101
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
102
+ month_caption: cn(
103
+ "flex h-(--cell-size) w-full items-center justify-center",
104
+ "px-(--cell-size)",
105
+ defaultClassNames.month_caption,
106
+ ),
107
+ months: cn("relative flex flex-col gap-4", "md:flex-row", defaultClassNames.months),
108
+ nav: cn(
109
+ "absolute flex w-full items-center justify-between gap-1",
110
+ "inset-x-0 top-0",
111
+ defaultClassNames.nav,
112
+ ),
113
+ outside: cn(
114
+ "text-muted-foreground",
115
+ "aria-selected:text-muted-foreground",
116
+ defaultClassNames.outside,
117
+ ),
118
+ range_end: cn("rounded-r-md", "bg-accent", defaultClassNames.range_end),
119
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
120
+ range_start: cn("rounded-l-md", "bg-accent", defaultClassNames.range_start),
121
+ root: cn("w-fit", defaultClassNames.root),
122
+ month_grid: "w-full border-collapse",
123
+ today: cn(
124
+ "rounded-md",
125
+ "bg-accent text-accent-foreground",
126
+ "data-selected:rounded-none",
127
+ defaultClassNames.today,
128
+ ),
129
+ week: cn("flex w-full", "mt-2", defaultClassNames.week),
130
+ week_number: cn(
131
+ "text-[0.8rem] text-muted-foreground",
132
+ "select-none",
133
+ defaultClassNames.week_number,
134
+ ),
135
+ week_number_header: cn(
136
+ "w-(--cell-size)",
137
+ "select-none",
138
+ defaultClassNames.week_number_header,
139
+ ),
140
+ weekday: cn(
141
+ "flex-1",
142
+ "rounded-md",
143
+ "text-[0.8rem] font-normal text-muted-foreground",
144
+ "select-none",
145
+ defaultClassNames.weekday,
146
+ ),
147
+ weekdays: cn("flex", defaultClassNames.weekdays),
148
+ ...classNames,
149
+ }}
150
+ components={{
151
+ Chevron: CalendarChevron,
152
+ DayButton: CalendarDayButton,
153
+ Root: CalendarRoot,
154
+ WeekNumber: CalendarWeekNumber,
155
+ ...components,
156
+ }}
157
+ formatters={{
158
+ formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
159
+ ...formatters,
160
+ }}
161
+ showOutsideDays={showOutsideDays}
162
+ {...props}
163
+ />
164
+ );
165
+ }
166
+
167
+ /* -----------------------------------------------------------------------------
168
+ * Component: CalendarChevron (internal)
169
+ * -------------------------------------------------------------------------- */
170
+
171
+ function CalendarChevron({
172
+ className,
173
+ orientation,
174
+ ...props
175
+ }: ComponentProps<typeof Chevron>): JSX.Element {
176
+ if (orientation === "left") {
177
+ return <ChevronLeftIcon className={cn("size-4", className)} {...props} />;
178
+ }
179
+
180
+ if (orientation === "right") {
181
+ return <ChevronRightIcon className={cn("size-4", className)} {...props} />;
182
+ }
183
+
184
+ return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
185
+ }
186
+
187
+ /* -----------------------------------------------------------------------------
188
+ * Component: CalendarRoot (internal)
189
+ * -------------------------------------------------------------------------- */
190
+
191
+ function CalendarRoot({ className, rootRef, ...props }: ComponentProps<typeof Root>): JSX.Element {
192
+ return <div ref={rootRef} className={cn(className)} data-slot="calendar" {...props} />;
193
+ }
194
+
195
+ /* -----------------------------------------------------------------------------
196
+ * Component: CalendarWeekNumber (internal)
197
+ * -------------------------------------------------------------------------- */
198
+
199
+ function CalendarWeekNumber({
200
+ children,
201
+ ...props
202
+ }: ComponentProps<typeof WeekNumber>): JSX.Element {
203
+ return (
204
+ <td {...props}>
205
+ <div className={cn("flex size-(--cell-size) items-center justify-center", "text-center")}>
206
+ {children}
207
+ </div>
208
+ </td>
209
+ );
210
+ }
211
+
212
+ /* -----------------------------------------------------------------------------
213
+ * Component: CalendarDayButton
214
+ * -------------------------------------------------------------------------- */
215
+
216
+ /**
217
+ * @since 0.3.16-canary.0
218
+ */
219
+ type CalendarDayButtonProps = ComponentProps<typeof DayButton>;
220
+
221
+ /**
222
+ * @since 0.3.16-canary.0
223
+ */
224
+ function CalendarDayButton({
225
+ className,
226
+ day,
227
+ modifiers,
228
+ ...props
229
+ }: CalendarDayButtonProps): JSX.Element {
230
+ const defaultClassNames = getDefaultClassNames();
231
+
232
+ const ref = useRef<HTMLButtonElement>(null);
233
+
234
+ useEffect(() => {
235
+ if (modifiers.focused) {
236
+ ref.current?.focus();
237
+ }
238
+ }, [modifiers.focused]);
239
+
240
+ return (
241
+ <Button
242
+ ref={ref}
243
+ className={cn(
244
+ "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal",
245
+ "group-data-focused/day:relative group-data-focused/day:z-10 group-data-focused/day:border-ring group-data-focused/day:ring-3 group-data-focused/day:ring-ring/50",
246
+ "data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground",
247
+ "data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground",
248
+ "data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground",
249
+ "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground",
250
+ "dark:hover:text-accent-foreground",
251
+ "[&>span]:text-xs [&>span]:opacity-70",
252
+ defaultClassNames.day,
253
+ className,
254
+ )}
255
+ data-day={day.date.toLocaleDateString()}
256
+ data-range-end={modifiers.range_end}
257
+ data-range-middle={modifiers.range_middle}
258
+ data-range-start={modifiers.range_start}
259
+ data-selected-single={
260
+ modifiers.selected &&
261
+ !modifiers.range_start &&
262
+ !modifiers.range_end &&
263
+ !modifiers.range_middle
264
+ }
265
+ size="icon"
266
+ variant="ghost"
267
+ {...props}
268
+ />
269
+ );
270
+ }
271
+
272
+ /* -----------------------------------------------------------------------------
273
+ * Exports
274
+ * -------------------------------------------------------------------------- */
275
+
276
+ export { Calendar, CalendarDayButton };
277
+ export type { CalendarDayButtonProps, CalendarProps };