@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,69 @@
1
+ <script setup lang="ts" generic="TData extends RowData">
2
+ import type { RowData, Table } from '@tanstack/vue-table'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import type { DataTableFeatures } from './features'
5
+ import { computed } from 'vue'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { ChevronDown } from '../../lib/icons'
8
+ import { cn } from '../../lib/utils'
9
+ import DropdownMenu from '../dropdown-menu/DropdownMenu.vue'
10
+ import DropdownMenuCheckboxItem from '../dropdown-menu/DropdownMenuCheckboxItem.vue'
11
+ import DropdownMenuContent from '../dropdown-menu/DropdownMenuContent.vue'
12
+ import DropdownMenuLabel from '../dropdown-menu/DropdownMenuLabel.vue'
13
+ import DropdownMenuSeparator from '../dropdown-menu/DropdownMenuSeparator.vue'
14
+ import DropdownMenuTrigger from '../dropdown-menu/DropdownMenuTrigger.vue'
15
+
16
+ /**
17
+ * Gốc là `DropdownMenu`, một provider KHÔNG vẽ ra DOM — thuộc tính rơi tự do
18
+ * không có chỗ đáp và biến mất hẳn. Chuyển tay xuống chính cái trigger.
19
+ */
20
+ defineOptions({ inheritAttrs: false })
21
+
22
+ const props = defineProps<ClassProps & {
23
+ table: Table<DataTableFeatures, TData>
24
+ }>()
25
+ const { t } = useI18n()
26
+ /**
27
+ * Chỉ liệt kê cột có thể ẩn. Cột điều khiển (checkbox chọn dòng, nút hành động)
28
+ * nên đặt enableHiding: false trong column def để không lọt vào đây.
29
+ */
30
+ const hideableColumns = computed(() =>
31
+ props.table.getAllLeafColumns().filter(column => column.getCanHide()),
32
+ )
33
+
34
+ function labelOf(columnId: string, header: unknown): string {
35
+ return typeof header === 'string' && header.length > 0 ? header : columnId
36
+ }
37
+ </script>
38
+
39
+ <template>
40
+ <DropdownMenu>
41
+ <DropdownMenuTrigger
42
+ v-bind="$attrs"
43
+ :class="cn(
44
+ 'flex h-(--ui-field-height-sm) items-center gap-1.5 rounded-md border border-border px-(--ui-field-padding-x-sm)',
45
+ 'text-[11.5px] font-medium transition-colors hover:bg-muted',
46
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
47
+ props.class,
48
+ )"
49
+ >
50
+ {{ t('ui.table.columnsTrigger') }}
51
+ <ChevronDown class="size-3 text-muted-foreground" />
52
+ </DropdownMenuTrigger>
53
+
54
+ <DropdownMenuContent align="end" class="w-48">
55
+ <DropdownMenuLabel>{{ t('ui.table.columns') }}</DropdownMenuLabel>
56
+ <DropdownMenuSeparator />
57
+
58
+ <DropdownMenuCheckboxItem
59
+ v-for="column in hideableColumns"
60
+ :key="column.id"
61
+ :model-value="column.getIsVisible()"
62
+ @select="(event: Event) => event.preventDefault()"
63
+ @update:model-value="(value: boolean) => column.toggleVisibility(value)"
64
+ >
65
+ {{ labelOf(column.id, column.columnDef.header) }}
66
+ </DropdownMenuCheckboxItem>
67
+ </DropdownMenuContent>
68
+ </DropdownMenu>
69
+ </template>
@@ -0,0 +1,87 @@
1
+ import type { CellData, ColumnDef, RowData } from '@tanstack/vue-table'
2
+ import {
3
+ columnFilteringFeature,
4
+ columnPinningFeature,
5
+ columnSizingFeature,
6
+ columnVisibilityFeature,
7
+ createFilteredRowModel,
8
+ createPaginatedRowModel,
9
+ createSortedRowModel,
10
+ filterFn_equals,
11
+ filterFn_includesString,
12
+ filterFn_inNumberRange,
13
+ rowPaginationFeature,
14
+ rowSelectionFeature,
15
+ rowSortingFeature,
16
+ sortFn_alphanumeric,
17
+ sortFn_basic,
18
+ sortFn_datetime,
19
+ sortFn_text,
20
+ tableFeatures,
21
+ } from '@tanstack/vue-table'
22
+
23
+ /**
24
+ * Kiểu của `columnDef.meta`.
25
+ *
26
+ * v9 cho khai kiểu này qua slot `columnMeta` của tableFeatures — dùng cách đó
27
+ * thay vì `declare module`: augment sẽ cần `@tanstack/table-core` là dependency
28
+ * trực tiếp, mà nó chỉ là dependency gián tiếp của `@tanstack/vue-table`.
29
+ */
30
+ export interface DataTableColumnMeta {
31
+ /**
32
+ * Căn chữ cho cả header và ô. Mặc định 'left'.
33
+ *
34
+ * `'number'` không phải một kiểu căn — nó nói cột này CHỨA SỐ, và kéo theo
35
+ * hai thứ luôn đi cùng nhau: căn phải + `tabular-nums`.
36
+ *
37
+ * Tách riêng khỏi `'right'` vì `'right'` một mình là chưa đủ: font mặc định
38
+ * (Geist) dùng chữ số tỉ lệ, nên `1.111` hẹp hơn `8.888` và cột số căn phải
39
+ * vẫn so le từng hàng. Phải có tabular figures thì các chữ số mới xếp thành
40
+ * lưới dọc quét được bằng mắt — vốn là lý do duy nhất để căn phải cột số.
41
+ *
42
+ * Để bên gọi tự nhớ `class: 'text-right tabular-nums'` thì kiểu gì cũng có
43
+ * bảng quên một nửa.
44
+ */
45
+ align?: 'left' | 'center' | 'right' | 'number'
46
+ }
47
+
48
+ /**
49
+ * v9 không bật feature nào sẵn — phải khai báo tường minh.
50
+ * Chỉ đăng ký đúng những gì DataTable cần, để bundle không kéo theo
51
+ * grouping / expanding / resizing khi không dùng.
52
+ *
53
+ * Row model client-side vẫn đăng ký cả khi chạy server-side: ở chế độ
54
+ * serverSide ta bật manual* nên các row model đó bị bỏ qua, đổi lại
55
+ * một component duy nhất phục vụ được cả hai chế độ.
56
+ */
57
+ export const dataTableFeatures = tableFeatures({
58
+ columnVisibilityFeature,
59
+ columnPinningFeature,
60
+ columnSizingFeature,
61
+ columnFilteringFeature,
62
+ filteredRowModel: createFilteredRowModel(),
63
+ filterFns: {
64
+ includesString: filterFn_includesString,
65
+ equals: filterFn_equals,
66
+ inNumberRange: filterFn_inNumberRange,
67
+ },
68
+ rowSortingFeature,
69
+ sortedRowModel: createSortedRowModel(),
70
+ sortFns: {
71
+ alphanumeric: sortFn_alphanumeric,
72
+ text: sortFn_text,
73
+ datetime: sortFn_datetime,
74
+ basic: sortFn_basic,
75
+ },
76
+ rowPaginationFeature,
77
+ paginatedRowModel: createPaginatedRowModel(),
78
+ rowSelectionFeature,
79
+
80
+ columnMeta: {} as DataTableColumnMeta,
81
+ })
82
+
83
+ export type DataTableFeatures = typeof dataTableFeatures
84
+
85
+ /** Kiểu column def đã gắn sẵn feature set — dùng ở app thay cho ColumnDef thô. */
86
+ export type DataTableColumn<TData extends RowData, TValue extends CellData = CellData>
87
+ = ColumnDef<DataTableFeatures, TData, TValue>
@@ -0,0 +1,27 @@
1
+ export { default as DataTable } from './DataTable.vue'
2
+ export { default as DataTableFacetedFilter } from './DataTableFacetedFilter.vue'
3
+ export type { FacetOption } from './DataTableFacetedFilter.vue'
4
+ export { default as DataTablePagination } from './DataTablePagination.vue'
5
+ export { default as DataTableViewOptions } from './DataTableViewOptions.vue'
6
+ export type { DataTableColumn, DataTableFeatures } from './features'
7
+ export { dataTableFeatures } from './features'
8
+ export {
9
+ createCustomAdapter,
10
+ createPageNumberAdapter,
11
+ createSkipTakeAdapter,
12
+ } from './pagination-adapter'
13
+ export { createSelectionColumn } from './selection-column'
14
+ export type {
15
+ PageNumberParams,
16
+ PaginationAdapter,
17
+ SkipTakeParams,
18
+ TableQuery,
19
+ } from './types'
20
+ // Re-export type state của TanStack: app không được import thẳng
21
+ // @tanstack/vue-table (nó không phải dependency của apps/admin).
22
+ export type {
23
+ ColumnFiltersState,
24
+ PaginationState,
25
+ RowSelectionState,
26
+ SortingState,
27
+ } from '@tanstack/vue-table'
@@ -0,0 +1,67 @@
1
+ import type {
2
+ PageNumberParams,
3
+ PaginationAdapter,
4
+ SkipTakeParams,
5
+ TableQuery,
6
+ } from './types'
7
+
8
+ function toFilterRecord(query: TableQuery): Record<string, unknown> | undefined {
9
+ if (query.filters.length === 0)
10
+ return undefined
11
+
12
+ return Object.fromEntries(query.filters.map(f => [f.id, f.value]))
13
+ }
14
+
15
+ /**
16
+ * Backend nhận `page` (1-based), `pageSize`, `sortBy`, `sortDir`.
17
+ *
18
+ * const adapter = createPageNumberAdapter()
19
+ * const params = adapter.toParams(query)
20
+ * // { page: 1, pageSize: 20, sortBy: 'createdAt', sortDir: 'desc' }
21
+ */
22
+ export function createPageNumberAdapter(): PaginationAdapter<PageNumberParams> {
23
+ return {
24
+ toParams(query) {
25
+ const primarySort = query.sorting[0]
26
+
27
+ return {
28
+ page: query.pageIndex + 1,
29
+ pageSize: query.pageSize,
30
+ sortBy: primarySort?.id,
31
+ sortDir: primarySort ? (primarySort.desc ? 'desc' : 'asc') : undefined,
32
+ filters: toFilterRecord(query),
33
+ }
34
+ },
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Backend nhận `skip` / `take` và chuỗi `orderBy` kiểu OData ("name desc").
40
+ */
41
+ export function createSkipTakeAdapter(): PaginationAdapter<SkipTakeParams> {
42
+ return {
43
+ toParams(query) {
44
+ const orderBy = query.sorting
45
+ .map(sort => `${sort.id} ${sort.desc ? 'desc' : 'asc'}`)
46
+ .join(', ')
47
+
48
+ return {
49
+ skip: query.pageIndex * query.pageSize,
50
+ take: query.pageSize,
51
+ orderBy: orderBy.length > 0 ? orderBy : undefined,
52
+ filters: toFilterRecord(query),
53
+ }
54
+ },
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Khi backend có quy ước riêng: tự viết hàm map, vẫn giữ được kiểu.
60
+ *
61
+ * const adapter = createCustomAdapter(q => ({ offset: q.pageIndex * q.pageSize }))
62
+ */
63
+ export function createCustomAdapter<TParams>(
64
+ toParams: (query: TableQuery) => TParams,
65
+ ): PaginationAdapter<TParams> {
66
+ return { toParams }
67
+ }
@@ -0,0 +1,48 @@
1
+ import type { RowData } from '@tanstack/vue-table'
2
+ import type { DataTableColumn } from './features'
3
+ import { h } from 'vue'
4
+ import { translate } from '../../composables/useI18n'
5
+ import Checkbox from '../checkbox/Checkbox.vue'
6
+
7
+ /**
8
+ * Cột checkbox chọn dòng. Đặt ở đầu mảng columns:
9
+ *
10
+ * const columns = [createSelectionColumn<User>(), ...]
11
+ *
12
+ * Cột này không sort / không ẩn được / không lọt vào menu "Cột".
13
+ *
14
+ * Nhãn đi qua `translate` chứ không `useI18n`: đây là hàm thường, không phải
15
+ * component, nên không gọi được composable có `onMounted`. Vẫn reactive vì hai
16
+ * hàm render bên dưới chạy trong effect render của bảng.
17
+ */
18
+ export function createSelectionColumn<TData extends RowData>(): DataTableColumn<TData> {
19
+ return {
20
+ id: '__select',
21
+ size: 40,
22
+ enableSorting: false,
23
+ enableHiding: false,
24
+ header: ({ table }) =>
25
+ h(Checkbox, {
26
+ 'modelValue': table.getIsAllPageRowsSelected()
27
+ ? true
28
+ : table.getIsSomePageRowsSelected()
29
+ ? 'indeterminate'
30
+ : false,
31
+ 'aria-label': translate('ui.table.selectAll'),
32
+ 'onUpdate:modelValue': (value: boolean | 'indeterminate') => {
33
+ table.toggleAllPageRowsSelected(value === true)
34
+ },
35
+ }),
36
+ cell: ({ row }) =>
37
+ h(Checkbox, {
38
+ 'modelValue': row.getIsSelected(),
39
+ 'disabled': !row.getCanSelect(),
40
+ 'aria-label': translate('ui.table.selectRow'),
41
+ 'onUpdate:modelValue': (value: boolean | 'indeterminate') => {
42
+ row.toggleSelected(value === true)
43
+ },
44
+ // Chọn dòng không được kéo theo sự kiện click của cả hàng.
45
+ 'onClick': (event: Event) => event.stopPropagation(),
46
+ }),
47
+ }
48
+ }
@@ -0,0 +1,36 @@
1
+ import type { ColumnFiltersState, SortingState } from '@tanstack/vue-table'
2
+
3
+ /**
4
+ * Trạng thái truy vấn mà DataTable phát ra. Cố tình trung lập với backend:
5
+ * DataTable không biết .NET dùng page/pageSize hay skip/take.
6
+ * Việc dịch sang tham số thật do adapter lo (xem pagination-adapter.ts).
7
+ */
8
+ export interface TableQuery {
9
+ /** 0-based, dùng nguyên bản của TanStack */
10
+ pageIndex: number
11
+ pageSize: number
12
+ sorting: SortingState
13
+ filters: ColumnFiltersState
14
+ }
15
+
16
+ /** Tham số kiểu page number — PagedList, X.PagedList... */
17
+ export interface PageNumberParams {
18
+ page: number
19
+ pageSize: number
20
+ sortBy?: string
21
+ sortDir?: 'asc' | 'desc'
22
+ filters?: Record<string, unknown>
23
+ }
24
+
25
+ /** Tham số kiểu offset — OData, EF Core raw. */
26
+ export interface SkipTakeParams {
27
+ skip: number
28
+ take: number
29
+ orderBy?: string
30
+ filters?: Record<string, unknown>
31
+ }
32
+
33
+ export interface PaginationAdapter<TParams> {
34
+ /** Biến TableQuery thành query string params gửi cho API. */
35
+ toParams: (query: TableQuery) => TParams
36
+ }
@@ -0,0 +1,136 @@
1
+ <script setup lang="ts" generic="TItem">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { TableQuery } from '../data-table/types'
4
+ import { computed, ref, watch } from 'vue'
5
+ import { useI18n } from '../../composables/useI18n'
6
+ import { LayoutGrid, List } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+ import Button from '../button/Button.vue'
9
+ import Empty from '../empty/Empty.vue'
10
+ import Pagination from '../pagination/Pagination.vue'
11
+ import Spinner from '../spinner/Spinner.vue'
12
+
13
+ const props = withDefaults(
14
+ defineProps<ClassProps & {
15
+ items: TItem[]
16
+ /** Khoá duy nhất của một mục. Bắt buộc — `index` không sống sót qua sắp xếp. */
17
+ itemKey: (item: TItem, index: number) => string | number
18
+ /** Backend lo phân trang; khi đó `totalRecords` là bắt buộc. */
19
+ serverSide?: boolean
20
+ totalRecords?: number
21
+ pageSize?: number
22
+ paginate?: boolean
23
+ loading?: boolean
24
+ emptyMessage?: string
25
+ /** Cho người dùng đổi giữa danh sách và lưới. */
26
+ switchable?: boolean
27
+ /** Lớp lưới khi ở chế độ `grid`. Số cột là chuyện của trang, không phải của đây. */
28
+ gridClass?: string
29
+ }>(),
30
+ {
31
+ serverSide: false,
32
+ pageSize: 12,
33
+ paginate: true,
34
+ loading: false,
35
+ switchable: true,
36
+ gridClass: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
37
+ },
38
+ )
39
+
40
+ const emit = defineEmits<{ 'page-change': [query: TableQuery] }>()
41
+
42
+ const layout = defineModel<'list' | 'grid'>('layout', { default: 'list' })
43
+
44
+ const { t } = useI18n()
45
+
46
+ const pageIndex = ref(0)
47
+
48
+ const total = computed(() =>
49
+ props.serverSide ? props.totalRecords ?? 0 : props.items.length,
50
+ )
51
+
52
+ /**
53
+ * Chế độ server-side thì KHÔNG tự cắt mảng.
54
+ *
55
+ * Cắt tiếp một trang mà backend đã cắt sẵn là hiện ra một trang của một trang —
56
+ * lỗi im lặng vì nó chỉ lộ ra khi tổng số vượt quá `pageSize`.
57
+ */
58
+ const visible = computed(() => {
59
+ if (props.serverSide || !props.paginate)
60
+ return props.items
61
+ const start = pageIndex.value * props.pageSize
62
+ return props.items.slice(start, start + props.pageSize)
63
+ })
64
+
65
+ /** Cùng hình dạng `TableQuery` mà DataTable phát ra, nên dùng chung adapter. */
66
+ function query(): TableQuery {
67
+ return { pageIndex: pageIndex.value, pageSize: props.pageSize, sorting: [], filters: [] }
68
+ }
69
+
70
+ watch(pageIndex, () => emit('page-change', query()))
71
+
72
+ // Lọc lại ở tầng trên làm số trang co lại; đứng ở trang 7 của một danh sách còn
73
+ // 2 trang thì màn hình trống trơn mà không có gì nói vì sao.
74
+ watch(total, (value) => {
75
+ const last = Math.max(0, Math.ceil(value / props.pageSize) - 1)
76
+ if (pageIndex.value > last)
77
+ pageIndex.value = last
78
+ })
79
+ </script>
80
+
81
+ <template>
82
+ <div :class="cn('flex flex-col gap-4', props.class)">
83
+ <div v-if="props.switchable || $slots.toolbar" class="flex items-center justify-between gap-3">
84
+ <slot name="toolbar" />
85
+ <div v-if="props.switchable" class="ml-auto flex items-center gap-1">
86
+ <Button
87
+ v-for="mode in (['list', 'grid'] as const)"
88
+ :key="mode"
89
+ type="button"
90
+ :variant="layout === mode ? 'secondary' : 'ghost'"
91
+ size="icon-sm"
92
+ :aria-pressed="layout === mode"
93
+ :aria-label="t(`ui.dataView.${mode}`)"
94
+ @click="layout = mode"
95
+ >
96
+ <List v-if="mode === 'list'" aria-hidden="true" />
97
+ <LayoutGrid v-else aria-hidden="true" />
98
+ </Button>
99
+ </div>
100
+ </div>
101
+
102
+ <div v-if="props.loading" class="flex items-center justify-center py-10">
103
+ <Spinner class="text-muted-foreground" />
104
+ </div>
105
+
106
+ <slot v-else-if="visible.length === 0" name="empty">
107
+ <Empty :title="props.emptyMessage ?? t('ui.table.empty')" />
108
+ </slot>
109
+
110
+ <!--
111
+ `role="list"` khai TƯỜNG MINH, dù đây đã là một `<ul>`.
112
+
113
+ Preflight của Tailwind đặt `list-style: none`, và Safari bỏ ngữ nghĩa danh
114
+ sách của một `<ul>` không có dấu đầu dòng — nên số mục không còn được đọc
115
+ ra. Khai lại role là cách chữa đã biết, và nó chẳng tốn gì ở nơi khác.
116
+ -->
117
+ <ul
118
+ v-else
119
+ role="list"
120
+ :class="cn(layout === 'grid' ? cn('grid gap-4', props.gridClass) : 'flex flex-col gap-3')"
121
+ >
122
+ <li v-for="(item, index) in visible" :key="props.itemKey(item, index)">
123
+ <slot name="item" :item="item" :index="index" :layout="layout" />
124
+ </li>
125
+ </ul>
126
+
127
+ <Pagination
128
+ v-if="props.paginate && total > props.pageSize"
129
+ v-model:page-index="pageIndex"
130
+ :total="total"
131
+ :page-size="props.pageSize"
132
+ show-summary
133
+ class="justify-between"
134
+ />
135
+ </div>
136
+ </template>
@@ -0,0 +1 @@
1
+ export { default as DataView } from './DataView.vue'
@@ -0,0 +1,117 @@
1
+ <script setup lang="ts">
2
+ import type { DateValue } from '@internationalized/date'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { DateFormatter, getLocalTimeZone } from '@internationalized/date'
5
+ import { computed, ref } from 'vue'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { invalidRingStatic } from '../../lib/focus'
8
+ import { CalendarIcon } from '../../lib/icons'
9
+ import { cn } from '../../lib/utils'
10
+ import { Button } from '../button'
11
+ import { Calendar } from '../calendar'
12
+ import { Popover, PopoverContent, PopoverTrigger } from '../popover'
13
+
14
+ /**
15
+ * Gốc của component là một provider KHÔNG vẽ ra DOM, nên thuộc tính rơi tự do
16
+ * không có chỗ đáp và biến mất hẳn. Đo được: đặt `id` lên component thì nó
17
+ * không xuất hiện ở bất kỳ đâu trong DOM, và `<Label for>` trỏ vào hư không.
18
+ *
19
+ * Chuyển tay xuống chính cái trigger.
20
+ */
21
+ defineOptions({ inheritAttrs: false })
22
+
23
+ const props = withDefaults(
24
+ defineProps<ClassProps & {
25
+ placeholder?: string
26
+ locale?: string
27
+ /** Kiểu hiện ngày trên nút. `long` ra "31 tháng 8, 2026". */
28
+ dateStyle?: 'short' | 'medium' | 'long'
29
+ size?: 'sm' | 'default'
30
+ invalid?: boolean
31
+ disabled?: boolean
32
+ minValue?: DateValue
33
+ maxValue?: DateValue
34
+ }>(),
35
+ {
36
+ dateStyle: 'medium',
37
+ size: 'default',
38
+ invalid: false,
39
+ disabled: false,
40
+ },
41
+ )
42
+
43
+ const { t, tag } = useI18n()
44
+
45
+ /**
46
+ * Cả hai mặc định phải đi qua i18n, không đặt được trong `withDefaults`.
47
+ *
48
+ * `locale` cũng vậy chứ không riêng `placeholder`: chốt cứng 'vi-VN' thì đổi
49
+ * sang tiếng Anh xong nút vẫn hiện "31 tháng 8, 2026". Prop vẫn thắng khi có —
50
+ * hai picker trên cùng một trang được phép khác locale.
51
+ */
52
+ const placeholder = computed(() => props.placeholder ?? t('ui.datePicker.placeholder'))
53
+ const locale = computed(() => props.locale ?? tag.value)
54
+
55
+ const model = defineModel<DateValue | undefined>()
56
+
57
+ const open = ref(false)
58
+
59
+ /**
60
+ * `DateFormatter` tạo lại mỗi khi đổi locale hoặc kiểu hiện — không cache sẵn ở
61
+ * cấp module, vì locale là prop và có thể khác nhau giữa hai picker trên cùng
62
+ * một trang.
63
+ */
64
+ const formatter = computed(() => new DateFormatter(locale.value, { dateStyle: props.dateStyle }))
65
+
66
+ const label = computed(() =>
67
+ model.value ? formatter.value.format(model.value.toDate(getLocalTimeZone())) : placeholder.value,
68
+ )
69
+
70
+ /**
71
+ * Chọn xong thì đóng.
72
+ *
73
+ * Reka không tự đóng — nó không biết popover có tồn tại hay không. Để mở là
74
+ * người dùng phải tự bấm ra ngoài sau mỗi lần chọn, mà thao tác chọn ngày thì
75
+ * gần như luôn là thao tác cuối.
76
+ */
77
+ function onUpdate(value: DateValue | undefined): void {
78
+ model.value = value
79
+ if (value)
80
+ open.value = false
81
+ }
82
+ </script>
83
+
84
+ <template>
85
+ <Popover v-model:open="open">
86
+ <PopoverTrigger as-child>
87
+ <Button
88
+ v-bind="$attrs"
89
+ variant="outline"
90
+ :size="props.size === 'sm' ? 'sm' : 'lg'"
91
+ :disabled="props.disabled"
92
+ :aria-invalid="props.invalid || undefined"
93
+ :class="cn(
94
+ 'w-full justify-start gap-2 font-normal',
95
+ // Nút mặc định canh giữa; ở đây là một ô nhập nên chữ phải bám trái.
96
+ !model && 'text-muted-foreground',
97
+ props.invalid && invalidRingStatic,
98
+ props.class,
99
+ )"
100
+ >
101
+ <CalendarIcon class="text-muted-foreground" />
102
+ {{ label }}
103
+ </Button>
104
+ </PopoverTrigger>
105
+
106
+ <PopoverContent class="w-auto p-0" align="start">
107
+ <Calendar
108
+ :model-value="model"
109
+ :locale="locale"
110
+ :min-value="props.minValue"
111
+ :max-value="props.maxValue"
112
+ class="p-3"
113
+ @update:model-value="onUpdate"
114
+ />
115
+ </PopoverContent>
116
+ </Popover>
117
+ </template>