@brumaombra/ui-vintage 0.9.1 → 0.9.2

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 (334) hide show
  1. package/module.mjs +43 -43
  2. package/package.json +175 -175
  3. package/src/components/background-grid/BackgroundGrid.vue +4 -4
  4. package/src/components/blog/AllPostsSection.vue +33 -33
  5. package/src/components/blog/BlogContentRenderer.vue +111 -111
  6. package/src/components/blog/BlogFAQSection.vue +19 -19
  7. package/src/components/blog/BlogHeaderSection.vue +80 -80
  8. package/src/components/blog/BlogInfoSection.vue +47 -47
  9. package/src/components/blog/BlogPostHeader.vue +135 -135
  10. package/src/components/blog/BlogProgressBar.vue +33 -33
  11. package/src/components/blog/BlogSectionTitle.vue +22 -22
  12. package/src/components/blog/BlogTagsSection.vue +25 -25
  13. package/src/components/blog/CategoriesList.vue +14 -14
  14. package/src/components/blog/CategoriesSection.vue +11 -11
  15. package/src/components/blog/CategoryCard.vue +25 -25
  16. package/src/components/blog/HeaderCarousel.vue +97 -97
  17. package/src/components/blog/PostCard.vue +33 -33
  18. package/src/components/blog/PostsList.vue +15 -15
  19. package/src/components/blog/SocialShareSidebar.vue +84 -84
  20. package/src/components/blog/TableOfContents.vue +307 -307
  21. package/src/components/busy-indicator/BusyIndicator.vue +7 -7
  22. package/src/components/busy-indicator/busy-indicator-state.ts +56 -56
  23. package/src/components/card-grid/CardGrid.vue +34 -34
  24. package/src/components/chip/Chip.vue +15 -15
  25. package/src/components/confirm-dialog/ConfirmDialog.vue +50 -50
  26. package/src/components/confirm-dialog/confirm-dialog-state.ts +131 -131
  27. package/src/components/content/BlogList.vue +30 -30
  28. package/src/components/content/BlogTable.vue +36 -36
  29. package/src/components/content/CodeBlock.vue +136 -136
  30. package/src/components/content/Flow.vue +60 -60
  31. package/src/components/content/ProseHr.vue +15 -15
  32. package/src/components/content/ProsePre.vue +12 -12
  33. package/src/components/content/Terminal.vue +59 -59
  34. package/src/components/cookie-consent/CookieConsent.vue +36 -36
  35. package/src/components/cookie-consent/useCookieConsent.ts +37 -37
  36. package/src/components/dashboard-shell/DashboardShell.vue +171 -171
  37. package/src/components/data-list/DataList.vue +6 -6
  38. package/src/components/data-list/DataListItem.vue +4 -4
  39. package/src/components/data-list/DataListLabel.vue +4 -4
  40. package/src/components/data-list/DataListText.vue +4 -4
  41. package/src/components/data-list/DataListValue.vue +4 -4
  42. package/src/components/empty-state-card/EmptyStateCard.vue +40 -40
  43. package/src/components/error-page/ErrorPage.vue +72 -72
  44. package/src/components/info-card/InfoCard.vue +31 -31
  45. package/src/components/landing/landing-content/LandingContent.vue +4 -4
  46. package/src/components/landing/landing-footer/LandingFooter.vue +128 -128
  47. package/src/components/landing/landing-navbar/LandingNavbar.vue +50 -50
  48. package/src/components/landing/landing-shell/LandingShell.vue +36 -36
  49. package/src/components/language-flag/LanguageFlag.vue +25 -25
  50. package/src/components/language-flag/flags/ChineseFlag.vue +8 -8
  51. package/src/components/language-flag/flags/EnglishFlag.vue +7 -7
  52. package/src/components/language-flag/flags/FrenchFlag.vue +5 -5
  53. package/src/components/language-flag/flags/GermanFlag.vue +5 -5
  54. package/src/components/language-flag/flags/ItalianFlag.vue +7 -7
  55. package/src/components/language-flag/flags/JapaneseFlag.vue +4 -4
  56. package/src/components/language-flag/flags/PortugueseFlag.vue +57 -57
  57. package/src/components/language-flag/flags/RussianFlag.vue +5 -5
  58. package/src/components/language-flag/flags/SpanishFlag.vue +4 -4
  59. package/src/components/language-selector/LanguageSelector.vue +76 -76
  60. package/src/components/load-more-button/LoadMoreButton.vue +17 -17
  61. package/src/components/loading-state-card/LoadingStateCard.vue +28 -28
  62. package/src/components/message-dialog/MessageDialog.vue +59 -59
  63. package/src/components/message-dialog/message-dialog-state.ts +105 -105
  64. package/src/components/message-toast/MessageToast.vue +149 -149
  65. package/src/components/message-toast/message-toast-state.ts +146 -146
  66. package/src/components/page-header/PageHeader.vue +34 -34
  67. package/src/components/progress-component/ProgressComponent.vue +33 -33
  68. package/src/components/single-value-card/SingleValueCard.vue +57 -57
  69. package/src/components/slider-form-component/SliderFormComponent.vue +36 -36
  70. package/src/components/stat-strip/StatStrip.vue +22 -22
  71. package/src/components/switch-form-component/SwitchFormComponent.vue +20 -20
  72. package/src/components/text-link/TextLink.vue +14 -14
  73. package/src/components/theme-selector/ThemeSelector.vue +61 -61
  74. package/src/components/theme-selector/theme-transition.ts +63 -63
  75. package/src/components/ui/accordion/Accordion.vue +38 -38
  76. package/src/components/ui/alert/Alert.vue +5 -5
  77. package/src/components/ui/alert/AlertDescription.vue +4 -4
  78. package/src/components/ui/alert/AlertTitle.vue +4 -4
  79. package/src/components/ui/alert/index.ts +2 -2
  80. package/src/components/ui/alert-dialog/AlertDialog.vue +3 -3
  81. package/src/components/ui/alert-dialog/AlertDialogAction.vue +3 -3
  82. package/src/components/ui/alert-dialog/AlertDialogCancel.vue +3 -3
  83. package/src/components/ui/alert-dialog/AlertDialogContent.vue +7 -7
  84. package/src/components/ui/alert-dialog/AlertDialogDescription.vue +3 -3
  85. package/src/components/ui/alert-dialog/AlertDialogFooter.vue +4 -4
  86. package/src/components/ui/alert-dialog/AlertDialogHeader.vue +4 -4
  87. package/src/components/ui/alert-dialog/AlertDialogTitle.vue +3 -3
  88. package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +3 -3
  89. package/src/components/ui/animated-number/AnimatedNumber.vue +49 -48
  90. package/src/components/ui/avatar/Avatar.vue +28 -28
  91. package/src/components/ui/avatar/AvatarFallback.vue +6 -6
  92. package/src/components/ui/avatar/AvatarGroup.vue +40 -40
  93. package/src/components/ui/avatar/AvatarImage.vue +3 -3
  94. package/src/components/ui/avatar/index.ts +17 -17
  95. package/src/components/ui/badge/Badge.vue +20 -20
  96. package/src/components/ui/breadcrumb/Breadcrumb.vue +4 -4
  97. package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +9 -9
  98. package/src/components/ui/breadcrumb/BreadcrumbItem.vue +4 -4
  99. package/src/components/ui/breadcrumb/BreadcrumbLink.vue +4 -4
  100. package/src/components/ui/breadcrumb/BreadcrumbList.vue +4 -4
  101. package/src/components/ui/breadcrumb/BreadcrumbPage.vue +4 -4
  102. package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +4 -4
  103. package/src/components/ui/busy/Busy.vue +33 -33
  104. package/src/components/ui/button/Button.vue +23 -23
  105. package/src/components/ui/button/index.ts +56 -56
  106. package/src/components/ui/calendar/Calendar.vue +138 -138
  107. package/src/components/ui/calendar/CalendarCell.vue +7 -7
  108. package/src/components/ui/calendar/CalendarCellTrigger.vue +18 -18
  109. package/src/components/ui/calendar/CalendarGrid.vue +3 -3
  110. package/src/components/ui/calendar/CalendarGridBody.vue +3 -3
  111. package/src/components/ui/calendar/CalendarGridHead.vue +3 -3
  112. package/src/components/ui/calendar/CalendarGridRow.vue +3 -3
  113. package/src/components/ui/calendar/CalendarHeadCell.vue +7 -7
  114. package/src/components/ui/calendar/CalendarHeader.vue +7 -7
  115. package/src/components/ui/calendar/CalendarHeading.vue +6 -6
  116. package/src/components/ui/calendar/CalendarNextButton.vue +15 -15
  117. package/src/components/ui/calendar/CalendarPrevButton.vue +15 -15
  118. package/src/components/ui/calendar/index.ts +4 -4
  119. package/src/components/ui/card/Card.vue +20 -20
  120. package/src/components/ui/card/CardAction.vue +8 -8
  121. package/src/components/ui/card/CardContent.vue +4 -4
  122. package/src/components/ui/card/CardDescription.vue +12 -12
  123. package/src/components/ui/card/CardFooter.vue +4 -4
  124. package/src/components/ui/card/CardHeader.vue +8 -8
  125. package/src/components/ui/card/CardText.vue +8 -8
  126. package/src/components/ui/card/CardTitle.vue +8 -8
  127. package/src/components/ui/checkbox/Checkbox.vue +27 -27
  128. package/src/components/ui/collapsible/Collapsible.vue +3 -3
  129. package/src/components/ui/collapsible/CollapsibleContent.vue +3 -3
  130. package/src/components/ui/collapsible/CollapsibleTrigger.vue +3 -3
  131. package/src/components/ui/combobox/Combobox.vue +4 -4
  132. package/src/components/ui/combobox/ComboboxAnchor.vue +16 -16
  133. package/src/components/ui/combobox/ComboboxEmpty.vue +3 -3
  134. package/src/components/ui/combobox/ComboboxGroup.vue +9 -9
  135. package/src/components/ui/combobox/ComboboxInput.vue +6 -6
  136. package/src/components/ui/combobox/ComboboxItem.vue +17 -17
  137. package/src/components/ui/combobox/ComboboxList.vue +19 -19
  138. package/src/components/ui/combobox/ComboboxSelect.vue +77 -77
  139. package/src/components/ui/combobox/ComboboxSeparator.vue +1 -1
  140. package/src/components/ui/combobox/ComboboxTrigger.vue +10 -10
  141. package/src/components/ui/combobox/types.ts +5 -5
  142. package/src/components/ui/command/Command.vue +48 -48
  143. package/src/components/ui/command/CommandDialog.vue +14 -14
  144. package/src/components/ui/command/CommandEmpty.vue +4 -4
  145. package/src/components/ui/command/CommandGroup.vue +23 -23
  146. package/src/components/ui/command/CommandInput.vue +9 -9
  147. package/src/components/ui/command/CommandItem.vue +40 -40
  148. package/src/components/ui/command/CommandList.vue +9 -9
  149. package/src/components/ui/command/CommandSeparator.vue +3 -3
  150. package/src/components/ui/command/CommandShortcut.vue +8 -8
  151. package/src/components/ui/command/index.ts +11 -11
  152. package/src/components/ui/data-table/DataTable.vue +145 -145
  153. package/src/components/ui/data-table/index.ts +11 -11
  154. package/src/components/ui/date-picker/DatePicker.vue +31 -31
  155. package/src/components/ui/date-time-picker/DateTimePicker.vue +97 -97
  156. package/src/components/ui/dialog/Dialog.vue +3 -3
  157. package/src/components/ui/dialog/DialogClose.vue +3 -3
  158. package/src/components/ui/dialog/DialogContent.vue +21 -21
  159. package/src/components/ui/dialog/DialogDescription.vue +7 -7
  160. package/src/components/ui/dialog/DialogFooter.vue +8 -8
  161. package/src/components/ui/dialog/DialogHeader.vue +4 -4
  162. package/src/components/ui/dialog/DialogOverlay.vue +7 -7
  163. package/src/components/ui/dialog/DialogScrollContent.vue +32 -32
  164. package/src/components/ui/dialog/DialogTitle.vue +3 -3
  165. package/src/components/ui/dialog/DialogTrigger.vue +3 -3
  166. package/src/components/ui/dropdown-menu/DropdownMenu.vue +3 -3
  167. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +11 -11
  168. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +15 -15
  169. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +3 -3
  170. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +12 -12
  171. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +9 -9
  172. package/src/components/ui/dropdown-menu/DropdownMenuPortal.vue +3 -3
  173. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +3 -3
  174. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +11 -11
  175. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +1 -1
  176. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +4 -4
  177. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +3 -3
  178. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +15 -15
  179. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +15 -15
  180. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +3 -3
  181. package/src/components/ui/dropdown-menu/classes.ts +16 -16
  182. package/src/components/ui/field/Field.vue +5 -5
  183. package/src/components/ui/field/FieldContent.vue +8 -8
  184. package/src/components/ui/field/FieldDescription.vue +10 -10
  185. package/src/components/ui/field/FieldError.vue +39 -39
  186. package/src/components/ui/field/FieldGroup.vue +8 -8
  187. package/src/components/ui/field/FieldLabel.vue +10 -10
  188. package/src/components/ui/field/FieldLegend.vue +11 -11
  189. package/src/components/ui/field/FieldSeparator.vue +11 -11
  190. package/src/components/ui/field/FieldSet.vue +9 -9
  191. package/src/components/ui/field/FieldTitle.vue +8 -8
  192. package/src/components/ui/field/field-context.ts +36 -36
  193. package/src/components/ui/field/index.ts +22 -22
  194. package/src/components/ui/file-dropzone/FileDropzone.vue +144 -144
  195. package/src/components/ui/file-dropzone/index.ts +19 -19
  196. package/src/components/ui/hover-card/HoverCard.vue +5 -5
  197. package/src/components/ui/hover-card/HoverCardContent.vue +13 -13
  198. package/src/components/ui/hover-card/HoverCardTrigger.vue +3 -3
  199. package/src/components/ui/input/Input.vue +13 -13
  200. package/src/components/ui/kbd/Kbd.vue +10 -10
  201. package/src/components/ui/kbd/KbdGroup.vue +49 -49
  202. package/src/components/ui/label/Label.vue +7 -7
  203. package/src/components/ui/native-select/NativeSelect.vue +16 -16
  204. package/src/components/ui/native-select/NativeSelectOptGroup.vue +3 -3
  205. package/src/components/ui/native-select/NativeSelectOption.vue +3 -3
  206. package/src/components/ui/number-field/NumberField.vue +88 -88
  207. package/src/components/ui/pagination/Pagination.vue +4 -4
  208. package/src/components/ui/pagination/PaginationContent.vue +4 -4
  209. package/src/components/ui/pagination/PaginationEllipsis.vue +9 -9
  210. package/src/components/ui/pagination/PaginationFirst.vue +8 -8
  211. package/src/components/ui/pagination/PaginationItem.vue +14 -14
  212. package/src/components/ui/pagination/PaginationLast.vue +8 -8
  213. package/src/components/ui/pagination/PaginationNext.vue +8 -8
  214. package/src/components/ui/pagination/PaginationPrevious.vue +8 -8
  215. package/src/components/ui/pagination/SimplePagination.vue +25 -25
  216. package/src/components/ui/pin-input/PinInput.vue +20 -20
  217. package/src/components/ui/pin-input/PinInputInput.vue +17 -17
  218. package/src/components/ui/pin-input/context.ts +1 -1
  219. package/src/components/ui/popover/Popover.vue +3 -3
  220. package/src/components/ui/popover/PopoverAnchor.vue +3 -3
  221. package/src/components/ui/popover/PopoverContent.vue +12 -12
  222. package/src/components/ui/popover/PopoverTrigger.vue +3 -3
  223. package/src/components/ui/progress/Progress.vue +16 -16
  224. package/src/components/ui/radio-group/RadioGroup.vue +7 -7
  225. package/src/components/ui/radio-group/RadioGroupCard.vue +39 -39
  226. package/src/components/ui/radio-group/RadioGroupItem.vue +20 -20
  227. package/src/components/ui/scroll-area/ScrollArea.vue +14 -14
  228. package/src/components/ui/scroll-area/ScrollBar.vue +12 -12
  229. package/src/components/ui/select/Select.vue +3 -3
  230. package/src/components/ui/select/SelectContent.vue +25 -25
  231. package/src/components/ui/select/SelectGroup.vue +3 -3
  232. package/src/components/ui/select/SelectItem.vue +24 -24
  233. package/src/components/ui/select/SelectItemContent.vue +32 -32
  234. package/src/components/ui/select/SelectItemText.vue +3 -3
  235. package/src/components/ui/select/SelectLabel.vue +3 -3
  236. package/src/components/ui/select/SelectScrollDownButton.vue +9 -9
  237. package/src/components/ui/select/SelectScrollUpButton.vue +9 -9
  238. package/src/components/ui/select/SelectSeparator.vue +2 -2
  239. package/src/components/ui/select/SelectTrigger.vue +14 -14
  240. package/src/components/ui/select/SelectValue.vue +3 -3
  241. package/src/components/ui/select/SelectValueContent.vue +39 -39
  242. package/src/components/ui/separator/Separator.vue +7 -7
  243. package/src/components/ui/sheet/Sheet.vue +3 -3
  244. package/src/components/ui/sheet/SheetClose.vue +3 -3
  245. package/src/components/ui/sheet/SheetContent.vue +22 -22
  246. package/src/components/ui/sheet/SheetDescription.vue +3 -3
  247. package/src/components/ui/sheet/SheetFooter.vue +3 -3
  248. package/src/components/ui/sheet/SheetHeader.vue +3 -3
  249. package/src/components/ui/sheet/SheetOverlay.vue +7 -7
  250. package/src/components/ui/sheet/SheetTitle.vue +3 -3
  251. package/src/components/ui/sheet/SheetTrigger.vue +3 -3
  252. package/src/components/ui/sidebar/Sidebar.vue +57 -57
  253. package/src/components/ui/sidebar/SidebarContent.vue +8 -8
  254. package/src/components/ui/sidebar/SidebarFooter.vue +8 -8
  255. package/src/components/ui/sidebar/SidebarGroup.vue +8 -8
  256. package/src/components/ui/sidebar/SidebarGroupAction.vue +9 -9
  257. package/src/components/ui/sidebar/SidebarGroupContent.vue +4 -4
  258. package/src/components/ui/sidebar/SidebarGroupLabel.vue +8 -8
  259. package/src/components/ui/sidebar/SidebarHeader.vue +8 -8
  260. package/src/components/ui/sidebar/SidebarInput.vue +8 -8
  261. package/src/components/ui/sidebar/SidebarInset.vue +9 -9
  262. package/src/components/ui/sidebar/SidebarMenu.vue +4 -4
  263. package/src/components/ui/sidebar/SidebarMenuAction.vue +18 -18
  264. package/src/components/ui/sidebar/SidebarMenuBadge.vue +14 -14
  265. package/src/components/ui/sidebar/SidebarMenuButton.vue +21 -21
  266. package/src/components/ui/sidebar/SidebarMenuButtonChild.vue +10 -10
  267. package/src/components/ui/sidebar/SidebarMenuItem.vue +4 -4
  268. package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +10 -10
  269. package/src/components/ui/sidebar/SidebarMenuSub.vue +9 -9
  270. package/src/components/ui/sidebar/SidebarMenuSubButton.vue +17 -17
  271. package/src/components/ui/sidebar/SidebarMenuSubItem.vue +4 -4
  272. package/src/components/ui/sidebar/SidebarProvider.vue +46 -46
  273. package/src/components/ui/sidebar/SidebarRail.vue +13 -13
  274. package/src/components/ui/sidebar/SidebarSeparator.vue +4 -4
  275. package/src/components/ui/sidebar/SidebarTrigger.vue +5 -5
  276. package/src/components/ui/sidebar/index.ts +29 -29
  277. package/src/components/ui/sidebar/utils.ts +7 -7
  278. package/src/components/ui/skeleton/Skeleton.vue +6 -6
  279. package/src/components/ui/slider/Slider.vue +14 -14
  280. package/src/components/ui/spinner/Spinner.vue +21 -21
  281. package/src/components/ui/stepper/SimpleStepper.vue +26 -26
  282. package/src/components/ui/stepper/Stepper.vue +6 -6
  283. package/src/components/ui/stepper/StepperDescription.vue +5 -5
  284. package/src/components/ui/stepper/StepperIndicator.vue +17 -17
  285. package/src/components/ui/stepper/StepperItem.vue +4 -4
  286. package/src/components/ui/stepper/StepperSeparator.vue +7 -7
  287. package/src/components/ui/stepper/StepperTitle.vue +5 -5
  288. package/src/components/ui/stepper/StepperTrigger.vue +4 -4
  289. package/src/components/ui/stepper/index.ts +3 -3
  290. package/src/components/ui/switch/Switch.vue +15 -15
  291. package/src/components/ui/table/Table.vue +6 -6
  292. package/src/components/ui/table/TableBody.vue +4 -4
  293. package/src/components/ui/table/TableCaption.vue +4 -4
  294. package/src/components/ui/table/TableCell.vue +8 -8
  295. package/src/components/ui/table/TableEmpty.vue +14 -14
  296. package/src/components/ui/table/TableFooter.vue +8 -8
  297. package/src/components/ui/table/TableHead.vue +8 -8
  298. package/src/components/ui/table/TableHeader.vue +4 -4
  299. package/src/components/ui/table/TableRow.vue +8 -8
  300. package/src/components/ui/tabs/Tabs.vue +4 -4
  301. package/src/components/ui/tabs/TabsContent.vue +4 -4
  302. package/src/components/ui/tabs/TabsList.vue +15 -15
  303. package/src/components/ui/tabs/TabsTrigger.vue +10 -10
  304. package/src/components/ui/tags-input/TagsInput.vue +17 -17
  305. package/src/components/ui/tags-input/TagsInputInput.vue +6 -6
  306. package/src/components/ui/tags-input/TagsInputItem.vue +15 -15
  307. package/src/components/ui/tags-input/TagsInputItemDelete.vue +12 -12
  308. package/src/components/ui/tags-input/TagsInputItemText.vue +4 -4
  309. package/src/components/ui/textarea/Textarea.vue +12 -12
  310. package/src/components/ui/time-picker/TimePicker.vue +25 -25
  311. package/src/components/ui/toggle-group/Toggle.vue +10 -10
  312. package/src/components/ui/toggle-group/ToggleGroup.vue +38 -38
  313. package/src/components/ui/toggle-group/ToggleGroupItem.vue +9 -9
  314. package/src/components/ui/toggle-group/index.ts +46 -46
  315. package/src/components/ui/tooltip/Tooltip.vue +3 -3
  316. package/src/components/ui/tooltip/TooltipContent.vue +13 -13
  317. package/src/components/ui/tooltip/TooltipProvider.vue +4 -4
  318. package/src/components/ui/tooltip/TooltipTrigger.vue +3 -3
  319. package/src/i18n/de.json +185 -185
  320. package/src/i18n/en.json +185 -185
  321. package/src/i18n/es.json +185 -185
  322. package/src/i18n/fr.json +185 -185
  323. package/src/i18n/it.json +185 -185
  324. package/src/i18n/ja.json +185 -185
  325. package/src/i18n/pt.json +185 -185
  326. package/src/i18n/ru.json +185 -185
  327. package/src/i18n/zh.json +185 -185
  328. package/src/lib/color-tokens.ts +24 -24
  329. package/src/lib/i18n.ts +65 -65
  330. package/src/lib/utils.ts +33 -33
  331. package/src/nuxt-components.d.ts +2 -2
  332. package/src/runtime/ui-vintage-i18n-plugin.ts +49 -49
  333. package/src/shims-vue.d.ts +3 -3
  334. package/src/styles.css +377 -377
