@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,291 @@
1
+ <script setup lang="ts" generic="T extends Record<string, unknown>">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { ChartConfig, ChartValueFormatter } from './types'
4
+ import { computed, ref } from 'vue'
5
+ import { cn } from '../../lib/utils'
6
+ import ChartContainer from './ChartContainer.vue'
7
+ import ChartLegend from './ChartLegend.vue'
8
+ import { polarToCartesian, polygonPoints, toPointsAttr } from './polar'
9
+ import { formatChartValue } from './tooltip'
10
+
11
+ /**
12
+ * Radar: mỗi hàng dữ liệu là một nan hoa, mỗi chuỗi là một đa giác.
13
+ *
14
+ * Vẽ tay — Unovis không có radar. Hình học giống SpeedDial: chia đều 360° cho
15
+ * số nan, rồi đặt điểm theo (góc, bán kính tỉ lệ với giá trị).
16
+ *
17
+ * MỘT CẢNH BÁO ĐI KÈM, và nó là thật chứ không phải câu khách sáo: radar đánh
18
+ * lừa mắt theo hai kiểu. Diện tích tăng theo BÌNH PHƯƠNG bán kính, nên một
19
+ * chuỗi hơn 40% trông như hơn gấp đôi; và đổi THỨ TỰ các nan là đổi luôn hình
20
+ * dạng dù dữ liệu y nguyên. Chỉ dùng khi các trục thật sự cùng đơn vị và thứ tự
21
+ * của chúng có nghĩa; còn lại thì cột nhóm đọc chính xác hơn.
22
+ */
23
+ const props = withDefaults(defineProps<ClassProps & {
24
+ data: T[]
25
+ /** Khoá làm nhãn của từng nan hoa. */
26
+ index: Extract<keyof T, string>
27
+ /** Các chuỗi cần vẽ. Bỏ trống thì lấy các khoá trong `config`. */
28
+ categories?: Extract<keyof T, string>[]
29
+ config: ChartConfig
30
+ /** Giá trị ứng với mép ngoài. Bỏ trống thì lấy giá trị lớn nhất trong dữ liệu. */
31
+ max?: number
32
+ /** Số vòng lưới. @default 4 */
33
+ gridLevels?: number
34
+ /**
35
+ * Bán kính vòng ngoài cùng, pixel trong khung 340×260.
36
+ *
37
+ * Hạ xuống khi nhãn nan hoa cần nhiều hơn một dòng: khung là cố định, nên chỗ
38
+ * cho nhãn chỉ lấy được từ bán kính. Với nhãn hai dòng thì 86 là vừa — nan
39
+ * dưới cùng rơi vào y = 130 + 86 + 16 = 232, còn đủ chỗ cho dòng thứ hai.
40
+ * @default 100
41
+ */
42
+ radius?: number
43
+ /**
44
+ * Hình vòng lưới. `polygon` nối thẳng giữa các nan nên đếm được số trục;
45
+ * `circle` là đường tròn, gọn hơn nhưng giấu mất số trục.
46
+ * @default 'polygon'
47
+ */
48
+ gridShape?: 'polygon' | 'circle'
49
+ /** Vẽ các vòng lưới. @default true */
50
+ showGrid?: boolean
51
+ /** Vẽ nan hoa từ tâm ra. @default true */
52
+ showSpokes?: boolean
53
+ /**
54
+ * Tô nền vùng lưới bằng **màu của chuỗi đầu** ở 20%.
55
+ *
56
+ * Không phải `--muted`: shadcn khai `fill-(--color-desktop) opacity-20`, tức
57
+ * nền lưới ăn theo chính màu đang vẽ. Dùng màu trung tính thì hai ô
58
+ * `Grid Filled` và `Grid Circle Filled` trông y hệt bản không tô, chỉ xám hơn
59
+ * một chút — mất hẳn ý nghĩa của biến thể.
60
+ * @default false
61
+ */
62
+ gridFill?: boolean
63
+ /** Tô nền đa giác. @default true */
64
+ showArea?: boolean
65
+ /**
66
+ * Độ đục của nền đa giác.
67
+ *
68
+ * 0,6 là mặc định của `<Radar>` bên Recharts, tức thứ mà mọi biến thể radar của
69
+ * shadcn nhìn ra — trừ hai ô `*-fill` (0,5). Con số 0,22 mà bản trước dùng là
70
+ * tôi tự đặt, không đo đạc gì.
71
+ * @default 0.6
72
+ */
73
+ fillOpacity?: number
74
+ /** Chấm tại mỗi đỉnh. @default false */
75
+ showDots?: boolean
76
+ /** @default true */
77
+ showLegend?: boolean
78
+ valueFormatter?: ChartValueFormatter
79
+ }>(), {
80
+ gridLevels: 4,
81
+ radius: 100,
82
+ gridShape: 'polygon',
83
+ showGrid: true,
84
+ showSpokes: true,
85
+ gridFill: false,
86
+ showArea: true,
87
+ fillOpacity: 0.6,
88
+ showDots: false,
89
+ showLegend: true,
90
+ })
91
+
92
+ /**
93
+ * Khung vẽ CỐ Ý rộng hơn cao. Nhãn nan hoa nằm ngang nên chỗ thiếu là chiều
94
+ * NGANG, không phải chiều dọc: với khung vuông 260px, "Support" và "Uptime" ở
95
+ * hai mép trái/phải bị xén mất chữ đầu — đã dính đúng vậy.
96
+ * Đặt ngắn nhãn nan hoa; khung này chừa khoảng 54px mỗi bên.
97
+ */
98
+ const VIEW_W = 340
99
+ const VIEW_H = 260
100
+ const CX = VIEW_W / 2
101
+ const CY = VIEW_H / 2
102
+ /** Khoảng cách từ mép lưới ra tới nhãn. */
103
+ const LABEL_GAP = 16
104
+ const RADIUS = computed(() => props.radius)
105
+
106
+ const hidden = ref<string[]>([])
107
+
108
+ const categories = computed(() => (props.categories ?? Object.keys(props.config)) as string[])
109
+
110
+ /**
111
+ * Màu nền vùng lưới: chuỗi ĐẦU ở 20%.
112
+ *
113
+ * Chuỗi đầu chứ không phải trộn nhiều chuỗi — cả hai ô dùng `gridFill` bên
114
+ * shadcn đều chỉ có một chuỗi, và với nhiều chuỗi thì nền lưới mang màu của một
115
+ * chuỗi cụ thể sẽ đọc ra như chuỗi đó được ưu tiên. Rơi về `--muted` khi chưa
116
+ * có chuỗi nào để không vẽ ra một mảng trong suốt.
117
+ */
118
+ const gridFillColor = computed(() => {
119
+ const key = categories.value[0]
120
+ return key === undefined
121
+ ? 'var(--muted)'
122
+ : `color-mix(in oklab, var(--color-${key}) 20%, transparent)`
123
+ })
124
+ const axes = computed(() => props.data.map(row => String(row[props.index])))
125
+ const axisCount = computed(() => axes.value.length)
126
+
127
+ const maxValue = computed(() => {
128
+ if (props.max !== undefined)
129
+ return props.max
130
+ const values = props.data.flatMap(row => categories.value.map(key => Number(row[key]) || 0))
131
+ return Math.max(...values, 1)
132
+ })
133
+
134
+ /**
135
+ * Vòng lưới. Mặc định là ĐA GIÁC chứ không phải đường tròn: cạnh thẳng nối giữa
136
+ * hai nan cho mắt đếm được số trục, còn đường tròn thì giấu mất điều đó.
137
+ * `gridShape="circle"` trả về bán kính để vẽ `<circle>`.
138
+ */
139
+ const gridRings = computed(() => Array.from({ length: props.gridLevels }, (_, i) => {
140
+ const r = (RADIUS.value * (i + 1)) / props.gridLevels
141
+ return { r, points: toPointsAttr(polygonPoints(CX, CY, r, Math.max(3, axisCount.value))) }
142
+ }))
143
+
144
+ const spokes = computed(() => axes.value.map((label, i) => {
145
+ const angle = (360 / axisCount.value) * i
146
+ const end = polarToCartesian(CX, CY, RADIUS.value, angle)
147
+ // Nhãn đẩy ra ngoài mép một chút, căn theo phía để không đè lên lưới.
148
+ const at = polarToCartesian(CX, CY, RADIUS.value + LABEL_GAP, angle)
149
+ const anchor = Math.abs(angle % 360) < 1 || Math.abs((angle % 360) - 180) < 1
150
+ ? 'middle'
151
+ : (angle % 360) < 180 ? 'start' : 'end'
152
+ return { label, end, labelAt: at, anchor, row: props.data[i] as T, index: i }
153
+ }))
154
+
155
+ const series = computed(() => categories.value.map((key) => {
156
+ const points = props.data.map((row, i) => {
157
+ const raw = Number(row[key]) || 0
158
+ const r = maxValue.value === 0 ? 0 : (RADIUS.value * Math.min(1, raw / maxValue.value))
159
+ return { ...polarToCartesian(CX, CY, r, (360 / axisCount.value) * i), raw }
160
+ })
161
+ return {
162
+ key,
163
+ label: props.config[key]?.label ?? key,
164
+ color: `var(--color-${key})`,
165
+ inactive: hidden.value.includes(key),
166
+ points: toPointsAttr(points),
167
+ dots: points,
168
+ }
169
+ }))
170
+
171
+ function toggle(key: string): void {
172
+ hidden.value = hidden.value.includes(key)
173
+ ? hidden.value.filter(k => k !== key)
174
+ : [...hidden.value, key]
175
+ }
176
+
177
+ function describe(label: string, raw: number, key: string): string {
178
+ const v = props.valueFormatter ? props.valueFormatter(raw, key) : formatChartValue(raw)
179
+ return `${label}: ${v}`
180
+ }
181
+ </script>
182
+
183
+ <template>
184
+ <ChartContainer :config="props.config" :class="cn(props.class)">
185
+ <div class="flex min-h-0 flex-1 items-center justify-center">
186
+ <svg
187
+ :viewBox="`0 0 ${VIEW_W} ${VIEW_H}`"
188
+ class="h-full max-h-full w-auto max-w-full"
189
+ role="img"
190
+ aria-label="Radar chart"
191
+ >
192
+ <!-- Nền lưới vẽ TRƯỚC để nằm dưới các vòng kẻ. -->
193
+ <template v-if="props.gridFill">
194
+ <circle v-if="props.gridShape === 'circle'" :cx="CX" :cy="CY" :r="RADIUS" :fill="gridFillColor" />
195
+ <polygon v-else :points="gridRings[gridRings.length - 1]?.points" :fill="gridFillColor" />
196
+ </template>
197
+
198
+ <!-- Lưới và nan hoa dùng --border, cùng màu với kẻ lưới của chart XY. -->
199
+ <template v-if="props.showGrid && props.gridShape === 'circle'">
200
+ <circle
201
+ v-for="(ring, i) in gridRings"
202
+ :key="`ring-${i}`"
203
+ :cx="CX"
204
+ :cy="CY"
205
+ :r="ring.r"
206
+ fill="none"
207
+ stroke="var(--border)"
208
+ stroke-width="1"
209
+ />
210
+ </template>
211
+ <template v-else-if="props.showGrid">
212
+ <polygon
213
+ v-for="(ring, i) in gridRings"
214
+ :key="`poly-${i}`"
215
+ :points="ring.points"
216
+ fill="none"
217
+ stroke="var(--border)"
218
+ stroke-width="1"
219
+ />
220
+ </template>
221
+ <line
222
+ v-for="(spoke, i) in (props.showSpokes ? spokes : [])"
223
+ :key="`spoke-${i}`"
224
+ :x1="CX"
225
+ :y1="CY"
226
+ :x2="spoke.end.x"
227
+ :y2="spoke.end.y"
228
+ stroke="var(--border)"
229
+ stroke-width="1"
230
+ />
231
+
232
+ <!--
233
+ Nhãn nan hoa mở thành slot có phạm vi — đúng vai của prop `tick` mà
234
+ Recharts nhận: biến thể "custom label" của shadcn thay hẳn nội dung
235
+ nhãn bằng hai dòng (số/số rồi tên tháng), không phải chỉ đổi cách viết
236
+ một dòng. Slot thì đoạn mã hiện trên trang docs NÓI ĐÚNG thứ đang vẽ.
237
+
238
+ Nhãn nhiều dòng thì hạ `radius` để lấy chỗ — xem prop đó.
239
+ -->
240
+ <template v-for="(spoke, i) in spokes" :key="`label-${i}`">
241
+ <slot
242
+ name="spokeLabel"
243
+ :row="spoke.row"
244
+ :index="i"
245
+ :label="spoke.label"
246
+ :x="spoke.labelAt.x"
247
+ :y="spoke.labelAt.y"
248
+ :anchor="spoke.anchor"
249
+ >
250
+ <text
251
+ :x="spoke.labelAt.x"
252
+ :y="spoke.labelAt.y"
253
+ :text-anchor="spoke.anchor"
254
+ dominant-baseline="middle"
255
+ class="fill-muted-foreground text-[11px]"
256
+ >{{ spoke.label }}</text>
257
+ </slot>
258
+ </template>
259
+
260
+ <g v-for="s in series" :key="s.key" :opacity="s.inactive ? 0.12 : 1">
261
+ <polygon
262
+ :points="s.points"
263
+ :fill="props.showArea ? s.color : 'none'"
264
+ :fill-opacity="props.showArea ? props.fillOpacity : 0"
265
+ :stroke="s.color"
266
+ stroke-width="2"
267
+ stroke-linejoin="round"
268
+ />
269
+ <circle
270
+ v-for="(dot, i) in (props.showDots ? s.dots : [])"
271
+ :key="i"
272
+ :cx="dot.x"
273
+ :cy="dot.y"
274
+ r="3"
275
+ :fill="s.color"
276
+ >
277
+ <title>{{ describe(s.label, dot.raw, s.key) }}</title>
278
+ </circle>
279
+ </g>
280
+ </svg>
281
+ </div>
282
+
283
+ <ChartLegend
284
+ v-if="props.showLegend"
285
+ :categories="categories"
286
+ :hidden="hidden"
287
+ interactive
288
+ @toggle="toggle"
289
+ />
290
+ </ChartContainer>
291
+ </template>
@@ -0,0 +1,354 @@
1
+ <script setup lang="ts" generic="T extends Record<string, unknown>">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { ChartConfig, ChartTooltipOptions, ChartTooltipRow, ChartValueFormatter } from './types'
4
+ import { computed, ref } from 'vue'
5
+ import { cn } from '../../lib/utils'
6
+ import ChartContainer from './ChartContainer.vue'
7
+ import ChartLegend from './ChartLegend.vue'
8
+ import ChartTooltipCard from './ChartTooltipCard.vue'
9
+ import { arcBounds, arcPath, polarToCartesian } from './polar'
10
+ import { formatChartValue } from './tooltip'
11
+
12
+ /**
13
+ * Radial bar. Hai cách đọc, chọn bằng `stacked`:
14
+ *
15
+ * - mặc định — mỗi HÀNG dữ liệu một vòng đồng tâm, độ dài cung theo giá trị;
16
+ * - `stacked` — MỘT vòng duy nhất, mỗi chuỗi một đoạn cung nối tiếp nhau.
17
+ *
18
+ * Hình học lấy theo `RadialBarChart` của Recharts, tức đúng thứ shadcn dùng:
19
+ * khai `innerRadius` / `outerRadius` cho CẢ biểu đồ rồi chia dải đó cho N vòng,
20
+ * chứ không khai bề dày từng vòng. Khác biệt quan trọng nhất: luôn có LỖ Ở GIỮA
21
+ * (mặc định bán kính 30) — bản trước vẽ kín tới tâm nên ra hình cái bia bắn.
22
+ *
23
+ * Vẽ tay vì Unovis không có loại này: `nested-donut` của nó là sunburst chia
24
+ * theo GÓC, còn radial bar chia theo BÁN KÍNH.
25
+ */
26
+ const props = withDefaults(defineProps<ClassProps & {
27
+ data: T[]
28
+ /** Khoá chứa tên vòng. Bỏ qua khi `stacked`. */
29
+ index: Extract<keyof T, string>
30
+ /** Khoá chứa giá trị. Bỏ qua khi `stacked`. */
31
+ value: Extract<keyof T, string>
32
+ config: ChartConfig
33
+ /** Gộp mọi chuỗi vào MỘT vòng. Khi đó chỉ đọc hàng đầu của `data`. @default false */
34
+ stacked?: boolean
35
+ /** Các khoá làm đoạn cung khi `stacked`. Bỏ trống thì lấy khoá của `config`. */
36
+ categories?: Extract<keyof T, string>[]
37
+ /** Giá trị ứng với cung đầy. Bỏ trống thì lấy giá trị lớn nhất trong dữ liệu. */
38
+ max?: number
39
+ /** Bán kính lỗ giữa. @default 30 */
40
+ innerRadius?: number
41
+ /** Bán kính mép ngoài. @default 110 */
42
+ outerRadius?: number
43
+ /** Bo tròn hai đầu cung. Số nào lớn hơn 0 cũng cho đầu tròn. @default 0 */
44
+ cornerRadius?: number
45
+ /** Góc bắt đầu, độ, 0 ở đỉnh. @default 0 */
46
+ startAngle?: number
47
+ /** Góc kết thúc. Để 180 cho bán nguyệt. @default 360 */
48
+ endAngle?: number
49
+ /** Vệt nền mờ cho phần cung còn thiếu. @default true */
50
+ showTrack?: boolean
51
+ /** Vòng kẻ tròn làm mốc. @default false */
52
+ showGrid?: boolean
53
+ /** In tên hạng mục bên trong cung. @default false */
54
+ showLabels?: boolean
55
+ /** Chữ lớn ở giữa. */
56
+ centralLabel?: string
57
+ /** Dòng nhỏ dưới `centralLabel`. */
58
+ centralSubLabel?: string
59
+ /** @default true */
60
+ showTooltip?: boolean
61
+ /** @default false */
62
+ showLegend?: boolean
63
+ valueFormatter?: ChartValueFormatter
64
+ tooltip?: ChartTooltipOptions
65
+ }>(), {
66
+ stacked: false,
67
+ innerRadius: 30,
68
+ outerRadius: 110,
69
+ cornerRadius: 0,
70
+ startAngle: 0,
71
+ endAngle: 360,
72
+ showTrack: true,
73
+ showGrid: false,
74
+ showLabels: false,
75
+ showTooltip: true,
76
+ showLegend: false,
77
+ })
78
+
79
+ /** Lề quanh mép ngoài, đủ để nét vẽ không bị viewBox cắt. */
80
+ const PAD = 8
81
+
82
+ const hidden = ref<string[]>([])
83
+ const hoverKey = ref<string | null>(null)
84
+ const pointer = ref({ x: 0, y: 0 })
85
+
86
+ const center = computed(() => props.outerRadius + PAD)
87
+
88
+ const categories = computed(() => (props.categories ?? Object.keys(props.config)) as string[])
89
+
90
+ const names = computed(() => (props.stacked
91
+ ? categories.value
92
+ : props.data.map(row => String(row[props.index]))))
93
+
94
+ function colorOf(name: string): string {
95
+ return `var(--color-${name})`
96
+ }
97
+
98
+ function labelOf(name: string): string {
99
+ return props.config[name]?.label ?? name
100
+ }
101
+
102
+ function formatValue(raw: number, name: string): string {
103
+ return props.valueFormatter ? props.valueFormatter(raw, name) : formatChartValue(raw)
104
+ }
105
+
106
+ const sweep = computed(() => props.endAngle - props.startAngle)
107
+
108
+ const maxValue = computed(() => {
109
+ if (props.max !== undefined)
110
+ return props.max
111
+ if (props.stacked) {
112
+ const row = props.data[0]
113
+ return categories.value.reduce((sum, key) => sum + (Number(row?.[key]) || 0), 0) || 1
114
+ }
115
+ return Math.max(...props.data.map(row => Number(row[props.value]) || 0), 1)
116
+ })
117
+
118
+ /**
119
+ * Chia dải `[innerRadius, outerRadius]` cho N vòng, vòng ĐẦU nằm ngoài cùng —
120
+ * đúng thứ tự Recharts xếp. Chừa 12% làm khe giữa hai vòng.
121
+ */
122
+ function band(i: number, count: number): { mid: number, width: number } {
123
+ const per = (props.outerRadius - props.innerRadius) / Math.max(1, count)
124
+ const outer = props.outerRadius - i * per
125
+ const width = per * 0.88
126
+ return { mid: outer - width / 2, width }
127
+ }
128
+
129
+ interface Segment {
130
+ key: string
131
+ label: string
132
+ color: string
133
+ value: string
134
+ raw: number
135
+ mid: number
136
+ width: number
137
+ trackPath: string
138
+ valuePath: string
139
+ labelAt: { x: number, y: number }
140
+ labelFits: boolean
141
+ inactive: boolean
142
+ }
143
+
144
+ const segments = computed<Segment[]>(() => {
145
+ const c = center.value
146
+
147
+ if (props.stacked) {
148
+ // MỘT vòng, các đoạn nối tiếp: đoạn sau bắt đầu ở chỗ đoạn trước dừng lại.
149
+ const row = props.data[0]
150
+ const b = band(0, 1)
151
+ let acc = 0
152
+ return categories.value.map((key, i) => {
153
+ const raw = Number(row?.[key]) || 0
154
+ const from = props.startAngle + (acc / maxValue.value) * sweep.value
155
+ acc += raw
156
+ const to = props.startAngle + (acc / maxValue.value) * sweep.value
157
+ const arcLen = ((to - from) / 360) * 2 * Math.PI * b.mid
158
+ return {
159
+ key,
160
+ label: labelOf(key),
161
+ color: colorOf(key),
162
+ raw,
163
+ value: formatValue(raw, key),
164
+ mid: b.mid,
165
+ width: b.width,
166
+ trackPath: i === 0 ? arcPath(c, c, b.mid, props.startAngle, props.endAngle) : '',
167
+ valuePath: arcPath(c, c, b.mid, from, to),
168
+ labelAt: polarToCartesian(c, c, b.mid, (from + to) / 2),
169
+ labelFits: arcLen > 46,
170
+ inactive: hidden.value.includes(key),
171
+ }
172
+ })
173
+ }
174
+
175
+ return props.data.map((row, i) => {
176
+ const name = String(row[props.index])
177
+ const raw = Number(row[props.value]) || 0
178
+ const ratio = maxValue.value === 0 ? 0 : Math.min(1, raw / maxValue.value)
179
+ const b = band(i, props.data.length)
180
+ // Nhãn đặt ở ĐẦU cung, thụt vào một chút — đúng `insideStart` của shadcn.
181
+ // Mọi vòng cùng góc bắt đầu nhưng khác bán kính nên chúng xếp thành một cột
182
+ // theo hướng đó. HƯỚNG ẤY PHẢI LÀ DỌC: đặt góc bắt đầu ở 9 hoặc 3 giờ thì
183
+ // các nhãn nằm ngang cùng một hàng và đè lên nhau (bán kính chỉ cách nhau
184
+ // ~17px trong khi chữ rộng ~35px). Ví dụ Label vì vậy bắt đầu ở 6 giờ.
185
+ const arcLen = ((sweep.value * ratio) / 360) * 2 * Math.PI * b.mid
186
+ const insetDeg = (10 / (2 * Math.PI * b.mid)) * 360
187
+ const labelAngle = props.startAngle + insetDeg
188
+ return {
189
+ key: name,
190
+ label: labelOf(name),
191
+ color: colorOf(name),
192
+ raw,
193
+ value: formatValue(raw, name),
194
+ mid: b.mid,
195
+ width: b.width,
196
+ trackPath: arcPath(c, c, b.mid, props.startAngle, props.endAngle),
197
+ valuePath: arcPath(c, c, b.mid, props.startAngle, props.startAngle + sweep.value * ratio),
198
+ labelAt: polarToCartesian(c, c, b.mid, labelAngle),
199
+ labelFits: arcLen > 46,
200
+ inactive: hidden.value.includes(name),
201
+ }
202
+ })
203
+ })
204
+
205
+ /** Vòng kẻ tròn ở mép ngoài của từng vòng dữ liệu. */
206
+ const gridRadii = computed(() => (props.showGrid
207
+ ? segments.value.map(s => s.mid + s.width / 2)
208
+ : []))
209
+
210
+ /**
211
+ * viewBox cắt theo cung THẬT SỰ được vẽ, cộng lề.
212
+ * Để nguyên khung vuông thì biểu đồ bán nguyệt dạt lên trên và bỏ trống nửa
213
+ * dưới — trông như bị lệch chứ không phải như một cái đồng hồ đo.
214
+ */
215
+ const bounds = computed(() => {
216
+ const c = center.value
217
+ return arcBounds(c, c, props.outerRadius, props.innerRadius, props.startAngle, props.endAngle)
218
+ })
219
+
220
+ const viewBox = computed(() => {
221
+ const b = bounds.value
222
+ return `${b.x - PAD} ${b.y - PAD} ${b.width + PAD * 2} ${b.height + PAD * 2}`
223
+ })
224
+
225
+ /**
226
+ * Chữ giữa đặt ở tâm KHUNG NHÌN THẤY, không phải tâm cực.
227
+ *
228
+ * Với cung không trọn vòng, viewBox bị cắt lệch nên tâm cực rơi ra sát mép —
229
+ * biểu đồ bán nguyệt vẽ ra là chữ "1.830" nằm ngoài khung và bị xén mất nửa.
230
+ * Lấy tâm của khung đã cắt thì chữ luôn nằm giữa phần nhìn thấy.
231
+ */
232
+ const labelCenter = computed(() => {
233
+ const b = bounds.value
234
+ return { x: b.x + b.width / 2, y: b.y + b.height / 2 }
235
+ })
236
+
237
+ const hovered = computed(() => segments.value.find(s => s.key === hoverKey.value) ?? null)
238
+
239
+ const tooltipRows = computed<ChartTooltipRow[]>(() => {
240
+ const s = hovered.value
241
+ return s ? [{ key: s.key, label: s.label, color: s.color, value: s.value, raw: s.raw }] : []
242
+ })
243
+
244
+ function onMove(event: MouseEvent): void {
245
+ const host = (event.currentTarget as HTMLElement).getBoundingClientRect()
246
+ pointer.value = { x: event.clientX - host.left, y: event.clientY - host.top }
247
+ }
248
+
249
+ function toggle(name: string): void {
250
+ hidden.value = hidden.value.includes(name)
251
+ ? hidden.value.filter(n => n !== name)
252
+ : [...hidden.value, name]
253
+ }
254
+ </script>
255
+
256
+ <template>
257
+ <ChartContainer :config="props.config" :class="cn(props.class)">
258
+ <div class="relative flex min-h-0 flex-1 items-center justify-center" @mousemove="onMove">
259
+ <svg
260
+ :viewBox="viewBox"
261
+ class="h-full max-h-full w-auto max-w-full"
262
+ role="img"
263
+ :aria-label="props.centralLabel ?? 'Radial chart'"
264
+ >
265
+ <circle
266
+ v-for="(r, i) in gridRadii"
267
+ :key="`grid-${i}`"
268
+ :cx="center"
269
+ :cy="center"
270
+ :r="r"
271
+ fill="none"
272
+ stroke="var(--border)"
273
+ stroke-width="1"
274
+ />
275
+
276
+ <g
277
+ v-for="segment in segments"
278
+ :key="segment.key"
279
+ @mouseenter="hoverKey = segment.key"
280
+ @mouseleave="hoverKey = null"
281
+ >
282
+ <!--
283
+ Cung vẽ bằng NÉT DÀY chạy dọc đường tâm của vành, không phải hình
284
+ quạt được tô. Nhờ vậy `stroke-linecap="round"` cho hai đầu bo tròn
285
+ mà không phải dựng path bo góc.
286
+ Vệt nền dùng --muted chứ không phải màu chuỗi pha loãng: pha loãng
287
+ thì phần thiếu vẫn mang sắc của chuỗi và đọc ra như đã đạt.
288
+ -->
289
+ <path
290
+ v-if="props.showTrack && segment.trackPath"
291
+ :d="segment.trackPath"
292
+ fill="none"
293
+ stroke="var(--muted)"
294
+ :stroke-width="segment.width"
295
+ :stroke-linecap="props.cornerRadius > 0 ? 'round' : 'butt'"
296
+ />
297
+ <path
298
+ v-if="segment.valuePath"
299
+ :d="segment.valuePath"
300
+ fill="none"
301
+ :stroke="segment.color"
302
+ :stroke-width="segment.width"
303
+ :stroke-linecap="props.cornerRadius > 0 ? 'round' : 'butt'"
304
+ :opacity="segment.inactive ? 0.15 : 1"
305
+ >
306
+ <title>{{ segment.label }}: {{ segment.value }}</title>
307
+ </path>
308
+ <text
309
+ v-if="props.showLabels && segment.labelFits && !segment.inactive"
310
+ :x="segment.labelAt.x"
311
+ :y="segment.labelAt.y"
312
+ text-anchor="middle"
313
+ dominant-baseline="middle"
314
+ class="pointer-events-none text-[10px] font-medium"
315
+ :fill="`var(--color-${segment.key}-foreground)`"
316
+ >{{ segment.label }}</text>
317
+ </g>
318
+
319
+ <text
320
+ v-if="props.centralLabel"
321
+ :x="labelCenter.x"
322
+ :y="props.centralSubLabel ? labelCenter.y - 4 : labelCenter.y"
323
+ text-anchor="middle"
324
+ dominant-baseline="middle"
325
+ class="fill-foreground text-[24px] font-semibold tabular-nums"
326
+ >{{ props.centralLabel }}</text>
327
+ <text
328
+ v-if="props.centralSubLabel"
329
+ :x="labelCenter.x"
330
+ :y="labelCenter.y + 18"
331
+ text-anchor="middle"
332
+ dominant-baseline="middle"
333
+ class="fill-muted-foreground text-[12px]"
334
+ >{{ props.centralSubLabel }}</text>
335
+ </svg>
336
+
337
+ <div
338
+ v-if="props.showTooltip && hovered"
339
+ class="pointer-events-none absolute z-(--z-raised)"
340
+ :style="{ left: `${pointer.x + 14}px`, top: `${pointer.y + 14}px` }"
341
+ >
342
+ <ChartTooltipCard :rows="tooltipRows" :options="{ hideLabel: true, ...props.tooltip }" />
343
+ </div>
344
+ </div>
345
+
346
+ <ChartLegend
347
+ v-if="props.showLegend"
348
+ :categories="names"
349
+ :hidden="hidden"
350
+ interactive
351
+ @toggle="toggle"
352
+ />
353
+ </ChartContainer>
354
+ </template>
@@ -0,0 +1,30 @@
1
+ export { default as AreaChart } from './AreaChart.vue'
2
+ export { default as BarChart } from './BarChart.vue'
3
+ export { default as ChartContainer } from './ChartContainer.vue'
4
+ export { default as ChartCrosshair } from './ChartCrosshair.vue'
5
+ export { default as ChartLegend } from './ChartLegend.vue'
6
+ export { default as ChartTooltipCard } from './ChartTooltipCard.vue'
7
+ export { default as LineChart } from './LineChart.vue'
8
+ export { default as PieChart } from './PieChart.vue'
9
+ export { annularArcPath, arcBounds, arcPath, polarToCartesian, polygonPoints, toPointsAttr } from './polar'
10
+ export type { Point } from './polar'
11
+
12
+ export { default as RadarChart } from './RadarChart.vue'
13
+ export { default as RadialChart } from './RadialChart.vue'
14
+ export { escapeHtml, formatChartValue, renderTooltip } from './tooltip'
15
+ export type {
16
+ ChartBaseProps,
17
+ ChartConfig,
18
+ ChartContext,
19
+ ChartCurve,
20
+ ChartLabelKey,
21
+ ChartSeriesConfig,
22
+ ChartTickFormatter,
23
+ ChartTooltipOptions,
24
+ ChartTooltipRow,
25
+ ChartValueFormatter,
26
+ } from './types'
27
+ export { CHART_CONTEXT_KEY } from './types'
28
+ export { toCurveType, useChartSeries } from './useChartSeries'
29
+ export { xyLabelHtml } from './xy-label'
30
+ export type { XYLabelOffset } from './xy-label'
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Lên `src/variants/lib/chart/polar` — hình học / ghép chuỗi thuần,
3
+ * không dính framework nào, nên cả hai cây đọc chung một bản.
4
+ */
5
+ export * from '../../variants/lib/chart/polar'
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Lên `src/variants/lib/chart/tooltip` — hình học / ghép chuỗi thuần,
3
+ * không dính framework nào, nên cả hai cây đọc chung một bản.
4
+ */
5
+ export * from '../../variants/lib/chart/tooltip'