@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,52 @@
1
+ import type { Component, InjectionKey, Ref } from 'vue'
2
+ import type { ChartSeriesConfig, ChartBaseProps as SharedChartBaseProps } from '../../variants/lib/chart/types'
3
+
4
+ /**
5
+ * Bộ kiểu dùng chung nằm ở `src/variants/lib/chart/types` — nó mô tả dữ
6
+ * liệu và tuỳ chọn hiển thị, không dính framework nào. Ở đây chỉ còn hai thứ
7
+ * CÓ dính: kiểu của `icon` trong config, và context của `ChartContainer`.
8
+ */
9
+ export type {
10
+ ChartCurve,
11
+ ChartLabelKey,
12
+ ChartSeriesConfig,
13
+ ChartTickFormatter,
14
+ ChartTooltipOptions,
15
+ ChartTooltipRow,
16
+ ChartValueFormatter,
17
+ } from '../../variants/lib/chart/types'
18
+
19
+ /** `icon` thu hẹp lại thành component của Vue. */
20
+ export interface ChartSeries extends Omit<ChartSeriesConfig, 'icon'> {
21
+ icon?: Component
22
+ }
23
+
24
+ /** Khoá của object là khoá trong dữ liệu. */
25
+ export type ChartConfig = Record<string, ChartSeries>
26
+
27
+ /**
28
+ * Prop dùng chung của mọi biểu đồ trục XY, đã chốt `config` về bản của Vue.
29
+ *
30
+ * `ChartBaseProps` ở tầng chung generic theo kiểu config đúng vì lý do này:
31
+ * `icon` là `unknown` ở đó và là `Component` ở đây, nên không generic thì
32
+ * `ChartConfig` của hai tầng không gán được cho nhau.
33
+ */
34
+ export type ChartBaseProps<T extends Record<string, unknown>>
35
+ = SharedChartBaseProps<T, ChartConfig>
36
+
37
+ /**
38
+ * Config được ChartContainer đưa xuống cho con.
39
+ *
40
+ * `colorOf` trả về chuỗi `var(--color-<key>)` chứ không phải màu đã resolve:
41
+ * biến đó do chính ChartContainer khai trên thẻ bọc, nên đổi theme hay đổi bảng
42
+ * màu là SVG tự đổi theo cascade, không cần đọc lại bằng JS.
43
+ */
44
+ export interface ChartContext {
45
+ config: ChartConfig
46
+ colorOf: (key: string) => string
47
+ labelOf: (key: string) => string
48
+ /** Con trỏ đang ở trong khung biểu đồ. Dùng để nhả tooltip đã ghim ra. */
49
+ hovered: Ref<boolean>
50
+ }
51
+
52
+ export const CHART_CONTEXT_KEY: InjectionKey<ChartContext> = Symbol('woodblock-chart')
@@ -0,0 +1,138 @@
1
+ import type { Ref } from 'vue'
2
+ import type { ChartBaseProps, ChartCurve } from './types'
3
+ import { CurveType } from '@unovis/ts'
4
+ import { computed, onMounted, ref } from 'vue'
5
+
6
+ /** Ba lựa chọn rút gọn -> tên đầy đủ trong enum của Unovis. */
7
+ const CURVE_MAP: Record<ChartCurve, CurveType> = {
8
+ monotone: CurveType.MonotoneX,
9
+ natural: CurveType.Natural,
10
+ linear: CurveType.Linear,
11
+ step: CurveType.StepAfter,
12
+ }
13
+
14
+ export function toCurveType(curve: ChartCurve): CurveType {
15
+ return CURVE_MAP[curve]
16
+ }
17
+
18
+ function toNumber(value: unknown): number {
19
+ const n = Number(value)
20
+ return Number.isFinite(n) ? n : 0
21
+ }
22
+
23
+ /** Số nhãn tối đa trên trục hoành trước khi bắt đầu bỏ bớt. */
24
+ const MAX_X_TICKS = 12
25
+
26
+ /**
27
+ * Nhận GETTER chứ không nhận giá trị: hook đọc chúng bên trong `computed`, nên
28
+ * truyền giá trị trần sẽ đóng băng ở lần gọi đầu và đổi `stacked` lúc chạy
29
+ * không có tác dụng.
30
+ */
31
+ export interface UseChartSeriesOptions {
32
+ stacked?: () => boolean
33
+ /** Chuẩn hoá mỗi cột về 100% — dùng cho biểu đồ "stacked expanded". */
34
+ expand?: () => boolean
35
+ }
36
+
37
+ /**
38
+ * Chuẩn bị dữ liệu vẽ dùng chung cho Area và Bar.
39
+ *
40
+ * Xếp chồng được tính SẴN THÀNH CỘT `__base_<key>` / `__value_<key>` / `__top_<key>` thay vì
41
+ * truyền mảng accessor `y` cho Unovis. Lý do: truyền mảng thì mọi lớp nằm chung
42
+ * một component nên chỉ đặt được MỘT `fill`, tức mất khả năng cho từng chuỗi
43
+ * một gradient riêng — mà gradient chính là thứ gallery area của shadcn dựa vào.
44
+ * Tách ra từng lớp rồi neo bằng `baseline` thì vừa chồng đúng, vừa tô riêng được.
45
+ */
46
+ export function useChartSeries<T extends Record<string, unknown>>(
47
+ props: ChartBaseProps<T>,
48
+ options: UseChartSeriesOptions = {},
49
+ ): {
50
+ categories: Ref<string[]>
51
+ plotData: Ref<Record<string, unknown>[]>
52
+ xTicks: Ref<number[]>
53
+ isMounted: Ref<boolean>
54
+ valueOf: (key: string) => (d: Record<string, unknown>) => number
55
+ topOf: (key: string) => (d: Record<string, unknown>) => number
56
+ baseOf: (key: string) => (d: Record<string, unknown>) => number
57
+ } {
58
+ // Bỏ trống `categories` thì lấy đúng các khoá trong `config`, giữ nguyên thứ tự
59
+ // khai báo — nhờ vậy màu, legend và thứ tự chồng lớp luôn khớp nhau.
60
+ const categories = computed(() => props.categories ?? Object.keys(props.config))
61
+
62
+ const plotData = computed<Record<string, unknown>[]>(() => {
63
+ const stacked = options.stacked?.() ?? false
64
+ const expand = options.expand?.() ?? false
65
+
66
+ return props.data.map((row, rowIndex) => {
67
+ // `__i` là chỉ số hàng, ghi sẵn vào dữ liệu.
68
+ // Cần vì `VisXYLabels` gọi accessor `x` KHÔNG truyền chỉ số
69
+ // (`getNumber(data, config.x)`), khác với Area/Line/Bar. Dùng
70
+ // `(_d, i) => i` ở đó sẽ ra NaN và Unovis lặng lẽ loại hết nhãn khỏi
71
+ // vùng vẽ — nhóm `xy-labels` render ra rỗng, không một cảnh báo nào.
72
+ const out: Record<string, unknown> = { ...row, __i: rowIndex }
73
+
74
+ if (!stacked) {
75
+ categories.value.forEach((key) => {
76
+ const raw = toNumber(row[key])
77
+ out[`__base_${key}`] = 0
78
+ out[`__value_${key}`] = raw
79
+ out[`__top_${key}`] = raw
80
+ })
81
+ return out
82
+ }
83
+
84
+ const total = expand
85
+ ? categories.value.reduce((sum, key) => sum + toNumber(row[key]), 0)
86
+ : 1
87
+
88
+ let acc = 0
89
+ categories.value.forEach((key) => {
90
+ const raw = toNumber(row[key])
91
+ const value = expand ? (total === 0 ? 0 : raw / total) : raw
92
+ out[`__base_${key}`] = acc
93
+ out[`__value_${key}`] = value
94
+ acc += value
95
+ out[`__top_${key}`] = acc
96
+ })
97
+ return out
98
+ })
99
+ })
100
+
101
+ /**
102
+ * Trục hoành chạy theo CHỈ SỐ, nên phải tự khai mốc chia.
103
+ * Để d3 tự chọn thì nó ra mốc lẻ như 0,5 hay 1,5 — mà chỉ số lẻ không ứng với
104
+ * điểm dữ liệu nào, nhãn hiện ra là chuỗi rỗng hoặc lặp lại.
105
+ */
106
+ const xTicks = computed(() => {
107
+ const n = plotData.value.length
108
+ if (n === 0)
109
+ return []
110
+ const stride = Math.max(1, Math.ceil(n / MAX_X_TICKS))
111
+ const ticks: number[] = []
112
+ for (let i = 0; i < n; i += stride)
113
+ ticks.push(i)
114
+ return ticks
115
+ })
116
+
117
+ // Trước khi mount, `height: 100%` tính theo một thẻ cha cao 0px nên biểu đồ ra
118
+ // 0px rồi không tự vẽ lại. Chờ mount xong mới trao chiều cao thật.
119
+ const isMounted = ref(false)
120
+ onMounted(() => {
121
+ isMounted.value = true
122
+ })
123
+
124
+ /**
125
+ * `valueOf` là ĐỘ CAO tính từ baseline, không phải toạ độ đỉnh.
126
+ *
127
+ * `getStackedData` của Unovis chồng theo kiểu `[base, base + y]`, nên đưa toạ
128
+ * độ đỉnh vào `y` sẽ cộng dồn thêm một lần nữa: lớp thứ hai vọt lên
129
+ * `base + top` thay vì dừng ở `top`. Lỗi này KHÔNG báo gì cả, biểu đồ vẫn vẽ
130
+ * ra một hình hợp lý — chỉ sai số. Dùng `topOf` cho thứ vẽ theo toạ độ tuyệt
131
+ * đối (đường kẻ), `valueOf` + `baseOf` cho thứ có xếp chồng (vùng).
132
+ */
133
+ const valueOf = (key: string) => (d: Record<string, unknown>): number => toNumber(d[`__value_${key}`])
134
+ const topOf = (key: string) => (d: Record<string, unknown>): number => toNumber(d[`__top_${key}`])
135
+ const baseOf = (key: string) => (d: Record<string, unknown>): number => toNumber(d[`__base_${key}`])
136
+
137
+ return { categories, plotData, xTicks, isMounted, valueOf, topOf, baseOf }
138
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Lên `src/variants/lib/chart/xy-label` — 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/xy-label'
@@ -0,0 +1,81 @@
1
+ <script setup lang="ts">
2
+ import type { CheckboxRootEmits, CheckboxRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import type { CheckboxVariants } from './index'
5
+ import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'reka-ui'
6
+ import { computed } from 'vue'
7
+ import { Check, Minus } from '../../lib/icons'
8
+ import { cn } from '../../lib/utils'
9
+ import { checkboxVariants, injectCheckboxGroupContext } from './index'
10
+
11
+ const props = withDefaults(
12
+ defineProps<CheckboxRootProps & ClassProps & {
13
+ size?: CheckboxVariants['size']
14
+ tone?: CheckboxVariants['tone']
15
+ /** Viền đỏ + `aria-invalid`. Trong `FormField` thì không cần khai — xem dưới. */
16
+ invalid?: boolean
17
+ }>(),
18
+ // Vue mặc định gán `false` cho prop kiểu Boolean khi không khai. Ở đây phải là
19
+ // `undefined` mới phân biệt được "không khai" với "khai là false" — `false` sẽ
20
+ // chặn mất cả nhóm lẫn `aria-invalid` trong chuỗi `??` bên dưới.
21
+ { invalid: undefined },
22
+ )
23
+
24
+ const emits = defineEmits<CheckboxRootEmits>()
25
+
26
+ defineSlots<{
27
+ /** Thay glyph trong ô. Nhận trạng thái để tự đổi hình khi indeterminate. */
28
+ indicator?: (props: { state: boolean | 'indeterminate' }) => unknown
29
+ }>()
30
+
31
+ // Nằm trong CheckboxGroup thì kế thừa cỡ, kiểu tô và trạng thái lỗi của nhóm.
32
+ // Prop khai thẳng trên từng ô vẫn thắng.
33
+ const group = injectCheckboxGroupContext(null)
34
+
35
+ const size = computed(() => props.size ?? group?.size.value)
36
+ const tone = computed(() => props.tone ?? group?.tone.value)
37
+ const invalid = computed(() => props.invalid ?? group?.invalid.value)
38
+
39
+ /**
40
+ * `v-bind="field"` của FormField truyền `aria-invalid` xuống dưới dạng **attr**,
41
+ * nên đọc luôn ở đây: control trong form tự đỏ viền, không phải nối tay `invalid`.
42
+ *
43
+ * Phải gọi trong template chứ không bọc thành computed: `useAttrs()` KHÔNG phản
44
+ * ứng — computed đọc nó sẽ nhớ đúng giá trị lúc render đầu rồi đứng im, nên ô
45
+ * vẫn viền xám sau khi form báo lỗi. Đọc `$attrs` ngay lúc render thì mỗi lần
46
+ * attr đổi, component render lại và giá trị tính lại theo.
47
+ */
48
+ function resolveInvalid(attrs: Record<string, unknown>): boolean {
49
+ return invalid.value ?? (attrs['aria-invalid'] === true || attrs['aria-invalid'] === 'true')
50
+ }
51
+
52
+ // Tách `class` và ba prop trình bày ra khỏi props trước khi forward: chúng
53
+ // không thuộc CheckboxRoot, để lọt xuống sẽ thành thuộc tính lạ trên DOM.
54
+ const delegated = computed(() => {
55
+ const { class: _class, size: _size, tone: _tone, invalid: _invalid, ...rest } = props
56
+ return rest
57
+ })
58
+
59
+ const forwarded = useForwardPropsEmits(delegated, emits)
60
+ </script>
61
+
62
+ <template>
63
+ <CheckboxRoot
64
+ v-slot="{ state }"
65
+ v-bind="forwarded"
66
+ :aria-invalid="resolveInvalid($attrs) || undefined"
67
+ :data-invalid="resolveInvalid($attrs) || undefined"
68
+ :class="cn(checkboxVariants({ size, tone, invalid: resolveInvalid($attrs) }), props.class)"
69
+ >
70
+ <!-- Indicator chỉ tồn tại khi đã chọn, nên animate-in chạy đúng một lần lúc
71
+ nó xuất hiện — không cần transition-group hay forceMount. -->
72
+ <CheckboxIndicator
73
+ class="flex size-full animate-in items-center justify-center text-current zoom-in-50 duration-(--duration-fast) motion-reduce:animate-none"
74
+ >
75
+ <slot name="indicator" :state="state">
76
+ <Minus v-if="state === 'indeterminate'" />
77
+ <Check v-else />
78
+ </slot>
79
+ </CheckboxIndicator>
80
+ </CheckboxRoot>
81
+ </template>
@@ -0,0 +1,129 @@
1
+ <script setup lang="ts">
2
+ import type { CheckboxRootEmits, CheckboxRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import type { CheckboxVariants } from './index'
5
+ import { useForwardPropsEmits } from 'reka-ui'
6
+ import { computed, useId } from 'vue'
7
+ import { cn } from '../../lib/utils'
8
+ import Label from '../label/Label.vue'
9
+ import Checkbox from './Checkbox.vue'
10
+ import { injectCheckboxGroupContext } from './index'
11
+
12
+ /**
13
+ * Attr rơi tự do phải đi xuống Ô, không đọng lại ở div bọc ngoài: `v-bind="field"`
14
+ * của FormField truyền `aria-invalid` và `aria-describedby` dưới dạng attr, mà
15
+ * cả hai đều tả cái ô chứ không tả cái hàng.
16
+ */
17
+ defineOptions({ inheritAttrs: false })
18
+
19
+ const props = withDefaults(
20
+ defineProps<CheckboxRootProps & ClassProps & {
21
+ size?: CheckboxVariants['size']
22
+ tone?: CheckboxVariants['tone']
23
+ invalid?: boolean
24
+ /** Nhãn. Cần đánh dấu chữ (ví dụ chèn link) thì dùng slot mặc định. */
25
+ label?: string
26
+ /** Dòng phụ bên dưới nhãn. */
27
+ description?: string
28
+ }>(),
29
+ // Vue mặc định gán `false` cho prop kiểu Boolean khi không khai. Ở đây phải là
30
+ // `undefined` mới phân biệt được "không khai" với "khai là false" — `false` sẽ
31
+ // chặn mất cả nhóm lẫn `aria-invalid` trong chuỗi `??` bên dưới.
32
+ { invalid: undefined },
33
+ )
34
+
35
+ const emits = defineEmits<CheckboxRootEmits>()
36
+
37
+ defineSlots<{
38
+ default?: () => unknown
39
+ description?: () => unknown
40
+ indicator?: (props: { state: boolean | 'indeterminate' }) => unknown
41
+ }>()
42
+
43
+ const group = injectCheckboxGroupContext(null)
44
+
45
+ const fallbackId = useId()
46
+ const controlId = computed(() => props.id ?? fallbackId)
47
+ const descriptionId = computed(() => `${controlId.value}-description`)
48
+
49
+ const hasDescription = computed(() => Boolean(props.description))
50
+
51
+ /**
52
+ * Nối chứ không ghi đè: field trong form đã trỏ sang thông báo lỗi rồi.
53
+ *
54
+ * Nhận `attrs` làm tham số để gọi thẳng trong template — `useAttrs()` không phản
55
+ * ứng, bọc vào computed là giá trị đứng im ở lần render đầu (xem Checkbox.vue).
56
+ */
57
+ function resolveDescribedBy(attrs: Record<string, unknown>): string | undefined {
58
+ const external = typeof attrs['aria-describedby'] === 'string' ? attrs['aria-describedby'] : undefined
59
+ const ids = [external, hasDescription.value ? descriptionId.value : undefined].filter(Boolean)
60
+ return ids.length > 0 ? ids.join(' ') : undefined
61
+ }
62
+
63
+ const size = computed(() => props.size ?? group?.size.value ?? 'md')
64
+
65
+ /**
66
+ * Đẩy ô xuống cho tâm nó thẳng hàng với dòng chữ ĐẦU TIÊN của nhãn, không phải
67
+ * với cả khối. Nhãn là `text-sm` nên dòng cao 20px, tâm ở 10px: ô 14px lệch
68
+ * 3px, ô 16px lệch 2px, ô 20px vừa khít.
69
+ */
70
+ const alignClass = computed(() => ({
71
+ sm: 'mt-[3px]',
72
+ md: 'mt-0.5',
73
+ lg: 'mt-0',
74
+ }[size.value ?? 'md']))
75
+
76
+ const delegated = computed(() => {
77
+ const {
78
+ class: _class,
79
+ size: _size,
80
+ tone: _tone,
81
+ invalid: _invalid,
82
+ label: _label,
83
+ description: _description,
84
+ ...rest
85
+ } = props
86
+ return rest
87
+ })
88
+
89
+ const forwarded = useForwardPropsEmits(delegated, emits)
90
+ </script>
91
+
92
+ <template>
93
+ <div :class="cn('flex items-start gap-2.5', props.class)">
94
+ <Checkbox
95
+ v-bind="{ ...forwarded, ...$attrs }"
96
+ :id="controlId"
97
+ :size="props.size"
98
+ :tone="props.tone"
99
+ :invalid="props.invalid"
100
+ :aria-describedby="resolveDescribedBy($attrs)"
101
+ :class="alignClass"
102
+ >
103
+ <template v-if="$slots.indicator" #indicator="slotProps">
104
+ <slot name="indicator" v-bind="slotProps" />
105
+ </template>
106
+ </Checkbox>
107
+
108
+ <div class="flex flex-col gap-1">
109
+ <!-- `for` trỏ vào chính ô: <button> là labelable element nên bấm vào chữ
110
+ cũng bật/tắt được, không phải bọc ô vào trong <label>. -->
111
+ <Label
112
+ :for="controlId"
113
+ :class="props.disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'"
114
+ >
115
+ <slot>{{ props.label }}</slot>
116
+ </Label>
117
+
118
+ <p
119
+ v-if="hasDescription || $slots.description"
120
+ :id="descriptionId"
121
+ :class="cn('text-xs leading-snug text-muted-foreground', props.disabled && 'opacity-50')"
122
+ >
123
+ <slot name="description">
124
+ {{ props.description }}
125
+ </slot>
126
+ </p>
127
+ </div>
128
+ </div>
129
+ </template>
@@ -0,0 +1,62 @@
1
+ <script setup lang="ts" generic="T extends AcceptableValue = AcceptableValue">
2
+ import type { AcceptableValue, CheckboxGroupRootEmits, CheckboxGroupRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import type { CheckboxVariants } from './index'
5
+ import { CheckboxGroupRoot, useForwardPropsEmits } from 'reka-ui'
6
+ import { computed } from 'vue'
7
+ import { cn } from '../../lib/utils'
8
+ import { provideCheckboxGroupContext } from './index'
9
+
10
+ const props = withDefaults(
11
+ defineProps<CheckboxGroupRootProps<T> & ClassProps & {
12
+ size?: CheckboxVariants['size']
13
+ tone?: CheckboxVariants['tone']
14
+ invalid?: boolean
15
+ }>(),
16
+ {
17
+ orientation: 'vertical',
18
+ invalid: false,
19
+ /**
20
+ * Reka mặc định `true` — mỗi nhóm chỉ một điểm dừng Tab, di chuyển bằng
21
+ * phím mũi tên. Đó là khuôn của **radio group**: ở đó chọn cái này là bỏ
22
+ * cái kia nên đi qua cả nhóm bằng mũi tên là hợp lý.
23
+ *
24
+ * Ô đánh dấu thì độc lập với nhau, và WAI-ARIA APG xếp **từng ô** vào chuỗi
25
+ * Tab. Bật roving focus sẽ khiến người dùng bàn phím bỏ sót các ô còn lại
26
+ * nếu họ chỉ nhấn Tab. Cần khuôn kia thì khai `roving-focus` tường minh.
27
+ */
28
+ rovingFocus: false,
29
+ },
30
+ )
31
+
32
+ const emits = defineEmits<CheckboxGroupRootEmits<T>>()
33
+
34
+ const delegated = computed(() => {
35
+ const { class: _class, size: _size, tone: _tone, invalid: _invalid, ...rest } = props
36
+ return rest
37
+ })
38
+
39
+ const forwarded = useForwardPropsEmits(delegated, emits)
40
+
41
+ // Cỡ và kiểu tô khai một lần ở nhóm, từng ô con khỏi lặp lại.
42
+ provideCheckboxGroupContext({
43
+ size: computed(() => props.size),
44
+ tone: computed(() => props.tone),
45
+ invalid: computed(() => props.invalid),
46
+ })
47
+ </script>
48
+
49
+ <template>
50
+ <CheckboxGroupRoot
51
+ v-bind="forwarded"
52
+ :class="cn(
53
+ 'flex',
54
+ props.orientation === 'horizontal'
55
+ ? 'flex-wrap items-center gap-x-5 gap-y-2.5'
56
+ : 'flex-col gap-2.5',
57
+ props.class,
58
+ )"
59
+ >
60
+ <slot />
61
+ </CheckboxGroupRoot>
62
+ </template>
@@ -0,0 +1,21 @@
1
+ import type { ComputedRef } from 'vue'
2
+ import type { CheckboxVariants } from '../../variants/components/checkbox'
3
+ import { createContext } from 'reka-ui'
4
+
5
+ export { checkboxVariants, type CheckboxVariants } from '../../variants/components/checkbox'
6
+ export { default as Checkbox } from './Checkbox.vue'
7
+ export { default as CheckboxField } from './CheckboxField.vue'
8
+
9
+ /** Cỡ/kiểu tô/trạng thái lỗi mà `CheckboxGroup` truyền xuống từng ô con. */
10
+ export interface CheckboxGroupContext {
11
+ size: ComputedRef<CheckboxVariants['size']>
12
+ tone: ComputedRef<CheckboxVariants['tone']>
13
+ invalid: ComputedRef<boolean>
14
+ }
15
+
16
+ // Dùng createContext của reka thay vì tự khai InjectionKey: cùng một cơ chế với
17
+ // mọi context khác đang chạy trong cây component, và báo lỗi kèm tên component.
18
+ export const [injectCheckboxGroupContext, provideCheckboxGroupContext]
19
+ = createContext<CheckboxGroupContext>('CheckboxGroup')
20
+
21
+ export { default as CheckboxGroup } from './CheckboxGroup.vue'
@@ -0,0 +1,73 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { BadgeVariants } from '../badge'
4
+ import type { ChipVariants } from './index'
5
+ import { computed } from 'vue'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { X } from '../../lib/icons'
8
+ import { cn } from '../../lib/utils'
9
+ import { badgeVariants } from '../badge'
10
+ import { chipVariants } from './index'
11
+
12
+ const props = withDefaults(
13
+ defineProps<ClassProps & {
14
+ variant?: BadgeVariants['variant']
15
+ tone?: BadgeVariants['tone']
16
+ size?: ChipVariants['size']
17
+ /** Hiện nút ×. Không bật thì Chip chỉ là một nhãn bo tròn. */
18
+ removable?: boolean
19
+ /**
20
+ * Nhãn cho nút gỡ. Kèm tên chip vào để đọc ra "Gỡ Đang mở".
21
+ *
22
+ * KHÔNG đặt default ở `withDefaults`: default tính một lần lúc dựng
23
+ * component nên nó đóng băng ở ngôn ngữ lúc đó. Rơi lui bằng computed.
24
+ */
25
+ removeLabel?: string
26
+ disabled?: boolean
27
+ }>(),
28
+ { removable: false, disabled: false },
29
+ )
30
+
31
+ const emit = defineEmits<{ remove: [] }>()
32
+
33
+ const { t } = useI18n()
34
+
35
+ const removeLabel = computed(() => props.removeLabel ?? t('ui.chip.remove'))
36
+
37
+ /**
38
+ * Lấy phần MÀU của badgeVariants rồi bỏ phần hình dáng đi.
39
+ *
40
+ * `badgeVariants` gộp cả hai trong một chuỗi. `cn()` dùng tailwind-merge nên
41
+ * lớp hình dáng của chip viết sau sẽ thắng `rounded-md px-2 py-0.5 text-xs` của
42
+ * badge — không phải cắt chuỗi bằng tay.
43
+ */
44
+ const classes = computed(() => cn(
45
+ badgeVariants({ variant: props.variant, tone: props.tone }),
46
+ chipVariants({ size: props.size, removable: props.removable }),
47
+ props.disabled && 'pointer-events-none opacity-50',
48
+ props.class,
49
+ ))
50
+ </script>
51
+
52
+ <template>
53
+ <span :class="classes">
54
+ <slot name="leading" />
55
+ <span class="min-w-0 truncate"><slot /></span>
56
+
57
+ <!--
58
+ Nút gỡ là <button> thật, không phải icon bấm được: nó phải vào được chuỗi
59
+ Tab và nhận Enter/Space. `currentColor` cho nó tự hợp với mọi variant, kể
60
+ cả nền đặc lẫn nền soft.
61
+ -->
62
+ <button
63
+ v-if="props.removable"
64
+ type="button"
65
+ class="grid size-4 shrink-0 place-items-center rounded-full text-current opacity-60 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current"
66
+ :aria-label="removeLabel"
67
+ :disabled="props.disabled"
68
+ @click.stop="emit('remove')"
69
+ >
70
+ <X class="size-3" />
71
+ </button>
72
+ </span>
73
+ </template>
@@ -0,0 +1,3 @@
1
+ export { chipVariants, type ChipVariants } from '../../variants/components/chip'
2
+
3
+ export { default as Chip } from './Chip.vue'
@@ -0,0 +1,100 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { Language } from '../../variants/lib/highlight'
4
+ import { computed, onUnmounted, ref } from 'vue'
5
+ import { useI18n } from '../../composables/useI18n'
6
+ import { Check, Copy } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+ import { codeTokenClass } from '../../variants/components/code-block'
9
+ import { highlightLines } from '../../variants/lib/highlight'
10
+
11
+ const props = withDefaults(
12
+ defineProps<ClassProps & {
13
+ code: string
14
+ /** `vue` cho SFC và template, `ts` cho đoạn script thuần. */
15
+ language?: Language
16
+ /** Tắt khi khối chỉ có một hai dòng lệnh shell. */
17
+ lineNumbers?: boolean
18
+ /** Bỏ viền khi khối nằm ngay dưới khung preview (đã có viền ngoài). */
19
+ bordered?: boolean
20
+ /** Quá số dòng này thì khối tự cuộn dọc thay vì kéo dài trang. */
21
+ maxLines?: number
22
+ }>(),
23
+ { language: 'vue', lineNumbers: true, bordered: true, maxLines: 10 },
24
+ )
25
+ const { t } = useI18n()
26
+ /** Giữ trạng thái "đã chép" bao lâu trước khi cho bấm lại. */
27
+ const RESET_DELAY = 3000
28
+
29
+ /**
30
+ * Chiều cao trần = số dòng × line-height + padding dọc.
31
+ * `em` ăn theo font-size của chính khối code (12.5px) nên đổi cỡ chữ là nó tự
32
+ * theo, không phải chỉnh lại con số.
33
+ */
34
+ const maxHeight = computed(() => `calc(${props.maxLines} * 1.85em + 2rem)`)
35
+
36
+ /** Cắt theo dòng để số dòng bên trái luôn thẳng hàng với nội dung. */
37
+ const lines = computed(() => highlightLines(props.code, props.language))
38
+
39
+ const copied = ref(false)
40
+ let timer: ReturnType<typeof setTimeout> | undefined
41
+
42
+ onUnmounted(() => clearTimeout(timer))
43
+
44
+ async function copy(): Promise<void> {
45
+ try {
46
+ await navigator.clipboard.writeText(props.code)
47
+ }
48
+ catch {
49
+ // Clipboard API cần ngữ cảnh bảo mật (https hoặc localhost). Không chép
50
+ // được thì thôi, không báo thành công nhầm.
51
+ return
52
+ }
53
+
54
+ copied.value = true
55
+ clearTimeout(timer)
56
+ timer = setTimeout(() => {
57
+ copied.value = false
58
+ }, RESET_DELAY)
59
+ }
60
+ </script>
61
+
62
+ <template>
63
+ <div :class="cn('relative', props.class)">
64
+ <button
65
+ type="button"
66
+ :aria-label="copied ? t('ui.copied') : t('ui.copy.code')"
67
+ class="absolute right-3 top-3 z-(--z-raised) grid size-[26px] place-items-center rounded-md border border-border bg-card text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&_svg]:size-[13px]"
68
+ :disabled="copied"
69
+ @click="copy"
70
+ >
71
+ <Check v-if="copied" class="text-success" />
72
+ <Copy v-else />
73
+ </button>
74
+
75
+ <!-- Nền tô ở lớp ngoài, đúng MỘT lần; lớp trong chỉ lo cuộn và mờ dần. -->
76
+ <div
77
+ class="overflow-hidden bg-code-bg"
78
+ :class="bordered ? 'rounded-xl border border-border' : 'border-t border-border'"
79
+ >
80
+ <div
81
+ class="overflow-auto py-4 pl-[18px] pr-[44px] font-mono text-[12.5px] leading-[1.85] text-code-fg"
82
+ :style="{ maxHeight }"
83
+ >
84
+ <div
85
+ v-for="(tokens, row) in lines"
86
+ :key="row"
87
+ class="grid w-max gap-3.5 pr-[42px]"
88
+ :class="lineNumbers ? 'grid-cols-[28px_max-content]' : 'grid-cols-[max-content]'"
89
+ >
90
+ <span v-if="lineNumbers" class="text-right text-muted-foreground opacity-65">{{ row + 1 }}</span>
91
+ <span class="min-w-0 whitespace-pre"><span
92
+ v-for="(token, index) in tokens"
93
+ :key="index"
94
+ :class="codeTokenClass[token.kind]"
95
+ >{{ token.value }}</span></span>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </template>
@@ -0,0 +1,4 @@
1
+ // Kiểu của prop `language`. Export ở đây để app khai được mà không phải
2
+ // import từ `src/variants/lib/highlight`.
3
+ export type { Language } from '../../variants/lib/highlight'
4
+ export { default as CodeBlock } from './CodeBlock.vue'