@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,31 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { AlertCircle } from '../../lib/icons'
4
+ import { cn } from '../../lib/utils'
5
+
6
+ const props = defineProps<ClassProps & { id?: string, message?: string }>()
7
+ </script>
8
+
9
+ <template>
10
+ <!--
11
+ Icon là bắt buộc, không phải trang trí: viền đỏ cộng chữ đỏ đều là tín hiệu
12
+ MÀU, mà WCAG 1.4.1 cấm mã hoá ý nghĩa chỉ bằng màu. Người bị mù màu đỏ-lục
13
+ thấy dòng này cùng tông với chữ thường, nên phải có một dấu hiệu không phụ
14
+ thuộc màu đứng cạnh.
15
+
16
+ `aria-hidden` vì chữ ngay bên cạnh đã nói đủ — trình đọc màn hình đọc thêm
17
+ "hình ảnh cảnh báo" chỉ làm dài thêm câu.
18
+
19
+ `mt-px` chứ không phải `items-center`: dòng lỗi có thể dài hai dòng, lúc đó
20
+ căn giữa sẽ đẩy icon xuống giữa khối chữ. Neo theo dòng đầu mới đúng.
21
+ -->
22
+ <p
23
+ v-if="props.message"
24
+ :id="props.id"
25
+ role="alert"
26
+ :class="cn('flex items-start gap-1.5 text-xs font-medium text-destructive', props.class)"
27
+ >
28
+ <AlertCircle class="mt-px size-3.5 shrink-0" aria-hidden="true" />
29
+ <span>{{ props.message }}</span>
30
+ </p>
31
+ </template>
@@ -0,0 +1,54 @@
1
+ import type { AnyFormApi } from '@tanstack/vue-form'
2
+ import type { ComputedRef, InjectionKey, Ref } from 'vue'
3
+ import { inject, provide } from 'vue'
4
+
5
+ /**
6
+ * Những gì `Form` chuyền xuống cho `FormField`.
7
+ *
8
+ * TanStack Form **không có context sẵn**: `useField` bắt buộc nhận `form` qua
9
+ * tham số, nên khuôn dùng chính thống của nó là `<form.Field>` viết ngay trong
10
+ * template của màn đang dùng. Ở đây tự provide/inject để giữ nguyên API cũ —
11
+ * `<FormField name="email">` là một component rời, không cần biết instance form
12
+ * nằm ở đâu. Nhờ vậy đổi thư viện form không phải sửa dòng nào trong
13
+ * `apps/admin`.
14
+ */
15
+ export interface FormContext {
16
+ /** Kiểu `AnyFormApi` vì `FormField` không cần biết kiểu giá trị của form bao ngoài. */
17
+ api: AnyFormApi
18
+ /**
19
+ * Lỗi do server trả về, giữ **ngoài** errorMap của TanStack. Xem chú thích
20
+ * `setErrors` trong `Form.vue` để biết vì sao không dùng khoá `onServer`.
21
+ */
22
+ serverErrors: Ref<Record<string, string>>
23
+ /**
24
+ * Form đã bấm gửi ít nhất một lần chưa. `FormField` cần biết để hiện lỗi cho
25
+ * field người dùng **chưa hề chạm tới** — bỏ trống rồi bấm gửi thì vẫn phải
26
+ * báo.
27
+ *
28
+ * Phải chuyền xuống dưới dạng đã bọc sẵn, không để `FormField` tự đọc
29
+ * `form.state.submissionAttempts`: `AnyFormApi` là kiểu của core, `.state`
30
+ * của nó là getter trần trên store chứ **không** reactive trong Vue. Đọc
31
+ * thẳng thì computed không track, và bấm gửi sẽ không hiện lỗi nào — đã dính
32
+ * đúng lỗi đó một lần. Chỗ duy nhất lấy được bản reactive là `useSelector`
33
+ * của adapter Vue, mà chỉ `Form.vue` mới có.
34
+ *
35
+ * (`useField` thì khác: api nó trả về CÓ state reactive, nên `FormField` đọc
36
+ * `api.state.meta` trực tiếp được.)
37
+ */
38
+ submitted: ComputedRef<boolean>
39
+ }
40
+
41
+ const formContextKey = Symbol('woodblock-form') as InjectionKey<FormContext>
42
+
43
+ export function provideFormContext(context: FormContext): void {
44
+ provide(formContextKey, context)
45
+ }
46
+
47
+ export function useFormContext(): FormContext {
48
+ const context = inject(formContextKey, null)
49
+
50
+ if (!context)
51
+ throw new Error('FormField phải nằm bên trong <Form>.')
52
+
53
+ return context
54
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Lên `src/variants/lib/form-errors` — `form-core` là chung cho cả hai
3
+ * adapter, nên bản React gặp đúng hình dạng errorMap này. Hai bản là hai cơ hội
4
+ * để một bên quên nhánh MẢNG, mà nhánh đó hỏng âm thầm.
5
+ */
6
+ export { type FieldErrorMap, firstErrorMessage } from '../../variants/lib/form-errors'
@@ -0,0 +1,7 @@
1
+ export { default as Form } from './Form.vue'
2
+ export { default as FormDescription } from './FormDescription.vue'
3
+ export { default as FormField } from './FormField.vue'
4
+ export { default as FormItem } from './FormItem.vue'
5
+ export { default as FormLabel } from './FormLabel.vue'
6
+ export { default as FormMessage } from './FormMessage.vue'
7
+ export type { FieldSlotProps, FormExpose } from './types'
@@ -0,0 +1,55 @@
1
+ import type { Ref } from 'vue'
2
+
3
+ /**
4
+ * Props mà FormField truyền xuống control bên trong.
5
+ * Mục tiêu: `v-bind="field"` là đủ để một control (Input, Select, Switch...)
6
+ * nối dây vào form, không cần biết gì thêm.
7
+ *
8
+ * `T` mặc định là string vì phần lớn field là text input.
9
+ * Với kiểu khác, khai báo `:default-value` để TS suy ra:
10
+ *
11
+ * <FormField name="age" :default-value="0" /> -> T = number
12
+ * <FormField name="active" :default-value="false" /> -> T = boolean
13
+ */
14
+ export interface FieldBindings<T = string> {
15
+ 'modelValue': T
16
+ /**
17
+ * Nhận `unknown` chứ không phải `T`: tham số của hàm là contravariant,
18
+ * một handler chỉ nhận `string` KHÔNG gán được vào control khai báo
19
+ * `(value: string | number | null) => void`. `unknown` nhận được mọi control.
20
+ */
21
+ 'onUpdate:modelValue': (value: unknown) => void
22
+ 'onBlur': (event?: Event) => void
23
+ 'name': string
24
+ 'id': string
25
+ 'aria-describedby': string | undefined
26
+ 'aria-invalid': true | undefined
27
+ }
28
+
29
+ export interface FieldSlotProps<T = string> {
30
+ /** Bind thẳng vào control: <Input v-bind="field" /> */
31
+ field: FieldBindings<T>
32
+ value: T
33
+ setValue: (value: T) => void
34
+ errorMessage: string | undefined
35
+ invalid: boolean
36
+ /** id của control, dùng khi cần nối label thủ công */
37
+ id: string
38
+ }
39
+
40
+ /**
41
+ * Những gì `<Form>` expose ra ngoài qua template ref.
42
+ *
43
+ * Khai thành interface riêng để bên gọi tự viết kiểu cho `useTemplateRef` —
44
+ * `Form` là generic component nên `InstanceType<typeof Form>` không dùng được.
45
+ */
46
+ export interface FormExpose {
47
+ /** Về giá trị khởi tạo, xoá luôn lỗi server đang hiện. */
48
+ resetForm: () => void
49
+ /** Map lỗi của API (ModelState / ProblemDetails.errors) về từng field. */
50
+ setErrors: (fields: Record<string, string>) => void
51
+ setFieldError: (name: string, message: string) => void
52
+ values: Readonly<Ref<Record<string, unknown>>>
53
+ errors: Readonly<Ref<Record<string, string | undefined>>>
54
+ isSubmitting: Readonly<Ref<boolean>>
55
+ }
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import type { HoverCardRootEmits, HoverCardRootProps } from 'reka-ui'
3
+ import { HoverCardRoot, useForwardPropsEmits } from 'reka-ui'
4
+
5
+ const props = withDefaults(
6
+ defineProps<HoverCardRootProps>(),
7
+ {
8
+ /**
9
+ * Reka mặc định 700ms — quá lâu cho một thẻ xem nhanh: rê qua tên người rồi
10
+ * chờ gần một giây mới thấy gì thì người ta đã bỏ đi. 300ms là mức vẫn chặn
11
+ * được thẻ nhảy ra khi chỉ lướt chuột ngang qua.
12
+ */
13
+ openDelay: 300,
14
+ /** Đóng chậm hơn mở, để còn kịp rê chuột từ trigger sang chính thẻ. */
15
+ closeDelay: 200,
16
+ },
17
+ )
18
+ const emits = defineEmits<HoverCardRootEmits>()
19
+
20
+ const forwarded = useForwardPropsEmits(props, emits)
21
+ </script>
22
+
23
+ <template>
24
+ <HoverCardRoot v-bind="forwarded">
25
+ <slot />
26
+ </HoverCardRoot>
27
+ </template>
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import type { HoverCardContentProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { HoverCardContent, HoverCardPortal } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = withDefaults(
9
+ defineProps<HoverCardContentProps & ClassProps>(),
10
+ { sideOffset: 6, align: 'center', collisionPadding: 8 },
11
+ )
12
+
13
+ const delegated = computed(() => {
14
+ const { class: _class, ...rest } = props
15
+ return rest
16
+ })
17
+ </script>
18
+
19
+ <template>
20
+ <HoverCardPortal>
21
+ <HoverCardContent
22
+ v-bind="delegated"
23
+ :class="cn(
24
+ 'surface z-(--z-overlay) w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',
25
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
26
+ 'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',
27
+ 'data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95',
28
+ 'data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2',
29
+ 'data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2',
30
+ props.class,
31
+ )"
32
+ >
33
+ <slot />
34
+ </HoverCardContent>
35
+ </HoverCardPortal>
36
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { HoverCardTriggerProps } from 'reka-ui'
3
+ import { HoverCardTrigger } from 'reka-ui'
4
+
5
+ const props = defineProps<HoverCardTriggerProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <HoverCardTrigger v-bind="props">
10
+ <slot />
11
+ </HoverCardTrigger>
12
+ </template>
@@ -0,0 +1,3 @@
1
+ export { default as HoverCard } from './HoverCard.vue'
2
+ export { default as HoverCardContent } from './HoverCardContent.vue'
3
+ export { default as HoverCardTrigger } from './HoverCardTrigger.vue'
@@ -0,0 +1,26 @@
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
+ <div
10
+ :class="cn(
11
+ 'relative w-full',
12
+
13
+ // Ô cao 52px: nhãn 6..22, giá trị 24..44, chừa 8 ở đáy.
14
+ '[&_input]:h-13 [&_input]:pt-6 [&_input]:pb-2',
15
+
16
+ // Nhãn đứng yên một chỗ, nên không có transition nào ở đây cả.
17
+ '[&>label]:pointer-events-none [&>label]:absolute [&>label]:left-3 [&>label]:top-1.5 [&>label]:z-(--z-raised)',
18
+ '[&>label]:text-xs [&>label]:font-normal [&>label]:text-muted-foreground',
19
+ 'has-[input:disabled]:[&>label]:opacity-50',
20
+
21
+ props.class,
22
+ )"
23
+ >
24
+ <slot />
25
+ </div>
26
+ </template>
@@ -0,0 +1 @@
1
+ export { default as IftaLabel } from './IftaLabel.vue'
@@ -0,0 +1,89 @@
1
+ export * from './accordion'
2
+ export * from './alert'
3
+ export * from './avatar'
4
+ export * from './badge'
5
+ export * from './breadcrumb'
6
+ export * from './button'
7
+ export * from './button-group'
8
+ export * from './calendar'
9
+ export * from './card'
10
+ export * from './carousel'
11
+ export * from './cascade-select'
12
+ export * from './chart'
13
+ export * from './checkbox'
14
+ export * from './chip'
15
+ export * from './code-block'
16
+ export * from './collapsible'
17
+ export * from './combobox'
18
+ export * from './command'
19
+ export * from './command-block'
20
+ export * from './confirm-dialog'
21
+ export * from './confirm-popup'
22
+ export * from './context-menu'
23
+ export * from './data-table'
24
+ export * from './data-view'
25
+ export * from './date-picker'
26
+ export * from './deferred'
27
+ export * from './dialog'
28
+ export * from './doc-example'
29
+ export * from './doc-text'
30
+ export * from './dropdown-menu'
31
+ export * from './editable'
32
+ export * from './empty'
33
+ export * from './field'
34
+ export * from './fieldset'
35
+ export * from './file-upload'
36
+ export * from './float-label'
37
+ export * from './form'
38
+ export * from './hover-card'
39
+ export * from './ifta-label'
40
+ export * from './input'
41
+ export * from './input-color'
42
+ export * from './input-group'
43
+ export * from './input-number'
44
+ export * from './input-otp'
45
+ export * from './input-password'
46
+ export * from './input-tags'
47
+ export * from './kbd'
48
+ export * from './label'
49
+ export * from './listbox'
50
+ export * from './mask'
51
+ export * from './menubar'
52
+ export * from './navigation-menu'
53
+ export * from './order-list'
54
+ export * from './pagination'
55
+ export * from './panel'
56
+ export * from './pick-list'
57
+ export * from './popover'
58
+ export * from './progress'
59
+ export * from './props-table'
60
+ export * from './radio-group'
61
+ export * from './rating'
62
+ export * from './scroll-area'
63
+ export * from './search-input'
64
+ export * from './select'
65
+ export * from './separator'
66
+ export * from './sheet'
67
+ export * from './sidebar'
68
+ export * from './skeleton'
69
+ export * from './skip-link'
70
+ export * from './slider'
71
+ export * from './speed-dial'
72
+ export * from './spinner'
73
+ export * from './splitter'
74
+ export * from './stepper'
75
+ export * from './switch'
76
+ export * from './table'
77
+ export * from './tabs'
78
+ export * from './textarea'
79
+ export * from './theme-controls'
80
+ export * from './timeline'
81
+ export * from './toast'
82
+ export * from './toggle'
83
+ export * from './token-table'
84
+ export * from './toolbar'
85
+ export * from './tooltip'
86
+ export * from './tree'
87
+ export * from './tree-select'
88
+ export * from './tree-table'
89
+ export * from './video-player'
@@ -0,0 +1,87 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { computed } from 'vue'
4
+ import { focusRing, invalidRing } from '../../lib/focus'
5
+ import { Check } from '../../lib/icons'
6
+ import { cn } from '../../lib/utils'
7
+ import Spinner from '../spinner/Spinner.vue'
8
+
9
+ /**
10
+ * Gốc của component là một `<div>` bọc ngoài, nên thuộc tính rơi tự do phải
11
+ * được chuyển tay vào đúng cái `<input>` — nếu không `id`, `name`,
12
+ * `aria-describedby` sẽ dính lên div và `<label for>` mất đích.
13
+ */
14
+ defineOptions({ inheritAttrs: false })
15
+
16
+ const props = withDefaults(
17
+ defineProps<ClassProps & {
18
+ invalid?: boolean
19
+ /**
20
+ * Đã kiểm và hợp lệ. Hiện dấu tick **trong ô** — đúng chỗ mắt người dùng
21
+ * đang nhìn. Toast là lựa chọn sai cho việc này: nó kéo chú ý đi nơi khác
22
+ * rồi biến mất trước khi kịp đọc.
23
+ */
24
+ success?: boolean
25
+ /** Đang kiểm bất đồng bộ (trùng email, mã giảm giá…). */
26
+ loading?: boolean
27
+ /** sm = 30px, dùng cho toolbar/bộ lọc theo mật độ compact của thiết kế. */
28
+ size?: 'sm' | 'default'
29
+ }>(),
30
+ { size: 'default' },
31
+ )
32
+
33
+ // defineModel để Input dùng được với v-model và với FormField.
34
+ const model = defineModel<string | number | null>()
35
+
36
+ const sizeClass = computed(() =>
37
+ 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',
38
+ )
39
+
40
+ /** Lỗi thắng tick: sai thì không còn gì để mà xác nhận là đúng. */
41
+ const showSuccess = computed(() => props.success && !props.invalid && !props.loading)
42
+ const hasAdornment = computed(() => props.loading || showSuccess.value)
43
+ </script>
44
+
45
+ <template>
46
+ <div class="relative w-full">
47
+ <input
48
+ v-bind="$attrs"
49
+ v-model="model"
50
+ :aria-invalid="props.invalid || undefined"
51
+ :data-invalid="props.invalid || undefined"
52
+ :aria-busy="props.loading || undefined"
53
+ :readonly="props.loading || undefined"
54
+ :class="cn(
55
+ 'flex w-full rounded-md border border-input bg-background py-1 shadow-xs transition-colors',
56
+ sizeClass,
57
+ 'placeholder:text-muted-foreground',
58
+ 'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground',
59
+ focusRing,
60
+ 'disabled:cursor-not-allowed disabled:opacity-50',
61
+ invalidRing,
62
+ // Chừa chỗ cho icon, nếu không chữ chui xuống dưới nó.
63
+ hasAdornment && (props.size === 'sm' ? 'pr-8' : 'pr-9'),
64
+ props.class,
65
+ )"
66
+ >
67
+
68
+ <!--
69
+ `loading` khoá ô bằng `readonly`, KHÔNG bằng `disabled`.
70
+
71
+ `disabled` cướp focus khỏi phần tử người dùng đang đứng, nên giữa lúc
72
+ kiểm tra họ mất luôn vị trí trong form — và `disabled` còn có nghĩa "bạn
73
+ không được phép", khác hẳn "đang chạy". `readonly` chặn gõ mà vẫn giữ
74
+ focus, vẫn copy được; `aria-busy` nói phần còn lại cho trình đọc màn hình.
75
+ -->
76
+ <span
77
+ v-if="hasAdornment"
78
+ :class="cn(
79
+ 'pointer-events-none absolute top-1/2 -translate-y-1/2',
80
+ props.size === 'sm' ? 'right-2.5' : 'right-3',
81
+ )"
82
+ >
83
+ <Spinner v-if="props.loading" class="text-muted-foreground" />
84
+ <Check v-else class="size-4 text-success" aria-hidden="true" />
85
+ </span>
86
+ </div>
87
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Input } from './Input.vue'
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import type { ColorAreaRootEmits, ColorAreaRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ColorAreaArea, ColorAreaRoot, ColorAreaThumb, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<ColorAreaRootProps & ClassProps>()
9
+ const emits = defineEmits<ColorAreaRootEmits>()
10
+
11
+ const delegated = computed(() => {
12
+ const { class: _class, ...rest } = props
13
+ return rest
14
+ })
15
+
16
+ const forwarded = useForwardPropsEmits(delegated, emits)
17
+ </script>
18
+
19
+ <template>
20
+ <!--
21
+ `ColorAreaArea` KHÔNG tự tô nền — nó chỉ đặt `touch-action: none`. Dải màu
22
+ nằm ở `style` mà slot của root trả về, và phải tự bind sang. Quên là ra một
23
+ ô xám trơn vẫn kéo được, tức hỏng mà nhìn như đang tải dở.
24
+ -->
25
+ <ColorAreaRoot
26
+ v-slot="{ style }"
27
+ v-bind="forwarded"
28
+ :class="cn('relative h-40 w-full touch-none select-none rounded-md border border-border', props.class)"
29
+ >
30
+ <ColorAreaArea :style="style" class="size-full rounded-[inherit]">
31
+ <ColorAreaThumb
32
+ class="size-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,.35)] outline-none focus-visible:ring-2 focus-visible:ring-ring"
33
+ />
34
+ </ColorAreaArea>
35
+ </ColorAreaRoot>
36
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import type { ColorFieldRootEmits, ColorFieldRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ColorFieldInput, ColorFieldRoot, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { focusRing } from '../../lib/focus'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ const props = defineProps<ColorFieldRootProps & ClassProps>()
10
+ const emits = defineEmits<ColorFieldRootEmits>()
11
+
12
+ const delegated = computed(() => {
13
+ const { class: _class, ...rest } = props
14
+ return rest
15
+ })
16
+
17
+ const forwarded = useForwardPropsEmits(delegated, emits)
18
+ </script>
19
+
20
+ <template>
21
+ <!-- Ô nhập hex hoặc một kênh màu. `font-mono` vì đây là mã, không phải chữ —
22
+ và mã màu thì hay được đọc theo từng ký tự. -->
23
+ <ColorFieldRoot v-bind="forwarded" :class="cn('w-full', props.class)">
24
+ <ColorFieldInput
25
+ :class="cn(
26
+ 'h-8 w-full rounded-md border border-input bg-background px-2 font-mono text-xs uppercase shadow-xs transition-colors',
27
+ focusRing,
28
+ 'disabled:cursor-not-allowed disabled:opacity-50',
29
+ )"
30
+ />
31
+ </ColorFieldRoot>
32
+ </template>
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ import type { ColorSliderRootEmits, ColorSliderRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { ColorSliderRoot, ColorSliderThumb, ColorSliderTrack, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<ColorSliderRootProps & ClassProps>()
9
+ const emits = defineEmits<ColorSliderRootEmits>()
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
+ <!-- Khác `ColorArea`: rãnh ở đây TỰ tô, reka bind nền thẳng lên `Track`. -->
21
+ <ColorSliderRoot
22
+ v-bind="forwarded"
23
+ :class="cn('relative flex h-4 w-full touch-none select-none items-center', props.class)"
24
+ >
25
+ <ColorSliderTrack class="h-3 w-full rounded-full border border-border">
26
+ <ColorSliderThumb
27
+ class="size-4 -translate-x-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,.35)] outline-none focus-visible:ring-2 focus-visible:ring-ring"
28
+ />
29
+ </ColorSliderTrack>
30
+ </ColorSliderRoot>
31
+ </template>
@@ -0,0 +1,65 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { computed } from 'vue'
4
+ import { useI18n } from '../../composables/useI18n'
5
+ import { cn } from '../../lib/utils'
6
+ import Popover from '../popover/Popover.vue'
7
+ import PopoverContent from '../popover/PopoverContent.vue'
8
+ import PopoverTrigger from '../popover/PopoverTrigger.vue'
9
+ import ColorArea from './ColorArea.vue'
10
+ import ColorField from './ColorField.vue'
11
+ import ColorSlider from './ColorSlider.vue'
12
+
13
+ /**
14
+ * Gốc của component là một provider KHÔNG vẽ ra DOM, nên thuộc tính rơi tự do
15
+ * không có chỗ đáp và biến mất hẳn. Đo được: đặt `id` lên component thì nó
16
+ * không xuất hiện ở bất kỳ đâu trong DOM, và `<Label for>` trỏ vào hư không.
17
+ *
18
+ * Chuyển tay xuống chính cái trigger.
19
+ */
20
+ defineOptions({ inheritAttrs: false })
21
+
22
+ const props = defineProps<ClassProps & {
23
+ /** Nhãn trợ năng cho nút mở. Bỏ trống thì lấy chuỗi của thư viện. */
24
+ label?: string
25
+ disabled?: boolean
26
+ }>()
27
+
28
+ const model = defineModel<string>({ default: '#2563EB' })
29
+
30
+ const { t } = useI18n()
31
+
32
+ const label = computed(() => props.label ?? t('ui.inputColor.open'))
33
+ </script>
34
+
35
+ <template>
36
+ <Popover>
37
+ <PopoverTrigger
38
+ v-bind="$attrs"
39
+ :disabled="props.disabled"
40
+ :aria-label="`${label}: ${model}`"
41
+ :class="cn(
42
+ 'inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-2 pr-3 shadow-xs transition-colors',
43
+ 'hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
44
+ 'disabled:pointer-events-none disabled:opacity-50',
45
+ props.class,
46
+ )"
47
+ >
48
+ <!--
49
+ Ô màu đặt trên nền ca-rô, không phải nền trơn: màu có alpha thấp nằm
50
+ trên nền trắng thì trông hệt như trắng, và người dùng không có cách nào
51
+ biết mình vừa chọn một màu gần như trong suốt.
52
+ -->
53
+ <span class="size-5 shrink-0 overflow-hidden rounded-sm border border-border bg-[repeating-conic-gradient(theme(colors.slate.400)_0_25%,transparent_0_50%)] bg-[length:8px_8px]">
54
+ <span class="block size-full" :style="{ background: model }" />
55
+ </span>
56
+ <span class="font-mono text-xs uppercase">{{ model }}</span>
57
+ </PopoverTrigger>
58
+
59
+ <PopoverContent class="w-60 space-y-3 p-3">
60
+ <ColorArea v-model="model" color-space="hsb" x-channel="saturation" y-channel="brightness" />
61
+ <ColorSlider v-model="model" color-space="hsb" channel="hue" />
62
+ <ColorField v-model="model" />
63
+ </PopoverContent>
64
+ </Popover>
65
+ </template>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Bộ chọn màu. `<InputColor v-model="brand" />` là một nút ô màu mở ra popover
3
+ * gồm vùng bão-hoà/độ-sáng, thanh sắc và ô nhập hex.
4
+ *
5
+ * Ba phần bên trong cũng export riêng cho lúc cần dựng bố cục khác — ví dụ một
6
+ * bảng màu luôn hiện trong trang cài đặt, không qua popover.
7
+ *
8
+ * Cái bẫy đáng nhớ: `ColorAreaArea` **không tự tô nền**. Dải màu nằm ở `style`
9
+ * mà slot của root trả về; `ColorArea.vue` bind nó sang. Còn `ColorSliderTrack`
10
+ * thì ngược lại, reka tô sẵn.
11
+ */
12
+
13
+ export { default as ColorArea } from './ColorArea.vue'
14
+ export { default as ColorField } from './ColorField.vue'
15
+ export { default as ColorSlider } from './ColorSlider.vue'
16
+ export { default as InputColor } from './InputColor.vue'
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { InputGroupVariants } from './index'
4
+ import { computed } from 'vue'
5
+ import { cn } from '../../lib/utils'
6
+ import { inputGroupVariants, provideInputGroupContext } from './index'
7
+
8
+ const props = withDefaults(
9
+ defineProps<ClassProps & {
10
+ size?: InputGroupVariants['size']
11
+ invalid?: boolean
12
+ }>(),
13
+ { size: 'default', invalid: false },
14
+ )
15
+
16
+ provideInputGroupContext({ size: computed(() => props.size) })
17
+ </script>
18
+
19
+ <template>
20
+ <div
21
+ :data-invalid="props.invalid || undefined"
22
+ :class="cn(inputGroupVariants({ size: props.size }), props.class)"
23
+ >
24
+ <slot />
25
+ </div>
26
+ </template>