@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,18 @@
1
+ <script setup lang="ts">
2
+ import type { TagsInputItemTextProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { TagsInputItemText } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<TagsInputItemTextProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <TagsInputItemText v-bind="delegated" :class="cn('min-w-0 truncate', props.class)" />
18
+ </template>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Ô nhập biến từng mục thành một chip: người nhận trong ô "To:", tag của bài
3
+ * viết, bộ lọc đang áp.
4
+ *
5
+ * Dáng của chip lấy thẳng `badgeVariants` + `chipVariants` của `Chip`, nên hai
6
+ * chỗ không trôi khỏi nhau. Nhưng KHÔNG bọc chính `Chip`: nút gỡ của nó và
7
+ * `TagsInputItemDelete` của reka sẽ tranh nhau một việc, mà bản của reka mới là
8
+ * bản biết xoá khỏi model rồi trả focus về ô nhập.
9
+ */
10
+
11
+ export { default as InputTags } from './InputTags.vue'
12
+ export { default as InputTagsClear } from './InputTagsClear.vue'
13
+ export { default as InputTagsInput } from './InputTagsInput.vue'
14
+ export { default as InputTagsItem } from './InputTagsItem.vue'
15
+ export { default as InputTagsItemDelete } from './InputTagsItemDelete.vue'
16
+ export { default as InputTagsItemText } from './InputTagsItemText.vue'
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { KbdVariants } from './index'
4
+ import { cn } from '../../lib/utils'
5
+ import { kbdVariants } from './index'
6
+
7
+ const props = defineProps<ClassProps & {
8
+ size?: KbdVariants['size']
9
+ tone?: KbdVariants['tone']
10
+ }>()
11
+ </script>
12
+
13
+ <template>
14
+ <kbd :class="cn(kbdVariants({ size: props.size, tone: props.tone }), props.class)">
15
+ <slot />
16
+ </kbd>
17
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <!-- Cũng là thẻ <kbd>, lồng đúng theo HTML spec: một tổ hợp phím là một <kbd>
10
+ chứa nhiều <kbd> con. Trình đọc màn hình nhờ vậy đọc ra "phím tắt" chứ
11
+ không phải mấy chữ rời rạc. -->
12
+ <kbd :class="cn('inline-flex items-center gap-1', props.class)">
13
+ <slot />
14
+ </kbd>
15
+ </template>
@@ -0,0 +1,4 @@
1
+ export { kbdVariants, type KbdVariants } from '../../variants/components/kbd'
2
+ export { default as Kbd } from './Kbd.vue'
3
+
4
+ export { default as KbdGroup } from './KbdGroup.vue'
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import type { LabelProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { Label } from 'reka-ui'
5
+ import { cn } from '../../lib/utils'
6
+
7
+ const props = defineProps<LabelProps & ClassProps>()
8
+ </script>
9
+
10
+ <template>
11
+ <Label
12
+ :for="props.for"
13
+ :as="props.as"
14
+ :as-child="props.asChild"
15
+ :class="cn(
16
+ 'text-sm font-medium leading-none select-none',
17
+ 'peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
18
+ props.class,
19
+ )"
20
+ >
21
+ <slot />
22
+ </Label>
23
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Label } from './Label.vue'
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ListboxRoot, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = withDefaults(
9
+ defineProps<ListboxRootProps & ClassProps>(),
10
+ { highlightOnHover: true },
11
+ )
12
+ const emits = defineEmits<ListboxRootEmits>()
13
+
14
+ const delegated = computed(() => {
15
+ const { class: _class, ...rest } = props
16
+ return rest
17
+ })
18
+
19
+ const forwarded = useForwardPropsEmits(delegated, emits)
20
+ </script>
21
+
22
+ <template>
23
+ <!--
24
+ `highlightOnHover` bật sẵn, khác mặc định của reka.
25
+
26
+ Đây là danh sách LUÔN hiện, không phải một tấm menu vừa bung ra: con trỏ đã
27
+ ở trong vùng đó suốt, nên không rê chuột mà vẫn sáng theo bàn phím thì đọc
28
+ ra như danh sách chết. Tắt đi khi dòng nào cũng có nút riêng bên trong, vì
29
+ lúc đó hai vùng sáng chồng nhau.
30
+ -->
31
+ <ListboxRoot
32
+ v-bind="forwarded"
33
+ :class="cn(
34
+ 'surface flex w-full flex-col overflow-hidden rounded-md border border-border bg-background text-sm',
35
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
36
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
37
+ props.class,
38
+ )"
39
+ >
40
+ <slot />
41
+ </ListboxRoot>
42
+ </template>
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxContentProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ListboxContent } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<ListboxContentProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <!-- Vùng cuộn. Chiều cao do bên gọi đặt (`max-h-*`) — danh sách dài bao nhiêu
18
+ thì chỉ bên gọi biết. -->
19
+ <ListboxContent v-bind="delegated" :class="cn('flex flex-col gap-0.5 overflow-y-auto p-1', props.class)">
20
+ <slot />
21
+ </ListboxContent>
22
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxFilterEmits, ListboxFilterProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ListboxFilter, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { Search } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ const props = defineProps<ListboxFilterProps & ClassProps & { placeholder?: string }>()
10
+ const emits = defineEmits<ListboxFilterEmits>()
11
+
12
+ const delegated = computed(() => {
13
+ const { class: _class, placeholder: _placeholder, ...rest } = props
14
+ return rest
15
+ })
16
+
17
+ const forwarded = useForwardPropsEmits(delegated, emits)
18
+ </script>
19
+
20
+ <template>
21
+ <!--
22
+ Ô lọc KHÔNG tự lọc gì cả — nó chỉ giữ chuỗi và chuyển phím mũi tên xuống
23
+ danh sách, đúng cách `Command` làm. Bên gọi tự quyết lọc thế nào; xem ghi
24
+ chú ở `components/command/index.ts` để biết vì sao.
25
+ -->
26
+ <div :class="cn('flex items-center gap-2 border-b border-border px-3', props.class)">
27
+ <Search class="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
28
+ <ListboxFilter
29
+ v-bind="forwarded"
30
+ :placeholder="props.placeholder"
31
+ class="h-9 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground"
32
+ />
33
+ </div>
34
+ </template>
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxGroupProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ListboxGroup, ListboxGroupLabel } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<ListboxGroupProps & ClassProps & { heading?: string }>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, heading: _heading, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <!-- Nhãn nhóm phải là `ListboxGroupLabel` chứ không phải một `<div>` tự viết:
18
+ reka nối nó vào nhóm bằng `aria-labelledby`, nên trình đọc màn hình mới
19
+ đọc ra "Nhóm X, mục 2 trên 5". -->
20
+ <ListboxGroup v-bind="delegated" :class="cn('flex flex-col gap-0.5', props.class)">
21
+ <ListboxGroupLabel
22
+ v-if="props.heading || $slots.heading"
23
+ class="px-2 py-1.5 text-xs font-medium text-muted-foreground"
24
+ >
25
+ <slot name="heading">
26
+ {{ props.heading }}
27
+ </slot>
28
+ </ListboxGroupLabel>
29
+ <slot />
30
+ </ListboxGroup>
31
+ </template>
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ListboxItem, ListboxItemIndicator, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { Check } from '../../lib/icons'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ // Không đặt generic ở đây, cùng lý do với SelectItem: generic làm TS mất thông
10
+ // tin "value là bắt buộc" lúc forward prop xuống primitive của reka.
11
+ const props = defineProps<ListboxItemProps & ClassProps>()
12
+ const emits = defineEmits<ListboxItemEmits>()
13
+
14
+ const delegated = computed(() => {
15
+ const { class: _class, ...rest } = props
16
+ return rest
17
+ })
18
+
19
+ const forwarded = useForwardPropsEmits(delegated, emits)
20
+ </script>
21
+
22
+ <template>
23
+ <!--
24
+ Hai trạng thái KHÁC NHAU, và trộn chúng là lỗi hay gặp nhất ở listbox:
25
+ `data-highlighted` là dòng bàn phím đang đứng, `data-state=checked` là dòng
26
+ đã chọn. Ở chế độ nhiều lựa chọn, hai dòng đó thường không phải một.
27
+ -->
28
+ <ListboxItem
29
+ v-bind="forwarded"
30
+ :class="cn(
31
+ 'relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none transition-colors',
32
+ 'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',
33
+ 'data-[state=checked]:font-medium',
34
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
35
+ '[&_svg]:size-4 [&_svg]:shrink-0',
36
+ props.class,
37
+ )"
38
+ >
39
+ <slot />
40
+ <span class="absolute right-2 flex size-4 items-center justify-center">
41
+ <ListboxItemIndicator>
42
+ <Check class="size-4" />
43
+ </ListboxItemIndicator>
44
+ </span>
45
+ </ListboxItem>
46
+ </template>
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Danh sách chọn LUÔN HIỆN. Cùng primitive với `Command`, khác cách đóng khung.
3
+ *
4
+ * | dùng khi | lấy cái nào |
5
+ * |---|---|
6
+ * | danh sách ngắn, luôn thấy, chọn một hoặc nhiều | `Listbox` |
7
+ * | cùng lựa chọn đó nhưng thu vào một nút | `Select` |
8
+ * | gõ để lọc, danh sách dài, mở bằng phím tắt | `Command` |
9
+ *
10
+ * `ListboxFilter` có ở đây cho trường hợp danh sách hơi dài nhưng vẫn muốn nó
11
+ * nằm nguyên trong trang. Nó **không tự lọc** — bên gọi tự quyết, cùng lý do đã
12
+ * ghi ở `components/command/index.ts`.
13
+ */
14
+
15
+ export { default as Listbox } from './Listbox.vue'
16
+ export { default as ListboxContent } from './ListboxContent.vue'
17
+ export { default as ListboxFilter } from './ListboxFilter.vue'
18
+ export { default as ListboxGroup } from './ListboxGroup.vue'
19
+ export { default as ListboxItem } from './ListboxItem.vue'
@@ -0,0 +1,205 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { computed, nextTick, ref, watch } from 'vue'
4
+ import { focusRing, invalidRing } from '../../lib/focus'
5
+ import { cn } from '../../lib/utils'
6
+ import { dataBefore, formatMask, parseMask, toRaw } from './index'
7
+
8
+ /**
9
+ * Gốc là một `<div>` bọc ngoài, nên thuộc tính rơi tự do phải chuyển tay vào
10
+ * đúng cái `<input>` — cùng lý do đã ghi ở `Input.vue`.
11
+ */
12
+ defineOptions({ inheritAttrs: false })
13
+
14
+ const props = withDefaults(
15
+ defineProps<ClassProps & {
16
+ /** `9` là chữ số, `a` là chữ cái, `*` là chữ hoặc số. Còn lại là cố định. */
17
+ mask: string
18
+ /** Ký tự giữ chỗ cho ô chưa điền. */
19
+ slotChar?: string
20
+ /** Giá trị là dữ liệu THÔ, không kèm ký tự cố định. */
21
+ unmask?: boolean
22
+ invalid?: boolean
23
+ disabled?: boolean
24
+ size?: 'sm' | 'default'
25
+ placeholder?: string
26
+ }>(),
27
+ { slotChar: '_', unmask: false, size: 'default' },
28
+ )
29
+
30
+ const model = defineModel<string>({ default: '' })
31
+
32
+ const input = ref<HTMLInputElement>()
33
+ const focused = ref(false)
34
+
35
+ const slots = computed(() => parseMask(props.mask))
36
+
37
+ /** Dữ liệu thật, không định dạng. Đây mới là nguồn sự thật của component. */
38
+ const raw = ref(toRaw(model.value, slots.value))
39
+
40
+ const result = computed(() => formatMask(raw.value, slots.value, props.slotChar))
41
+
42
+ /**
43
+ * Khuôn chỉ hiện ra khi ô ĐANG focus hoặc ĐÃ có gì đó.
44
+ *
45
+ * PrimeVue hiện `(___) ___-____` mọi lúc. Với ô rỗng thì đó là một ô trông như
46
+ * đã điền sẵn, và trình đọc màn hình đọc ra một tràng gạch dưới trước cả khi
47
+ * người dùng biết mình đang ở đâu. Placeholder làm đúng việc đó tốt hơn.
48
+ */
49
+ const display = computed(() => {
50
+ if (raw.value.length === 0 && !focused.value)
51
+ return ''
52
+ return result.value.text
53
+ })
54
+
55
+ /** Đủ mọi ô dữ liệu thì mới coi là hoàn chỉnh. */
56
+ const complete = computed(() =>
57
+ raw.value.length === slots.value.filter(slot => slot.accepts !== undefined).length,
58
+ )
59
+
60
+ const inputMode = computed(() =>
61
+ props.mask.includes('a') || props.mask.includes('*') ? undefined : 'numeric',
62
+ )
63
+
64
+ function publish(): void {
65
+ model.value = props.unmask ? raw.value : result.value.filled
66
+ }
67
+
68
+ /** Ghi thẳng vào DOM rồi đặt con trỏ — Vue không kịp làm việc này giữa hai phím. */
69
+ function render(caret: number): void {
70
+ const el = input.value
71
+ if (el === undefined)
72
+ return
73
+ el.value = display.value
74
+ el.setSelectionRange(caret, caret)
75
+ }
76
+
77
+ function onInput(): void {
78
+ const el = input.value
79
+ if (el === undefined)
80
+ return
81
+
82
+ // Đếm số ký tự dữ liệu nằm TRƯỚC con trỏ, rồi đặt lại con trỏ ngay sau đúng
83
+ // chừng ấy ô. Nhảy thẳng về cuối chuỗi thì gõ chen vào giữa một số điện thoại
84
+ // đã điền dở sẽ hất con trỏ đi mất sau mỗi phím.
85
+ const before = toRaw(el.value.slice(0, el.selectionStart ?? 0), slots.value).length
86
+
87
+ raw.value = toRaw(el.value, slots.value)
88
+ publish()
89
+ void nextTick(() => render(caretAfter(before)))
90
+ }
91
+
92
+ /**
93
+ * Backspace và Delete phải tự viết, không để trình duyệt xử lý.
94
+ *
95
+ * Mặc định nó xoá ký tự ngay trước con trỏ, mà ký tự đó thường là một ký tự CỐ
96
+ * ĐỊNH. Xoá xong thì `toRaw` vẫn ra đúng chuỗi cũ, khuôn dựng lại y nguyên, và
97
+ * người dùng thấy phím Backspace không làm gì cả — bấm bao nhiêu lần cũng vậy.
98
+ * Nên phím đó phải nhắm vào ô DỮ LIỆU, không nhắm vào ký tự.
99
+ */
100
+ function onKeydown(event: KeyboardEvent): void {
101
+ if (event.key !== 'Backspace' && event.key !== 'Delete')
102
+ return
103
+
104
+ const el = input.value
105
+ if (el === undefined)
106
+ return
107
+
108
+ event.preventDefault()
109
+
110
+ const start = el.selectionStart ?? 0
111
+ const end = el.selectionEnd ?? start
112
+
113
+ // Kẹp vào độ dài dữ liệu THẬT. Bấm chuột vào vùng giữ chỗ rồi bấm Backspace
114
+ // thì `dataBefore` đếm cả những ô còn trống, ra một chỉ số nằm ngoài `raw`,
115
+ // và phím đó im lặng không làm gì — đúng cái mà nó sinh ra để tránh.
116
+ const from = Math.min(dataBefore(slots.value, start), raw.value.length)
117
+
118
+ if (end > start) {
119
+ // Bôi đen rồi xoá: bỏ đúng những ô dữ liệu nằm trong vùng bôi đen.
120
+ const to = Math.min(dataBefore(slots.value, end), raw.value.length)
121
+ raw.value = raw.value.slice(0, from) + raw.value.slice(to)
122
+ publish()
123
+ void nextTick(() => render(caretAfter(from)))
124
+ return
125
+ }
126
+
127
+ const index = event.key === 'Backspace' ? from - 1 : from
128
+ if (index < 0 || index >= raw.value.length)
129
+ return
130
+
131
+ raw.value = raw.value.slice(0, index) + raw.value.slice(index + 1)
132
+ publish()
133
+ void nextTick(() => render(caretAfter(index)))
134
+ }
135
+
136
+ /** Vị trí con trỏ ứng với ô dữ liệu thứ `index`. */
137
+ function caretForIndex(index: number): number {
138
+ if (index <= 0)
139
+ return slots.value.findIndex(slot => slot.accepts !== undefined)
140
+ let seen = 0
141
+ for (const [position, slot] of slots.value.entries()) {
142
+ if (slot.accepts === undefined)
143
+ continue
144
+ if (seen === index)
145
+ return position
146
+ seen += 1
147
+ }
148
+ return result.value.text.length
149
+ }
150
+
151
+ /** Vị trí con trỏ sau khi đã điền `count` ô dữ liệu. */
152
+ function caretAfter(count: number): number {
153
+ return count <= 0 ? caretForIndex(0) : caretForIndex(count - 1) + 1
154
+ }
155
+
156
+ function onFocus(): void {
157
+ focused.value = true
158
+ // Vào bằng Tab thì con trỏ đứng ngay sau ô đã điền cuối cùng. Vào bằng chuột
159
+ // thì KHÔNG: `mouseup` đặt lại con trỏ theo chỗ bấm, sau cả `focus`. Đó là
160
+ // hành vi đúng của một ô nhập, và việc gõ vẫn chèn đúng chỗ.
161
+ void nextTick(() => render(caretAfter(raw.value.length)))
162
+ }
163
+
164
+ function onBlur(): void {
165
+ focused.value = false
166
+ }
167
+
168
+ /** Giá trị đổi từ bên ngoài thì dựng lại — nhưng đừng đè lên thứ đang gõ. */
169
+ watch(model, (value) => {
170
+ const next = props.unmask ? value : toRaw(value, slots.value)
171
+ if (next !== raw.value && !focused.value)
172
+ raw.value = toRaw(value, slots.value)
173
+ })
174
+ </script>
175
+
176
+ <template>
177
+ <div class="relative w-full">
178
+ <input
179
+ ref="input"
180
+ v-bind="$attrs"
181
+ type="text"
182
+ :value="display"
183
+ :placeholder="props.placeholder"
184
+ :disabled="props.disabled"
185
+ :inputmode="inputMode"
186
+ :aria-invalid="props.invalid || undefined"
187
+ :data-invalid="props.invalid || undefined"
188
+ :data-complete="complete || undefined"
189
+ autocomplete="off"
190
+ :class="cn(
191
+ 'flex w-full rounded-md border border-input bg-background py-1 shadow-xs transition-colors',
192
+ props.size === 'sm' ? 'h-(--ui-field-height-sm) px-(--ui-field-padding-x-sm) text-(length:--ui-field-text-sm)' : 'h-(--ui-field-height-md) px-(--ui-field-padding-x-md) text-sm',
193
+ 'placeholder:text-muted-foreground',
194
+ focusRing,
195
+ 'disabled:cursor-not-allowed disabled:opacity-50',
196
+ invalidRing,
197
+ props.class,
198
+ )"
199
+ @input="onInput"
200
+ @keydown="onKeydown"
201
+ @focus="onFocus"
202
+ @blur="onBlur"
203
+ >
204
+ </div>
205
+ </template>
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Bốn hàm khuôn giờ ở `src/variants/lib/mask` — logic thuần, không dính
3
+ * framework, nên bản React đọc CÙNG một file thay vì chép lại. Re-export ở đây
4
+ * để chỗ nào đang `import { toRaw } from '../mask'` không phải sửa.
5
+ */
6
+ export {
7
+ dataBefore,
8
+ formatMask,
9
+ type FormatResult,
10
+ type MaskSlot,
11
+ parseMask,
12
+ toRaw,
13
+ } from '../../variants/lib/mask'
14
+
15
+ export { default as Mask } from './Mask.vue'
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { MenubarRootEmits, MenubarRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { MenubarRoot, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<MenubarRootProps & ClassProps>()
9
+ const emits = defineEmits<MenubarRootEmits>()
10
+
11
+ const delegated = computed(() => {
12
+ const { class: _class, ...rest } = props
13
+ return rest
14
+ })
15
+
16
+ const forwarded = useForwardPropsEmits(delegated, emits)
17
+ </script>
18
+
19
+ <template>
20
+ <MenubarRoot
21
+ v-bind="forwarded"
22
+ :class="cn('flex h-9 items-center gap-1 rounded-md border border-border bg-background p-1 shadow-xs', props.class)"
23
+ >
24
+ <slot />
25
+ </MenubarRoot>
26
+ </template>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { MenubarCheckboxItemEmits, MenubarCheckboxItemProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { MenubarCheckboxItem, MenubarItemIndicator, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { Check } from '../../lib/icons'
7
+ import { menuIndicatorItemClass, menuIndicatorSlotClass } from '../../lib/menu-styles'
8
+ import { cn } from '../../lib/utils'
9
+
10
+ const props = defineProps<MenubarCheckboxItemProps & ClassProps>()
11
+ const emits = defineEmits<MenubarCheckboxItemEmits>()
12
+
13
+ const delegated = computed(() => {
14
+ const { class: _class, ...rest } = props
15
+ return rest
16
+ })
17
+
18
+ const forwarded = useForwardPropsEmits(delegated, emits)
19
+ </script>
20
+
21
+ <template>
22
+ <MenubarCheckboxItem v-bind="forwarded" :class="cn(menuIndicatorItemClass, props.class)">
23
+ <span :class="menuIndicatorSlotClass">
24
+ <MenubarItemIndicator>
25
+ <Check class="size-4" />
26
+ </MenubarItemIndicator>
27
+ </span>
28
+ <slot />
29
+ </MenubarCheckboxItem>
30
+ </template>
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import type { FocusOutsideEvent, MenubarContentProps, PointerDownOutsideEvent } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { MenubarContent, MenubarPortal, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { menuContentClass } from '../../lib/menu-styles'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ const props = withDefaults(
10
+ defineProps<MenubarContentProps & ClassProps>(),
11
+ { align: 'start', sideOffset: 6, alignOffset: -4, collisionPadding: 8 },
12
+ )
13
+
14
+ /*
15
+ * Khai tay danh sách emit, không dùng `MenubarContentEmits`.
16
+ *
17
+ * reka chỉ export `MenubarSubContentEmits`, không có bản cho content thường —
18
+ * năm sự kiện dưới đây chép từ chính khai báo kiểu của component.
19
+ *
20
+ * Và không bỏ đi được: gốc của component này là `MenubarPortal`, nên listener
21
+ * rơi tự do sẽ dính vào portal thay vì vào tấm menu, rồi im lặng không chạy.
22
+ */
23
+ const emits = defineEmits<{
24
+ escapeKeyDown: [event: KeyboardEvent]
25
+ pointerDownOutside: [event: PointerDownOutsideEvent]
26
+ focusOutside: [event: FocusOutsideEvent]
27
+ interactOutside: [event: PointerDownOutsideEvent | FocusOutsideEvent]
28
+ closeAutoFocus: [event: Event]
29
+ }>()
30
+
31
+ const delegated = computed(() => {
32
+ const { class: _class, ...rest } = props
33
+ return rest
34
+ })
35
+
36
+ const forwarded = useForwardPropsEmits(delegated, emits)
37
+ </script>
38
+
39
+ <template>
40
+ <MenubarPortal>
41
+ <MenubarContent
42
+ v-bind="forwarded"
43
+ :class="cn(
44
+ menuContentClass,
45
+ 'max-h-[var(--reka-menubar-content-available-height)] min-w-[12rem] overflow-y-auto',
46
+ props.class,
47
+ )"
48
+ >
49
+ <slot />
50
+ </MenubarContent>
51
+ </MenubarPortal>
52
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { MenubarGroupProps } from 'reka-ui'
3
+ import { MenubarGroup } from 'reka-ui'
4
+
5
+ const props = defineProps<MenubarGroupProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <MenubarGroup v-bind="props">
10
+ <slot />
11
+ </MenubarGroup>
12
+ </template>