@@ -5,26 +5,26 @@ export type DialogMessageType = 'error' | 'success' | 'info' | 'warning';
5
5
  export type { HugeiconsIconDefinition };
6
6
 
7
7
  export interface ShowMessageDialogOptions {
8
- type?: DialogMessageType;
9
- title?: string;
10
- message: string;
11
- closeText?: string;
12
- icon?: HugeiconsIconDefinition | null;
13
- closeButtonIcon?: HugeiconsIconDefinition | null;
8
+ type?: DialogMessageType;
9
+ title?: string;
10
+ message: string;
11
+ closeText?: string;
12
+ icon?: HugeiconsIconDefinition | null;
13
+ closeButtonIcon?: HugeiconsIconDefinition | null;
14
14
  }
15
15
 
16
16
  interface MessageDialogRequest {
17
- id: number;
18
- options: Omit<ShowMessageDialogOptions, 'icon' | 'closeButtonIcon'> & {
19
- icon: HugeiconsIconDefinition | null;
20
- closeButtonIcon: HugeiconsIconDefinition | null;
21
- };
22
- resolve: () => void;
17
+ id: number;
18
+ options: Omit<ShowMessageDialogOptions, 'icon' | 'closeButtonIcon'> & {
19
+ icon: HugeiconsIconDefinition | null;
20
+ closeButtonIcon: HugeiconsIconDefinition | null;
21
+ };
22
+ resolve: () => void;
23
23
  }
