@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,59 @@
1
+ /**
2
+ * Một field của TanStack Form giữ lỗi trong `meta.errorMap`, khoá theo **nguyên
3
+ * nhân** chứ không phải một chuỗi duy nhất:
4
+ *
5
+ * { onChange: …, onBlur: …, onSubmit: …, onMount: … }
6
+ *
7
+ * Mỗi giá trị có thể là chuỗi (lỗi tự đặt), một issue, hoặc **mảng issue** —
8
+ * đây là chỗ dễ hụt: validator ở cấp form gom issue theo path rồi gán cả
9
+ * `[issue, …]` cho từng field (`prefixSchemaToErrors` trong form-core), nên
10
+ * một field hỏng vì hai luật sẽ nhận mảng hai phần tử. Đọc thẳng `.message`
11
+ * của mảng ra `undefined` và lỗi biến mất **âm thầm** — không cảnh báo, không
12
+ * throw, chỉ là form không bao giờ báo sai.
13
+ *
14
+ * Nằm ở `src/variants` vì `form-core` là chung cho cả hai adapter, nên cả
15
+ * hai cây gặp đúng hình dạng errorMap này. Viết hai lần là hai cơ hội để một
16
+ * bên quên nhánh mảng.
17
+ */
18
+ export type FieldErrorMap = Record<string, unknown>
19
+
20
+ /**
21
+ * Không có `onServer` trong danh sách: lỗi từ server đi đường riêng chứ không
22
+ * ghi vào errorMap. Lý do ở `Form` của mỗi cây.
23
+ */
24
+ const CAUSE_ORDER = ['onChange', 'onBlur', 'onSubmit', 'onDynamic', 'onMount'] as const
25
+
26
+ function toMessage(error: unknown): string | undefined {
27
+ if (typeof error === 'string')
28
+ return error === '' ? undefined : error
29
+
30
+ if (Array.isArray(error)) {
31
+ for (const item of error) {
32
+ const message = toMessage(item)
33
+ if (message !== undefined)
34
+ return message
35
+ }
36
+ return undefined
37
+ }
38
+
39
+ if (error !== null && typeof error === 'object' && 'message' in error) {
40
+ const { message } = error as { message: unknown }
41
+ return typeof message === 'string' ? message : undefined
42
+ }
43
+
44
+ return undefined
45
+ }
46
+
47
+ /** Quy errorMap về đúng MỘT chuỗi để hiển thị — chỗ báo lỗi chỉ vẽ một dòng. */
48
+ export function firstErrorMessage(errorMap: FieldErrorMap | undefined): string | undefined {
49
+ if (errorMap === undefined)
50
+ return undefined
51
+
52
+ for (const cause of CAUSE_ORDER) {
53
+ const message = toMessage(errorMap[cause])
54
+ if (message !== undefined)
55
+ return message
56
+ }
57
+
58
+ return undefined
59
+ }
@@ -0,0 +1,548 @@
1
+ /**
2
+ * Tô màu cú pháp cho các đoạn code trong trang tài liệu.
3
+ *
4
+ * Tự viết thay vì thêm Shiki hay Prism: trang docs chỉ hiển thị chính các ví
5
+ * dụ do repo này viết ra — một tập nhỏ, biết trước — nên không cần bộ
6
+ * highlight đầy đủ nặng cả megabyte. Đổi lại nó *không* phải parser thật:
7
+ * chỉ nhận đúng những cấu trúc dùng trong ví dụ (template Vue và vài dòng
8
+ * import/khai báo TypeScript). Gặp cú pháp lạ thì phần đó rơi về `text`,
9
+ * mất màu chứ không vỡ.
10
+ *
11
+ * Muốn tô đúng một file bất kỳ do người dùng dán vào thì phải đổi sang Shiki.
12
+ */
13
+
14
+ export type TokenKind
15
+ = | 'text'
16
+ | 'comment'
17
+ | 'tag'
18
+ | 'component'
19
+ | 'attr'
20
+ | 'string'
21
+ | 'keyword'
22
+ | 'function'
23
+ | 'number'
24
+ | 'punctuation'
25
+
26
+ export interface Token {
27
+ kind: TokenKind
28
+ value: string
29
+ }
30
+
31
+ export type Language = 'vue' | 'ts' | 'tsx'
32
+
33
+ const KEYWORDS = new Set([
34
+ 'as',
35
+ 'async',
36
+ 'await',
37
+ 'break',
38
+ 'case',
39
+ 'catch',
40
+ 'class',
41
+ 'const',
42
+ 'continue',
43
+ 'default',
44
+ 'delete',
45
+ 'else',
46
+ 'export',
47
+ 'extends',
48
+ 'finally',
49
+ 'for',
50
+ 'from',
51
+ 'function',
52
+ 'if',
53
+ 'import',
54
+ 'in',
55
+ 'interface',
56
+ 'let',
57
+ 'new',
58
+ 'of',
59
+ 'return',
60
+ 'satisfies',
61
+ 'switch',
62
+ 'throw',
63
+ 'try',
64
+ 'type',
65
+ 'typeof',
66
+ 'var',
67
+ 'while',
68
+ ])
69
+
70
+ const LITERALS = new Set(['true', 'false', 'null', 'undefined'])
71
+
72
+ /** Gộp token liền kề cùng loại để bớt số thẻ span phải render. */
73
+ function push(tokens: Token[], kind: TokenKind, value: string): void {
74
+ if (value === '')
75
+ return
76
+
77
+ const last = tokens[tokens.length - 1]
78
+ if (last?.kind === kind)
79
+ last.value += value
80
+ else
81
+ tokens.push({ kind, value })
82
+ }
83
+
84
+ /** Một dòng TypeScript: chú thích, chuỗi, từ khoá, số, tên hàm. */
85
+ const TS_PATTERN = /(?<comment>\/\/[^\n]*|\/\*[\s\S]*?\*\/)|(?<string>'[^']*'|"[^"]*"|`[^`]*`)|(?<number>\b\d+(?:\.\d+)?\b)|(?<word>[A-Z_$][\w$]*)|(?<punctuation>[{}()[\].,;:=<>!?+\-*/&|]+)/gi
86
+
87
+ function tokenizeScript(code: string, tokens: Token[]): void {
88
+ let index = 0
89
+
90
+ for (const match of code.matchAll(TS_PATTERN)) {
91
+ push(tokens, 'text', code.slice(index, match.index))
92
+ index = match.index + match[0].length
93
+
94
+ const groups = match.groups ?? {}
95
+
96
+ if (groups.comment !== undefined)
97
+ push(tokens, 'comment', groups.comment)
98
+ else if (groups.string !== undefined)
99
+ push(tokens, 'string', groups.string)
100
+ else if (groups.number !== undefined)
101
+ push(tokens, 'number', groups.number)
102
+ else if (groups.punctuation !== undefined)
103
+ push(tokens, 'punctuation', groups.punctuation)
104
+ else if (groups.word !== undefined)
105
+ push(tokens, wordKind(groups.word, code, index), groups.word)
106
+ }
107
+
108
+ push(tokens, 'text', code.slice(index))
109
+ }
110
+
111
+ function wordKind(word: string, code: string, after: number): TokenKind {
112
+ if (KEYWORDS.has(word))
113
+ return 'keyword'
114
+
115
+ if (LITERALS.has(word))
116
+ return 'number'
117
+
118
+ // Theo sau là dấu `(` thì coi là lời gọi hàm.
119
+ return code[after] === '(' ? 'function' : 'text'
120
+ }
121
+
122
+ /** Nội dung bên trong một cặp ngoặc nhọn: tên thẻ, thuộc tính, giá trị. */
123
+ // Thân thẻ liệt kê tường minh chuỗi-trong-nháy và ký tự thường, không dùng
124
+ // [sS]*? — kiểu lười đó chồng lấn với tên thẻ nên regex backtrack rất tệ.
125
+ const TAG_PATTERN = /(?<open><\/?)(?<name>[a-z][\w.-]*)(?![\w.-])(?<body>(?:"[^"]*"|'[^']*'|[^>"'])*)(?<close>>)/gi
126
+
127
+ const ATTR_PATTERN = /(?<name>[\w:@.[\]-]+)|(?<equals>=)|(?<value>"[^"]*"|'[^']*')/g
128
+
129
+ function tokenizeTagBody(body: string, tokens: Token[]): void {
130
+ let index = 0
131
+
132
+ for (const match of body.matchAll(ATTR_PATTERN)) {
133
+ push(tokens, 'text', body.slice(index, match.index))
134
+ index = match.index + match[0].length
135
+
136
+ const groups = match.groups ?? {}
137
+
138
+ if (groups.name !== undefined)
139
+ push(tokens, 'attr', groups.name)
140
+ else if (groups.equals !== undefined)
141
+ push(tokens, 'keyword', groups.equals)
142
+ else if (groups.value !== undefined)
143
+ push(tokens, 'string', groups.value)
144
+ }
145
+
146
+ push(tokens, 'text', body.slice(index))
147
+ }
148
+
149
+ /** Thẻ viết hoa là component, viết thường là thẻ HTML — hai màu khác nhau. */
150
+ function tagKind(name: string): TokenKind {
151
+ return /^[A-Z]/.test(name) ? 'component' : 'tag'
152
+ }
153
+
154
+ const COMMENT_PATTERN = /<!--[\s\S]*?-->/g
155
+
156
+ function tokenizeMarkup(code: string, tokens: Token[]): void {
157
+ let index = 0
158
+
159
+ for (const match of code.matchAll(TAG_PATTERN)) {
160
+ const before = code.slice(index, match.index)
161
+ tokenizeMarkupText(before, tokens)
162
+ index = match.index + match[0].length
163
+
164
+ const groups = match.groups ?? {}
165
+
166
+ // Dấu `<` `>` `</` để màu chữ thường, chỉ tên thẻ mới đổi màu — GitHub và
167
+ // shadcn đều tô như vậy.
168
+ push(tokens, 'punctuation', groups.open ?? '')
169
+ push(tokens, tagKind(groups.name ?? ''), groups.name ?? '')
170
+ tokenizeTagBody(groups.body ?? '', tokens)
171
+ push(tokens, 'punctuation', groups.close ?? '')
172
+ }
173
+
174
+ tokenizeMarkupText(code.slice(index), tokens)
175
+ }
176
+
177
+ /** Phần nằm ngoài thẻ: chỉ cần tách chú thích HTML ra khỏi chữ thường. */
178
+ function tokenizeMarkupText(text: string, tokens: Token[]): void {
179
+ let index = 0
180
+
181
+ for (const match of text.matchAll(COMMENT_PATTERN)) {
182
+ push(tokens, 'text', text.slice(index, match.index))
183
+ push(tokens, 'comment', match[0])
184
+ index = match.index + match[0].length
185
+ }
186
+
187
+ push(tokens, 'text', text.slice(index))
188
+ }
189
+
190
+ /** Tách khối <script> ra khỏi phần template của một SFC. */
191
+ const SCRIPT_PATTERN = /(<script\b[^>]*>)([\s\S]*?)(<\/script>)/g
192
+
193
+ function tokenizeSfc(code: string, tokens: Token[]): void {
194
+ let index = 0
195
+
196
+ for (const match of code.matchAll(SCRIPT_PATTERN)) {
197
+ tokenizeMarkup(code.slice(index, match.index), tokens)
198
+ index = match.index + match[0].length
199
+
200
+ tokenizeMarkup(match[1], tokens)
201
+ tokenizeScript(match[2], tokens)
202
+ tokenizeMarkup(match[3], tokens)
203
+ }
204
+
205
+ tokenizeMarkup(code.slice(index), tokens)
206
+ }
207
+
208
+ export function highlight(code: string, language: Language = 'vue'): Token[] {
209
+ const tokens: Token[] = []
210
+
211
+ if (language === 'tsx')
212
+ tokenizeTsx(code, tokens)
213
+ else if (language === 'ts')
214
+ tokenizeScript(code, tokens)
215
+ else
216
+ tokenizeSfc(code, tokens)
217
+
218
+ return tokens
219
+ }
220
+
221
+ /**
222
+ * Tô màu cả khối rồi mới cắt theo dòng.
223
+ *
224
+ * Đừng gọi `highlight()` cho từng dòng một: `<script>` và `</script>` nằm ở hai
225
+ * dòng khác nhau nên regex tách khối script không bao giờ khớp, và toàn bộ phần
226
+ * TypeScript rơi về `text` — mất màu sạch. Chú thích nhiều dòng cũng vậy.
227
+ */
228
+ export function highlightLines(code: string, language: Language = 'vue'): Token[][] {
229
+ const lines: Token[][] = [[]]
230
+
231
+ for (const token of highlight(code.replace(/\n+$/, ''), language)) {
232
+ const parts = token.value.split('\n')
233
+
234
+ parts.forEach((part, index) => {
235
+ if (index > 0)
236
+ lines.push([])
237
+
238
+ if (part !== '')
239
+ lines[lines.length - 1].push({ kind: token.kind, value: part })
240
+ })
241
+ }
242
+
243
+ return lines
244
+ }
245
+
246
+ /* ------------------------------------------------------------------------- *
247
+ * TSX
248
+ * ------------------------------------------------------------------------- */
249
+
250
+ /**
251
+ * JSX KHÔNG tách được bằng cách cắt khối như SFC.
252
+ *
253
+ * `tokenizeSfc` chạy được vì `<script>` và `<template>` là hai vùng rời nhau,
254
+ * cắt một lần là xong. Trong `.tsx` thì JSX lồng vào giữa biểu thức — một `<`
255
+ * có thể là thẻ, là toán tử nhỏ hơn, hay là tham số generic — nên phải quét
256
+ * tuần tự và đổi chế độ tại chỗ.
257
+ *
258
+ * Vẫn theo đúng tinh thần của cả file: không phải parser thật, chỉ nhận những
259
+ * cấu trúc mà ví dụ trong repo dùng, gặp cú pháp lạ thì rơi về `text` chứ
260
+ * không vỡ.
261
+ */
262
+
263
+ /** Ký tự đứng ngay trước `<` cho phép nó mở một thẻ JSX. */
264
+ const JSX_OPENERS = new Set(['(', '{', '}', '=', ',', '&', '|', '?', ':', ';', '>', '['])
265
+
266
+ /** Từ khoá đứng trước `<` cũng mở được — `return <div/>`. */
267
+ const JSX_OPENER_WORDS = /(?:return|=>|\?\?|&&|\|\|)\s*$/
268
+
269
+ /**
270
+ * `<` này có phải mở đầu một thẻ JSX không.
271
+ *
272
+ * Hai điều kiện, và cần cả hai. Sau `<` phải là chữ cái, `_`, `$` (tên thẻ)
273
+ * hoặc `>` (fragment). Trước `<` phải là chỗ mà một BIỂU THỨC được phép bắt
274
+ * đầu — nếu không thì `a < b` và `Array<string>` đều bị đọc thành thẻ.
275
+ */
276
+ function opensJsx(code: string, at: number): boolean {
277
+ const next = code[at + 1]
278
+ if (next === undefined || !/[A-Z_$>]/i.test(next))
279
+ return false
280
+
281
+ const before = code.slice(0, at)
282
+ const trimmed = before.trimEnd()
283
+ if (trimmed === '')
284
+ return true
285
+
286
+ const last = trimmed[trimmed.length - 1]!
287
+ return JSX_OPENERS.has(last) || JSX_OPENER_WORDS.test(trimmed)
288
+ }
289
+
290
+ /**
291
+ * Bỏ qua chuỗi và chú thích khi đi tìm `<`.
292
+ *
293
+ * Không có bước này thì một `<` nằm trong `'a < b'` hay trong chú thích cũng mở
294
+ * ra một thẻ, và phần còn lại của file bị đọc nhầm hết.
295
+ */
296
+ function findJsxStart(code: string, from: number): number {
297
+ let i = from
298
+
299
+ while (i < code.length) {
300
+ const ch = code[i]!
301
+
302
+ if (ch === '/' && code[i + 1] === '/') {
303
+ const end = code.indexOf('\n', i)
304
+ i = end === -1 ? code.length : end
305
+ continue
306
+ }
307
+
308
+ if (ch === '/' && code[i + 1] === '*') {
309
+ const end = code.indexOf('*/', i + 2)
310
+ i = end === -1 ? code.length : end + 2
311
+ continue
312
+ }
313
+
314
+ if (ch === '\'' || ch === '"' || ch === '`') {
315
+ i = skipString(code, i)
316
+ continue
317
+ }
318
+
319
+ if (ch === '<' && opensJsx(code, i))
320
+ return i
321
+
322
+ i += 1
323
+ }
324
+
325
+ return -1
326
+ }
327
+
328
+ /** Trả về chỉ số NGAY SAU dấu đóng của chuỗi bắt đầu tại `start`. */
329
+ function skipString(code: string, start: number): number {
330
+ const quote = code[start]!
331
+ let i = start + 1
332
+
333
+ while (i < code.length) {
334
+ if (code[i] === '\\') {
335
+ i += 2
336
+ continue
337
+ }
338
+ if (code[i] === quote)
339
+ return i + 1
340
+ i += 1
341
+ }
342
+
343
+ return code.length
344
+ }
345
+
346
+ /**
347
+ * Quét thân thẻ mở, có ĐẾM NGOẶC NHỌN.
348
+ *
349
+ * `TAG_PATTERN` của phần markup không dùng lại được ở đây: nó coi `>` đầu tiên
350
+ * là hết thẻ, mà JSX thì `onClick={() => x}` có một `>` nằm giữa thân. Thẻ bị
351
+ * cắt sớm và phần còn lại của file lệch hết.
352
+ *
353
+ * Trả về chỉ số của `>` đóng thẻ.
354
+ */
355
+ function findTagEnd(code: string, from: number): number {
356
+ let i = from
357
+ let braces = 0
358
+
359
+ while (i < code.length) {
360
+ const ch = code[i]!
361
+
362
+ if (ch === '\'' || ch === '"' || ch === '`') {
363
+ i = skipString(code, i)
364
+ continue
365
+ }
366
+ if (ch === '{') {
367
+ braces += 1
368
+ i += 1
369
+ continue
370
+ }
371
+ if (ch === '}') {
372
+ braces -= 1
373
+ i += 1
374
+ continue
375
+ }
376
+ if (ch === '>' && braces === 0)
377
+ return i
378
+
379
+ i += 1
380
+ }
381
+
382
+ return code.length
383
+ }
384
+
385
+ const JSX_NAME = /^<\/?([A-Z_$][\w$.]*)?/i
386
+
387
+ /** Thuộc tính JSX: tên, `=`, rồi chuỗi hoặc một biểu thức trong ngoặc nhọn. */
388
+ function tokenizeJsxAttrs(body: string, tokens: Token[]): void {
389
+ let i = 0
390
+
391
+ while (i < body.length) {
392
+ const ch = body[i]!
393
+
394
+ if (/\s/.test(ch)) {
395
+ const start = i
396
+ while (i < body.length && /\s/.test(body[i]!))
397
+ i += 1
398
+ push(tokens, 'text', body.slice(start, i))
399
+ continue
400
+ }
401
+
402
+ if (ch === '=') {
403
+ push(tokens, 'keyword', '=')
404
+ i += 1
405
+ continue
406
+ }
407
+
408
+ if (ch === '\'' || ch === '"') {
409
+ const end = skipString(body, i)
410
+ push(tokens, 'string', body.slice(i, end))
411
+ i = end
412
+ continue
413
+ }
414
+
415
+ // `{...}`: ngoặc là dấu câu, ruột quay lại chế độ script.
416
+ if (ch === '{') {
417
+ const end = findMatchingBrace(body, i)
418
+ push(tokens, 'punctuation', '{')
419
+ tokenizeTsx(body.slice(i + 1, end), tokens)
420
+ if (end < body.length)
421
+ push(tokens, 'punctuation', '}')
422
+ i = end + 1
423
+ continue
424
+ }
425
+
426
+ const name = /^[\w:.$-]+/.exec(body.slice(i))
427
+ if (name !== null) {
428
+ push(tokens, 'attr', name[0])
429
+ i += name[0].length
430
+ continue
431
+ }
432
+
433
+ push(tokens, 'text', ch)
434
+ i += 1
435
+ }
436
+ }
437
+
438
+ /** Chỉ số của `}` khớp với `{` tại `start`; `code.length` nếu không có. */
439
+ function findMatchingBrace(code: string, start: number): number {
440
+ let depth = 0
441
+ let i = start
442
+
443
+ while (i < code.length) {
444
+ const ch = code[i]!
445
+
446
+ if (ch === '\'' || ch === '"' || ch === '`') {
447
+ i = skipString(code, i)
448
+ continue
449
+ }
450
+ if (ch === '{') {
451
+ depth += 1
452
+ }
453
+ else if (ch === '}') {
454
+ depth -= 1
455
+ if (depth === 0)
456
+ return i
457
+ }
458
+ i += 1
459
+ }
460
+
461
+ return code.length
462
+ }
463
+
464
+ /**
465
+ * Một phần tử JSX, từ `<` mở tới hết thẻ đóng. Trả về chỉ số ngay sau nó.
466
+ *
467
+ * Đệ quy cho phần tử lồng nhau; `{...}` trong nội dung quay lại chế độ script,
468
+ * nên `{items.map(x => <Row key={x} />)}` được tô đúng ở cả ba tầng.
469
+ */
470
+ function tokenizeJsxElement(code: string, start: number, tokens: Token[]): number {
471
+ const tagEnd = findTagEnd(code, start)
472
+ const raw = code.slice(start, tagEnd + 1)
473
+ const name = JSX_NAME.exec(raw)?.[1] ?? ''
474
+
475
+ const openLen = 1
476
+ push(tokens, 'punctuation', '<')
477
+ push(tokens, tagKind(name), name)
478
+
479
+ const bodyEnd = raw.endsWith('/>') ? tagEnd - 1 : tagEnd
480
+ tokenizeJsxAttrs(code.slice(start + openLen + name.length, bodyEnd), tokens)
481
+
482
+ if (raw.endsWith('/>')) {
483
+ push(tokens, 'punctuation', '/>')
484
+ return tagEnd + 1
485
+ }
486
+
487
+ push(tokens, 'punctuation', '>')
488
+
489
+ let i = tagEnd + 1
490
+ while (i < code.length) {
491
+ const ch = code[i]!
492
+
493
+ // Thẻ đóng: hết phần tử này.
494
+ if (ch === '<' && code[i + 1] === '/') {
495
+ const end = code.indexOf('>', i)
496
+ const closeName = JSX_NAME.exec(code.slice(i))?.[1] ?? ''
497
+ push(tokens, 'punctuation', '</')
498
+ push(tokens, tagKind(closeName), closeName)
499
+ push(tokens, 'punctuation', '>')
500
+ return end === -1 ? code.length : end + 1
501
+ }
502
+
503
+ if (ch === '<' && /[A-Z_$>]/i.test(code[i + 1] ?? '')) {
504
+ i = tokenizeJsxElement(code, i, tokens)
505
+ continue
506
+ }
507
+
508
+ if (ch === '{') {
509
+ const end = findMatchingBrace(code, i)
510
+ push(tokens, 'punctuation', '{')
511
+ tokenizeTsx(code.slice(i + 1, end), tokens)
512
+ if (end < code.length)
513
+ push(tokens, 'punctuation', '}')
514
+ i = end + 1
515
+ continue
516
+ }
517
+
518
+ // Chữ thường giữa hai thẻ.
519
+ const start2 = i
520
+ while (i < code.length && code[i] !== '<' && code[i] !== '{')
521
+ i += 1
522
+ push(tokens, 'text', code.slice(start2, i))
523
+ }
524
+
525
+ return code.length
526
+ }
527
+
528
+ /**
529
+ * Chế độ `tsx`: script và JSX xen kẽ.
530
+ *
531
+ * Đệ quy lẫn nhau với `tokenizeJsxElement` — đó là hình dạng thật của JSX, và
532
+ * cũng là lý do `tokenizeSfc` không dùng lại được.
533
+ */
534
+ function tokenizeTsx(code: string, tokens: Token[]): void {
535
+ let i = 0
536
+
537
+ while (i < code.length) {
538
+ const next = findJsxStart(code, i)
539
+
540
+ if (next === -1) {
541
+ tokenizeScript(code.slice(i), tokens)
542
+ return
543
+ }
544
+
545
+ tokenizeScript(code.slice(i, next), tokens)
546
+ i = tokenizeJsxElement(code, next, tokens)
547
+ }
548
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Phép dời phần tử trong mảng, dùng chung cho `OrderList` và `PickList`.
3
+ *
4
+ * KHÔNG dính framework nào — cùng lý do `lib/mask` và `lib/tree` nằm ở đây. Bốn
5
+ * component (`OrderList`, `PickList` của cả hai cây) chạy đúng một thuật toán
6
+ * dời chỗ, chứ không phải hai bản hôm nay còn khớp.
7
+ *
8
+ * Hàm thuần, trả về mảng MỚI — không sửa tại chỗ. Danh sách ở đây luôn là giá
9
+ * trị do bên ngoài giữ, mà sửa tại chỗ thì cả hai framework đều không thấy tham
10
+ * chiếu đổi và một nửa số chỗ đọc sẽ không vẽ lại.
11
+ */
12
+
13
+ /** Dời một phần tử từ `from` tới `to`. Chỉ số ngoài phạm vi thì trả nguyên mảng. */
14
+ export function moveItem<T>(items: T[], from: number, to: number): T[] {
15
+ if (from === to || from < 0 || from >= items.length)
16
+ return items
17
+ const next = [...items]
18
+ const [moved] = next.splice(from, 1)
19
+ next.splice(Math.max(0, Math.min(to, next.length)), 0, moved)
20
+ return next
21
+ }
22
+
23
+ /**
24
+ * Dời cả một nhóm đang chọn lên hoặc xuống một bậc.
25
+ *
26
+ * `step` là `-1` hoặc `1`. Nhóm giữ nguyên thứ tự tương đối, và một phần tử
27
+ * đang chọn KHÔNG đổi chỗ với một phần tử cũng đang chọn — nếu không thì chọn
28
+ * ba dòng liền nhau rồi bấm lên sẽ đảo lộn chính ba dòng đó.
29
+ *
30
+ * Duyệt theo chiều ngược với hướng dời: đi lên thì duyệt từ đầu, đi xuống thì
31
+ * duyệt từ cuối. Duyệt sai chiều là phần tử vừa dời bị dời tiếp.
32
+ */
33
+ export function moveSelectionByStep<T>(items: T[], selected: Set<number>, step: -1 | 1): T[] {
34
+ const next = [...items]
35
+ const order = [...selected].sort((a, b) => (step === -1 ? a - b : b - a))
36
+
37
+ for (const index of order) {
38
+ const target = index + step
39
+ if (target < 0 || target >= next.length || selected.has(target))
40
+ continue
41
+ const temp = next[index]
42
+ next[index] = next[target]
43
+ next[target] = temp
44
+ selected.delete(index)
45
+ selected.add(target)
46
+ }
47
+
48
+ return next
49
+ }
50
+
51
+ /** Dồn nhóm đang chọn về đầu hoặc cuối, giữ nguyên thứ tự tương đối của nhóm. */
52
+ export function moveSelectionToEdge<T>(items: T[], selected: Set<number>, edge: 'start' | 'end'): T[] {
53
+ const picked = items.filter((_, index) => selected.has(index))
54
+ const rest = items.filter((_, index) => !selected.has(index))
55
+ const next = edge === 'start' ? [...picked, ...rest] : [...rest, ...picked]
56
+
57
+ selected.clear()
58
+ const offset = edge === 'start' ? 0 : rest.length
59
+ for (let i = 0; i < picked.length; i += 1)
60
+ selected.add(offset + i)
61
+
62
+ return next
63
+ }