@vielzeug/refine 26.10.0 → 26.10.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 (463) hide show
  1. package/README.md +1 -1
  2. package/dist/accordion-item.cjs.map +1 -1
  3. package/dist/accordion-item.js.map +1 -1
  4. package/dist/accordion.cjs.map +1 -1
  5. package/dist/accordion.js.map +1 -1
  6. package/dist/async.cjs.map +1 -1
  7. package/dist/async.js.map +1 -1
  8. package/dist/badge.cjs.map +1 -1
  9. package/dist/badge.js.map +1 -1
  10. package/dist/box.cjs.map +1 -1
  11. package/dist/box.js.map +1 -1
  12. package/dist/button.cjs +3 -3
  13. package/dist/button.cjs.map +1 -1
  14. package/dist/button.js +3 -3
  15. package/dist/button.js.map +1 -1
  16. package/dist/calendar.cjs.map +1 -1
  17. package/dist/calendar.js.map +1 -1
  18. package/dist/carousel.cjs.map +1 -1
  19. package/dist/carousel.js.map +1 -1
  20. package/dist/chat-message.cjs.map +1 -1
  21. package/dist/chat-message.js.map +1 -1
  22. package/dist/chat-panel.cjs.map +1 -1
  23. package/dist/chat-panel.js.map +1 -1
  24. package/dist/checkbox-group.cjs.map +1 -1
  25. package/dist/checkbox-group.js.map +1 -1
  26. package/dist/chip.cjs.map +1 -1
  27. package/dist/chip.js.map +1 -1
  28. package/dist/code-window.cjs.map +1 -1
  29. package/dist/code-window.js.map +1 -1
  30. package/dist/combobox.cjs.map +1 -1
  31. package/dist/combobox.js.map +1 -1
  32. package/dist/command-palette.cjs.map +1 -1
  33. package/dist/command-palette.js.map +1 -1
  34. package/dist/content/card/card.css.cjs.map +1 -1
  35. package/dist/content/card/card.css.js.map +1 -1
  36. package/dist/content/carousel/carousel-slide.css.cjs.map +1 -1
  37. package/dist/content/carousel/carousel-slide.css.js.map +1 -1
  38. package/dist/content/carousel/carousel.css.cjs.map +1 -1
  39. package/dist/content/carousel/carousel.css.js.map +1 -1
  40. package/dist/content/carousel/carousel.d.ts +5 -5
  41. package/dist/content/chat-message/chat-message.css.cjs +1 -1
  42. package/dist/content/chat-message/chat-message.css.cjs.map +1 -1
  43. package/dist/content/chat-message/chat-message.css.js +1 -1
  44. package/dist/content/chat-message/chat-message.css.js.map +1 -1
  45. package/dist/content/chat-message/chat-message.d.ts +4 -4
  46. package/dist/content/chat-message/chat-message.d.ts.map +1 -1
  47. package/dist/content/chat-panel/chat-panel.d.ts +1 -1
  48. package/dist/content/code-window/code-window.css.cjs.map +1 -1
  49. package/dist/content/code-window/code-window.css.js.map +1 -1
  50. package/dist/content/code-window/code-window.d.ts +4 -4
  51. package/dist/content/index.d.ts +4 -0
  52. package/dist/content/index.d.ts.map +1 -1
  53. package/dist/content/list/_list-item-reveal.cjs.map +1 -1
  54. package/dist/content/list/_list-item-reveal.d.ts +4 -4
  55. package/dist/content/list/_list-item-reveal.d.ts.map +1 -1
  56. package/dist/content/list/_list-item-reveal.js.map +1 -1
  57. package/dist/content/list/list-item.css.cjs.map +1 -1
  58. package/dist/content/list/list-item.css.js.map +1 -1
  59. package/dist/content/list/list-item.d.ts +8 -8
  60. package/dist/content/list/list-item.d.ts.map +1 -1
  61. package/dist/content/list/list.d.ts +8 -8
  62. package/dist/content/list/list.d.ts.map +1 -1
  63. package/dist/content/qr-code/qr-code.d.ts +1 -1
  64. package/dist/content/rank-list/rank-item.css.cjs +2 -0
  65. package/dist/content/rank-list/rank-item.css.cjs.map +1 -0
  66. package/dist/content/rank-list/rank-item.css.js +2 -0
  67. package/dist/content/rank-list/rank-item.css.js.map +1 -0
  68. package/dist/content/rank-list/rank-item.d.ts +68 -0
  69. package/dist/content/rank-list/rank-item.d.ts.map +1 -0
  70. package/dist/content/rank-list/rank-list.css.cjs +2 -0
  71. package/dist/content/rank-list/rank-list.css.cjs.map +1 -0
  72. package/dist/content/rank-list/rank-list.css.js +2 -0
  73. package/dist/content/rank-list/rank-list.css.js.map +1 -0
  74. package/dist/content/rank-list/rank-list.d.ts +44 -0
  75. package/dist/content/rank-list/rank-list.d.ts.map +1 -0
  76. package/dist/content/separator/separator.d.ts +1 -1
  77. package/dist/content/separator/separator.d.ts.map +1 -1
  78. package/dist/content/speech-player/speech-player.css.cjs.map +1 -1
  79. package/dist/content/speech-player/speech-player.css.js.map +1 -1
  80. package/dist/content/speech-player/speech-player.d.ts +12 -12
  81. package/dist/content/speech-player/speech-player.d.ts.map +1 -1
  82. package/dist/content/stepper/step.css.cjs.map +1 -1
  83. package/dist/content/stepper/step.css.js.map +1 -1
  84. package/dist/content/stepper/step.d.ts +3 -3
  85. package/dist/content/stepper/step.d.ts.map +1 -1
  86. package/dist/content/stepper/stepper.css.cjs.map +1 -1
  87. package/dist/content/stepper/stepper.css.js.map +1 -1
  88. package/dist/content/stepper/stepper.d.ts +3 -3
  89. package/dist/content/stepper/stepper.d.ts.map +1 -1
  90. package/dist/content/table/table.css.cjs.map +1 -1
  91. package/dist/content/table/table.css.js.map +1 -1
  92. package/dist/content/table/table.d.ts +3 -3
  93. package/dist/content/table/table.d.ts.map +1 -1
  94. package/dist/content/text/text.css.cjs.map +1 -1
  95. package/dist/content/text/text.css.js.map +1 -1
  96. package/dist/content/text/text.d.ts +2 -2
  97. package/dist/content/text/text.d.ts.map +1 -1
  98. package/dist/cookie-banner.cjs.map +1 -1
  99. package/dist/cookie-banner.js.map +1 -1
  100. package/dist/copy-command.cjs +1 -1
  101. package/dist/copy-command.cjs.map +1 -1
  102. package/dist/copy-command.js +1 -1
  103. package/dist/copy-command.js.map +1 -1
  104. package/dist/core/announcer.cjs.map +1 -1
  105. package/dist/core/announcer.d.ts +2 -2
  106. package/dist/core/announcer.js.map +1 -1
  107. package/dist/core/aria-reflection.cjs.map +1 -1
  108. package/dist/core/aria-reflection.d.ts +3 -3
  109. package/dist/core/aria-reflection.js.map +1 -1
  110. package/dist/core/auto-resize.cjs.map +1 -1
  111. package/dist/core/auto-resize.d.ts +1 -1
  112. package/dist/core/auto-resize.js.map +1 -1
  113. package/dist/core/checkable.cjs.map +1 -1
  114. package/dist/core/checkable.d.ts +2 -2
  115. package/dist/core/checkable.d.ts.map +1 -1
  116. package/dist/core/checkable.js.map +1 -1
  117. package/dist/core/choice-field.cjs.map +1 -1
  118. package/dist/core/choice-field.d.ts +3 -3
  119. package/dist/core/choice-field.d.ts.map +1 -1
  120. package/dist/core/choice-field.js.map +1 -1
  121. package/dist/core/composer.cjs.map +1 -1
  122. package/dist/core/composer.d.ts +4 -4
  123. package/dist/core/composer.d.ts.map +1 -1
  124. package/dist/core/composer.js.map +1 -1
  125. package/dist/core/date-picker.cjs.map +1 -1
  126. package/dist/core/date-picker.d.ts +5 -5
  127. package/dist/core/date-picker.d.ts.map +1 -1
  128. package/dist/core/date-picker.js.map +1 -1
  129. package/dist/core/direction.cjs.map +1 -1
  130. package/dist/core/direction.d.ts +1 -1
  131. package/dist/core/direction.js.map +1 -1
  132. package/dist/core/field-base.cjs.map +1 -1
  133. package/dist/core/field-base.d.ts +9 -9
  134. package/dist/core/field-base.d.ts.map +1 -1
  135. package/dist/core/field-base.js.map +1 -1
  136. package/dist/core/focus.cjs.map +1 -1
  137. package/dist/core/focus.d.ts +1 -1
  138. package/dist/core/focus.js.map +1 -1
  139. package/dist/core/icon-registry.cjs.map +1 -1
  140. package/dist/core/icon-registry.d.ts +1 -1
  141. package/dist/core/icon-registry.js.map +1 -1
  142. package/dist/core/icons.cjs.map +1 -1
  143. package/dist/core/icons.js.map +1 -1
  144. package/dist/core/keyboard.cjs.map +1 -1
  145. package/dist/core/keyboard.d.ts +1 -1
  146. package/dist/core/keyboard.js.map +1 -1
  147. package/dist/core/numbers.cjs.map +1 -1
  148. package/dist/core/numbers.d.ts +1 -1
  149. package/dist/core/numbers.js.map +1 -1
  150. package/dist/core/overlay.cjs.map +1 -1
  151. package/dist/core/overlay.d.ts +6 -6
  152. package/dist/core/overlay.js.map +1 -1
  153. package/dist/core/parse.cjs.map +1 -1
  154. package/dist/core/parse.d.ts +1 -1
  155. package/dist/core/parse.js.map +1 -1
  156. package/dist/core/positioner.cjs.map +1 -1
  157. package/dist/core/positioner.d.ts +3 -3
  158. package/dist/core/positioner.js.map +1 -1
  159. package/dist/core/ref-callback.cjs.map +1 -1
  160. package/dist/core/ref-callback.d.ts +2 -2
  161. package/dist/core/ref-callback.d.ts.map +1 -1
  162. package/dist/core/ref-callback.js.map +1 -1
  163. package/dist/core/text-field.cjs.map +1 -1
  164. package/dist/core/text-field.d.ts +6 -6
  165. package/dist/core/text-field.d.ts.map +1 -1
  166. package/dist/core/text-field.js.map +1 -1
  167. package/dist/counter.cjs +1 -0
  168. package/dist/counter.cjs.map +1 -1
  169. package/dist/counter.js +1 -0
  170. package/dist/counter.js.map +1 -1
  171. package/dist/custom-elements.json +315 -87
  172. package/dist/datagrid.cjs.map +1 -1
  173. package/dist/datagrid.js.map +1 -1
  174. package/dist/date-picker.cjs +1 -1
  175. package/dist/date-picker.cjs.map +1 -1
  176. package/dist/date-picker.js +1 -1
  177. package/dist/date-picker.js.map +1 -1
  178. package/dist/dialog.cjs.map +1 -1
  179. package/dist/dialog.js.map +1 -1
  180. package/dist/disclosure/accordion-item/accordion-item.css.cjs +1 -1
  181. package/dist/disclosure/accordion-item/accordion-item.css.cjs.map +1 -1
  182. package/dist/disclosure/accordion-item/accordion-item.css.js +1 -1
  183. package/dist/disclosure/accordion-item/accordion-item.css.js.map +1 -1
  184. package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
  185. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  186. package/dist/drawer.cjs.map +1 -1
  187. package/dist/drawer.js.map +1 -1
  188. package/dist/feedback/alert/alert.css.cjs.map +1 -1
  189. package/dist/feedback/alert/alert.css.js.map +1 -1
  190. package/dist/feedback/badge/badge.css.cjs.map +1 -1
  191. package/dist/feedback/badge/badge.css.js.map +1 -1
  192. package/dist/feedback/badge/badge.d.ts +1 -1
  193. package/dist/feedback/badge/badge.d.ts.map +1 -1
  194. package/dist/feedback/chip/chip.css.cjs.map +1 -1
  195. package/dist/feedback/chip/chip.css.js.map +1 -1
  196. package/dist/feedback/chip/chip.d.ts +3 -3
  197. package/dist/feedback/chip/chip.d.ts.map +1 -1
  198. package/dist/feedback/cookie-banner/cookie-banner.css.cjs.map +1 -1
  199. package/dist/feedback/cookie-banner/cookie-banner.css.js.map +1 -1
  200. package/dist/feedback/cookie-banner/cookie-banner.d.ts +8 -8
  201. package/dist/feedback/cookie-banner/cookie-banner.d.ts.map +1 -1
  202. package/dist/feedback/progress/progress.css.cjs.map +1 -1
  203. package/dist/feedback/progress/progress.css.js.map +1 -1
  204. package/dist/feedback/progress/progress.d.ts +1 -1
  205. package/dist/feedback/progress/progress.d.ts.map +1 -1
  206. package/dist/feedback/skeleton/skeleton.css.cjs.map +1 -1
  207. package/dist/feedback/skeleton/skeleton.css.js.map +1 -1
  208. package/dist/feedback/skeleton/skeleton.d.ts +1 -1
  209. package/dist/feedback/skeleton/skeleton.d.ts.map +1 -1
  210. package/dist/feedback/toast/toast.css.cjs +1 -1
  211. package/dist/feedback/toast/toast.css.cjs.map +1 -1
  212. package/dist/feedback/toast/toast.css.js +1 -1
  213. package/dist/feedback/toast/toast.css.js.map +1 -1
  214. package/dist/feedback/toast/toast.d.ts +1 -1
  215. package/dist/feedback/toast/toast.d.ts.map +1 -1
  216. package/dist/feedback/typing-indicator/typing-indicator.d.ts +2 -2
  217. package/dist/file-input.cjs +1 -1
  218. package/dist/file-input.cjs.map +1 -1
  219. package/dist/file-input.js +1 -1
  220. package/dist/file-input.js.map +1 -1
  221. package/dist/frameworks/elements.d.ts +1 -1
  222. package/dist/grid-item.cjs.map +1 -1
  223. package/dist/grid-item.js.map +1 -1
  224. package/dist/grid.cjs.map +1 -1
  225. package/dist/grid.js.map +1 -1
  226. package/dist/icon.cjs.map +1 -1
  227. package/dist/icon.js.map +1 -1
  228. package/dist/input.cjs.map +1 -1
  229. package/dist/input.js.map +1 -1
  230. package/dist/inputs/button/button.css.cjs.map +1 -1
  231. package/dist/inputs/button/button.css.js.map +1 -1
  232. package/dist/inputs/button/button.d.ts +3 -3
  233. package/dist/inputs/button/button.d.ts.map +1 -1
  234. package/dist/inputs/calendar/calendar.css.cjs.map +1 -1
  235. package/dist/inputs/calendar/calendar.css.js.map +1 -1
  236. package/dist/inputs/calendar/calendar.d.ts +2 -2
  237. package/dist/inputs/checkbox-group/checkbox-group.d.ts +2 -2
  238. package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -1
  239. package/dist/inputs/combobox/combobox.css.cjs.map +1 -1
  240. package/dist/inputs/combobox/combobox.css.js.map +1 -1
  241. package/dist/inputs/counter/counter.css.cjs +1 -1
  242. package/dist/inputs/counter/counter.css.cjs.map +1 -1
  243. package/dist/inputs/counter/counter.css.js +1 -1
  244. package/dist/inputs/counter/counter.css.js.map +1 -1
  245. package/dist/inputs/counter/counter.d.ts +2 -1
  246. package/dist/inputs/counter/counter.d.ts.map +1 -1
  247. package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
  248. package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
  249. package/dist/inputs/datagrid/datagrid.d.ts +5 -5
  250. package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
  251. package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
  252. package/dist/inputs/date-picker/date-picker.d.ts +1 -1
  253. package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
  254. package/dist/inputs/file-input/file-input-upload.d.ts +6 -6
  255. package/dist/inputs/file-input/file-input-upload.js.map +1 -1
  256. package/dist/inputs/file-input/file-input.css.cjs.map +1 -1
  257. package/dist/inputs/file-input/file-input.css.js.map +1 -1
  258. package/dist/inputs/file-input/file-input.d.ts +6 -6
  259. package/dist/inputs/input/input.css.cjs +1 -1
  260. package/dist/inputs/input/input.css.cjs.map +1 -1
  261. package/dist/inputs/input/input.css.js +1 -1
  262. package/dist/inputs/input/input.css.js.map +1 -1
  263. package/dist/inputs/input/input.d.ts +6 -6
  264. package/dist/inputs/input/input.d.ts.map +1 -1
  265. package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -1
  266. package/dist/inputs/message-composer/message-composer.css.js.map +1 -1
  267. package/dist/inputs/message-composer/message-composer.d.ts +7 -7
  268. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
  269. package/dist/inputs/number-input/number-input.css.cjs.map +1 -1
  270. package/dist/inputs/number-input/number-input.css.js.map +1 -1
  271. package/dist/inputs/number-input/number-input.d.ts +2 -2
  272. package/dist/inputs/otp-input/otp-input.css.cjs.map +1 -1
  273. package/dist/inputs/otp-input/otp-input.css.js.map +1 -1
  274. package/dist/inputs/qr-scanner/qr-scanner.d.ts +1 -1
  275. package/dist/inputs/qr-scanner/qr-scanner.d.ts.map +1 -1
  276. package/dist/inputs/rating/rating.d.ts +1 -1
  277. package/dist/inputs/rating/rating.d.ts.map +1 -1
  278. package/dist/inputs/select/select.css.cjs +1 -1
  279. package/dist/inputs/select/select.css.cjs.map +1 -1
  280. package/dist/inputs/select/select.css.js +1 -1
  281. package/dist/inputs/select/select.css.js.map +1 -1
  282. package/dist/inputs/select/select.d.ts +1 -1
  283. package/dist/inputs/select/select.d.ts.map +1 -1
  284. package/dist/inputs/shared/field-binding.cjs.map +1 -1
  285. package/dist/inputs/shared/field-binding.d.ts +2 -2
  286. package/dist/inputs/shared/field-binding.d.ts.map +1 -1
  287. package/dist/inputs/shared/field-binding.js.map +1 -1
  288. package/dist/inputs/shared/native-field-event.cjs.map +1 -1
  289. package/dist/inputs/shared/native-field-event.d.ts +1 -1
  290. package/dist/inputs/shared/native-field-event.js.map +1 -1
  291. package/dist/inputs/shared/templates.cjs.map +1 -1
  292. package/dist/inputs/shared/templates.d.ts +3 -3
  293. package/dist/inputs/shared/templates.js.map +1 -1
  294. package/dist/inputs/slider/slider.css.cjs.map +1 -1
  295. package/dist/inputs/slider/slider.css.js.map +1 -1
  296. package/dist/inputs/slider/slider.d.ts +1 -1
  297. package/dist/inputs/slider/slider.d.ts.map +1 -1
  298. package/dist/inputs/textarea/textarea.css.cjs.map +1 -1
  299. package/dist/inputs/textarea/textarea.css.js.map +1 -1
  300. package/dist/inputs/textarea/textarea.d.ts +1 -1
  301. package/dist/inputs/time-picker/time-picker.css.cjs.map +1 -1
  302. package/dist/inputs/time-picker/time-picker.css.js.map +1 -1
  303. package/dist/inputs/time-picker/time-picker.d.ts +1 -1
  304. package/dist/layout/box/box.css.cjs.map +1 -1
  305. package/dist/layout/box/box.css.js.map +1 -1
  306. package/dist/layout/box/box.d.ts +1 -1
  307. package/dist/layout/grid/grid.d.ts +1 -1
  308. package/dist/layout/grid-item/grid-item.d.ts +3 -3
  309. package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
  310. package/dist/layout/navbar/navbar.css.cjs +1 -1
  311. package/dist/layout/navbar/navbar.css.cjs.map +1 -1
  312. package/dist/layout/navbar/navbar.css.js +1 -1
  313. package/dist/layout/navbar/navbar.css.js.map +1 -1
  314. package/dist/layout/navbar/navbar.d.ts +3 -3
  315. package/dist/layout/sidebar/sidebar-item.css.cjs.map +1 -1
  316. package/dist/layout/sidebar/sidebar-item.css.js.map +1 -1
  317. package/dist/layout/sidebar/sidebar.d.ts +5 -5
  318. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  319. package/dist/list-item.cjs.map +1 -1
  320. package/dist/list-item.js.map +1 -1
  321. package/dist/list.cjs.map +1 -1
  322. package/dist/list.js.map +1 -1
  323. package/dist/menu.cjs +6 -5
  324. package/dist/menu.cjs.map +1 -1
  325. package/dist/menu.js +6 -5
  326. package/dist/menu.js.map +1 -1
  327. package/dist/message-composer.cjs.map +1 -1
  328. package/dist/message-composer.js.map +1 -1
  329. package/dist/navbar.cjs.map +1 -1
  330. package/dist/navbar.js.map +1 -1
  331. package/dist/number-input.cjs.map +1 -1
  332. package/dist/number-input.js.map +1 -1
  333. package/dist/otp-input.cjs.map +1 -1
  334. package/dist/otp-input.js.map +1 -1
  335. package/dist/overlay/command-palette/command-palette-items.cjs.map +1 -1
  336. package/dist/overlay/command-palette/command-palette-items.d.ts +1 -1
  337. package/dist/overlay/command-palette/command-palette-items.js.map +1 -1
  338. package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
  339. package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
  340. package/dist/overlay/command-palette/command-palette.d.ts +3 -3
  341. package/dist/overlay/command-palette/command-palette.types.d.ts +6 -6
  342. package/dist/overlay/command-palette/command-palette.types.d.ts.map +1 -1
  343. package/dist/overlay/dialog/dialog.css.cjs +1 -1
  344. package/dist/overlay/dialog/dialog.css.cjs.map +1 -1
  345. package/dist/overlay/dialog/dialog.css.js +1 -1
  346. package/dist/overlay/dialog/dialog.css.js.map +1 -1
  347. package/dist/overlay/dialog/dialog.d.ts +2 -2
  348. package/dist/overlay/dialog/dialog.d.ts.map +1 -1
  349. package/dist/overlay/drawer/drawer.css.cjs.map +1 -1
  350. package/dist/overlay/drawer/drawer.css.js.map +1 -1
  351. package/dist/overlay/drawer/drawer.d.ts +1 -1
  352. package/dist/overlay/drawer/drawer.d.ts.map +1 -1
  353. package/dist/overlay/menu/menu-item.css.cjs.map +1 -1
  354. package/dist/overlay/menu/menu-item.css.js.map +1 -1
  355. package/dist/overlay/menu/menu.d.ts.map +1 -1
  356. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  357. package/dist/overlay/shared/use-dialog.d.ts +6 -6
  358. package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
  359. package/dist/overlay/shared/use-dialog.js.map +1 -1
  360. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  361. package/dist/overlay/shared/use-floating-trigger.d.ts +1 -1
  362. package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
  363. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  364. package/dist/overlay/tooltip/tooltip.css.cjs.map +1 -1
  365. package/dist/overlay/tooltip/tooltip.css.js.map +1 -1
  366. package/dist/progress.cjs.map +1 -1
  367. package/dist/progress.js.map +1 -1
  368. package/dist/qr-code.cjs.map +1 -1
  369. package/dist/qr-code.js.map +1 -1
  370. package/dist/qr-scanner.cjs.map +1 -1
  371. package/dist/qr-scanner.js.map +1 -1
  372. package/dist/radio-group.cjs.map +1 -1
  373. package/dist/radio-group.js.map +1 -1
  374. package/dist/radio.cjs.map +1 -1
  375. package/dist/radio.js.map +1 -1
  376. package/dist/rank-item.cjs +21 -0
  377. package/dist/rank-item.cjs.map +1 -0
  378. package/dist/rank-item.js +21 -0
  379. package/dist/rank-item.js.map +1 -0
  380. package/dist/rank-list.cjs +4 -0
  381. package/dist/rank-list.cjs.map +1 -0
  382. package/dist/rank-list.js +4 -0
  383. package/dist/rank-list.js.map +1 -0
  384. package/dist/rating.cjs.map +1 -1
  385. package/dist/rating.js.map +1 -1
  386. package/dist/refine.cjs +103 -80
  387. package/dist/refine.cjs.map +1 -1
  388. package/dist/refine.iife.js +103 -80
  389. package/dist/refine.iife.js.map +1 -1
  390. package/dist/refine.js +104 -81
  391. package/dist/refine.js.map +1 -1
  392. package/dist/select.cjs.map +1 -1
  393. package/dist/select.js.map +1 -1
  394. package/dist/separator.cjs.map +1 -1
  395. package/dist/separator.js.map +1 -1
  396. package/dist/shared/index.d.ts +3 -3
  397. package/dist/shared/size-presets.cjs.map +1 -1
  398. package/dist/shared/size-presets.d.ts +4 -4
  399. package/dist/shared/size-presets.js.map +1 -1
  400. package/dist/shared/types.d.ts +1 -1
  401. package/dist/sidebar.cjs.map +1 -1
  402. package/dist/sidebar.js.map +1 -1
  403. package/dist/skeleton.cjs.map +1 -1
  404. package/dist/skeleton.js.map +1 -1
  405. package/dist/slider.cjs.map +1 -1
  406. package/dist/slider.js.map +1 -1
  407. package/dist/speech-player.cjs.map +1 -1
  408. package/dist/speech-player.js.map +1 -1
  409. package/dist/step.cjs.map +1 -1
  410. package/dist/step.js.map +1 -1
  411. package/dist/stepper.cjs.map +1 -1
  412. package/dist/stepper.js.map +1 -1
  413. package/dist/styles/fouc.css +2 -2
  414. package/dist/styles/mixins/accessibility.css.cjs.map +1 -1
  415. package/dist/styles/mixins/accessibility.css.d.ts +4 -4
  416. package/dist/styles/mixins/accessibility.css.js.map +1 -1
  417. package/dist/styles/mixins/animation.css.cjs +2 -2
  418. package/dist/styles/mixins/animation.css.cjs.map +1 -1
  419. package/dist/styles/mixins/animation.css.d.ts +4 -4
  420. package/dist/styles/mixins/animation.css.js +2 -2
  421. package/dist/styles/mixins/animation.css.js.map +1 -1
  422. package/dist/styles/mixins/field-variants.css.cjs +2 -2
  423. package/dist/styles/mixins/field-variants.css.cjs.map +1 -1
  424. package/dist/styles/mixins/field-variants.css.d.ts +6 -6
  425. package/dist/styles/mixins/field-variants.css.d.ts.map +1 -1
  426. package/dist/styles/mixins/field-variants.css.js +2 -2
  427. package/dist/styles/mixins/field-variants.css.js.map +1 -1
  428. package/dist/styles/mixins/shape.css.cjs.map +1 -1
  429. package/dist/styles/mixins/shape.css.d.ts +9 -9
  430. package/dist/styles/mixins/shape.css.d.ts.map +1 -1
  431. package/dist/styles/mixins/shape.css.js.map +1 -1
  432. package/dist/styles/mixins/variants.css.cjs.map +1 -1
  433. package/dist/styles/mixins/variants.css.d.ts +1 -1
  434. package/dist/styles/mixins/variants.css.js.map +1 -1
  435. package/dist/styles/theme.css +36 -28
  436. package/dist/tab-item.cjs.map +1 -1
  437. package/dist/tab-item.js.map +1 -1
  438. package/dist/tab-panel.cjs.map +1 -1
  439. package/dist/tab-panel.js.map +1 -1
  440. package/dist/table.cjs.map +1 -1
  441. package/dist/table.js.map +1 -1
  442. package/dist/text.cjs.map +1 -1
  443. package/dist/text.js.map +1 -1
  444. package/dist/textarea.cjs.map +1 -1
  445. package/dist/textarea.js.map +1 -1
  446. package/dist/theme.cjs.map +1 -1
  447. package/dist/theme.d.ts +2 -2
  448. package/dist/theme.js.map +1 -1
  449. package/dist/time-picker.cjs +1 -1
  450. package/dist/time-picker.cjs.map +1 -1
  451. package/dist/time-picker.js +1 -1
  452. package/dist/time-picker.js.map +1 -1
  453. package/dist/toast.cjs.map +1 -1
  454. package/dist/toast.js.map +1 -1
  455. package/dist/types/elements.d.ts +6 -2
  456. package/dist/typing-indicator.cjs.map +1 -1
  457. package/dist/typing-indicator.js.map +1 -1
  458. package/dist/utils/css.cjs.map +1 -1
  459. package/dist/utils/css.js.map +1 -1
  460. package/dist/utils/link.cjs.map +1 -1
  461. package/dist/utils/link.d.ts +2 -2
  462. package/dist/utils/link.js.map +1 -1
  463. package/package.json +31 -14