24
24
 
25
25
  interface MessageDialogState {
26
- current: MessageDialogRequest | null;
27
- isOpen: boolean;
26
+ current: MessageDialogRequest | null;
27
+ isOpen: boolean;
28
28
  }
29
29
 
30
30
  const messageDialogQueue: MessageDialogRequest[] = [];
@@ -37,8 +37,8 @@ const MESSAGE_DIALOG_ROOT_ID = 'ui-vintage-message-dialog-root';
37
37
 
38
38
  // Shared message dialog state
39
39
  export const messageDialogState: MessageDialogState = reactive({
40
- current: null,
41
- isOpen: false
40
+ current: null,
41
+ isOpen: false
42
42
  });
43
43
 
44
44
  // Keep icon definitions non-reactive
@@ -46,121 +46,121 @@ const markIcon = (icon: HugeiconsIconDefinition | null | undefined) => icon ? ma
46
46
 
47
47
  // Mount the dialog once on demand
48
48
  const ensureMessageDialogMounted = () => {
49
- // Skip mounting during SSR
50
- if (typeof document === 'undefined') {
51
- return Promise.resolve();
52
- }
53
-
54
- // Reuse the existing mount root
55
- const existingRoot = document.getElementById(MESSAGE_DIALOG_ROOT_ID);
56
- if (existingRoot) {
57
- return Promise.resolve();
58
- }
59
-
60
- // Reuse the in-flight mount
61
- if (messageDialogMountPromise) {
62
- return messageDialogMountPromise;
63
- }
64
-
65
- // Start the lazy mount
66
- messageDialogMountPromise = (async () => {
67
- // Load the component only when needed
68
- const { default: MessageDialog } = await import('./MessageDialog.vue');
69
-
70
- // Guard against a concurrent mount
71
- if (document.getElementById(MESSAGE_DIALOG_ROOT_ID)) {
72
- return;
73
- }
74
-
75
- // Create the host element and render the component
76
- const container = document.createElement('div');
77
- container.id = MESSAGE_DIALOG_ROOT_ID;
78
- document.body.appendChild(container);
79
- render(h(MessageDialog), container);
80
- })().finally(() => {
81
- messageDialogMountPromise = null;
82
- });
83
-
84
- // Let callers await the mount
85
- return messageDialogMountPromise;
49
+ // Skip mounting during SSR
50
+ if (typeof document === 'undefined') {
51
+ return Promise.resolve();
52
+ }
53
+
54
+ // Reuse the existing mount root
55
+ const existingRoot = document.getElementById(MESSAGE_DIALOG_ROOT_ID);
56
+ if (existingRoot) {
57
+ return Promise.resolve();
58
+ }
59
+
60
+ // Reuse the in-flight mount
61
+ if (messageDialogMountPromise) {
62
+ return messageDialogMountPromise;
63
+ }
64
+
65
+ // Start the lazy mount
66
+ messageDialogMountPromise = (async () => {
67
+ // Load the component only when needed
68
+ const { default: MessageDialog } = await import('./MessageDialog.vue');
69
+
70
+ // Guard against a concurrent mount
71
+ if (document.getElementById(MESSAGE_DIALOG_ROOT_ID)) {
72
+ return;
73
+ }
74
+
75
+ // Create the host element and render the component
76
+ const container = document.createElement('div');
77
+ container.id = MESSAGE_DIALOG_ROOT_ID;
78
+ document.body.appendChild(container);
79
+ render(h(MessageDialog), container);
80
+ })().finally(() => {
81
+ messageDialogMountPromise = null;
82
+ });
83
+
84
+ // Let callers await the mount
85
+ return messageDialogMountPromise;
86
86
  };
