@polymarbot/nuxt-layer-shadcn-ui 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 (408) hide show
  1. package/app/assets/styles/animate.css +71 -0
  2. package/app/assets/styles/colors.css +116 -0
  3. package/app/assets/styles/globals.css +43 -0
  4. package/app/assets/styles/index.stories.ts +211 -0
  5. package/app/assets/styles/transition.css +34 -0
  6. package/app/assets/styles/utilities.css +26 -0
  7. package/app/components/shadcn/accordion/Accordion.vue +18 -0
  8. package/app/components/shadcn/accordion/AccordionContent.vue +23 -0
  9. package/app/components/shadcn/accordion/AccordionItem.vue +24 -0
  10. package/app/components/shadcn/accordion/AccordionTrigger.vue +37 -0
  11. package/app/components/shadcn/accordion/index.ts +4 -0
  12. package/app/components/shadcn/alert/Alert.vue +21 -0
  13. package/app/components/shadcn/alert/AlertDescription.vue +17 -0
  14. package/app/components/shadcn/alert/AlertTitle.vue +17 -0
  15. package/app/components/shadcn/alert/index.ts +24 -0
  16. package/app/components/shadcn/avatar/Avatar.vue +18 -0
  17. package/app/components/shadcn/avatar/AvatarFallback.vue +21 -0
  18. package/app/components/shadcn/avatar/AvatarImage.vue +16 -0
  19. package/app/components/shadcn/avatar/index.ts +3 -0
  20. package/app/components/shadcn/badge/Badge.vue +26 -0
  21. package/app/components/shadcn/badge/index.ts +26 -0
  22. package/app/components/shadcn/breadcrumb/Breadcrumb.vue +17 -0
  23. package/app/components/shadcn/breadcrumb/BreadcrumbEllipsis.vue +23 -0
  24. package/app/components/shadcn/breadcrumb/BreadcrumbItem.vue +17 -0
  25. package/app/components/shadcn/breadcrumb/BreadcrumbLink.vue +21 -0
  26. package/app/components/shadcn/breadcrumb/BreadcrumbList.vue +17 -0
  27. package/app/components/shadcn/breadcrumb/BreadcrumbPage.vue +20 -0
  28. package/app/components/shadcn/breadcrumb/BreadcrumbSeparator.vue +22 -0
  29. package/app/components/shadcn/breadcrumb/index.ts +7 -0
  30. package/app/components/shadcn/button/Button.vue +31 -0
  31. package/app/components/shadcn/button/index.ts +38 -0
  32. package/app/components/shadcn/card/Card.vue +22 -0
  33. package/app/components/shadcn/card/CardAction.vue +17 -0
  34. package/app/components/shadcn/card/CardContent.vue +17 -0
  35. package/app/components/shadcn/card/CardDescription.vue +17 -0
  36. package/app/components/shadcn/card/CardFooter.vue +17 -0
  37. package/app/components/shadcn/card/CardHeader.vue +17 -0
  38. package/app/components/shadcn/card/CardTitle.vue +17 -0
  39. package/app/components/shadcn/card/index.ts +7 -0
  40. package/app/components/shadcn/checkbox/Checkbox.vue +35 -0
  41. package/app/components/shadcn/checkbox/index.ts +1 -0
  42. package/app/components/shadcn/collapsible/Collapsible.vue +19 -0
  43. package/app/components/shadcn/collapsible/CollapsibleContent.vue +15 -0
  44. package/app/components/shadcn/collapsible/CollapsibleTrigger.vue +15 -0
  45. package/app/components/shadcn/collapsible/index.ts +3 -0
  46. package/app/components/shadcn/command/Command.vue +87 -0
  47. package/app/components/shadcn/command/CommandDialog.vue +31 -0
  48. package/app/components/shadcn/command/CommandEmpty.vue +27 -0
  49. package/app/components/shadcn/command/CommandGroup.vue +45 -0
  50. package/app/components/shadcn/command/CommandInput.vue +39 -0
  51. package/app/components/shadcn/command/CommandItem.vue +76 -0
  52. package/app/components/shadcn/command/CommandList.vue +25 -0
  53. package/app/components/shadcn/command/CommandSeparator.vue +21 -0
  54. package/app/components/shadcn/command/CommandShortcut.vue +17 -0
  55. package/app/components/shadcn/command/index.ts +25 -0
  56. package/app/components/shadcn/dialog/Dialog.vue +19 -0
  57. package/app/components/shadcn/dialog/DialogClose.vue +15 -0
  58. package/app/components/shadcn/dialog/DialogContent.vue +53 -0
  59. package/app/components/shadcn/dialog/DialogDescription.vue +23 -0
  60. package/app/components/shadcn/dialog/DialogFooter.vue +27 -0
  61. package/app/components/shadcn/dialog/DialogHeader.vue +17 -0
  62. package/app/components/shadcn/dialog/DialogOverlay.vue +21 -0
  63. package/app/components/shadcn/dialog/DialogScrollContent.vue +59 -0
  64. package/app/components/shadcn/dialog/DialogTitle.vue +23 -0
  65. package/app/components/shadcn/dialog/DialogTrigger.vue +15 -0
  66. package/app/components/shadcn/dialog/index.ts +10 -0
  67. package/app/components/shadcn/dropdown-menu/DropdownMenu.vue +19 -0
  68. package/app/components/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +39 -0
  69. package/app/components/shadcn/dropdown-menu/DropdownMenuContent.vue +39 -0
  70. package/app/components/shadcn/dropdown-menu/DropdownMenuGroup.vue +15 -0
  71. package/app/components/shadcn/dropdown-menu/DropdownMenuItem.vue +31 -0
  72. package/app/components/shadcn/dropdown-menu/DropdownMenuLabel.vue +23 -0
  73. package/app/components/shadcn/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  74. package/app/components/shadcn/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  75. package/app/components/shadcn/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  76. package/app/components/shadcn/dropdown-menu/DropdownMenuShortcut.vue +17 -0
  77. package/app/components/shadcn/dropdown-menu/DropdownMenuSub.vue +18 -0
  78. package/app/components/shadcn/dropdown-menu/DropdownMenuSubContent.vue +27 -0
  79. package/app/components/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
  80. package/app/components/shadcn/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  81. package/app/components/shadcn/dropdown-menu/index.ts +16 -0
  82. package/app/components/shadcn/field/Field.vue +25 -0
  83. package/app/components/shadcn/field/FieldContent.vue +20 -0
  84. package/app/components/shadcn/field/FieldDescription.vue +22 -0
  85. package/app/components/shadcn/field/FieldError.vue +53 -0
  86. package/app/components/shadcn/field/FieldGroup.vue +20 -0
  87. package/app/components/shadcn/field/FieldLabel.vue +23 -0
  88. package/app/components/shadcn/field/FieldLegend.vue +24 -0
  89. package/app/components/shadcn/field/FieldSeparator.vue +29 -0
  90. package/app/components/shadcn/field/FieldSet.vue +21 -0
  91. package/app/components/shadcn/field/FieldTitle.vue +20 -0
  92. package/app/components/shadcn/field/index.ts +39 -0
  93. package/app/components/shadcn/input/Input.vue +33 -0
  94. package/app/components/shadcn/input/index.ts +1 -0
  95. package/app/components/shadcn/input-group/InputGroup.vue +35 -0
  96. package/app/components/shadcn/input-group/InputGroupAddon.vue +36 -0
  97. package/app/components/shadcn/input-group/InputGroupButton.vue +29 -0
  98. package/app/components/shadcn/input-group/InputGroupInput.vue +19 -0
  99. package/app/components/shadcn/input-group/InputGroupText.vue +19 -0
  100. package/app/components/shadcn/input-group/InputGroupTextarea.vue +19 -0
  101. package/app/components/shadcn/input-group/index.ts +51 -0
  102. package/app/components/shadcn/label/Label.vue +26 -0
  103. package/app/components/shadcn/label/index.ts +1 -0
  104. package/app/components/shadcn/number-field/NumberField.vue +20 -0
  105. package/app/components/shadcn/number-field/NumberFieldContent.vue +14 -0
  106. package/app/components/shadcn/number-field/NumberFieldDecrement.vue +22 -0
  107. package/app/components/shadcn/number-field/NumberFieldIncrement.vue +22 -0
  108. package/app/components/shadcn/number-field/NumberFieldInput.vue +16 -0
  109. package/app/components/shadcn/number-field/index.ts +5 -0
  110. package/app/components/shadcn/pagination/Pagination.vue +26 -0
  111. package/app/components/shadcn/pagination/PaginationContent.vue +22 -0
  112. package/app/components/shadcn/pagination/PaginationEllipsis.vue +25 -0
  113. package/app/components/shadcn/pagination/PaginationFirst.vue +33 -0
  114. package/app/components/shadcn/pagination/PaginationItem.vue +34 -0
  115. package/app/components/shadcn/pagination/PaginationLast.vue +33 -0
  116. package/app/components/shadcn/pagination/PaginationNext.vue +33 -0
  117. package/app/components/shadcn/pagination/PaginationPrevious.vue +33 -0
  118. package/app/components/shadcn/pagination/index.ts +8 -0
  119. package/app/components/shadcn/pin-input/PinInput.vue +26 -0
  120. package/app/components/shadcn/pin-input/PinInputGroup.vue +21 -0
  121. package/app/components/shadcn/pin-input/PinInputSeparator.vue +19 -0
  122. package/app/components/shadcn/pin-input/PinInputSlot.vue +21 -0
  123. package/app/components/shadcn/pin-input/index.ts +4 -0
  124. package/app/components/shadcn/popover/Popover.vue +19 -0
  125. package/app/components/shadcn/popover/PopoverAnchor.vue +15 -0
  126. package/app/components/shadcn/popover/PopoverContent.vue +45 -0
  127. package/app/components/shadcn/popover/PopoverTrigger.vue +15 -0
  128. package/app/components/shadcn/popover/index.ts +4 -0
  129. package/app/components/shadcn/progress/Progress.vue +38 -0
  130. package/app/components/shadcn/progress/index.ts +1 -0
  131. package/app/components/shadcn/radio-group/RadioGroup.vue +25 -0
  132. package/app/components/shadcn/radio-group/RadioGroupItem.vue +40 -0
  133. package/app/components/shadcn/radio-group/index.ts +2 -0
  134. package/app/components/shadcn/scroll-area/ScrollArea.vue +33 -0
  135. package/app/components/shadcn/scroll-area/ScrollBar.vue +32 -0
  136. package/app/components/shadcn/scroll-area/index.ts +2 -0
  137. package/app/components/shadcn/select/Select.vue +19 -0
  138. package/app/components/shadcn/select/SelectContent.vue +51 -0
  139. package/app/components/shadcn/select/SelectGroup.vue +15 -0
  140. package/app/components/shadcn/select/SelectItem.vue +44 -0
  141. package/app/components/shadcn/select/SelectItemText.vue +15 -0
  142. package/app/components/shadcn/select/SelectLabel.vue +17 -0
  143. package/app/components/shadcn/select/SelectScrollDownButton.vue +26 -0
  144. package/app/components/shadcn/select/SelectScrollUpButton.vue +26 -0
  145. package/app/components/shadcn/select/SelectSeparator.vue +19 -0
  146. package/app/components/shadcn/select/SelectTrigger.vue +33 -0
  147. package/app/components/shadcn/select/SelectValue.vue +15 -0
  148. package/app/components/shadcn/select/index.ts +11 -0
  149. package/app/components/shadcn/separator/Separator.vue +29 -0
  150. package/app/components/shadcn/separator/index.ts +1 -0
  151. package/app/components/shadcn/sheet/Sheet.vue +19 -0
  152. package/app/components/shadcn/sheet/SheetClose.vue +15 -0
  153. package/app/components/shadcn/sheet/SheetContent.vue +62 -0
  154. package/app/components/shadcn/sheet/SheetDescription.vue +21 -0
  155. package/app/components/shadcn/sheet/SheetFooter.vue +16 -0
  156. package/app/components/shadcn/sheet/SheetHeader.vue +15 -0
  157. package/app/components/shadcn/sheet/SheetOverlay.vue +21 -0
  158. package/app/components/shadcn/sheet/SheetTitle.vue +21 -0
  159. package/app/components/shadcn/sheet/SheetTrigger.vue +15 -0
  160. package/app/components/shadcn/sheet/index.ts +8 -0
  161. package/app/components/shadcn/sidebar/Sidebar.vue +96 -0
  162. package/app/components/shadcn/sidebar/SidebarContent.vue +18 -0
  163. package/app/components/shadcn/sidebar/SidebarFooter.vue +18 -0
  164. package/app/components/shadcn/sidebar/SidebarGroup.vue +18 -0
  165. package/app/components/shadcn/sidebar/SidebarGroupAction.vue +27 -0
  166. package/app/components/shadcn/sidebar/SidebarGroupContent.vue +18 -0
  167. package/app/components/shadcn/sidebar/SidebarGroupLabel.vue +25 -0
  168. package/app/components/shadcn/sidebar/SidebarHeader.vue +18 -0
  169. package/app/components/shadcn/sidebar/SidebarInput.vue +22 -0
  170. package/app/components/shadcn/sidebar/SidebarInset.vue +21 -0
  171. package/app/components/shadcn/sidebar/SidebarMenu.vue +18 -0
  172. package/app/components/shadcn/sidebar/SidebarMenuAction.vue +35 -0
  173. package/app/components/shadcn/sidebar/SidebarMenuBadge.vue +26 -0
  174. package/app/components/shadcn/sidebar/SidebarMenuButton.vue +48 -0
  175. package/app/components/shadcn/sidebar/SidebarMenuButtonChild.vue +36 -0
  176. package/app/components/shadcn/sidebar/SidebarMenuItem.vue +18 -0
  177. package/app/components/shadcn/sidebar/SidebarMenuSkeleton.vue +35 -0
  178. package/app/components/shadcn/sidebar/SidebarMenuSub.vue +22 -0
  179. package/app/components/shadcn/sidebar/SidebarMenuSubButton.vue +36 -0
  180. package/app/components/shadcn/sidebar/SidebarMenuSubItem.vue +18 -0
  181. package/app/components/shadcn/sidebar/SidebarProvider.vue +82 -0
  182. package/app/components/shadcn/sidebar/SidebarRail.vue +33 -0
  183. package/app/components/shadcn/sidebar/SidebarSeparator.vue +19 -0
  184. package/app/components/shadcn/sidebar/SidebarTrigger.vue +27 -0
  185. package/app/components/shadcn/sidebar/index.ts +60 -0
  186. package/app/components/shadcn/sidebar/utils.ts +19 -0
  187. package/app/components/shadcn/skeleton/Skeleton.vue +17 -0
  188. package/app/components/shadcn/skeleton/index.ts +1 -0
  189. package/app/components/shadcn/slider/Slider.vue +43 -0
  190. package/app/components/shadcn/slider/index.ts +1 -0
  191. package/app/components/shadcn/sonner/Sonner.vue +42 -0
  192. package/app/components/shadcn/sonner/index.ts +1 -0
  193. package/app/components/shadcn/switch/Switch.vue +38 -0
  194. package/app/components/shadcn/switch/index.ts +1 -0
  195. package/app/components/shadcn/table/Table.vue +16 -0
  196. package/app/components/shadcn/table/TableBody.vue +17 -0
  197. package/app/components/shadcn/table/TableCaption.vue +17 -0
  198. package/app/components/shadcn/table/TableCell.vue +22 -0
  199. package/app/components/shadcn/table/TableEmpty.vue +34 -0
  200. package/app/components/shadcn/table/TableFooter.vue +17 -0
  201. package/app/components/shadcn/table/TableHead.vue +17 -0
  202. package/app/components/shadcn/table/TableHeader.vue +17 -0
  203. package/app/components/shadcn/table/TableRow.vue +17 -0
  204. package/app/components/shadcn/table/index.ts +9 -0
  205. package/app/components/shadcn/table/utils.ts +10 -0
  206. package/app/components/shadcn/tabs/Tabs.vue +24 -0
  207. package/app/components/shadcn/tabs/TabsContent.vue +21 -0
  208. package/app/components/shadcn/tabs/TabsList.vue +24 -0
  209. package/app/components/shadcn/tabs/TabsTrigger.vue +26 -0
  210. package/app/components/shadcn/tabs/index.ts +4 -0
  211. package/app/components/shadcn/textarea/Textarea.vue +28 -0
  212. package/app/components/shadcn/textarea/index.ts +1 -0
  213. package/app/components/shadcn/toggle/Toggle.vue +35 -0
  214. package/app/components/shadcn/toggle/index.ts +28 -0
  215. package/app/components/shadcn/toggle-group/ToggleGroup.vue +49 -0
  216. package/app/components/shadcn/toggle-group/ToggleGroupItem.vue +46 -0
  217. package/app/components/shadcn/toggle-group/index.ts +2 -0
  218. package/app/components/shadcn/tooltip/Tooltip.vue +19 -0
  219. package/app/components/shadcn/tooltip/TooltipContent.vue +34 -0
  220. package/app/components/shadcn/tooltip/TooltipProvider.vue +14 -0
  221. package/app/components/shadcn/tooltip/TooltipTrigger.vue +15 -0
  222. package/app/components/shadcn/tooltip/index.ts +4 -0
  223. package/app/components/ui/Accordion/index.stories.ts +108 -0
  224. package/app/components/ui/Accordion/index.vue +80 -0
  225. package/app/components/ui/Accordion/types.ts +27 -0
  226. package/app/components/ui/Alert/index.stories.ts +53 -0
  227. package/app/components/ui/Alert/index.vue +61 -0
  228. package/app/components/ui/Alert/types.ts +9 -0
  229. package/app/components/ui/AlertDialog/index.stories.ts +108 -0
  230. package/app/components/ui/AlertDialog/index.vue +25 -0
  231. package/app/components/ui/AsyncDataTable/en.json +3 -0
  232. package/app/components/ui/AsyncDataTable/index.stories.ts +141 -0
  233. package/app/components/ui/AsyncDataTable/index.vue +312 -0
  234. package/app/components/ui/AsyncDataTable/types.ts +53 -0
  235. package/app/components/ui/Avatar/index.stories.ts +84 -0
  236. package/app/components/ui/Avatar/index.vue +52 -0
  237. package/app/components/ui/Avatar/types.ts +8 -0
  238. package/app/components/ui/Badge/index.stories.ts +67 -0
  239. package/app/components/ui/Badge/index.vue +12 -0
  240. package/app/components/ui/Badge/types.ts +3 -0
  241. package/app/components/ui/Breadcrumb/index.stories.ts +52 -0
  242. package/app/components/ui/Breadcrumb/index.vue +61 -0
  243. package/app/components/ui/Breadcrumb/types.ts +11 -0
  244. package/app/components/ui/Button/index.stories.ts +145 -0
  245. package/app/components/ui/Button/index.vue +63 -0
  246. package/app/components/ui/Button/types.ts +14 -0
  247. package/app/components/ui/ButtonGroup/index.stories.ts +75 -0
  248. package/app/components/ui/ButtonGroup/index.vue +22 -0
  249. package/app/components/ui/ButtonGroup/types.ts +3 -0
  250. package/app/components/ui/Card/index.stories.ts +65 -0
  251. package/app/components/ui/Card/index.vue +28 -0
  252. package/app/components/ui/Card/types.ts +3 -0
  253. package/app/components/ui/Checkbox/index.stories.ts +68 -0
  254. package/app/components/ui/Checkbox/index.vue +23 -0
  255. package/app/components/ui/Checkbox/types.ts +3 -0
  256. package/app/components/ui/CopyButton/en.json +4 -0
  257. package/app/components/ui/CopyButton/index.stories.ts +55 -0
  258. package/app/components/ui/CopyButton/index.vue +98 -0
  259. package/app/components/ui/CopyButton/types.ts +10 -0
  260. package/app/components/ui/DataTable/en.json +3 -0
  261. package/app/components/ui/DataTable/index.stories.ts +231 -0
  262. package/app/components/ui/DataTable/index.vue +505 -0
  263. package/app/components/ui/DataTable/types.ts +42 -0
  264. package/app/components/ui/DatePicker/en.json +9 -0
  265. package/app/components/ui/DatePicker/index.stories.ts +70 -0
  266. package/app/components/ui/DatePicker/index.vue +127 -0
  267. package/app/components/ui/DatePicker/style.css +88 -0
  268. package/app/components/ui/DatePicker/types.ts +41 -0
  269. package/app/components/ui/DateRangePicker/en.json +5 -0
  270. package/app/components/ui/DateRangePicker/index.stories.ts +67 -0
  271. package/app/components/ui/DateRangePicker/index.vue +138 -0
  272. package/app/components/ui/DateRangePicker/types.ts +31 -0
  273. package/app/components/ui/Divider/index.stories.ts +42 -0
  274. package/app/components/ui/Divider/index.vue +16 -0
  275. package/app/components/ui/Divider/types.ts +3 -0
  276. package/app/components/ui/Drawer/index.stories.ts +124 -0
  277. package/app/components/ui/Drawer/index.vue +197 -0
  278. package/app/components/ui/Drawer/types.ts +22 -0
  279. package/app/components/ui/Dropdown/index.stories.ts +145 -0
  280. package/app/components/ui/Dropdown/index.vue +258 -0
  281. package/app/components/ui/Dropdown/types.ts +87 -0
  282. package/app/components/ui/FormItem/index.stories.ts +70 -0
  283. package/app/components/ui/FormItem/index.vue +56 -0
  284. package/app/components/ui/FormItem/types.ts +14 -0
  285. package/app/components/ui/Help/index.stories.ts +54 -0
  286. package/app/components/ui/Help/index.vue +35 -0
  287. package/app/components/ui/Help/types.ts +8 -0
  288. package/app/components/ui/Icon/index.stories.ts +68 -0
  289. package/app/components/ui/Icon/index.vue +30 -0
  290. package/app/components/ui/Icon/types.ts +5 -0
  291. package/app/components/ui/Input/index.stories.ts +73 -0
  292. package/app/components/ui/Input/index.vue +92 -0
  293. package/app/components/ui/Input/types.ts +9 -0
  294. package/app/components/ui/InputCurrency/index.stories.ts +75 -0
  295. package/app/components/ui/InputCurrency/index.vue +31 -0
  296. package/app/components/ui/InputCurrency/types.ts +4 -0
  297. package/app/components/ui/InputNumber/index.stories.ts +56 -0
  298. package/app/components/ui/InputNumber/index.vue +76 -0
  299. package/app/components/ui/InputNumber/types.ts +10 -0
  300. package/app/components/ui/InputOtp/index.stories.ts +39 -0
  301. package/app/components/ui/InputOtp/index.vue +45 -0
  302. package/app/components/ui/InputOtp/types.ts +5 -0
  303. package/app/components/ui/InputPercent/index.stories.ts +32 -0
  304. package/app/components/ui/InputPercent/index.vue +8 -0
  305. package/app/components/ui/InputRange/index.stories.ts +37 -0
  306. package/app/components/ui/InputRange/index.vue +49 -0
  307. package/app/components/ui/InputRange/types.ts +8 -0
  308. package/app/components/ui/Loading/index.stories.ts +36 -0
  309. package/app/components/ui/Loading/index.vue +15 -0
  310. package/app/components/ui/Loading/types.ts +3 -0
  311. package/app/components/ui/Markdown/index.stories.ts +52 -0
  312. package/app/components/ui/Markdown/index.vue +22 -0
  313. package/app/components/ui/Markdown/themes/github.css +1248 -0
  314. package/app/components/ui/Markdown/types.ts +3 -0
  315. package/app/components/ui/Modal/index.stories.ts +124 -0
  316. package/app/components/ui/Modal/index.vue +202 -0
  317. package/app/components/ui/Modal/types.ts +23 -0
  318. package/app/components/ui/ModalContent/index.stories.ts +47 -0
  319. package/app/components/ui/ModalContent/index.vue +79 -0
  320. package/app/components/ui/ModalContent/types.ts +9 -0
  321. package/app/components/ui/PageCard/index.stories.ts +106 -0
  322. package/app/components/ui/PageCard/index.vue +135 -0
  323. package/app/components/ui/PageCard/types.ts +16 -0
  324. package/app/components/ui/Pagination/en.json +3 -0
  325. package/app/components/ui/Pagination/index.stories.ts +82 -0
  326. package/app/components/ui/Pagination/index.vue +173 -0
  327. package/app/components/ui/Pagination/types.ts +18 -0
  328. package/app/components/ui/Popover/index.stories.ts +67 -0
  329. package/app/components/ui/Popover/index.vue +21 -0
  330. package/app/components/ui/Popover/types.ts +5 -0
  331. package/app/components/ui/Qrcode/index.stories.ts +57 -0
  332. package/app/components/ui/Qrcode/index.vue +40 -0
  333. package/app/components/ui/Qrcode/types.ts +3 -0
  334. package/app/components/ui/Radio/index.stories.ts +71 -0
  335. package/app/components/ui/Radio/index.vue +10 -0
  336. package/app/components/ui/Radio/types.ts +3 -0
  337. package/app/components/ui/RadioCardGroup/index.stories.ts +90 -0
  338. package/app/components/ui/RadioCardGroup/index.vue +64 -0
  339. package/app/components/ui/RadioCardGroup/types.ts +13 -0
  340. package/app/components/ui/ScrollArea/index.stories.ts +66 -0
  341. package/app/components/ui/ScrollArea/index.vue +64 -0
  342. package/app/components/ui/ScrollArea/types.ts +5 -0
  343. package/app/components/ui/SearchSelect/en.json +5 -0
  344. package/app/components/ui/SearchSelect/index.stories.ts +126 -0
  345. package/app/components/ui/SearchSelect/index.vue +259 -0
  346. package/app/components/ui/SearchSelect/types.ts +39 -0
  347. package/app/components/ui/Select/en.json +6 -0
  348. package/app/components/ui/Select/index.stories.ts +128 -0
  349. package/app/components/ui/Select/index.vue +267 -0
  350. package/app/components/ui/Select/types.ts +34 -0
  351. package/app/components/ui/Skeleton/index.stories.ts +56 -0
  352. package/app/components/ui/Skeleton/index.vue +12 -0
  353. package/app/components/ui/Skeleton/types.ts +4 -0
  354. package/app/components/ui/Slider/index.stories.ts +60 -0
  355. package/app/components/ui/Slider/index.vue +27 -0
  356. package/app/components/ui/Slider/types.ts +5 -0
  357. package/app/components/ui/Surface/index.stories.ts +50 -0
  358. package/app/components/ui/Surface/index.vue +108 -0
  359. package/app/components/ui/Surface/types.ts +8 -0
  360. package/app/components/ui/Switch/index.stories.ts +32 -0
  361. package/app/components/ui/Switch/index.vue +10 -0
  362. package/app/components/ui/Switch/types.ts +3 -0
  363. package/app/components/ui/Tabs/index.stories.ts +116 -0
  364. package/app/components/ui/Tabs/index.vue +94 -0
  365. package/app/components/ui/Tabs/types.ts +19 -0
  366. package/app/components/ui/Tag/index.stories.ts +51 -0
  367. package/app/components/ui/Tag/index.vue +108 -0
  368. package/app/components/ui/Tag/types.ts +8 -0
  369. package/app/components/ui/Textarea/index.stories.ts +35 -0
  370. package/app/components/ui/Textarea/index.vue +50 -0
  371. package/app/components/ui/Textarea/types.ts +8 -0
  372. package/app/components/ui/Toast/index.stories.ts +48 -0
  373. package/app/components/ui/Toast/index.vue +21 -0
  374. package/app/components/ui/Toast/types.ts +5 -0
  375. package/app/components/ui/Tooltip/index.stories.ts +62 -0
  376. package/app/components/ui/Tooltip/index.vue +72 -0
  377. package/app/components/ui/Tooltip/types.ts +7 -0
  378. package/app/components/ui/WebLink/index.stories.ts +59 -0
  379. package/app/components/ui/WebLink/index.vue +61 -0
  380. package/app/components/ui/WebLink/types.ts +11 -0
  381. package/app/composables/index.ts +9 -0
  382. package/app/composables/useDialog.ts +76 -0
  383. package/app/composables/useToast.ts +49 -0
  384. package/app/en.json +23 -0
  385. package/app/types/index.ts +7 -0
  386. package/app/utils/index.ts +6 -0
  387. package/i18n/messages/ar.json +65 -0
  388. package/i18n/messages/de.json +65 -0
  389. package/i18n/messages/en.json +65 -0
  390. package/i18n/messages/es.json +65 -0
  391. package/i18n/messages/fr.json +65 -0
  392. package/i18n/messages/hi.json +65 -0
  393. package/i18n/messages/id.json +65 -0
  394. package/i18n/messages/it.json +65 -0
  395. package/i18n/messages/ja.json +65 -0
  396. package/i18n/messages/ko.json +65 -0
  397. package/i18n/messages/nl.json +65 -0
  398. package/i18n/messages/pl.json +65 -0
  399. package/i18n/messages/pt.json +65 -0
  400. package/i18n/messages/ru.json +65 -0
  401. package/i18n/messages/th.json +65 -0
  402. package/i18n/messages/tr.json +65 -0
  403. package/i18n/messages/vi.json +65 -0
  404. package/i18n/messages/zh-CN.json +65 -0
  405. package/i18n/messages/zh-TW.json +65 -0
  406. package/i18n.config.ts +19 -0
  407. package/nuxt.config.ts +62 -0
  408. package/package.json +46 -0
