@comitor/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 (307) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +458 -0
  3. package/dist/chart/chart.d.ts +88 -0
  4. package/dist/chart/chart.js +199 -0
  5. package/dist/chart/chart.js.map +1 -0
  6. package/dist/chart/comitor-chart.d.ts +109 -0
  7. package/dist/chart/comitor-chart.js +189 -0
  8. package/dist/chart/comitor-chart.js.map +1 -0
  9. package/dist/chart/index.d.ts +4 -0
  10. package/dist/chart/index.js +3 -0
  11. package/dist/chart/index.js.map +1 -0
  12. package/dist/components/composite/avatar-group.d.ts +33 -0
  13. package/dist/components/composite/avatar-group.js +86 -0
  14. package/dist/components/composite/avatar-group.js.map +1 -0
  15. package/dist/components/composite/combobox.d.ts +70 -0
  16. package/dist/components/composite/combobox.js +291 -0
  17. package/dist/components/composite/combobox.js.map +1 -0
  18. package/dist/components/composite/command-palette.d.ts +56 -0
  19. package/dist/components/composite/command-palette.js +131 -0
  20. package/dist/components/composite/command-palette.js.map +1 -0
  21. package/dist/components/composite/confirm-dialog.d.ts +40 -0
  22. package/dist/components/composite/confirm-dialog.js +96 -0
  23. package/dist/components/composite/confirm-dialog.js.map +1 -0
  24. package/dist/components/composite/copy-button.d.ts +27 -0
  25. package/dist/components/composite/copy-button.js +80 -0
  26. package/dist/components/composite/copy-button.js.map +1 -0
  27. package/dist/components/composite/data-table.d.ts +136 -0
  28. package/dist/components/composite/data-table.js +300 -0
  29. package/dist/components/composite/data-table.js.map +1 -0
  30. package/dist/components/composite/date-picker.d.ts +77 -0
  31. package/dist/components/composite/date-picker.js +268 -0
  32. package/dist/components/composite/date-picker.js.map +1 -0
  33. package/dist/components/composite/empty-state.d.ts +38 -0
  34. package/dist/components/composite/empty-state.js +35 -0
  35. package/dist/components/composite/empty-state.js.map +1 -0
  36. package/dist/components/composite/filter-chips.d.ts +39 -0
  37. package/dist/components/composite/filter-chips.js +79 -0
  38. package/dist/components/composite/filter-chips.js.map +1 -0
  39. package/dist/components/composite/form-field.d.ts +58 -0
  40. package/dist/components/composite/form-field.js +81 -0
  41. package/dist/components/composite/form-field.js.map +1 -0
  42. package/dist/components/composite/form-section.d.ts +33 -0
  43. package/dist/components/composite/form-section.js +85 -0
  44. package/dist/components/composite/form-section.js.map +1 -0
  45. package/dist/components/composite/inline-edit.d.ts +38 -0
  46. package/dist/components/composite/inline-edit.js +165 -0
  47. package/dist/components/composite/inline-edit.js.map +1 -0
  48. package/dist/components/composite/keyboard-hint.d.ts +31 -0
  49. package/dist/components/composite/keyboard-hint.js +72 -0
  50. package/dist/components/composite/keyboard-hint.js.map +1 -0
  51. package/dist/components/composite/letter-avatar.d.ts +47 -0
  52. package/dist/components/composite/letter-avatar.js +66 -0
  53. package/dist/components/composite/letter-avatar.js.map +1 -0
  54. package/dist/components/composite/page-container.d.ts +25 -0
  55. package/dist/components/composite/page-container.js +23 -0
  56. package/dist/components/composite/page-container.js.map +1 -0
  57. package/dist/components/composite/page-header.d.ts +49 -0
  58. package/dist/components/composite/page-header.js +75 -0
  59. package/dist/components/composite/page-header.js.map +1 -0
  60. package/dist/components/composite/relative-time.d.ts +28 -0
  61. package/dist/components/composite/relative-time.js +44 -0
  62. package/dist/components/composite/relative-time.js.map +1 -0
  63. package/dist/components/composite/search-filter-bar.d.ts +38 -0
  64. package/dist/components/composite/search-filter-bar.js +135 -0
  65. package/dist/components/composite/search-filter-bar.js.map +1 -0
  66. package/dist/components/composite/stat-card.d.ts +48 -0
  67. package/dist/components/composite/stat-card.js +76 -0
  68. package/dist/components/composite/stat-card.js.map +1 -0
  69. package/dist/components/composite/status-config.d.ts +85 -0
  70. package/dist/components/composite/status-config.js +41 -0
  71. package/dist/components/composite/status-config.js.map +1 -0
  72. package/dist/components/composite/status-pill.d.ts +26 -0
  73. package/dist/components/composite/status-pill.js +59 -0
  74. package/dist/components/composite/status-pill.js.map +1 -0
  75. package/dist/components/composite/table-pagination.d.ts +31 -0
  76. package/dist/components/composite/table-pagination.js +103 -0
  77. package/dist/components/composite/table-pagination.js.map +1 -0
  78. package/dist/components/composite/text-utils.d.ts +38 -0
  79. package/dist/components/composite/text-utils.js +40 -0
  80. package/dist/components/composite/text-utils.js.map +1 -0
  81. package/dist/components/composite/toast.d.ts +56 -0
  82. package/dist/components/composite/toast.js +63 -0
  83. package/dist/components/composite/toast.js.map +1 -0
  84. package/dist/components/ui/accordion.d.ts +17 -0
  85. package/dist/components/ui/accordion.js +53 -0
  86. package/dist/components/ui/accordion.js.map +1 -0
  87. package/dist/components/ui/alert-dialog.d.ts +34 -0
  88. package/dist/components/ui/alert-dialog.js +103 -0
  89. package/dist/components/ui/alert-dialog.js.map +1 -0
  90. package/dist/components/ui/alert.d.ts +16 -0
  91. package/dist/components/ui/alert.js +50 -0
  92. package/dist/components/ui/alert.js.map +1 -0
  93. package/dist/components/ui/aspect-ratio.d.ts +7 -0
  94. package/dist/components/ui/aspect-ratio.js +10 -0
  95. package/dist/components/ui/aspect-ratio.js.map +1 -0
  96. package/dist/components/ui/avatar.d.ts +11 -0
  97. package/dist/components/ui/avatar.js +33 -0
  98. package/dist/components/ui/avatar.js.map +1 -0
  99. package/dist/components/ui/badge.d.ts +15 -0
  100. package/dist/components/ui/badge.js +37 -0
  101. package/dist/components/ui/badge.js.map +1 -0
  102. package/dist/components/ui/breadcrumb.d.ts +30 -0
  103. package/dist/components/ui/breadcrumb.js +89 -0
  104. package/dist/components/ui/breadcrumb.js.map +1 -0
  105. package/dist/components/ui/button-group.d.ts +21 -0
  106. package/dist/components/ui/button-group.js +62 -0
  107. package/dist/components/ui/button-group.js.map +1 -0
  108. package/dist/components/ui/button.d.ts +21 -0
  109. package/dist/components/ui/button.js +70 -0
  110. package/dist/components/ui/button.js.map +1 -0
  111. package/dist/components/ui/calendar.d.ts +26 -0
  112. package/dist/components/ui/calendar.js +148 -0
  113. package/dist/components/ui/calendar.js.map +1 -0
  114. package/dist/components/ui/card.d.ts +33 -0
  115. package/dist/components/ui/card.js +70 -0
  116. package/dist/components/ui/card.js.map +1 -0
  117. package/dist/components/ui/carousel.d.ts +46 -0
  118. package/dist/components/ui/carousel.js +173 -0
  119. package/dist/components/ui/carousel.js.map +1 -0
  120. package/dist/components/ui/checkbox.d.ts +17 -0
  121. package/dist/components/ui/checkbox.js +67 -0
  122. package/dist/components/ui/checkbox.js.map +1 -0
  123. package/dist/components/ui/collapsible.d.ts +17 -0
  124. package/dist/components/ui/collapsible.js +18 -0
  125. package/dist/components/ui/collapsible.js.map +1 -0
  126. package/dist/components/ui/command.d.ts +41 -0
  127. package/dist/components/ui/command.js +122 -0
  128. package/dist/components/ui/command.js.map +1 -0
  129. package/dist/components/ui/context-menu.d.ts +51 -0
  130. package/dist/components/ui/context-menu.js +166 -0
  131. package/dist/components/ui/context-menu.js.map +1 -0
  132. package/dist/components/ui/dialog.d.ts +48 -0
  133. package/dist/components/ui/dialog.js +131 -0
  134. package/dist/components/ui/dialog.js.map +1 -0
  135. package/dist/components/ui/drawer.d.ts +32 -0
  136. package/dist/components/ui/drawer.js +102 -0
  137. package/dist/components/ui/drawer.js.map +1 -0
  138. package/dist/components/ui/dropdown-menu.d.ts +52 -0
  139. package/dist/components/ui/dropdown-menu.js +167 -0
  140. package/dist/components/ui/dropdown-menu.js.map +1 -0
  141. package/dist/components/ui/empty.d.ts +22 -0
  142. package/dist/components/ui/empty.js +87 -0
  143. package/dist/components/ui/empty.js.map +1 -0
  144. package/dist/components/ui/field.d.ts +46 -0
  145. package/dist/components/ui/field.js +197 -0
  146. package/dist/components/ui/field.js.map +1 -0
  147. package/dist/components/ui/form.d.ts +50 -0
  148. package/dist/components/ui/form.js +100 -0
  149. package/dist/components/ui/form.js.map +1 -0
  150. package/dist/components/ui/hover-card.d.ts +17 -0
  151. package/dist/components/ui/hover-card.js +31 -0
  152. package/dist/components/ui/hover-card.js.map +1 -0
  153. package/dist/components/ui/input-group.d.ts +26 -0
  154. package/dist/components/ui/input-group.js +148 -0
  155. package/dist/components/ui/input-group.js.map +1 -0
  156. package/dist/components/ui/input-otp.d.ts +23 -0
  157. package/dist/components/ui/input-otp.js +54 -0
  158. package/dist/components/ui/input-otp.js.map +1 -0
  159. package/dist/components/ui/input.d.ts +21 -0
  160. package/dist/components/ui/input.js +62 -0
  161. package/dist/components/ui/input.js.map +1 -0
  162. package/dist/components/ui/item.d.ts +39 -0
  163. package/dist/components/ui/item.js +142 -0
  164. package/dist/components/ui/item.js.map +1 -0
  165. package/dist/components/ui/kbd.d.ts +8 -0
  166. package/dist/components/ui/kbd.js +25 -0
  167. package/dist/components/ui/kbd.js.map +1 -0
  168. package/dist/components/ui/label.d.ts +7 -0
  169. package/dist/components/ui/label.js +21 -0
  170. package/dist/components/ui/label.js.map +1 -0
  171. package/dist/components/ui/menubar.d.ts +51 -0
  172. package/dist/components/ui/menubar.js +196 -0
  173. package/dist/components/ui/menubar.js.map +1 -0
  174. package/dist/components/ui/navigation-menu.d.ts +39 -0
  175. package/dist/components/ui/navigation-menu.js +123 -0
  176. package/dist/components/ui/navigation-menu.js.map +1 -0
  177. package/dist/components/ui/pagination.d.ts +40 -0
  178. package/dist/components/ui/pagination.js +95 -0
  179. package/dist/components/ui/pagination.js.map +1 -0
  180. package/dist/components/ui/popover.d.ts +19 -0
  181. package/dist/components/ui/popover.js +35 -0
  182. package/dist/components/ui/popover.js.map +1 -0
  183. package/dist/components/ui/progress.d.ts +12 -0
  184. package/dist/components/ui/progress.js +27 -0
  185. package/dist/components/ui/progress.js.map +1 -0
  186. package/dist/components/ui/radio-group.d.ts +9 -0
  187. package/dist/components/ui/radio-group.js +34 -0
  188. package/dist/components/ui/radio-group.js.map +1 -0
  189. package/dist/components/ui/resizable.d.ts +19 -0
  190. package/dist/components/ui/resizable.js +38 -0
  191. package/dist/components/ui/resizable.js.map +1 -0
  192. package/dist/components/ui/scroll-area.d.ts +13 -0
  193. package/dist/components/ui/scroll-area.js +46 -0
  194. package/dist/components/ui/scroll-area.js.map +1 -0
  195. package/dist/components/ui/select.d.ts +33 -0
  196. package/dist/components/ui/select.js +133 -0
  197. package/dist/components/ui/select.js.map +1 -0
  198. package/dist/components/ui/separator.d.ts +7 -0
  199. package/dist/components/ui/separator.js +23 -0
  200. package/dist/components/ui/separator.js.map +1 -0
  201. package/dist/components/ui/sheet.d.ts +38 -0
  202. package/dist/components/ui/sheet.js +96 -0
  203. package/dist/components/ui/sheet.js.map +1 -0
  204. package/dist/components/ui/skeleton.d.ts +6 -0
  205. package/dist/components/ui/skeleton.js +9 -0
  206. package/dist/components/ui/skeleton.js.map +1 -0
  207. package/dist/components/ui/slider.d.ts +12 -0
  208. package/dist/components/ui/slider.js +54 -0
  209. package/dist/components/ui/slider.js.map +1 -0
  210. package/dist/components/ui/sonner.d.ts +9 -0
  211. package/dist/components/ui/sonner.js +25 -0
  212. package/dist/components/ui/sonner.js.map +1 -0
  213. package/dist/components/ui/spinner.d.ts +6 -0
  214. package/dist/components/ui/spinner.js +10 -0
  215. package/dist/components/ui/spinner.js.map +1 -0
  216. package/dist/components/ui/switch.d.ts +14 -0
  217. package/dist/components/ui/switch.js +65 -0
  218. package/dist/components/ui/switch.js.map +1 -0
  219. package/dist/components/ui/table.d.ts +30 -0
  220. package/dist/components/ui/table.js +87 -0
  221. package/dist/components/ui/table.js.map +1 -0
  222. package/dist/components/ui/tabs.d.ts +35 -0
  223. package/dist/components/ui/tabs.js +54 -0
  224. package/dist/components/ui/tabs.js.map +1 -0
  225. package/dist/components/ui/textarea.d.ts +6 -0
  226. package/dist/components/ui/textarea.js +19 -0
  227. package/dist/components/ui/textarea.js.map +1 -0
  228. package/dist/components/ui/toggle-group.d.ts +18 -0
  229. package/dist/components/ui/toggle-group.js +52 -0
  230. package/dist/components/ui/toggle-group.js.map +1 -0
  231. package/dist/components/ui/toggle.d.ts +15 -0
  232. package/dist/components/ui/toggle.js +33 -0
  233. package/dist/components/ui/toggle.js.map +1 -0
  234. package/dist/components/ui/tooltip.d.ts +21 -0
  235. package/dist/components/ui/tooltip.js +38 -0
  236. package/dist/components/ui/tooltip.js.map +1 -0
  237. package/dist/form.d.ts +5 -0
  238. package/dist/form.js +2 -0
  239. package/dist/form.js.map +1 -0
  240. package/dist/index.d.ts +111 -0
  241. package/dist/index.js +76 -0
  242. package/dist/index.js.map +1 -0
  243. package/dist/lib/cn.d.ts +16 -0
  244. package/dist/lib/cn.js +9 -0
  245. package/dist/lib/cn.js.map +1 -0
  246. package/dist/shell/app-header.d.ts +41 -0
  247. package/dist/shell/app-header.js +136 -0
  248. package/dist/shell/app-header.js.map +1 -0
  249. package/dist/shell/app-launcher.d.ts +33 -0
  250. package/dist/shell/app-launcher.js +189 -0
  251. package/dist/shell/app-launcher.js.map +1 -0
  252. package/dist/shell/app-shell.d.ts +44 -0
  253. package/dist/shell/app-shell.js +99 -0
  254. package/dist/shell/app-shell.js.map +1 -0
  255. package/dist/shell/comitor-lockup.d.ts +33 -0
  256. package/dist/shell/comitor-lockup.js +112 -0
  257. package/dist/shell/comitor-lockup.js.map +1 -0
  258. package/dist/shell/comitor-logo.d.ts +28 -0
  259. package/dist/shell/comitor-logo.js +92 -0
  260. package/dist/shell/comitor-logo.js.map +1 -0
  261. package/dist/shell/index.d.ts +24 -0
  262. package/dist/shell/index.js +23 -0
  263. package/dist/shell/index.js.map +1 -0
  264. package/dist/shell/mobile-menu.d.ts +26 -0
  265. package/dist/shell/mobile-menu.js +56 -0
  266. package/dist/shell/mobile-menu.js.map +1 -0
  267. package/dist/shell/notifications-button.d.ts +22 -0
  268. package/dist/shell/notifications-button.js +39 -0
  269. package/dist/shell/notifications-button.js.map +1 -0
  270. package/dist/shell/shell-context.d.ts +91 -0
  271. package/dist/shell/shell-context.js +233 -0
  272. package/dist/shell/shell-context.js.map +1 -0
  273. package/dist/shell/shell-link.d.ts +19 -0
  274. package/dist/shell/shell-link.js +18 -0
  275. package/dist/shell/shell-link.js.map +1 -0
  276. package/dist/shell/sidebar-group.d.ts +21 -0
  277. package/dist/shell/sidebar-group.js +43 -0
  278. package/dist/shell/sidebar-group.js.map +1 -0
  279. package/dist/shell/sidebar-menu-item.d.ts +27 -0
  280. package/dist/shell/sidebar-menu-item.js +152 -0
  281. package/dist/shell/sidebar-menu-item.js.map +1 -0
  282. package/dist/shell/sidebar.d.ts +26 -0
  283. package/dist/shell/sidebar.js +92 -0
  284. package/dist/shell/sidebar.js.map +1 -0
  285. package/dist/shell/theme-provider.d.ts +18 -0
  286. package/dist/shell/theme-provider.js +29 -0
  287. package/dist/shell/theme-provider.js.map +1 -0
  288. package/dist/shell/theme-toggle.d.ts +28 -0
  289. package/dist/shell/theme-toggle.js +67 -0
  290. package/dist/shell/theme-toggle.js.map +1 -0
  291. package/dist/shell/types.d.ts +168 -0
  292. package/dist/shell/types.js +38 -0
  293. package/dist/shell/types.js.map +1 -0
  294. package/dist/shell/user-menu.d.ts +42 -0
  295. package/dist/shell/user-menu.js +132 -0
  296. package/dist/shell/user-menu.js.map +1 -0
  297. package/dist/shell/utils.d.ts +62 -0
  298. package/dist/shell/utils.js +73 -0
  299. package/dist/shell/utils.js.map +1 -0
  300. package/dist/shell/workspace-switcher.d.ts +24 -0
  301. package/dist/shell/workspace-switcher.js +219 -0
  302. package/dist/shell/workspace-switcher.js.map +1 -0
  303. package/dist/tokens.d.ts +173 -0
  304. package/dist/tokens.js +161 -0
  305. package/dist/tokens.js.map +1 -0
  306. package/package.json +151 -0
  307. package/styles.css +357 -0