87
87
 
88
88
  // Show the next queued dialog
89
89
  const openNextMessageDialog = () => {
90
- const nextDialog = messageDialogQueue.shift() ?? null;
91
- messageDialogState.current = nextDialog;
92
- messageDialogState.isOpen = Boolean(nextDialog);
90
+ const nextDialog = messageDialogQueue.shift() ?? null;
91
+ messageDialogState.current = nextDialog;
92
+ messageDialogState.isOpen = Boolean(nextDialog);
93
93
  };
94
94
 
95
95
  // Queue a new dialog request
96
96
  const enqueueMessageDialog = (request: MessageDialogRequest) => {
97
- messageDialogQueue.push(request);
98
- if (!messageDialogState.current) {
99
- openNextMessageDialog();
100
- }
97
+ messageDialogQueue.push(request);
98
+ if (!messageDialogState.current) {
99
+ openNextMessageDialog();
100
+ }
101
101
  };
102
102
 
103
103
  // Clear the active dialog and continue the queue
104
104
  const clearCurrentMessageDialog = () => {
105
- messageDialogState.isOpen = false;
106
- messageDialogState.current = null;
107
- openNextMessageDialog();
105
+ messageDialogState.isOpen = false;
106
+ messageDialogState.current = null;
107
+ openNextMessageDialog();
108
108
  };
