@ui-sdk/web 0.0.0-stage → 0.1.0-beta.1

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 (467) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +10 -2
  3. package/browser/web/accordion.js +1 -0
  4. package/browser/web/alert-dialog.js +1 -0
  5. package/browser/web/autocomplete.js +1 -0
  6. package/browser/web/avatar.js +1 -0
  7. package/browser/web/button.js +1 -0
  8. package/browser/web/calendar.js +1 -0
  9. package/browser/web/carousel.js +1 -0
  10. package/browser/web/checkbox.js +1 -0
  11. package/browser/web/chunks/0eRGibL6.js +1 -0
  12. package/browser/web/chunks/2bIEUO6_.js +1 -0
  13. package/browser/web/chunks/5A9w2ULz.js +1 -0
  14. package/browser/web/chunks/5RSyydjV.js +1 -0
  15. package/browser/web/chunks/9pWTy2wl.js +1 -0
  16. package/browser/web/chunks/B0f2j6zz.js +1 -0
  17. package/browser/web/chunks/B1rux6br.js +1 -0
  18. package/browser/web/chunks/B3-APaNf.js +1 -0
  19. package/browser/web/chunks/B7EgSgjQ.js +1 -0
  20. package/browser/web/chunks/B8QcOzJU.js +1 -0
  21. package/browser/web/chunks/BFueEkwm.js +3 -0
  22. package/browser/web/chunks/BJj3oS29.js +1 -0
  23. package/browser/web/chunks/BNSvTCpr.js +1 -0
  24. package/browser/web/chunks/BPD0kAZB.js +1 -0
  25. package/browser/web/chunks/BQeduZqT.js +1 -0
  26. package/browser/web/chunks/B_CVFyiz.js +1 -0
  27. package/browser/web/chunks/B_ns1YHO.js +1 -0
  28. package/browser/web/chunks/BcwkVTsR.js +1 -0
  29. package/browser/web/chunks/BeaQ6TYM.js +1 -0
  30. package/browser/web/chunks/BgBB013u.js +1 -0
  31. package/browser/web/chunks/BgsKhHDm.js +1 -0
  32. package/browser/web/chunks/BjMcbuhi.js +9 -0
  33. package/browser/web/chunks/Bjiy_F2N.js +1 -0
  34. package/browser/web/chunks/BqScCLwv.js +1 -0
  35. package/browser/web/chunks/BqX3Utqx.js +1 -0
  36. package/browser/web/chunks/BtVkQf3z.js +1 -0
  37. package/browser/web/chunks/By30h-7B.js +1 -0
  38. package/browser/web/chunks/C1zqYpy2.js +1 -0
  39. package/browser/web/chunks/C436juFf.js +1 -0
  40. package/browser/web/chunks/C4_bULs1.js +1 -0
  41. package/browser/web/chunks/C4omqJEz.js +1 -0
  42. package/browser/web/chunks/C7tt0T3n.js +1 -0
  43. package/browser/web/chunks/C8w7s5dg.js +1 -0
  44. package/browser/web/chunks/CElY4erO.js +1 -0
  45. package/browser/web/chunks/CFODo-m2.js +1 -0
  46. package/browser/web/chunks/CL4wjam9.js +1 -0
  47. package/browser/web/chunks/CMg-8UVf.js +1 -0
  48. package/browser/web/chunks/COWKfakj.js +1 -0
  49. package/browser/web/chunks/CQBU0qZ4.js +1 -0
  50. package/browser/web/chunks/CV6uABgc.js +1 -0
  51. package/browser/web/chunks/C_SWFpWQ.js +1 -0
  52. package/browser/web/chunks/C_Uanbrl.js +1 -0
  53. package/browser/web/chunks/Ce_CSanC.js +1 -0
  54. package/browser/web/chunks/Cg-ZmRhS.js +1 -0
  55. package/browser/web/chunks/Cgf2wPI_.js +1 -0
  56. package/browser/web/chunks/Cuep_3Vf.js +1 -0
  57. package/browser/web/chunks/D02PaHn6.js +1 -0
  58. package/browser/web/chunks/D5LiaI5R.js +1 -0
  59. package/browser/web/chunks/D9UgVYvF.js +1 -0
  60. package/browser/web/chunks/DC08tnkE.js +2 -0
  61. package/browser/web/chunks/DG8YGSvu.js +1 -0
  62. package/browser/web/chunks/DIQd0FYD.js +1 -0
  63. package/browser/web/chunks/DMLqacE8.js +1 -0
  64. package/browser/web/chunks/DSUI3yI-.js +1 -0
  65. package/browser/web/chunks/DT3Hb76X.js +1 -0
  66. package/browser/web/chunks/DY75g3-W.js +1 -0
  67. package/browser/web/chunks/DZpNQKZ9.js +1 -0
  68. package/browser/web/chunks/Db-W1wrC.js +1 -0
  69. package/browser/web/chunks/Dc1xK3Ii.js +1 -0
  70. package/browser/web/chunks/DdF6awFs.js +1 -0
  71. package/browser/web/chunks/DdaCLml8.js +1 -0
  72. package/browser/web/chunks/Dh8MLjQO.js +1 -0
  73. package/browser/web/chunks/DiuslJRy.js +1 -0
  74. package/browser/web/chunks/DjRcw3Y0.js +1 -0
  75. package/browser/web/chunks/Djdv-16J.js +1 -0
  76. package/browser/web/chunks/DnFXe_lF.js +1 -0
  77. package/browser/web/chunks/DneGv1oC.js +1 -0
  78. package/browser/web/chunks/DsVxP-p-.js +1 -0
  79. package/browser/web/chunks/DwDilCo2.js +1 -0
  80. package/browser/web/chunks/DwV48AXv.js +1 -0
  81. package/browser/web/chunks/F37aF4-L.js +1 -0
  82. package/browser/web/chunks/LyB6XIbN.js +1 -0
  83. package/browser/web/chunks/NKnbYGjC.js +1 -0
  84. package/browser/web/chunks/Vk-rVi16.js +1 -0
  85. package/browser/web/chunks/XsM0J1Ex.js +1 -0
  86. package/browser/web/chunks/asSN9iEp.js +1 -0
  87. package/browser/web/chunks/c-AjHfdF.js +1 -0
  88. package/browser/web/chunks/dR-12TPY.js +1 -0
  89. package/browser/web/chunks/hR4xM0EC.js +1 -0
  90. package/browser/web/chunks/hqOaBxAg.js +1 -0
  91. package/browser/web/chunks/kMKqqeG4.js +1 -0
  92. package/browser/web/chunks/kXboBcfi.js +1 -0
  93. package/browser/web/chunks/l4aQIg22.js +1 -0
  94. package/browser/web/chunks/tJC0JSU4.js +1 -0
  95. package/browser/web/chunks/wHdS_QYM.js +1 -0
  96. package/browser/web/chunks/yv8dTvNI.js +1 -0
  97. package/browser/web/chunks/yw9M3nfi.js +1 -0
  98. package/browser/web/collapsible.js +1 -0
  99. package/browser/web/color-picker.js +1 -0
  100. package/browser/web/combobox.js +2 -0
  101. package/browser/web/command.js +1 -0
  102. package/browser/web/core.js +5 -0
  103. package/browser/web/date-input.js +1 -0
  104. package/browser/web/date-picker.js +1 -0
  105. package/browser/web/dialog.js +1 -0
  106. package/browser/web/drawer.js +1 -0
  107. package/browser/web/field.js +1 -0
  108. package/browser/web/file-input.js +1 -0
  109. package/browser/web/hover-card.js +1 -0
  110. package/browser/web/image-cropper.js +1 -0
  111. package/browser/web/input.js +1 -0
  112. package/browser/web/label.js +1 -0
  113. package/browser/web/listbox.js +1 -0
  114. package/browser/web/menu.js +1 -0
  115. package/browser/web/menubar.js +1 -0
  116. package/browser/web/meter.js +1 -0
  117. package/browser/web/navigation-menu.js +1 -0
  118. package/browser/web/number-input.js +1 -0
  119. package/browser/web/otp-input.js +2 -0
  120. package/browser/web/overlays.js +1 -0
  121. package/browser/web/pagination.js +1 -0
  122. package/browser/web/password-input.js +1 -0
  123. package/browser/web/popover.js +1 -0
  124. package/browser/web/preferences.js +1 -0
  125. package/browser/web/progress.js +1 -0
  126. package/browser/web/radio.js +1 -0
  127. package/browser/web/rating.js +1 -0
  128. package/browser/web/resizable.js +1 -0
  129. package/browser/web/scroll-area.js +1 -0
  130. package/browser/web/segmented-control.js +1 -0
  131. package/browser/web/select.js +1 -0
  132. package/browser/web/separator.js +1 -0
  133. package/browser/web/slider.js +1 -0
  134. package/browser/web/switch.js +1 -0
  135. package/browser/web/tabs.js +1 -0
  136. package/browser/web/textarea.js +1 -0
  137. package/browser/web/time-input.js +1 -0
  138. package/browser/web/timeline.js +1 -0
  139. package/browser/web/toast.js +1 -0
  140. package/browser/web/toggle.js +1 -0
  141. package/browser/web/token-input.js +8 -0
  142. package/browser/web/toolbar.js +1 -0
  143. package/browser/web/tooltip.js +1 -0
  144. package/browser/web/tree.js +1 -0
  145. package/browser/web/trigger-menu.js +4 -0
  146. package/browser/web/waterfall.js +1 -0
  147. package/browser/web.css +3378 -0
  148. package/browser/web.js +3 -0
  149. package/custom-elements.json +32315 -0
  150. package/dist/accordion.d.ts +2 -0
  151. package/dist/accordion.js +57 -0
  152. package/dist/action.d.ts +16 -0
  153. package/dist/action.js +39 -0
  154. package/dist/agent.d.ts +2 -0
  155. package/dist/agent.js +7 -0
  156. package/dist/autocomplete.d.ts +2 -0
  157. package/dist/autocomplete.js +120 -0
  158. package/dist/autoload.d.ts +18 -0
  159. package/dist/autoload.js +63 -0
  160. package/dist/avatar.d.ts +2 -0
  161. package/dist/avatar.js +27 -0
  162. package/dist/browser-core.d.ts +2 -0
  163. package/dist/browser-core.js +8 -0
  164. package/dist/button.d.ts +2 -0
  165. package/dist/button.js +35 -0
  166. package/dist/calendar.d.ts +23 -0
  167. package/dist/calendar.js +429 -0
  168. package/dist/carousel.d.ts +2 -0
  169. package/dist/carousel.js +54 -0
  170. package/dist/checkbox.d.ts +4 -0
  171. package/dist/checkbox.js +75 -0
  172. package/dist/collapsible.d.ts +2 -0
  173. package/dist/collapsible.js +28 -0
  174. package/dist/color-picker.d.ts +2 -0
  175. package/dist/color-picker.js +64 -0
  176. package/dist/combobox.d.ts +2 -0
  177. package/dist/combobox.js +334 -0
  178. package/dist/command.d.ts +2 -0
  179. package/dist/command.js +122 -0
  180. package/dist/date-input.d.ts +3 -0
  181. package/dist/date-input.js +87 -0
  182. package/dist/date-picker.d.ts +2 -0
  183. package/dist/date-picker.js +174 -0
  184. package/dist/default-text.d.ts +3 -0
  185. package/dist/default-text.js +24 -0
  186. package/dist/define-element.d.ts +404 -0
  187. package/dist/define-element.js +1489 -0
  188. package/dist/dialog.d.ts +3 -0
  189. package/dist/dialog.js +94 -0
  190. package/dist/drawer.d.ts +2 -0
  191. package/dist/drawer.js +96 -0
  192. package/dist/entries/accordion.d.ts +3 -0
  193. package/dist/entries/accordion.js +7 -0
  194. package/dist/entries/alert-dialog.d.ts +3 -0
  195. package/dist/entries/alert-dialog.js +13 -0
  196. package/dist/entries/autocomplete.d.ts +3 -0
  197. package/dist/entries/autocomplete.js +7 -0
  198. package/dist/entries/avatar.d.ts +2 -0
  199. package/dist/entries/avatar.js +3 -0
  200. package/dist/entries/button.d.ts +2 -0
  201. package/dist/entries/button.js +3 -0
  202. package/dist/entries/calendar.d.ts +3 -0
  203. package/dist/entries/calendar.js +7 -0
  204. package/dist/entries/carousel.d.ts +3 -0
  205. package/dist/entries/carousel.js +7 -0
  206. package/dist/entries/checkbox.d.ts +3 -0
  207. package/dist/entries/checkbox.js +15 -0
  208. package/dist/entries/collapsible.d.ts +3 -0
  209. package/dist/entries/collapsible.js +7 -0
  210. package/dist/entries/color-picker.d.ts +3 -0
  211. package/dist/entries/color-picker.js +7 -0
  212. package/dist/entries/combobox.d.ts +3 -0
  213. package/dist/entries/combobox.js +7 -0
  214. package/dist/entries/command.d.ts +3 -0
  215. package/dist/entries/command.js +7 -0
  216. package/dist/entries/date-input.d.ts +3 -0
  217. package/dist/entries/date-input.js +7 -0
  218. package/dist/entries/date-picker.d.ts +3 -0
  219. package/dist/entries/date-picker.js +7 -0
  220. package/dist/entries/dialog.d.ts +3 -0
  221. package/dist/entries/dialog.js +7 -0
  222. package/dist/entries/drawer.d.ts +3 -0
  223. package/dist/entries/drawer.js +8 -0
  224. package/dist/entries/field.d.ts +2 -0
  225. package/dist/entries/field.js +3 -0
  226. package/dist/entries/file-input.d.ts +3 -0
  227. package/dist/entries/file-input.js +13 -0
  228. package/dist/entries/hover-card.d.ts +3 -0
  229. package/dist/entries/hover-card.js +7 -0
  230. package/dist/entries/image-cropper.d.ts +3 -0
  231. package/dist/entries/image-cropper.js +7 -0
  232. package/dist/entries/input.d.ts +3 -0
  233. package/dist/entries/input.js +8 -0
  234. package/dist/entries/label.d.ts +2 -0
  235. package/dist/entries/label.js +3 -0
  236. package/dist/entries/listbox.d.ts +3 -0
  237. package/dist/entries/listbox.js +7 -0
  238. package/dist/entries/menu.d.ts +3 -0
  239. package/dist/entries/menu.js +7 -0
  240. package/dist/entries/menubar.d.ts +3 -0
  241. package/dist/entries/menubar.js +7 -0
  242. package/dist/entries/meter.d.ts +2 -0
  243. package/dist/entries/meter.js +3 -0
  244. package/dist/entries/navigation-menu.d.ts +3 -0
  245. package/dist/entries/navigation-menu.js +7 -0
  246. package/dist/entries/number-input.d.ts +3 -0
  247. package/dist/entries/number-input.js +7 -0
  248. package/dist/entries/otp-input.d.ts +3 -0
  249. package/dist/entries/otp-input.js +7 -0
  250. package/dist/entries/overlays.d.ts +2 -0
  251. package/dist/entries/overlays.js +3 -0
  252. package/dist/entries/pagination.d.ts +3 -0
  253. package/dist/entries/pagination.js +11 -0
  254. package/dist/entries/password-input.d.ts +3 -0
  255. package/dist/entries/password-input.js +7 -0
  256. package/dist/entries/popover.d.ts +3 -0
  257. package/dist/entries/popover.js +7 -0
  258. package/dist/entries/preferences.d.ts +3 -0
  259. package/dist/entries/preferences.js +13 -0
  260. package/dist/entries/progress.d.ts +2 -0
  261. package/dist/entries/progress.js +3 -0
  262. package/dist/entries/radio.d.ts +3 -0
  263. package/dist/entries/radio.js +7 -0
  264. package/dist/entries/rating.d.ts +3 -0
  265. package/dist/entries/rating.js +8 -0
  266. package/dist/entries/resizable.d.ts +3 -0
  267. package/dist/entries/resizable.js +11 -0
  268. package/dist/entries/scroll-area.d.ts +3 -0
  269. package/dist/entries/scroll-area.js +7 -0
  270. package/dist/entries/segmented-control.d.ts +3 -0
  271. package/dist/entries/segmented-control.js +7 -0
  272. package/dist/entries/select.d.ts +3 -0
  273. package/dist/entries/select.js +7 -0
  274. package/dist/entries/separator.d.ts +2 -0
  275. package/dist/entries/separator.js +3 -0
  276. package/dist/entries/slider.d.ts +3 -0
  277. package/dist/entries/slider.js +7 -0
  278. package/dist/entries/switch.d.ts +3 -0
  279. package/dist/entries/switch.js +7 -0
  280. package/dist/entries/tabs.d.ts +3 -0
  281. package/dist/entries/tabs.js +7 -0
  282. package/dist/entries/textarea.d.ts +3 -0
  283. package/dist/entries/textarea.js +7 -0
  284. package/dist/entries/time-input.d.ts +3 -0
  285. package/dist/entries/time-input.js +7 -0
  286. package/dist/entries/timeline.d.ts +3 -0
  287. package/dist/entries/timeline.js +7 -0
  288. package/dist/entries/toast.d.ts +2 -0
  289. package/dist/entries/toast.js +3 -0
  290. package/dist/entries/toggle.d.ts +3 -0
  291. package/dist/entries/toggle.js +12 -0
  292. package/dist/entries/token-input.d.ts +3 -0
  293. package/dist/entries/token-input.js +17 -0
  294. package/dist/entries/toolbar.d.ts +3 -0
  295. package/dist/entries/toolbar.js +7 -0
  296. package/dist/entries/tooltip.d.ts +3 -0
  297. package/dist/entries/tooltip.js +7 -0
  298. package/dist/entries/tree.d.ts +3 -0
  299. package/dist/entries/tree.js +17 -0
  300. package/dist/entries/trigger-menu.d.ts +3 -0
  301. package/dist/entries/trigger-menu.js +11 -0
  302. package/dist/entries/waterfall.d.ts +3 -0
  303. package/dist/entries/waterfall.js +11 -0
  304. package/dist/events.d.ts +1658 -0
  305. package/dist/events.js +0 -0
  306. package/dist/field.d.ts +2 -0
  307. package/dist/field.js +101 -0
  308. package/dist/file-input.d.ts +2 -0
  309. package/dist/file-input.js +140 -0
  310. package/dist/forward-attributes.d.ts +2 -0
  311. package/dist/forward-attributes.js +22 -0
  312. package/dist/history.d.ts +2 -0
  313. package/dist/history.js +11 -0
  314. package/dist/hover-card.d.ts +2 -0
  315. package/dist/hover-card.js +31 -0
  316. package/dist/image-cropper.d.ts +2 -0
  317. package/dist/image-cropper.js +66 -0
  318. package/dist/index.d.ts +66 -0
  319. package/dist/index.js +269 -0
  320. package/dist/input.d.ts +3 -0
  321. package/dist/input.js +69 -0
  322. package/dist/label.d.ts +2 -0
  323. package/dist/label.js +11 -0
  324. package/dist/list.d.ts +40 -0
  325. package/dist/list.js +192 -0
  326. package/dist/listbox.d.ts +2 -0
  327. package/dist/listbox.js +84 -0
  328. package/dist/menu.d.ts +4 -0
  329. package/dist/menu.js +295 -0
  330. package/dist/menubar.d.ts +4 -0
  331. package/dist/menubar.js +30 -0
  332. package/dist/meter.d.ts +2 -0
  333. package/dist/meter.js +22 -0
  334. package/dist/navigation-menu.d.ts +2 -0
  335. package/dist/navigation-menu.js +114 -0
  336. package/dist/number-input.d.ts +2 -0
  337. package/dist/number-input.js +73 -0
  338. package/dist/observe.d.ts +2 -0
  339. package/dist/observe.js +7 -0
  340. package/dist/otp-input.d.ts +2 -0
  341. package/dist/otp-input.js +72 -0
  342. package/dist/overlays.d.ts +13 -0
  343. package/dist/overlays.js +156 -0
  344. package/dist/pagination.d.ts +2 -0
  345. package/dist/pagination.js +127 -0
  346. package/dist/password-input.d.ts +2 -0
  347. package/dist/password-input.js +57 -0
  348. package/dist/popover.d.ts +2 -0
  349. package/dist/popover.js +64 -0
  350. package/dist/popup.d.ts +40 -0
  351. package/dist/popup.js +112 -0
  352. package/dist/preferences.d.ts +2 -0
  353. package/dist/preferences.js +56 -0
  354. package/dist/progress.d.ts +2 -0
  355. package/dist/progress.js +22 -0
  356. package/dist/radio.d.ts +2 -0
  357. package/dist/radio.js +33 -0
  358. package/dist/rating.d.ts +2 -0
  359. package/dist/rating.js +64 -0
  360. package/dist/resizable.d.ts +2 -0
  361. package/dist/resizable.js +42 -0
  362. package/dist/scroll-area.d.ts +2 -0
  363. package/dist/scroll-area.js +45 -0
  364. package/dist/segmented-control.d.ts +2 -0
  365. package/dist/segmented-control.js +28 -0
  366. package/dist/select.d.ts +2 -0
  367. package/dist/select.js +239 -0
  368. package/dist/separator.d.ts +2 -0
  369. package/dist/separator.js +11 -0
  370. package/dist/slider.d.ts +2 -0
  371. package/dist/slider.js +77 -0
  372. package/dist/tabs.d.ts +2 -0
  373. package/dist/tabs.js +37 -0
  374. package/dist/timeline.d.ts +2 -0
  375. package/dist/timeline.js +27 -0
  376. package/dist/toast.d.ts +20 -0
  377. package/dist/toast.js +177 -0
  378. package/dist/toggle.d.ts +3 -0
  379. package/dist/toggle.js +64 -0
  380. package/dist/token-input.d.ts +2 -0
  381. package/dist/token-input.js +103 -0
  382. package/dist/toolbar.d.ts +2 -0
  383. package/dist/toolbar.js +36 -0
  384. package/dist/tooltip.d.ts +2 -0
  385. package/dist/tooltip.js +35 -0
  386. package/dist/tree.d.ts +2 -0
  387. package/dist/tree.js +147 -0
  388. package/dist/trigger-menu.d.ts +2 -0
  389. package/dist/trigger-menu.js +133 -0
  390. package/dist/waterfall.d.ts +2 -0
  391. package/dist/waterfall.js +140 -0
  392. package/docs/README.md +89 -0
  393. package/docs/agents.md +1523 -0
  394. package/docs/components/accordion.md +1401 -0
  395. package/docs/components/alert-dialog.md +788 -0
  396. package/docs/components/autocomplete.md +1692 -0
  397. package/docs/components/avatar.md +261 -0
  398. package/docs/components/button.md +441 -0
  399. package/docs/components/calendar.md +1536 -0
  400. package/docs/components/carousel.md +1055 -0
  401. package/docs/components/checkbox.md +1045 -0
  402. package/docs/components/collapsible.md +535 -0
  403. package/docs/components/color-picker.md +651 -0
  404. package/docs/components/combobox.md +3274 -0
  405. package/docs/components/command.md +1431 -0
  406. package/docs/components/date-input.md +563 -0
  407. package/docs/components/date-picker.md +1136 -0
  408. package/docs/components/dialog.md +1360 -0
  409. package/docs/components/drawer.md +1201 -0
  410. package/docs/components/field.md +519 -0
  411. package/docs/components/file-input.md +617 -0
  412. package/docs/components/hover-card.md +486 -0
  413. package/docs/components/image-cropper.md +489 -0
  414. package/docs/components/input.md +327 -0
  415. package/docs/components/label.md +208 -0
  416. package/docs/components/listbox.md +1015 -0
  417. package/docs/components/menu.md +1212 -0
  418. package/docs/components/menubar.md +460 -0
  419. package/docs/components/meter.md +298 -0
  420. package/docs/components/navigation-menu.md +1573 -0
  421. package/docs/components/number-input.md +1087 -0
  422. package/docs/components/otp-input.md +558 -0
  423. package/docs/components/pagination.md +639 -0
  424. package/docs/components/password-input.md +649 -0
  425. package/docs/components/popover.md +1433 -0
  426. package/docs/components/preferences.md +243 -0
  427. package/docs/components/progress.md +406 -0
  428. package/docs/components/radio.md +855 -0
  429. package/docs/components/rating.md +431 -0
  430. package/docs/components/resizable.md +866 -0
  431. package/docs/components/scroll-area.md +898 -0
  432. package/docs/components/segmented-control.md +421 -0
  433. package/docs/components/select.md +1957 -0
  434. package/docs/components/separator.md +238 -0
  435. package/docs/components/slider.md +1018 -0
  436. package/docs/components/switch.md +583 -0
  437. package/docs/components/tabs.md +948 -0
  438. package/docs/components/textarea.md +331 -0
  439. package/docs/components/time-input.md +235 -0
  440. package/docs/components/timeline.md +622 -0
  441. package/docs/components/toast.md +1223 -0
  442. package/docs/components/toggle.md +522 -0
  443. package/docs/components/token-input.md +854 -0
  444. package/docs/components/toolbar.md +815 -0
  445. package/docs/components/tooltip.md +860 -0
  446. package/docs/components/tree.md +1243 -0
  447. package/docs/components/trigger-menu.md +1110 -0
  448. package/docs/components/waterfall.md +709 -0
  449. package/docs/controllers.md +66 -0
  450. package/docs/core.md +8027 -0
  451. package/docs/custom-parts.md +91 -0
  452. package/docs/first-component.md +88 -0
  453. package/docs/forms.md +125 -0
  454. package/docs/installation.md +141 -0
  455. package/docs/introduction.md +32 -0
  456. package/docs/lists-and-menus.md +166 -0
  457. package/docs/llms.txt +1566 -0
  458. package/docs/parts-and-composition.md +57 -0
  459. package/docs/popups.md +92 -0
  460. package/docs/rendering.md +71 -0
  461. package/docs/server-rendering.md +118 -0
  462. package/docs/state-and-events.md +134 -0
  463. package/docs/styling-and-animation.md +104 -0
  464. package/docs/utilities/async-options.md +332 -0
  465. package/docs/utilities/shortcuts.md +184 -0
  466. package/html-custom-data.json +14792 -0
  467. package/package.json +302 -3
