@vestow/vue 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 (491) hide show
  1. package/README.md +233 -0
  2. package/index.ts +8 -0
  3. package/package.json +68 -0
  4. package/src/components/accordion/Accordion.vue +45 -0
  5. package/src/components/accordion/AccordionContent.vue +31 -0
  6. package/src/components/accordion/AccordionItem.vue +26 -0
  7. package/src/components/accordion/AccordionTrigger.vue +39 -0
  8. package/src/components/accordion/index.ts +18 -0
  9. package/src/components/alert/Alert.vue +17 -0
  10. package/src/components/alert/AlertDescription.vue +12 -0
  11. package/src/components/alert/AlertTitle.vue +12 -0
  12. package/src/components/alert/index.ts +5 -0
  13. package/src/components/avatar/Avatar.vue +32 -0
  14. package/src/components/avatar/AvatarFallback.vue +23 -0
  15. package/src/components/avatar/AvatarImage.vue +18 -0
  16. package/src/components/avatar/index.ts +3 -0
  17. package/src/components/badge/Badge.vue +25 -0
  18. package/src/components/badge/index.ts +3 -0
  19. package/src/components/breadcrumb/Breadcrumb.vue +14 -0
  20. package/src/components/breadcrumb/BreadcrumbItem.vue +12 -0
  21. package/src/components/breadcrumb/BreadcrumbLink.vue +19 -0
  22. package/src/components/breadcrumb/BreadcrumbPage.vue +12 -0
  23. package/src/components/breadcrumb/BreadcrumbSeparator.vue +15 -0
  24. package/src/components/breadcrumb/index.ts +5 -0
  25. package/src/components/button/Button.vue +55 -0
  26. package/src/components/button/index.ts +3 -0
  27. package/src/components/button-group/ButtonGroup.vue +29 -0
  28. package/src/components/button-group/ButtonGroupSeparator.vue +30 -0
  29. package/src/components/button-group/ButtonGroupText.vue +29 -0
  30. package/src/components/button-group/SplitButton.vue +103 -0
  31. package/src/components/button-group/SplitButtonItems.vue +50 -0
  32. package/src/components/button-group/index.ts +34 -0
  33. package/src/components/calendar/Calendar.vue +120 -0
  34. package/src/components/calendar/RangeCalendar.vue +127 -0
  35. package/src/components/calendar/index.ts +2 -0
  36. package/src/components/card/Card.vue +12 -0
  37. package/src/components/card/CardAction.vue +12 -0
  38. package/src/components/card/CardContent.vue +12 -0
  39. package/src/components/card/CardDescription.vue +12 -0
  40. package/src/components/card/CardFooter.vue +12 -0
  41. package/src/components/card/CardHeader.vue +15 -0
  42. package/src/components/card/CardTitle.vue +12 -0
  43. package/src/components/card/index.ts +7 -0
  44. package/src/components/carousel/Carousel.vue +164 -0
  45. package/src/components/carousel/CarouselContent.vue +43 -0
  46. package/src/components/carousel/CarouselDots.vue +42 -0
  47. package/src/components/carousel/CarouselItem.vue +58 -0
  48. package/src/components/carousel/CarouselNext.vue +45 -0
  49. package/src/components/carousel/CarouselPrevious.vue +45 -0
  50. package/src/components/carousel/index.ts +44 -0
  51. package/src/components/cascade-select/CascadeSelect.vue +314 -0
  52. package/src/components/cascade-select/index.ts +11 -0
  53. package/src/components/chart/AreaChart.vue +201 -0
  54. package/src/components/chart/BarChart.vue +389 -0
  55. package/src/components/chart/ChartContainer.vue +127 -0
  56. package/src/components/chart/ChartCrosshair.vue +92 -0
  57. package/src/components/chart/ChartLegend.vue +63 -0
  58. package/src/components/chart/ChartTooltipCard.vue +49 -0
  59. package/src/components/chart/LineChart.vue +214 -0
  60. package/src/components/chart/PieChart.vue +280 -0
  61. package/src/components/chart/RadarChart.vue +291 -0
  62. package/src/components/chart/RadialChart.vue +354 -0
  63. package/src/components/chart/index.ts +30 -0
  64. package/src/components/chart/polar.ts +5 -0
  65. package/src/components/chart/tooltip.ts +5 -0
  66. package/src/components/chart/types.ts +52 -0
  67. package/src/components/chart/useChartSeries.ts +138 -0
  68. package/src/components/chart/xy-label.ts +5 -0
  69. package/src/components/checkbox/Checkbox.vue +81 -0
  70. package/src/components/checkbox/CheckboxField.vue +129 -0
  71. package/src/components/checkbox/CheckboxGroup.vue +62 -0
  72. package/src/components/checkbox/index.ts +21 -0
  73. package/src/components/chip/Chip.vue +73 -0
  74. package/src/components/chip/index.ts +3 -0
  75. package/src/components/code-block/CodeBlock.vue +100 -0
  76. package/src/components/code-block/index.ts +4 -0
  77. package/src/components/collapsible/Collapsible.vue +15 -0
  78. package/src/components/collapsible/CollapsibleContent.vue +26 -0
  79. package/src/components/collapsible/CollapsibleTrigger.vue +12 -0
  80. package/src/components/collapsible/index.ts +3 -0
  81. package/src/components/combobox/Combobox.vue +23 -0
  82. package/src/components/combobox/ComboboxAnchor.vue +20 -0
  83. package/src/components/combobox/ComboboxEmpty.vue +21 -0
  84. package/src/components/combobox/ComboboxGroup.vue +23 -0
  85. package/src/components/combobox/ComboboxInput.vue +32 -0
  86. package/src/components/combobox/ComboboxItem.vue +38 -0
  87. package/src/components/combobox/ComboboxList.vue +43 -0
  88. package/src/components/combobox/ComboboxSeparator.vue +18 -0
  89. package/src/components/combobox/ComboboxTrigger.vue +12 -0
  90. package/src/components/combobox/index.ts +9 -0
  91. package/src/components/command/Command.vue +54 -0
  92. package/src/components/command/CommandDialog.vue +41 -0
  93. package/src/components/command/CommandEmpty.vue +19 -0
  94. package/src/components/command/CommandGroup.vue +28 -0
  95. package/src/components/command/CommandInput.vue +25 -0
  96. package/src/components/command/CommandItem.vue +40 -0
  97. package/src/components/command/CommandList.vue +13 -0
  98. package/src/components/command/CommandSeparator.vue +11 -0
  99. package/src/components/command/CommandShortcut.vue +13 -0
  100. package/src/components/command/index.ts +34 -0
  101. package/src/components/command-block/CommandBlock.vue +90 -0
  102. package/src/components/command-block/index.ts +2 -0
  103. package/src/components/confirm-dialog/ConfirmDialog.vue +37 -0
  104. package/src/components/confirm-dialog/index.ts +1 -0
  105. package/src/components/confirm-popup/ConfirmPopup.vue +123 -0
  106. package/src/components/confirm-popup/index.ts +1 -0
  107. package/src/components/context-menu/ContextMenu.vue +15 -0
  108. package/src/components/context-menu/ContextMenuCheckboxItem.vue +30 -0
  109. package/src/components/context-menu/ContextMenuContent.vue +36 -0
  110. package/src/components/context-menu/ContextMenuGroup.vue +12 -0
  111. package/src/components/context-menu/ContextMenuItem.vue +32 -0
  112. package/src/components/context-menu/ContextMenuLabel.vue +21 -0
  113. package/src/components/context-menu/ContextMenuRadioGroup.vue +15 -0
  114. package/src/components/context-menu/ContextMenuRadioItem.vue +30 -0
  115. package/src/components/context-menu/ContextMenuSeparator.vue +19 -0
  116. package/src/components/context-menu/ContextMenuShortcut.vue +13 -0
  117. package/src/components/context-menu/ContextMenuSub.vue +15 -0
  118. package/src/components/context-menu/ContextMenuSubContent.vue +26 -0
  119. package/src/components/context-menu/ContextMenuSubTrigger.vue +26 -0
  120. package/src/components/context-menu/ContextMenuTrigger.vue +12 -0
  121. package/src/components/context-menu/index.ts +14 -0
  122. package/src/components/data-table/DataTable.vue +458 -0
  123. package/src/components/data-table/DataTableFacetedFilter.vue +97 -0
  124. package/src/components/data-table/DataTablePagination.vue +103 -0
  125. package/src/components/data-table/DataTableViewOptions.vue +69 -0
  126. package/src/components/data-table/features.ts +87 -0
  127. package/src/components/data-table/index.ts +27 -0
  128. package/src/components/data-table/pagination-adapter.ts +67 -0
  129. package/src/components/data-table/selection-column.ts +48 -0
  130. package/src/components/data-table/types.ts +36 -0
  131. package/src/components/data-view/DataView.vue +136 -0
  132. package/src/components/data-view/index.ts +1 -0
  133. package/src/components/date-picker/DatePicker.vue +117 -0
  134. package/src/components/date-picker/DateRangePicker.vue +122 -0
  135. package/src/components/date-picker/index.ts +2 -0
  136. package/src/components/deferred/Deferred.vue +80 -0
  137. package/src/components/deferred/index.ts +1 -0
  138. package/src/components/dialog/Dialog.vue +15 -0
  139. package/src/components/dialog/DialogClose.vue +12 -0
  140. package/src/components/dialog/DialogContent.vue +46 -0
  141. package/src/components/dialog/DialogDescription.vue +19 -0
  142. package/src/components/dialog/DialogFooter.vue +12 -0
  143. package/src/components/dialog/DialogHeader.vue +12 -0
  144. package/src/components/dialog/DialogTitle.vue +19 -0
  145. package/src/components/dialog/DialogTrigger.vue +12 -0
  146. package/src/components/dialog/index.ts +10 -0
  147. package/src/components/doc-example/DocExample.vue +41 -0
  148. package/src/components/doc-example/index.ts +1 -0
  149. package/src/components/doc-text/DocText.vue +64 -0
  150. package/src/components/doc-text/index.ts +1 -0
  151. package/src/components/dropdown-menu/DropdownMenu.vue +15 -0
  152. package/src/components/dropdown-menu/DropdownMenuCheckboxItem.vue +33 -0
  153. package/src/components/dropdown-menu/DropdownMenuContent.vue +36 -0
  154. package/src/components/dropdown-menu/DropdownMenuGroup.vue +12 -0
  155. package/src/components/dropdown-menu/DropdownMenuItem.vue +32 -0
  156. package/src/components/dropdown-menu/DropdownMenuLabel.vue +24 -0
  157. package/src/components/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
  158. package/src/components/dropdown-menu/DropdownMenuRadioItem.vue +33 -0
  159. package/src/components/dropdown-menu/DropdownMenuSeparator.vue +19 -0
  160. package/src/components/dropdown-menu/DropdownMenuShortcut.vue +13 -0
  161. package/src/components/dropdown-menu/DropdownMenuSub.vue +15 -0
  162. package/src/components/dropdown-menu/DropdownMenuSubContent.vue +29 -0
  163. package/src/components/dropdown-menu/DropdownMenuSubTrigger.vue +26 -0
  164. package/src/components/dropdown-menu/DropdownMenuTrigger.vue +12 -0
  165. package/src/components/dropdown-menu/index.ts +14 -0
  166. package/src/components/editable/Editable.vue +41 -0
  167. package/src/components/editable/EditableArea.vue +22 -0
  168. package/src/components/editable/EditableCancelTrigger.vue +40 -0
  169. package/src/components/editable/EditableEditTrigger.vue +40 -0
  170. package/src/components/editable/EditableInput.vue +28 -0
  171. package/src/components/editable/EditablePreview.vue +34 -0
  172. package/src/components/editable/EditableSubmitTrigger.vue +40 -0
  173. package/src/components/editable/index.ts +17 -0
  174. package/src/components/empty/Empty.vue +17 -0
  175. package/src/components/empty/EmptyActions.vue +14 -0
  176. package/src/components/empty/EmptyDescription.vue +12 -0
  177. package/src/components/empty/EmptyMedia.vue +16 -0
  178. package/src/components/empty/EmptyTitle.vue +17 -0
  179. package/src/components/empty/index.ts +7 -0
  180. package/src/components/field/Field.vue +22 -0
  181. package/src/components/field/FieldDescription.vue +20 -0
  182. package/src/components/field/FieldGroup.vue +22 -0
  183. package/src/components/field/FieldLabel.vue +27 -0
  184. package/src/components/field/FieldSeparator.vue +28 -0
  185. package/src/components/field/index.ts +7 -0
  186. package/src/components/fieldset/Fieldset.vue +126 -0
  187. package/src/components/fieldset/index.ts +1 -0
  188. package/src/components/file-upload/FileUpload.vue +149 -0
  189. package/src/components/file-upload/index.ts +8 -0
  190. package/src/components/float-label/FloatLabel.vue +26 -0
  191. package/src/components/float-label/index.ts +3 -0
  192. package/src/components/form/Form.vue +126 -0
  193. package/src/components/form/FormDescription.vue +12 -0
  194. package/src/components/form/FormField.vue +127 -0
  195. package/src/components/form/FormItem.vue +12 -0
  196. package/src/components/form/FormLabel.vue +14 -0
  197. package/src/components/form/FormMessage.vue +31 -0
  198. package/src/components/form/context.ts +54 -0
  199. package/src/components/form/errors.ts +6 -0
  200. package/src/components/form/index.ts +7 -0
  201. package/src/components/form/types.ts +55 -0
  202. package/src/components/hover-card/HoverCard.vue +27 -0
  203. package/src/components/hover-card/HoverCardContent.vue +36 -0
  204. package/src/components/hover-card/HoverCardTrigger.vue +12 -0
  205. package/src/components/hover-card/index.ts +3 -0
  206. package/src/components/ifta-label/IftaLabel.vue +26 -0
  207. package/src/components/ifta-label/index.ts +1 -0
  208. package/src/components/index.ts +89 -0
  209. package/src/components/input/Input.vue +87 -0
  210. package/src/components/input/index.ts +1 -0
  211. package/src/components/input-color/ColorArea.vue +36 -0
  212. package/src/components/input-color/ColorField.vue +32 -0
  213. package/src/components/input-color/ColorSlider.vue +31 -0
  214. package/src/components/input-color/InputColor.vue +65 -0
  215. package/src/components/input-color/index.ts +16 -0
  216. package/src/components/input-group/InputGroup.vue +26 -0
  217. package/src/components/input-group/InputGroupAddon.vue +32 -0
  218. package/src/components/input-group/InputGroupInput.vue +33 -0
  219. package/src/components/input-group/index.ts +17 -0
  220. package/src/components/input-number/InputNumber.vue +82 -0
  221. package/src/components/input-number/index.ts +1 -0
  222. package/src/components/input-otp/InputOtp.vue +186 -0
  223. package/src/components/input-otp/index.ts +1 -0
  224. package/src/components/input-password/InputPassword.vue +116 -0
  225. package/src/components/input-password/index.ts +5 -0
  226. package/src/components/input-tags/InputTags.vue +38 -0
  227. package/src/components/input-tags/InputTagsClear.vue +39 -0
  228. package/src/components/input-tags/InputTagsInput.vue +27 -0
  229. package/src/components/input-tags/InputTagsItem.vue +40 -0
  230. package/src/components/input-tags/InputTagsItemDelete.vue +32 -0
  231. package/src/components/input-tags/InputTagsItemText.vue +18 -0
  232. package/src/components/input-tags/index.ts +16 -0
  233. package/src/components/kbd/Kbd.vue +17 -0
  234. package/src/components/kbd/KbdGroup.vue +15 -0
  235. package/src/components/kbd/index.ts +4 -0
  236. package/src/components/label/Label.vue +23 -0
  237. package/src/components/label/index.ts +1 -0
  238. package/src/components/listbox/Listbox.vue +42 -0
  239. package/src/components/listbox/ListboxContent.vue +22 -0
  240. package/src/components/listbox/ListboxFilter.vue +34 -0
  241. package/src/components/listbox/ListboxGroup.vue +31 -0
  242. package/src/components/listbox/ListboxItem.vue +46 -0
  243. package/src/components/listbox/index.ts +19 -0
  244. package/src/components/mask/Mask.vue +205 -0
  245. package/src/components/mask/index.ts +15 -0
  246. package/src/components/menubar/Menubar.vue +26 -0
  247. package/src/components/menubar/MenubarCheckboxItem.vue +30 -0
  248. package/src/components/menubar/MenubarContent.vue +52 -0
  249. package/src/components/menubar/MenubarGroup.vue +12 -0
  250. package/src/components/menubar/MenubarItem.vue +32 -0
  251. package/src/components/menubar/MenubarLabel.vue +21 -0
  252. package/src/components/menubar/MenubarMenu.vue +12 -0
  253. package/src/components/menubar/MenubarRadioGroup.vue +15 -0
  254. package/src/components/menubar/MenubarRadioItem.vue +30 -0
  255. package/src/components/menubar/MenubarSeparator.vue +12 -0
  256. package/src/components/menubar/MenubarShortcut.vue +13 -0
  257. package/src/components/menubar/MenubarSub.vue +15 -0
  258. package/src/components/menubar/MenubarSubContent.vue +26 -0
  259. package/src/components/menubar/MenubarSubTrigger.vue +26 -0
  260. package/src/components/menubar/MenubarTrigger.vue +30 -0
  261. package/src/components/menubar/index.ts +29 -0
  262. package/src/components/navigation-menu/NavigationMenu.vue +43 -0
  263. package/src/components/navigation-menu/NavigationMenuContent.vue +63 -0
  264. package/src/components/navigation-menu/NavigationMenuIndicator.vue +31 -0
  265. package/src/components/navigation-menu/NavigationMenuItem.vue +20 -0
  266. package/src/components/navigation-menu/NavigationMenuLink.vue +34 -0
  267. package/src/components/navigation-menu/NavigationMenuList.vue +23 -0
  268. package/src/components/navigation-menu/NavigationMenuTrigger.vue +38 -0
  269. package/src/components/navigation-menu/NavigationMenuViewport.vue +34 -0
  270. package/src/components/navigation-menu/index.ts +18 -0
  271. package/src/components/order-list/OrderList.vue +168 -0
  272. package/src/components/order-list/SelectableList.vue +200 -0
  273. package/src/components/order-list/index.ts +1 -0
  274. package/src/components/pagination/Pagination.vue +133 -0
  275. package/src/components/pagination/index.ts +1 -0
  276. package/src/components/panel/Panel.vue +69 -0
  277. package/src/components/panel/index.ts +1 -0
  278. package/src/components/pick-list/PickList.vue +211 -0
  279. package/src/components/pick-list/index.ts +1 -0
  280. package/src/components/popover/Popover.vue +15 -0
  281. package/src/components/popover/PopoverAnchor.vue +12 -0
  282. package/src/components/popover/PopoverContent.vue +39 -0
  283. package/src/components/popover/PopoverTrigger.vue +12 -0
  284. package/src/components/popover/index.ts +4 -0
  285. package/src/components/progress/Progress.vue +39 -0
  286. package/src/components/progress/index.ts +1 -0
  287. package/src/components/props-table/PropsTable.vue +62 -0
  288. package/src/components/props-table/index.ts +2 -0
  289. package/src/components/radio-group/RadioGroup.vue +52 -0
  290. package/src/components/radio-group/RadioGroupItem.vue +80 -0
  291. package/src/components/radio-group/RadioGroupItemField.vue +128 -0
  292. package/src/components/radio-group/index.ts +21 -0
  293. package/src/components/rating/Rating.vue +70 -0
  294. package/src/components/rating/RatingItem.vue +26 -0
  295. package/src/components/rating/RatingItemIndicator.vue +28 -0
  296. package/src/components/rating/RatingStar.vue +16 -0
  297. package/src/components/rating/index.ts +13 -0
  298. package/src/components/scroll-area/ScrollArea.vue +52 -0
  299. package/src/components/scroll-area/index.ts +1 -0
  300. package/src/components/search-input/SearchInput.vue +46 -0
  301. package/src/components/search-input/index.ts +1 -0
  302. package/src/components/select/Select.vue +15 -0
  303. package/src/components/select/SelectContent.vue +67 -0
  304. package/src/components/select/SelectGroup.vue +20 -0
  305. package/src/components/select/SelectItem.vue +59 -0
  306. package/src/components/select/SelectLabel.vue +20 -0
  307. package/src/components/select/SelectSeparator.vue +18 -0
  308. package/src/components/select/SelectTrigger.vue +101 -0
  309. package/src/components/select/SelectValue.vue +46 -0
  310. package/src/components/select/index.ts +8 -0
  311. package/src/components/separator/Separator.vue +25 -0
  312. package/src/components/separator/index.ts +1 -0
  313. package/src/components/sheet/Sheet.vue +15 -0
  314. package/src/components/sheet/SheetClose.vue +12 -0
  315. package/src/components/sheet/SheetContent.vue +45 -0
  316. package/src/components/sheet/SheetDescription.vue +19 -0
  317. package/src/components/sheet/SheetFooter.vue +12 -0
  318. package/src/components/sheet/SheetHeader.vue +12 -0
  319. package/src/components/sheet/SheetTitle.vue +19 -0
  320. package/src/components/sheet/SheetTrigger.vue +12 -0
  321. package/src/components/sheet/index.ts +10 -0
  322. package/src/components/sidebar/Sidebar.vue +108 -0
  323. package/src/components/sidebar/SidebarContent.vue +19 -0
  324. package/src/components/sidebar/SidebarFooter.vue +19 -0
  325. package/src/components/sidebar/SidebarGroup.vue +19 -0
  326. package/src/components/sidebar/SidebarGroupAction.vue +28 -0
  327. package/src/components/sidebar/SidebarGroupContent.vue +19 -0
  328. package/src/components/sidebar/SidebarGroupLabel.vue +25 -0
  329. package/src/components/sidebar/SidebarHeader.vue +19 -0
  330. package/src/components/sidebar/SidebarInput.vue +15 -0
  331. package/src/components/sidebar/SidebarInset.vue +22 -0
  332. package/src/components/sidebar/SidebarMenu.vue +19 -0
  333. package/src/components/sidebar/SidebarMenuAction.vue +41 -0
  334. package/src/components/sidebar/SidebarMenuBadge.vue +24 -0
  335. package/src/components/sidebar/SidebarMenuButton.vue +94 -0
  336. package/src/components/sidebar/SidebarMenuItem.vue +19 -0
  337. package/src/components/sidebar/SidebarMenuSkeleton.vue +36 -0
  338. package/src/components/sidebar/SidebarMenuSub.vue +22 -0
  339. package/src/components/sidebar/SidebarMenuSubButton.vue +39 -0
  340. package/src/components/sidebar/SidebarMenuSubItem.vue +19 -0
  341. package/src/components/sidebar/SidebarProvider.vue +114 -0
  342. package/src/components/sidebar/SidebarRail.vue +37 -0
  343. package/src/components/sidebar/SidebarSeparator.vue +15 -0
  344. package/src/components/sidebar/SidebarTrigger.vue +27 -0
  345. package/src/components/sidebar/context.ts +39 -0
  346. package/src/components/sidebar/index.ts +34 -0
  347. package/src/components/skeleton/Skeleton.vue +10 -0
  348. package/src/components/skeleton/index.ts +1 -0
  349. package/src/components/skip-link/SkipLink.vue +45 -0
  350. package/src/components/skip-link/index.ts +1 -0
  351. package/src/components/slider/Slider.vue +57 -0
  352. package/src/components/slider/index.ts +3 -0
  353. package/src/components/speed-dial/SpeedDial.vue +362 -0
  354. package/src/components/speed-dial/index.ts +28 -0
  355. package/src/components/spinner/Spinner.vue +20 -0
  356. package/src/components/spinner/index.ts +1 -0
  357. package/src/components/splitter/Splitter.vue +24 -0
  358. package/src/components/splitter/SplitterHandle.vue +51 -0
  359. package/src/components/splitter/SplitterPanel.vue +30 -0
  360. package/src/components/splitter/index.ts +14 -0
  361. package/src/components/stepper/Stepper.vue +34 -0
  362. package/src/components/stepper/StepperItem.vue +113 -0
  363. package/src/components/stepper/index.ts +2 -0
  364. package/src/components/switch/Switch.vue +35 -0
  365. package/src/components/switch/index.ts +1 -0
  366. package/src/components/table/Table.vue +24 -0
  367. package/src/components/table/TableBody.vue +12 -0
  368. package/src/components/table/TableCell.vue +12 -0
  369. package/src/components/table/TableEmpty.vue +20 -0
  370. package/src/components/table/TableHead.vue +17 -0
  371. package/src/components/table/TableHeader.vue +12 -0
  372. package/src/components/table/TableRow.vue +19 -0
  373. package/src/components/table/index.ts +7 -0
  374. package/src/components/tabs/Tabs.vue +23 -0
  375. package/src/components/tabs/TabsContent.vue +23 -0
  376. package/src/components/tabs/TabsList.vue +26 -0
  377. package/src/components/tabs/TabsTrigger.vue +30 -0
  378. package/src/components/tabs/index.ts +4 -0
  379. package/src/components/textarea/Textarea.vue +25 -0
  380. package/src/components/textarea/index.ts +1 -0
  381. package/src/components/theme-controls/LocaleMenu.vue +95 -0
  382. package/src/components/theme-controls/PaletteMenu.vue +155 -0
  383. package/src/components/theme-controls/ThemeToggle.vue +21 -0
  384. package/src/components/theme-controls/index.ts +15 -0
  385. package/src/components/timeline/Timeline.vue +20 -0
  386. package/src/components/timeline/TimelineItem.vue +68 -0
  387. package/src/components/timeline/index.ts +15 -0
  388. package/src/components/toast/Toaster.vue +62 -0
  389. package/src/components/toast/index.ts +4 -0
  390. package/src/components/toast/toast.ts +57 -0
  391. package/src/components/toggle/Toggle.vue +32 -0
  392. package/src/components/toggle/ToggleGroup.vue +56 -0
  393. package/src/components/toggle/ToggleGroupItem.vue +33 -0
  394. package/src/components/toggle/index.ts +18 -0
  395. package/src/components/token-table/TokenTable.vue +67 -0
  396. package/src/components/token-table/index.ts +2 -0
  397. package/src/components/toolbar/Toolbar.vue +34 -0
  398. package/src/components/toolbar/ToolbarButton.vue +33 -0
  399. package/src/components/toolbar/ToolbarSeparator.vue +21 -0
  400. package/src/components/toolbar/index.ts +3 -0
  401. package/src/components/tooltip/Tooltip.vue +15 -0
  402. package/src/components/tooltip/TooltipContent.vue +38 -0
  403. package/src/components/tooltip/TooltipProvider.vue +16 -0
  404. package/src/components/tooltip/TooltipTrigger.vue +12 -0
  405. package/src/components/tooltip/index.ts +4 -0
  406. package/src/components/tree/Tree.vue +53 -0
  407. package/src/components/tree/TreeItem.vue +59 -0
  408. package/src/components/tree/index.ts +21 -0
  409. package/src/components/tree-select/TreeSelect.vue +141 -0
  410. package/src/components/tree-select/index.ts +1 -0
  411. package/src/components/tree-table/TreeTable.vue +302 -0
  412. package/src/components/tree-table/features.ts +49 -0
  413. package/src/components/tree-table/index.ts +3 -0
  414. package/src/components/video-player/VideoPlayer.vue +472 -0
  415. package/src/components/video-player/index.ts +20 -0
  416. package/src/composables/index.ts +15 -0
  417. package/src/composables/useBase.ts +32 -0
  418. package/src/composables/useChartPalette.ts +33 -0
  419. package/src/composables/useColorMode.ts +29 -0
  420. package/src/composables/useConfirm.ts +81 -0
  421. package/src/composables/useDelayedFlag.ts +62 -0
  422. package/src/composables/useI18n.ts +107 -0
  423. package/src/composables/useIsMobile.ts +34 -0
  424. package/src/composables/useMenuAccent.ts +32 -0
  425. package/src/composables/useMenuAppearance.ts +31 -0
  426. package/src/composables/useMenuColor.ts +31 -0
  427. package/src/composables/usePalette.ts +30 -0
  428. package/src/composables/useStyle.ts +35 -0
  429. package/src/composables/useSurface.ts +30 -0
  430. package/src/composables/useTableQuery.ts +73 -0
  431. package/src/composables/useThemeController.ts +48 -0
  432. package/src/i18n/README.md +68 -0
  433. package/src/i18n/controller.ts +233 -0
  434. package/src/i18n/dictionary.ts +43 -0
  435. package/src/i18n/index.ts +34 -0
  436. package/src/i18n/registry.ts +64 -0
  437. package/src/i18n/ui/en/ui.json +114 -0
  438. package/src/i18n/ui/en/zod.json +16 -0
  439. package/src/i18n/ui/index.ts +48 -0
  440. package/src/i18n/ui/vi/ui.json +114 -0
  441. package/src/i18n/ui/vi/zod.json +16 -0
  442. package/src/lib/date.ts +24 -0
  443. package/src/lib/focus.ts +12 -0
  444. package/src/lib/icons.ts +345 -0
  445. package/src/lib/menu-styles.ts +16 -0
  446. package/src/lib/menu.ts +20 -0
  447. package/src/lib/platform.ts +5 -0
  448. package/src/lib/types.ts +6 -0
  449. package/src/lib/utils.ts +9 -0
  450. package/src/lib/zod-messages.ts +127 -0
  451. package/src/styles/chart.css +30 -0
  452. package/src/styles/index.css +18 -0
  453. package/src/variants/README.md +55 -0
  454. package/src/variants/components/accordion.ts +71 -0
  455. package/src/variants/components/alert.ts +20 -0
  456. package/src/variants/components/badge.ts +76 -0
  457. package/src/variants/components/button-group.ts +136 -0
  458. package/src/variants/components/button.ts +160 -0
  459. package/src/variants/components/checkbox.ts +67 -0
  460. package/src/variants/components/chip.ts +51 -0
  461. package/src/variants/components/code-block.ts +22 -0
  462. package/src/variants/components/dialog.ts +28 -0
  463. package/src/variants/components/empty.ts +60 -0
  464. package/src/variants/components/field.ts +35 -0
  465. package/src/variants/components/float-label.ts +95 -0
  466. package/src/variants/components/input-group.ts +73 -0
  467. package/src/variants/components/input-password.ts +68 -0
  468. package/src/variants/components/kbd.ts +47 -0
  469. package/src/variants/components/picker-trigger.ts +30 -0
  470. package/src/variants/components/radio-group.ts +63 -0
  471. package/src/variants/components/sheet.ts +23 -0
  472. package/src/variants/components/sidebar.ts +33 -0
  473. package/src/variants/components/slider.ts +49 -0
  474. package/src/variants/components/timeline.ts +45 -0
  475. package/src/variants/components/toggle.ts +58 -0
  476. package/src/variants/index.ts +35 -0
  477. package/src/variants/lib/chart/polar.ts +139 -0
  478. package/src/variants/lib/chart/tooltip.ts +101 -0
  479. package/src/variants/lib/chart/types.ts +172 -0
  480. package/src/variants/lib/chart/xy-label.ts +42 -0
  481. package/src/variants/lib/focus.ts +66 -0
  482. package/src/variants/lib/form-errors.ts +59 -0
  483. package/src/variants/lib/highlight.ts +548 -0
  484. package/src/variants/lib/list-move.ts +63 -0
  485. package/src/variants/lib/mask.ts +106 -0
  486. package/src/variants/lib/media.ts +56 -0
  487. package/src/variants/lib/menu-styles.ts +71 -0
  488. package/src/variants/lib/platform.ts +68 -0
  489. package/src/variants/lib/tree.ts +119 -0
  490. package/src/variants/lib/upload.ts +58 -0
  491. package/src/variants/lib/utils.ts +11 -0