109
109
 
110
110
  // Close the current dialog after the leave transition
111
111
  const scheduleCloseCurrentMessageDialog = () => {
112
- // Guard against missing or already closing dialogs
113
- if (!messageDialogState.current || !messageDialogState.isOpen) {
114
- return;
115
- }
116
-
117
- // Start the close transition
118
- messageDialogState.isOpen = false;
119
- if (closeTimer) {
120
- clearTimeout(closeTimer);
121
- }
122
-
123
- // Schedule the dialog to be cleared after the transition
124
- closeTimer = setTimeout(() => {
125
- closeTimer = null;
126
- clearCurrentMessageDialog();
127
- }, DIALOG_CLOSE_DURATION_MS);
112
+ // Guard against missing or already closing dialogs
113
+ if (!messageDialogState.current || !messageDialogState.isOpen) {
114
+ return;
115
+ }
116
+
117
+ // Start the close transition
118
+ messageDialogState.isOpen = false;
119
+ if (closeTimer) {
120
+ clearTimeout(closeTimer);
121
+ }
122
+
123
+ // Schedule the dialog to be cleared after the transition
124
+ closeTimer = setTimeout(() => {
125
+ closeTimer = null;
126
+ clearCurrentMessageDialog();
127
+ }, DIALOG_CLOSE_DURATION_MS);
128
128
  };
129
129
 
130
130
  // Resolve the dialog as closed
131
131
  export const closeMessageDialog = () => {
132
- const current = messageDialogState.current;
133
- if (!current || !messageDialogState.isOpen) return;
134
- current.resolve();
135
- scheduleCloseCurrentMessageDialog();
132
+ const current = messageDialogState.current;
133
+ if (!current || !messageDialogState.isOpen) return;
134
+ current.resolve();
135
+ scheduleCloseCurrentMessageDialog();
136
136
  };
137
137
 
138
138
  // Resolve the active message dialog
139
139
  export const resolveActiveMessageDialog = () => {
140
- const current = messageDialogState.current;
141
- if (!current || !messageDialogState.isOpen) return;
142
- current.resolve();
143
- scheduleCloseCurrentMessageDialog();
140
+ const current = messageDialogState.current;
141
+ if (!current || !messageDialogState.isOpen) return;
142
+ current.resolve();
143
+ scheduleCloseCurrentMessageDialog();
144
144
  };
145
145
 
146
146
  // Queue and show a message dialog
147
147
  export const showMessageDialog = (options: ShowMessageDialogOptions) => {
148
- // Ensure the renderer exists before queuing work
149
- void ensureMessageDialogMounted();
150
-
151
- // Return a promise that resolves when the dialog is closed
152
- return new Promise<void>((resolve) => {
153
- enqueueMessageDialog({
154
- id: nextMessageDialogId += 1,
155
- options: {
156
- type: options.type ?? 'info',
157
- title: options.title ?? '',
158
- message: options.message,
159
- closeText: options.closeText ?? '',
160
- icon: markIcon(options.icon),
161
- closeButtonIcon: markIcon(options.closeButtonIcon)
162
- },
163
- resolve
164
- });
165
- });
148
+ // Ensure the renderer exists before queuing work
149
+ void ensureMessageDialogMounted();
150
+
151
+ // Return a promise that resolves when the dialog is closed
152
+ return new Promise<void>((resolve) => {
153
+ enqueueMessageDialog({
154
+ id: nextMessageDialogId += 1,
155
+ options: {
156
+ type: options.type ?? 'info',
157
+ title: options.title ?? '',
158
+ message: options.message,
159
+ closeText: options.closeText ?? '',
160
+ icon: markIcon(options.icon),
161
+ closeButtonIcon: markIcon(options.closeButtonIcon)
162
+ },
163
+ resolve
164
+ });
165
+ });
166
166
  };