@@ -1 +1 @@
1
- {"version":3,"file":"toast.cjs","names":[],"sources":["../src/feedback/toast/toast.ts"],"sourcesContent":["import { createPanGesture, type PanGesture } from '@vielzeug/gesture';\nimport { define, each, getHost, html, onCleanup, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { reducedMotionMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\nimport componentStyles from './toast.css?inline';\n\nexport { ALERT_TAG } from '../alert/alert';\n\n/**\n * The single exit budget: removal happens this many milliseconds (plus a small buffer)\n * after dismissal, on a store-owned timeout. The CSS exit transition\n * (`--toast-exit-duration`, default 200ms) must stay within it or the fade is clipped.\n */\nconst TOAST_EXIT_MS = 200;\n\nexport type OreToastEvents = {\n add: { id: string };\n dismiss: { id: string };\n};\n\n/** Runtime events exposed through {@link ToastService.tap}. */\nexport type ToastEvent = { id: string; type: 'add' | 'dismiss' } | { type: 'dispose' };\n\nexport type OreToastProps = {\n max?: number;\n position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\n};\n\n/** Individual toast notification. */\nexport type ToastItem = {\n actions?: Array<{\n color?: ThemeColor;\n label: string;\n onClick?: () => void;\n variant?: 'solid' | 'flat' | 'bordered';\n }>;\n color?: ThemeColor;\n dismissible?: boolean;\n /** Auto-dismiss delay in ms. Set to 0 for persistent toasts (default: 5000). */\n duration?: number;\n heading?: string;\n /** Show message and actions side-by-side (horizontal layout). */\n horizontal?: boolean;\n /** Auto-generated when omitted. */\n id?: string;\n message: string;\n /** Metadata text (for example, a timestamp) shown in the alert meta slot. */\n meta?: string;\n /** Called after the toast is fully dismissed and removed. */\n onDismiss?: () => void;\n /**\n * Replace a live entry carrying the same message instead of stacking a duplicate —\n * repeated bursts update the existing notification and restart its timer.\n */\n replace?: boolean;\n rounded?: RoundedSize | '';\n /**\n * Material-style compact bar: an inverted neutral surface (dark chip in light themes,\n * light chip in dark themes) with single-row padding, and actions rendered as flat text\n * buttons. Overrides the alert `variant`; the close button inherits the surface's text\n * color. Style through `--toast-snackbar-*` custom properties.\n */\n snackbar?: boolean;\n size?: ComponentSize;\n /**\n * Screen-reader announcement urgency. Error-coloured toasts are assertive by\n * default; all other toasts are polite.\n */\n urgency?: 'polite' | 'assertive';\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\ntype ToastPhase = 'entering' | 'active' | 'exiting';\n\ntype ToastTimer = {\n remaining: number;\n startedAt: number;\n timeoutId: ReturnType<typeof setTimeout> | null;\n};\n\ntype ToastEntry = Required<Pick<ToastItem, 'dismissible' | 'duration' | 'id'>> &\n Omit<ToastItem, 'dismissible' | 'duration' | 'id'> & {\n exitTimeoutId: ReturnType<typeof setTimeout> | null;\n id: string;\n phase: ToastPhase;\n timer: ToastTimer | null;\n };\n\n/**\n * Owns notification data and every timer. Renderers only subscribe to this\n * store; they never expose imperative mutation methods themselves.\n */\nclass ToastStore {\n readonly #entries = signal<ToastEntry[]>([]);\n readonly #listeners = new Set<(entries: ToastEntry[]) => void>();\n readonly #tappers = new Set<(event: ToastEvent) => void>();\n #disposed = false;\n #max = 5;\n #paused = false;\n\n add(item: ToastItem): string {\n if (this.#disposed) return item.id ?? crypto.randomUUID();\n\n const id = item.id ?? crypto.randomUUID();\n\n // A repeated burst replaces its own live entry instead of stacking duplicates.\n if (item.replace) {\n const existing = this.#entries.value.find((entry) => entry.phase !== 'exiting' && entry.message === item.message);\n\n if (existing) {\n this.update(existing.id, { ...item, id: existing.id });\n return existing.id;\n }\n }\n\n const active = this.#entries.value.filter((entry) => entry.phase !== 'exiting');\n const overflow = active.length - (this.#max - 1);\n\n if (overflow > 0) {\n for (const entry of active.slice(0, overflow)) this.dismiss(entry.id);\n }\n\n const entry: ToastEntry = {\n ...item,\n dismissible: item.dismissible ?? true,\n // Action toasts persist until dismissed by default: keyboard and screen-reader users\n // reach toasts last in tab order, so a timed expiry would expire the choice unseen.\n duration: item.duration ?? (item.actions?.length ? 0 : 5000),\n exitTimeoutId: null,\n id,\n phase: 'entering',\n timer: null,\n };\n\n this.#setEntries([...this.#entries.value, entry]);\n this.#dispatch({ id, type: 'add' });\n\n // Two frames: the first lets the browser compute styles for the `entering` state,\n // the second flips to `active` so the CSS transition has a start value to animate from.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (this.#entry(id)?.phase === 'entering') this.#update(id, { phase: 'active' });\n });\n });\n\n if (entry.duration > 0) {\n // While paused the window is recorded without arming a timeout; resume arms it.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: entry.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, entry.duration);\n }\n }\n\n return id;\n }\n\n clear(): void {\n for (const entry of this.#entries.value) {\n if (entry.phase !== 'exiting') this.dismiss(entry.id);\n }\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n\n for (const entry of this.#entries.value) {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n }\n\n this.#dispatch({ type: 'dispose' });\n this.#setEntries([]);\n this.#listeners.clear();\n this.#tappers.clear();\n }\n\n dismiss(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || entry.phase === 'exiting' || this.#disposed) return;\n\n this.#update(id, { ...this.#clearTimer(entry), phase: 'exiting' });\n this.scheduleFinalization(id, TOAST_EXIT_MS + 50);\n }\n\n finalize(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n this.#setEntries(this.#entries.value.filter((candidate) => candidate.id !== id));\n entry.onDismiss?.();\n this.#dispatch({ id, type: 'dismiss' });\n }\n\n pauseTimers(): void {\n if (this.#disposed || this.#paused) return;\n\n this.#paused = true;\n\n this.#setEntries(\n this.#entries.value.map((entry) => {\n if (!entry.timer) return entry;\n\n if (entry.timer.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return {\n ...entry,\n timer: {\n ...entry.timer,\n remaining: Math.max(0, entry.timer.remaining - (Date.now() - entry.timer.startedAt)),\n },\n };\n }),\n );\n }\n\n resumeTimers(): void {\n if (this.#disposed || !this.#paused) return;\n\n this.#paused = false;\n\n for (const entry of this.#entries.value) {\n if (entry.timer && entry.timer.remaining > 0) this.#scheduleTimer(entry.id, entry.timer.remaining);\n }\n }\n\n scheduleFinalization(id: string, delay: number): void {\n const entry = this.#entry(id);\n\n if (entry?.phase !== 'exiting' || this.#disposed) return;\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n const exitTimeoutId = setTimeout(() => this.finalize(id), delay);\n\n this.#update(id, { exitTimeoutId });\n }\n\n setMax(max: number | undefined): void {\n if (max != null) this.#max = Math.max(1, max);\n }\n\n subscribe(listener: (entries: ToastEntry[]) => void): () => void {\n listener(this.#entries.value);\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n /** Side-channel observation of add/dismiss/dispose transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void {\n if (this.#disposed) return () => {};\n\n this.#tappers.add(handler);\n options?.signal?.addEventListener(\n 'abort',\n () => {\n this.#tappers.delete(handler);\n },\n { once: true },\n );\n\n return () => this.#tappers.delete(handler);\n }\n\n update(id: string, updates: Partial<ToastItem>): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n // Omitted fields leave the entry unchanged; only provided values patch it.\n const patch = Object.fromEntries(\n Object.entries(updates).filter(([, value]) => value !== undefined),\n ) as Partial<ToastItem>;\n\n const cleared = patch.duration !== undefined ? this.#clearTimer(entry) : entry;\n\n this.#update(id, { ...cleared, ...patch, id });\n\n if (patch.duration !== undefined && patch.duration > 0) {\n // Same pause contract as add(): record the window, let resumeTimers() arm it,\n // so a toast updated behind an open dialog does not expire unseen.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: patch.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, patch.duration);\n }\n }\n }\n\n #clearTimer(entry: ToastEntry): ToastEntry {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return { ...entry, timer: null };\n }\n\n #dispatch(event: ToastEvent): void {\n if (this.#tappers.size === 0) return;\n\n for (const tapper of this.#tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect toast behavior.\n }\n }\n }\n\n #entry(id: string): ToastEntry | undefined {\n return this.#entries.value.find((entry) => entry.id === id);\n }\n\n #scheduleTimer(id: string, remaining: number): void {\n if (remaining <= 0 || this.#disposed) return;\n\n const timeoutId = setTimeout(() => this.dismiss(id), remaining);\n\n this.#update(id, { timer: { remaining, startedAt: Date.now(), timeoutId } });\n }\n\n #setEntries(entries: ToastEntry[]): void {\n this.#entries.value = entries;\n for (const listener of this.#listeners) listener(entries);\n }\n\n #update(id: string, patch: Partial<ToastEntry>): void {\n this.#setEntries(this.#entries.value.map((entry) => (entry.id === id ? { ...entry, ...patch } : entry)));\n }\n}\n\ntype ToastHostBinding = {\n bind: (store: ToastStore) => void;\n unbind: () => void;\n};\n\nconst hostBindings = new WeakMap<HTMLElement, ToastHostBinding>();\nconst hostStores = new WeakMap<HTMLElement, ToastStore>();\n\nconst bindToastHost = (host: HTMLElement, store: ToastStore): void => {\n hostStores.set(host, store);\n hostBindings.get(host)?.bind(store);\n};\n\nconst NO_ACTIONS: NonNullable<ToastItem['actions']> = [];\n\nconst urgencyOf = (entry: ToastEntry): 'polite' | 'assertive' =>\n entry.urgency ?? (entry.color === 'error' ? 'assertive' : 'polite');\n\n/** Renders the action buttons for a toast entry. Buttons are keyed so focus survives store updates. */\nfunction renderToastActions(item: Readable<ToastEntry>, dismiss: () => void) {\n const actions = computed(() => item.value.actions ?? NO_ACTIONS);\n\n return html`\n ${() =>\n actions.value.length\n ? html`\n <div slot=\"actions\" class=\"toast-actions\">\n ${each(\n () => actions.value,\n (action, index) => `${index}:${action.label}`,\n (action) => html`\n <ore-button\n size=\"sm\"\n color=${() => action.value.color || item.value.color || 'primary'}\n variant=${() => action.value.variant || (item.value.snackbar ? 'ghost' : 'flat')}\n @click=${() => {\n action.value.onClick?.();\n dismiss();\n }}>\n ${() => action.value.label}\n </ore-button>\n `,\n )}\n </div>\n `\n : ''}\n `;\n}\n\nexport const TOAST_TAG = 'ore-toast' as const;\n\n/**\n * Declarative toast host. It subscribes to the service for its scope and\n * renders notifications, but has no imperative mutation API of its own.\n *\n * Notifications render as a vertical list (newest nearest the anchored edge)\n * inside polite and assertive live regions. Entries are keyed by id, so store\n * updates (timer pauses, message updates, phase changes) patch the existing\n * DOM instead of re-creating it — focus, in-flight gestures, and CSS\n * transitions all survive.\n *\n * @element ore-toast\n *\n * @attr {string} position - Stack placement.\n * @attr {number} max - Maximum live notifications for the scoped service.\n *\n * @cssprop --toast-max-width - Panel width cap (default 400px; full width on phones).\n * @cssprop --toast-gap - Gap between notifications.\n * @cssprop --toast-bg - Opaque surface for flat/bordered notifications.\n * @cssprop --toast-shadow - Elevation shadow.\n * @cssprop --toast-enter-duration / --toast-exit-duration - Motion durations.\n * @cssprop --toast-progress-height - Height of the auto-dismiss progress bar.\n * @cssprop --toast-inset-top / --toast-inset-bottom / --toast-inset-left / --toast-inset-right - Viewport insets.\n *\n * @part container - Notification list.\n * @part toast-wrapper - Per-notification layout wrapper (swipe target).\n * @part toast-inner - Per-notification motion target.\n * @part progress - Auto-dismiss progress bar.\n */\ndefine<OreToastProps>(TOAST_TAG, {\n props: {\n max: prop.number(5),\n position: prop.oneOf(\n ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'] as const,\n 'bottom-right',\n ),\n },\n setup(props) {\n const el = getHost() as HTMLElement;\n const emit = useEmit<OreToastEvents>();\n const containerRef = ref<HTMLDivElement>();\n const entries = signal<ToastEntry[]>([]);\n const hoverPaused = signal(false);\n const focusPaused = signal(false);\n const modalPaused = signal(false);\n const paused = computed(() => hoverPaused.value || focusPaused.value || modalPaused.value);\n const swipeControls = new Map<string, { element: HTMLElement; gesture: PanGesture }>();\n let pendingSyncFrame: number | undefined;\n let store: ToastStore | null = null;\n let unsubscribeEntries = () => {};\n let unsubscribeEvents = () => {};\n\n // The declarative `max` attribute stays live: the service seeds it once at host\n // creation, and later attribute changes take effect through this watch.\n watch(\n () => props.max.value,\n (max) => store?.setMax(max),\n );\n\n const getInner = (wrapper: HTMLElement): HTMLElement | null => {\n return wrapper.querySelector<HTMLElement>('.toast-inner');\n };\n\n const wrapperFromEvent = (event: Event): HTMLElement | null =>\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.classList.contains('toast-wrapper')) ??\n null;\n\n /** Timers pause while a top-layer surface (an open dialog, fullscreen) covers the\n * toasts: the user cannot interact with them, so choices must not expire unseen.\n * Any open dialog counts — pausing wrongly is safer than expiring a choice the\n * user could not see. `fullscreenElement` is undefined on engines without the API. */\n const syncTopLayer = (): void => {\n const doc = el.ownerDocument;\n modalPaused.value = doc.querySelector('dialog[open]') !== null || doc.fullscreenElement != null;\n };\n\n /** The element focused before a toast took focus; removal hands it back so keyboard\n * users keep their place instead of restarting from the document top. */\n let lastExternalFocus: HTMLElement | null = null;\n let focusedWrapperId: string | null = null;\n /** Frame budget for the focus-restore re-check; see the restore block in syncControls. */\n let restoreCheckFrames = 0;\n\n /** The deepest focused element, piercing shadow roots — document-level targets\n * retarget to their host, and focusing a host without a tabindex is a no-op. */\n const deepActiveElement = (doc: Document): HTMLElement | null => {\n let active = doc.activeElement as HTMLElement | null;\n\n while (active?.shadowRoot) {\n const deeper = active.shadowRoot.activeElement as HTMLElement | null;\n if (!deeper) break;\n active = deeper;\n }\n\n return active;\n };\n\n const onDocumentFocusIn = (event: FocusEvent): void => {\n if (event.composedPath().includes(el)) return;\n lastExternalFocus = deepActiveElement(el.ownerDocument);\n };\n\n const onToastFocusIn = (event: FocusEvent): void => {\n focusPaused.value = true;\n focusedWrapperId = wrapperFromEvent(event)?.dataset.toastId ?? null;\n restoreCheckFrames = 0;\n };\n\n const onToastFocusOut = (): void => {\n focusPaused.value = false;\n // Focusout fires before the next focusin settles; check after the microtask so a\n // move inside the region keeps the tracked wrapper while leaving clears it. Focus\n // that fell to `<body>` means the focused node was removed — keep the marker so\n // the restore in syncControls can hand focus back.\n void Promise.resolve().then(() => {\n const doc = el.ownerDocument;\n if (!focusPaused.value && doc.activeElement !== doc.body) focusedWrapperId = null;\n });\n };\n\n /** Escape dismisses the newest dismissible toast when nothing inside the toast region\n * holds focus (the in-region handler owns that case and stops the event) and no\n * top-layer surface is open — those own the Escape key. */\n const onDocumentKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || event.defaultPrevented || modalPaused.value) return;\n if (focusPaused.value) return;\n\n const newest = [...entries.value].reverse().find((entry) => entry.dismissible && entry.phase !== 'exiting');\n\n if (newest) {\n event.preventDefault();\n store?.dismiss(newest.id);\n }\n };\n\n const createToastSwipe = (id: string, wrapper: HTMLElement): PanGesture => {\n const isDismissible = (): boolean => entries.value.find((entry) => entry.id === id)?.dismissible ?? true;\n const reset = (): void => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = '';\n inner.style.transform = '';\n inner.style.opacity = '';\n };\n\n return createPanGesture(wrapper, {\n axis: 'x',\n disabled: () => !isDismissible(),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) {\n reset();\n\n return;\n }\n\n const inner = getInner(wrapper);\n\n if (!inner || !store) return;\n\n store.dismiss(id);\n\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n inner.style.opacity = '0';\n store.scheduleFinalization(id, 0);\n\n return;\n }\n\n const direction = distance >= 0 ? 1 : -1;\n\n inner.style.transition = 'transform 0.22s ease-out, opacity 0.22s ease-out';\n void inner.offsetWidth;\n inner.style.transform = `translateX(${direction * 120}%)`;\n inner.style.opacity = '0';\n\n // Removal spans the 0.22s flight; the store's dismiss() timeout is rescheduled\n // here so the swipe animation finishes before the node leaves the DOM.\n store.scheduleFinalization(id, 300);\n },\n onMove: ({ distance }) => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = 'none';\n inner.style.transform = `translateX(${distance}px)`;\n inner.style.opacity = String(Math.max(0, 1 - Math.abs(distance) / 200));\n },\n pointerCapture: false,\n shouldStart: (event) =>\n !event\n .composedPath()\n .some((node) => node instanceof Element && node.matches('button, a, input, select, textarea, ore-button')),\n });\n };\n\n const syncControls = (): void => {\n const currentIds = new Set(entries.value.map((entry) => entry.id));\n\n for (const [id, control] of swipeControls) {\n if (!currentIds.has(id)) {\n control.gesture.dispose();\n\n swipeControls.delete(id);\n }\n }\n\n // A removed wrapper that held focus drops focus to `<body>`; hand it back so\n // keyboard users keep their place. The entry leaves the store before the keyed\n // removal unmounts the focused node, so the frame re-checks below perform the\n // restore once focus has actually fallen to `<body>`.\n if (focusedWrapperId !== null && !currentIds.has(focusedWrapperId)) {\n const doc = el.ownerDocument;\n\n if (doc.activeElement === doc.body) {\n const restore = lastExternalFocus;\n focusedWrapperId = null;\n if (restore?.isConnected) restore.focus();\n } else if (restoreCheckFrames < 10) {\n // The keyed removal has not unmounted the focused node yet; re-check until\n // focus actually falls to `<body>`. A timer, not a frame: animation frames\n // never fire while the tab is hidden, and toasts outlive tab switches.\n restoreCheckFrames += 1;\n setTimeout(() => syncControls(), 16);\n }\n }\n\n for (const entry of entries.value) {\n const wrapper = containerRef.value?.querySelector<HTMLElement>(`[data-toast-id=\"${entry.id}\"]`);\n const control = swipeControls.get(entry.id);\n\n if (wrapper && control?.element !== wrapper) {\n control?.gesture.dispose();\n swipeControls.set(entry.id, { element: wrapper, gesture: createToastSwipe(entry.id, wrapper) });\n }\n }\n };\n\n const scheduleSyncControls = (): void => {\n syncControls();\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n pendingSyncFrame = requestAnimationFrame(() => {\n pendingSyncFrame = undefined;\n syncControls();\n });\n };\n\n watch(entries, scheduleSyncControls);\n watch(paused, (isPaused) => {\n if (isPaused) store?.pauseTimers();\n else store?.resumeTimers();\n });\n\n const bind = (nextStore: ToastStore): void => {\n if (store === nextStore) return;\n\n unsubscribeEntries();\n\n unsubscribeEvents();\n store = nextStore;\n store.setMax(props.max.value);\n unsubscribeEntries = store.subscribe((nextEntries) => {\n entries.value = nextEntries;\n });\n unsubscribeEvents = store.tap((event) => {\n if (event.type === 'dispose') return;\n emit(event.type, { id: event.id });\n });\n\n if (paused.value) store.pauseTimers();\n };\n\n /** Escape dismisses the notification that currently holds focus. */\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n\n const id = wrapperFromEvent(event)?.dataset.toastId;\n const entry = id ? entries.value.find((candidate) => candidate.id === id) : undefined;\n\n if (!entry?.dismissible) return;\n\n event.preventDefault();\n event.stopPropagation();\n store?.dismiss(entry.id);\n };\n\n const renderEntry = (item: Readable<ToastEntry>) => {\n const id = item.value.id;\n const dismiss = () => store?.dismiss(id);\n const meta = computed(() => item.value.meta ?? '');\n const innerClass = computed(\n () =>\n `toast-inner${item.value.phase !== 'active' ? ` ${item.value.phase}` : ''}${\n item.value.snackbar ? ' snackbar' : ''\n }`,\n );\n const innerStyle = computed(\n () =>\n `--_toast-accent: var(--color-${item.value.color || 'primary'}); --_toast-radius: var(--rounded-${\n item.value.rounded || (item.value.snackbar ? 'sm' : 'md')\n })`,\n );\n // Progress restarts from the correct fraction whenever the timer is (re)scheduled:\n // the animation runs for the full duration with a negative delay for elapsed time.\n const progressStyle = computed(() => {\n const { duration, timer } = item.value;\n\n if (!timer || duration <= 0) return '';\n\n return `--_toast-duration: ${duration}ms; --_toast-elapsed: -${Math.max(0, duration - timer.remaining)}ms`;\n });\n\n return html`\n <div class=\"toast-wrapper\" data-toast-id=${id} part=\"toast-wrapper\">\n <div class=${() => innerClass.value} style=${() => innerStyle.value} part=\"toast-inner\">\n <ore-alert\n embedded\n color=${() => item.value.color || (urgencyOf(item.value) === 'assertive' ? 'error' : 'primary')}\n variant=${() => (item.value.snackbar ? 'flat' : item.value.variant || 'solid')}\n size=${() => item.value.size || 'md'}\n rounded=${() => item.value.rounded || 'md'}\n ?horizontal=${() => Boolean(item.value.horizontal)}\n heading=${() => item.value.heading || null}\n ?dismissible=${() => item.value.dismissible}\n @dismiss=${dismiss}>\n <span slot=\"meta\" ?hidden=${() => !meta.value}>${() => meta.value}</span>\n ${() => item.value.message} ${renderToastActions(item, dismiss)}\n </ore-alert>\n <div\n class=\"toast-progress\"\n part=\"progress\"\n style=${() => progressStyle.value}\n ?hidden=${() => !progressStyle.value}\n aria-hidden=\"true\"></div>\n </div>\n </div>\n `;\n };\n\n onMounted(() => {\n hostBindings.set(el, {\n bind,\n unbind() {\n unsubscribeEntries();\n unsubscribeEvents();\n store = null;\n entries.value = [];\n },\n });\n\n const doc = el.ownerDocument;\n\n // The host mounts with the first toast, so pre-toast focus was never tracked by\n // the document listener — snapshot where focus sits right now (the control that\n // triggered the toast) as the restore target.\n const beforeFirstToast = deepActiveElement(doc);\n lastExternalFocus = beforeFirstToast !== doc.body ? beforeFirstToast : null;\n\n doc.addEventListener('focusin', onDocumentFocusIn);\n doc.addEventListener('keydown', onDocumentKeydown);\n // `toggle` does not bubble; the capture listener still sees dialog and popover toggles.\n doc.addEventListener('toggle', syncTopLayer, true);\n doc.addEventListener('fullscreenchange', syncTopLayer);\n syncTopLayer();\n\n const boundStore = hostStores.get(el);\n\n if (boundStore) bind(boundStore);\n });\n\n onCleanup(() => {\n hostBindings.get(el)?.unbind();\n\n hostBindings.delete(el);\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n for (const control of swipeControls.values()) control.gesture.dispose();\n swipeControls.clear();\n\n const doc = el.ownerDocument;\n\n doc.removeEventListener('focusin', onDocumentFocusIn);\n doc.removeEventListener('keydown', onDocumentKeydown);\n doc.removeEventListener('toggle', syncTopLayer, true);\n doc.removeEventListener('fullscreenchange', syncTopLayer);\n });\n\n const politeEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'polite'));\n const assertiveEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'assertive'));\n const keyOf = (entry: ToastEntry) => entry.id;\n\n return html`\n <div\n class=${() => `toast-container${paused.value ? ' paused' : ''}`}\n ref=${containerRef}\n @pointerenter=${() => {\n hoverPaused.value = true;\n }}\n @pointerleave=${() => {\n hoverPaused.value = false;\n }}\n @focusin=${onToastFocusIn}\n @focusout=${onToastFocusOut}\n @keydown=${onKeydown}\n part=\"container\">\n <div\n role=\"region\"\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Notifications\"\n class=\"toast-live-region\">\n ${each(politeEntries, keyOf, renderEntry)}\n </div>\n <div\n role=\"region\"\n aria-live=\"assertive\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Critical notifications\"\n class=\"toast-live-region\">\n ${each(assertiveEntries, keyOf, renderEntry)}\n </div>\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n\nexport type ToastServiceConfig = OreToastProps;\n\nexport interface ToastService {\n add(item: ToastItem): string;\n clear(): void;\n configure(config: ToastServiceConfig): void;\n dismiss(id: string): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n error(message: string, opts?: Partial<ToastItem>): string;\n info(message: string, opts?: Partial<ToastItem>): string;\n promise<T>(\n promise: Promise<T>,\n messages: {\n error: string | ((err: unknown) => string);\n loading: string;\n success: string | ((data: T) => string);\n },\n ): Promise<T>;\n success(message: string, opts?: Partial<ToastItem>): string;\n /** Side-channel observation of add/dispose/dismiss transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n update(id: string, updates: Partial<ToastItem>): void;\n warning(message: string, opts?: Partial<ToastItem>): string;\n [Symbol.dispose](): void;\n}\n\nconst services = new WeakMap<ParentNode, ToastService>();\n\n/**\n * Creates a scoped toast service. The service owns its notification store and\n * binds it to the declarative `<ore-toast>` host inside `root`, creating that\n * host lazily when notifications are first requested.\n */\nexport function createToastService(root: ParentNode = document.body): ToastService {\n const existing = services.get(root);\n\n if (existing) return existing;\n\n const store = new ToastStore();\n const disposalController = new AbortController();\n let disposed = false;\n let pendingConfig: ToastServiceConfig | null = null;\n let host: HTMLElement | null = null;\n\n const assertActive = (): boolean => !disposed;\n const rootNode = root as Element | Document | ShadowRoot;\n\n /** Applies stashed configuration to the host as attributes; the component's own `max`\n * watch and the bind-time seed carry them into the store, so this stays declarative. */\n const applyConfig = (): void => {\n if (!pendingConfig || !host) return;\n\n if (pendingConfig.position) host.setAttribute('position', pendingConfig.position);\n\n if (pendingConfig.max != null) host.setAttribute('max', String(pendingConfig.max));\n\n pendingConfig = null;\n };\n\n const getHost = (): HTMLElement | null => {\n if (!assertActive()) return null;\n\n if (host?.isConnected) return host;\n\n host = rootNode.querySelector<HTMLElement>(TOAST_TAG);\n\n if (!host) {\n host = document.createElement(TOAST_TAG);\n rootNode.appendChild(host);\n }\n\n applyConfig();\n bindToastHost(host, store);\n\n return host;\n };\n const ensureHost = (): boolean => Boolean(getHost());\n\n const service: ToastService = {\n add(item) {\n if (!ensureHost()) return item.id ?? crypto.randomUUID();\n\n return store.add(item);\n },\n\n clear() {\n if (ensureHost()) store.clear();\n },\n\n configure(config) {\n pendingConfig = { ...pendingConfig, ...config };\n applyConfig();\n },\n\n dismiss(id) {\n if (ensureHost()) store.dismiss(id);\n },\n\n get disposalSignal() {\n return disposalController.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n\n disposalController.abort();\n\n store.dispose();\n\n if (services.get(root) === service) services.delete(root);\n },\n\n get disposed() {\n return disposed;\n },\n\n error(message, opts) {\n return service.add({ color: 'error', ...opts, message });\n },\n\n info(message, opts) {\n return service.add({ color: 'info', ...opts, message });\n },\n\n async promise(promise, messages) {\n // The loading entry stays dismissible: if the promise never settles, the user keeps\n // an escape hatch instead of an immortal notification.\n const id = service.add({ color: 'primary', duration: 0, message: messages.loading });\n\n try {\n const data = await promise;\n\n service.update(id, {\n color: 'success',\n duration: 5000,\n message: typeof messages.success === 'function' ? messages.success(data) : messages.success,\n });\n\n return data;\n } catch (err) {\n service.update(id, {\n color: 'error',\n duration: 5000,\n message: typeof messages.error === 'function' ? messages.error(err) : messages.error,\n });\n throw err;\n }\n },\n\n success(message, opts) {\n return service.add({ color: 'success', ...opts, message });\n },\n\n tap(handler, options) {\n return store.tap(handler, options);\n },\n\n [Symbol.dispose]() {\n service.dispose();\n },\n\n update(id, updates) {\n if (ensureHost()) store.update(id, updates);\n },\n\n warning(message, opts) {\n return service.add({ color: 'warning', ...opts, message });\n },\n };\n\n services.set(root, service);\n\n return service;\n}\n\n/** Singleton service backed by a lazily created host in `document.body`. */\nexport const toast: ToastService = createToastService();\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.cjs","names":[],"sources":["../src/feedback/toast/toast.ts"],"sourcesContent":["import { createPanGesture, type PanGesture } from '@vielzeug/gesture';\nimport { define, each, getHost, html, onCleanup, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { reducedMotionMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\nimport componentStyles from './toast.css?inline';\n\nexport { ALERT_TAG } from '../alert/alert';\n\n/**\n * The single exit budget: removal happens this many milliseconds (plus a small buffer)\n * after dismissal, on a store-owned timeout. The CSS exit transition\n * (`--toast-exit-duration`, default 200ms) must stay within it or the fade is clipped.\n */\nconst TOAST_EXIT_MS = 200;\n\nexport type OreToastEvents = {\n add: { id: string };\n dismiss: { id: string };\n};\n\n/** Runtime events exposed through {@link ToastService.tap}. */\nexport type ToastEvent = { id: string; type: 'add' | 'dismiss' } | { type: 'dispose' };\n\nexport type OreToastProps = {\n max?: number;\n position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\n};\n\n/** Individual toast notification. */\nexport type ToastItem = {\n actions?: Array<{\n color?: ThemeColor;\n label: string;\n onClick?: () => void;\n variant?: 'solid' | 'flat' | 'bordered';\n }>;\n color?: ThemeColor;\n dismissible?: boolean;\n /** Auto-dismiss delay in ms. Set to 0 for persistent toasts (default: 5000). */\n duration?: number;\n heading?: string;\n /** Show message and actions side-by-side (horizontal layout). */\n horizontal?: boolean;\n /** Auto-generated when omitted. */\n id?: string;\n message: string;\n /** Metadata text (for example, a timestamp) shown in the alert meta slot. */\n meta?: string;\n /** Called after the toast is fully dismissed and removed. */\n onDismiss?: () => void;\n /**\n * Replace a live entry carrying the same message instead of stacking a duplicate :\n * repeated bursts update the existing notification and restart its timer.\n */\n replace?: boolean;\n rounded?: RoundedSize | '';\n /**\n * Material-style compact bar: an inverted neutral surface (dark chip in light themes,\n * light chip in dark themes) with single-row padding, and actions rendered as flat text\n * buttons. Overrides the alert `variant`; the close button inherits the surface's text\n * color. Style through `--toast-snackbar-*` custom properties.\n */\n snackbar?: boolean;\n size?: ComponentSize;\n /**\n * Screen-reader announcement urgency. Error-coloured toasts are assertive by\n * default; all other toasts are polite.\n */\n urgency?: 'polite' | 'assertive';\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\ntype ToastPhase = 'entering' | 'active' | 'exiting';\n\ntype ToastTimer = {\n remaining: number;\n startedAt: number;\n timeoutId: ReturnType<typeof setTimeout> | null;\n};\n\ntype ToastEntry = Required<Pick<ToastItem, 'dismissible' | 'duration' | 'id'>> &\n Omit<ToastItem, 'dismissible' | 'duration' | 'id'> & {\n exitTimeoutId: ReturnType<typeof setTimeout> | null;\n id: string;\n phase: ToastPhase;\n timer: ToastTimer | null;\n };\n\n/**\n * Owns notification data and every timer. Renderers only subscribe to this\n * store; they never expose imperative mutation methods themselves.\n */\nclass ToastStore {\n readonly #entries = signal<ToastEntry[]>([]);\n readonly #listeners = new Set<(entries: ToastEntry[]) => void>();\n readonly #tappers = new Set<(event: ToastEvent) => void>();\n #disposed = false;\n #max = 5;\n #paused = false;\n\n add(item: ToastItem): string {\n if (this.#disposed) return item.id ?? crypto.randomUUID();\n\n const id = item.id ?? crypto.randomUUID();\n\n // A repeated burst replaces its own live entry instead of stacking duplicates.\n if (item.replace) {\n const existing = this.#entries.value.find((entry) => entry.phase !== 'exiting' && entry.message === item.message);\n\n if (existing) {\n this.update(existing.id, { ...item, id: existing.id });\n return existing.id;\n }\n }\n\n const active = this.#entries.value.filter((entry) => entry.phase !== 'exiting');\n const overflow = active.length - (this.#max - 1);\n\n if (overflow > 0) {\n for (const entry of active.slice(0, overflow)) this.dismiss(entry.id);\n }\n\n const entry: ToastEntry = {\n ...item,\n dismissible: item.dismissible ?? true,\n // Action toasts persist until dismissed by default: keyboard and screen-reader users\n // reach toasts last in tab order, so a timed expiry would expire the choice unseen.\n duration: item.duration ?? (item.actions?.length ? 0 : 5000),\n exitTimeoutId: null,\n id,\n phase: 'entering',\n timer: null,\n };\n\n this.#setEntries([...this.#entries.value, entry]);\n this.#dispatch({ id, type: 'add' });\n\n // Two frames: the first lets the browser compute styles for the `entering` state,\n // the second flips to `active` so the CSS transition has a start value to animate from.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (this.#entry(id)?.phase === 'entering') this.#update(id, { phase: 'active' });\n });\n });\n\n if (entry.duration > 0) {\n // While paused the window is recorded without arming a timeout; resume arms it.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: entry.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, entry.duration);\n }\n }\n\n return id;\n }\n\n clear(): void {\n for (const entry of this.#entries.value) {\n if (entry.phase !== 'exiting') this.dismiss(entry.id);\n }\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n\n for (const entry of this.#entries.value) {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n }\n\n this.#dispatch({ type: 'dispose' });\n this.#setEntries([]);\n this.#listeners.clear();\n this.#tappers.clear();\n }\n\n dismiss(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || entry.phase === 'exiting' || this.#disposed) return;\n\n this.#update(id, { ...this.#clearTimer(entry), phase: 'exiting' });\n this.scheduleFinalization(id, TOAST_EXIT_MS + 50);\n }\n\n finalize(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n this.#setEntries(this.#entries.value.filter((candidate) => candidate.id !== id));\n entry.onDismiss?.();\n this.#dispatch({ id, type: 'dismiss' });\n }\n\n pauseTimers(): void {\n if (this.#disposed || this.#paused) return;\n\n this.#paused = true;\n\n this.#setEntries(\n this.#entries.value.map((entry) => {\n if (!entry.timer) return entry;\n\n if (entry.timer.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return {\n ...entry,\n timer: {\n ...entry.timer,\n remaining: Math.max(0, entry.timer.remaining - (Date.now() - entry.timer.startedAt)),\n },\n };\n }),\n );\n }\n\n resumeTimers(): void {\n if (this.#disposed || !this.#paused) return;\n\n this.#paused = false;\n\n for (const entry of this.#entries.value) {\n if (entry.timer && entry.timer.remaining > 0) this.#scheduleTimer(entry.id, entry.timer.remaining);\n }\n }\n\n scheduleFinalization(id: string, delay: number): void {\n const entry = this.#entry(id);\n\n if (entry?.phase !== 'exiting' || this.#disposed) return;\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n const exitTimeoutId = setTimeout(() => this.finalize(id), delay);\n\n this.#update(id, { exitTimeoutId });\n }\n\n setMax(max: number | undefined): void {\n if (max != null) this.#max = Math.max(1, max);\n }\n\n subscribe(listener: (entries: ToastEntry[]) => void): () => void {\n listener(this.#entries.value);\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n /** Side-channel observation of add/dismiss/dispose transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void {\n if (this.#disposed) return () => {};\n\n this.#tappers.add(handler);\n options?.signal?.addEventListener(\n 'abort',\n () => {\n this.#tappers.delete(handler);\n },\n { once: true },\n );\n\n return () => this.#tappers.delete(handler);\n }\n\n update(id: string, updates: Partial<ToastItem>): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n // Omitted fields leave the entry unchanged; only provided values patch it.\n const patch = Object.fromEntries(\n Object.entries(updates).filter(([, value]) => value !== undefined),\n ) as Partial<ToastItem>;\n\n const cleared = patch.duration !== undefined ? this.#clearTimer(entry) : entry;\n\n this.#update(id, { ...cleared, ...patch, id });\n\n if (patch.duration !== undefined && patch.duration > 0) {\n // Same pause contract as add(): record the window, let resumeTimers() arm it,\n // so a toast updated behind an open dialog does not expire unseen.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: patch.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, patch.duration);\n }\n }\n }\n\n #clearTimer(entry: ToastEntry): ToastEntry {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return { ...entry, timer: null };\n }\n\n #dispatch(event: ToastEvent): void {\n if (this.#tappers.size === 0) return;\n\n for (const tapper of this.#tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect toast behavior.\n }\n }\n }\n\n #entry(id: string): ToastEntry | undefined {\n return this.#entries.value.find((entry) => entry.id === id);\n }\n\n #scheduleTimer(id: string, remaining: number): void {\n if (remaining <= 0 || this.#disposed) return;\n\n const timeoutId = setTimeout(() => this.dismiss(id), remaining);\n\n this.#update(id, { timer: { remaining, startedAt: Date.now(), timeoutId } });\n }\n\n #setEntries(entries: ToastEntry[]): void {\n this.#entries.value = entries;\n for (const listener of this.#listeners) listener(entries);\n }\n\n #update(id: string, patch: Partial<ToastEntry>): void {\n this.#setEntries(this.#entries.value.map((entry) => (entry.id === id ? { ...entry, ...patch } : entry)));\n }\n}\n\ntype ToastHostBinding = {\n bind: (store: ToastStore) => void;\n unbind: () => void;\n};\n\nconst hostBindings = new WeakMap<HTMLElement, ToastHostBinding>();\nconst hostStores = new WeakMap<HTMLElement, ToastStore>();\n\nconst bindToastHost = (host: HTMLElement, store: ToastStore): void => {\n hostStores.set(host, store);\n hostBindings.get(host)?.bind(store);\n};\n\nconst NO_ACTIONS: NonNullable<ToastItem['actions']> = [];\n\nconst urgencyOf = (entry: ToastEntry): 'polite' | 'assertive' =>\n entry.urgency ?? (entry.color === 'error' ? 'assertive' : 'polite');\n\n/** Renders the action buttons for a toast entry. Buttons are keyed so focus survives store updates. */\nfunction renderToastActions(item: Readable<ToastEntry>, dismiss: () => void) {\n const actions = computed(() => item.value.actions ?? NO_ACTIONS);\n\n return html`\n ${() =>\n actions.value.length\n ? html`\n <div slot=\"actions\" class=\"toast-actions\">\n ${each(\n () => actions.value,\n (action, index) => `${index}:${action.label}`,\n (action) => html`\n <ore-button\n size=\"sm\"\n color=${() => action.value.color || item.value.color || 'primary'}\n variant=${() => action.value.variant || (item.value.snackbar ? 'ghost' : 'flat')}\n @click=${() => {\n action.value.onClick?.();\n dismiss();\n }}>\n ${() => action.value.label}\n </ore-button>\n `,\n )}\n </div>\n `\n : ''}\n `;\n}\n\nexport const TOAST_TAG = 'ore-toast' as const;\n\n/**\n * Declarative toast host. It subscribes to the service for its scope and\n * renders notifications, but has no imperative mutation API of its own.\n *\n * Notifications render as a vertical list (newest nearest the anchored edge)\n * inside polite and assertive live regions. Entries are keyed by id, so store\n * updates (timer pauses, message updates, phase changes) patch the existing\n * DOM instead of re-creating it: focus, in-flight gestures, and CSS\n * transitions all survive.\n *\n * @element ore-toast\n *\n * @attr {string} position - Stack placement.\n * @attr {number} max - Maximum live notifications for the scoped service.\n *\n * @cssprop --toast-max-width - Panel width cap (default 400px; full width on phones).\n * @cssprop --toast-gap - Gap between notifications.\n * @cssprop --toast-bg - Opaque surface for flat/bordered notifications.\n * @cssprop --toast-shadow - Elevation shadow.\n * @cssprop --toast-enter-duration / --toast-exit-duration - Motion durations.\n * @cssprop --toast-progress-height - Height of the auto-dismiss progress bar.\n * @cssprop --toast-snackbar-height - Snackbar message row height, action or not (default --size-8).\n * @cssprop --toast-inset-top / --toast-inset-bottom / --toast-inset-left / --toast-inset-right - Viewport insets.\n *\n * @part container - Notification list.\n * @part toast-wrapper - Per-notification layout wrapper (swipe target).\n * @part toast-inner - Per-notification motion target.\n * @part progress - Auto-dismiss progress bar.\n */\ndefine<OreToastProps>(TOAST_TAG, {\n props: {\n max: prop.number(5),\n position: prop.oneOf(\n ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'] as const,\n 'bottom-right',\n ),\n },\n setup(props) {\n const el = getHost() as HTMLElement;\n const emit = useEmit<OreToastEvents>();\n const containerRef = ref<HTMLDivElement>();\n const entries = signal<ToastEntry[]>([]);\n const hoverPaused = signal(false);\n const focusPaused = signal(false);\n const modalPaused = signal(false);\n const paused = computed(() => hoverPaused.value || focusPaused.value || modalPaused.value);\n const swipeControls = new Map<string, { element: HTMLElement; gesture: PanGesture }>();\n let pendingSyncFrame: number | undefined;\n let store: ToastStore | null = null;\n let unsubscribeEntries = () => {};\n let unsubscribeEvents = () => {};\n\n // The declarative `max` attribute stays live: the service seeds it once at host\n // creation, and later attribute changes take effect through this watch.\n watch(\n () => props.max.value,\n (max) => store?.setMax(max),\n );\n\n const getInner = (wrapper: HTMLElement): HTMLElement | null => {\n return wrapper.querySelector<HTMLElement>('.toast-inner');\n };\n\n const wrapperFromEvent = (event: Event): HTMLElement | null =>\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.classList.contains('toast-wrapper')) ??\n null;\n\n /** Timers pause while a top-layer surface (an open dialog, fullscreen) covers the\n * toasts: the user cannot interact with them, so choices must not expire unseen.\n * Any open dialog counts: pausing wrongly is safer than expiring a choice the\n * user could not see. `fullscreenElement` is undefined on engines without the API. */\n const syncTopLayer = (): void => {\n const doc = el.ownerDocument;\n modalPaused.value = doc.querySelector('dialog[open]') !== null || doc.fullscreenElement != null;\n };\n\n /** The element focused before a toast took focus; removal hands it back so keyboard\n * users keep their place instead of restarting from the document top. */\n let lastExternalFocus: HTMLElement | null = null;\n let focusedWrapperId: string | null = null;\n /** Frame budget for the focus-restore re-check; see the restore block in syncControls. */\n let restoreCheckFrames = 0;\n\n /** The deepest focused element, piercing shadow roots: document-level targets\n * retarget to their host, and focusing a host without a tabindex is a no-op. */\n const deepActiveElement = (doc: Document): HTMLElement | null => {\n let active = doc.activeElement as HTMLElement | null;\n\n while (active?.shadowRoot) {\n const deeper = active.shadowRoot.activeElement as HTMLElement | null;\n if (!deeper) break;\n active = deeper;\n }\n\n return active;\n };\n\n const onDocumentFocusIn = (event: FocusEvent): void => {\n if (event.composedPath().includes(el)) return;\n lastExternalFocus = deepActiveElement(el.ownerDocument);\n };\n\n const onToastFocusIn = (event: FocusEvent): void => {\n focusPaused.value = true;\n focusedWrapperId = wrapperFromEvent(event)?.dataset.toastId ?? null;\n restoreCheckFrames = 0;\n };\n\n const onToastFocusOut = (): void => {\n focusPaused.value = false;\n // Focusout fires before the next focusin settles; check after the microtask so a\n // move inside the region keeps the tracked wrapper while leaving clears it. Focus\n // that fell to `<body>` means the focused node was removed: keep the marker so\n // the restore in syncControls can hand focus back.\n void Promise.resolve().then(() => {\n const doc = el.ownerDocument;\n if (!focusPaused.value && doc.activeElement !== doc.body) focusedWrapperId = null;\n });\n };\n\n /** Escape dismisses the newest dismissible toast when nothing inside the toast region\n * holds focus (the in-region handler owns that case and stops the event) and no\n * top-layer surface is open: those own the Escape key. */\n const onDocumentKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || event.defaultPrevented || modalPaused.value) return;\n if (focusPaused.value) return;\n\n const newest = [...entries.value].reverse().find((entry) => entry.dismissible && entry.phase !== 'exiting');\n\n if (newest) {\n event.preventDefault();\n store?.dismiss(newest.id);\n }\n };\n\n const createToastSwipe = (id: string, wrapper: HTMLElement): PanGesture => {\n const isDismissible = (): boolean => entries.value.find((entry) => entry.id === id)?.dismissible ?? true;\n const reset = (): void => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = '';\n inner.style.transform = '';\n inner.style.opacity = '';\n };\n\n return createPanGesture(wrapper, {\n axis: 'x',\n disabled: () => !isDismissible(),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) {\n reset();\n\n return;\n }\n\n const inner = getInner(wrapper);\n\n if (!inner || !store) return;\n\n store.dismiss(id);\n\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n inner.style.opacity = '0';\n store.scheduleFinalization(id, 0);\n\n return;\n }\n\n const direction = distance >= 0 ? 1 : -1;\n\n inner.style.transition = 'transform 0.22s ease-out, opacity 0.22s ease-out';\n void inner.offsetWidth;\n inner.style.transform = `translateX(${direction * 120}%)`;\n inner.style.opacity = '0';\n\n // Removal spans the 0.22s flight; the store's dismiss() timeout is rescheduled\n // here so the swipe animation finishes before the node leaves the DOM.\n store.scheduleFinalization(id, 300);\n },\n onMove: ({ distance }) => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = 'none';\n inner.style.transform = `translateX(${distance}px)`;\n inner.style.opacity = String(Math.max(0, 1 - Math.abs(distance) / 200));\n },\n pointerCapture: false,\n shouldStart: (event) =>\n !event\n .composedPath()\n .some((node) => node instanceof Element && node.matches('button, a, input, select, textarea, ore-button')),\n });\n };\n\n const syncControls = (): void => {\n const currentIds = new Set(entries.value.map((entry) => entry.id));\n\n for (const [id, control] of swipeControls) {\n if (!currentIds.has(id)) {\n control.gesture.dispose();\n\n swipeControls.delete(id);\n }\n }\n\n // A removed wrapper that held focus drops focus to `<body>`; hand it back so\n // keyboard users keep their place. The entry leaves the store before the keyed\n // removal unmounts the focused node, so the frame re-checks below perform the\n // restore once focus has actually fallen to `<body>`.\n if (focusedWrapperId !== null && !currentIds.has(focusedWrapperId)) {\n const doc = el.ownerDocument;\n\n if (doc.activeElement === doc.body) {\n const restore = lastExternalFocus;\n focusedWrapperId = null;\n if (restore?.isConnected) restore.focus();\n } else if (restoreCheckFrames < 10) {\n // The keyed removal has not unmounted the focused node yet; re-check until\n // focus actually falls to `<body>`. A timer, not a frame: animation frames\n // never fire while the tab is hidden, and toasts outlive tab switches.\n restoreCheckFrames += 1;\n setTimeout(() => syncControls(), 16);\n }\n }\n\n for (const entry of entries.value) {\n const wrapper = containerRef.value?.querySelector<HTMLElement>(`[data-toast-id=\"${entry.id}\"]`);\n const control = swipeControls.get(entry.id);\n\n if (wrapper && control?.element !== wrapper) {\n control?.gesture.dispose();\n swipeControls.set(entry.id, { element: wrapper, gesture: createToastSwipe(entry.id, wrapper) });\n }\n }\n };\n\n const scheduleSyncControls = (): void => {\n syncControls();\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n pendingSyncFrame = requestAnimationFrame(() => {\n pendingSyncFrame = undefined;\n syncControls();\n });\n };\n\n watch(entries, scheduleSyncControls);\n watch(paused, (isPaused) => {\n if (isPaused) store?.pauseTimers();\n else store?.resumeTimers();\n });\n\n const bind = (nextStore: ToastStore): void => {\n if (store === nextStore) return;\n\n unsubscribeEntries();\n\n unsubscribeEvents();\n store = nextStore;\n store.setMax(props.max.value);\n unsubscribeEntries = store.subscribe((nextEntries) => {\n entries.value = nextEntries;\n });\n unsubscribeEvents = store.tap((event) => {\n if (event.type === 'dispose') return;\n emit(event.type, { id: event.id });\n });\n\n if (paused.value) store.pauseTimers();\n };\n\n /** Escape dismisses the notification that currently holds focus. */\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n\n const id = wrapperFromEvent(event)?.dataset.toastId;\n const entry = id ? entries.value.find((candidate) => candidate.id === id) : undefined;\n\n if (!entry?.dismissible) return;\n\n event.preventDefault();\n event.stopPropagation();\n store?.dismiss(entry.id);\n };\n\n const renderEntry = (item: Readable<ToastEntry>) => {\n const id = item.value.id;\n const dismiss = () => store?.dismiss(id);\n const meta = computed(() => item.value.meta ?? '');\n const innerClass = computed(\n () =>\n `toast-inner${item.value.phase !== 'active' ? ` ${item.value.phase}` : ''}${\n item.value.snackbar ? ' snackbar' : ''\n }`,\n );\n const innerStyle = computed(\n () =>\n `--_toast-accent: var(--color-${item.value.color || 'primary'}); --_toast-radius: var(--rounded-${\n item.value.rounded || (item.value.snackbar ? 'sm' : 'md')\n })`,\n );\n // Progress restarts from the correct fraction whenever the timer is (re)scheduled:\n // the animation runs for the full duration with a negative delay for elapsed time.\n const progressStyle = computed(() => {\n const { duration, timer } = item.value;\n\n if (!timer || duration <= 0) return '';\n\n return `--_toast-duration: ${duration}ms; --_toast-elapsed: -${Math.max(0, duration - timer.remaining)}ms`;\n });\n\n return html`\n <div class=\"toast-wrapper\" data-toast-id=${id} part=\"toast-wrapper\">\n <div class=${() => innerClass.value} style=${() => innerStyle.value} part=\"toast-inner\">\n <ore-alert\n embedded\n color=${() => item.value.color || (urgencyOf(item.value) === 'assertive' ? 'error' : 'primary')}\n variant=${() => (item.value.snackbar ? 'flat' : item.value.variant || 'solid')}\n size=${() => item.value.size || 'md'}\n rounded=${() => item.value.rounded || 'md'}\n ?horizontal=${() => Boolean(item.value.horizontal)}\n heading=${() => item.value.heading || null}\n ?dismissible=${() => item.value.dismissible}\n @dismiss=${dismiss}>\n <span slot=\"meta\" ?hidden=${() => !meta.value}>${() => meta.value}</span>\n ${() => item.value.message} ${renderToastActions(item, dismiss)}\n </ore-alert>\n <div\n class=\"toast-progress\"\n part=\"progress\"\n style=${() => progressStyle.value}\n ?hidden=${() => !progressStyle.value}\n aria-hidden=\"true\"></div>\n </div>\n </div>\n `;\n };\n\n onMounted(() => {\n hostBindings.set(el, {\n bind,\n unbind() {\n unsubscribeEntries();\n unsubscribeEvents();\n store = null;\n entries.value = [];\n },\n });\n\n const doc = el.ownerDocument;\n\n // The host mounts with the first toast, so pre-toast focus was never tracked by\n // the document listener: snapshot where focus sits right now (the control that\n // triggered the toast) as the restore target.\n const beforeFirstToast = deepActiveElement(doc);\n lastExternalFocus = beforeFirstToast !== doc.body ? beforeFirstToast : null;\n\n doc.addEventListener('focusin', onDocumentFocusIn);\n doc.addEventListener('keydown', onDocumentKeydown);\n // `toggle` does not bubble; the capture listener still sees dialog and popover toggles.\n doc.addEventListener('toggle', syncTopLayer, true);\n doc.addEventListener('fullscreenchange', syncTopLayer);\n syncTopLayer();\n\n const boundStore = hostStores.get(el);\n\n if (boundStore) bind(boundStore);\n });\n\n onCleanup(() => {\n hostBindings.get(el)?.unbind();\n\n hostBindings.delete(el);\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n for (const control of swipeControls.values()) control.gesture.dispose();\n swipeControls.clear();\n\n const doc = el.ownerDocument;\n\n doc.removeEventListener('focusin', onDocumentFocusIn);\n doc.removeEventListener('keydown', onDocumentKeydown);\n doc.removeEventListener('toggle', syncTopLayer, true);\n doc.removeEventListener('fullscreenchange', syncTopLayer);\n });\n\n const politeEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'polite'));\n const assertiveEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'assertive'));\n const keyOf = (entry: ToastEntry) => entry.id;\n\n return html`\n <div\n class=${() => `toast-container${paused.value ? ' paused' : ''}`}\n ref=${containerRef}\n @pointerenter=${() => {\n hoverPaused.value = true;\n }}\n @pointerleave=${() => {\n hoverPaused.value = false;\n }}\n @focusin=${onToastFocusIn}\n @focusout=${onToastFocusOut}\n @keydown=${onKeydown}\n part=\"container\">\n <div\n role=\"region\"\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Notifications\"\n class=\"toast-live-region\">\n ${each(politeEntries, keyOf, renderEntry)}\n </div>\n <div\n role=\"region\"\n aria-live=\"assertive\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Critical notifications\"\n class=\"toast-live-region\">\n ${each(assertiveEntries, keyOf, renderEntry)}\n </div>\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n\nexport type ToastServiceConfig = OreToastProps;\n\nexport interface ToastService {\n add(item: ToastItem): string;\n clear(): void;\n configure(config: ToastServiceConfig): void;\n dismiss(id: string): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n error(message: string, opts?: Partial<ToastItem>): string;\n info(message: string, opts?: Partial<ToastItem>): string;\n promise<T>(\n promise: Promise<T>,\n messages: {\n error: string | ((err: unknown) => string);\n loading: string;\n success: string | ((data: T) => string);\n },\n ): Promise<T>;\n success(message: string, opts?: Partial<ToastItem>): string;\n /** Side-channel observation of add/dispose/dismiss transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n update(id: string, updates: Partial<ToastItem>): void;\n warning(message: string, opts?: Partial<ToastItem>): string;\n [Symbol.dispose](): void;\n}\n\nconst services = new WeakMap<ParentNode, ToastService>();\n\n/**\n * Creates a scoped toast service. The service owns its notification store and\n * binds it to the declarative `<ore-toast>` host inside `root`, creating that\n * host lazily when notifications are first requested.\n */\nexport function createToastService(root: ParentNode = document.body): ToastService {\n const existing = services.get(root);\n\n if (existing) return existing;\n\n const store = new ToastStore();\n const disposalController = new AbortController();\n let disposed = false;\n let pendingConfig: ToastServiceConfig | null = null;\n let host: HTMLElement | null = null;\n\n const assertActive = (): boolean => !disposed;\n const rootNode = root as Element | Document | ShadowRoot;\n\n /** Applies stashed configuration to the host as attributes; the component's own `max`\n * watch and the bind-time seed carry them into the store, so this stays declarative. */\n const applyConfig = (): void => {\n if (!pendingConfig || !host) return;\n\n if (pendingConfig.position) host.setAttribute('position', pendingConfig.position);\n\n if (pendingConfig.max != null) host.setAttribute('max', String(pendingConfig.max));\n\n pendingConfig = null;\n };\n\n const getHost = (): HTMLElement | null => {\n if (!assertActive()) return null;\n\n if (host?.isConnected) return host;\n\n host = rootNode.querySelector<HTMLElement>(TOAST_TAG);\n\n if (!host) {\n host = document.createElement(TOAST_TAG);\n rootNode.appendChild(host);\n }\n\n applyConfig();\n bindToastHost(host, store);\n\n return host;\n };\n const ensureHost = (): boolean => Boolean(getHost());\n\n const service: ToastService = {\n add(item) {\n if (!ensureHost()) return item.id ?? crypto.randomUUID();\n\n return store.add(item);\n },\n\n clear() {\n if (ensureHost()) store.clear();\n },\n\n configure(config) {\n pendingConfig = { ...pendingConfig, ...config };\n applyConfig();\n },\n\n dismiss(id) {\n if (ensureHost()) store.dismiss(id);\n },\n\n get disposalSignal() {\n return disposalController.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n\n disposalController.abort();\n\n store.dispose();\n\n if (services.get(root) === service) services.delete(root);\n },\n\n get disposed() {\n return disposed;\n },\n\n error(message, opts) {\n return service.add({ color: 'error', ...opts, message });\n },\n\n info(message, opts) {\n return service.add({ color: 'info', ...opts, message });\n },\n\n async promise(promise, messages) {\n // The loading entry stays dismissible: if the promise never settles, the user keeps\n // an escape hatch instead of an immortal notification.\n const id = service.add({ color: 'primary', duration: 0, message: messages.loading });\n\n try {\n const data = await promise;\n\n service.update(id, {\n color: 'success',\n duration: 5000,\n message: typeof messages.success === 'function' ? messages.success(data) : messages.success,\n });\n\n return data;\n } catch (err) {\n service.update(id, {\n color: 'error',\n duration: 5000,\n message: typeof messages.error === 'function' ? messages.error(err) : messages.error,\n });\n throw err;\n }\n },\n\n success(message, opts) {\n return service.add({ color: 'success', ...opts, message });\n },\n\n tap(handler, options) {\n return store.tap(handler, options);\n },\n\n [Symbol.dispose]() {\n service.dispose();\n },\n\n update(id, updates) {\n if (ensureHost()) store.update(id, updates);\n },\n\n warning(message, opts) {\n return service.add({ color: 'warning', ...opts, message });\n },\n };\n\n services.set(root, service);\n\n return service;\n}\n\n/** Singleton service backed by a lazily created host in `document.body`. */\nexport const toast: ToastService = createToastService();\n"],"mappings":"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"}
package/dist/toast.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"toast.js","names":[],"sources":["../src/feedback/toast/toast.ts"],"sourcesContent":["import { createPanGesture, type PanGesture } from '@vielzeug/gesture';\nimport { define, each, getHost, html, onCleanup, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { reducedMotionMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\nimport componentStyles from './toast.css?inline';\n\nexport { ALERT_TAG } from '../alert/alert';\n\n/**\n * The single exit budget: removal happens this many milliseconds (plus a small buffer)\n * after dismissal, on a store-owned timeout. The CSS exit transition\n * (`--toast-exit-duration`, default 200ms) must stay within it or the fade is clipped.\n */\nconst TOAST_EXIT_MS = 200;\n\nexport type OreToastEvents = {\n add: { id: string };\n dismiss: { id: string };\n};\n\n/** Runtime events exposed through {@link ToastService.tap}. */\nexport type ToastEvent = { id: string; type: 'add' | 'dismiss' } | { type: 'dispose' };\n\nexport type OreToastProps = {\n max?: number;\n position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\n};\n\n/** Individual toast notification. */\nexport type ToastItem = {\n actions?: Array<{\n color?: ThemeColor;\n label: string;\n onClick?: () => void;\n variant?: 'solid' | 'flat' | 'bordered';\n }>;\n color?: ThemeColor;\n dismissible?: boolean;\n /** Auto-dismiss delay in ms. Set to 0 for persistent toasts (default: 5000). */\n duration?: number;\n heading?: string;\n /** Show message and actions side-by-side (horizontal layout). */\n horizontal?: boolean;\n /** Auto-generated when omitted. */\n id?: string;\n message: string;\n /** Metadata text (for example, a timestamp) shown in the alert meta slot. */\n meta?: string;\n /** Called after the toast is fully dismissed and removed. */\n onDismiss?: () => void;\n /**\n * Replace a live entry carrying the same message instead of stacking a duplicate —\n * repeated bursts update the existing notification and restart its timer.\n */\n replace?: boolean;\n rounded?: RoundedSize | '';\n /**\n * Material-style compact bar: an inverted neutral surface (dark chip in light themes,\n * light chip in dark themes) with single-row padding, and actions rendered as flat text\n * buttons. Overrides the alert `variant`; the close button inherits the surface's text\n * color. Style through `--toast-snackbar-*` custom properties.\n */\n snackbar?: boolean;\n size?: ComponentSize;\n /**\n * Screen-reader announcement urgency. Error-coloured toasts are assertive by\n * default; all other toasts are polite.\n */\n urgency?: 'polite' | 'assertive';\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\ntype ToastPhase = 'entering' | 'active' | 'exiting';\n\ntype ToastTimer = {\n remaining: number;\n startedAt: number;\n timeoutId: ReturnType<typeof setTimeout> | null;\n};\n\ntype ToastEntry = Required<Pick<ToastItem, 'dismissible' | 'duration' | 'id'>> &\n Omit<ToastItem, 'dismissible' | 'duration' | 'id'> & {\n exitTimeoutId: ReturnType<typeof setTimeout> | null;\n id: string;\n phase: ToastPhase;\n timer: ToastTimer | null;\n };\n\n/**\n * Owns notification data and every timer. Renderers only subscribe to this\n * store; they never expose imperative mutation methods themselves.\n */\nclass ToastStore {\n readonly #entries = signal<ToastEntry[]>([]);\n readonly #listeners = new Set<(entries: ToastEntry[]) => void>();\n readonly #tappers = new Set<(event: ToastEvent) => void>();\n #disposed = false;\n #max = 5;\n #paused = false;\n\n add(item: ToastItem): string {\n if (this.#disposed) return item.id ?? crypto.randomUUID();\n\n const id = item.id ?? crypto.randomUUID();\n\n // A repeated burst replaces its own live entry instead of stacking duplicates.\n if (item.replace) {\n const existing = this.#entries.value.find((entry) => entry.phase !== 'exiting' && entry.message === item.message);\n\n if (existing) {\n this.update(existing.id, { ...item, id: existing.id });\n return existing.id;\n }\n }\n\n const active = this.#entries.value.filter((entry) => entry.phase !== 'exiting');\n const overflow = active.length - (this.#max - 1);\n\n if (overflow > 0) {\n for (const entry of active.slice(0, overflow)) this.dismiss(entry.id);\n }\n\n const entry: ToastEntry = {\n ...item,\n dismissible: item.dismissible ?? true,\n // Action toasts persist until dismissed by default: keyboard and screen-reader users\n // reach toasts last in tab order, so a timed expiry would expire the choice unseen.\n duration: item.duration ?? (item.actions?.length ? 0 : 5000),\n exitTimeoutId: null,\n id,\n phase: 'entering',\n timer: null,\n };\n\n this.#setEntries([...this.#entries.value, entry]);\n this.#dispatch({ id, type: 'add' });\n\n // Two frames: the first lets the browser compute styles for the `entering` state,\n // the second flips to `active` so the CSS transition has a start value to animate from.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (this.#entry(id)?.phase === 'entering') this.#update(id, { phase: 'active' });\n });\n });\n\n if (entry.duration > 0) {\n // While paused the window is recorded without arming a timeout; resume arms it.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: entry.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, entry.duration);\n }\n }\n\n return id;\n }\n\n clear(): void {\n for (const entry of this.#entries.value) {\n if (entry.phase !== 'exiting') this.dismiss(entry.id);\n }\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n\n for (const entry of this.#entries.value) {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n }\n\n this.#dispatch({ type: 'dispose' });\n this.#setEntries([]);\n this.#listeners.clear();\n this.#tappers.clear();\n }\n\n dismiss(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || entry.phase === 'exiting' || this.#disposed) return;\n\n this.#update(id, { ...this.#clearTimer(entry), phase: 'exiting' });\n this.scheduleFinalization(id, TOAST_EXIT_MS + 50);\n }\n\n finalize(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n this.#setEntries(this.#entries.value.filter((candidate) => candidate.id !== id));\n entry.onDismiss?.();\n this.#dispatch({ id, type: 'dismiss' });\n }\n\n pauseTimers(): void {\n if (this.#disposed || this.#paused) return;\n\n this.#paused = true;\n\n this.#setEntries(\n this.#entries.value.map((entry) => {\n if (!entry.timer) return entry;\n\n if (entry.timer.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return {\n ...entry,\n timer: {\n ...entry.timer,\n remaining: Math.max(0, entry.timer.remaining - (Date.now() - entry.timer.startedAt)),\n },\n };\n }),\n );\n }\n\n resumeTimers(): void {\n if (this.#disposed || !this.#paused) return;\n\n this.#paused = false;\n\n for (const entry of this.#entries.value) {\n if (entry.timer && entry.timer.remaining > 0) this.#scheduleTimer(entry.id, entry.timer.remaining);\n }\n }\n\n scheduleFinalization(id: string, delay: number): void {\n const entry = this.#entry(id);\n\n if (entry?.phase !== 'exiting' || this.#disposed) return;\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n const exitTimeoutId = setTimeout(() => this.finalize(id), delay);\n\n this.#update(id, { exitTimeoutId });\n }\n\n setMax(max: number | undefined): void {\n if (max != null) this.#max = Math.max(1, max);\n }\n\n subscribe(listener: (entries: ToastEntry[]) => void): () => void {\n listener(this.#entries.value);\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n /** Side-channel observation of add/dismiss/dispose transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void {\n if (this.#disposed) return () => {};\n\n this.#tappers.add(handler);\n options?.signal?.addEventListener(\n 'abort',\n () => {\n this.#tappers.delete(handler);\n },\n { once: true },\n );\n\n return () => this.#tappers.delete(handler);\n }\n\n update(id: string, updates: Partial<ToastItem>): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n // Omitted fields leave the entry unchanged; only provided values patch it.\n const patch = Object.fromEntries(\n Object.entries(updates).filter(([, value]) => value !== undefined),\n ) as Partial<ToastItem>;\n\n const cleared = patch.duration !== undefined ? this.#clearTimer(entry) : entry;\n\n this.#update(id, { ...cleared, ...patch, id });\n\n if (patch.duration !== undefined && patch.duration > 0) {\n // Same pause contract as add(): record the window, let resumeTimers() arm it,\n // so a toast updated behind an open dialog does not expire unseen.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: patch.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, patch.duration);\n }\n }\n }\n\n #clearTimer(entry: ToastEntry): ToastEntry {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return { ...entry, timer: null };\n }\n\n #dispatch(event: ToastEvent): void {\n if (this.#tappers.size === 0) return;\n\n for (const tapper of this.#tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect toast behavior.\n }\n }\n }\n\n #entry(id: string): ToastEntry | undefined {\n return this.#entries.value.find((entry) => entry.id === id);\n }\n\n #scheduleTimer(id: string, remaining: number): void {\n if (remaining <= 0 || this.#disposed) return;\n\n const timeoutId = setTimeout(() => this.dismiss(id), remaining);\n\n this.#update(id, { timer: { remaining, startedAt: Date.now(), timeoutId } });\n }\n\n #setEntries(entries: ToastEntry[]): void {\n this.#entries.value = entries;\n for (const listener of this.#listeners) listener(entries);\n }\n\n #update(id: string, patch: Partial<ToastEntry>): void {\n this.#setEntries(this.#entries.value.map((entry) => (entry.id === id ? { ...entry, ...patch } : entry)));\n }\n}\n\ntype ToastHostBinding = {\n bind: (store: ToastStore) => void;\n unbind: () => void;\n};\n\nconst hostBindings = new WeakMap<HTMLElement, ToastHostBinding>();\nconst hostStores = new WeakMap<HTMLElement, ToastStore>();\n\nconst bindToastHost = (host: HTMLElement, store: ToastStore): void => {\n hostStores.set(host, store);\n hostBindings.get(host)?.bind(store);\n};\n\nconst NO_ACTIONS: NonNullable<ToastItem['actions']> = [];\n\nconst urgencyOf = (entry: ToastEntry): 'polite' | 'assertive' =>\n entry.urgency ?? (entry.color === 'error' ? 'assertive' : 'polite');\n\n/** Renders the action buttons for a toast entry. Buttons are keyed so focus survives store updates. */\nfunction renderToastActions(item: Readable<ToastEntry>, dismiss: () => void) {\n const actions = computed(() => item.value.actions ?? NO_ACTIONS);\n\n return html`\n ${() =>\n actions.value.length\n ? html`\n <div slot=\"actions\" class=\"toast-actions\">\n ${each(\n () => actions.value,\n (action, index) => `${index}:${action.label}`,\n (action) => html`\n <ore-button\n size=\"sm\"\n color=${() => action.value.color || item.value.color || 'primary'}\n variant=${() => action.value.variant || (item.value.snackbar ? 'ghost' : 'flat')}\n @click=${() => {\n action.value.onClick?.();\n dismiss();\n }}>\n ${() => action.value.label}\n </ore-button>\n `,\n )}\n </div>\n `\n : ''}\n `;\n}\n\nexport const TOAST_TAG = 'ore-toast' as const;\n\n/**\n * Declarative toast host. It subscribes to the service for its scope and\n * renders notifications, but has no imperative mutation API of its own.\n *\n * Notifications render as a vertical list (newest nearest the anchored edge)\n * inside polite and assertive live regions. Entries are keyed by id, so store\n * updates (timer pauses, message updates, phase changes) patch the existing\n * DOM instead of re-creating it — focus, in-flight gestures, and CSS\n * transitions all survive.\n *\n * @element ore-toast\n *\n * @attr {string} position - Stack placement.\n * @attr {number} max - Maximum live notifications for the scoped service.\n *\n * @cssprop --toast-max-width - Panel width cap (default 400px; full width on phones).\n * @cssprop --toast-gap - Gap between notifications.\n * @cssprop --toast-bg - Opaque surface for flat/bordered notifications.\n * @cssprop --toast-shadow - Elevation shadow.\n * @cssprop --toast-enter-duration / --toast-exit-duration - Motion durations.\n * @cssprop --toast-progress-height - Height of the auto-dismiss progress bar.\n * @cssprop --toast-inset-top / --toast-inset-bottom / --toast-inset-left / --toast-inset-right - Viewport insets.\n *\n * @part container - Notification list.\n * @part toast-wrapper - Per-notification layout wrapper (swipe target).\n * @part toast-inner - Per-notification motion target.\n * @part progress - Auto-dismiss progress bar.\n */\ndefine<OreToastProps>(TOAST_TAG, {\n props: {\n max: prop.number(5),\n position: prop.oneOf(\n ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'] as const,\n 'bottom-right',\n ),\n },\n setup(props) {\n const el = getHost() as HTMLElement;\n const emit = useEmit<OreToastEvents>();\n const containerRef = ref<HTMLDivElement>();\n const entries = signal<ToastEntry[]>([]);\n const hoverPaused = signal(false);\n const focusPaused = signal(false);\n const modalPaused = signal(false);\n const paused = computed(() => hoverPaused.value || focusPaused.value || modalPaused.value);\n const swipeControls = new Map<string, { element: HTMLElement; gesture: PanGesture }>();\n let pendingSyncFrame: number | undefined;\n let store: ToastStore | null = null;\n let unsubscribeEntries = () => {};\n let unsubscribeEvents = () => {};\n\n // The declarative `max` attribute stays live: the service seeds it once at host\n // creation, and later attribute changes take effect through this watch.\n watch(\n () => props.max.value,\n (max) => store?.setMax(max),\n );\n\n const getInner = (wrapper: HTMLElement): HTMLElement | null => {\n return wrapper.querySelector<HTMLElement>('.toast-inner');\n };\n\n const wrapperFromEvent = (event: Event): HTMLElement | null =>\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.classList.contains('toast-wrapper')) ??\n null;\n\n /** Timers pause while a top-layer surface (an open dialog, fullscreen) covers the\n * toasts: the user cannot interact with them, so choices must not expire unseen.\n * Any open dialog counts — pausing wrongly is safer than expiring a choice the\n * user could not see. `fullscreenElement` is undefined on engines without the API. */\n const syncTopLayer = (): void => {\n const doc = el.ownerDocument;\n modalPaused.value = doc.querySelector('dialog[open]') !== null || doc.fullscreenElement != null;\n };\n\n /** The element focused before a toast took focus; removal hands it back so keyboard\n * users keep their place instead of restarting from the document top. */\n let lastExternalFocus: HTMLElement | null = null;\n let focusedWrapperId: string | null = null;\n /** Frame budget for the focus-restore re-check; see the restore block in syncControls. */\n let restoreCheckFrames = 0;\n\n /** The deepest focused element, piercing shadow roots — document-level targets\n * retarget to their host, and focusing a host without a tabindex is a no-op. */\n const deepActiveElement = (doc: Document): HTMLElement | null => {\n let active = doc.activeElement as HTMLElement | null;\n\n while (active?.shadowRoot) {\n const deeper = active.shadowRoot.activeElement as HTMLElement | null;\n if (!deeper) break;\n active = deeper;\n }\n\n return active;\n };\n\n const onDocumentFocusIn = (event: FocusEvent): void => {\n if (event.composedPath().includes(el)) return;\n lastExternalFocus = deepActiveElement(el.ownerDocument);\n };\n\n const onToastFocusIn = (event: FocusEvent): void => {\n focusPaused.value = true;\n focusedWrapperId = wrapperFromEvent(event)?.dataset.toastId ?? null;\n restoreCheckFrames = 0;\n };\n\n const onToastFocusOut = (): void => {\n focusPaused.value = false;\n // Focusout fires before the next focusin settles; check after the microtask so a\n // move inside the region keeps the tracked wrapper while leaving clears it. Focus\n // that fell to `<body>` means the focused node was removed — keep the marker so\n // the restore in syncControls can hand focus back.\n void Promise.resolve().then(() => {\n const doc = el.ownerDocument;\n if (!focusPaused.value && doc.activeElement !== doc.body) focusedWrapperId = null;\n });\n };\n\n /** Escape dismisses the newest dismissible toast when nothing inside the toast region\n * holds focus (the in-region handler owns that case and stops the event) and no\n * top-layer surface is open — those own the Escape key. */\n const onDocumentKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || event.defaultPrevented || modalPaused.value) return;\n if (focusPaused.value) return;\n\n const newest = [...entries.value].reverse().find((entry) => entry.dismissible && entry.phase !== 'exiting');\n\n if (newest) {\n event.preventDefault();\n store?.dismiss(newest.id);\n }\n };\n\n const createToastSwipe = (id: string, wrapper: HTMLElement): PanGesture => {\n const isDismissible = (): boolean => entries.value.find((entry) => entry.id === id)?.dismissible ?? true;\n const reset = (): void => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = '';\n inner.style.transform = '';\n inner.style.opacity = '';\n };\n\n return createPanGesture(wrapper, {\n axis: 'x',\n disabled: () => !isDismissible(),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) {\n reset();\n\n return;\n }\n\n const inner = getInner(wrapper);\n\n if (!inner || !store) return;\n\n store.dismiss(id);\n\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n inner.style.opacity = '0';\n store.scheduleFinalization(id, 0);\n\n return;\n }\n\n const direction = distance >= 0 ? 1 : -1;\n\n inner.style.transition = 'transform 0.22s ease-out, opacity 0.22s ease-out';\n void inner.offsetWidth;\n inner.style.transform = `translateX(${direction * 120}%)`;\n inner.style.opacity = '0';\n\n // Removal spans the 0.22s flight; the store's dismiss() timeout is rescheduled\n // here so the swipe animation finishes before the node leaves the DOM.\n store.scheduleFinalization(id, 300);\n },\n onMove: ({ distance }) => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = 'none';\n inner.style.transform = `translateX(${distance}px)`;\n inner.style.opacity = String(Math.max(0, 1 - Math.abs(distance) / 200));\n },\n pointerCapture: false,\n shouldStart: (event) =>\n !event\n .composedPath()\n .some((node) => node instanceof Element && node.matches('button, a, input, select, textarea, ore-button')),\n });\n };\n\n const syncControls = (): void => {\n const currentIds = new Set(entries.value.map((entry) => entry.id));\n\n for (const [id, control] of swipeControls) {\n if (!currentIds.has(id)) {\n control.gesture.dispose();\n\n swipeControls.delete(id);\n }\n }\n\n // A removed wrapper that held focus drops focus to `<body>`; hand it back so\n // keyboard users keep their place. The entry leaves the store before the keyed\n // removal unmounts the focused node, so the frame re-checks below perform the\n // restore once focus has actually fallen to `<body>`.\n if (focusedWrapperId !== null && !currentIds.has(focusedWrapperId)) {\n const doc = el.ownerDocument;\n\n if (doc.activeElement === doc.body) {\n const restore = lastExternalFocus;\n focusedWrapperId = null;\n if (restore?.isConnected) restore.focus();\n } else if (restoreCheckFrames < 10) {\n // The keyed removal has not unmounted the focused node yet; re-check until\n // focus actually falls to `<body>`. A timer, not a frame: animation frames\n // never fire while the tab is hidden, and toasts outlive tab switches.\n restoreCheckFrames += 1;\n setTimeout(() => syncControls(), 16);\n }\n }\n\n for (const entry of entries.value) {\n const wrapper = containerRef.value?.querySelector<HTMLElement>(`[data-toast-id=\"${entry.id}\"]`);\n const control = swipeControls.get(entry.id);\n\n if (wrapper && control?.element !== wrapper) {\n control?.gesture.dispose();\n swipeControls.set(entry.id, { element: wrapper, gesture: createToastSwipe(entry.id, wrapper) });\n }\n }\n };\n\n const scheduleSyncControls = (): void => {\n syncControls();\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n pendingSyncFrame = requestAnimationFrame(() => {\n pendingSyncFrame = undefined;\n syncControls();\n });\n };\n\n watch(entries, scheduleSyncControls);\n watch(paused, (isPaused) => {\n if (isPaused) store?.pauseTimers();\n else store?.resumeTimers();\n });\n\n const bind = (nextStore: ToastStore): void => {\n if (store === nextStore) return;\n\n unsubscribeEntries();\n\n unsubscribeEvents();\n store = nextStore;\n store.setMax(props.max.value);\n unsubscribeEntries = store.subscribe((nextEntries) => {\n entries.value = nextEntries;\n });\n unsubscribeEvents = store.tap((event) => {\n if (event.type === 'dispose') return;\n emit(event.type, { id: event.id });\n });\n\n if (paused.value) store.pauseTimers();\n };\n\n /** Escape dismisses the notification that currently holds focus. */\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n\n const id = wrapperFromEvent(event)?.dataset.toastId;\n const entry = id ? entries.value.find((candidate) => candidate.id === id) : undefined;\n\n if (!entry?.dismissible) return;\n\n event.preventDefault();\n event.stopPropagation();\n store?.dismiss(entry.id);\n };\n\n const renderEntry = (item: Readable<ToastEntry>) => {\n const id = item.value.id;\n const dismiss = () => store?.dismiss(id);\n const meta = computed(() => item.value.meta ?? '');\n const innerClass = computed(\n () =>\n `toast-inner${item.value.phase !== 'active' ? ` ${item.value.phase}` : ''}${\n item.value.snackbar ? ' snackbar' : ''\n }`,\n );\n const innerStyle = computed(\n () =>\n `--_toast-accent: var(--color-${item.value.color || 'primary'}); --_toast-radius: var(--rounded-${\n item.value.rounded || (item.value.snackbar ? 'sm' : 'md')\n })`,\n );\n // Progress restarts from the correct fraction whenever the timer is (re)scheduled:\n // the animation runs for the full duration with a negative delay for elapsed time.\n const progressStyle = computed(() => {\n const { duration, timer } = item.value;\n\n if (!timer || duration <= 0) return '';\n\n return `--_toast-duration: ${duration}ms; --_toast-elapsed: -${Math.max(0, duration - timer.remaining)}ms`;\n });\n\n return html`\n <div class=\"toast-wrapper\" data-toast-id=${id} part=\"toast-wrapper\">\n <div class=${() => innerClass.value} style=${() => innerStyle.value} part=\"toast-inner\">\n <ore-alert\n embedded\n color=${() => item.value.color || (urgencyOf(item.value) === 'assertive' ? 'error' : 'primary')}\n variant=${() => (item.value.snackbar ? 'flat' : item.value.variant || 'solid')}\n size=${() => item.value.size || 'md'}\n rounded=${() => item.value.rounded || 'md'}\n ?horizontal=${() => Boolean(item.value.horizontal)}\n heading=${() => item.value.heading || null}\n ?dismissible=${() => item.value.dismissible}\n @dismiss=${dismiss}>\n <span slot=\"meta\" ?hidden=${() => !meta.value}>${() => meta.value}</span>\n ${() => item.value.message} ${renderToastActions(item, dismiss)}\n </ore-alert>\n <div\n class=\"toast-progress\"\n part=\"progress\"\n style=${() => progressStyle.value}\n ?hidden=${() => !progressStyle.value}\n aria-hidden=\"true\"></div>\n </div>\n </div>\n `;\n };\n\n onMounted(() => {\n hostBindings.set(el, {\n bind,\n unbind() {\n unsubscribeEntries();\n unsubscribeEvents();\n store = null;\n entries.value = [];\n },\n });\n\n const doc = el.ownerDocument;\n\n // The host mounts with the first toast, so pre-toast focus was never tracked by\n // the document listener — snapshot where focus sits right now (the control that\n // triggered the toast) as the restore target.\n const beforeFirstToast = deepActiveElement(doc);\n lastExternalFocus = beforeFirstToast !== doc.body ? beforeFirstToast : null;\n\n doc.addEventListener('focusin', onDocumentFocusIn);\n doc.addEventListener('keydown', onDocumentKeydown);\n // `toggle` does not bubble; the capture listener still sees dialog and popover toggles.\n doc.addEventListener('toggle', syncTopLayer, true);\n doc.addEventListener('fullscreenchange', syncTopLayer);\n syncTopLayer();\n\n const boundStore = hostStores.get(el);\n\n if (boundStore) bind(boundStore);\n });\n\n onCleanup(() => {\n hostBindings.get(el)?.unbind();\n\n hostBindings.delete(el);\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n for (const control of swipeControls.values()) control.gesture.dispose();\n swipeControls.clear();\n\n const doc = el.ownerDocument;\n\n doc.removeEventListener('focusin', onDocumentFocusIn);\n doc.removeEventListener('keydown', onDocumentKeydown);\n doc.removeEventListener('toggle', syncTopLayer, true);\n doc.removeEventListener('fullscreenchange', syncTopLayer);\n });\n\n const politeEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'polite'));\n const assertiveEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'assertive'));\n const keyOf = (entry: ToastEntry) => entry.id;\n\n return html`\n <div\n class=${() => `toast-container${paused.value ? ' paused' : ''}`}\n ref=${containerRef}\n @pointerenter=${() => {\n hoverPaused.value = true;\n }}\n @pointerleave=${() => {\n hoverPaused.value = false;\n }}\n @focusin=${onToastFocusIn}\n @focusout=${onToastFocusOut}\n @keydown=${onKeydown}\n part=\"container\">\n <div\n role=\"region\"\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Notifications\"\n class=\"toast-live-region\">\n ${each(politeEntries, keyOf, renderEntry)}\n </div>\n <div\n role=\"region\"\n aria-live=\"assertive\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Critical notifications\"\n class=\"toast-live-region\">\n ${each(assertiveEntries, keyOf, renderEntry)}\n </div>\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n\nexport type ToastServiceConfig = OreToastProps;\n\nexport interface ToastService {\n add(item: ToastItem): string;\n clear(): void;\n configure(config: ToastServiceConfig): void;\n dismiss(id: string): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n error(message: string, opts?: Partial<ToastItem>): string;\n info(message: string, opts?: Partial<ToastItem>): string;\n promise<T>(\n promise: Promise<T>,\n messages: {\n error: string | ((err: unknown) => string);\n loading: string;\n success: string | ((data: T) => string);\n },\n ): Promise<T>;\n success(message: string, opts?: Partial<ToastItem>): string;\n /** Side-channel observation of add/dispose/dismiss transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n update(id: string, updates: Partial<ToastItem>): void;\n warning(message: string, opts?: Partial<ToastItem>): string;\n [Symbol.dispose](): void;\n}\n\nconst services = new WeakMap<ParentNode, ToastService>();\n\n/**\n * Creates a scoped toast service. The service owns its notification store and\n * binds it to the declarative `<ore-toast>` host inside `root`, creating that\n * host lazily when notifications are first requested.\n */\nexport function createToastService(root: ParentNode = document.body): ToastService {\n const existing = services.get(root);\n\n if (existing) return existing;\n\n const store = new ToastStore();\n const disposalController = new AbortController();\n let disposed = false;\n let pendingConfig: ToastServiceConfig | null = null;\n let host: HTMLElement | null = null;\n\n const assertActive = (): boolean => !disposed;\n const rootNode = root as Element | Document | ShadowRoot;\n\n /** Applies stashed configuration to the host as attributes; the component's own `max`\n * watch and the bind-time seed carry them into the store, so this stays declarative. */\n const applyConfig = (): void => {\n if (!pendingConfig || !host) return;\n\n if (pendingConfig.position) host.setAttribute('position', pendingConfig.position);\n\n if (pendingConfig.max != null) host.setAttribute('max', String(pendingConfig.max));\n\n pendingConfig = null;\n };\n\n const getHost = (): HTMLElement | null => {\n if (!assertActive()) return null;\n\n if (host?.isConnected) return host;\n\n host = rootNode.querySelector<HTMLElement>(TOAST_TAG);\n\n if (!host) {\n host = document.createElement(TOAST_TAG);\n rootNode.appendChild(host);\n }\n\n applyConfig();\n bindToastHost(host, store);\n\n return host;\n };\n const ensureHost = (): boolean => Boolean(getHost());\n\n const service: ToastService = {\n add(item) {\n if (!ensureHost()) return item.id ?? crypto.randomUUID();\n\n return store.add(item);\n },\n\n clear() {\n if (ensureHost()) store.clear();\n },\n\n configure(config) {\n pendingConfig = { ...pendingConfig, ...config };\n applyConfig();\n },\n\n dismiss(id) {\n if (ensureHost()) store.dismiss(id);\n },\n\n get disposalSignal() {\n return disposalController.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n\n disposalController.abort();\n\n store.dispose();\n\n if (services.get(root) === service) services.delete(root);\n },\n\n get disposed() {\n return disposed;\n },\n\n error(message, opts) {\n return service.add({ color: 'error', ...opts, message });\n },\n\n info(message, opts) {\n return service.add({ color: 'info', ...opts, message });\n },\n\n async promise(promise, messages) {\n // The loading entry stays dismissible: if the promise never settles, the user keeps\n // an escape hatch instead of an immortal notification.\n const id = service.add({ color: 'primary', duration: 0, message: messages.loading });\n\n try {\n const data = await promise;\n\n service.update(id, {\n color: 'success',\n duration: 5000,\n message: typeof messages.success === 'function' ? messages.success(data) : messages.success,\n });\n\n return data;\n } catch (err) {\n service.update(id, {\n color: 'error',\n duration: 5000,\n message: typeof messages.error === 'function' ? messages.error(err) : messages.error,\n });\n throw err;\n }\n },\n\n success(message, opts) {\n return service.add({ color: 'success', ...opts, message });\n },\n\n tap(handler, options) {\n return store.tap(handler, options);\n },\n\n [Symbol.dispose]() {\n service.dispose();\n },\n\n update(id, updates) {\n if (ensureHost()) store.update(id, updates);\n },\n\n warning(message, opts) {\n return service.add({ color: 'warning', ...opts, message });\n },\n };\n\n services.set(root, service);\n\n return service;\n}\n\n/** Singleton service backed by a lazily created host in `document.body`. */\nexport const toast: ToastService = createToastService();\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.js","names":[],"sources":["../src/feedback/toast/toast.ts"],"sourcesContent":["import { createPanGesture, type PanGesture } from '@vielzeug/gesture';\nimport { define, each, getHost, html, onCleanup, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { reducedMotionMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\nimport componentStyles from './toast.css?inline';\n\nexport { ALERT_TAG } from '../alert/alert';\n\n/**\n * The single exit budget: removal happens this many milliseconds (plus a small buffer)\n * after dismissal, on a store-owned timeout. The CSS exit transition\n * (`--toast-exit-duration`, default 200ms) must stay within it or the fade is clipped.\n */\nconst TOAST_EXIT_MS = 200;\n\nexport type OreToastEvents = {\n add: { id: string };\n dismiss: { id: string };\n};\n\n/** Runtime events exposed through {@link ToastService.tap}. */\nexport type ToastEvent = { id: string; type: 'add' | 'dismiss' } | { type: 'dispose' };\n\nexport type OreToastProps = {\n max?: number;\n position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\n};\n\n/** Individual toast notification. */\nexport type ToastItem = {\n actions?: Array<{\n color?: ThemeColor;\n label: string;\n onClick?: () => void;\n variant?: 'solid' | 'flat' | 'bordered';\n }>;\n color?: ThemeColor;\n dismissible?: boolean;\n /** Auto-dismiss delay in ms. Set to 0 for persistent toasts (default: 5000). */\n duration?: number;\n heading?: string;\n /** Show message and actions side-by-side (horizontal layout). */\n horizontal?: boolean;\n /** Auto-generated when omitted. */\n id?: string;\n message: string;\n /** Metadata text (for example, a timestamp) shown in the alert meta slot. */\n meta?: string;\n /** Called after the toast is fully dismissed and removed. */\n onDismiss?: () => void;\n /**\n * Replace a live entry carrying the same message instead of stacking a duplicate :\n * repeated bursts update the existing notification and restart its timer.\n */\n replace?: boolean;\n rounded?: RoundedSize | '';\n /**\n * Material-style compact bar: an inverted neutral surface (dark chip in light themes,\n * light chip in dark themes) with single-row padding, and actions rendered as flat text\n * buttons. Overrides the alert `variant`; the close button inherits the surface's text\n * color. Style through `--toast-snackbar-*` custom properties.\n */\n snackbar?: boolean;\n size?: ComponentSize;\n /**\n * Screen-reader announcement urgency. Error-coloured toasts are assertive by\n * default; all other toasts are polite.\n */\n urgency?: 'polite' | 'assertive';\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\ntype ToastPhase = 'entering' | 'active' | 'exiting';\n\ntype ToastTimer = {\n remaining: number;\n startedAt: number;\n timeoutId: ReturnType<typeof setTimeout> | null;\n};\n\ntype ToastEntry = Required<Pick<ToastItem, 'dismissible' | 'duration' | 'id'>> &\n Omit<ToastItem, 'dismissible' | 'duration' | 'id'> & {\n exitTimeoutId: ReturnType<typeof setTimeout> | null;\n id: string;\n phase: ToastPhase;\n timer: ToastTimer | null;\n };\n\n/**\n * Owns notification data and every timer. Renderers only subscribe to this\n * store; they never expose imperative mutation methods themselves.\n */\nclass ToastStore {\n readonly #entries = signal<ToastEntry[]>([]);\n readonly #listeners = new Set<(entries: ToastEntry[]) => void>();\n readonly #tappers = new Set<(event: ToastEvent) => void>();\n #disposed = false;\n #max = 5;\n #paused = false;\n\n add(item: ToastItem): string {\n if (this.#disposed) return item.id ?? crypto.randomUUID();\n\n const id = item.id ?? crypto.randomUUID();\n\n // A repeated burst replaces its own live entry instead of stacking duplicates.\n if (item.replace) {\n const existing = this.#entries.value.find((entry) => entry.phase !== 'exiting' && entry.message === item.message);\n\n if (existing) {\n this.update(existing.id, { ...item, id: existing.id });\n return existing.id;\n }\n }\n\n const active = this.#entries.value.filter((entry) => entry.phase !== 'exiting');\n const overflow = active.length - (this.#max - 1);\n\n if (overflow > 0) {\n for (const entry of active.slice(0, overflow)) this.dismiss(entry.id);\n }\n\n const entry: ToastEntry = {\n ...item,\n dismissible: item.dismissible ?? true,\n // Action toasts persist until dismissed by default: keyboard and screen-reader users\n // reach toasts last in tab order, so a timed expiry would expire the choice unseen.\n duration: item.duration ?? (item.actions?.length ? 0 : 5000),\n exitTimeoutId: null,\n id,\n phase: 'entering',\n timer: null,\n };\n\n this.#setEntries([...this.#entries.value, entry]);\n this.#dispatch({ id, type: 'add' });\n\n // Two frames: the first lets the browser compute styles for the `entering` state,\n // the second flips to `active` so the CSS transition has a start value to animate from.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (this.#entry(id)?.phase === 'entering') this.#update(id, { phase: 'active' });\n });\n });\n\n if (entry.duration > 0) {\n // While paused the window is recorded without arming a timeout; resume arms it.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: entry.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, entry.duration);\n }\n }\n\n return id;\n }\n\n clear(): void {\n for (const entry of this.#entries.value) {\n if (entry.phase !== 'exiting') this.dismiss(entry.id);\n }\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n\n for (const entry of this.#entries.value) {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n }\n\n this.#dispatch({ type: 'dispose' });\n this.#setEntries([]);\n this.#listeners.clear();\n this.#tappers.clear();\n }\n\n dismiss(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || entry.phase === 'exiting' || this.#disposed) return;\n\n this.#update(id, { ...this.#clearTimer(entry), phase: 'exiting' });\n this.scheduleFinalization(id, TOAST_EXIT_MS + 50);\n }\n\n finalize(id: string): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n this.#setEntries(this.#entries.value.filter((candidate) => candidate.id !== id));\n entry.onDismiss?.();\n this.#dispatch({ id, type: 'dismiss' });\n }\n\n pauseTimers(): void {\n if (this.#disposed || this.#paused) return;\n\n this.#paused = true;\n\n this.#setEntries(\n this.#entries.value.map((entry) => {\n if (!entry.timer) return entry;\n\n if (entry.timer.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return {\n ...entry,\n timer: {\n ...entry.timer,\n remaining: Math.max(0, entry.timer.remaining - (Date.now() - entry.timer.startedAt)),\n },\n };\n }),\n );\n }\n\n resumeTimers(): void {\n if (this.#disposed || !this.#paused) return;\n\n this.#paused = false;\n\n for (const entry of this.#entries.value) {\n if (entry.timer && entry.timer.remaining > 0) this.#scheduleTimer(entry.id, entry.timer.remaining);\n }\n }\n\n scheduleFinalization(id: string, delay: number): void {\n const entry = this.#entry(id);\n\n if (entry?.phase !== 'exiting' || this.#disposed) return;\n\n if (entry.exitTimeoutId) clearTimeout(entry.exitTimeoutId);\n\n const exitTimeoutId = setTimeout(() => this.finalize(id), delay);\n\n this.#update(id, { exitTimeoutId });\n }\n\n setMax(max: number | undefined): void {\n if (max != null) this.#max = Math.max(1, max);\n }\n\n subscribe(listener: (entries: ToastEntry[]) => void): () => void {\n listener(this.#entries.value);\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n /** Side-channel observation of add/dismiss/dispose transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void {\n if (this.#disposed) return () => {};\n\n this.#tappers.add(handler);\n options?.signal?.addEventListener(\n 'abort',\n () => {\n this.#tappers.delete(handler);\n },\n { once: true },\n );\n\n return () => this.#tappers.delete(handler);\n }\n\n update(id: string, updates: Partial<ToastItem>): void {\n const entry = this.#entry(id);\n\n if (!entry || this.#disposed) return;\n\n // Omitted fields leave the entry unchanged; only provided values patch it.\n const patch = Object.fromEntries(\n Object.entries(updates).filter(([, value]) => value !== undefined),\n ) as Partial<ToastItem>;\n\n const cleared = patch.duration !== undefined ? this.#clearTimer(entry) : entry;\n\n this.#update(id, { ...cleared, ...patch, id });\n\n if (patch.duration !== undefined && patch.duration > 0) {\n // Same pause contract as add(): record the window, let resumeTimers() arm it,\n // so a toast updated behind an open dialog does not expire unseen.\n if (this.#paused) {\n this.#update(id, { timer: { remaining: patch.duration, startedAt: Date.now(), timeoutId: null } });\n } else {\n this.#scheduleTimer(id, patch.duration);\n }\n }\n }\n\n #clearTimer(entry: ToastEntry): ToastEntry {\n if (entry.timer?.timeoutId) clearTimeout(entry.timer.timeoutId);\n\n return { ...entry, timer: null };\n }\n\n #dispatch(event: ToastEvent): void {\n if (this.#tappers.size === 0) return;\n\n for (const tapper of this.#tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect toast behavior.\n }\n }\n }\n\n #entry(id: string): ToastEntry | undefined {\n return this.#entries.value.find((entry) => entry.id === id);\n }\n\n #scheduleTimer(id: string, remaining: number): void {\n if (remaining <= 0 || this.#disposed) return;\n\n const timeoutId = setTimeout(() => this.dismiss(id), remaining);\n\n this.#update(id, { timer: { remaining, startedAt: Date.now(), timeoutId } });\n }\n\n #setEntries(entries: ToastEntry[]): void {\n this.#entries.value = entries;\n for (const listener of this.#listeners) listener(entries);\n }\n\n #update(id: string, patch: Partial<ToastEntry>): void {\n this.#setEntries(this.#entries.value.map((entry) => (entry.id === id ? { ...entry, ...patch } : entry)));\n }\n}\n\ntype ToastHostBinding = {\n bind: (store: ToastStore) => void;\n unbind: () => void;\n};\n\nconst hostBindings = new WeakMap<HTMLElement, ToastHostBinding>();\nconst hostStores = new WeakMap<HTMLElement, ToastStore>();\n\nconst bindToastHost = (host: HTMLElement, store: ToastStore): void => {\n hostStores.set(host, store);\n hostBindings.get(host)?.bind(store);\n};\n\nconst NO_ACTIONS: NonNullable<ToastItem['actions']> = [];\n\nconst urgencyOf = (entry: ToastEntry): 'polite' | 'assertive' =>\n entry.urgency ?? (entry.color === 'error' ? 'assertive' : 'polite');\n\n/** Renders the action buttons for a toast entry. Buttons are keyed so focus survives store updates. */\nfunction renderToastActions(item: Readable<ToastEntry>, dismiss: () => void) {\n const actions = computed(() => item.value.actions ?? NO_ACTIONS);\n\n return html`\n ${() =>\n actions.value.length\n ? html`\n <div slot=\"actions\" class=\"toast-actions\">\n ${each(\n () => actions.value,\n (action, index) => `${index}:${action.label}`,\n (action) => html`\n <ore-button\n size=\"sm\"\n color=${() => action.value.color || item.value.color || 'primary'}\n variant=${() => action.value.variant || (item.value.snackbar ? 'ghost' : 'flat')}\n @click=${() => {\n action.value.onClick?.();\n dismiss();\n }}>\n ${() => action.value.label}\n </ore-button>\n `,\n )}\n </div>\n `\n : ''}\n `;\n}\n\nexport const TOAST_TAG = 'ore-toast' as const;\n\n/**\n * Declarative toast host. It subscribes to the service for its scope and\n * renders notifications, but has no imperative mutation API of its own.\n *\n * Notifications render as a vertical list (newest nearest the anchored edge)\n * inside polite and assertive live regions. Entries are keyed by id, so store\n * updates (timer pauses, message updates, phase changes) patch the existing\n * DOM instead of re-creating it: focus, in-flight gestures, and CSS\n * transitions all survive.\n *\n * @element ore-toast\n *\n * @attr {string} position - Stack placement.\n * @attr {number} max - Maximum live notifications for the scoped service.\n *\n * @cssprop --toast-max-width - Panel width cap (default 400px; full width on phones).\n * @cssprop --toast-gap - Gap between notifications.\n * @cssprop --toast-bg - Opaque surface for flat/bordered notifications.\n * @cssprop --toast-shadow - Elevation shadow.\n * @cssprop --toast-enter-duration / --toast-exit-duration - Motion durations.\n * @cssprop --toast-progress-height - Height of the auto-dismiss progress bar.\n * @cssprop --toast-snackbar-height - Snackbar message row height, action or not (default --size-8).\n * @cssprop --toast-inset-top / --toast-inset-bottom / --toast-inset-left / --toast-inset-right - Viewport insets.\n *\n * @part container - Notification list.\n * @part toast-wrapper - Per-notification layout wrapper (swipe target).\n * @part toast-inner - Per-notification motion target.\n * @part progress - Auto-dismiss progress bar.\n */\ndefine<OreToastProps>(TOAST_TAG, {\n props: {\n max: prop.number(5),\n position: prop.oneOf(\n ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'] as const,\n 'bottom-right',\n ),\n },\n setup(props) {\n const el = getHost() as HTMLElement;\n const emit = useEmit<OreToastEvents>();\n const containerRef = ref<HTMLDivElement>();\n const entries = signal<ToastEntry[]>([]);\n const hoverPaused = signal(false);\n const focusPaused = signal(false);\n const modalPaused = signal(false);\n const paused = computed(() => hoverPaused.value || focusPaused.value || modalPaused.value);\n const swipeControls = new Map<string, { element: HTMLElement; gesture: PanGesture }>();\n let pendingSyncFrame: number | undefined;\n let store: ToastStore | null = null;\n let unsubscribeEntries = () => {};\n let unsubscribeEvents = () => {};\n\n // The declarative `max` attribute stays live: the service seeds it once at host\n // creation, and later attribute changes take effect through this watch.\n watch(\n () => props.max.value,\n (max) => store?.setMax(max),\n );\n\n const getInner = (wrapper: HTMLElement): HTMLElement | null => {\n return wrapper.querySelector<HTMLElement>('.toast-inner');\n };\n\n const wrapperFromEvent = (event: Event): HTMLElement | null =>\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.classList.contains('toast-wrapper')) ??\n null;\n\n /** Timers pause while a top-layer surface (an open dialog, fullscreen) covers the\n * toasts: the user cannot interact with them, so choices must not expire unseen.\n * Any open dialog counts: pausing wrongly is safer than expiring a choice the\n * user could not see. `fullscreenElement` is undefined on engines without the API. */\n const syncTopLayer = (): void => {\n const doc = el.ownerDocument;\n modalPaused.value = doc.querySelector('dialog[open]') !== null || doc.fullscreenElement != null;\n };\n\n /** The element focused before a toast took focus; removal hands it back so keyboard\n * users keep their place instead of restarting from the document top. */\n let lastExternalFocus: HTMLElement | null = null;\n let focusedWrapperId: string | null = null;\n /** Frame budget for the focus-restore re-check; see the restore block in syncControls. */\n let restoreCheckFrames = 0;\n\n /** The deepest focused element, piercing shadow roots: document-level targets\n * retarget to their host, and focusing a host without a tabindex is a no-op. */\n const deepActiveElement = (doc: Document): HTMLElement | null => {\n let active = doc.activeElement as HTMLElement | null;\n\n while (active?.shadowRoot) {\n const deeper = active.shadowRoot.activeElement as HTMLElement | null;\n if (!deeper) break;\n active = deeper;\n }\n\n return active;\n };\n\n const onDocumentFocusIn = (event: FocusEvent): void => {\n if (event.composedPath().includes(el)) return;\n lastExternalFocus = deepActiveElement(el.ownerDocument);\n };\n\n const onToastFocusIn = (event: FocusEvent): void => {\n focusPaused.value = true;\n focusedWrapperId = wrapperFromEvent(event)?.dataset.toastId ?? null;\n restoreCheckFrames = 0;\n };\n\n const onToastFocusOut = (): void => {\n focusPaused.value = false;\n // Focusout fires before the next focusin settles; check after the microtask so a\n // move inside the region keeps the tracked wrapper while leaving clears it. Focus\n // that fell to `<body>` means the focused node was removed: keep the marker so\n // the restore in syncControls can hand focus back.\n void Promise.resolve().then(() => {\n const doc = el.ownerDocument;\n if (!focusPaused.value && doc.activeElement !== doc.body) focusedWrapperId = null;\n });\n };\n\n /** Escape dismisses the newest dismissible toast when nothing inside the toast region\n * holds focus (the in-region handler owns that case and stops the event) and no\n * top-layer surface is open: those own the Escape key. */\n const onDocumentKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || event.defaultPrevented || modalPaused.value) return;\n if (focusPaused.value) return;\n\n const newest = [...entries.value].reverse().find((entry) => entry.dismissible && entry.phase !== 'exiting');\n\n if (newest) {\n event.preventDefault();\n store?.dismiss(newest.id);\n }\n };\n\n const createToastSwipe = (id: string, wrapper: HTMLElement): PanGesture => {\n const isDismissible = (): boolean => entries.value.find((entry) => entry.id === id)?.dismissible ?? true;\n const reset = (): void => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = '';\n inner.style.transform = '';\n inner.style.opacity = '';\n };\n\n return createPanGesture(wrapper, {\n axis: 'x',\n disabled: () => !isDismissible(),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) {\n reset();\n\n return;\n }\n\n const inner = getInner(wrapper);\n\n if (!inner || !store) return;\n\n store.dismiss(id);\n\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n inner.style.opacity = '0';\n store.scheduleFinalization(id, 0);\n\n return;\n }\n\n const direction = distance >= 0 ? 1 : -1;\n\n inner.style.transition = 'transform 0.22s ease-out, opacity 0.22s ease-out';\n void inner.offsetWidth;\n inner.style.transform = `translateX(${direction * 120}%)`;\n inner.style.opacity = '0';\n\n // Removal spans the 0.22s flight; the store's dismiss() timeout is rescheduled\n // here so the swipe animation finishes before the node leaves the DOM.\n store.scheduleFinalization(id, 300);\n },\n onMove: ({ distance }) => {\n const inner = getInner(wrapper);\n\n if (!inner) return;\n\n inner.style.transition = 'none';\n inner.style.transform = `translateX(${distance}px)`;\n inner.style.opacity = String(Math.max(0, 1 - Math.abs(distance) / 200));\n },\n pointerCapture: false,\n shouldStart: (event) =>\n !event\n .composedPath()\n .some((node) => node instanceof Element && node.matches('button, a, input, select, textarea, ore-button')),\n });\n };\n\n const syncControls = (): void => {\n const currentIds = new Set(entries.value.map((entry) => entry.id));\n\n for (const [id, control] of swipeControls) {\n if (!currentIds.has(id)) {\n control.gesture.dispose();\n\n swipeControls.delete(id);\n }\n }\n\n // A removed wrapper that held focus drops focus to `<body>`; hand it back so\n // keyboard users keep their place. The entry leaves the store before the keyed\n // removal unmounts the focused node, so the frame re-checks below perform the\n // restore once focus has actually fallen to `<body>`.\n if (focusedWrapperId !== null && !currentIds.has(focusedWrapperId)) {\n const doc = el.ownerDocument;\n\n if (doc.activeElement === doc.body) {\n const restore = lastExternalFocus;\n focusedWrapperId = null;\n if (restore?.isConnected) restore.focus();\n } else if (restoreCheckFrames < 10) {\n // The keyed removal has not unmounted the focused node yet; re-check until\n // focus actually falls to `<body>`. A timer, not a frame: animation frames\n // never fire while the tab is hidden, and toasts outlive tab switches.\n restoreCheckFrames += 1;\n setTimeout(() => syncControls(), 16);\n }\n }\n\n for (const entry of entries.value) {\n const wrapper = containerRef.value?.querySelector<HTMLElement>(`[data-toast-id=\"${entry.id}\"]`);\n const control = swipeControls.get(entry.id);\n\n if (wrapper && control?.element !== wrapper) {\n control?.gesture.dispose();\n swipeControls.set(entry.id, { element: wrapper, gesture: createToastSwipe(entry.id, wrapper) });\n }\n }\n };\n\n const scheduleSyncControls = (): void => {\n syncControls();\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n pendingSyncFrame = requestAnimationFrame(() => {\n pendingSyncFrame = undefined;\n syncControls();\n });\n };\n\n watch(entries, scheduleSyncControls);\n watch(paused, (isPaused) => {\n if (isPaused) store?.pauseTimers();\n else store?.resumeTimers();\n });\n\n const bind = (nextStore: ToastStore): void => {\n if (store === nextStore) return;\n\n unsubscribeEntries();\n\n unsubscribeEvents();\n store = nextStore;\n store.setMax(props.max.value);\n unsubscribeEntries = store.subscribe((nextEntries) => {\n entries.value = nextEntries;\n });\n unsubscribeEvents = store.tap((event) => {\n if (event.type === 'dispose') return;\n emit(event.type, { id: event.id });\n });\n\n if (paused.value) store.pauseTimers();\n };\n\n /** Escape dismisses the notification that currently holds focus. */\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n\n const id = wrapperFromEvent(event)?.dataset.toastId;\n const entry = id ? entries.value.find((candidate) => candidate.id === id) : undefined;\n\n if (!entry?.dismissible) return;\n\n event.preventDefault();\n event.stopPropagation();\n store?.dismiss(entry.id);\n };\n\n const renderEntry = (item: Readable<ToastEntry>) => {\n const id = item.value.id;\n const dismiss = () => store?.dismiss(id);\n const meta = computed(() => item.value.meta ?? '');\n const innerClass = computed(\n () =>\n `toast-inner${item.value.phase !== 'active' ? ` ${item.value.phase}` : ''}${\n item.value.snackbar ? ' snackbar' : ''\n }`,\n );\n const innerStyle = computed(\n () =>\n `--_toast-accent: var(--color-${item.value.color || 'primary'}); --_toast-radius: var(--rounded-${\n item.value.rounded || (item.value.snackbar ? 'sm' : 'md')\n })`,\n );\n // Progress restarts from the correct fraction whenever the timer is (re)scheduled:\n // the animation runs for the full duration with a negative delay for elapsed time.\n const progressStyle = computed(() => {\n const { duration, timer } = item.value;\n\n if (!timer || duration <= 0) return '';\n\n return `--_toast-duration: ${duration}ms; --_toast-elapsed: -${Math.max(0, duration - timer.remaining)}ms`;\n });\n\n return html`\n <div class=\"toast-wrapper\" data-toast-id=${id} part=\"toast-wrapper\">\n <div class=${() => innerClass.value} style=${() => innerStyle.value} part=\"toast-inner\">\n <ore-alert\n embedded\n color=${() => item.value.color || (urgencyOf(item.value) === 'assertive' ? 'error' : 'primary')}\n variant=${() => (item.value.snackbar ? 'flat' : item.value.variant || 'solid')}\n size=${() => item.value.size || 'md'}\n rounded=${() => item.value.rounded || 'md'}\n ?horizontal=${() => Boolean(item.value.horizontal)}\n heading=${() => item.value.heading || null}\n ?dismissible=${() => item.value.dismissible}\n @dismiss=${dismiss}>\n <span slot=\"meta\" ?hidden=${() => !meta.value}>${() => meta.value}</span>\n ${() => item.value.message} ${renderToastActions(item, dismiss)}\n </ore-alert>\n <div\n class=\"toast-progress\"\n part=\"progress\"\n style=${() => progressStyle.value}\n ?hidden=${() => !progressStyle.value}\n aria-hidden=\"true\"></div>\n </div>\n </div>\n `;\n };\n\n onMounted(() => {\n hostBindings.set(el, {\n bind,\n unbind() {\n unsubscribeEntries();\n unsubscribeEvents();\n store = null;\n entries.value = [];\n },\n });\n\n const doc = el.ownerDocument;\n\n // The host mounts with the first toast, so pre-toast focus was never tracked by\n // the document listener: snapshot where focus sits right now (the control that\n // triggered the toast) as the restore target.\n const beforeFirstToast = deepActiveElement(doc);\n lastExternalFocus = beforeFirstToast !== doc.body ? beforeFirstToast : null;\n\n doc.addEventListener('focusin', onDocumentFocusIn);\n doc.addEventListener('keydown', onDocumentKeydown);\n // `toggle` does not bubble; the capture listener still sees dialog and popover toggles.\n doc.addEventListener('toggle', syncTopLayer, true);\n doc.addEventListener('fullscreenchange', syncTopLayer);\n syncTopLayer();\n\n const boundStore = hostStores.get(el);\n\n if (boundStore) bind(boundStore);\n });\n\n onCleanup(() => {\n hostBindings.get(el)?.unbind();\n\n hostBindings.delete(el);\n\n if (pendingSyncFrame !== undefined) cancelAnimationFrame(pendingSyncFrame);\n\n for (const control of swipeControls.values()) control.gesture.dispose();\n swipeControls.clear();\n\n const doc = el.ownerDocument;\n\n doc.removeEventListener('focusin', onDocumentFocusIn);\n doc.removeEventListener('keydown', onDocumentKeydown);\n doc.removeEventListener('toggle', syncTopLayer, true);\n doc.removeEventListener('fullscreenchange', syncTopLayer);\n });\n\n const politeEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'polite'));\n const assertiveEntries = computed(() => entries.value.filter((entry) => urgencyOf(entry) === 'assertive'));\n const keyOf = (entry: ToastEntry) => entry.id;\n\n return html`\n <div\n class=${() => `toast-container${paused.value ? ' paused' : ''}`}\n ref=${containerRef}\n @pointerenter=${() => {\n hoverPaused.value = true;\n }}\n @pointerleave=${() => {\n hoverPaused.value = false;\n }}\n @focusin=${onToastFocusIn}\n @focusout=${onToastFocusOut}\n @keydown=${onKeydown}\n part=\"container\">\n <div\n role=\"region\"\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Notifications\"\n class=\"toast-live-region\">\n ${each(politeEntries, keyOf, renderEntry)}\n </div>\n <div\n role=\"region\"\n aria-live=\"assertive\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Critical notifications\"\n class=\"toast-live-region\">\n ${each(assertiveEntries, keyOf, renderEntry)}\n </div>\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n\nexport type ToastServiceConfig = OreToastProps;\n\nexport interface ToastService {\n add(item: ToastItem): string;\n clear(): void;\n configure(config: ToastServiceConfig): void;\n dismiss(id: string): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n error(message: string, opts?: Partial<ToastItem>): string;\n info(message: string, opts?: Partial<ToastItem>): string;\n promise<T>(\n promise: Promise<T>,\n messages: {\n error: string | ((err: unknown) => string);\n loading: string;\n success: string | ((data: T) => string);\n },\n ): Promise<T>;\n success(message: string, opts?: Partial<ToastItem>): string;\n /** Side-channel observation of add/dispose/dismiss transitions; handler errors are swallowed. */\n tap(handler: (event: ToastEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n update(id: string, updates: Partial<ToastItem>): void;\n warning(message: string, opts?: Partial<ToastItem>): string;\n [Symbol.dispose](): void;\n}\n\nconst services = new WeakMap<ParentNode, ToastService>();\n\n/**\n * Creates a scoped toast service. The service owns its notification store and\n * binds it to the declarative `<ore-toast>` host inside `root`, creating that\n * host lazily when notifications are first requested.\n */\nexport function createToastService(root: ParentNode = document.body): ToastService {\n const existing = services.get(root);\n\n if (existing) return existing;\n\n const store = new ToastStore();\n const disposalController = new AbortController();\n let disposed = false;\n let pendingConfig: ToastServiceConfig | null = null;\n let host: HTMLElement | null = null;\n\n const assertActive = (): boolean => !disposed;\n const rootNode = root as Element | Document | ShadowRoot;\n\n /** Applies stashed configuration to the host as attributes; the component's own `max`\n * watch and the bind-time seed carry them into the store, so this stays declarative. */\n const applyConfig = (): void => {\n if (!pendingConfig || !host) return;\n\n if (pendingConfig.position) host.setAttribute('position', pendingConfig.position);\n\n if (pendingConfig.max != null) host.setAttribute('max', String(pendingConfig.max));\n\n pendingConfig = null;\n };\n\n const getHost = (): HTMLElement | null => {\n if (!assertActive()) return null;\n\n if (host?.isConnected) return host;\n\n host = rootNode.querySelector<HTMLElement>(TOAST_TAG);\n\n if (!host) {\n host = document.createElement(TOAST_TAG);\n rootNode.appendChild(host);\n }\n\n applyConfig();\n bindToastHost(host, store);\n\n return host;\n };\n const ensureHost = (): boolean => Boolean(getHost());\n\n const service: ToastService = {\n add(item) {\n if (!ensureHost()) return item.id ?? crypto.randomUUID();\n\n return store.add(item);\n },\n\n clear() {\n if (ensureHost()) store.clear();\n },\n\n configure(config) {\n pendingConfig = { ...pendingConfig, ...config };\n applyConfig();\n },\n\n dismiss(id) {\n if (ensureHost()) store.dismiss(id);\n },\n\n get disposalSignal() {\n return disposalController.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n\n disposalController.abort();\n\n store.dispose();\n\n if (services.get(root) === service) services.delete(root);\n },\n\n get disposed() {\n return disposed;\n },\n\n error(message, opts) {\n return service.add({ color: 'error', ...opts, message });\n },\n\n info(message, opts) {\n return service.add({ color: 'info', ...opts, message });\n },\n\n async promise(promise, messages) {\n // The loading entry stays dismissible: if the promise never settles, the user keeps\n // an escape hatch instead of an immortal notification.\n const id = service.add({ color: 'primary', duration: 0, message: messages.loading });\n\n try {\n const data = await promise;\n\n service.update(id, {\n color: 'success',\n duration: 5000,\n message: typeof messages.success === 'function' ? messages.success(data) : messages.success,\n });\n\n return data;\n } catch (err) {\n service.update(id, {\n color: 'error',\n duration: 5000,\n message: typeof messages.error === 'function' ? messages.error(err) : messages.error,\n });\n throw err;\n }\n },\n\n success(message, opts) {\n return service.add({ color: 'success', ...opts, message });\n },\n\n tap(handler, options) {\n return store.tap(handler, options);\n },\n\n [Symbol.dispose]() {\n service.dispose();\n },\n\n update(id, updates) {\n if (ensureHost()) store.update(id, updates);\n },\n\n warning(message, opts) {\n return service.add({ color: 'warning', ...opts, message });\n },\n };\n\n services.set(root, service);\n\n return service;\n}\n\n/** Singleton service backed by a lazily created host in `document.body`. */\nexport const toast: ToastService = createToastService();\n"],"mappings":"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"}
@@ -3,11 +3,11 @@
3
3
  * This file is the single source of truth for DOM and framework element types.
4
4
  *
5
5
  * Every type referenced below is imported explicitly. The root tsconfig sets
6
- * `skipLibCheck: true`, which exempts `.d.ts` files from having their contents verified — an
6
+ * `skipLibCheck: true`, which exempts `.d.ts` files from having their contents verified: an
7
7
  * unresolvable bare type name here doesn't raise `TS2304: Cannot find name`, it silently
8
8
  * resolves to `any`, which then collapses the entire intersection it's part of to `any` too.
9
9
  * That turns every property/method access on the affected tag into a silent no-op for
10
- * consumers — no autocomplete, no error, nothing — which is a much worse failure mode than a
10
+ * consumers: no autocomplete, no error, nothing, which is a much worse failure mode than a
11
11
  * build error. Importing the real types is what keeps this file honest under `skipLibCheck`;
12
12
  * see `src/types/elements.test.ts` for the regression test that would have caught this.
13
13
  */
@@ -28,6 +28,8 @@ import type { OreListItemEvents, OreListItemProps } from '../content/list/list-i
28
28
  import type { OreMarqueeProps } from '../content/marquee/marquee.js';
29
29
  import type { OrePaginationEvents, OrePaginationProps } from '../content/pagination/pagination.js';
30
30
  import type { OreQrCodeEvents, OreQrCodeProps } from '../content/qr-code/qr-code.js';
31
+ import type { OreRankItemProps } from '../content/rank-list/rank-item.js';
32
+ import type { OreRankListProps } from '../content/rank-list/rank-list.js';
31
33
  import type { OreSeparatorProps } from '../content/separator/separator.js';
32
34
  import type { OreSpeechPlayerEvents, SpeechPlayerElement } from '../content/speech-player/speech-player.js';
33
35
  import type { OreStatsProps } from '../content/stats/stats.js';
@@ -181,6 +183,8 @@ export interface RefineElementMap {
181
183
  'ore-qr-scanner': HTMLElement & OreQrScannerProps & AddEventListeners<OreQrScannerEvents>;
182
184
  'ore-radio': HTMLElement & OreRadioProps & FormValidityMethods & AddEventListeners<OreRadioEvents>;
183
185
  'ore-radio-group': HTMLElement & OreRadioGroupProps & FormValidityMethods & AddEventListeners<OreRadioGroupEvents>;
186
+ 'ore-rank-item': HTMLElement & OreRankItemProps;
187
+ 'ore-rank-list': HTMLElement & OreRankListProps;
184
188
  'ore-rating': HTMLElement & OreRatingProps & FormValidityMethods & AddEventListeners<OreRatingEvents>;
185
189
  'ore-select': HTMLElement & OreSelectProps & FormValidityMethods & AddEventListeners<OreSelectEvents>;
186
190
  'ore-separator': HTMLElement & OreSeparatorProps;
@@ -1 +1 @@
1
- {"version":3,"file":"typing-indicator.cjs","names":[],"sources":["../src/feedback/typing-indicator/typing-indicator.ts"],"sourcesContent":["import { define, getHost, html, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\nimport { announce } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './typing-indicator.css?inline';\n\n/** Typing indicator component properties */\nexport type OreTypingIndicatorProps = {\n /** Theme color for the dots */\n color?: ThemeColor;\n /** Accessible label announced once via a polite live region (default: `\"Typing…\"`) */\n label?: string;\n /** Dot size preset */\n size?: ComponentSize;\n};\n\n/**\n * Three bouncing dots signaling that the other side of a conversation is composing a reply —\n * the moment before any content exists. For a message whose content is already streaming in,\n * use `ore-chat-message`'s `streaming` attribute (a blinking cursor) instead.\n *\n * The dots are decorative (`aria-hidden`) — `label` is the entire accessibility contract,\n * announced through the shared singleton live region (`core/announcer.ts`) rather than a\n * static `aria-live` element in the template. A live region populated in the same paint as\n * its own insertion is unreliable across browsers/screen readers; routing through the shared\n * announcer (pre-existing region, clear-then-set, document-scoped) is the same pattern\n * already used for other transient status messages across this package.\n *\n * @element ore-typing-indicator\n *\n * @attr {string} label - Accessible label announced once via a polite live region (default: \"Typing…\")\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @cssprop --typing-indicator-color - Dot color\n * @cssprop --typing-indicator-size - Dot diameter\n * @cssprop --typing-indicator-gap - Gap between dots\n *\n * @part dots - Dots container.\n * @part dot - Individual dot element.\n * @example\n * ```html\n * <ore-typing-indicator></ore-typing-indicator>\n * <ore-typing-indicator label=\"Assistant is typing…\" color=\"primary\"></ore-typing-indicator>\n * ```\n */\nexport const TYPING_INDICATOR_TAG = 'ore-typing-indicator' as const;\ndefine<OreTypingIndicatorProps>(TYPING_INDICATOR_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n label: prop.string('Typing…'),\n },\n setup(props) {\n const el = getHost();\n\n watch(\n () => props.label.value,\n (label) => announce(label ?? '', { document: el.ownerDocument }),\n { immediate: true },\n );\n\n return html`\n <span class=\"dots\" part=\"dots\" aria-hidden=\"true\">\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n </span>\n `;\n },\n styles: [\n colorThemeMixin,\n reducedMotionMixin,\n sizeVariantMixin({\n lg: {\n gap: 'var(--typing-indicator-gap, var(--size-1-5))',\n size: 'var(--typing-indicator-size, var(--size-2-5))',\n },\n md: { gap: 'var(--typing-indicator-gap, var(--size-1))', size: 'var(--typing-indicator-size, var(--size-2))' },\n sm: {\n gap: 'var(--typing-indicator-gap, var(--size-1))',\n size: 'var(--typing-indicator-size, var(--size-1-5))',\n },\n }),\n componentStyles,\n ],\n});\n"],"mappings":"0ZAgDA,IAAa,EAAuB,wBACpC,EAAA,EAAA,OAAA,CAAgC,EAAsB,CACpD,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,MAAO,EAAA,KAAK,OAAO,SAAS,CAC9B,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EAQnB,OANA,EAAA,EAAA,MAAA,KACQ,EAAM,MAAM,MACjB,GAAU,EAAA,SAAS,GAAS,GAAI,CAAE,SAAU,EAAG,aAAc,CAAC,EAC/D,CAAE,UAAW,EAAK,CACpB,EAEO,EAAA,IAAI;;;;;;KAOb,EACA,OAAQ,CACN,EAAA,gBACA,EAAA,mBACA,EAAA,iBAAiB,CACf,GAAI,CACF,IAAK,+CACL,KAAM,+CACR,EACA,GAAI,CAAE,IAAK,6CAA8C,KAAM,6CAA8C,EAC7G,GAAI,CACF,IAAK,6CACL,KAAM,+CACR,CACF,CAAC,EACD,EAAA,OACF,CACF,CAAC"}
1
+ {"version":3,"file":"typing-indicator.cjs","names":[],"sources":["../src/feedback/typing-indicator/typing-indicator.ts"],"sourcesContent":["import { define, getHost, html, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\nimport { announce } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './typing-indicator.css?inline';\n\n/** Typing indicator component properties */\nexport type OreTypingIndicatorProps = {\n /** Theme color for the dots */\n color?: ThemeColor;\n /** Accessible label announced once via a polite live region (default: `\"Typing…\"`) */\n label?: string;\n /** Dot size preset */\n size?: ComponentSize;\n};\n\n/**\n * Three bouncing dots signaling that the other side of a conversation is composing a reply :\n * the moment before any content exists. For a message whose content is already streaming in,\n * use `ore-chat-message`'s `streaming` attribute (a blinking cursor) instead.\n *\n * The dots are decorative (`aria-hidden`): `label` is the entire accessibility contract,\n * announced through the shared singleton live region (`core/announcer.ts`) rather than a\n * static `aria-live` element in the template. A live region populated in the same paint as\n * its own insertion is unreliable across browsers/screen readers; routing through the shared\n * announcer (pre-existing region, clear-then-set, document-scoped) is the same pattern\n * already used for other transient status messages across this package.\n *\n * @element ore-typing-indicator\n *\n * @attr {string} label - Accessible label announced once via a polite live region (default: \"Typing…\")\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @cssprop --typing-indicator-color - Dot color\n * @cssprop --typing-indicator-size - Dot diameter\n * @cssprop --typing-indicator-gap - Gap between dots\n *\n * @part dots - Dots container.\n * @part dot - Individual dot element.\n * @example\n * ```html\n * <ore-typing-indicator></ore-typing-indicator>\n * <ore-typing-indicator label=\"Assistant is typing…\" color=\"primary\"></ore-typing-indicator>\n * ```\n */\nexport const TYPING_INDICATOR_TAG = 'ore-typing-indicator' as const;\ndefine<OreTypingIndicatorProps>(TYPING_INDICATOR_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n label: prop.string('Typing…'),\n },\n setup(props) {\n const el = getHost();\n\n watch(\n () => props.label.value,\n (label) => announce(label ?? '', { document: el.ownerDocument }),\n { immediate: true },\n );\n\n return html`\n <span class=\"dots\" part=\"dots\" aria-hidden=\"true\">\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n </span>\n `;\n },\n styles: [\n colorThemeMixin,\n reducedMotionMixin,\n sizeVariantMixin({\n lg: {\n gap: 'var(--typing-indicator-gap, var(--size-1-5))',\n size: 'var(--typing-indicator-size, var(--size-2-5))',\n },\n md: { gap: 'var(--typing-indicator-gap, var(--size-1))', size: 'var(--typing-indicator-size, var(--size-2))' },\n sm: {\n gap: 'var(--typing-indicator-gap, var(--size-1))',\n size: 'var(--typing-indicator-size, var(--size-1-5))',\n },\n }),\n componentStyles,\n ],\n});\n"],"mappings":"0ZAgDA,IAAa,EAAuB,wBACpC,EAAA,EAAA,OAAA,CAAgC,EAAsB,CACpD,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,MAAO,EAAA,KAAK,OAAO,SAAS,CAC9B,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EAQnB,OANA,EAAA,EAAA,MAAA,KACQ,EAAM,MAAM,MACjB,GAAU,EAAA,SAAS,GAAS,GAAI,CAAE,SAAU,EAAG,aAAc,CAAC,EAC/D,CAAE,UAAW,EAAK,CACpB,EAEO,EAAA,IAAI;;;;;;KAOb,EACA,OAAQ,CACN,EAAA,gBACA,EAAA,mBACA,EAAA,iBAAiB,CACf,GAAI,CACF,IAAK,+CACL,KAAM,+CACR,EACA,GAAI,CAAE,IAAK,6CAA8C,KAAM,6CAA8C,EAC7G,GAAI,CACF,IAAK,6CACL,KAAM,+CACR,CACF,CAAC,EACD,EAAA,OACF,CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"typing-indicator.js","names":[],"sources":["../src/feedback/typing-indicator/typing-indicator.ts"],"sourcesContent":["import { define, getHost, html, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\nimport { announce } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './typing-indicator.css?inline';\n\n/** Typing indicator component properties */\nexport type OreTypingIndicatorProps = {\n /** Theme color for the dots */\n color?: ThemeColor;\n /** Accessible label announced once via a polite live region (default: `\"Typing…\"`) */\n label?: string;\n /** Dot size preset */\n size?: ComponentSize;\n};\n\n/**\n * Three bouncing dots signaling that the other side of a conversation is composing a reply —\n * the moment before any content exists. For a message whose content is already streaming in,\n * use `ore-chat-message`'s `streaming` attribute (a blinking cursor) instead.\n *\n * The dots are decorative (`aria-hidden`) — `label` is the entire accessibility contract,\n * announced through the shared singleton live region (`core/announcer.ts`) rather than a\n * static `aria-live` element in the template. A live region populated in the same paint as\n * its own insertion is unreliable across browsers/screen readers; routing through the shared\n * announcer (pre-existing region, clear-then-set, document-scoped) is the same pattern\n * already used for other transient status messages across this package.\n *\n * @element ore-typing-indicator\n *\n * @attr {string} label - Accessible label announced once via a polite live region (default: \"Typing…\")\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @cssprop --typing-indicator-color - Dot color\n * @cssprop --typing-indicator-size - Dot diameter\n * @cssprop --typing-indicator-gap - Gap between dots\n *\n * @part dots - Dots container.\n * @part dot - Individual dot element.\n * @example\n * ```html\n * <ore-typing-indicator></ore-typing-indicator>\n * <ore-typing-indicator label=\"Assistant is typing…\" color=\"primary\"></ore-typing-indicator>\n * ```\n */\nexport const TYPING_INDICATOR_TAG = 'ore-typing-indicator' as const;\ndefine<OreTypingIndicatorProps>(TYPING_INDICATOR_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n label: prop.string('Typing…'),\n },\n setup(props) {\n const el = getHost();\n\n watch(\n () => props.label.value,\n (label) => announce(label ?? '', { document: el.ownerDocument }),\n { immediate: true },\n );\n\n return html`\n <span class=\"dots\" part=\"dots\" aria-hidden=\"true\">\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n </span>\n `;\n },\n styles: [\n colorThemeMixin,\n reducedMotionMixin,\n sizeVariantMixin({\n lg: {\n gap: 'var(--typing-indicator-gap, var(--size-1-5))',\n size: 'var(--typing-indicator-size, var(--size-2-5))',\n },\n md: { gap: 'var(--typing-indicator-gap, var(--size-1))', size: 'var(--typing-indicator-size, var(--size-2))' },\n sm: {\n gap: 'var(--typing-indicator-gap, var(--size-1))',\n size: 'var(--typing-indicator-size, var(--size-1-5))',\n },\n }),\n componentStyles,\n ],\n});\n"],"mappings":"yfAgDA,IAAa,EAAuB,uBACpC,EAAgC,EAAsB,CACpD,MAAO,CACL,GAAG,EACH,GAAG,EACH,MAAO,EAAK,OAAO,SAAS,CAC9B,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EAQnB,OANA,MACQ,EAAM,MAAM,MACjB,GAAU,EAAS,GAAS,GAAI,CAAE,SAAU,EAAG,aAAc,CAAC,EAC/D,CAAE,UAAW,EAAK,CACpB,EAEO,CAAI;;;;;;KAOb,EACA,OAAQ,CACN,EACA,EACA,EAAiB,CACf,GAAI,CACF,IAAK,+CACL,KAAM,+CACR,EACA,GAAI,CAAE,IAAK,6CAA8C,KAAM,6CAA8C,EAC7G,GAAI,CACF,IAAK,6CACL,KAAM,+CACR,CACF,CAAC,EACD,CACF,CACF,CAAC"}
1
+ {"version":3,"file":"typing-indicator.js","names":[],"sources":["../src/feedback/typing-indicator/typing-indicator.ts"],"sourcesContent":["import { define, getHost, html, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\nimport { announce } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './typing-indicator.css?inline';\n\n/** Typing indicator component properties */\nexport type OreTypingIndicatorProps = {\n /** Theme color for the dots */\n color?: ThemeColor;\n /** Accessible label announced once via a polite live region (default: `\"Typing…\"`) */\n label?: string;\n /** Dot size preset */\n size?: ComponentSize;\n};\n\n/**\n * Three bouncing dots signaling that the other side of a conversation is composing a reply :\n * the moment before any content exists. For a message whose content is already streaming in,\n * use `ore-chat-message`'s `streaming` attribute (a blinking cursor) instead.\n *\n * The dots are decorative (`aria-hidden`): `label` is the entire accessibility contract,\n * announced through the shared singleton live region (`core/announcer.ts`) rather than a\n * static `aria-live` element in the template. A live region populated in the same paint as\n * its own insertion is unreliable across browsers/screen readers; routing through the shared\n * announcer (pre-existing region, clear-then-set, document-scoped) is the same pattern\n * already used for other transient status messages across this package.\n *\n * @element ore-typing-indicator\n *\n * @attr {string} label - Accessible label announced once via a polite live region (default: \"Typing…\")\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @cssprop --typing-indicator-color - Dot color\n * @cssprop --typing-indicator-size - Dot diameter\n * @cssprop --typing-indicator-gap - Gap between dots\n *\n * @part dots - Dots container.\n * @part dot - Individual dot element.\n * @example\n * ```html\n * <ore-typing-indicator></ore-typing-indicator>\n * <ore-typing-indicator label=\"Assistant is typing…\" color=\"primary\"></ore-typing-indicator>\n * ```\n */\nexport const TYPING_INDICATOR_TAG = 'ore-typing-indicator' as const;\ndefine<OreTypingIndicatorProps>(TYPING_INDICATOR_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n label: prop.string('Typing…'),\n },\n setup(props) {\n const el = getHost();\n\n watch(\n () => props.label.value,\n (label) => announce(label ?? '', { document: el.ownerDocument }),\n { immediate: true },\n );\n\n return html`\n <span class=\"dots\" part=\"dots\" aria-hidden=\"true\">\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n <span class=\"dot\" part=\"dot\"></span>\n </span>\n `;\n },\n styles: [\n colorThemeMixin,\n reducedMotionMixin,\n sizeVariantMixin({\n lg: {\n gap: 'var(--typing-indicator-gap, var(--size-1-5))',\n size: 'var(--typing-indicator-size, var(--size-2-5))',\n },\n md: { gap: 'var(--typing-indicator-gap, var(--size-1))', size: 'var(--typing-indicator-size, var(--size-2))' },\n sm: {\n gap: 'var(--typing-indicator-gap, var(--size-1))',\n size: 'var(--typing-indicator-size, var(--size-1-5))',\n },\n }),\n componentStyles,\n ],\n});\n"],"mappings":"yfAgDA,IAAa,EAAuB,uBACpC,EAAgC,EAAsB,CACpD,MAAO,CACL,GAAG,EACH,GAAG,EACH,MAAO,EAAK,OAAO,SAAS,CAC9B,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EAQnB,OANA,MACQ,EAAM,MAAM,MACjB,GAAU,EAAS,GAAS,GAAI,CAAE,SAAU,EAAG,aAAc,CAAC,EAC/D,CAAE,UAAW,EAAK,CACpB,EAEO,CAAI;;;;;;KAOb,EACA,OAAQ,CACN,EACA,EACA,EAAiB,CACf,GAAI,CACF,IAAK,+CACL,KAAM,+CACR,EACA,GAAI,CAAE,IAAK,6CAA8C,KAAM,6CAA8C,EAC7G,GAAI,CACF,IAAK,6CACL,KAAM,+CACR,CACF,CAAC,EACD,CACF,CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"css.cjs","names":[],"sources":["../../src/utils/css.ts"],"sourcesContent":["/**\n * Validates that a string is a safe CSS length value before injecting it\n * into a CSS custom property. Accepts standard length units, percentages,\n * CSS keywords, and `calc()`/`var()` expressions without embedded semicolons,\n * curly braces, or other CSS injection vectors.\n *\n * @returns The trimmed value if safe, `null` otherwise.\n */\nexport function safeCSSLength(value: string | null | undefined): string | null {\n if (!value) return null;\n\n const v = value.trim();\n\n // Block CSS injection sequences (parens excluded — needed by var()/calc())\n if (/[;{}\\n\\r]/.test(v)) return null;\n\n // Allow: numbers with units, %, keywords, var(--token), calc(...), env(...)\n if (\n /^-?(\\d+(\\.\\d+)?)(px|em|rem|%|vh|vw|vmin|vmax|dvh|dvw|svh|svw|ch|ex|lh|rlh|cm|mm|in|pt|pc|fr|s|ms|deg|rad|turn)$/.test(\n v,\n )\n )\n return v;\n\n if (/^(0|auto|none|inherit|initial|unset|revert)$/.test(v)) return v;\n\n // Allow CSS function expressions: var(--token), calc(...), env(...), clamp(...), min(...), max(...)\n // Tightened pattern: must match the whole value and inner parens must close properly.\n if (/^(var|calc|env|clamp|min|max)\\([^;{}]*\\)$/.test(v)) return v;\n\n return null;\n}\n"],"mappings":"AAQA,SAAgB,cAAc,EAAiD,CAC7E,GAAI,CAAC,EAAO,OAAO,KAEnB,IAAM,EAAI,EAAM,KAAK,EAmBrB,MAhBI,YAAY,KAAK,CAAC,EAAU,KAI9B,kHAAkH,KAChH,CACF,GAIE,+CAA+C,KAAK,CAAC,GAIrD,4CAA4C,KAAK,CAAC,EAAU,EAEzD,IACT"}
1
+ {"version":3,"file":"css.cjs","names":[],"sources":["../../src/utils/css.ts"],"sourcesContent":["/**\n * Validates that a string is a safe CSS length value before injecting it\n * into a CSS custom property. Accepts standard length units, percentages,\n * CSS keywords, and `calc()`/`var()` expressions without embedded semicolons,\n * curly braces, or other CSS injection vectors.\n *\n * @returns The trimmed value if safe, `null` otherwise.\n */\nexport function safeCSSLength(value: string | null | undefined): string | null {\n if (!value) return null;\n\n const v = value.trim();\n\n // Block CSS injection sequences (parens excluded: needed by var()/calc())\n if (/[;{}\\n\\r]/.test(v)) return null;\n\n // Allow: numbers with units, %, keywords, var(--token), calc(...), env(...)\n if (\n /^-?(\\d+(\\.\\d+)?)(px|em|rem|%|vh|vw|vmin|vmax|dvh|dvw|svh|svw|ch|ex|lh|rlh|cm|mm|in|pt|pc|fr|s|ms|deg|rad|turn)$/.test(\n v,\n )\n )\n return v;\n\n if (/^(0|auto|none|inherit|initial|unset|revert)$/.test(v)) return v;\n\n // Allow CSS function expressions: var(--token), calc(...), env(...), clamp(...), min(...), max(...)\n // Tightened pattern: must match the whole value and inner parens must close properly.\n if (/^(var|calc|env|clamp|min|max)\\([^;{}]*\\)$/.test(v)) return v;\n\n return null;\n}\n"],"mappings":"AAQA,SAAgB,cAAc,EAAiD,CAC7E,GAAI,CAAC,EAAO,OAAO,KAEnB,IAAM,EAAI,EAAM,KAAK,EAmBrB,MAhBI,YAAY,KAAK,CAAC,EAAU,KAI9B,kHAAkH,KAChH,CACF,GAIE,+CAA+C,KAAK,CAAC,GAIrD,4CAA4C,KAAK,CAAC,EAAU,EAEzD,IACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"css.js","names":[],"sources":["../../src/utils/css.ts"],"sourcesContent":["/**\n * Validates that a string is a safe CSS length value before injecting it\n * into a CSS custom property. Accepts standard length units, percentages,\n * CSS keywords, and `calc()`/`var()` expressions without embedded semicolons,\n * curly braces, or other CSS injection vectors.\n *\n * @returns The trimmed value if safe, `null` otherwise.\n */\nexport function safeCSSLength(value: string | null | undefined): string | null {\n if (!value) return null;\n\n const v = value.trim();\n\n // Block CSS injection sequences (parens excluded — needed by var()/calc())\n if (/[;{}\\n\\r]/.test(v)) return null;\n\n // Allow: numbers with units, %, keywords, var(--token), calc(...), env(...)\n if (\n /^-?(\\d+(\\.\\d+)?)(px|em|rem|%|vh|vw|vmin|vmax|dvh|dvw|svh|svw|ch|ex|lh|rlh|cm|mm|in|pt|pc|fr|s|ms|deg|rad|turn)$/.test(\n v,\n )\n )\n return v;\n\n if (/^(0|auto|none|inherit|initial|unset|revert)$/.test(v)) return v;\n\n // Allow CSS function expressions: var(--token), calc(...), env(...), clamp(...), min(...), max(...)\n // Tightened pattern: must match the whole value and inner parens must close properly.\n if (/^(var|calc|env|clamp|min|max)\\([^;{}]*\\)$/.test(v)) return v;\n\n return null;\n}\n"],"mappings":"AAQA,SAAgB,cAAc,EAAiD,CAC7E,GAAI,CAAC,EAAO,OAAO,KAEnB,IAAM,EAAI,EAAM,KAAK,EAmBrB,MAhBI,YAAY,KAAK,CAAC,EAAU,KAI9B,kHAAkH,KAChH,CACF,GAIE,+CAA+C,KAAK,CAAC,GAIrD,4CAA4C,KAAK,CAAC,EAAU,EAEzD,IACT"}
1
+ {"version":3,"file":"css.js","names":[],"sources":["../../src/utils/css.ts"],"sourcesContent":["/**\n * Validates that a string is a safe CSS length value before injecting it\n * into a CSS custom property. Accepts standard length units, percentages,\n * CSS keywords, and `calc()`/`var()` expressions without embedded semicolons,\n * curly braces, or other CSS injection vectors.\n *\n * @returns The trimmed value if safe, `null` otherwise.\n */\nexport function safeCSSLength(value: string | null | undefined): string | null {\n if (!value) return null;\n\n const v = value.trim();\n\n // Block CSS injection sequences (parens excluded: needed by var()/calc())\n if (/[;{}\\n\\r]/.test(v)) return null;\n\n // Allow: numbers with units, %, keywords, var(--token), calc(...), env(...)\n if (\n /^-?(\\d+(\\.\\d+)?)(px|em|rem|%|vh|vw|vmin|vmax|dvh|dvw|svh|svw|ch|ex|lh|rlh|cm|mm|in|pt|pc|fr|s|ms|deg|rad|turn)$/.test(\n v,\n )\n )\n return v;\n\n if (/^(0|auto|none|inherit|initial|unset|revert)$/.test(v)) return v;\n\n // Allow CSS function expressions: var(--token), calc(...), env(...), clamp(...), min(...), max(...)\n // Tightened pattern: must match the whole value and inner parens must close properly.\n if (/^(var|calc|env|clamp|min|max)\\([^;{}]*\\)$/.test(v)) return v;\n\n return null;\n}\n"],"mappings":"AAQA,SAAgB,cAAc,EAAiD,CAC7E,GAAI,CAAC,EAAO,OAAO,KAEnB,IAAM,EAAI,EAAM,KAAK,EAmBrB,MAhBI,YAAY,KAAK,CAAC,EAAU,KAI9B,kHAAkH,KAChH,CACF,GAIE,+CAA+C,KAAK,CAAC,GAIrD,4CAA4C,KAAK,CAAC,EAAU,EAEzD,IACT"}