@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,314 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { TreeNode } from '../tree'
4
+ import { computed, nextTick, ref, watch } from 'vue'
5
+ import { useI18n } from '../../composables/useI18n'
6
+ import { focusRing, invalidRing } from '../../lib/focus'
7
+ import { ChevronDown, ChevronRight } from '../../lib/icons'
8
+ import { cn } from '../../lib/utils'
9
+ import { Popover, PopoverContent, PopoverTrigger } from '../popover'
10
+ import { findPath, isBranch, pickerTriggerVariants } from './index'
11
+
12
+ /**
13
+ * Gốc của component là `Popover`, mà `PopoverRoot` không vẽ ra DOM nào — nên
14
+ * thuộc tính rơi tự do KHÔNG có chỗ đáp và biến mất lặng lẽ. `id` là cái mất
15
+ * đau nhất: `<Label for>` trỏ vào một id không tồn tại thì nhãn vẫn hiện ra
16
+ * bình thường và chẳng làm gì cả.
17
+ *
18
+ * Chuyển tay xuống chính cái nút, cùng cách `Input.vue` làm.
19
+ */
20
+ defineOptions({ inheritAttrs: false })
21
+
22
+ const props = withDefaults(
23
+ defineProps<ClassProps & {
24
+ items: TreeNode[]
25
+ placeholder?: string
26
+ disabled?: boolean
27
+ invalid?: boolean
28
+ size?: 'sm' | 'default'
29
+ /**
30
+ * Hiện cả đường đi trên nút chứ không chỉ mỗi lá.
31
+ *
32
+ * Bật sẵn, và đó là chỗ khác PrimeVue một cách có chủ ý: hai thành phố
33
+ * trùng tên ở hai tỉnh khác nhau thì riêng cái lá không nói được bạn đã
34
+ * chọn cái nào — mà phân biệt đúng chuyện đó là lý do người ta dùng cascade.
35
+ */
36
+ showPath?: boolean
37
+ /** Chiều cao tối đa của một cột trước khi nó cuộn. */
38
+ maxHeight?: string
39
+ }>(),
40
+ {
41
+ disabled: false,
42
+ invalid: false,
43
+ size: 'default',
44
+ showPath: true,
45
+ maxHeight: '260px',
46
+ },
47
+ )
48
+
49
+ const model = defineModel<TreeNode | undefined>()
50
+
51
+ const { t } = useI18n()
52
+
53
+ const open = ref(false)
54
+
55
+ /** Chuỗi nhánh đang mở. Cột thứ k hiện con của `activePath[k - 1]`. */
56
+ const activePath = ref<TreeNode[]>([])
57
+
58
+ /** Nút đang giữ focus. Roving tabindex chạy quanh giá trị này. */
59
+ const focusedId = ref<string>()
60
+
61
+ const panel = ref<HTMLElement>()
62
+
63
+ const placeholder = computed(() => props.placeholder ?? t('ui.cascadeSelect.placeholder'))
64
+
65
+ const selectedPath = computed(() =>
66
+ model.value === undefined ? [] : findPath(props.items, model.value.id),
67
+ )
68
+
69
+ const label = computed(() => {
70
+ if (selectedPath.value.length === 0)
71
+ return placeholder.value
72
+ return props.showPath
73
+ ? selectedPath.value.map(node => node.label).join(' / ')
74
+ : selectedPath.value[selectedPath.value.length - 1].label
75
+ })
76
+
77
+ /**
78
+ * Các cột đang hiện: cột gốc, rồi con của từng nhánh đang mở.
79
+ *
80
+ * Nhánh không có con thì không sinh ra cột — `activePath` chỉ nhận nhánh, nhưng
81
+ * dữ liệu do bên ngoài đưa vào nên vẫn phải lọc.
82
+ */
83
+ const columns = computed<{ parent?: TreeNode, nodes: TreeNode[] }[]>(() => {
84
+ const list: { parent?: TreeNode, nodes: TreeNode[] }[] = [{ nodes: props.items }]
85
+ for (const branch of activePath.value) {
86
+ if (branch.children !== undefined && branch.children.length > 0)
87
+ list.push({ parent: branch, nodes: branch.children })
88
+ }
89
+ return list
90
+ })
91
+
92
+ function columnOf(id: string): number {
93
+ return columns.value.findIndex(column => column.nodes.some(node => node.id === id))
94
+ }
95
+
96
+ function focusNode(id: string | undefined): void {
97
+ focusedId.value = id
98
+ if (id === undefined)
99
+ return
100
+ void nextTick(() => {
101
+ panel.value?.querySelector<HTMLElement>(`[data-node="${CSS.escape(id)}"]`)?.focus()
102
+ })
103
+ }
104
+
105
+ /** Mở một nhánh, cắt bỏ mọi cột sâu hơn nó. */
106
+ function openBranch(node: TreeNode, column: number): void {
107
+ activePath.value = [...activePath.value.slice(0, column), node]
108
+ }
109
+
110
+ /**
111
+ * Mở nhánh khi rê chuột — nhưng nghe `pointermove`, KHÔNG nghe `pointerenter`.
112
+ *
113
+ * `pointerenter` bắn cả khi con trỏ đứng yên còn phần tử thì vừa xuất hiện dưới
114
+ * nó. Cột mới luôn vẽ ra ngay chỗ con trỏ vừa bấm, nên đi bằng bàn phím một
115
+ * nhịp `ArrowRight` lại mở ra HAI cột: một cột do mình mở, một cột do cái nhánh
116
+ * tình cờ nằm dưới con trỏ. Đo được đúng như vậy trước khi sửa.
117
+ *
118
+ * `pointermove` chỉ bắn khi con trỏ thật sự nhúc nhích.
119
+ */
120
+ function hoverBranch(node: TreeNode, column: number): void {
121
+ if (!isBranch(node) || node.disabled === true)
122
+ return
123
+ // Không mở lại cái đang mở: `pointermove` bắn liên tục, mà mỗi lần gán là một
124
+ // mảng mới và cả bảng vẽ lại.
125
+ if (activePath.value[column] === node)
126
+ return
127
+ openBranch(node, column)
128
+ }
129
+
130
+ function choose(node: TreeNode, column: number): void {
131
+ if (node.disabled === true)
132
+ return
133
+
134
+ if (isBranch(node)) {
135
+ openBranch(node, column)
136
+ const first = node.children?.find(child => child.disabled !== true)
137
+ focusNode(first?.id)
138
+ return
139
+ }
140
+
141
+ model.value = node
142
+ open.value = false
143
+ }
144
+
145
+ function moveWithin(column: number, from: string, step: number): void {
146
+ const nodes = columns.value[column]?.nodes.filter(node => node.disabled !== true) ?? []
147
+ if (nodes.length === 0)
148
+ return
149
+ const at = nodes.findIndex(node => node.id === from)
150
+ // Chạy vòng: từ mục cuối bấm xuống thì về mục đầu, đúng như một menu.
151
+ const next = at < 0 ? 0 : (at + step + nodes.length) % nodes.length
152
+ focusNode(nodes[next].id)
153
+ }
154
+
155
+ function onKeydown(event: KeyboardEvent): void {
156
+ const id = focusedId.value
157
+ if (id === undefined)
158
+ return
159
+ const column = columnOf(id)
160
+ if (column < 0)
161
+ return
162
+ const node = columns.value[column].nodes.find(item => item.id === id)
163
+ if (node === undefined)
164
+ return
165
+
166
+ switch (event.key) {
167
+ case 'ArrowDown':
168
+ event.preventDefault()
169
+ moveWithin(column, id, 1)
170
+ break
171
+
172
+ case 'ArrowUp':
173
+ event.preventDefault()
174
+ moveWithin(column, id, -1)
175
+ break
176
+
177
+ case 'ArrowRight':
178
+ if (isBranch(node)) {
179
+ event.preventDefault()
180
+ choose(node, column)
181
+ }
182
+ break
183
+
184
+ case 'ArrowLeft':
185
+ // Lùi ra cột trước và đứng lại đúng cái nhánh đã mở cột này — không phải
186
+ // mục đầu cột. Người dùng vừa đi vào từ đó, trả họ về chỗ khác là mất dấu.
187
+ if (column > 0) {
188
+ event.preventDefault()
189
+ const parent = columns.value[column].parent
190
+ activePath.value = activePath.value.slice(0, column - 1)
191
+ focusNode(parent?.id)
192
+ }
193
+ break
194
+
195
+ case 'Home':
196
+ case 'End': {
197
+ event.preventDefault()
198
+ const nodes = columns.value[column].nodes.filter(item => item.disabled !== true)
199
+ if (nodes.length > 0)
200
+ focusNode(event.key === 'Home' ? nodes[0].id : nodes[nodes.length - 1].id)
201
+ break
202
+ }
203
+
204
+ case 'Enter':
205
+ case ' ':
206
+ event.preventDefault()
207
+ choose(node, column)
208
+ break
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Mở bảng thì dựng lại đường đi theo giá trị đang chọn.
214
+ *
215
+ * Mở ra ở cột gốc trong khi ô đang hiện "Việt Nam / Hà Nội" thì người dùng phải
216
+ * đi lại từ đầu chỉ để xem mình đang ở đâu.
217
+ */
218
+ watch(open, (isOpen) => {
219
+ if (!isOpen)
220
+ return
221
+ const path = selectedPath.value
222
+ activePath.value = path.slice(0, -1)
223
+ focusNode(path.length > 0
224
+ ? path[path.length - 1].id
225
+ : props.items.find(node => node.disabled !== true)?.id)
226
+ })
227
+ </script>
228
+
229
+ <template>
230
+ <Popover v-model:open="open">
231
+ <PopoverTrigger as-child>
232
+ <button
233
+ v-bind="$attrs"
234
+ type="button"
235
+ role="combobox"
236
+ aria-haspopup="dialog"
237
+ :aria-expanded="open"
238
+ :disabled="props.disabled"
239
+ :aria-invalid="props.invalid || undefined"
240
+ :data-invalid="props.invalid || undefined"
241
+ :data-placeholder="selectedPath.length === 0 ? '' : undefined"
242
+ :class="cn(pickerTriggerVariants({ size: props.size }), focusRing, invalidRing, props.class)"
243
+ >
244
+ <span class="truncate text-left">{{ label }}</span>
245
+ <ChevronDown class="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
246
+ </button>
247
+ </PopoverTrigger>
248
+
249
+ <!--
250
+ Bảng KHÔNG bám bề rộng của nút, khác `TreeSelect`: số cột đổi theo việc
251
+ người dùng đi sâu tới đâu, nên bề rộng phải do nội dung quyết định.
252
+ -->
253
+ <PopoverContent class="w-auto p-0" align="start">
254
+ <!--
255
+ `role="tree"` phải nằm ở một thẻ BÊN TRONG, không đặt lên `PopoverContent`.
256
+
257
+ reka hard-code `role: "dialog"` trong `PopoverContentImpl` và nó thắng
258
+ mọi thuộc tính truyền vào — thử đặt `role="tree"` lên đó thì `treeitem`
259
+ rơi thẳng vào một `dialog`, tức là nằm ngoài cây mà nó khai là thuộc về.
260
+ Không lỗi, không cảnh báo, chỉ là quan hệ cha con biến mất.
261
+
262
+ Vì vẫn còn một `dialog` bọc ngoài nên nút cũng khai `aria-haspopup="dialog"`
263
+ chứ không phải `"tree"`: DOM nói gì thì khai đúng thứ đó.
264
+ -->
265
+ <div
266
+ ref="panel"
267
+ role="tree"
268
+ :aria-label="placeholder"
269
+ class="flex items-stretch"
270
+ @keydown="onKeydown"
271
+ >
272
+ <div
273
+ v-for="(column, columnIndex) in columns"
274
+ :key="column.parent?.id ?? '__root'"
275
+ role="group"
276
+ :aria-label="column.parent?.label"
277
+ class="min-w-[168px] overflow-y-auto p-1 not-first:border-l not-first:border-border"
278
+ :style="{ maxHeight: props.maxHeight }"
279
+ >
280
+ <div
281
+ v-for="node in column.nodes"
282
+ :key="node.id"
283
+ role="treeitem"
284
+ :data-node="node.id"
285
+ :aria-level="columnIndex + 1"
286
+ :aria-expanded="isBranch(node) ? activePath.includes(node) : undefined"
287
+ :aria-selected="model?.id === node.id ? true : undefined"
288
+ :aria-disabled="node.disabled === true ? true : undefined"
289
+ :tabindex="focusedId === node.id ? 0 : -1"
290
+ :class="cn(
291
+ 'flex h-8 cursor-default items-center justify-between gap-2 rounded-md px-2 text-sm outline-none transition-colors',
292
+ 'focus-visible:ring-2 focus-visible:ring-ring',
293
+ node.disabled === true
294
+ ? 'pointer-events-none opacity-50'
295
+ : 'hover:bg-accent/50',
296
+ activePath.includes(node) && 'bg-accent/50',
297
+ model?.id === node.id && 'bg-accent text-accent-foreground',
298
+ )"
299
+ @click="choose(node, columnIndex)"
300
+ @focus="focusedId = node.id"
301
+ @pointermove="hoverBranch(node, columnIndex)"
302
+ >
303
+ <span class="truncate">{{ node.label }}</span>
304
+ <ChevronRight
305
+ v-if="isBranch(node)"
306
+ class="size-3.5 shrink-0 text-muted-foreground"
307
+ aria-hidden="true"
308
+ />
309
+ </div>
310
+ </div>
311
+ </div>
312
+ </PopoverContent>
313
+ </Popover>
314
+ </template>
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Dùng chung `TreeNode` với `Tree` và `TreeSelect`, và cả hai phép tra.
3
+ *
4
+ * Ba component này nhận cùng một hình dạng dữ liệu vì chúng đang nói về cùng
5
+ * một thứ — một cây. Nguồn nằm ở `src/variants/lib/tree` nên bản React
6
+ * đọc đúng file đó chứ không chép lại.
7
+ */
8
+ export { pickerTriggerVariants } from '../../variants/components/picker-trigger'
9
+
10
+ export { findPath, isBranch, type TreeNode } from '../../variants/lib/tree'
11
+ export { default as CascadeSelect } from './CascadeSelect.vue'
@@ -0,0 +1,201 @@
1
+ <script setup lang="ts" generic="T extends Record<string, unknown>">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { ChartBaseProps, ChartCurve } from './types'
4
+ import { VisArea, VisAxis, VisXYContainer } from '@unovis/vue'
5
+ import { computed, ref, useId } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+ import ChartContainer from './ChartContainer.vue'
8
+ import ChartCrosshair from './ChartCrosshair.vue'
9
+ import ChartLegend from './ChartLegend.vue'
10
+ import { toCurveType, useChartSeries } from './useChartSeries'
11
+
12
+ const props = withDefaults(defineProps<ClassProps & ChartBaseProps<T> & {
13
+ /** @default 'monotone' */
14
+ curve?: ChartCurve
15
+ /** Xếp chồng các chuỗi lên nhau. @default false */
16
+ stacked?: boolean
17
+ /** Chuẩn hoá mỗi cột về 100%. Chỉ có nghĩa khi `stacked`. @default false */
18
+ expand?: boolean
19
+ /** Tô nền vùng bằng gradient nhạt dần. @default true */
20
+ showGradient?: boolean
21
+ /**
22
+ * Độ đục của nền khi tô PHẲNG (`show-gradient="false"`). Không đụng tới gradient
23
+ * — gradient có hai chặng riêng, 0,8 xuống 0,1.
24
+ * @default 0.4
25
+ */
26
+ fillOpacity?: number
27
+ /** Vẽ đường viền trên mặt vùng. @default true */
28
+ showLine?: boolean
29
+ /** Bấm vào legend để ẩn/hiện chuỗi. @default false */
30
+ interactiveLegend?: boolean
31
+ /**
32
+ * Thời lượng animation vào trang, mili giây. Mặc định **0**: 68 biểu đồ cùng
33
+ * mount một lúc, animation từ 0 làm cả trang trông như cột bị nén dí xuống
34
+ * đáy trong ~0,7 giây đầu — đã đo, và đã khiến chính tôi lẫn người dùng tưởng
35
+ * là lỗi hình học. Đặt 400–600 nếu muốn hiệu ứng ở màn dashboard chỉ có vài
36
+ * biểu đồ.
37
+ * @default 0
38
+ */
39
+ duration?: number
40
+ }>(), {
41
+ duration: 0,
42
+ curve: 'monotone',
43
+ stacked: false,
44
+ expand: false,
45
+ showGradient: true,
46
+ fillOpacity: 0.4,
47
+ showLine: true,
48
+ showXAxis: true,
49
+ showYAxis: true,
50
+ showTooltip: true,
51
+ showLegend: false,
52
+ showGridLine: true,
53
+ showCursor: true,
54
+ interactiveLegend: false,
55
+ margin: () => ({ top: 8, right: 8, bottom: 0, left: 0 }),
56
+ })
57
+
58
+ const uid = useId()
59
+ const hidden = ref<string[]>([])
60
+
61
+ const { categories, plotData, xTicks, isMounted, valueOf, baseOf } = useChartSeries(props, {
62
+ stacked: () => props.stacked,
63
+ expand: () => props.expand,
64
+ })
65
+
66
+ const curveType = computed(() => toCurveType(props.curve))
67
+
68
+ function colorOf(key: string): string {
69
+ return `var(--color-${key})`
70
+ }
71
+
72
+ function labelOf(key: string): string {
73
+ return props.config[key]?.label ?? key
74
+ }
75
+
76
+ /**
77
+ * Chuỗi bị tắt thì làm mờ bằng chính MÀU, không dùng `stroke-opacity`:
78
+ * `_renderLines` của Unovis đặt cứng `stroke-opacity: 1` ở mỗi lần vẽ nên ghi
79
+ * đè thuộc tính đó sẽ bị xoá ngay lần render kế tiếp.
80
+ */
81
+ function strokeOf(key: string): string {
82
+ return hidden.value.includes(key)
83
+ ? `color-mix(in oklab, var(--color-${key}) 12%, transparent)`
84
+ : `var(--color-${key})`
85
+ }
86
+
87
+ /** Vùng bị legend tắt vẫn vẽ nhưng mờ hẳn đi, giống cách shadcn làm. */
88
+ function opacityOf(key: string): number {
89
+ return hidden.value.includes(key) ? 0.1 : 1
90
+ }
91
+
92
+ function gradientId(key: string): string {
93
+ return `${uid}-fill-${key}`
94
+ }
95
+
96
+ /** Nhãn trục hoành lấy từ chính dữ liệu gốc theo chỉ số. */
97
+ function formatX(tick: number | Date, i: number, ticks: number[] | Date[]): string {
98
+ if (props.xFormatter)
99
+ return props.xFormatter(tick, i, ticks)
100
+ return String(props.data[Number(tick)]?.[props.index] ?? '')
101
+ }
102
+
103
+ function toggle(key: string): void {
104
+ hidden.value = hidden.value.includes(key)
105
+ ? hidden.value.filter(k => k !== key)
106
+ : [...hidden.value, key]
107
+ }
108
+ </script>
109
+
110
+ <template>
111
+ <ChartContainer :config="props.config" :show-cursor="props.showCursor" :class="cn(props.class)">
112
+ <VisXYContainer
113
+ :data="plotData"
114
+ :margin="props.margin"
115
+ :duration="props.duration"
116
+ :style="{ height: isMounted ? '100%' : 'auto' }"
117
+ >
118
+ <!--
119
+ Gradient khai bằng SVG rời 0x0 rồi tham chiếu qua `url(#…)`.
120
+ `stop-color` nhận được `var(--color-<key>)`, nên gradient cũng đổi theo
121
+ bảng màu và theme y như phần còn lại — không phải resolve màu bằng JS.
122
+ -->
123
+ <svg width="0" height="0" aria-hidden="true" class="absolute">
124
+ <defs>
125
+ <linearGradient
126
+ v-for="key in categories"
127
+ :id="gradientId(key)"
128
+ :key="key"
129
+ x1="0"
130
+ y1="0"
131
+ x2="0"
132
+ y2="1"
133
+ >
134
+ <template v-if="props.showGradient">
135
+ <stop offset="5%" :stop-color="colorOf(key)" stop-opacity="0.8" />
136
+ <stop offset="95%" :stop-color="colorOf(key)" stop-opacity="0.1" />
137
+ </template>
138
+ <template v-else>
139
+ <stop offset="0%" :stop-color="colorOf(key)" :stop-opacity="props.fillOpacity" />
140
+ </template>
141
+ </linearGradient>
142
+ </defs>
143
+ </svg>
144
+
145
+ <VisArea
146
+ v-for="key in categories"
147
+ :key="key"
148
+ :x="(_d: Record<string, unknown>, i: number) => i"
149
+ :y="valueOf(key)"
150
+ :baseline="baseOf(key)"
151
+ :color="`url(#${gradientId(key)})`"
152
+ :curve-type="curveType"
153
+ :opacity="opacityOf(key)"
154
+ :line="props.showLine"
155
+ :line-color="strokeOf(key)"
156
+ :line-width="2"
157
+ />
158
+
159
+ <ChartCrosshair
160
+ v-if="props.showTooltip"
161
+ :index="props.index"
162
+ :categories="categories as Extract<keyof T, string>[]"
163
+ :hidden="hidden"
164
+ :color-of="colorOf"
165
+ :label-of="labelOf"
166
+ :value-formatter="props.valueFormatter"
167
+ :options="props.tooltip"
168
+ :default-index="props.defaultIndex"
169
+ :show-cursor="props.showCursor"
170
+ />
171
+
172
+ <VisAxis
173
+ v-if="props.showXAxis"
174
+ type="x"
175
+ :tick-values="xTicks"
176
+ :tick-format="formatX"
177
+ :grid-line="false"
178
+ :tick-line="false"
179
+ :domain-line="false"
180
+ />
181
+ <VisAxis
182
+ v-if="props.showYAxis"
183
+ type="y"
184
+ :tick-format="props.yFormatter"
185
+ :grid-line="props.showGridLine"
186
+ :tick-line="false"
187
+ :domain-line="false"
188
+ />
189
+
190
+ <slot />
191
+ </VisXYContainer>
192
+
193
+ <ChartLegend
194
+ v-if="props.showLegend"
195
+ :categories="categories"
196
+ :hidden="hidden"
197
+ :interactive="props.interactiveLegend"
198
+ @toggle="toggle"
199
+ />
200
+ </ChartContainer>
201
+ </template>