@@ -26,25 +26,25 @@ const regionAriaLabel = computed(() => getUiVintageRuntimeMessage('uiVintage.toa
26
26
 
27
27
  // Resolve the icon for each toast type
28
28
  const getToastIcon = (toast: MessageToastItem) => {
29
- if (toast.icon) return toast.icon;
30
- if (toast.type === 'success') return CheckmarkCircle02Icon;
31
- return toast.type === 'info' ? InformationCircleIcon : AlertCircleIcon;
29
+ if (toast.icon) return toast.icon;
30
+ if (toast.type === 'success') return CheckmarkCircle02Icon;
31
+ return toast.type === 'info' ? InformationCircleIcon : AlertCircleIcon;
32
32
  };
33
33
 
34
34
  // Resolve the tinted icon tile classes for each toast type
35
35
  const toneClasses: Record<MessageToastType, string> = {
36
- success: 'border-success/25 bg-success/10 text-success',
37
- info: 'border-info/25 bg-info/10 text-info',
38
- warning: 'border-warning/25 bg-warning/10 text-warning',
39
- error: 'border-destructive/25 bg-destructive/10 text-destructive'
36
+ success: 'border-success/25 bg-success/10 text-success',
37
+ info: 'border-info/25 bg-info/10 text-info',
38
+ warning: 'border-warning/25 bg-warning/10 text-warning',
39
+ error: 'border-destructive/25 bg-destructive/10 text-destructive'
40
40
  };
41
41
 
42
42
  // Progress bar color for each toast type
43
43
  const progressClasses: Record<MessageToastType, string> = {
44
- success: 'bg-success',
45
- info: 'bg-info',
46
- warning: 'bg-warning',
47
- error: 'bg-destructive'
44
+ success: 'bg-success',
45
+ info: 'bg-info',
46
+ warning: 'bg-warning',
47
+ error: 'bg-destructive'
48
48
  };
49
49
 
50
50
  const toasts = computed(() => messageToastState.toasts);
@@ -52,41 +52,41 @@ const frontHeight = computed(() => (toasts.value[0] && heights.get(toasts.value[
52
52
 
53
53
  // Height of the stack container so the hover area always matches what is visible
54
54
  const containerHeight = computed(() => {
55
- const visible = toasts.value.slice(0, VISIBLE_TOASTS);
56
- if (!visible.length) return 0;
57
- if (expanded.value) {
58
- return visible.reduce((total, toast) => total + (heights.get(toast.id) || 0), 0) + STACK_GAP_PX * (visible.length - 1);
59
- }
60
- return frontHeight.value + STACK_OFFSET_PX * (visible.length - 1);
55
+ const visible = toasts.value.slice(0, VISIBLE_TOASTS);
56
+ if (!visible.length) return 0;
57
+ if (expanded.value) {
58
+ return visible.reduce((total, toast) => total + (heights.get(toast.id) || 0), 0) + STACK_GAP_PX * (visible.length - 1);
59
+ }
60
+ return frontHeight.value + STACK_OFFSET_PX * (visible.length - 1);
61
61
  });
62
62
 
63
63
  // Compute the stacked position of a toast from its index (0 = newest)
64
64
  const getToastStyle = (toast: MessageToastItem, index: number) => {
65
- const isSwiping = swipe.id === toast.id;
66
- let offset = 0;
67
- let scale = 1;
68
-
69
- // Expanded: toasts sit on top of each other with a gap
70
- if (expanded.value) {
71
- for (const previous of toasts.value.slice(0, index)) {
72
- offset += (heights.get(previous.id) || 0) + STACK_GAP_PX;
73
- }
74
- } else {
75
- // Collapsed: toasts peek out behind the front one
76
- offset = index * STACK_OFFSET_PX;
77
- scale = 1 - index * 0.05;
78
- }
79
-
80
- return {
81
- '--uv-toast-leave-x': `${(leaveDirection.get(toast.id) ?? 1) * 110}%`,
82
- zIndex: String(100 - index),
83
- translate: `${isSwiping ? swipe.deltaX : 0}px ${-offset}px`,
84
- scale: String(scale),
85
- opacity: index >= VISIBLE_TOASTS ? '0' : isSwiping ? String(1 - Math.min(Math.abs(swipe.deltaX) / 240, 0.6)) : '1',
86
- height: !expanded.value && index > 0 && frontHeight.value ? `${frontHeight.value}px` : undefined,
87
- pointerEvents: index >= VISIBLE_TOASTS ? 'none' as const : undefined,
88
- transition: isSwiping ? 'none' : undefined
89
- };
65
+ const isSwiping = swipe.id === toast.id;
66
+ let offset = 0;
67
+ let scale = 1;
68
+
69
+ // Expanded: toasts sit on top of each other with a gap
70
+ if (expanded.value) {
71
+ for (const previous of toasts.value.slice(0, index)) {
72
+ offset += (heights.get(previous.id) || 0) + STACK_GAP_PX;
73
+ }
74
+ } else {
75
+ // Collapsed: toasts peek out behind the front one
76
+ offset = index * STACK_OFFSET_PX;
77
+ scale = 1 - index * 0.05;
78
+ }
79
+
80
+ return {
81
+ '--uv-toast-leave-x': `${(leaveDirection.get(toast.id) ?? 1) * 110}%`,
82
+ zIndex: String(100 - index),
83
+ translate: `${isSwiping ? swipe.deltaX : 0}px ${-offset}px`,
84
+ scale: String(scale),
85
+ opacity: index >= VISIBLE_TOASTS ? '0' : isSwiping ? String(1 - Math.min(Math.abs(swipe.deltaX) / 240, 0.6)) : '1',
86
+ height: !expanded.value && index > 0 && frontHeight.value ? `${frontHeight.value}px` : undefined,
87
+ pointerEvents: index >= VISIBLE_TOASTS ? 'none' as const : undefined,
88
+ transition: isSwiping ? 'none' : undefined
89
+ };
90
90
  };
91
91
 
92
92
  // Toast content elements currently watched by the observer, by toast id
@@ -94,172 +94,172 @@ const observedElements = new Map<number, HTMLElement>();
94
94
 
95
95
  // Measure toast content heights so the stack can lay itself out
96
96
  const resizeObserver = typeof ResizeObserver !== 'undefined'
97
- ? new ResizeObserver((entries) => {
98
- for (const entry of entries) {
99
- const id = Number((entry.target as HTMLElement).dataset.toastId);
97
+ ? new ResizeObserver((entries) => {
98
+ for (const entry of entries) {
99
+ const id = Number((entry.target as HTMLElement).dataset.toastId);
100
100
 
101
- // Skip late notifications for toasts that already left
102
- if (observedElements.get(id) !== entry.target) continue;
103
- heights.set(id, (entry.target as HTMLElement).offsetHeight);
104
- }
105
- })
106
- : null;
101
+ // Skip late notifications for toasts that already left
102
+ if (observedElements.get(id) !== entry.target) continue;
103
+ heights.set(id, (entry.target as HTMLElement).offsetHeight);
104
+ }
105
+ })
106
+ : null;
107
107
 
108
108
  // Register toast content elements with the observer
109
109
  const observeToast = (element: unknown) => {
110
- if (element instanceof HTMLElement && resizeObserver) {
111
- const id = Number(element.dataset.toastId);
112
- if (observedElements.get(id) === element) return;
113
- heights.set(id, element.offsetHeight);
114
- observedElements.set(id, element);
115
- resizeObserver.observe(element);
116
- }
110
+ if (element instanceof HTMLElement && resizeObserver) {
111
+ const id = Number(element.dataset.toastId);
112
+ if (observedElements.get(id) === element) return;
113
+ heights.set(id, element.offsetHeight);
114
+ observedElements.set(id, element);
115
+ resizeObserver.observe(element);
116
+ }
117
117
  };
118
118
 
119
119
  // Expand the stack and pause timers while the user interacts with it
120
120
  const handleEnter = () => {
121
- expanded.value = true;
122
- pauseMessageToasts();
121
+ expanded.value = true;
122
+ pauseMessageToasts();
123
123
  };
124
124
 
125
125
  // Collapse the stack and resume timers
126
126
  const handleLeave = () => {
127
- expanded.value = false;
128
- resumeMessageToasts();
127
+ expanded.value = false;
128
+ resumeMessageToasts();
129
129
  };
130
130
 
131
131
  // Begin a horizontal swipe gesture
132
132
  const handlePointerDown = (event: PointerEvent, toast: MessageToastItem) => {
133
- if (!toast.dismissible || event.button !== 0 || (event.target as HTMLElement).closest('button')) return;
134
- swipe.id = toast.id;
135
- swipe.startX = event.clientX;
136
- swipe.deltaX = 0;
137
- (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
133
+ if (!toast.dismissible || event.button !== 0 || (event.target as HTMLElement).closest('button')) return;
134
+ swipe.id = toast.id;
135
+ swipe.startX = event.clientX;
136
+ swipe.deltaX = 0;
137
+ (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
138
138
  };
139
139
 
140
140
  // Follow the pointer while swiping
141
141
  const handlePointerMove = (event: PointerEvent) => {
142
- if (swipe.id === null) return;
143
- swipe.deltaX = event.clientX - swipe.startX;
142
+ if (swipe.id === null) return;
143
+ swipe.deltaX = event.clientX - swipe.startX;
144
144
  };
145
145
 
146
146
  // Dismiss the toast when swiped far enough, otherwise spring back
147
147
  const handlePointerUp = () => {
148
- if (swipe.id === null) return;
149
- const id = swipe.id;
150
- const deltaX = swipe.deltaX;
151
- swipe.id = null;
152
- swipe.deltaX = 0;
153
- if (Math.abs(deltaX) > SWIPE_THRESHOLD_PX) {
154
- leaveDirection.set(id, Math.sign(deltaX));
155
- closeMessageToast(id);
156
- }
148
+ if (swipe.id === null) return;
149
+ const id = swipe.id;
150
+ const deltaX = swipe.deltaX;
151
+ swipe.id = null;
152
+ swipe.deltaX = 0;
153
+ if (Math.abs(deltaX) > SWIPE_THRESHOLD_PX) {
154
+ leaveDirection.set(id, Math.sign(deltaX));
155
+ closeMessageToast(id);
156
+ }
157
157
  };
158
158
 
159
159
  // Run a toast action and dismiss it
160
160
  const handleAction = async (toast: MessageToastItem) => {
161
- closeMessageToast(toast.id);
162
- await toast.action?.onClick();
161
+ closeMessageToast(toast.id);
162
+ await toast.action?.onClick();
163
163
  };
164
164
 
165
165
  // Forget measurements of removed toasts
166
166
  const handleAfterLeave = (element: Element) => {
167
- const id = Number((element as HTMLElement).dataset.toastId);
168
- const content = observedElements.get(id);
169
- if (content) {
170
- resizeObserver?.unobserve(content);
171
- observedElements.delete(id);
172
- }
173
- heights.delete(id);
174
- leaveDirection.delete(id);
167
+ const id = Number((element as HTMLElement).dataset.toastId);
168
+ const content = observedElements.get(id);
169
+ if (content) {
170
+ resizeObserver?.unobserve(content);
171
+ observedElements.delete(id);
172
+ }
173
+ heights.delete(id);
174
+ leaveDirection.delete(id);
175
175
  };
176
176
 
177
177
  // Reset the interaction state once the stack is empty (mouseleave never fires on a collapsed region)
178
178
  watch(() => toasts.value.length, (length) => {
179
- if (length === 0 && expanded.value) {
180
- handleLeave();
181
- }
179
+ if (length === 0 && expanded.value) {
180
+ handleLeave();
181
+ }
182
182
  });
183
183
 
184
184
  // Stop observing on unmount
185
185
  onBeforeUnmount(() => {
186
- resizeObserver?.disconnect();
187
- observedElements.clear();
186
+ resizeObserver?.disconnect();
187
+ observedElements.clear();
188
188
  });
189
189
  </script>
190
190
 
191
191
  <template>
192
- <section :aria-label="regionAriaLabel" class="pointer-events-none fixed inset-x-3 bottom-3 z-60 sm:inset-x-auto sm:right-6 sm:bottom-6 sm:w-[380px]">
193
- <ol class="pointer-events-auto relative transition-[height] duration-300 ease-out-expo" :style="{ height: `${containerHeight}px` }" @mouseenter="handleEnter" @mouseleave="handleLeave" @focusin="handleEnter" @focusout="handleLeave">
194
- <TransitionGroup name="uv-toast" @after-leave="handleAfterLeave">
195
- <li v-for="(toast, index) in toasts" :key="toast.id" :data-toast-id="toast.id" :data-front="index === 0 ? '' : undefined" role="status" :aria-live="toast.type === 'error' || toast.type === 'warning' ? 'assertive' : 'polite'" aria-atomic="true" class="uv-toast absolute inset-x-0 bottom-0 origin-bottom touch-pan-y select-none overflow-hidden rounded border border-border bg-card text-card-foreground shadow-elevated-lg" :style="getToastStyle(toast, index)" @pointerdown="handlePointerDown($event, toast)" @pointermove="handlePointerMove" @pointerup="handlePointerUp" @pointercancel="handlePointerUp">
196
- <!-- Measured content -->
197
- <div :ref="observeToast" :data-toast-id="toast.id" :class="cn('flex items-start gap-3 p-4 transition-opacity duration-200', !expanded && index > 0 && 'opacity-0')">
198
- <!-- Leading type icon -->
199
- <div :class="cn('flex size-8 shrink-0 items-center justify-center rounded border', toneClasses[toast.type])">
200
- <HugeiconsIcon :icon="getToastIcon(toast)" :stroke-width="1.8" class="size-4.5 animate-uv-pop [animation-delay:120ms]" />
201
- </div>
202
-
203
- <!-- Title and message -->
204
- <div class="min-w-0 flex-1 self-center">
205
- <p v-if="toast.title" class="m-0 text-sm font-semibold leading-5">
206
- {{ toast.title }}
207
- </p>
208
- <p :class="cn('m-0 text-sm leading-5 wrap-break-word', toast.title && 'text-xs text-muted-foreground sm:text-[13px]')">
209
- {{ toast.message }}
210
- </p>
211
- </div>
212
-
213
- <!-- Action button -->
214
- <button v-if="toast.action" type="button" class="shrink-0 self-center rounded border border-border bg-secondary px-2.5 py-1.5 text-xs font-semibold shadow-elevated-sm outline-none transition-[background-color,border-color,transform] duration-150 hover:border-border-strong hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/45 active:scale-95" @click="handleAction(toast)">
215
- {{ toast.action.label }}
216
- </button>
217
-
218
- <!-- Dismiss button -->
219
- <button v-if="toast.dismissible" type="button" :aria-label="closeAriaLabel" class="group/close -me-1 -mt-1 flex size-7 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground outline-none transition-colors duration-150 hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/45" @click="closeMessageToast(toast.id)">
220
- <HugeiconsIcon :icon="Cancel01Icon" class="size-4 transition-transform duration-300 ease-spring group-hover/close:rotate-90" />
221
- </button>
222
- </div>
223
-
224
- <!-- Countdown bar -->
225
- <div v-if="toast.duration > 0" class="absolute inset-x-0 bottom-0 h-0.5 bg-transparent">
226
- <div :class="cn('h-full origin-left opacity-60', progressClasses[toast.type])" :style="{ animation: `uv-toast-countdown ${toast.duration}ms linear forwards`, animationPlayState: messageToastState.paused ? 'paused' : 'running' }" />
227
- </div>
228
- </li>
229
- </TransitionGroup>
230
- </ol>
231
- </section>
192
+ <section :aria-label="regionAriaLabel" class="pointer-events-none fixed inset-x-3 bottom-3 z-60 sm:inset-x-auto sm:right-6 sm:bottom-6 sm:w-[380px]">
193
+ <ol class="pointer-events-auto relative transition-[height] duration-300 ease-out-expo" :style="{ height: `${containerHeight}px` }" @mouseenter="handleEnter" @mouseleave="handleLeave" @focusin="handleEnter" @focusout="handleLeave">
194
+ <TransitionGroup name="uv-toast" @after-leave="handleAfterLeave">
195
+ <li v-for="(toast, index) in toasts" :key="toast.id" :data-toast-id="toast.id" :data-front="index === 0 ? '' : undefined" role="status" :aria-live="toast.type === 'error' || toast.type === 'warning' ? 'assertive' : 'polite'" aria-atomic="true" class="uv-toast absolute inset-x-0 bottom-0 origin-bottom touch-pan-y select-none overflow-hidden rounded border border-border bg-card text-card-foreground shadow-elevated-lg" :style="getToastStyle(toast, index)" @pointerdown="handlePointerDown($event, toast)" @pointermove="handlePointerMove" @pointerup="handlePointerUp" @pointercancel="handlePointerUp">
196
+ <!-- Measured content -->
197
+ <div :ref="observeToast" :data-toast-id="toast.id" :class="cn('flex items-start gap-3 p-4 transition-opacity duration-200', !expanded && index > 0 && 'opacity-0')">
198
+ <!-- Leading type icon -->
199
+ <div :class="cn('flex size-8 shrink-0 items-center justify-center rounded border', toneClasses[toast.type])">
200
+ <HugeiconsIcon :icon="getToastIcon(toast)" :stroke-width="1.8" class="size-4.5 animate-uv-pop [animation-delay:120ms]" />
201
+ </div>
202
+
203
+ <!-- Title and message -->
204
+ <div class="min-w-0 flex-1 self-center">
205
+ <p v-if="toast.title" class="m-0 text-sm font-semibold leading-5">
206
+ {{ toast.title }}
207
+ </p>
208
+ <p :class="cn('m-0 text-sm leading-5 wrap-break-word', toast.title && 'text-xs text-muted-foreground sm:text-[13px]')">
209
+ {{ toast.message }}
210
+ </p>
211
+ </div>
212
+
213
+ <!-- Action button -->
214
+ <button v-if="toast.action" type="button" class="shrink-0 self-center rounded border border-border bg-secondary px-2.5 py-1.5 text-xs font-semibold shadow-elevated-sm outline-none transition-[background-color,border-color,transform] duration-150 hover:border-border-strong hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/45 active:scale-95" @click="handleAction(toast)">
215
+ {{ toast.action.label }}
216
+ </button>
217
+
218
+ <!-- Dismiss button -->
219
+ <button v-if="toast.dismissible" type="button" :aria-label="closeAriaLabel" class="group/close -me-1 -mt-1 flex size-7 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground outline-none transition-colors duration-150 hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/45" @click="closeMessageToast(toast.id)">
220
+ <HugeiconsIcon :icon="Cancel01Icon" class="size-4 transition-transform duration-300 ease-spring group-hover/close:rotate-90" />
221
+ </button>
222
+ </div>
223
+
224
+ <!-- Countdown bar -->
225
+ <div v-if="toast.duration > 0" class="absolute inset-x-0 bottom-0 h-0.5 bg-transparent">
226
+ <div :class="cn('h-full origin-left opacity-60', progressClasses[toast.type])" :style="{ animation: `uv-toast-countdown ${toast.duration}ms linear forwards`, animationPlayState: messageToastState.paused ? 'paused' : 'running' }" />
227
+ </div>
228
+ </li>
229
+ </TransitionGroup>
230
+ </ol>
231
+ </section>
232
232
  </template>
233
233
 
234
234
  <style>
235
235
  .uv-toast {
236
- transition:
237
- translate 480ms var(--ease-spring),
238
- scale 480ms var(--ease-spring),
239
- opacity 250ms var(--ease-out-expo),
240
- height 300ms var(--ease-out-expo),
241
- transform 480ms var(--ease-spring);
242
- will-change: translate, scale;
236
+ transition:
237
+ translate 480ms var(--ease-spring),
238
+ scale 480ms var(--ease-spring),
239
+ opacity 250ms var(--ease-out-expo),
240
+ height 300ms var(--ease-out-expo),
241
+ transform 480ms var(--ease-spring);
242
+ will-change: translate, scale;
243
243
  }
244
244
 
245
245
  .uv-toast-enter-from {
246
- opacity: 0 !important;
247
- transform: translateY(110%) scale(0.92);
246
+ opacity: 0 !important;
247
+ transform: translateY(110%) scale(0.92);
248
248
  }
249
249
 
250
250
  .uv-toast-leave-active {
251
- transition:
252
- transform 260ms var(--ease-snappy),
253
- opacity 200ms var(--ease-snappy) !important;
251
+ transition:
252
+ transform 260ms var(--ease-snappy),
253
+ opacity 200ms var(--ease-snappy) !important;
254
254
  }
255
255
 
256
256
  .uv-toast-leave-to {
257
- opacity: 0 !important;
258
- transform: translateX(var(--uv-toast-leave-x, 110%));
257
+ opacity: 0 !important;
258
+ transform: translateX(var(--uv-toast-leave-x, 110%));
259
259
  }
260
260
 
261
261
  @keyframes uv-toast-countdown {
262
- from { transform: scaleX(1); }
263
- to { transform: scaleX(0); }
262
+ from { transform: scaleX(1); }
263
+ to { transform: scaleX(0); }
264
264
  }
265
265
  </style>