@@ -0,0 +1,505 @@
1
+ <script setup lang="ts" generic="TData extends Record<string, any>">
2
+ import { useResizeObserver } from '@vueuse/core'
3
+ import { get } from 'lodash-es'
4
+ import {
5
+ Table,
6
+ TableBody,
7
+ TableCell,
8
+ TableEmpty,
9
+ TableFooter,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ } from '@polymarbot/nuxt-layer-shadcn-ui/app/components/shadcn/table'
14
+ import type {
15
+ DataTableColumn,
16
+ DataTableProps,
17
+ } from './types'
18
+
19
+ type FrozenShadow = 'left' | 'right'
20
+
21
+ const props = withDefaults(defineProps<DataTableProps<TData>>(), {
22
+ data: () => [],
23
+ columns: () => [],
24
+ selectionMode: undefined,
25
+ sortBy: undefined,
26
+ sortOrder: undefined,
27
+ loading: false,
28
+ })
29
+
30
+ const emit = defineEmits<{
31
+ 'update:sortBy': [value: string | null]
32
+ 'update:sortOrder': [value: number | null]
33
+ }>()
34
+
35
+ const selection = defineModel<TData | TData[] | null>('selection', { default: null })
36
+
37
+ defineSlots<
38
+ Record<string, (_: {
39
+ column: DataTableColumn
40
+ row: TData
41
+ value: unknown
42
+ index: number
43
+ }) => any> & {
44
+ empty?: () => any
45
+ footer?: () => any
46
+ } & Record<`header-${string}`, (_: { column: DataTableColumn }) => any>
47
+ >()
48
+
49
+ const T = useTranslations('components.ui.DataTable')
50
+ const { formatDateTime } = useDate()
51
+
52
+ // -- Selection --
53
+
54
+ const showSelectionColumn = computed(() => !!props.selectionMode)
55
+
56
+ // Set of raw references for O(1) lookup, centralizes toRaw conversion
57
+ const selectedSet = computed(() => {
58
+ if (!Array.isArray(selection.value)) return new Set<TData>()
59
+ return new Set(selection.value.map(r => toRaw(r) as TData))
60
+ })
61
+
62
+ // Header "select all" checkbox
63
+ const allChecked = computed({
64
+ get () {
65
+ if (!props.data?.length) return false
66
+ const size = selectedSet.value.size
67
+ if (size === props.data.length) return true
68
+ if (size > 0) return 'indeterminate' as const
69
+ return false
70
+ },
71
+ set (val: boolean | 'indeterminate') {
72
+ selection.value = val === true ? [ ...props.data ] : []
73
+ },
74
+ })
75
+
76
+ function isRowSelected (row: TData): boolean {
77
+ if (props.selectionMode === 'multiple') {
78
+ return selectedSet.value.has(toRaw(row))
79
+ }
80
+ return toRaw(selection.value) === toRaw(row)
81
+ }
82
+
83
+ function toggleRow (row: TData) {
84
+ const rawRow = toRaw(row) as TData
85
+ if (props.selectionMode === 'single') {
86
+ selection.value = isRowSelected(row) ? null : rawRow
87
+ } else if (props.selectionMode === 'multiple') {
88
+ const set = new Set(selectedSet.value)
89
+ set.has(rawRow) ? set.delete(rawRow) : set.add(rawRow)
90
+ selection.value = [ ...set ]
91
+ }
92
+ }
93
+
94
+ // -- Sorting --
95
+ // Sort cycle: null → asc(1) → desc(-1) → null (removable sort)
96
+
97
+ function handleSort (column: DataTableColumn) {
98
+ if (!column.sortable) return
99
+
100
+ if (props.sortBy !== column.field) {
101
+ emit('update:sortBy', column.field)
102
+ emit('update:sortOrder', 1)
103
+ } else if (props.sortOrder === 1) {
104
+ emit('update:sortOrder', -1)
105
+ } else {
106
+ emit('update:sortBy', null)
107
+ emit('update:sortOrder', null)
108
+ }
109
+ }
110
+
111
+ function getSortIcon (column: DataTableColumn): string | null {
112
+ if (!column.sortable) return null
113
+ if (props.sortBy !== column.field) return 'arrow-up-down'
114
+ return props.sortOrder === 1 ? 'arrow-up' : 'arrow-down'
115
+ }
116
+
117
+ // -- Cell formatting --
118
+
119
+ function formatCellValue (value: unknown, column: DataTableColumn): string {
120
+ if (value === null || value === undefined) return ''
121
+
122
+ switch (column.type) {
123
+ case 'date':
124
+ return formatDateTime(value as string | Date).split(' ').join('\n')
125
+
126
+ case 'unixDate':
127
+ return formatDateTime((value as number) * 1000).split(' ').join('\n')
128
+
129
+ case 'currency':
130
+ return formatCurrency(value as number | string, column.currency ?? 'JPY')
131
+
132
+ case 'empty':
133
+ return ''
134
+
135
+ default:
136
+ return String(value)
137
+ }
138
+ }
139
+
140
+ // -- Column styles --
141
+
142
+ const totalColumns = computed(() =>
143
+ props.columns.length + (showSelectionColumn.value ? 1 : 0),
144
+ )
145
+
146
+ // -- Scroll & frozen column state --
147
+
148
+ const tableRef = ref<InstanceType<typeof Table>>()
149
+ const scrollEl = ref<HTMLElement>()
150
+ const headerRowEl = ref<HTMLElement>()
151
+ const { atStart, atEnd } = useScrollState(scrollEl, 'horizontal')
152
+ useResizeObserver(headerRowEl, measureFrozenOffsets)
153
+
154
+ // Frozen column offsets: measured from rendered header cells
155
+ const frozenOffsets = ref(new Map<string, string>())
156
+
157
+ onMounted(() => {
158
+ const root = tableRef.value?.$el as HTMLElement | undefined
159
+ scrollEl.value = root ?? undefined
160
+ headerRowEl.value = root?.querySelector<HTMLElement>('thead tr') ?? undefined
161
+ nextTick(measureFrozenOffsets)
162
+ })
163
+
164
+ function measureFrozenOffsets () {
165
+ const row = headerRowEl.value
166
+ if (!row) return
167
+
168
+ const cells = Array.from(row.querySelectorAll<HTMLElement>('th'))
169
+ const offsets = new Map<string, string>()
170
+ const cols = props.columns
171
+ const selOffset = showSelectionColumn.value ? 1 : 0
172
+
173
+ // Left-fixed: accumulate from left (start after selection column if present)
174
+ let left = selOffset ? (cells[0]?.offsetWidth ?? 0) : 0
175
+ for (let i = 0; i < cols.length; i++) {
176
+ if (cols[i]!.fixed !== 'left') break
177
+ offsets.set(cols[i]!.field, `${left}px`)
178
+ left += cells[i + selOffset]?.offsetWidth ?? 0
179
+ }
180
+
181
+ // Right-fixed: accumulate from right
182
+ let right = 0
183
+ for (let i = cols.length - 1; i >= 0; i--) {
184
+ const col = cols[i]!
185
+ if (col.fixed !== 'right') break
186
+ offsets.set(col.field, `${right}px`)
187
+ right += cells[i + selOffset]?.offsetWidth ?? 0
188
+ }
189
+
190
+ frozenOffsets.value = offsets
191
+ }
192
+
193
+ // Compute edge frozen columns for shadow effect
194
+ const lastLeftFrozenField = computed(() =>
195
+ props.columns.findLast(c => c.fixed === 'left')?.field ?? null,
196
+ )
197
+
198
+ const firstRightFrozenField = computed(() =>
199
+ props.columns.find(c => c.fixed === 'right')?.field ?? null,
200
+ )
201
+
202
+ function buildColumnClass (column: DataTableColumn, headerIndex?: number): string {
203
+ const isHeader = headerIndex !== undefined
204
+ const hasDivider = isHeader && headerIndex < props.columns.length - 1
205
+
206
+ return cn(
207
+ column.align === 'center' && 'text-center',
208
+ column.align === 'right' && 'text-right',
209
+ // Header-specific
210
+ isHeader && column.sortable && `
211
+ cursor-pointer select-none
212
+ hover:text-foreground
213
+ `,
214
+ hasDivider && headerDividerClass,
215
+ // Fixed column last — sticky overrides relative via tailwind-merge
216
+ column.fixed && 'sticky z-10',
217
+ )
218
+ }
219
+
220
+ function buildFrozenShadow (column: DataTableColumn): FrozenShadow | undefined {
221
+ if (column.field === lastLeftFrozenField.value && !atStart.value) return 'left'
222
+ if (column.field === firstRightFrozenField.value && !atEnd.value) return 'right'
223
+ return undefined
224
+ }
225
+
226
+ function buildColumnStyle (column: DataTableColumn): Record<string, string> {
227
+ const style: Record<string, string> = {}
228
+ if (column.width) style.width = column.width
229
+ if (column.minWidth) style.minWidth = column.minWidth
230
+
231
+ if (column.type === 'date' || column.type === 'unixDate') {
232
+ style.whiteSpace = 'pre'
233
+ } else if (!column.wrap) {
234
+ style.whiteSpace = 'nowrap'
235
+ }
236
+
237
+ // Frozen column offset
238
+ const offset = frozenOffsets.value.get(column.field)
239
+ if (offset !== undefined) {
240
+ if (column.fixed === 'left') style.left = offset
241
+ else if (column.fixed === 'right') style.right = offset
242
+ }
243
+
244
+ return style
245
+ }
246
+
247
+ // Reusable class fragments
248
+ const headerCellClass = 'h-auto bg-border px-4 py-3 text-xs font-normal text-foreground'
249
+ const headerDividerClass = 'relative after:absolute after:top-1/2 after:right-0 after:h-4 after:w-px after:-translate-y-1/2 after:bg-muted-foreground/25'
250
+ const stickyLeftClass = 'sticky left-0 z-10'
251
+
252
+ const selectionColumnClass = '[&:has([role=checkbox])]:pr-4'
253
+ const selectionColumnStyle = { width: '1%' }
254
+ const selectionColumnShadowDir = computed<FrozenShadow | undefined>(() =>
255
+ showSelectionColumn.value && !lastLeftFrozenField.value && !atStart.value ? 'left' : undefined,
256
+ )
257
+ </script>
258
+
259
+ <template>
260
+ <div
261
+ :class="cn('relative rounded-lg bg-border px-1 text-foreground', !$slots.footer && `
262
+ pb-1
263
+ `)"
264
+ >
265
+ <!-- Loading overlay -->
266
+ <Transition
267
+ enterActiveClass="transition-opacity duration-200"
268
+ leaveActiveClass="transition-opacity duration-200"
269
+ enterFromClass="opacity-0"
270
+ leaveToClass="opacity-0"
271
+ >
272
+ <div
273
+ v-if="loading"
274
+ class="
275
+ absolute inset-0 z-20 flex items-center justify-center rounded-lg
276
+ bg-background/60
277
+ "
278
+ >
279
+ <Icon
280
+ name="loader-circle"
281
+ class="size-6 animate-spin text-muted-foreground"
282
+ />
283
+ </div>
284
+ </Transition>
285
+
286
+ <Table ref="tableRef">
287
+ <TableHeader>
288
+ <TableRow
289
+ class="hover:bg-transparent"
290
+ >
291
+ <!-- Selection header -->
292
+ <TableHead
293
+ v-if="showSelectionColumn"
294
+ :class="cn(headerCellClass, headerDividerClass, stickyLeftClass, selectionColumnClass)"
295
+ :style="selectionColumnStyle"
296
+ :data-shadow="selectionColumnShadowDir"
297
+ >
298
+ <Checkbox
299
+ v-if="selectionMode === 'multiple'"
300
+ v-model="allChecked"
301
+ class="bg-background"
302
+ />
303
+ </TableHead>
304
+
305
+ <!-- Column headers -->
306
+ <TableHead
307
+ v-for="(column, colIndex) in columns"
308
+ :key="column.field"
309
+ :class="cn(headerCellClass, buildColumnClass(column, colIndex))"
310
+ :style="buildColumnStyle(column)"
311
+ :data-shadow="buildFrozenShadow(column)"
312
+ @click="handleSort(column)"
313
+ >
314
+ <slot
315
+ :name="`header-${column.field}`"
316
+ :column="column"
317
+ >
318
+ <div
319
+ :class="cn(
320
+ 'flex items-center gap-1',
321
+ column.align === 'center' && 'justify-center',
322
+ column.align === 'right' && 'justify-end',
323
+ )"
324
+ >
325
+ <span>{{ column.title }}</span>
326
+ <Icon
327
+ v-if="getSortIcon(column)"
328
+ :name="getSortIcon(column)!"
329
+ :class="cn(
330
+ 'size-3 shrink-0',
331
+ sortBy === column.field ? 'text-foreground' : `
332
+ text-muted-foreground
333
+ `,
334
+ )"
335
+ />
336
+ </div>
337
+ </slot>
338
+ </TableHead>
339
+ </TableRow>
340
+ </TableHeader>
341
+
342
+ <TableBody
343
+ class="
344
+ [&_td]:px-4 [&_td]:py-2 [&_td]:text-card-foreground
345
+ [&_tr]:h-15
346
+ "
347
+ >
348
+ <template v-if="data?.length">
349
+ <TableRow
350
+ v-for="(row, index) in data"
351
+ :key="index"
352
+ :class="showSelectionColumn && 'cursor-pointer'"
353
+ :data-state="isRowSelected(row) ? 'selected' : undefined"
354
+ @click="showSelectionColumn && toggleRow(row)"
355
+ >
356
+ <!-- Selection cell: stop click to prevent double toggle with row click -->
357
+ <TableCell
358
+ v-if="showSelectionColumn"
359
+ :class="cn(stickyLeftClass, selectionColumnClass)"
360
+ :style="selectionColumnStyle"
361
+ :data-shadow="selectionColumnShadowDir"
362
+ @click.stop
363
+ >
364
+ <Checkbox
365
+ :modelValue="isRowSelected(row)"
366
+ class="bg-muted-foreground/15"
367
+ @update:modelValue="toggleRow(row)"
368
+ />
369
+ </TableCell>
370
+
371
+ <!-- Data cells -->
372
+ <TableCell
373
+ v-for="column in columns"
374
+ :key="column.field"
375
+ :class="buildColumnClass(column)"
376
+ :style="buildColumnStyle(column)"
377
+ :data-shadow="buildFrozenShadow(column)"
378
+ >
379
+ <slot
380
+ :name="column.field"
381
+ :column="column"
382
+ :row="row"
383
+ :value="get(row, column.field)"
384
+ :index="index"
385
+ >
386
+ <span
387
+ v-if="!formatCellValue(get(row, column.field), column) && column.type !== 'empty'"
388
+ class="
389
+ inline-block h-0.5 w-2.5 rounded-full bg-muted-foreground/50
390
+ align-middle
391
+ "
392
+ />
393
+ <template v-else>
394
+ {{ formatCellValue(get(row, column.field), column) }}
395
+ </template>
396
+ </slot>
397
+ </TableCell>
398
+ </TableRow>
399
+ </template>
400
+
401
+ <template v-else>
402
+ <TableEmpty :colspan="totalColumns">
403
+ <slot name="empty">
404
+ <div
405
+ class="flex flex-col items-center gap-2 text-muted-foreground"
406
+ >
407
+ <Icon
408
+ name="inbox"
409
+ class="size-8"
410
+ />
411
+ <span class="text-sm">
412
+ {{ T('empty') }}
413
+ </span>
414
+ </div>
415
+ </slot>
416
+ </TableEmpty>
417
+ </template>
418
+ </TableBody>
419
+
420
+ <TableFooter
421
+ v-if="$slots.footer"
422
+ class="border-t-0 bg-transparent"
423
+ >
424
+ <slot name="footer" />
425
+ </TableFooter>
426
+ </Table>
427
+ </div>
428
+ </template>
429
+
430
+ <style scoped>
431
+ /* CSS variable on tr, background on td — sticky cells need opaque bg */
432
+ :deep(tbody tr) {
433
+ --cell-bg: var(--color-card);
434
+ --corner-r: 8px;
435
+ }
436
+
437
+ :deep(tbody tr:hover) {
438
+ --cell-bg: var(--color-muted);
439
+ }
440
+
441
+ :deep(tbody td) {
442
+ background: var(--cell-bg);
443
+ }
444
+
445
+ /* Rounded corners: radial-gradient positioned at each corner,
446
+ transparent circle inside reveals cell-bg, accent fills the corner gap */
447
+ :deep(tbody tr:first-child td:first-child) {
448
+ background:
449
+ radial-gradient(circle at var(--corner-r) var(--corner-r), transparent var(--corner-r), var(--color-accent) var(--corner-r)) 0 0 / var(--corner-r) var(--corner-r) no-repeat,
450
+ var(--cell-bg);
451
+ }
452
+
453
+ :deep(tbody tr:first-child td:last-child) {
454
+ background:
455
+ radial-gradient(circle at 0 var(--corner-r), transparent var(--corner-r), var(--color-accent) var(--corner-r)) 100% 0 / var(--corner-r) var(--corner-r) no-repeat,
456
+ var(--cell-bg);
457
+ }
458
+
459
+ :deep(tbody tr:last-child td:first-child) {
460
+ background:
461
+ radial-gradient(circle at var(--corner-r) 0, transparent var(--corner-r), var(--color-accent) var(--corner-r)) 0 100% / var(--corner-r) var(--corner-r) no-repeat,
462
+ var(--cell-bg);
463
+ }
464
+
465
+ :deep(tbody tr:last-child td:last-child) {
466
+ background:
467
+ radial-gradient(circle at 0 0, transparent var(--corner-r), var(--color-accent) var(--corner-r)) 100% 100% / var(--corner-r) var(--corner-r) no-repeat,
468
+ var(--cell-bg);
469
+ }
470
+
471
+ /* Single row: combine top + bottom gradients */
472
+ :deep(tbody tr:first-child:last-child td:first-child) {
473
+ background:
474
+ radial-gradient(circle at var(--corner-r) var(--corner-r), transparent var(--corner-r), var(--color-accent) var(--corner-r)) 0 0 / var(--corner-r) var(--corner-r) no-repeat,
475
+ radial-gradient(circle at var(--corner-r) 0, transparent var(--corner-r), var(--color-accent) var(--corner-r)) 0 100% / var(--corner-r) var(--corner-r) no-repeat,
476
+ var(--cell-bg);
477
+ }
478
+
479
+ :deep(tbody tr:first-child:last-child td:last-child) {
480
+ background:
481
+ radial-gradient(circle at 0 var(--corner-r), transparent var(--corner-r), var(--color-accent) var(--corner-r)) 100% 0 / var(--corner-r) var(--corner-r) no-repeat,
482
+ radial-gradient(circle at 0 0, transparent var(--corner-r), var(--color-accent) var(--corner-r)) 100% 100% / var(--corner-r) var(--corner-r) no-repeat,
483
+ var(--cell-bg);
484
+ }
485
+
486
+ /* Frozen column shadow via ::before — ::after is reserved for header divider */
487
+ :deep([data-shadow])::before {
488
+ content: '';
489
+ position: absolute;
490
+ top: 0;
491
+ bottom: 0;
492
+ width: 8px;
493
+ pointer-events: none;
494
+ }
495
+
496
+ :deep([data-shadow="left"])::before {
497
+ right: -8px;
498
+ box-shadow: inset 4px 0 8px -4px rgba(0, 0, 0, 0.15);
499
+ }
500
+
501
+ :deep([data-shadow="right"])::before {
502
+ left: -8px;
503
+ box-shadow: inset -4px 0 8px -4px rgba(0, 0, 0, 0.15);
504
+ }
505
+ </style>
@@ -0,0 +1,42 @@
1
+ export type DataTableColumnType = 'text' | 'date' | 'unixDate' | 'currency' | 'empty'
2
+ export type DataTableColumnFixed = 'left' | 'right'
3
+ export type DataTableColumnAlign = 'left' | 'center' | 'right'
4
+ export type DataTableSelectionMode = 'single' | 'multiple'
5
+
6
+ export interface DataTableColumn {
7
+ /** Column identifier - used for field binding and slot naming */
8
+ field: string
9
+ /** Column header title */
10
+ title?: string
11
+ /** Column value type for formatting */
12
+ type?: DataTableColumnType
13
+ /** Fixed column width (e.g., '100px', '10rem') */
14
+ width?: string
15
+ /** Minimum column width (e.g., '100px', '10rem') */
16
+ minWidth?: string
17
+ /** Fixed column position: left or right */
18
+ fixed?: DataTableColumnFixed
19
+ /** Whether text can wrap. Default: false (no wrap) */
20
+ wrap?: boolean
21
+ /** Text alignment. Default: 'left' */
22
+ align?: DataTableColumnAlign
23
+ /** Whether this column is sortable */
24
+ sortable?: boolean
25
+ /** Currency code for 'currency' type (e.g., 'USD', 'JPY'). Default: 'USD' */
26
+ currency?: string
27
+ }
28
+
29
+ export interface DataTableProps<T = Record<string, any>> {
30
+ /** Table data rows */
31
+ data?: T[]
32
+ /** Column definitions */
33
+ columns?: DataTableColumn[]
34
+ /** Selection mode: single or multiple */
35
+ selectionMode?: DataTableSelectionMode
36
+ /** Current sort field */
37
+ sortBy?: string | null
38
+ /** Current sort order: 1 for asc, -1 for desc */
39
+ sortOrder?: number | null
40
+ /** Show loading overlay */
41
+ loading?: boolean
42
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "format": {
3
+ "date": "yyyy-MM-dd",
4
+ "dateTime": "yyyy-MM-dd HH:mm",
5
+ "month": "MMM yyyy",
6
+ "year": "yyyy"
7
+ },
8
+ "placeholder": "Select a date"
9
+ }
@@ -0,0 +1,70 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import DatePicker from './index.vue'
3
+
4
+ const meta = {
5
+ title: 'UI/DatePicker',
6
+ component: DatePicker,
7
+ argTypes: {
8
+ showTime: { control: 'boolean' },
9
+ disabled: { control: 'boolean' },
10
+ },
11
+ args: {
12
+ showTime: false,
13
+ disabled: false,
14
+ },
15
+ } satisfies Meta<typeof DatePicker>
16
+
17
+ export default meta
18
+ type Story = StoryObj<typeof meta>
19
+
20
+ export const Default: Story = {
21
+ render: args => ({
22
+ components: { DatePicker },
23
+ setup () {
24
+ const date = ref<Date | null>(null)
25
+ const preselected = ref<Date>(new Date(2025, 5, 15))
26
+ const formatted = ref<string | null>(null)
27
+ const month = ref<Date | null>(null)
28
+ const year = ref<Date | null>(null)
29
+ return { args, date, month, year, preselected, formatted }
30
+ },
31
+ template: `
32
+ <div class="space-y-10 max-w-xs">
33
+ <!-- Controlled -->
34
+ <section>
35
+ <h3 class="mb-4 text-lg font-medium">Controlled</h3>
36
+ <DatePicker v-model="date" v-bind="args" />
37
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ date }}</div>
38
+ </section>
39
+
40
+ <!-- Month Picker -->
41
+ <section>
42
+ <h3 class="mb-4 text-lg font-medium">Month Picker</h3>
43
+ <DatePicker v-model="month" type="month" placeholder="Pick a month" />
44
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ month }}</div>
45
+ </section>
46
+
47
+ <!-- Year Picker -->
48
+ <section>
49
+ <h3 class="mb-4 text-lg font-medium">Year Picker</h3>
50
+ <DatePicker v-model="year" type="year" placeholder="Pick a year" />
51
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ year }}</div>
52
+ </section>
53
+
54
+ <!-- Preselected -->
55
+ <section>
56
+ <h3 class="mb-4 text-lg font-medium">Preselected</h3>
57
+ <DatePicker v-model="preselected" />
58
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ preselected }}</div>
59
+ </section>
60
+
61
+ <!-- Value Format -->
62
+ <section>
63
+ <h3 class="mb-4 text-lg font-medium">Value Format (yyyy-MM-dd)</h3>
64
+ <DatePicker v-model="formatted" valueFormat="yyyy-MM-dd" placeholder="Pick a date" />
65
+ <div class="mt-2 text-sm text-muted-foreground">Value: {{ formatted }}</div>
66
+ </section>
67
+ </div>
68
+ `,
69
+ }),
70
+ }