@@ -0,0 +1,21 @@
1
+ import type { ComputedRef } from 'vue'
2
+ import type { RadioGroupItemVariants } from '../../variants/components/radio-group'
3
+ import { createContext } from 'reka-ui'
4
+
5
+ export { radioGroupItemVariants, type RadioGroupItemVariants } from '../../variants/components/radio-group'
6
+ export { default as RadioGroup } from './RadioGroup.vue'
7
+ export { default as RadioGroupItem } from './RadioGroupItem.vue'
8
+
9
+ /** Cỡ/kiểu tô/trạng thái lỗi mà `RadioGroup` truyền xuống từng nút con. */
10
+ export interface RadioGroupContext {
11
+ size: ComputedRef<RadioGroupItemVariants['size']>
12
+ tone: ComputedRef<RadioGroupItemVariants['tone']>
13
+ invalid: ComputedRef<boolean>
14
+ }
15
+
16
+ // Dùng createContext của reka thay vì tự khai InjectionKey: cùng một cơ chế với
17
+ // mọi context khác đang chạy trong cây component, và báo lỗi kèm tên component.
18
+ export const [injectRadioGroupContext, provideRadioGroupContext]
19
+ = createContext<RadioGroupContext>('RadioGroup')
20
+
21
+ export { default as RadioGroupItemField } from './RadioGroupItemField.vue'
@@ -0,0 +1,70 @@
1
+ <script setup lang="ts">
2
+ import type { RatingRootEmits, RatingRootProps } from 'reka-ui'
3
+ import type { CSSProperties } from 'vue'
4
+ import type { ClassProps } from '../../lib/types'
5
+ import { RatingItem, RatingItemIndicator, RatingRoot, useForwardPropsEmits } from 'reka-ui'
6
+ import { computed } from 'vue'
7
+ import { cn } from '../../lib/utils'
8
+ import RatingStar from './RatingStar.vue'
9
+
10
+ const props = withDefaults(
11
+ defineProps<RatingRootProps & ClassProps & {
12
+ /** Cỡ một ngôi sao. Đặt thành biến CSS để lớp rỗng và lớp đầy khớp nhau. */
13
+ size?: 'sm' | 'default' | 'lg'
14
+ }>(),
15
+ { length: 5, hoverable: true, size: 'default' },
16
+ )
17
+ const emits = defineEmits<RatingRootEmits>()
18
+
19
+ const delegated = computed(() => {
20
+ const { class: _class, size: _size, ...rest } = props
21
+ return rest
22
+ })
23
+
24
+ const forwarded = useForwardPropsEmits(delegated, emits)
25
+
26
+ const sizes = { sm: '1rem', default: '1.25rem', lg: '1.5rem' }
27
+ const style = computed<CSSProperties>(() => ({ '--rating-item-size': sizes[props.size] } as CSSProperties))
28
+ </script>
29
+
30
+ <template>
31
+ <!--
32
+ Slot mặc định dựng sẵn cả hàng sao, nên `<Rating v-model="score" />` chạy
33
+ được ngay. Truyền nội dung vào là thay hẳn — dùng khi cần icon khác hoặc
34
+ bố cục khác, và khi đó `RatingItem` / `RatingItemIndicator` vẫn export sẵn.
35
+ -->
36
+ <RatingRoot
37
+ v-bind="forwarded"
38
+ :style="style"
39
+ :class="cn(
40
+ 'inline-flex items-center gap-0.5',
41
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
42
+ props.class,
43
+ )"
44
+ >
45
+ <slot>
46
+ <RatingItem
47
+ v-for="item in props.length"
48
+ v-slot="{ steps }"
49
+ :key="item"
50
+ :item="item"
51
+ class="relative block size-(--rating-item-size) cursor-pointer"
52
+ >
53
+ <RatingStar class="absolute inset-0 text-muted-foreground/35" />
54
+ <!--
55
+ Mỗi bước là một lớp phủ bị cắt theo `--reka-rating-item-step-width`
56
+ mà reka đặt inline. Ngôi sao bên trong giữ nguyên cỡ đầy đủ, nên nửa
57
+ sao là một ngôi sao bị xén chứ không phải một ngôi sao bị bóp.
58
+ -->
59
+ <RatingItemIndicator
60
+ v-for="step in steps"
61
+ :key="step"
62
+ :step="step"
63
+ class="absolute inset-y-0 left-0 block overflow-hidden outline-none w-(--reka-rating-item-step-width) opacity-(--reka-rating-item-step-opacity) z-(--reka-rating-item-step-z-index) focus-visible:outline-none"
64
+ >
65
+ <RatingStar class="text-warning" filled />
66
+ </RatingItemIndicator>
67
+ </RatingItem>
68
+ </slot>
69
+ </RatingRoot>
70
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { RatingItemProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { RatingItem } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<RatingItemProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <!-- Slot có phạm vi trả về `steps`: một phần tử khi `step` là 1, hai khi 0.5,
18
+ và cứ thế. Bên gọi dựng một `RatingItemIndicator` cho mỗi bước. -->
19
+ <RatingItem
20
+ v-slot="{ steps }"
21
+ v-bind="delegated"
22
+ :class="cn('relative block size-(--rating-item-size) cursor-pointer', props.class)"
23
+ >
24
+ <slot :steps="steps" />
25
+ </RatingItem>
26
+ </template>
@@ -0,0 +1,28 @@
1
+ <script setup lang="ts">
2
+ import type { RatingItemIndicatorProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { RatingItemIndicator } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<RatingItemIndicatorProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <!--
18
+ KHÔNG đặt `style` ở đây: reka đã bind inline `--reka-rating-item-step-width`,
19
+ `-opacity` và `-z-index` lên chính element này. Thêm style của mình vào là
20
+ tranh chỗ với nó, mà mấy biến đó chính là thứ vẽ ra nửa sao.
21
+ -->
22
+ <RatingItemIndicator
23
+ v-bind="delegated"
24
+ :class="cn('absolute inset-y-0 left-0 block overflow-hidden outline-none w-(--reka-rating-item-step-width) opacity-(--reka-rating-item-step-opacity) z-(--reka-rating-item-step-z-index)', props.class)"
25
+ >
26
+ <slot />
27
+ </RatingItemIndicator>
28
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { Star } from '../../lib/icons'
4
+ import { cn } from '../../lib/utils'
5
+
6
+ const props = defineProps<ClassProps & { filled?: boolean }>()
7
+ </script>
8
+
9
+ <template>
10
+ <!-- `max-w-none` giữ ngôi sao ở đúng cỡ ngay cả khi lớp phủ đã bị cắt hẹp —
11
+ thiếu nó thì nửa sao thành sao bị bóp méo thay vì sao bị xén. -->
12
+ <Star
13
+ :class="cn('size-(--rating-item-size) max-w-none', props.filled && 'fill-current', props.class)"
14
+ aria-hidden="true"
15
+ />
16
+ </template>
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Chấm sao. `<Rating v-model="score" />` là đủ — slot mặc định dựng sẵn cả hàng.
3
+ *
4
+ * Nửa sao (`step="0.5"`) không phải một icon riêng: reka chia mỗi ngôi sao thành
5
+ * mấy bước, mỗi bước là một lớp phủ bị **cắt** theo bề rộng, và ngôi sao bên
6
+ * trong giữ nguyên cỡ đầy đủ. Vì vậy `RatingStar` khai `max-w-none` — thiếu nó
7
+ * thì nửa sao thành ngôi sao bị bóp méo.
8
+ */
9
+
10
+ export { default as Rating } from './Rating.vue'
11
+ export { default as RatingItem } from './RatingItem.vue'
12
+ export { default as RatingItemIndicator } from './RatingItemIndicator.vue'
13
+ export { default as RatingStar } from './RatingStar.vue'
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import type { ScrollAreaRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import {
5
+ ScrollAreaCorner,
6
+ ScrollAreaRoot,
7
+ ScrollAreaScrollbar,
8
+ ScrollAreaThumb,
9
+ ScrollAreaViewport,
10
+ } from 'reka-ui'
11
+ import { computed } from 'vue'
12
+ import { cn } from '../../lib/utils'
13
+
14
+ const props = withDefaults(
15
+ defineProps<ScrollAreaRootProps & ClassProps & {
16
+ orientation?: 'vertical' | 'horizontal' | 'both'
17
+ viewportClass?: string
18
+ }>(),
19
+ { orientation: 'vertical' },
20
+ )
21
+
22
+ const delegated = computed(() => {
23
+ const { class: _class, orientation: _orientation, viewportClass: _viewportClass, ...rest } = props
24
+ return rest
25
+ })
26
+ </script>
27
+
28
+ <template>
29
+ <ScrollAreaRoot v-bind="delegated" :class="cn('relative overflow-hidden', props.class)">
30
+ <ScrollAreaViewport :class="cn('size-full rounded-[inherit]', props.viewportClass)">
31
+ <slot />
32
+ </ScrollAreaViewport>
33
+
34
+ <ScrollAreaScrollbar
35
+ v-if="props.orientation !== 'horizontal'"
36
+ orientation="vertical"
37
+ class="flex w-2 touch-none select-none border-l border-l-transparent p-px transition-colors"
38
+ >
39
+ <ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
40
+ </ScrollAreaScrollbar>
41
+
42
+ <ScrollAreaScrollbar
43
+ v-if="props.orientation !== 'vertical'"
44
+ orientation="horizontal"
45
+ class="flex h-2 touch-none select-none border-t border-t-transparent p-px transition-colors"
46
+ >
47
+ <ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
48
+ </ScrollAreaScrollbar>
49
+
50
+ <ScrollAreaCorner />
51
+ </ScrollAreaRoot>
52
+ </template>
@@ -0,0 +1 @@
1
+ export { default as ScrollArea } from './ScrollArea.vue'
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { computed } from 'vue'
4
+ import { Search } from '../../lib/icons'
5
+ import { cn } from '../../lib/utils'
6
+ import Input from '../input/Input.vue'
7
+
8
+ /**
9
+ * Gốc là cái vỏ `<div class="relative">` chứ không phải ô nhập, nên thuộc tính
10
+ * rơi tự do (`aria-label`, `id`, `disabled`, `name`) phải chuyển tay xuống
11
+ * `Input` — để mặc định thì chúng đáp xuống cái div và `<Label for>` trỏ vào
12
+ * hư không. `class` vẫn ở vỏ vì nó là thứ đặt bề rộng.
13
+ */
14
+ defineOptions({ inheritAttrs: false })
15
+
16
+ const props = withDefaults(
17
+ defineProps<ClassProps & {
18
+ placeholder?: string
19
+ size?: 'sm' | 'default'
20
+ }>(),
21
+ { size: 'sm' },
22
+ )
23
+
24
+ const model = defineModel<string>({ default: '' })
25
+
26
+ const iconClass = computed(() =>
27
+ props.size === 'sm' ? 'left-2.5 size-3.5' : 'left-3 size-4',
28
+ )
29
+ </script>
30
+
31
+ <template>
32
+ <div :class="cn('relative', props.class)">
33
+ <Search
34
+ :class="cn('pointer-events-none absolute top-1/2 -translate-y-1/2 text-muted-foreground', iconClass)"
35
+ aria-hidden="true"
36
+ />
37
+ <Input
38
+ v-bind="$attrs"
39
+ v-model="model"
40
+ type="search"
41
+ :size="props.size"
42
+ :placeholder="props.placeholder"
43
+ :class="props.size === 'sm' ? 'pl-8' : 'pl-9'"
44
+ />
45
+ </div>
46
+ </template>
@@ -0,0 +1 @@
1
+ export { default as SearchInput } from './SearchInput.vue'
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts" generic="T extends AcceptableValue = AcceptableValue">
2
+ import type { AcceptableValue, SelectRootEmits, SelectRootProps } from 'reka-ui'
3
+ import { SelectRoot, useForwardPropsEmits } from 'reka-ui'
4
+
5
+ const props = defineProps<SelectRootProps<T>>()
6
+ const emits = defineEmits<SelectRootEmits<T>>()
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits)
9
+ </script>
10
+
11
+ <template>
12
+ <SelectRoot v-bind="forwarded">
13
+ <slot />
14
+ </SelectRoot>
15
+ </template>
@@ -0,0 +1,67 @@
1
+ <script setup lang="ts">
2
+ import type { SelectContentEmits, SelectContentProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import {
5
+ injectSelectRootContext,
6
+ SelectContent,
7
+ SelectPortal,
8
+ SelectScrollDownButton,
9
+ SelectScrollUpButton,
10
+ SelectViewport,
11
+ useForwardPropsEmits,
12
+ } from 'reka-ui'
13
+ import { computed } from 'vue'
14
+ import { ChevronDown, ChevronUp } from '../../lib/icons'
15
+ import { cn } from '../../lib/utils'
16
+
17
+ const props = withDefaults(
18
+ defineProps<SelectContentProps & ClassProps>(),
19
+ { position: 'popper', sideOffset: 6 },
20
+ )
21
+ const emits = defineEmits<SelectContentEmits>()
22
+
23
+ const delegated = computed(() => {
24
+ const { class: _class, ...rest } = props
25
+ return rest
26
+ })
27
+
28
+ const forwarded = useForwardPropsEmits(delegated, emits)
29
+
30
+ // reka không đặt `aria-multiselectable` khi bật `multiple`, mà APG đòi listbox
31
+ // chọn nhiều phải khai — nếu không trình đọc màn hình vẫn nói "chọn một".
32
+ const rootContext = injectSelectRootContext()
33
+ const multiselectable = computed(() => rootContext.multiple.value || undefined)
34
+ </script>
35
+
36
+ <template>
37
+ <SelectPortal>
38
+ <SelectContent
39
+ v-bind="forwarded"
40
+ :aria-multiselectable="multiselectable"
41
+ :class="cn(
42
+ // `ui-menu` + `bg-menu-surface` cho khớp `menuContentClass`: Select là
43
+ // một menu, nên hai trục `data-menu-color` / `data-menu-appearance` phải
44
+ // với tới nó. Nó không dùng chung chuỗi class kia vì còn có nút cuộn
45
+ // trên/dưới và phần định vị riêng.
46
+ 'ui-menu surface relative z-(--z-overlay) max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-menu-surface text-popover-foreground shadow-md',
47
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
48
+ 'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',
49
+ 'data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95',
50
+ props.position === 'popper' && 'w-full min-w-[var(--reka-select-trigger-width)]',
51
+ props.class,
52
+ )"
53
+ >
54
+ <SelectScrollUpButton class="flex h-6 cursor-default items-center justify-center text-muted-foreground">
55
+ <ChevronUp class="size-4" />
56
+ </SelectScrollUpButton>
57
+
58
+ <SelectViewport :class="cn('p-1', props.position === 'popper' && 'max-h-[var(--reka-select-content-available-height)]')">
59
+ <slot />
60
+ </SelectViewport>
61
+
62
+ <SelectScrollDownButton class="flex h-6 cursor-default items-center justify-center text-muted-foreground">
63
+ <ChevronDown class="size-4" />
64
+ </SelectScrollDownButton>
65
+ </SelectContent>
66
+ </SelectPortal>
67
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { SelectGroupProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SelectGroup } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<SelectGroupProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <SelectGroup v-bind="delegated" :class="cn('p-1', props.class)">
18
+ <slot />
19
+ </SelectGroup>
20
+ </template>
@@ -0,0 +1,59 @@
1
+ <script setup lang="ts">
2
+ import type { SelectItemEmits, SelectItemProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SelectItem, SelectItemIndicator, SelectItemText, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { Check } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ // Không đặt generic ở đây: generic làm TS mất thông tin "value là bắt buộc"
10
+ // khi forward prop xuống SelectItem của reka. Kiểu của value vẫn là
11
+ // AcceptableValue (string | number | bigint | Record | null), đủ dùng.
12
+ const props = defineProps<SelectItemProps & ClassProps & {
13
+ /**
14
+ * Ô đánh dấu bên trái thay cho dấu tick bên phải — dành cho chế độ nhiều,
15
+ * nơi "đang chọn" của từng dòng phải đọc ra như một công tắc. Trạng thái lấy
16
+ * từ `data-state` mà reka đặt trên chính dòng, qua `group-data-*`.
17
+ */
18
+ checkbox?: boolean
19
+ }>()
20
+ const emits = defineEmits<SelectItemEmits>()
21
+
22
+ const delegated = computed(() => {
23
+ const { class: _class, checkbox: _checkbox, ...rest } = props
24
+ return rest
25
+ })
26
+
27
+ const forwarded = useForwardPropsEmits(delegated, emits)
28
+ </script>
29
+
30
+ <template>
31
+ <SelectItem
32
+ v-bind="forwarded"
33
+ :class="cn(
34
+ 'group relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 text-sm outline-none transition-colors',
35
+ props.checkbox ? 'pr-2' : 'pr-8',
36
+ 'focus:bg-accent focus:text-accent-foreground',
37
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
38
+ props.class,
39
+ )"
40
+ >
41
+ <span
42
+ v-if="props.checkbox"
43
+ aria-hidden="true"
44
+ class="flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background shadow-xs transition-colors group-data-[state=checked]:border-primary group-data-[state=checked]:bg-primary group-data-[state=checked]:text-primary-foreground"
45
+ >
46
+ <SelectItemIndicator>
47
+ <Check class="size-3.5" />
48
+ </SelectItemIndicator>
49
+ </span>
50
+ <SelectItemText>
51
+ <slot />
52
+ </SelectItemText>
53
+ <span v-if="!props.checkbox" class="absolute right-2 flex size-4 items-center justify-center">
54
+ <SelectItemIndicator>
55
+ <Check class="size-4" />
56
+ </SelectItemIndicator>
57
+ </span>
58
+ </SelectItem>
59
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { SelectLabelProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SelectLabel } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<SelectLabelProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <SelectLabel v-bind="delegated" :class="cn('px-2 py-1.5 text-xs font-medium text-muted-foreground', props.class)">
18
+ <slot />
19
+ </SelectLabel>
20
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ import type { SelectSeparatorProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SelectSeparator } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<SelectSeparatorProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <SelectSeparator v-bind="delegated" :class="cn('-mx-1 my-1 h-px bg-border', props.class)" />
18
+ </template>
@@ -0,0 +1,101 @@
1
+ <script setup lang="ts">
2
+ import type { SelectTriggerProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { injectSelectRootContext, SelectIcon, SelectTrigger } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { focusRing, invalidRing } from '../../lib/focus'
8
+ import { ChevronDown, X } from '../../lib/icons'
9
+ import { cn } from '../../lib/utils'
10
+ import Spinner from '../spinner/Spinner.vue'
11
+
12
+ /**
13
+ * Gốc là một `<div>` bọc ngoài chứ không phải chính cái nút: nút × xoá giá trị
14
+ * phải là `<button>` thật, mà button không được lồng trong button. Nó nằm CẠNH
15
+ * trigger, đặt chồng lên bằng `absolute`. Thuộc tính rơi tự do (`id`,
16
+ * `aria-invalid` từ FormField…) vì vậy phải chuyển tay xuống nút.
17
+ */
18
+ defineOptions({ inheritAttrs: false })
19
+
20
+ const props = defineProps<SelectTriggerProps & ClassProps & {
21
+ invalid?: boolean
22
+ size?: 'sm' | 'default'
23
+ /**
24
+ * Nút × xoá giá trị, chỉ hiện khi đang có giá trị. Bàn phím: `Delete` hoặc
25
+ * `Backspace` lúc trigger đang focus — nút × để `tabindex="-1"` nên không
26
+ * thêm một điểm dừng Tab cho mỗi select trong form.
27
+ */
28
+ clearable?: boolean
29
+ /** Thay mũi tên bằng spinner và khai `aria-busy`. Vẫn mở được. */
30
+ loading?: boolean
31
+ }>()
32
+
33
+ const { t } = useI18n()
34
+ const rootContext = injectSelectRootContext()
35
+
36
+ const delegated = computed(() => {
37
+ const { class: _class, invalid: _invalid, size: _size, clearable: _clearable, loading: _loading, ...rest } = props
38
+ return rest
39
+ })
40
+
41
+ const showClear = computed(() =>
42
+ props.clearable === true
43
+ && !rootContext.isEmptyModelValue.value
44
+ && !rootContext.disabled?.value,
45
+ )
46
+
47
+ function clear() {
48
+ rootContext.modelValue.value = rootContext.multiple.value ? [] : undefined
49
+ }
50
+
51
+ function onKeydown(event: KeyboardEvent) {
52
+ if (!showClear.value || (event.key !== 'Delete' && event.key !== 'Backspace'))
53
+ return
54
+ event.preventDefault()
55
+ clear()
56
+ }
57
+ </script>
58
+
59
+ <template>
60
+ <div :class="cn('relative', props.class)">
61
+ <SelectTrigger
62
+ v-bind="{ ...delegated, ...$attrs }"
63
+ :aria-invalid="props.invalid || undefined"
64
+ :aria-busy="props.loading || undefined"
65
+ :data-invalid="props.invalid || undefined"
66
+ :class="cn(
67
+ 'flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs transition-colors',
68
+ // `min-h` chứ không `h`: giá trị dạng chip xuống hàng thì trigger phải cao lên theo.
69
+ props.size === 'sm' ? 'min-h-8' : 'min-h-9',
70
+ 'data-[placeholder]:text-muted-foreground',
71
+ 'focus:outline-none',
72
+ focusRing,
73
+ 'disabled:cursor-not-allowed disabled:opacity-50',
74
+ invalidRing,
75
+ '[&>span]:truncate [&>span]:text-left',
76
+ // Chừa chỗ cho nút × (16px) và khoảng cách tới nó (8px).
77
+ showClear && '[&>[data-slot=select-value]]:mr-6',
78
+ // Mũi tên xoay theo `data-state` mà reka đặt trên trigger — không JS.
79
+ '[&[data-state=open]>svg]:rotate-180',
80
+ )"
81
+ @keydown="onKeydown"
82
+ >
83
+ <slot />
84
+ <Spinner v-if="props.loading" class="shrink-0 text-muted-foreground" />
85
+ <SelectIcon v-else as-child>
86
+ <ChevronDown class="size-4 shrink-0 text-muted-foreground transition-transform duration-(--duration-base) motion-reduce:transition-none" />
87
+ </SelectIcon>
88
+ </SelectTrigger>
89
+
90
+ <button
91
+ v-if="showClear"
92
+ type="button"
93
+ tabindex="-1"
94
+ :aria-label="t('ui.select.clear')"
95
+ class="absolute top-1/2 right-9 grid size-4 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground transition-colors hover:text-foreground"
96
+ @click="clear"
97
+ >
98
+ <X class="size-3.5" />
99
+ </button>
100
+ </div>
101
+ </template>
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import type { SelectValueProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SelectValue } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+ import { badgeVariants } from '../badge'
8
+ import { chipVariants } from '../chip'
9
+
10
+ const props = defineProps<SelectValueProps & ClassProps & {
11
+ /**
12
+ * Chế độ nhiều: mỗi nhãn đã chọn là một chip, thay vì chuỗi nối dấu phẩy.
13
+ * Chip chỉ để nhìn — nút gỡ trên chip sẽ là button lồng trong button.
14
+ */
15
+ chips?: boolean
16
+ }>()
17
+
18
+ const delegated = computed(() => {
19
+ const { class: _class, chips: _chips, ...rest } = props
20
+ return rest
21
+ })
22
+
23
+ const chipClass = cn(badgeVariants({ variant: 'secondary' }), chipVariants({ size: 'sm', removable: false }))
24
+ </script>
25
+
26
+ <template>
27
+ <!--
28
+ Phải chuyển tiếp slot scope: reka trả `selectedLabel` và `modelValue` qua
29
+ slot, viết `<slot />` trần là bên gọi nhận `undefined` mà không có gì báo.
30
+
31
+ Nhánh chip chỉ render khi CÓ giá trị; còn lại để rỗng để reka rơi về nội
32
+ dung mặc định của nó (nhãn nối dấu phẩy, hoặc placeholder).
33
+ -->
34
+ <SelectValue
35
+ v-slot="scope"
36
+ v-bind="delegated"
37
+ data-slot="select-value"
38
+ :class="cn('truncate', props.chips && 'flex flex-wrap gap-1', props.class)"
39
+ >
40
+ <slot v-bind="scope">
41
+ <template v-if="props.chips && scope.selectedLabel.length">
42
+ <span v-for="label in scope.selectedLabel" :key="label" :class="chipClass">{{ label }}</span>
43
+ </template>
44
+ </slot>
45
+ </SelectValue>
46
+ </template>
@@ -0,0 +1,8 @@
1
+ export { default as Select } from './Select.vue'
2
+ export { default as SelectContent } from './SelectContent.vue'
3
+ export { default as SelectGroup } from './SelectGroup.vue'
4
+ export { default as SelectItem } from './SelectItem.vue'
5
+ export { default as SelectLabel } from './SelectLabel.vue'
6
+ export { default as SelectSeparator } from './SelectSeparator.vue'
7
+ export { default as SelectTrigger } from './SelectTrigger.vue'
8
+ export { default as SelectValue } from './SelectValue.vue'