@@ -0,0 +1,89 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { ChevronRight, MoreHorizontal } from "lucide-react";
4
+ import { cn } from "../../lib/cn.js";
5
+ function Breadcrumb({ ...props }) {
6
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "\u0110\u01B0\u1EDDng d\u1EABn ph\xE2n c\u1EA5p", "data-slot": "breadcrumb", ...props });
7
+ }
8
+ function BreadcrumbList({ className, ...props }) {
9
+ return /* @__PURE__ */ jsx(
10
+ "ol",
11
+ {
12
+ "data-slot": "breadcrumb-list",
13
+ className: cn(
14
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
15
+ className
16
+ ),
17
+ ...props
18
+ }
19
+ );
20
+ }
21
+ function BreadcrumbItem({ className, ...props }) {
22
+ return /* @__PURE__ */ jsx("li", { "data-slot": "breadcrumb-item", className: cn("inline-flex items-center gap-1.5", className), ...props });
23
+ }
24
+ function BreadcrumbLink({ asChild, className, ...props }) {
25
+ const Comp = asChild ? Slot : "a";
26
+ return /* @__PURE__ */ jsx(
27
+ Comp,
28
+ {
29
+ "data-slot": "breadcrumb-link",
30
+ className: cn("hover:text-foreground transition-colors duration-150 ease-out", className),
31
+ ...props
32
+ }
33
+ );
34
+ }
35
+ function BreadcrumbPage({ className, ...props }) {
36
+ return (
37
+ // biome-ignore lint/a11y/useFocusableInteractive: giữ nguyên markup shadcn — mục hiện tại cố tình KHÔNG focus được (aria-disabled), chỉ mượn role="link" để trình đọc màn hình đọc đúng ngữ cảnh
38
+ /* @__PURE__ */ jsx(
39
+ "span",
40
+ {
41
+ "data-slot": "breadcrumb-page",
42
+ role: "link",
43
+ "aria-disabled": "true",
44
+ "aria-current": "page",
45
+ className: cn("text-foreground font-normal", className),
46
+ ...props
47
+ }
48
+ )
49
+ );
50
+ }
51
+ function BreadcrumbSeparator({ children, className, ...props }) {
52
+ return /* @__PURE__ */ jsx(
53
+ "li",
54
+ {
55
+ "data-slot": "breadcrumb-separator",
56
+ role: "presentation",
57
+ "aria-hidden": "true",
58
+ className: cn("[&>svg]:size-3.5", className),
59
+ ...props,
60
+ children: children ?? /* @__PURE__ */ jsx(ChevronRight, {})
61
+ }
62
+ );
63
+ }
64
+ function BreadcrumbEllipsis({ className, srLabel = "Th\xEAm m\u1EE5c", ...props }) {
65
+ return /* @__PURE__ */ jsxs(
66
+ "span",
67
+ {
68
+ "data-slot": "breadcrumb-ellipsis",
69
+ role: "presentation",
70
+ "aria-hidden": "true",
71
+ className: cn("flex size-9 items-center justify-center", className),
72
+ ...props,
73
+ children: [
74
+ /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" }),
75
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: srLabel })
76
+ ]
77
+ }
78
+ );
79
+ }
80
+ export {
81
+ Breadcrumb,
82
+ BreadcrumbEllipsis,
83
+ BreadcrumbItem,
84
+ BreadcrumbLink,
85
+ BreadcrumbList,
86
+ BreadcrumbPage,
87
+ BreadcrumbSeparator
88
+ };
89
+ //# sourceMappingURL=breadcrumb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/breadcrumb.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { ChevronRight, MoreHorizontal } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\n\n/**\n * Breadcrumb — primitive tĩnh (không \"use client\", dùng được trong RSC).\n * Chuỗi hiển thị mặc định là tiếng Việt và override được qua props tương ứng.\n *\n * Điều hướng: bọc `next/link` bằng `<BreadcrumbLink asChild><Link …/></BreadcrumbLink>`\n * để primitive không phụ thuộc `next/*`.\n */\n\nexport type BreadcrumbProps = React.ComponentProps<\"nav\">;\nexport type BreadcrumbListProps = React.ComponentProps<\"ol\">;\nexport type BreadcrumbItemProps = React.ComponentProps<\"li\">;\nexport type BreadcrumbLinkProps = React.ComponentProps<\"a\"> & { asChild?: boolean };\nexport type BreadcrumbPageProps = React.ComponentProps<\"span\">;\nexport type BreadcrumbSeparatorProps = React.ComponentProps<\"li\">;\nexport type BreadcrumbEllipsisProps = React.ComponentProps<\"span\"> & {\n /** Nhãn chỉ dành cho trình đọc màn hình. */\n srLabel?: string;\n};\n\nfunction Breadcrumb({ ...props }: BreadcrumbProps) {\n return <nav aria-label=\"Đường dẫn phân cấp\" data-slot=\"breadcrumb\" {...props} />;\n}\n\nfunction BreadcrumbList({ className, ...props }: BreadcrumbListProps) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\n \"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbItem({ className, ...props }: BreadcrumbItemProps) {\n return <li data-slot=\"breadcrumb-item\" className={cn(\"inline-flex items-center gap-1.5\", className)} {...props} />;\n}\n\nfunction BreadcrumbLink({ asChild, className, ...props }: BreadcrumbLinkProps) {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn(\"hover:text-foreground transition-colors duration-150 ease-out\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbPage({ className, ...props }: BreadcrumbPageProps) {\n return (\n // biome-ignore lint/a11y/useFocusableInteractive: giữ nguyên markup shadcn — mục hiện tại cố tình KHÔNG focus được (aria-disabled), chỉ mượn role=\"link\" để trình đọc màn hình đọc đúng ngữ cảnh\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn(\"text-foreground font-normal\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbSeparator({ children, className, ...props }: BreadcrumbSeparatorProps) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"[&>svg]:size-3.5\", className)}\n {...props}\n >\n {children ?? <ChevronRight />}\n </li>\n );\n}\n\nfunction BreadcrumbEllipsis({ className, srLabel = \"Thêm mục\", ...props }: BreadcrumbEllipsisProps) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"flex size-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">{srLabel}</span>\n </span>\n );\n}\n\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator\n};\n"],"mappings":"AAyBS,cA8DL,YA9DK;AAzBT,SAAS,YAAY;AACrB,SAAS,cAAc,sBAAsB;AAE7C,SAAS,UAAU;AAqBnB,SAAS,WAAW,EAAE,GAAG,MAAM,GAAoB;AACjD,SAAO,oBAAC,SAAI,cAAW,kDAAqB,aAAU,cAAc,GAAG,OAAO;AAChF;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,MAAM,GAAwB;AACpE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,MAAM,GAAwB;AACpE,SAAO,oBAAC,QAAG,aAAU,mBAAkB,WAAW,GAAG,oCAAoC,SAAS,GAAI,GAAG,OAAO;AAClH;AAEA,SAAS,eAAe,EAAE,SAAS,WAAW,GAAG,MAAM,GAAwB;AAC7E,QAAM,OAAO,UAAU,OAAO;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,iEAAiE,SAAS;AAAA,MACvF,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,MAAM,GAAwB;AACpE;AAAA;AAAA,IAEE;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,MAAK;AAAA,QACL,iBAAc;AAAA,QACd,gBAAa;AAAA,QACb,WAAW,GAAG,+BAA+B,SAAS;AAAA,QACrD,GAAG;AAAA;AAAA,IACN;AAAA;AAEJ;AAEA,SAAS,oBAAoB,EAAE,UAAU,WAAW,GAAG,MAAM,GAA6B;AACxF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,eAAY;AAAA,MACZ,WAAW,GAAG,oBAAoB,SAAS;AAAA,MAC1C,GAAG;AAAA,MAEH,sBAAY,oBAAC,gBAAa;AAAA;AAAA,EAC7B;AAEJ;AAEA,SAAS,mBAAmB,EAAE,WAAW,UAAU,oBAAY,GAAG,MAAM,GAA4B;AAClG,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,eAAY;AAAA,MACZ,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA,MAEJ;AAAA,4BAAC,kBAAe,WAAU,UAAS;AAAA,QACnC,oBAAC,UAAK,WAAU,WAAW,mBAAQ;AAAA;AAAA;AAAA,EACrC;AAEJ;","names":[]}
@@ -0,0 +1,21 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import { VariantProps } from 'class-variance-authority';
3
+ import * as React from 'react';
4
+ import { SeparatorProps } from './separator.js';
5
+ import '@radix-ui/react-separator';
6
+
7
+ declare const buttonGroupVariants: (props?: ({
8
+ orientation?: "horizontal" | "vertical" | null | undefined;
9
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
10
+ interface ButtonGroupProps extends React.ComponentProps<"div">, VariantProps<typeof buttonGroupVariants> {
11
+ }
12
+ interface ButtonGroupTextProps extends React.ComponentProps<"div"> {
13
+ /** Render ra chính phần tử con (Radix Slot) thay vì thẻ <div>. */
14
+ asChild?: boolean;
15
+ }
16
+ type ButtonGroupSeparatorProps = SeparatorProps;
17
+ declare function ButtonGroup({ className, orientation, ...props }: ButtonGroupProps): React.JSX.Element;
18
+ declare function ButtonGroupText({ className, asChild, ...props }: ButtonGroupTextProps): React.JSX.Element;
19
+ declare function ButtonGroupSeparator({ className, orientation, ...props }: ButtonGroupSeparatorProps): React.JSX.Element;
20
+
21
+ export { ButtonGroup, type ButtonGroupProps, ButtonGroupSeparator, type ButtonGroupSeparatorProps, ButtonGroupText, type ButtonGroupTextProps, buttonGroupVariants };
@@ -0,0 +1,62 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "../../lib/cn.js";
5
+ import { Separator } from "./separator.js";
6
+ const buttonGroupVariants = cva(
7
+ "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
8
+ {
9
+ variants: {
10
+ orientation: {
11
+ horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
12
+ vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ orientation: "horizontal"
17
+ }
18
+ }
19
+ );
20
+ function ButtonGroup({ className, orientation, ...props }) {
21
+ return /* @__PURE__ */ jsx(
22
+ "div",
23
+ {
24
+ role: "group",
25
+ "data-slot": "button-group",
26
+ "data-orientation": orientation,
27
+ className: cn(buttonGroupVariants({ orientation }), className),
28
+ ...props
29
+ }
30
+ );
31
+ }
32
+ function ButtonGroupText({ className, asChild = false, ...props }) {
33
+ const Comp = asChild ? Slot : "div";
34
+ return /* @__PURE__ */ jsx(
35
+ Comp,
36
+ {
37
+ className: cn(
38
+ "bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
39
+ className
40
+ ),
41
+ ...props
42
+ }
43
+ );
44
+ }
45
+ function ButtonGroupSeparator({ className, orientation = "vertical", ...props }) {
46
+ return /* @__PURE__ */ jsx(
47
+ Separator,
48
+ {
49
+ "data-slot": "button-group-separator",
50
+ orientation,
51
+ className: cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className),
52
+ ...props
53
+ }
54
+ );
55
+ }
56
+ export {
57
+ ButtonGroup,
58
+ ButtonGroupSeparator,
59
+ ButtonGroupText,
60
+ buttonGroupVariants
61
+ };
62
+ //# sourceMappingURL=button-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/button-group.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Separator, type SeparatorProps } from \"./separator.js\";\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\"\n }\n },\n defaultVariants: {\n orientation: \"horizontal\"\n }\n }\n);\n\nexport interface ButtonGroupProps extends React.ComponentProps<\"div\">, VariantProps<typeof buttonGroupVariants> {}\n\nexport interface ButtonGroupTextProps extends React.ComponentProps<\"div\"> {\n /** Render ra chính phần tử con (Radix Slot) thay vì thẻ <div>. */\n asChild?: boolean;\n}\n\nexport type ButtonGroupSeparatorProps = SeparatorProps;\n\nfunction ButtonGroup({ className, orientation, ...props }: ButtonGroupProps) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n );\n}\n\nfunction ButtonGroupText({ className, asChild = false, ...props }: ButtonGroupTextProps) {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ButtonGroupSeparator({ className, orientation = \"vertical\", ...props }: ButtonGroupSeparatorProps) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\", className)}\n {...props}\n />\n );\n}\n\nexport { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };\n"],"mappings":"AAkCI;AAlCJ,SAAS,YAAY;AACrB,SAAS,WAA8B;AAEvC,SAAS,UAAU;AACnB,SAAS,iBAAsC;AAE/C,MAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,aAAa;AAAA,QACX,YACE;AAAA,QACF,UACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,aAAa;AAAA,IACf;AAAA,EACF;AACF;AAWA,SAAS,YAAY,EAAE,WAAW,aAAa,GAAG,MAAM,GAAqB;AAC3E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,oBAAkB;AAAA,MAClB,WAAW,GAAG,oBAAoB,EAAE,YAAY,CAAC,GAAG,SAAS;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,gBAAgB,EAAE,WAAW,UAAU,OAAO,GAAG,MAAM,GAAyB;AACvF,QAAM,OAAO,UAAU,OAAO;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,qBAAqB,EAAE,WAAW,cAAc,YAAY,GAAG,MAAM,GAA8B;AAC1G,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,WAAW,GAAG,0EAA0E,SAAS;AAAA,MAChG,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -0,0 +1,21 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import { VariantProps } from 'class-variance-authority';
3
+ import * as React from 'react';
4
+
5
+ declare const buttonVariants: (props?: ({
6
+ variant?: "link" | "default" | "primary" | "secondary" | "outline" | "destructive" | "ghost" | null | undefined;
7
+ size?: "sm" | "md" | "lg" | "default" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
8
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
9
+ interface ButtonProps extends React.ComponentProps<"button">, VariantProps<typeof buttonVariants> {
10
+ /** Render ra chính phần tử con (Radix Slot) thay vì thẻ <button>. */
11
+ asChild?: boolean;
12
+ /** Hiện spinner và khoá nút. */
13
+ loading?: boolean;
14
+ /** Icon đặt trước nội dung; bị spinner thay thế khi `loading`. */
15
+ leftIcon?: React.ReactNode;
16
+ /** Icon đặt sau nội dung; ẩn khi `loading`. */
17
+ rightIcon?: React.ReactNode;
18
+ }
19
+ declare function Button({ className, variant, size, asChild, loading, leftIcon, rightIcon, disabled, children, ...props }: ButtonProps): React.JSX.Element;
20
+
21
+ export { Button, type ButtonProps, buttonVariants };
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import { cva } from "class-variance-authority";
5
+ import { Loader2 } from "lucide-react";
6
+ import { cn } from "../../lib/cn.js";
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center font-medium select-none whitespace-nowrap transition-colors duration-150 ease-out focus-visible:outline-2 focus-visible:outline-ring focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-primary text-primary-foreground hover:bg-[color:color-mix(in_srgb,var(--primary),var(--ink)_15%)] border border-transparent shadow-control",
13
+ primary: "bg-primary text-primary-foreground hover:bg-[color:color-mix(in_srgb,var(--primary),var(--ink)_15%)] border border-transparent shadow-control",
14
+ secondary: "bg-secondary text-secondary-foreground hover:bg-warm dark:hover:bg-muted border border-border",
15
+ outline: "bg-transparent text-foreground border border-border hover:border-gold-300 hover:bg-gold-50 dark:hover:bg-gold-500/10",
16
+ ghost: "bg-transparent text-foreground hover:bg-muted border border-transparent",
17
+ destructive: "bg-destructive text-destructive-foreground hover:bg-[color:color-mix(in_srgb,var(--destructive),var(--ink)_15%)] border border-transparent",
18
+ link: "bg-transparent text-gold-500 hover:text-gold-600 dark:text-gold-200 dark:hover:text-gold-100 underline-offset-4 hover:underline border border-transparent p-0 h-auto"
19
+ },
20
+ size: {
21
+ default: "h-9 px-4 text-sm rounded-md gap-2",
22
+ md: "h-9 px-4 text-sm rounded-md gap-2",
23
+ sm: "h-8 px-3 text-xs rounded-md gap-1.5",
24
+ lg: "h-11 px-6 text-base rounded-md gap-2",
25
+ icon: "h-9 w-9 rounded-md",
26
+ "icon-sm": "h-8 w-8 rounded-md",
27
+ "icon-lg": "h-11 w-11 rounded-md"
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ variant: "default",
32
+ size: "default"
33
+ }
34
+ }
35
+ );
36
+ function Button({
37
+ className,
38
+ variant,
39
+ size,
40
+ asChild = false,
41
+ loading = false,
42
+ leftIcon,
43
+ rightIcon,
44
+ disabled,
45
+ children,
46
+ ...props
47
+ }) {
48
+ if (asChild) {
49
+ return /* @__PURE__ */ jsx(Slot, { "data-slot": "button", className: cn(buttonVariants({ variant, size, className })), ...props, children });
50
+ }
51
+ return /* @__PURE__ */ jsxs(
52
+ "button",
53
+ {
54
+ "data-slot": "button",
55
+ disabled: disabled || loading,
56
+ className: cn(buttonVariants({ variant, size, className })),
57
+ ...props,
58
+ children: [
59
+ loading ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 shrink-0 animate-spin", "aria-hidden": true }) : leftIcon ? /* @__PURE__ */ jsx("span", { className: "shrink-0", children: leftIcon }) : null,
60
+ children,
61
+ !loading && rightIcon ? /* @__PURE__ */ jsx("span", { className: "shrink-0", children: rightIcon }) : null
62
+ ]
63
+ }
64
+ );
65
+ }
66
+ export {
67
+ Button,
68
+ buttonVariants
69
+ };
70
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader2 } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\n\n/*\n * Style port từ comitor-ds để giao diện khớp bản v0.\n * API giữ tương thích shadcn (cva + asChild + data-slot); `primary` là alias của `default`\n * — đã là API công khai trong docs comitor-ds nên không bỏ.\n *\n * ─ VÌ SAO NỀN NÚT LÀ TOKEN SEMANTIC, KHÔNG PHẢI THANG BRAND THÔ ─\n *\n * 1. `default`/`primary` trước dùng `bg-gold-300 text-ink` — cùng giá trị ở cả hai theme,\n * nên bảng màu dark của chính package (`.dark { --primary: #F5D060 }`) không bao giờ được\n * áp dụng, và app nào set lại `--primary` cho sản phẩm của mình cũng không đổi được nút.\n * Nay dùng `bg-primary text-primary-foreground`: light 10,19:1 (không đổi), dark 12,67:1\n * (trước 10,19:1) — đều vượt AA.\n *\n * 2. `destructive` trước dùng `bg-red text-white`. `--red` là màu phụ được NÂNG SÁNG ở dark\n * (#F87171) để làm CHỮ trên nền tối, dùng làm NỀN nút thì chữ trắng chỉ còn 2,77:1 ✗.\n * `--destructive` cố ý ghim #D64545 ở cả hai theme đúng cho việc này → 4,38:1 ở cả hai.\n * CÒN THIẾU 0,12 so với AA 4,5:1: đó là giá trị của token, phải sửa ở styles.css\n * (#D64545 → khoảng #C93B3B là đạt 5:1), không sửa được trong component mà không chôn hex.\n *\n * ─ VÌ SAO HOVER TRỘN `--ink` THAY VÌ `/90` ─\n *\n * `bg-primary/90` là \"nhạt dần về phía nền\" nên ở light mode nút SÁNG lên khi rê chuột (ngược\n * với bản v0 gold-300 → gold-400) và với destructive thì tương phản chữ trắng tụt còn 3,81:1 ✗.\n * Trộn 15% `--ink` thì tối đi ở CẢ hai theme, giữ đúng ngữ nghĩa \"nhấn xuống\" và tương phản chỉ\n * tăng: destructive 5,56:1 ✓, primary 7,58:1 (light) / 9,33:1 (dark) ✓.\n *\n * ─ `link` ─\n * `text-gold-400` (#B88A00) trên nền trắng chỉ 3,15:1 ✗ — chữ link buộc phải đạt 4,5:1.\n * Đổi sang bậc tối/sáng theo theme: gold-500 6,51:1 (light) và gold-200 12,67:1 (dark).\n * Vẫn là thang gold vì --primary ở light (#E8B824) trên nền trắng chỉ 1,86:1, không dùng\n * làm chữ được; xem docs/quyet-dinh-tich-hop.md.\n */\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center font-medium select-none whitespace-nowrap transition-colors duration-150 ease-out focus-visible:outline-2 focus-visible:outline-ring focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground hover:bg-[color:color-mix(in_srgb,var(--primary),var(--ink)_15%)] border border-transparent shadow-control\",\n primary:\n \"bg-primary text-primary-foreground hover:bg-[color:color-mix(in_srgb,var(--primary),var(--ink)_15%)] border border-transparent shadow-control\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-warm dark:hover:bg-muted border border-border\",\n outline:\n \"bg-transparent text-foreground border border-border hover:border-gold-300 hover:bg-gold-50 dark:hover:bg-gold-500/10\",\n ghost: \"bg-transparent text-foreground hover:bg-muted border border-transparent\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-[color:color-mix(in_srgb,var(--destructive),var(--ink)_15%)] border border-transparent\",\n link: \"bg-transparent text-gold-500 hover:text-gold-600 dark:text-gold-200 dark:hover:text-gold-100 underline-offset-4 hover:underline border border-transparent p-0 h-auto\"\n },\n size: {\n default: \"h-9 px-4 text-sm rounded-md gap-2\",\n md: \"h-9 px-4 text-sm rounded-md gap-2\",\n sm: \"h-8 px-3 text-xs rounded-md gap-1.5\",\n lg: \"h-11 px-6 text-base rounded-md gap-2\",\n icon: \"h-9 w-9 rounded-md\",\n \"icon-sm\": \"h-8 w-8 rounded-md\",\n \"icon-lg\": \"h-11 w-11 rounded-md\"\n }\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\"\n }\n }\n);\n\nexport interface ButtonProps extends React.ComponentProps<\"button\">, VariantProps<typeof buttonVariants> {\n /** Render ra chính phần tử con (Radix Slot) thay vì thẻ <button>. */\n asChild?: boolean;\n /** Hiện spinner và khoá nút. */\n loading?: boolean;\n /** Icon đặt trước nội dung; bị spinner thay thế khi `loading`. */\n leftIcon?: React.ReactNode;\n /** Icon đặt sau nội dung; ẩn khi `loading`. */\n rightIcon?: React.ReactNode;\n}\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n loading = false,\n leftIcon,\n rightIcon,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n // Slot chỉ nhận đúng MỘT phần tử con → bỏ qua lớp bọc icon/loading khi asChild.\n if (asChild) {\n return (\n <Slot data-slot=\"button\" className={cn(buttonVariants({ variant, size, className }))} {...props}>\n {children}\n </Slot>\n );\n }\n\n return (\n <button\n data-slot=\"button\"\n disabled={disabled || loading}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n >\n {loading ? (\n <Loader2 className=\"size-3.5 shrink-0 animate-spin\" aria-hidden />\n ) : leftIcon ? (\n <span className=\"shrink-0\">{leftIcon}</span>\n ) : null}\n {children}\n {!loading && rightIcon ? <span className=\"shrink-0\">{rightIcon}</span> : null}\n </button>\n );\n}\n\nexport { Button, buttonVariants };\n"],"mappings":";AAoGM,cAOF,YAPE;AAlGN,SAAS,YAAY;AACrB,SAAS,WAA8B;AACvC,SAAS,eAAe;AAExB,SAAS,UAAU;AAkCnB,MAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,SACE;AAAA,QACF,WAAW;AAAA,QACX,SACE;AAAA,QACF,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAaA,SAAS,OAAO;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAgB;AAEd,MAAI,SAAS;AACX,WACE,oBAAC,QAAK,aAAU,UAAS,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC,GAAI,GAAG,OACvF,UACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,UAAU,YAAY;AAAA,MACtB,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC;AAAA,MACzD,GAAG;AAAA,MAEH;AAAA,kBACC,oBAAC,WAAQ,WAAU,kCAAiC,eAAW,MAAC,IAC9D,WACF,oBAAC,UAAK,WAAU,YAAY,oBAAS,IACnC;AAAA,QACH;AAAA,QACA,CAAC,WAAW,YAAY,oBAAC,UAAK,WAAU,YAAY,qBAAU,IAAU;AAAA;AAAA;AAAA,EAC3E;AAEJ;","names":[]}
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import { DayPicker, DayButton } from 'react-day-picker';
3
+ import { ButtonProps } from './button.js';
4
+ import 'class-variance-authority/types';
5
+ import 'class-variance-authority';
6
+
7
+ /**
8
+ * Calendar (react-day-picker v9) — lịch trần, đã map class sang token Comitor.
9
+ * Bản có ô nhập `dd/MM/yyyy` + preset ("Hôm nay", "7 ngày qua"…) là composite
10
+ * `DatePicker` / `DateRangePicker` ở Tier 2.
11
+ *
12
+ * Ngôn ngữ: truyền `locale={vi}` (date-fns/locale) để đổi tên thứ/tháng.
13
+ *
14
+ * Khác bản comitor-ds: tên tháng rút gọn trong dropdown lấy theo `locale.code`
15
+ * (mặc định `vi-VN`) thay vì `"default"` — `"default"` phụ thuộc locale của môi
16
+ * trường chạy nên server và trình duyệt có thể ra chuỗi khác nhau → hydration mismatch.
17
+ */
18
+ type CalendarProps = React.ComponentProps<typeof DayPicker> & {
19
+ /** Biến thể Button dùng cho nút điều hướng tháng. */
20
+ buttonVariant?: ButtonProps["variant"];
21
+ };
22
+ type CalendarDayButtonProps = React.ComponentProps<typeof DayButton>;
23
+ declare function Calendar({ className, classNames, showOutsideDays, captionLayout, buttonVariant, formatters, components, locale, ...props }: CalendarProps): React.JSX.Element;
24
+ declare function CalendarDayButton({ className, day, modifiers, ...props }: CalendarDayButtonProps): React.JSX.Element;
25
+
26
+ export { Calendar, CalendarDayButton, type CalendarDayButtonProps, type CalendarProps };
@@ -0,0 +1,148 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
4
+ import * as React from "react";
5
+ import { DayPicker, getDefaultClassNames } from "react-day-picker";
6
+ import { cn } from "../../lib/cn.js";
7
+ import { Button, buttonVariants } from "./button.js";
8
+ function Calendar({
9
+ className,
10
+ classNames,
11
+ showOutsideDays = true,
12
+ captionLayout = "label",
13
+ buttonVariant = "ghost",
14
+ formatters,
15
+ components,
16
+ locale,
17
+ ...props
18
+ }) {
19
+ const defaultClassNames = getDefaultClassNames();
20
+ const localeCode = locale?.code ?? "vi-VN";
21
+ return /* @__PURE__ */ jsx(
22
+ DayPicker,
23
+ {
24
+ showOutsideDays,
25
+ locale,
26
+ className: cn(
27
+ "bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
28
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
29
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
30
+ className
31
+ ),
32
+ captionLayout,
33
+ formatters: {
34
+ formatMonthDropdown: (date) => date.toLocaleString(localeCode, { month: "short" }),
35
+ ...formatters
36
+ },
37
+ classNames: {
38
+ root: cn("w-fit", defaultClassNames.root),
39
+ months: cn("flex gap-4 flex-col md:flex-row relative", defaultClassNames.months),
40
+ month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
41
+ nav: cn("flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between", defaultClassNames.nav),
42
+ button_previous: cn(
43
+ buttonVariants({ variant: buttonVariant }),
44
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
45
+ defaultClassNames.button_previous
46
+ ),
47
+ button_next: cn(
48
+ buttonVariants({ variant: buttonVariant }),
49
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
50
+ defaultClassNames.button_next
51
+ ),
52
+ month_caption: cn(
53
+ "flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
54
+ defaultClassNames.month_caption
55
+ ),
56
+ dropdowns: cn(
57
+ "w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
58
+ defaultClassNames.dropdowns
59
+ ),
60
+ dropdown_root: cn(
61
+ "relative has-focus:outline-none border border-input shadow-xs has-focus:ring-2 has-focus:ring-ring/50 has-focus:ring-offset-2 has-focus:ring-offset-background rounded-md",
62
+ defaultClassNames.dropdown_root
63
+ ),
64
+ dropdown: cn("absolute bg-popover inset-0 opacity-0", defaultClassNames.dropdown),
65
+ caption_label: cn(
66
+ "select-none font-medium",
67
+ captionLayout === "label" ? "text-sm" : "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
68
+ defaultClassNames.caption_label
69
+ ),
70
+ table: "w-full border-collapse",
71
+ weekdays: cn("flex", defaultClassNames.weekdays),
72
+ weekday: cn(
73
+ "text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
74
+ defaultClassNames.weekday
75
+ ),
76
+ week: cn("flex w-full mt-2", defaultClassNames.week),
77
+ week_number_header: cn("select-none w-(--cell-size)", defaultClassNames.week_number_header),
78
+ week_number: cn("text-[0.8rem] select-none text-muted-foreground", defaultClassNames.week_number),
79
+ day: cn(
80
+ "relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
81
+ defaultClassNames.day
82
+ ),
83
+ range_start: cn("rounded-l-md bg-accent", defaultClassNames.range_start),
84
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
85
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
86
+ today: cn(
87
+ "bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
88
+ defaultClassNames.today
89
+ ),
90
+ outside: cn("text-muted-foreground aria-selected:text-muted-foreground", defaultClassNames.outside),
91
+ disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
92
+ hidden: cn("invisible", defaultClassNames.hidden),
93
+ ...classNames
94
+ },
95
+ components: {
96
+ Root: ({ className: rootClassName, rootRef, ...rootProps }) => {
97
+ return /* @__PURE__ */ jsx("div", { "data-slot": "calendar", ref: rootRef, className: cn(rootClassName), ...rootProps });
98
+ },
99
+ Chevron: ({ className: chevronClassName, orientation, ...chevronProps }) => {
100
+ if (orientation === "left") {
101
+ return /* @__PURE__ */ jsx(ChevronLeftIcon, { className: cn("size-4", chevronClassName), ...chevronProps });
102
+ }
103
+ if (orientation === "right") {
104
+ return /* @__PURE__ */ jsx(ChevronRightIcon, { className: cn("size-4", chevronClassName), ...chevronProps });
105
+ }
106
+ return /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("size-4", chevronClassName), ...chevronProps });
107
+ },
108
+ DayButton: CalendarDayButton,
109
+ WeekNumber: ({ children, week: _week, ...weekProps }) => {
110
+ return /* @__PURE__ */ jsx("td", { ...weekProps, children: /* @__PURE__ */ jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
111
+ },
112
+ ...components
113
+ },
114
+ ...props
115
+ }
116
+ );
117
+ }
118
+ function CalendarDayButton({ className, day, modifiers, ...props }) {
119
+ const defaultClassNames = getDefaultClassNames();
120
+ const ref = React.useRef(null);
121
+ React.useEffect(() => {
122
+ if (modifiers.focused) ref.current?.focus();
123
+ }, [modifiers.focused]);
124
+ return /* @__PURE__ */ jsx(
125
+ Button,
126
+ {
127
+ ref,
128
+ variant: "ghost",
129
+ size: "icon",
130
+ "data-day": day.date.toLocaleDateString(),
131
+ "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
132
+ "data-range-start": modifiers.range_start,
133
+ "data-range-end": modifiers.range_end,
134
+ "data-range-middle": modifiers.range_middle,
135
+ className: cn(
136
+ "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:outline-none group-data-[focused=true]/day:ring-ring/50 group-data-[focused=true]/day:ring-offset-2 group-data-[focused=true]/day:ring-offset-background dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-2 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
137
+ defaultClassNames.day,
138
+ className
139
+ ),
140
+ ...props
141
+ }
142
+ );
143
+ }
144
+ export {
145
+ Calendar,
146
+ CalendarDayButton
147
+ };
148
+ //# sourceMappingURL=calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/calendar.tsx"],"sourcesContent":["\"use client\";\n\nimport { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { type DayButton, DayPicker, getDefaultClassNames } from \"react-day-picker\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Button, type ButtonProps, buttonVariants } from \"./button.js\";\n\n/**\n * Calendar (react-day-picker v9) — lịch trần, đã map class sang token Comitor.\n * Bản có ô nhập `dd/MM/yyyy` + preset (\"Hôm nay\", \"7 ngày qua\"…) là composite\n * `DatePicker` / `DateRangePicker` ở Tier 2.\n *\n * Ngôn ngữ: truyền `locale={vi}` (date-fns/locale) để đổi tên thứ/tháng.\n *\n * Khác bản comitor-ds: tên tháng rút gọn trong dropdown lấy theo `locale.code`\n * (mặc định `vi-VN`) thay vì `\"default\"` — `\"default\"` phụ thuộc locale của môi\n * trường chạy nên server và trình duyệt có thể ra chuỗi khác nhau → hydration mismatch.\n */\n\nexport type CalendarProps = React.ComponentProps<typeof DayPicker> & {\n /** Biến thể Button dùng cho nút điều hướng tháng. */\n buttonVariant?: ButtonProps[\"variant\"];\n};\nexport type CalendarDayButtonProps = React.ComponentProps<typeof DayButton>;\n\nfunction Calendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = \"label\",\n buttonVariant = \"ghost\",\n formatters,\n components,\n locale,\n ...props\n}: CalendarProps) {\n const defaultClassNames = getDefaultClassNames();\n const localeCode = locale?.code ?? \"vi-VN\";\n\n return (\n <DayPicker\n showOutsideDays={showOutsideDays}\n locale={locale}\n className={cn(\n \"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent\",\n String.raw`rtl:**:[.rdp-button\\_next>svg]:rotate-180`,\n String.raw`rtl:**:[.rdp-button\\_previous>svg]:rotate-180`,\n className\n )}\n captionLayout={captionLayout}\n formatters={{\n formatMonthDropdown: (date) => date.toLocaleString(localeCode, { month: \"short\" }),\n ...formatters\n }}\n classNames={{\n root: cn(\"w-fit\", defaultClassNames.root),\n months: cn(\"flex gap-4 flex-col md:flex-row relative\", defaultClassNames.months),\n month: cn(\"flex flex-col w-full gap-4\", defaultClassNames.month),\n nav: cn(\"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between\", defaultClassNames.nav),\n button_previous: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none\",\n defaultClassNames.button_previous\n ),\n button_next: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none\",\n defaultClassNames.button_next\n ),\n month_caption: cn(\n \"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)\",\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n \"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5\",\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\n \"relative has-focus:outline-none border border-input shadow-xs has-focus:ring-2 has-focus:ring-ring/50 has-focus:ring-offset-2 has-focus:ring-offset-background rounded-md\",\n defaultClassNames.dropdown_root\n ),\n dropdown: cn(\"absolute bg-popover inset-0 opacity-0\", defaultClassNames.dropdown),\n caption_label: cn(\n \"select-none font-medium\",\n captionLayout === \"label\"\n ? \"text-sm\"\n : \"rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5\",\n defaultClassNames.caption_label\n ),\n table: \"w-full border-collapse\",\n weekdays: cn(\"flex\", defaultClassNames.weekdays),\n weekday: cn(\n \"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none\",\n defaultClassNames.weekday\n ),\n week: cn(\"flex w-full mt-2\", defaultClassNames.week),\n week_number_header: cn(\"select-none w-(--cell-size)\", defaultClassNames.week_number_header),\n week_number: cn(\"text-[0.8rem] select-none text-muted-foreground\", defaultClassNames.week_number),\n day: cn(\n \"relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none\",\n defaultClassNames.day\n ),\n range_start: cn(\"rounded-l-md bg-accent\", defaultClassNames.range_start),\n range_middle: cn(\"rounded-none\", defaultClassNames.range_middle),\n range_end: cn(\"rounded-r-md bg-accent\", defaultClassNames.range_end),\n today: cn(\n \"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none\",\n defaultClassNames.today\n ),\n outside: cn(\"text-muted-foreground aria-selected:text-muted-foreground\", defaultClassNames.outside),\n disabled: cn(\"text-muted-foreground opacity-50\", defaultClassNames.disabled),\n hidden: cn(\"invisible\", defaultClassNames.hidden),\n ...classNames\n }}\n components={{\n Root: ({ className: rootClassName, rootRef, ...rootProps }) => {\n return <div data-slot=\"calendar\" ref={rootRef} className={cn(rootClassName)} {...rootProps} />;\n },\n Chevron: ({ className: chevronClassName, orientation, ...chevronProps }) => {\n if (orientation === \"left\") {\n return <ChevronLeftIcon className={cn(\"size-4\", chevronClassName)} {...chevronProps} />;\n }\n\n if (orientation === \"right\") {\n return <ChevronRightIcon className={cn(\"size-4\", chevronClassName)} {...chevronProps} />;\n }\n\n return <ChevronDownIcon className={cn(\"size-4\", chevronClassName)} {...chevronProps} />;\n },\n DayButton: CalendarDayButton,\n WeekNumber: ({ children, week: _week, ...weekProps }) => {\n return (\n <td {...weekProps}>\n <div className=\"flex size-(--cell-size) items-center justify-center text-center\">{children}</div>\n </td>\n );\n },\n ...components\n }}\n {...props}\n />\n );\n}\n\nfunction CalendarDayButton({ className, day, modifiers, ...props }: CalendarDayButtonProps) {\n const defaultClassNames = getDefaultClassNames();\n\n const ref = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"icon\"\n data-day={day.date.toLocaleDateString()}\n data-selected-single={\n modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle\n }\n data-range-start={modifiers.range_start}\n data-range-end={modifiers.range_end}\n data-range-middle={modifiers.range_middle}\n className={cn(\n \"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:outline-none group-data-[focused=true]/day:ring-ring/50 group-data-[focused=true]/day:ring-offset-2 group-data-[focused=true]/day:ring-offset-background dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-2 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70\",\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Calendar, CalendarDayButton };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,33 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import { VariantProps } from 'class-variance-authority';
3
+ import * as React from 'react';
4
+
5
+ declare const cardVariants: (props?: ({
6
+ variant?: "default" | "outline" | "ghost" | "elevated" | null | undefined;
7
+ padding?: "none" | "sm" | "md" | "lg" | null | undefined;
8
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
9
+ interface CardProps extends React.ComponentProps<"div">, VariantProps<typeof cardVariants> {
10
+ }
11
+ type CardHeaderProps = React.ComponentProps<"div">;
12
+ type CardTitleProps = React.ComponentProps<"h3">;
13
+ type CardDescriptionProps = React.ComponentProps<"p">;
14
+ type CardActionProps = React.ComponentProps<"div">;
15
+ type CardContentProps = React.ComponentProps<"div">;
16
+ type CardFooterProps = React.ComponentProps<"div">;
17
+ declare function CardBase({ className, variant, padding, ...props }: CardProps): React.JSX.Element;
18
+ declare function CardHeader({ className, ...props }: CardHeaderProps): React.JSX.Element;
19
+ declare function CardTitle({ className, ...props }: CardTitleProps): React.JSX.Element;
20
+ declare function CardDescription({ className, ...props }: CardDescriptionProps): React.JSX.Element;
21
+ declare function CardAction({ className, ...props }: CardActionProps): React.JSX.Element;
22
+ declare function CardContent({ className, ...props }: CardContentProps): React.JSX.Element;
23
+ declare function CardFooter({ className, ...props }: CardFooterProps): React.JSX.Element;
24
+ declare const Card: typeof CardBase & {
25
+ Header: typeof CardHeader;
26
+ Title: typeof CardTitle;
27
+ Description: typeof CardDescription;
28
+ Content: typeof CardContent;
29
+ Footer: typeof CardFooter;
30
+ Action: typeof CardAction;
31
+ };
32
+
33
+ export { Card, CardAction, type CardActionProps, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, cardVariants };
@@ -0,0 +1,70 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "../../lib/cn.js";
4
+ const cardVariants = cva("rounded-xl", {
5
+ variants: {
6
+ variant: {
7
+ default: "bg-card border border-border shadow-surface",
8
+ elevated: "bg-card border border-border shadow-card",
9
+ outline: "bg-transparent border border-border",
10
+ ghost: "bg-transparent border-none"
11
+ },
12
+ padding: {
13
+ none: "",
14
+ sm: "p-4",
15
+ md: "p-6",
16
+ lg: "p-8"
17
+ }
18
+ },
19
+ defaultVariants: {
20
+ variant: "default",
21
+ padding: "md"
22
+ }
23
+ });
24
+ function CardBase({ className, variant, padding, ...props }) {
25
+ return /* @__PURE__ */ jsx("div", { "data-slot": "card", className: cn(cardVariants({ variant, padding }), className), ...props });
26
+ }
27
+ function CardHeader({ className, ...props }) {
28
+ return /* @__PURE__ */ jsx("div", { "data-slot": "card-header", className: cn("flex flex-col space-y-1.5", className), ...props });
29
+ }
30
+ function CardTitle({ className, ...props }) {
31
+ return /* @__PURE__ */ jsx(
32
+ "h3",
33
+ {
34
+ "data-slot": "card-title",
35
+ className: cn("text-lg font-semibold text-foreground leading-none tracking-tight", className),
36
+ ...props
37
+ }
38
+ );
39
+ }
40
+ function CardDescription({ className, ...props }) {
41
+ return /* @__PURE__ */ jsx("p", { "data-slot": "card-description", className: cn("text-sm text-muted-foreground", className), ...props });
42
+ }
43
+ function CardAction({ className, ...props }) {
44
+ return /* @__PURE__ */ jsx("div", { "data-slot": "card-action", className: cn("ml-auto", className), ...props });
45
+ }
46
+ function CardContent({ className, ...props }) {
47
+ return /* @__PURE__ */ jsx("div", { "data-slot": "card-content", className: cn("pt-4", className), ...props });
48
+ }
49
+ function CardFooter({ className, ...props }) {
50
+ return /* @__PURE__ */ jsx("div", { "data-slot": "card-footer", className: cn("flex items-center pt-4", className), ...props });
51
+ }
52
+ const Card = Object.assign(CardBase, {
53
+ Header: CardHeader,
54
+ Title: CardTitle,
55
+ Description: CardDescription,
56
+ Content: CardContent,
57
+ Footer: CardFooter,
58
+ Action: CardAction
59
+ });
60
+ export {
61
+ Card,
62
+ CardAction,
63
+ CardContent,
64
+ CardDescription,
65
+ CardFooter,
66
+ CardHeader,
67
+ CardTitle,
68
+ cardVariants
69
+ };
70
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/card.tsx"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\n\n/*\n * Cấu trúc + style port nguyên trạng từ comitor-ds. Tên export giữ tương thích shadcn\n * (Card / CardHeader / CardTitle / CardDescription / CardContent / CardFooter), thêm\n * CardAction (bổ sung, không có trong shadcn gốc).\n */\nconst cardVariants = cva(\"rounded-xl\", {\n variants: {\n variant: {\n default: \"bg-card border border-border shadow-surface\",\n elevated: \"bg-card border border-border shadow-card\",\n outline: \"bg-transparent border border-border\",\n ghost: \"bg-transparent border-none\"\n },\n padding: {\n none: \"\",\n sm: \"p-4\",\n md: \"p-6\",\n lg: \"p-8\"\n }\n },\n defaultVariants: {\n variant: \"default\",\n padding: \"md\"\n }\n});\n\nexport interface CardProps extends React.ComponentProps<\"div\">, VariantProps<typeof cardVariants> {}\nexport type CardHeaderProps = React.ComponentProps<\"div\">;\nexport type CardTitleProps = React.ComponentProps<\"h3\">;\nexport type CardDescriptionProps = React.ComponentProps<\"p\">;\nexport type CardActionProps = React.ComponentProps<\"div\">;\nexport type CardContentProps = React.ComponentProps<\"div\">;\nexport type CardFooterProps = React.ComponentProps<\"div\">;\n\nfunction CardBase({ className, variant, padding, ...props }: CardProps) {\n return <div data-slot=\"card\" className={cn(cardVariants({ variant, padding }), className)} {...props} />;\n}\n\nfunction CardHeader({ className, ...props }: CardHeaderProps) {\n return <div data-slot=\"card-header\" className={cn(\"flex flex-col space-y-1.5\", className)} {...props} />;\n}\n\nfunction CardTitle({ className, ...props }: CardTitleProps) {\n return (\n <h3\n data-slot=\"card-title\"\n className={cn(\"text-lg font-semibold text-foreground leading-none tracking-tight\", className)}\n {...props}\n />\n );\n}\n\nfunction CardDescription({ className, ...props }: CardDescriptionProps) {\n return <p data-slot=\"card-description\" className={cn(\"text-sm text-muted-foreground\", className)} {...props} />;\n}\n\nfunction CardAction({ className, ...props }: CardActionProps) {\n return <div data-slot=\"card-action\" className={cn(\"ml-auto\", className)} {...props} />;\n}\n\nfunction CardContent({ className, ...props }: CardContentProps) {\n return <div data-slot=\"card-content\" className={cn(\"pt-4\", className)} {...props} />;\n}\n\nfunction CardFooter({ className, ...props }: CardFooterProps) {\n return <div data-slot=\"card-footer\" className={cn(\"flex items-center pt-4\", className)} {...props} />;\n}\n\n/*\n * `Card` mở cả hai lối dùng: API tên rời (Card + CardHeader/CardTitle/…) và API gộp\n * (Card.Header / Card.Title / Card.Description / Card.Content / Card.Footer / Card.Action).\n */\nconst Card = Object.assign(CardBase, {\n Header: CardHeader,\n Title: CardTitle,\n Description: CardDescription,\n Content: CardContent,\n Footer: CardFooter,\n Action: CardAction\n});\n\nexport { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants };\n"],"mappings":"AAuCS;AAvCT,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAOnB,MAAM,eAAe,IAAI,cAAc;AAAA,EACrC,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACF,CAAC;AAUD,SAAS,SAAS,EAAE,WAAW,SAAS,SAAS,GAAG,MAAM,GAAc;AACtE,SAAO,oBAAC,SAAI,aAAU,QAAO,WAAW,GAAG,aAAa,EAAE,SAAS,QAAQ,CAAC,GAAG,SAAS,GAAI,GAAG,OAAO;AACxG;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAoB;AAC5D,SAAO,oBAAC,SAAI,aAAU,eAAc,WAAW,GAAG,6BAA6B,SAAS,GAAI,GAAG,OAAO;AACxG;AAEA,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAmB;AAC1D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,qEAAqE,SAAS;AAAA,MAC3F,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,MAAM,GAAyB;AACtE,SAAO,oBAAC,OAAE,aAAU,oBAAmB,WAAW,GAAG,iCAAiC,SAAS,GAAI,GAAG,OAAO;AAC/G;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAoB;AAC5D,SAAO,oBAAC,SAAI,aAAU,eAAc,WAAW,GAAG,WAAW,SAAS,GAAI,GAAG,OAAO;AACtF;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SAAO,oBAAC,SAAI,aAAU,gBAAe,WAAW,GAAG,QAAQ,SAAS,GAAI,GAAG,OAAO;AACpF;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAoB;AAC5D,SAAO,oBAAC,SAAI,aAAU,eAAc,WAAW,GAAG,0BAA0B,SAAS,GAAI,GAAG,OAAO;AACrG;AAMA,MAAM,OAAO,OAAO,OAAO,UAAU;AAAA,EACnC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AACV,CAAC;","names":[]}