@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,362 @@
1
+ <script setup lang="ts">
2
+ import type { CSSProperties } from 'vue'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import type { SpeedDialDirection, SpeedDialItem, SpeedDialType } from './index'
5
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { Plus } from '../../lib/icons'
8
+ import { cn } from '../../lib/utils'
9
+ import { Button } from '../button'
10
+ import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'
11
+
12
+ const props = withDefaults(
13
+ defineProps<ClassProps & {
14
+ /** Các mục bung ra. Mảng phẳng — SpeedDial không có submenu. */
15
+ model?: SpeedDialItem[]
16
+ type?: SpeedDialType
17
+ direction?: SpeedDialDirection
18
+ /** Bán kính quỹ đạo, tính bằng px. Chỉ dùng cho ba kiểu vòng cung. */
19
+ radius?: number
20
+ /** Độ trễ nối tiếp giữa hai mục, tính bằng ms. Đặt 0 thì bung cùng lúc. */
21
+ transitionDelay?: number
22
+ /** Phủ mờ phần còn lại của trang khi mở. */
23
+ mask?: boolean
24
+ hideOnClickOutside?: boolean
25
+ disabled?: boolean
26
+ /** Nút chính chỉ có icon nên bắt buộc phải có tên. */
27
+ ariaLabel?: string
28
+ }>(),
29
+ {
30
+ model: () => [],
31
+ type: 'linear',
32
+ direction: 'up',
33
+ radius: 80,
34
+ transitionDelay: 30,
35
+ mask: false,
36
+ hideOnClickOutside: true,
37
+ disabled: false,
38
+ },
39
+ )
40
+
41
+ const emit = defineEmits<{ 'update:visible': [value: boolean], 'click': [event: MouseEvent] }>()
42
+
43
+ const { t } = useI18n()
44
+
45
+ // Mặc định đi qua `t()` chứ không nằm trong `withDefaults` — default tính một
46
+ // lần lúc dựng component nên đổi ngôn ngữ xong nó vẫn giữ chuỗi cũ.
47
+ const ariaLabel = computed(() => props.ariaLabel ?? t('ui.speedDial.open'))
48
+
49
+ const visible = defineModel<boolean>('visible', { default: false })
50
+
51
+ const listId = useId()
52
+ const root = ref<HTMLElement>()
53
+ const itemRefs = ref<HTMLElement[]>([])
54
+ /** -1 nghĩa là tiêu điểm đang ở nút chính, không ở mục nào. */
55
+ const focusIndex = ref(-1)
56
+
57
+ /**
58
+ * Kích thước cố định, KHÔNG lấy từ prop `size` của Button.
59
+ *
60
+ * Toạ độ từng mục phải tính bằng số trước khi trình duyệt vẽ, mà đọc kích thước
61
+ * thật thì phải chờ layout xong — chưa kể lúc đóng các mục đang chồng lên nhau.
62
+ * Chốt cứng hai con số rồi ép Button theo là cách duy nhất khớp được.
63
+ */
64
+ const TRIGGER_SIZE = 36
65
+ const ITEM_SIZE = 32
66
+ /** Lệch để tâm mục trùng tâm nút chính. PrimeVue gọi là `--p-item-diff`. */
67
+ const CENTER = (TRIGGER_SIZE - ITEM_SIZE) / 2
68
+ /** Bước nhảy giữa hai mục ở kiểu `linear`. */
69
+ const LINEAR_STEP = ITEM_SIZE + 8
70
+
71
+ const DEG = Math.PI / 180
72
+
73
+ /**
74
+ * Góc của mục thứ `index`, tính bằng độ.
75
+ *
76
+ * `circle` chia đều 360° nên mục cuối không trùng mục đầu — chia cho `n`. Hai
77
+ * kiểu cung hở thì mục đầu và mục cuối phải nằm đúng hai đầu mút, nên chia cho
78
+ * `n - 1`. Số đo lấy từ chính primevue.dev: 5 mục ⇒ circle 72°, semi 45°,
79
+ * quarter 22.5°.
80
+ */
81
+ function angleOf(index: number): number {
82
+ const count = props.model.length
83
+ if (count < 2)
84
+ return 0
85
+
86
+ if (props.type === 'circle')
87
+ return (360 / count) * index
88
+
89
+ const sweep = props.type === 'semi-circle' ? 180 : 90
90
+ return (sweep / (count - 1)) * index
91
+ }
92
+
93
+ function placeLinear(index: number): [number, number] {
94
+ const d = (index + 1) * LINEAR_STEP
95
+
96
+ switch (props.direction) {
97
+ case 'down': return [0, d]
98
+ case 'left': return [-d, 0]
99
+ case 'right': return [d, 0]
100
+ default: return [0, -d]
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Độ lệch của mục thứ `index` so với tâm nút chính, tính bằng px.
106
+ *
107
+ * Bốn hướng KHÔNG phải bốn phép xoay của cùng một công thức: hướng dọc lấy cos
108
+ * cho trục ngang, hướng ngang thì hai trục **đổi vai** cos/sin — nếu không, một
109
+ * nửa số hướng sẽ quét ngược. Số đo đối chiếu từng mục với primevue.dev.
110
+ */
111
+ function place(index: number): [number, number] {
112
+ if (props.type === 'linear')
113
+ return placeLinear(index)
114
+
115
+ const angle = angleOf(index) * DEG
116
+ const cos = props.radius * Math.cos(angle)
117
+ const sin = props.radius * Math.sin(angle)
118
+
119
+ if (props.type === 'circle')
120
+ return [cos, sin]
121
+
122
+ if (props.type === 'semi-circle') {
123
+ switch (props.direction) {
124
+ case 'down': return [cos, sin]
125
+ case 'left': return [-sin, cos]
126
+ case 'right': return [sin, cos]
127
+ default: return [cos, -sin]
128
+ }
129
+ }
130
+
131
+ switch (props.direction) {
132
+ case 'up-left': return [-cos, -sin]
133
+ case 'down-left': return [-sin, cos]
134
+ case 'down-right': return [sin, cos]
135
+ default: return [cos, -sin]
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Lúc mở thì mục gần nút chính hiện trước; lúc đóng thì thu về theo thứ tự
141
+ * ngược lại. Chạy xuôi cả hai chiều trông như cái đuôi bị đứt: mục xa biến mất
142
+ * trước rồi mới tới mục gần, ngược với hướng chuyển động.
143
+ */
144
+ function delayOf(index: number): string {
145
+ const step = props.transitionDelay
146
+ const order = visible.value ? index : props.model.length - 1 - index
147
+ return `${order * step}ms`
148
+ }
149
+
150
+ /**
151
+ * Vị trí bằng `transform`, KHÔNG bằng `left/right/top/bottom`.
152
+ *
153
+ * Neo theo `bottom` hay `right` thì lúc đóng thuộc tính đối diện phải về
154
+ * `auto`, mà `auto` không nội suy được — mục **nhảy** thẳng tới đích thay vì
155
+ * trượt, và chỉ nhảy ở những hướng neo kiểu đó. Đã đo: hướng `up`/`left` giật,
156
+ * `down`/`right` mượt, cùng một component. Dịch bằng `transform` thì cả tám
157
+ * hướng chạy giống hệt nhau, lại không bắt trình duyệt tính lại layout.
158
+ */
159
+ function styleOf(index: number): CSSProperties {
160
+ const [x, y] = visible.value ? place(index) : [0, 0]
161
+
162
+ return {
163
+ transform: `translate(${x.toFixed(3)}px, ${y.toFixed(3)}px) scale(${visible.value ? 1 : 0.5})`,
164
+ transitionDelay: delayOf(index),
165
+ }
166
+ }
167
+
168
+ function close(): void {
169
+ if (!visible.value)
170
+ return
171
+
172
+ visible.value = false
173
+ focusIndex.value = -1
174
+ emit('update:visible', false)
175
+ }
176
+
177
+ function toggle(event: MouseEvent): void {
178
+ emit('click', event)
179
+
180
+ if (props.disabled)
181
+ return
182
+
183
+ visible.value = !visible.value
184
+ focusIndex.value = -1
185
+ emit('update:visible', visible.value)
186
+ }
187
+
188
+ function run(item: SpeedDialItem): void {
189
+ if (item.disabled)
190
+ return
191
+
192
+ if (!item.url)
193
+ item.command?.(item)
194
+
195
+ close()
196
+ }
197
+
198
+ /** Đưa tiêu điểm tới mục thứ `next`, quay vòng ở hai đầu. */
199
+ async function focusItem(next: number): Promise<void> {
200
+ const count = props.model.length
201
+ if (!count)
202
+ return
203
+
204
+ focusIndex.value = (next + count) % count
205
+ await nextTick()
206
+ itemRefs.value[focusIndex.value]?.focus()
207
+ }
208
+
209
+ function onKeydown(event: KeyboardEvent): void {
210
+ if (!visible.value)
211
+ return
212
+
213
+ switch (event.key) {
214
+ case 'Escape':
215
+ close()
216
+ // Trả tiêu điểm về nút chính, nếu không nó rơi ra ngoài body.
217
+ root.value?.querySelector<HTMLElement>('[data-speed-dial-trigger]')?.focus()
218
+ break
219
+ case 'ArrowDown':
220
+ case 'ArrowRight':
221
+ event.preventDefault()
222
+ focusItem(focusIndex.value + 1)
223
+ break
224
+ case 'ArrowUp':
225
+ case 'ArrowLeft':
226
+ event.preventDefault()
227
+ focusItem(focusIndex.value <= 0 ? props.model.length - 1 : focusIndex.value - 1)
228
+ break
229
+ case 'Home':
230
+ event.preventDefault()
231
+ focusItem(0)
232
+ break
233
+ case 'End':
234
+ event.preventDefault()
235
+ focusItem(props.model.length - 1)
236
+ break
237
+ }
238
+ }
239
+
240
+ function onPointerDown(event: PointerEvent): void {
241
+ if (props.hideOnClickOutside && !root.value?.contains(event.target as Node))
242
+ close()
243
+ }
244
+
245
+ onMounted(() => {
246
+ document.addEventListener('pointerdown', onPointerDown)
247
+ })
248
+
249
+ onBeforeUnmount(() => {
250
+ document.removeEventListener('pointerdown', onPointerDown)
251
+ })
252
+
253
+ // Danh sách đổi thì mảng ref cũ còn giữ node đã gỡ — dọn để phím mũi tên không
254
+ // focus vào phần tử mồ côi.
255
+ watch(() => props.model, () => {
256
+ itemRefs.value = []
257
+ focusIndex.value = -1
258
+ })
259
+
260
+ const rootStyle = computed<CSSProperties>(() => ({
261
+ width: `${TRIGGER_SIZE}px`,
262
+ height: `${TRIGGER_SIZE}px`,
263
+ }))
264
+ </script>
265
+
266
+ <template>
267
+ <div
268
+ ref="root"
269
+ :class="cn('relative', props.class)"
270
+ :style="rootStyle"
271
+ @keydown="onKeydown"
272
+ >
273
+ <!--
274
+ Lớp phủ nằm trong chính component chứ không Teleport ra body: đặt z thấp
275
+ hơn nút và các mục là đủ, mà lại không phải lo portal khi component nằm
276
+ trong dialog.
277
+ -->
278
+ <div
279
+ v-if="mask"
280
+ class="fixed inset-0 -z-10 bg-foreground/40 backdrop-blur-[2px] transition-opacity duration-(--duration-base) motion-reduce:transition-none"
281
+ :class="visible ? 'opacity-100' : 'pointer-events-none opacity-0'"
282
+ aria-hidden="true"
283
+ />
284
+
285
+ <ul
286
+ :id="listId"
287
+ class="pointer-events-none absolute inset-0 m-0 list-none p-0"
288
+ role="menu"
289
+ :aria-label="ariaLabel"
290
+ >
291
+ <li
292
+ v-for="(item, index) in model"
293
+ :key="index"
294
+ class="absolute transition-[transform,opacity] duration-(--duration-base) ease-out motion-reduce:transition-none"
295
+ :class="visible ? 'opacity-100' : 'pointer-events-none opacity-0'"
296
+ :style="[{ left: `${CENTER}px`, top: `${CENTER}px` }, styleOf(index)]"
297
+ role="none"
298
+ >
299
+ <Tooltip v-if="item.label" :delay-duration="200">
300
+ <TooltipTrigger as-child>
301
+ <Button
302
+ :ref="el => { if (el) itemRefs[index] = (el as { $el: HTMLElement }).$el }"
303
+ :as="item.url ? 'a' : 'button'"
304
+ :href="item.url"
305
+ :target="item.target"
306
+ variant="secondary"
307
+ size="icon"
308
+ role="menuitem"
309
+ class="pointer-events-auto rounded-full shadow-md"
310
+ :tabindex="visible ? 0 : -1"
311
+ :disabled="item.disabled"
312
+ :aria-label="item.label"
313
+ @click="run(item)"
314
+ >
315
+ <component :is="item.icon" v-if="item.icon" />
316
+ </Button>
317
+ </TooltipTrigger>
318
+ <TooltipContent :side="type === 'linear' && (direction === 'up' || direction === 'down') ? 'right' : 'top'">
319
+ {{ item.label }}
320
+ </TooltipContent>
321
+ </Tooltip>
322
+
323
+ <Button
324
+ v-else
325
+ :ref="el => { if (el) itemRefs[index] = (el as { $el: HTMLElement }).$el }"
326
+ :as="item.url ? 'a' : 'button'"
327
+ :href="item.url"
328
+ :target="item.target"
329
+ variant="secondary"
330
+ size="icon"
331
+ role="menuitem"
332
+ class="pointer-events-auto rounded-full shadow-md"
333
+ :tabindex="visible ? 0 : -1"
334
+ :disabled="item.disabled"
335
+ @click="run(item)"
336
+ >
337
+ <component :is="item.icon" v-if="item.icon" />
338
+ </Button>
339
+ </li>
340
+ </ul>
341
+
342
+ <Button
343
+ data-speed-dial-trigger
344
+ size="icon-lg"
345
+ class="relative rounded-full shadow-lg"
346
+ :disabled="disabled"
347
+ :aria-label="ariaLabel"
348
+ :aria-expanded="visible"
349
+ :aria-controls="listId"
350
+ aria-haspopup="menu"
351
+ @click="toggle"
352
+ >
353
+ <slot name="icon" :visible="visible">
354
+ <!-- Dấu cộng xoay 135° thành dấu nhân — cùng một icon, không đổi thẻ. -->
355
+ <Plus
356
+ class="transition-transform duration-(--duration-base) motion-reduce:transition-none"
357
+ :class="visible && 'rotate-[135deg]'"
358
+ />
359
+ </slot>
360
+ </Button>
361
+ </div>
362
+ </template>
@@ -0,0 +1,28 @@
1
+ import type { MenuActionItem } from '../../lib/menu'
2
+
3
+ export { default as SpeedDial } from './SpeedDial.vue'
4
+
5
+ /**
6
+ * SpeedDial chỉ nhận mục **phẳng**: không đường kẻ, không submenu. Mỗi mục là
7
+ * một nút tròn nằm trên quỹ đạo quanh nút chính, không có chỗ cho cấp hai.
8
+ */
9
+ export type SpeedDialItem = MenuActionItem
10
+
11
+ /** Kiểu quỹ đạo các mục bung ra. */
12
+ export type SpeedDialType = 'linear' | 'circle' | 'semi-circle' | 'quarter-circle'
13
+
14
+ /**
15
+ * Hướng bung.
16
+ *
17
+ * `linear` và `semi-circle` dùng bốn hướng thẳng; `quarter-circle` dùng bốn
18
+ * hướng chéo. `circle` bỏ qua prop này vì nó bung kín 360°.
19
+ */
20
+ export type SpeedDialDirection
21
+ = | 'up'
22
+ | 'down'
23
+ | 'left'
24
+ | 'right'
25
+ | 'up-left'
26
+ | 'up-right'
27
+ | 'down-left'
28
+ | 'down-right'
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { computed } from 'vue'
4
+ import { useI18n } from '../../composables/useI18n'
5
+ import { LoaderCircle } from '../../lib/icons'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<ClassProps & { label?: string }>()
9
+
10
+ const { t } = useI18n()
11
+
12
+ // Bỏ qua `withDefaults`: chuỗi mặc định phải đi qua `t()` mới đổi theo ngôn ngữ.
13
+ const label = computed(() => props.label ?? t('ui.spinner.label'))
14
+ </script>
15
+
16
+ <template>
17
+ <span role="status" :aria-label="label" :class="cn('inline-flex items-center', props.class)">
18
+ <LoaderCircle class="size-4 animate-spin" aria-hidden="true" />
19
+ </span>
20
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Spinner } from './Spinner.vue'
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type { SplitterGroupEmits, SplitterGroupProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SplitterGroup, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<SplitterGroupProps & ClassProps>()
9
+ const emits = defineEmits<SplitterGroupEmits>()
10
+
11
+ const delegated = computed(() => {
12
+ const { class: _class, ...rest } = props
13
+ return rest
14
+ })
15
+
16
+ const forwarded = useForwardPropsEmits(delegated, emits)
17
+ </script>
18
+
19
+ <template>
20
+ <!-- Chiều xếp do reka đặt inline theo `direction`; ở đây chỉ lo kích thước. -->
21
+ <SplitterGroup v-bind="forwarded" :class="cn('flex h-full w-full', props.class)">
22
+ <slot />
23
+ </SplitterGroup>
24
+ </template>
@@ -0,0 +1,51 @@
1
+ <script setup lang="ts">
2
+ import type { SplitterResizeHandleEmits, SplitterResizeHandleProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SplitterResizeHandle, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { GripVertical } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ const props = defineProps<SplitterResizeHandleProps & ClassProps & {
10
+ /** Hiện ô chấm ở giữa. Bật khi tay cầm nằm giữa hai mặt phẳng cùng màu. */
11
+ grip?: boolean
12
+ }>()
13
+ const emits = defineEmits<SplitterResizeHandleEmits>()
14
+
15
+ const delegated = computed(() => {
16
+ const { class: _class, grip: _grip, ...rest } = props
17
+ return rest
18
+ })
19
+
20
+ const forwarded = useForwardPropsEmits(delegated, emits)
21
+ </script>
22
+
23
+ <template>
24
+ <SplitterResizeHandle
25
+ v-bind="forwarded"
26
+ :class="cn(
27
+ 'relative flex w-px shrink-0 items-center justify-center bg-border',
28
+ // Đường kẻ dày 1px, nhưng vùng bắt chuột dày 9px — kéo được một đường
29
+ // tóc là bài kiểm tra độ chính xác, không phải một giao diện.
30
+ 'after:absolute after:inset-y-0 after:left-1/2 after:w-[9px] after:-translate-x-1/2',
31
+ // Vòng focus kiểu ô lịch, không phải `focusRing`: tay cầm không có viền
32
+ // để đổi màu, mà `focusRing` thì làm đúng việc đó.
33
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
34
+ 'data-[state=drag]:bg-ring',
35
+ // Nhóm dọc: kẻ nằm ngang, mọi thứ xoay 90°.
36
+ 'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',
37
+ 'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:left-0',
38
+ 'data-[orientation=vertical]:after:h-[9px] data-[orientation=vertical]:after:w-full',
39
+ 'data-[orientation=vertical]:after:-translate-y-1/2 data-[orientation=vertical]:after:translate-x-0',
40
+ props.class,
41
+ )"
42
+ >
43
+ <span
44
+ v-if="props.grip"
45
+ class="z-(--z-raised) grid h-4 w-3 place-items-center rounded-xs border border-border bg-border text-muted-foreground data-[orientation=vertical]:rotate-90"
46
+ >
47
+ <GripVertical class="size-2.5" />
48
+ </span>
49
+ <slot />
50
+ </SplitterResizeHandle>
51
+ </template>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { SplitterPanelEmits, SplitterPanelProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SplitterPanel, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<SplitterPanelProps & ClassProps>()
9
+ const emits = defineEmits<SplitterPanelEmits>()
10
+
11
+ const delegated = computed(() => {
12
+ const { class: _class, ...rest } = props
13
+ return rest
14
+ })
15
+
16
+ const forwarded = useForwardPropsEmits(delegated, emits)
17
+ </script>
18
+
19
+ <template>
20
+ <!--
21
+ `overflow-hidden` là bắt buộc, không phải cho đẹp.
22
+
23
+ reka đặt kích thước panel bằng `flex-grow`, nên nội dung rộng hơn phần đã
24
+ chia sẽ **đẩy panel giãn ra** thay vì bị cắt — kéo tay cầm về một phía là
25
+ panel bên kia không chịu co lại, trông như thanh chia bị kẹt.
26
+ -->
27
+ <SplitterPanel v-bind="forwarded" :class="cn('overflow-hidden', props.class)">
28
+ <slot />
29
+ </SplitterPanel>
30
+ </template>
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Vùng chia được, kéo tay cầm để đổi tỉ lệ.
3
+ *
4
+ * PrimeVue gọi là `Splitter`, shadcn gọi là `Resizable`. Lấy tên PrimeVue vì
5
+ * danh mục component của repo xếp theo phân loại bên đó.
6
+ *
7
+ * Tay cầm phải khai TƯỜNG MINH giữa hai panel — reka không tự chèn. Đổi lại,
8
+ * `Splitter` lồng trong `SplitterPanel` là ra lưới hai chiều mà không cần API
9
+ * riêng nào.
10
+ */
11
+
12
+ export { default as Splitter } from './Splitter.vue'
13
+ export { default as SplitterHandle } from './SplitterHandle.vue'
14
+ export { default as SplitterPanel } from './SplitterPanel.vue'
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import type { StepperRootEmits, StepperRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { StepperRoot, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = withDefaults(
9
+ defineProps<StepperRootProps & ClassProps>(),
10
+ { orientation: 'horizontal' },
11
+ )
12
+
13
+ const emits = defineEmits<StepperRootEmits>()
14
+
15
+ const delegated = computed(() => {
16
+ const { class: _class, ...rest } = props
17
+ return rest
18
+ })
19
+
20
+ const forwarded = useForwardPropsEmits(delegated, emits)
21
+ </script>
22
+
23
+ <template>
24
+ <StepperRoot
25
+ v-bind="forwarded"
26
+ :class="cn(
27
+ 'flex w-full',
28
+ props.orientation === 'vertical' ? 'flex-col' : 'items-start',
29
+ props.class,
30
+ )"
31
+ >
32
+ <slot />
33
+ </StepperRoot>
34
+ </template>
@@ -0,0 +1,113 @@
1
+ <script setup lang="ts">
2
+ import type { StepperItemProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import {
5
+ StepperDescription,
6
+ StepperItem,
7
+ StepperSeparator,
8
+ StepperTitle,
9
+ StepperTrigger,
10
+ } from 'reka-ui'
11
+ import { computed } from 'vue'
12
+ import { Check } from '../../lib/icons'
13
+ import { cn } from '../../lib/utils'
14
+
15
+ const props = withDefaults(
16
+ defineProps<StepperItemProps & ClassProps & {
17
+ title?: string
18
+ description?: string
19
+ /** Bước cuối không vẽ đoạn kẻ nối. */
20
+ last?: boolean
21
+ orientation?: 'horizontal' | 'vertical'
22
+ }>(),
23
+ { last: false, orientation: 'horizontal' },
24
+ )
25
+
26
+ const delegated = computed(() => {
27
+ const {
28
+ class: _class,
29
+ title: _title,
30
+ description: _description,
31
+ last: _last,
32
+ orientation: _orientation,
33
+ ...rest
34
+ } = props
35
+ return rest
36
+ })
37
+
38
+ /**
39
+ * Bước đã xong hiện dấu tick thay cho số.
40
+ *
41
+ * Reka phơi `data-state` là `completed` / `active` / `inactive`. Đổi số thành
42
+ * tick là cách duy nhất phân biệt được "đã xong" với "đang làm" mà không cần
43
+ * đến màu — người không phân biệt được màu vẫn đọc ra.
44
+ */
45
+ const indicator = cn(
46
+ 'grid size-8 shrink-0 place-items-center rounded-full border text-sm font-medium transition-colors',
47
+ 'group-data-[state=inactive]/step:border-border group-data-[state=inactive]/step:text-muted-foreground',
48
+ 'group-data-[state=active]/step:border-primary group-data-[state=active]/step:bg-primary group-data-[state=active]/step:text-primary-foreground',
49
+ 'group-data-[state=completed]/step:border-primary group-data-[state=completed]/step:bg-primary group-data-[state=completed]/step:text-primary-foreground',
50
+ )
51
+
52
+ const separator = cn(
53
+ 'bg-border transition-colors',
54
+ 'group-data-[state=completed]/step:bg-primary',
55
+ )
56
+ </script>
57
+
58
+ <template>
59
+ <StepperItem
60
+ v-bind="delegated"
61
+ :class="cn(
62
+ 'group/step relative flex',
63
+ props.orientation === 'vertical' ? 'gap-3 pb-6 last:pb-0' : 'flex-1 flex-col items-center gap-2 last:flex-none',
64
+ props.class,
65
+ )"
66
+ >
67
+ <!--
68
+ Ngang: đoạn kẻ nằm NGANG HÀNG với vòng tròn, không nằm dưới nhãn — nên nó
69
+ phải tuyệt đối, vì nhãn bên dưới có thể dài ngắn khác nhau và sẽ đẩy đoạn
70
+ kẻ lệch nếu để nó chảy theo dòng.
71
+ -->
72
+ <StepperSeparator
73
+ v-if="!props.last"
74
+ :class="props.orientation === 'vertical'
75
+ ? cn('absolute left-4 top-9 bottom-2 w-px -translate-x-1/2', separator)
76
+ : cn('absolute left-[calc(50%+1.5rem)] right-[calc(-50%+1.5rem)] top-4 h-px -translate-y-1/2', separator)"
77
+ />
78
+
79
+ <StepperTrigger
80
+ :class="cn(
81
+ 'relative z-(--z-raised) flex rounded-full outline-none',
82
+ 'focus-visible:ring-2 focus-visible:ring-ring',
83
+ 'disabled:pointer-events-none disabled:opacity-50',
84
+ )"
85
+ >
86
+ <span :class="indicator">
87
+ <Check v-if="props.step !== undefined" class="hidden size-4 group-data-[state=completed]/step:block" />
88
+ <span class="group-data-[state=completed]/step:hidden"><slot name="indicator">{{ props.step }}</slot></span>
89
+ </span>
90
+ </StepperTrigger>
91
+
92
+ <div
93
+ :class="cn(
94
+ 'flex min-w-0 flex-col gap-0.5',
95
+ props.orientation === 'vertical' ? 'pt-1' : 'items-center text-center',
96
+ )"
97
+ >
98
+ <StepperTitle class="text-sm font-medium group-data-[state=inactive]/step:text-muted-foreground">
99
+ <slot name="title">
100
+ {{ props.title }}
101
+ </slot>
102
+ </StepperTitle>
103
+ <StepperDescription
104
+ v-if="props.description || $slots.description"
105
+ class="text-xs leading-relaxed text-muted-foreground"
106
+ >
107
+ <slot name="description">
108
+ {{ props.description }}
109
+ </slot>
110
+ </StepperDescription>
111
+ </div>
112
+ </StepperItem>
113
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as Stepper } from './Stepper.vue'
2
+ export { default as StepperItem } from './StepperItem.vue'