@@ -0,0 +1,1223 @@
1
+ # Toast
2
+
3
+ Show notifications with actions, timed dismissal, and screen reader announcements.
4
+
5
+ A toast tells someone that something happened, like a saved change or a sent message, and goes away on its own. It can offer an action such as Undo, stacks with the toasts before it, and is announced to screen readers without taking focus.
6
+
7
+ ```ts title="demo.ts"
8
+ import "@ui-sdk/web/toast"
9
+ import { createToaster } from "@ui-sdk/web"
10
+ import { log } from "./log"
11
+
12
+ function mount(root: HTMLElement) {
13
+ const toast = createToaster()
14
+ root.innerHTML = `
15
+ <button>Create Event</button>
16
+ <ui-toast-region>
17
+ <template>
18
+ <ui-toast>
19
+ <div data-slot="stack">
20
+ <ui-toast-title></ui-toast-title>
21
+ <ui-toast-description></ui-toast-description>
22
+ </div>
23
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
24
+ </ui-toast>
25
+ </template>
26
+ </ui-toast-region>
27
+ `
28
+ root.querySelector("ui-toast-region")!.toaster = toast
29
+ root.querySelector("button")!.addEventListener("click", () =>
30
+ toast("Event created", {
31
+ description: "Friday, June 12 at 10:00 AM",
32
+ action: { label: "Undo", onAction: () => log(root, "Event removed") },
33
+ })
34
+ )
35
+ return () => {
36
+ toast.dismiss()
37
+ }
38
+ }
39
+
40
+ export { mount }
41
+ ```
42
+
43
+ Press Create Event. Choose Undo, swipe the toast away, or wait for it to close. Undo logs Event removed.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ npm install @ui-sdk/web @ui-sdk/core
49
+ ```
50
+
51
+ Import the component to register its elements. The import is safe on the server.
52
+
53
+ ```ts
54
+ import "@ui-sdk/web/toast"
55
+ ```
56
+
57
+ ## Composition
58
+
59
+ Use the following composition to build a `ui-toast-region`:
60
+
61
+ ```text
62
+ ui-toast-region
63
+ └── template
64
+ └── ui-toast
65
+ ├── ui-toast-title
66
+ ├── ui-toast-description
67
+ ├── ui-toast-action
68
+ │ └── button
69
+ └── ui-toast-close
70
+ └── button
71
+ ```
72
+
73
+ The region clones the `ui-toast` in its `template` for each toast in its queue, newest first. A toast is named by its title and described by its description. Empty title, description and action parts show the text from the toast's data, so a region's template is usually the same few parts. An empty `ui-toast-close` shows the toast's cancel and runs its `onCancel`, and hides when the toast has none.
74
+
75
+ ## Usage
76
+
77
+ Import the parts and put them together, then call `toast()` when an action finishes:
78
+
79
+ ```html
80
+ <script type="module">
81
+ import "@ui-sdk/web/toast"
82
+ import { toast } from "@ui-sdk/web"
83
+
84
+ document
85
+ .querySelector("#create-event")
86
+ .addEventListener("click", () =>
87
+ toast("Event created", { description: "Friday at 10:00 AM" })
88
+ )
89
+ </script>
90
+
91
+ <button id="create-event" type="button">Create Event</button>
92
+ <ui-toast-region>
93
+ <template>
94
+ <ui-toast>
95
+ <ui-toast-title></ui-toast-title>
96
+ <ui-toast-description></ui-toast-description>
97
+ </ui-toast>
98
+ </template>
99
+ </ui-toast-region>
100
+ ```
101
+
102
+ `toast()` works from anywhere, not only from event listeners, and returns the toast's id. Place the region once, near your app's root. Without a template, it renders each toast's title, description, action and cancel button with unstyled parts.
103
+
104
+ The examples below each call `createToaster()` for a queue of their own and set it on their region's `toaster` property, so their toasts don't mix.
105
+
106
+ ## Types
107
+
108
+ `toast.success`, `.info`, `.warning`, `.error` and `.loading` set the toast's type, which the toast exposes as `data-type` for an icon or a color. Errors are announced right away and other types wait for a pause; set `priority` to change that. A loading toast stays until it's updated or dismissed.
109
+
110
+ ```ts title="types.ts"
111
+ import "@ui-sdk/web/toast"
112
+ import { createToaster } from "@ui-sdk/web"
113
+ import {
114
+ CircleCheck,
115
+ createElement,
116
+ Info,
117
+ LoaderCircle,
118
+ OctagonX,
119
+ TriangleAlert,
120
+ } from "lucide"
121
+
122
+ const upload = () => new Promise((resolve) => setTimeout(resolve, 2000))
123
+
124
+ function mount(root: HTMLElement) {
125
+ const toast = createToaster()
126
+ root.innerHTML = `
127
+ <div data-slot="row">
128
+ <button>Default</button>
129
+ <button>Success</button>
130
+ <button>Info</button>
131
+ <button>Warning</button>
132
+ <button>Error</button>
133
+ <button>Loading</button>
134
+ </div>
135
+ <ui-toast-region>
136
+ <template>
137
+ <ui-toast>
138
+ ${createElement(CircleCheck, { "data-show": "success", "aria-hidden": "true" }).outerHTML}
139
+ ${createElement(Info, { "data-show": "info", "aria-hidden": "true" }).outerHTML}
140
+ ${createElement(TriangleAlert, { "data-show": "warning", "aria-hidden": "true" }).outerHTML}
141
+ ${createElement(OctagonX, { "data-show": "error", "aria-hidden": "true" }).outerHTML}
142
+ ${createElement(LoaderCircle, { "data-show": "loading", "aria-hidden": "true" }).outerHTML}
143
+ <ui-toast-title></ui-toast-title>
144
+ </ui-toast>
145
+ </template>
146
+ </ui-toast-region>
147
+ `
148
+ root.querySelector("ui-toast-region")!.toaster = toast
149
+ const [plain, success, info, warning, error, loading] =
150
+ root.querySelectorAll("button")
151
+ plain.addEventListener("click", () => toast("Event created"))
152
+ success.addEventListener("click", () => toast.success("Changes saved"))
153
+ info.addEventListener("click", () => toast.info("A new version is available"))
154
+ warning.addEventListener("click", () =>
155
+ toast.warning("Storage is almost full")
156
+ )
157
+ error.addEventListener("click", () => toast.error("Couldn't save changes"))
158
+ loading.addEventListener("click", () =>
159
+ toast.promise(upload, {
160
+ loading: "Uploading photos…",
161
+ success: "Photos uploaded",
162
+ error: "Upload failed",
163
+ })
164
+ )
165
+ return () => {
166
+ toast.dismiss()
167
+ }
168
+ }
169
+
170
+ export { mount }
171
+ ```
172
+
173
+ Choose a type. Each toast shows its type's icon, and Loading turns into Photos uploaded when it finishes.
174
+
175
+ ## Position
176
+
177
+ Set the region's `side` to `top` or `bottom`, and `align` to `start`, `center` or `end`. Start and end follow the writing direction. A toast can be swiped toward the side and, unless it's centered, toward the end it's aligned to.
178
+
179
+ ```ts title="position.ts"
180
+ import "@ui-sdk/web/select"
181
+ import "@ui-sdk/web/toast"
182
+ import { createToaster } from "@ui-sdk/web"
183
+ import { Check, ChevronDown, createElement } from "lucide"
184
+
185
+ const sides = [
186
+ { value: "top", label: "Top" },
187
+ { value: "bottom", label: "Bottom" },
188
+ ]
189
+ const aligns = [
190
+ { value: "start", label: "Start" },
191
+ { value: "center", label: "Center" },
192
+ { value: "end", label: "End" },
193
+ ]
194
+
195
+ const check = createElement(Check, { "aria-hidden": "true" }).outerHTML
196
+ const chevron = createElement(ChevronDown, { "aria-hidden": "true" }).outerHTML
197
+
198
+ function select(
199
+ attribute: string,
200
+ label: string,
201
+ value: string,
202
+ options: { value: string; label: string }[]
203
+ ) {
204
+ return `
205
+ <ui-select data-attribute="${attribute}" default-value="${value}">
206
+ <ui-select-label>${label}</ui-select-label>
207
+ <ui-select-trigger>
208
+ <button>
209
+ <ui-select-value></ui-select-value>
210
+ ${chevron}
211
+ </button>
212
+ </ui-select-trigger>
213
+ <ui-select-content hidden>
214
+ ${options
215
+ .map(
216
+ (option) => `
217
+ <ui-select-item value="${option.value}">
218
+ ${option.label}
219
+ <ui-select-item-indicator>${check}</ui-select-item-indicator>
220
+ </ui-select-item>
221
+ `
222
+ )
223
+ .join("")}
224
+ </ui-select-content>
225
+ </ui-select>
226
+ `
227
+ }
228
+
229
+ function mount(root: HTMLElement) {
230
+ const toast = createToaster()
231
+ root.innerHTML = `
232
+ <div data-slot="stack">
233
+ <div data-slot="controls">
234
+ ${select("side", "Side", "bottom", sides)}
235
+ ${select("align", "Align", "end", aligns)}
236
+ </div>
237
+ <button>Create Event</button>
238
+ <ui-toast-region side="bottom" align="end">
239
+ <template>
240
+ <ui-toast>
241
+ <div data-slot="stack">
242
+ <ui-toast-title></ui-toast-title>
243
+ <ui-toast-description></ui-toast-description>
244
+ </div>
245
+ </ui-toast>
246
+ </template>
247
+ </ui-toast-region>
248
+ </div>
249
+ `
250
+ const region = root.querySelector("ui-toast-region")!
251
+ region.toaster = toast
252
+ for (const control of root.querySelectorAll("ui-select")) {
253
+ control.addEventListener("valuechange", (event) => {
254
+ const value = event.detail.value
255
+ if (typeof value === "string") {
256
+ region.setAttribute(control.dataset.attribute!, value)
257
+ }
258
+ })
259
+ }
260
+ root
261
+ .querySelector("[data-slot='controls'] + button")!
262
+ .addEventListener("click", () =>
263
+ toast("Event created", { description: "Friday, June 12 at 10:00 AM" })
264
+ )
265
+ return () => {
266
+ toast.dismiss()
267
+ }
268
+ }
269
+
270
+ export { mount }
271
+ ```
272
+
273
+ Choose a side and an alignment, then press Create Event and look for the toast at that edge of the page.
274
+
275
+ ## Action and Cancel
276
+
277
+ Add an `action`, like Undo, and a `cancel` button that dismisses the toast. Their callbacks can update your app. `onDismiss` tells you why the toast is closing, and `details.cancel()` keeps it open; a canceled timeout starts the countdown again.
278
+
279
+ ```ts title="action.ts"
280
+ import "@ui-sdk/web/toast"
281
+ import { createToaster } from "@ui-sdk/web"
282
+ import { log } from "./log"
283
+
284
+ function mount(root: HTMLElement) {
285
+ const toast = createToaster()
286
+ root.innerHTML = `
287
+ <button>Archive Message</button>
288
+ <ui-toast-region>
289
+ <template>
290
+ <ui-toast>
291
+ <ui-toast-title></ui-toast-title>
292
+ <ui-toast-close><button></button></ui-toast-close>
293
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
294
+ </ui-toast>
295
+ </template>
296
+ </ui-toast-region>
297
+ `
298
+ root.querySelector("ui-toast-region")!.toaster = toast
299
+ root.querySelector("button")!.addEventListener("click", () =>
300
+ toast("Message archived", {
301
+ action: { label: "Undo", onAction: () => log(root, "Message restored") },
302
+ cancel: { label: "Dismiss", onCancel: () => log(root, "Kept archived") },
303
+ onDismiss: ({ reason }) => log(root, `Closed (${reason})`),
304
+ })
305
+ )
306
+ return () => {
307
+ toast.dismiss()
308
+ }
309
+ }
310
+
311
+ export { mount }
312
+ ```
313
+
314
+ Press Archive Message, then choose Undo or Dismiss, swipe the toast away, or let it time out. The console logs why it closed.
315
+
316
+ ## Link
317
+
318
+ Give an action an `href`, and write an `<a>` in `ui-toast-action` instead of a `<button>` to render it as a link; the region's `renderToast` sets the link's `href` from the toast. It keeps normal link behavior, including opening in a new tab.
319
+
320
+ ```ts title="link.ts"
321
+ import "@ui-sdk/web/toast"
322
+ import { createToaster } from "@ui-sdk/web"
323
+
324
+ function mount(root: HTMLElement) {
325
+ const toast = createToaster()
326
+ root.innerHTML = `
327
+ <button>Send Invoice</button>
328
+ <ui-toast-region>
329
+ <template>
330
+ <ui-toast>
331
+ <div data-slot="stack">
332
+ <ui-toast-title></ui-toast-title>
333
+ <ui-toast-description></ui-toast-description>
334
+ </div>
335
+ <ui-toast-action><a data-variant="solid"></a></ui-toast-action>
336
+ </ui-toast>
337
+ </template>
338
+ </ui-toast-region>
339
+ `
340
+ const region = root.querySelector("ui-toast-region")!
341
+ region.toaster = toast
342
+ region.renderToast = (item, el) => {
343
+ if (item.action?.href) {
344
+ el.querySelector("a")!.href = item.action.href
345
+ }
346
+ }
347
+ root.querySelector("button")!.addEventListener("click", () =>
348
+ toast("Invoice sent", {
349
+ description: "Hollis Grant · $240.00",
350
+ action: { label: "View", href: "#" },
351
+ })
352
+ )
353
+ return () => {
354
+ toast.dismiss()
355
+ }
356
+ }
357
+
358
+ export { mount }
359
+ ```
360
+
361
+ Press Send Invoice, then follow View in the toast.
362
+
363
+ ## Promise
364
+
365
+ `toast.promise()` shows a loading toast, then updates the same toast when the promise resolves or rejects. Each message can be a string, options with a description or an action, or a function of the result. A toast dismissed while loading stays closed.
366
+
367
+ ```ts title="promise.ts"
368
+ import "@ui-sdk/web/toast"
369
+ import { createToaster } from "@ui-sdk/web"
370
+
371
+ function mount(root: HTMLElement) {
372
+ const toast = createToaster()
373
+ let attempts = 0
374
+
375
+ function save() {
376
+ const succeeds = ++attempts % 2 === 1
377
+ return new Promise<void>((resolve, reject) =>
378
+ setTimeout(
379
+ () => (succeeds ? resolve() : reject(new Error("Network error"))),
380
+ 1500
381
+ )
382
+ )
383
+ }
384
+
385
+ function saveChanges() {
386
+ toast.promise(save, {
387
+ loading: "Saving changes…",
388
+ success: "Changes saved",
389
+ error: {
390
+ title: "Couldn't save changes",
391
+ description: "Check your connection and try again.",
392
+ action: { label: "Retry", onAction: saveChanges },
393
+ },
394
+ })
395
+ }
396
+
397
+ root.innerHTML = `
398
+ <button>Save Changes</button>
399
+ <ui-toast-region>
400
+ <template>
401
+ <ui-toast>
402
+ <div data-slot="stack">
403
+ <ui-toast-title></ui-toast-title>
404
+ <ui-toast-description></ui-toast-description>
405
+ </div>
406
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
407
+ </ui-toast>
408
+ </template>
409
+ </ui-toast-region>
410
+ `
411
+ root.querySelector("ui-toast-region")!.toaster = toast
412
+ root.querySelector("button")!.addEventListener("click", saveChanges)
413
+ return () => {
414
+ toast.dismiss()
415
+ }
416
+ }
417
+
418
+ export { mount }
419
+ ```
420
+
421
+ Press Save Changes to see Saving changes become Changes saved. Press it again for the error, then choose Retry.
422
+
423
+ ## Stacking
424
+
425
+ `max-visible` limits how many toasts show at once, three by default; the rest wait in the queue, and their timers start when they show. The stack expands while the pointer or focus is in it. Set `expanded` to keep it open. [Styling](#styling) shows the CSS that lays out the stack.
426
+
427
+ ```ts title="stacking.ts"
428
+ import "@ui-sdk/web/checkbox"
429
+ import "@ui-sdk/web/toast"
430
+ import { createToaster } from "@ui-sdk/web"
431
+ import { Check, createElement } from "lucide"
432
+
433
+ const notifications = [
434
+ { title: "Event created", description: "Friday, June 12 at 10:00 AM" },
435
+ { title: "Message sent" },
436
+ {
437
+ title: "Hollis Grant joined",
438
+ description: "They can now edit the Launch plan and see its comments.",
439
+ },
440
+ { title: "Changes saved" },
441
+ { title: "Invoice sent", description: "Inès Moreau · $240.00" },
442
+ { title: "Photos uploaded", description: "12 photos added to Summer trip" },
443
+ ]
444
+
445
+ function mount(root: HTMLElement) {
446
+ const toast = createToaster()
447
+ let count = 0
448
+ root.innerHTML = `
449
+ <div data-slot="stack">
450
+ <div data-slot="controls">
451
+ <label data-slot="label">
452
+ <ui-checkbox>
453
+ <ui-checkbox-indicator>${createElement(Check, { "aria-hidden": "true" }).outerHTML}</ui-checkbox-indicator>
454
+ </ui-checkbox>
455
+ Always expanded
456
+ </label>
457
+ </div>
458
+ <button>Add Toast</button>
459
+ <ui-toast-region max-visible="4">
460
+ <template>
461
+ <ui-toast>
462
+ <div data-slot="stack">
463
+ <ui-toast-title></ui-toast-title>
464
+ <ui-toast-description></ui-toast-description>
465
+ </div>
466
+ </ui-toast>
467
+ </template>
468
+ </ui-toast-region>
469
+ </div>
470
+ `
471
+ const region = root.querySelector("ui-toast-region")!
472
+ region.toaster = toast
473
+ root
474
+ .querySelector("ui-checkbox")!
475
+ .addEventListener("checkedchange", (event) => {
476
+ region.expanded = event.detail.value === true
477
+ })
478
+ root
479
+ .querySelector("button")!
480
+ .addEventListener("click", () =>
481
+ toast(notifications[count++ % notifications.length])
482
+ )
483
+ return () => {
484
+ toast.dismiss()
485
+ }
486
+ }
487
+
488
+ export { mount }
489
+ ```
490
+
491
+ Press Add Toast a few times, then hover the stack to expand it. Past four toasts, the rest wait their turn. Check Always expanded to keep it open.
492
+
493
+ ## Duration
494
+
495
+ Set `duration` in milliseconds, on the toaster or on one toast, or `Infinity` for a toast that stays until it's dismissed. The default is five seconds. Timers pause while the pointer or focus is in the region, and while the page is hidden or its window is inactive.
496
+
497
+ ```ts title="duration.ts"
498
+ import "@ui-sdk/web/toast"
499
+ import { createToaster } from "@ui-sdk/web"
500
+
501
+ function mount(root: HTMLElement) {
502
+ const toast = createToaster()
503
+ root.innerHTML = `
504
+ <div data-slot="row">
505
+ <button>1 Second</button>
506
+ <button>5 Seconds</button>
507
+ <button>Until Dismissed</button>
508
+ </div>
509
+ <ui-toast-region>
510
+ <template>
511
+ <ui-toast>
512
+ <ui-toast-title></ui-toast-title>
513
+ <ui-toast-close><button data-variant="solid"></button></ui-toast-close>
514
+ </ui-toast>
515
+ </template>
516
+ </ui-toast-region>
517
+ `
518
+ root.querySelector("ui-toast-region")!.toaster = toast
519
+ const [second, seconds, untilDismissed] = root.querySelectorAll("button")
520
+ second.addEventListener("click", () =>
521
+ toast("Link copied", { duration: 1000 })
522
+ )
523
+ seconds.addEventListener("click", () => toast("Changes saved"))
524
+ untilDismissed.addEventListener("click", () =>
525
+ toast("Your session expires in 5 minutes", {
526
+ duration: Infinity,
527
+ dismissible: false,
528
+ cancel: { label: "Got It" },
529
+ })
530
+ )
531
+ return () => {
532
+ toast.dismiss()
533
+ }
534
+ }
535
+
536
+ export { mount }
537
+ ```
538
+
539
+ Press each button. Hover a toast to pause its timer. The session toast stays until you press Got It.
540
+
541
+ ## Update and Dismiss
542
+
543
+ Keep the id `toast()` returns to update or dismiss that toast, or pass your own `id`. `toast.update()` returns whether the toast was still there, and `toast.dismiss()` without an id closes every toast.
544
+
545
+ ```ts title="update.ts"
546
+ import "@ui-sdk/web/toast"
547
+ import { createToaster } from "@ui-sdk/web"
548
+ import { CircleCheck, createElement, LoaderCircle } from "lucide"
549
+ import { log } from "./log"
550
+
551
+ function mount(root: HTMLElement) {
552
+ const toast = createToaster()
553
+ let timer: ReturnType<typeof setInterval> | undefined
554
+
555
+ function upload() {
556
+ clearInterval(timer)
557
+ const id = toast.loading("Uploading report.pdf… 0%", { id: "upload" })
558
+ let progress = 0
559
+ timer = setInterval(() => {
560
+ progress += 20
561
+ const done = progress >= 100
562
+ const open = toast.update(
563
+ id,
564
+ done
565
+ ? { title: "Report uploaded", type: "success" }
566
+ : { title: `Uploading report.pdf… ${progress}%` }
567
+ )
568
+ if (!open) {
569
+ log(root, "Upload canceled")
570
+ }
571
+ if (done || !open) {
572
+ clearInterval(timer)
573
+ }
574
+ }, 700)
575
+ }
576
+
577
+ root.innerHTML = `
578
+ <div data-slot="row">
579
+ <button>Upload Report</button>
580
+ <button>Cancel Upload</button>
581
+ <button>Dismiss All</button>
582
+ </div>
583
+ <ui-toast-region>
584
+ <template>
585
+ <ui-toast>
586
+ ${createElement(CircleCheck, { "data-show": "success", "aria-hidden": "true" }).outerHTML}
587
+ ${createElement(LoaderCircle, { "data-show": "loading", "aria-hidden": "true" }).outerHTML}
588
+ <ui-toast-title></ui-toast-title>
589
+ </ui-toast>
590
+ </template>
591
+ </ui-toast-region>
592
+ `
593
+ root.querySelector("ui-toast-region")!.toaster = toast
594
+ const [start, cancel, dismissAll] = root.querySelectorAll("button")
595
+ start.addEventListener("click", upload)
596
+ cancel.addEventListener("click", () => toast.dismiss("upload"))
597
+ dismissAll.addEventListener("click", () => toast.dismiss())
598
+ return () => {
599
+ clearInterval(timer)
600
+ toast.dismiss()
601
+ }
602
+ }
603
+
604
+ export { mount }
605
+ ```
606
+
607
+ Press Upload Report and watch one toast count up to Report uploaded. Cancel Upload closes it early, and Dismiss All clears every toast.
608
+
609
+ ## Async Action
610
+
611
+ Return a promise from an action to keep the toast open while it runs. Its button gets `data-pending` while it runs and ignores presses until it settles, and the action can change the button's text to say Restoring…, or offer a retry if it fails. See [Button](./button.md#changes-after-an-await) for changes made after an `await`.
612
+
613
+ ```ts title="async-action.ts"
614
+ import "@ui-sdk/web/toast"
615
+ import { createToaster } from "@ui-sdk/web"
616
+ import { log } from "./log"
617
+
618
+ const restore = () => new Promise((resolve) => setTimeout(resolve, 1500))
619
+
620
+ function mount(root: HTMLElement) {
621
+ const toast = createToaster({ duration: 6000 })
622
+ root.innerHTML = `
623
+ <button>Delete File</button>
624
+ <ui-toast-region>
625
+ <template>
626
+ <ui-toast>
627
+ <div data-slot="stack">
628
+ <ui-toast-title></ui-toast-title>
629
+ <ui-toast-description></ui-toast-description>
630
+ </div>
631
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
632
+ </ui-toast>
633
+ </template>
634
+ </ui-toast-region>
635
+ `
636
+ root.querySelector("ui-toast-region")!.toaster = toast
637
+ root.querySelector("button")!.addEventListener("click", () =>
638
+ toast("File deleted", {
639
+ description: "Q3 report.pdf",
640
+ action: {
641
+ label: "Undo",
642
+ onAction: async (event) => {
643
+ const button = (event?.target as Element | undefined)?.closest(
644
+ "button"
645
+ )
646
+ if (button) {
647
+ button.textContent = "Restoring…"
648
+ }
649
+ try {
650
+ await restore()
651
+ } catch (error) {
652
+ if (button) {
653
+ button.textContent = "Retry"
654
+ }
655
+ throw error
656
+ }
657
+ log(root, "Q3 report.pdf restored")
658
+ },
659
+ },
660
+ })
661
+ )
662
+ return () => {
663
+ toast.dismiss()
664
+ }
665
+ }
666
+
667
+ export { mount }
668
+ ```
669
+
670
+ Press Delete File, then Undo. The button shows Restoring… until the restore finishes, then the toast closes.
671
+
672
+ ## Keyboard Shortcut
673
+
674
+ F6 moves focus to the newest toast and back. Set the region's `shortcut` to use another key, or `none` to turn it off. The region advertises it through `aria-keyshortcuts`.
675
+
676
+ ```ts title="shortcut.ts"
677
+ import "@ui-sdk/web/toast"
678
+ import { createToaster } from "@ui-sdk/web"
679
+ import { log } from "./log"
680
+
681
+ function mount(root: HTMLElement) {
682
+ const toast = createToaster({ duration: 10000 })
683
+ root.innerHTML = `
684
+ <button>Send Message</button>
685
+ <ui-toast-region shortcut="alt+t" aria-label="Alerts">
686
+ <template>
687
+ <ui-toast>
688
+ <ui-toast-title></ui-toast-title>
689
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
690
+ </ui-toast>
691
+ </template>
692
+ </ui-toast-region>
693
+ `
694
+ root.querySelector("ui-toast-region")!.toaster = toast
695
+ root.querySelector("button")!.addEventListener("click", () =>
696
+ toast("Message sent", {
697
+ action: { label: "Undo", onAction: () => log(root, "Message unsent") },
698
+ })
699
+ )
700
+ return () => {
701
+ toast.dismiss()
702
+ }
703
+ }
704
+
705
+ export { mount }
706
+ ```
707
+
708
+ Press Send Message, then Alt+T (Option+T on a Mac) to focus the toast. Press Escape to dismiss it, or Alt+T again to go back.
709
+
710
+ ## Overlay Host and Confirm
711
+
712
+ Instead of placing a region, add one `ui-overlay-host` near your app's root. It renders the toaster's region and `confirm()` questions as alert dialogs. Set its `toast` property before it connects: `attributes` go on the region, and `template` holds the `ui-toast` each toast copies. A region you place yourself takes over from the host for its toaster.
713
+
714
+ To style the question, render a `ui-alert-dialog` with the confirm controller and read the question from its `payloadchange` event. [Alert Dialog](./alert-dialog.md) covers `createConfirm()` in more detail.
715
+
716
+ ```ts title="overlay-host.ts"
717
+ import "@ui-sdk/web/alert-dialog"
718
+ import "@ui-sdk/web/overlays"
719
+ import {
720
+ createConfirm,
721
+ createOverlays,
722
+ createToaster,
723
+ type ConfirmOptions,
724
+ type UiAlertDialogElement,
725
+ } from "@ui-sdk/web"
726
+ import { CircleCheck, createElement } from "lucide"
727
+
728
+ const names = ["Acme", "Globex", "Initech"]
729
+
730
+ function mount(root: HTMLElement) {
731
+ const overlays = createOverlays()
732
+ const toast = createToaster({ overlays })
733
+ const confirm = createConfirm({ overlays })
734
+ let projects = names
735
+ root.innerHTML = `
736
+ <div data-slot="stack">
737
+ <div data-slot="controls">
738
+ <button type="button">Reset Projects</button>
739
+ </div>
740
+ <ul data-slot="list" aria-label="Projects"></ul>
741
+ <ui-alert-dialog>
742
+ <ui-alert-dialog-backdrop hidden></ui-alert-dialog-backdrop>
743
+ <ui-alert-dialog-content hidden>
744
+ <div data-slot="stack">
745
+ <ui-alert-dialog-title></ui-alert-dialog-title>
746
+ <ui-alert-dialog-description></ui-alert-dialog-description>
747
+ </div>
748
+ <div data-slot="row">
749
+ <ui-alert-dialog-close><button></button></ui-alert-dialog-close>
750
+ <ui-alert-dialog-close value="confirm"><button data-variant="solid"></button></ui-alert-dialog-close>
751
+ </div>
752
+ </ui-alert-dialog-content>
753
+ </ui-alert-dialog>
754
+ </div>
755
+ `
756
+ const reset = root.querySelector("button")!
757
+ const list = root.querySelector("ul")!
758
+
759
+ function render() {
760
+ list.innerHTML = projects.length
761
+ ? projects
762
+ .map(
763
+ (name) =>
764
+ `<li data-slot="row">${name}<button type="button" data-size="sm" aria-label="Delete ${name}">Delete</button></li>`
765
+ )
766
+ .join("")
767
+ : `<li data-slot="row">All projects deleted.</li>`
768
+ list.querySelectorAll("button").forEach((button, index) => {
769
+ const name = projects[index]
770
+ button.addEventListener("click", () => remove(name, index))
771
+ })
772
+ }
773
+
774
+ async function remove(name: string, index: number) {
775
+ const confirmed = await confirm({
776
+ title: `Delete ${name}?`,
777
+ description:
778
+ "The project and its files will be deleted for everyone on your team.",
779
+ confirmLabel: "Delete",
780
+ cancelLabel: "Cancel",
781
+ })
782
+ if (!confirmed) {
783
+ return
784
+ }
785
+ projects = projects.filter((project) => project !== name)
786
+ render()
787
+ ;(
788
+ list.querySelectorAll("button")[Math.min(index, projects.length - 1)] ??
789
+ reset
790
+ ).focus()
791
+ toast.success(`${name} deleted`, { priority: "assertive" })
792
+ }
793
+
794
+ reset.addEventListener("click", () => {
795
+ projects = names
796
+ render()
797
+ })
798
+ render()
799
+
800
+ const dialog =
801
+ root.querySelector<UiAlertDialogElement<ConfirmOptions>>("ui-alert-dialog")!
802
+ const [cancel, agree] = dialog.querySelectorAll("button")
803
+ dialog.controller = confirm.controller
804
+ dialog.addEventListener("payloadchange", (event) => {
805
+ const question = event.detail.value
806
+ dialog.querySelector("ui-alert-dialog-title")!.textContent =
807
+ question?.title ?? ""
808
+ dialog.querySelector("ui-alert-dialog-description")!.textContent =
809
+ question?.description ?? ""
810
+ cancel.textContent = question?.cancelLabel ?? ""
811
+ agree.textContent = question?.confirmLabel ?? ""
812
+ })
813
+
814
+ const template = document.createElement("template")
815
+ template.innerHTML = `
816
+ <ui-toast>
817
+ ${createElement(CircleCheck, { "data-show": "success", "aria-hidden": "true" }).outerHTML}
818
+ <ui-toast-title></ui-toast-title>
819
+ </ui-toast>
820
+ `
821
+ dialog.before(
822
+ Object.assign(document.createElement("ui-overlay-host"), {
823
+ overlays,
824
+ toast: { template },
825
+ })
826
+ )
827
+ return () => {
828
+ toast.dismiss()
829
+ }
830
+ }
831
+
832
+ export { mount }
833
+ ```
834
+
835
+ Press Delete on a project and confirm. The row goes away and a toast says so. Reset Projects brings them back.
836
+
837
+ ## Custom Rendering
838
+
839
+ Pass anything else your toast needs in `data`, and read it in the region's `renderToast(toast, el)`, which runs for each toast element when it shows and after every update.
840
+
841
+ ```ts title="custom.ts"
842
+ import "@ui-sdk/web/toast"
843
+ import { createToaster } from "@ui-sdk/web"
844
+ import { createElement, X } from "lucide"
845
+ import { log } from "./log"
846
+
847
+ function mount(root: HTMLElement) {
848
+ const toast = createToaster()
849
+ root.innerHTML = `
850
+ <button>New Message</button>
851
+ <ui-toast-region aria-label="Messages">
852
+ <template>
853
+ <ui-toast>
854
+ <span data-slot="media"></span>
855
+ <div data-slot="stack">
856
+ <ui-toast-title></ui-toast-title>
857
+ <ui-toast-description></ui-toast-description>
858
+ </div>
859
+ <ui-toast-action><button data-variant="solid"></button></ui-toast-action>
860
+ <ui-toast-close>
861
+ <button aria-label="Close">${createElement(X, { "aria-hidden": "true" }).outerHTML}</button>
862
+ </ui-toast-close>
863
+ </ui-toast>
864
+ </template>
865
+ </ui-toast-region>
866
+ `
867
+ const region = root.querySelector("ui-toast-region")!
868
+ region.toaster = toast
869
+ region.renderToast = (item, el) => {
870
+ el.querySelector("[data-slot='media']")!.textContent = (
871
+ item.data as { initials: string }
872
+ ).initials
873
+ }
874
+ root.querySelector("button")!.addEventListener("click", () =>
875
+ toast({
876
+ title: "Hollis Grant",
877
+ description: "Can you review the draft?",
878
+ data: { initials: "HG" },
879
+ action: {
880
+ label: "Reply",
881
+ onAction: () => log(root, "Replying to Hollis Grant"),
882
+ },
883
+ })
884
+ )
885
+ return () => {
886
+ toast.dismiss()
887
+ }
888
+ }
889
+
890
+ export { mount }
891
+ ```
892
+
893
+ Press New Message to show a toast with Hollis Grant's initials. Choose Reply or close it.
894
+
895
+ ## Styling
896
+
897
+ Toasts are unstyled, and the region and its toasts carry what you need to animate a stack:
898
+
899
+ - **The stack.** The region sets `--toast-front-height`, the newest toast's height, and `--toast-stack-height`, all of them added up. Each toast gets `--toast-index`, 0 for the newest, `--toast-offset`, the height of the toasts in front of it, and `--toast-height`, its own height. Position the toasts absolutely in the region and set `height: var(--toast-height)` so changes in height animate.
900
+ - **Collapsed and expanded.** `data-front` marks the newest toast. While the stack is collapsed, clip the toasts behind it to `--toast-front-height` and peek them out by their index. While it's expanded, the region and its toasts get `data-expanded`; move each toast by its `--toast-offset`.
901
+ - **Swiping.** While a toast is swiped it gets `data-swiping`, and `--toast-swipe-x` and `--toast-swipe-y` hold how far it moved. Translate it by them and turn off transitions. When a swipe dismisses it, `data-swipe-direction` says which way, so it can leave in that direction. A mouse drag that starts on selectable text selects it, so set `user-select: none` on toasts to swipe them from anywhere.
902
+ - **Entering and leaving.** A toast has `data-starting-style` for its first frame and `data-ending-style` while it leaves, and stays mounted until its transitions finish.
903
+
904
+ A stack at the bottom of the page, in plain CSS:
905
+
906
+ ```css
907
+ [data-slot="toast-region"] {
908
+ width: 356px;
909
+ height: var(--toast-front-height);
910
+ }
911
+
912
+ [data-slot="toast-region"][data-expanded] {
913
+ height: calc(var(--toast-stack-height) + (var(--toast-count) - 1) * 12px);
914
+ }
915
+
916
+ [data-slot="toast"] {
917
+ --y: calc(var(--toast-index) * -12px);
918
+ position: absolute;
919
+ inset-inline: 0;
920
+ bottom: 0;
921
+ z-index: calc(100 - var(--toast-index));
922
+ overflow: hidden;
923
+ height: var(--toast-height);
924
+ translate: var(--toast-swipe-x, 0px)
925
+ calc(var(--y) + var(--toast-swipe-y, 0px));
926
+ scale: calc(1 - var(--toast-index) * 0.05);
927
+ transition-property: translate, scale, opacity, height;
928
+ transition-duration: 400ms;
929
+ user-select: none;
930
+ }
931
+
932
+ [data-slot="toast"]:not([data-front], [data-expanded]) {
933
+ height: var(--toast-front-height);
934
+ }
935
+
936
+ [data-slot="toast"][data-expanded] {
937
+ --y: calc(-1 * (var(--toast-offset) + var(--toast-index) * 12px));
938
+ scale: 1;
939
+ }
940
+
941
+ [data-slot="toast"][data-starting-style] {
942
+ transition: none;
943
+ }
944
+
945
+ [data-slot="toast"][data-starting-style][data-front] {
946
+ --y: 100%;
947
+ }
948
+
949
+ [data-slot="toast"]:is(
950
+ [data-starting-style]:not([data-front]),
951
+ [data-ending-style]
952
+ ) {
953
+ opacity: 0;
954
+ }
955
+
956
+ [data-slot="toast"][data-swiping] {
957
+ transition: none;
958
+ }
959
+
960
+ @media (prefers-reduced-motion: reduce) {
961
+ [data-slot="toast"] {
962
+ transition-property: opacity;
963
+ }
964
+ }
965
+ ```
966
+
967
+ Each part has a `data-slot`, such as `toast`, and its state attributes are listed under [Data Attributes](#data-attributes). An action's or close's attributes land on its button.
968
+
969
+ ### `<ui-toast-region>`
970
+ - `--toast-front-height`: The newest toast's height. Clip the toasts behind it to it in a collapsed stack.
971
+ - `--toast-stack-height`: The toasts' heights added up, for the height of an expanded stack.
972
+ - `--toast-count`: How many toasts show.
973
+ - `--keyboard-inset`: How many pixels of the page the on-screen keyboard covers, 0 without one.
974
+ - `--visual-viewport-width`: The width of the part of the page you can see.
975
+ - `--visual-viewport-height`: The height of the part of the page you can see, above the keyboard.
976
+ - `--visual-viewport-top`: How far the part of the page you can see is scrolled from the top of the layout, as when the keyboard pushes it up.
977
+
978
+ ### `<ui-toast>`
979
+ - `--toast-index`: The toast's place in the stack, 0 for the newest. A closing toast keeps its place.
980
+ - `--toast-offset`: The height of the toasts in front of this one, in pixels. Add gaps with `--toast-index` to place an expanded stack.
981
+ - `--toast-height`: The toast's own height with its content laid out freely, whatever height it's given. Set it as the height to animate the stack.
982
+ - `--toast-swipe-x`: How far a swipe moved the toast sideways, in pixels. Translate the toast by it.
983
+ - `--toast-swipe-y`: How far a swipe moved the toast up or down, in pixels.
984
+
985
+ ## Data Attributes
986
+
987
+ `ui-toast-title` and `ui-toast-description` have no state attributes. The button in `ui-toast-close` gets `data-pending`, like the one in `ui-toast-action`, while a Promise from its action runs.
988
+
989
+ ### `<ui-toast-region>`
990
+ `[data-slot="toast-region"]`
991
+
992
+ - `data-side` (`top`, `bottom`): The edge of the viewport the region sits on.
993
+ - `data-align` (`start`, `center`, `end`): Where along that edge.
994
+ - `data-expanded`: Present while the stack is expanded: hovered, focused, or always with `expanded`.
995
+ - `data-keyboard`: Present on the region while the on-screen keyboard covers part of the page.
996
+
997
+ ### `<ui-toast>`
998
+ `[data-slot="toast"]`
999
+
1000
+ - `data-type` (`default`, `success`, `error`, `info`, `warning`, `loading`): What the toast is about.
1001
+ - `data-front`: Present on the newest toast, in front of a collapsed stack. A closing toast keeps it while it animates out.
1002
+ - `data-expanded`: Present while the stack is expanded: hovered, focused, or always with `expanded`.
1003
+ - `data-starting-style`: Present for a toast's first frame. Style the state you animate from.
1004
+ - `data-ending-style`: Present while a toast animates out. Style the state you animate to.
1005
+
1006
+ ### `<ui-toast-action>`
1007
+ `[data-slot="toast-action"]`
1008
+
1009
+ - `data-pending`: Present on an action or close button while its handler's Promise runs.
1010
+
1011
+ ## API Reference
1012
+
1013
+ ### Toast
1014
+
1015
+ - `id?` (`string`): Reuses a toast: a toast with this id that's still showing is updated instead of added again.
1016
+ - `title?` (`Content`): The main message.
1017
+ - `description?` (`Content`): More detail, under the title.
1018
+ - `type?` (`ToastType`): What it's about, for styling through `data-type`, and for how it's announced.
1019
+ - `duration?` (`number`): How long it shows, in ms, while nothing pauses it. `Infinity` keeps it until dismissed.
1020
+ - `priority?` (`"assertive" | "polite"`): How screen readers announce it: `"polite"` waits for a pause, `"assertive"` interrupts.
1021
+ - `action?` (`ToastAction<Content>`): A button that does something, like Undo.
1022
+ - `cancel?` (`ToastCancel<Content>`): A button that dismisses it, like Cancel.
1023
+ - `dismissible?` (`boolean`): Whether the user can dismiss it: swiping, Escape and Close parts. Timers and `dismiss()` still close it.
1024
+ - `data?` (`unknown`): Anything else, for your own rendering, like an avatar.
1025
+ - `onDismiss?` (`((details: ToastDismissDetails) => void)`): Runs when it closes, with why. Calling `details.cancel()` keeps it.
1026
+
1027
+ `toast(message, options)` and `toast(options)` return the toast's id. `toast.success`, `.info`, `.warning`, `.error` and `.loading` set the type. `toast.promise(promise, { loading, success, error })` returns the id too, and `toast.update(id, options)` returns whether the toast was still there. `toast.dismiss(id)` closes one, and `toast.dismiss()` every one.
1028
+
1029
+ ### Actions
1030
+
1031
+ - `label` (`Content`): The button's text.
1032
+ - `onAction?` (`((event: Event | undefined, details: ToastActionDetails) => unknown)`): Runs when it's pressed. A returned Promise marks the action pending, then dismisses the toast once it resolves. A rejection keeps the toast. `details.source` says how it was pressed, for changes made after an `await`.
1033
+ - `href?` (`string`): Makes the action a link.
1034
+ - `dismiss?` (`boolean`): Whether pressing it dismisses the toast.
1035
+
1036
+ - `label` (`Content`): The button's text.
1037
+ - `onCancel?` (`((event: Event | undefined, details: ToastActionDetails) => void)`): Runs when it's pressed, before the toast closes. `details.source` says how it was pressed.
1038
+
1039
+ ### ToastRegion
1040
+
1041
+ - `toaster?` (`Toaster<any>`): The queue it shows. A second toaster, from `createToaster()`, gives a second region its own toasts.
1042
+ - `side?` (`"bottom" | "top"`): The edge of the viewport it sits on. Swiping toward it dismisses a toast.
1043
+ - `align?` (`"center" | "end" | "start"`): Where along that edge. `"start"` and `"end"` follow the writing direction, and swiping toward them dismisses too.
1044
+ - `maxVisible?` (`number`): How many toasts show at once. Older ones wait, with their timers stopped, until there's room.
1045
+ - `expanded?` (`boolean`): Whether the stack is always expanded. Otherwise it expands while the pointer or focus is in it.
1046
+ - `shortcut?` (`string | null`): The key that moves focus into the region and back, like `"F6"` or `"alt+t"`. `null` turns it off.
1047
+ - `pendingAnnouncement?` (`string`): What screen readers hear once a toast's action or close button has been pending for a second, so a slow action doesn't pass in silence. Set it in the page's language. An empty string says nothing.
1048
+ - `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.
1049
+
1050
+ ### ToastAction
1051
+
1052
+ - `action event`: Runs when it's pressed, instead of the toast's own `action.onAction`. A returned Promise marks it pending. `details.source` says how it was pressed, for changes made after an `await`.
1053
+ - `dismiss?` (`boolean`): Whether pressing it dismisses the toast.
1054
+
1055
+ ### ToastClose
1056
+
1057
+ - `action?` (`((event: Event | undefined, details: ToastActionDetails) => unknown)`): Runs before the toast closes. A returned Promise keeps it open and the button pending until it settles. `details.source` says how it was pressed, for changes made after an `await`.
1058
+
1059
+ ### Confirm
1060
+
1061
+ - `title` (`string`): The question, like "Delete this project?".
1062
+ - `description?` (`string`): What agreeing does.
1063
+ - `confirmLabel?` (`string`): The agreeing button's text.
1064
+ - `cancelLabel?` (`string`): The other button's text.
1065
+
1066
+ ### State
1067
+
1068
+ `ui-toast-region`:
1069
+
1070
+ - `side` (`"top" | "bottom"`): The edge it sits on.
1071
+ - `align` (`"start" | "center" | "end"`): Where along that edge.
1072
+ - `expanded` (`boolean`): Whether the stack is expanded.
1073
+ - `toasts` (`readonly ToastItem<unknown>[]`): The toasts to render, newest first, including ones animating out.
1074
+
1075
+ `ui-toast`:
1076
+
1077
+ - `type` (`ToastType`): What it's about.
1078
+ - `index` (`number`): Its place in the stack, 0 for the newest.
1079
+ - `front` (`boolean`): Whether it's the newest, on top of a collapsed stack. A closing toast keeps it.
1080
+ - `expanded` (`boolean`): Whether the stack is expanded.
1081
+ - `leaving` (`boolean`): Whether it's animating out.
1082
+
1083
+ `ui-toast-action` and `ui-toast-close`:
1084
+
1085
+ - `pending` (`boolean`): Whether a Promise its handler returned is still running.
1086
+ - `error` (`unknown`): Why its handler failed, until it's pressed again.
1087
+
1088
+ ### Reasons
1089
+
1090
+ - `timeout` (`none`): A duration ran out, like a toast's, or a rotating carousel's interval.
1091
+ - `close-press` (`MouseEvent | KeyboardEvent | SubmitEvent`): A Close part was pressed, or a form with `method="dialog"` was submitted.
1092
+ - `swipe` (`TouchEvent | PointerEvent`): A swipe gesture: a finger, mouse or pen dragged it.
1093
+ - `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
1094
+ - `action` (`MouseEvent | KeyboardEvent`): A Close part's `action` finished.
1095
+ - `imperative` (`none`): A controller or `api` call, or a property set on a web component.
1096
+
1097
+ ## Accessibility
1098
+
1099
+ Toasts are announced through shared [live regions](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions), once each, without making the visible region live: politely by default and assertively for errors. While it has toasts, the region is a landmark named Notifications; set `aria-label` to name it in the page's language. Keep messages short, and use `duration: Infinity` for one that has to stay available.
1100
+
1101
+ ### Keyboard
1102
+
1103
+ F6, or the region's `shortcut`, moves focus to the newest toast, and pressing it again returns focus to where it came from. Tab moves through the toasts and their buttons, and Tab past the last one goes back too. Escape dismisses the focused toast; focus then moves to the next toast, or back where it came from after the last one. The region stays reachable while a modal dialog is open, and its timers pause while focus is inside.
1104
+
1105
+ ### Tested Behavior
1106
+
1107
+ Every line below is an automated test.
1108
+
1109
+ **Showing**
1110
+
1111
+ - A toast shows its title, description and action in the Notifications region.
1112
+ - Newer toasts come first.
1113
+ - The newest toast is marked as the front one.
1114
+ - Each toast says what it's about through data-type.
1115
+ - The region sits on its side and alignment.
1116
+ - It shows above everything, in the top layer.
1117
+ - A promise toast loads, then shows the result.
1118
+ - A toast with an id that's showing is updated in place.
1119
+
1120
+ **Closing**
1121
+
1122
+ - A toast closes after its duration.
1123
+ - Infinity keeps it until it's dismissed.
1124
+ - The Dismiss button closes it.
1125
+ - The action runs and closes it.
1126
+ - Escape on a focused toast closes it.
1127
+ - A closing toast stays while it animates out.
1128
+ - A toast that can't be dismissed ignores Escape.
1129
+
1130
+ **Timers**
1131
+
1132
+ - Hovering the region pauses its timers, and leaving resumes them.
1133
+ - Focus in the region pauses its timers.
1134
+
1135
+ **Keyboard**
1136
+
1137
+ - F6 moves focus to the newest toast, and again back where it was.
1138
+ - The shortcut is configurable.
1139
+ - The region names its shortcut.
1140
+ - When the focused toast closes, focus goes to the next one, then back where it was.
1141
+
1142
+ **Stacking**
1143
+
1144
+ - Only maxVisible toasts show; the rest wait for room.
1145
+ - The stack expands while hovered or focused.
1146
+ - Expanded keeps the stack expanded.
1147
+ - Toasts measure their heights and offsets for the stack.
1148
+ - A toast measures its content's height, whatever height it's given.
1149
+ - A toast given its measured height animates to a new one when its content changes.
1150
+ - A toast measures again when a child, its class or its padding changes.
1151
+ - A toast closing from the front stays in front while it animates out.
1152
+
1153
+ **Swiping**
1154
+
1155
+ - Swiping toward the region's side dismisses.
1156
+ - Swiping toward the aligned edge dismisses too.
1157
+ - A short swipe snaps back.
1158
+ - Swiping away from the side never dismisses.
1159
+ - A toast that can't be dismissed doesn't swipe.
1160
+
1161
+ **Over a modal dialog**
1162
+
1163
+ - A toast shown from a modal dialog is visible, usable and above it.
1164
+
1165
+ **Updates after closing**
1166
+
1167
+ - A promise toast dismissed while loading stays closed.
1168
+ - An update after a toast closed never brings it back.
1169
+
1170
+ **More pausing and keys**
1171
+
1172
+ - The window losing focus pauses timers, and getting it back resumes them.
1173
+ - F6 does nothing while there are no toasts, so the browser keeps it.
1174
+ - A toast on the top edge swipes up, and a swipe down snaps back.
1175
+
1176
+ Runs in React, Vue and web components.
1177
+
1178
+ Also tested:
1179
+
1180
+ **Enhancements**
1181
+
1182
+ - Update() says whether the toast was still there.
1183
+ - A toast beyond maxVisible never expires unseen.
1184
+ - There's no empty Notifications landmark.
1185
+ - Focus never falls to the page when a toast focused by the mouse closes.
1186
+ - A pending action shows it and holds the toast open until it settles.
1187
+
1188
+ **Pausing**
1189
+
1190
+ - A hidden page pauses timers.
1191
+ - Pause reasons hold separately: getting the window back doesn't resume while focus is in the region.
1192
+
1193
+ **Announcements**
1194
+
1195
+ - The live regions exist before the first toast.
1196
+ - A toast is announced politely, with its title and description.
1197
+ - An error is announced assertively.
1198
+ - Toasts that arrive together are announced together.
1199
+ - The visible region isn't a live region, so nothing is read twice.
1200
+
1201
+ **The shortcut**
1202
+
1203
+ - F6 works from a text field and types nothing.
1204
+ - A shortcut of null turns it off.
1205
+ - Tab past the last toast goes back where F6 came from.
1206
+
1207
+ **Over modal dialogs**
1208
+
1209
+ - F6 reaches the toasts from inside a modal dialog, and goes back into it.
1210
+ - Escape on a toast closes the toast, not the dialog beneath.
1211
+ - A dialog opened after a toast doesn't cover it, and pressing it doesn't close the dialog.
1212
+
1213
+ **Swiping**
1214
+
1215
+ - Dragging across a toast's text with a mouse selects it instead of dismissing.
1216
+
1217
+ Runs in React, Vue and web components.
1218
+
1219
+ Screen readers hear the same thing in each tested framework, recorded by a virtual screen reader:
1220
+
1221
+ - Announcements while reaching a toast with F6 and leaving it.
1222
+
1223
+ Runs in React, Vue and web components.