@ctrl-ui/react 0.8.6 → 0.8.8

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 (376) hide show
  1. package/dist/action-bar.d.ts +15 -7
  2. package/dist/action-bar.js +39 -19
  3. package/dist/activity.js +7 -15
  4. package/dist/audio-recorder.d.ts +14 -4
  5. package/dist/audio-recorder.js +82 -29
  6. package/dist/audio-visualizer.js +1 -1
  7. package/dist/blocks/coding-agent.js +54 -57
  8. package/dist/blocks/design-canvas-data.d.ts +32 -0
  9. package/dist/blocks/design-canvas-data.js +100 -0
  10. package/dist/blocks/design-canvas-inspector.d.ts +8 -0
  11. package/dist/blocks/design-canvas-inspector.js +238 -0
  12. package/dist/blocks/design-canvas.d.ts +21 -0
  13. package/dist/blocks/design-canvas.js +452 -0
  14. package/dist/blocks/discussion.d.ts +28 -0
  15. package/dist/blocks/discussion.js +67 -0
  16. package/dist/blocks/file-explorer-data.d.ts +1 -0
  17. package/dist/blocks/file-explorer-data.js +4 -1
  18. package/dist/blocks/file-explorer.d.ts +9 -1
  19. package/dist/blocks/file-explorer.js +461 -192
  20. package/dist/blocks/settings.d.ts +2 -1
  21. package/dist/blocks/settings.js +101 -79
  22. package/dist/blocks/team-chat.d.ts +12 -0
  23. package/dist/blocks/team-chat.js +26 -0
  24. package/dist/blocks/theme-toggle.js +23 -31
  25. package/dist/chat-composer-attachment.d.ts +12 -3
  26. package/dist/chat-composer-attachment.js +61 -19
  27. package/dist/chat-composer-editor/extensions/mention.d.ts +5 -1
  28. package/dist/chat-composer-editor/extensions/mention.js +58 -27
  29. package/dist/chat-composer-editor/ghost.js +2 -4
  30. package/dist/chat-composer-editor/types.d.ts +5 -0
  31. package/dist/chat-composer-editor.d.ts +1 -1
  32. package/dist/chat-composer-editor.js +71 -28
  33. package/dist/chat-composer.d.ts +13 -32
  34. package/dist/chat-composer.js +54 -13
  35. package/dist/chat-layout.d.ts +19 -0
  36. package/dist/chat-layout.js +96 -32
  37. package/dist/chat-message/social.d.ts +26 -0
  38. package/dist/chat-message/social.js +122 -0
  39. package/dist/chat-message.d.ts +28 -29
  40. package/dist/chat-message.js +106 -25
  41. package/dist/context.d.ts +2 -2
  42. package/dist/context.js +38 -23
  43. package/dist/dynamic-notification-canvas-loop.d.ts +24 -0
  44. package/dist/dynamic-notification-canvas-loop.js +113 -0
  45. package/dist/dynamic-notification-glass.js +23 -114
  46. package/dist/dynamic-notification-liquid.js +14 -118
  47. package/dist/dynamic-notification.d.ts +16 -8
  48. package/dist/dynamic-notification.js +85 -22
  49. package/dist/email/email-brand.d.ts +7 -4
  50. package/dist/email/email-brand.js +9 -6
  51. package/dist/email/email-code.d.ts +3 -2
  52. package/dist/email/email-code.js +11 -9
  53. package/dist/email/email-footer.d.ts +5 -3
  54. package/dist/email/email-footer.js +11 -5
  55. package/dist/email/email.d.ts +31 -9
  56. package/dist/email/email.js +50 -26
  57. package/dist/email/templates.d.ts +10 -9
  58. package/dist/email/templates.js +102 -38
  59. package/dist/email/theme.js +1 -1
  60. package/dist/environment-variables.d.ts +4 -2
  61. package/dist/environment-variables.js +52 -32
  62. package/dist/filter-bar/context.d.ts +32 -0
  63. package/dist/filter-bar/context.js +11 -0
  64. package/dist/filter-bar/editor.d.ts +14 -0
  65. package/dist/filter-bar/editor.js +216 -0
  66. package/dist/filter-bar/model.d.ts +10 -0
  67. package/dist/filter-bar/model.js +57 -0
  68. package/dist/filter-bar/motion.d.ts +10 -0
  69. package/dist/filter-bar/motion.js +84 -0
  70. package/dist/filter-bar/parts.d.ts +19 -0
  71. package/dist/filter-bar/parts.js +244 -0
  72. package/dist/filter-bar/types.d.ts +54 -0
  73. package/dist/filter-bar/types.js +0 -0
  74. package/dist/filter-bar.d.ts +27 -0
  75. package/dist/filter-bar.js +310 -0
  76. package/dist/hooks/use-audio-recorder.js +12 -6
  77. package/dist/hooks/use-chat-composer.d.ts +21 -7
  78. package/dist/hooks/use-chat-composer.js +32 -5
  79. package/dist/hooks/use-chat-message.d.ts +28 -2
  80. package/dist/hooks/use-chat-message.js +41 -10
  81. package/dist/hooks/use-chat-thread-scroll.js +43 -7
  82. package/dist/hooks/use-color-area.d.ts +3 -3
  83. package/dist/hooks/use-color-area.js +13 -12
  84. package/dist/hooks/use-copy-to-clipboard.d.ts +2 -1
  85. package/dist/hooks/use-copy-to-clipboard.js +20 -20
  86. package/dist/hooks/use-dropzone.d.ts +7 -4
  87. package/dist/hooks/use-dropzone.js +34 -3
  88. package/dist/hooks/use-dynamic-notification.d.ts +6 -2
  89. package/dist/hooks/use-dynamic-notification.js +26 -10
  90. package/dist/hooks/use-mobile.d.ts +3 -2
  91. package/dist/hooks/use-mobile.js +8 -4
  92. package/dist/hooks/use-textarea-trigger-menu.js +2 -1
  93. package/dist/hooks/use-trigger-menu.d.ts +54 -0
  94. package/dist/hooks/use-trigger-menu.js +102 -47
  95. package/dist/hooks/use-user-ask.d.ts +2 -0
  96. package/dist/hooks/use-user-ask.js +35 -41
  97. package/dist/inline-attachment.d.ts +6 -2
  98. package/dist/inline-attachment.js +44 -29
  99. package/dist/inline-citation.d.ts +12 -5
  100. package/dist/inline-citation.js +25 -16
  101. package/dist/knob-contracts/audio-recorder-knobs.d.ts +1 -1
  102. package/dist/knob-contracts/audio-recorder-knobs.js +2 -1
  103. package/dist/knob-contracts/audio-visualizer-knobs.d.ts +1 -1
  104. package/dist/knob-contracts/audio-visualizer-knobs.js +2 -1
  105. package/dist/knob-contracts/avatar-knobs.d.ts +1 -1
  106. package/dist/knob-contracts/avatar-knobs.js +6 -1
  107. package/dist/knob-contracts/badge-knobs.d.ts +1 -1
  108. package/dist/knob-contracts/badge-knobs.js +2 -1
  109. package/dist/knob-contracts/breadcrumb-knobs.d.ts +4 -0
  110. package/dist/knob-contracts/breadcrumb-knobs.js +8 -0
  111. package/dist/knob-contracts/button-knobs.d.ts +1 -1
  112. package/dist/knob-contracts/button-knobs.js +1 -0
  113. package/dist/knob-contracts/chat-layout-knobs.d.ts +1 -1
  114. package/dist/knob-contracts/chat-layout-knobs.js +2 -1
  115. package/dist/knob-contracts/chat-message-knobs.d.ts +1 -1
  116. package/dist/knob-contracts/chat-message-knobs.js +8 -1
  117. package/dist/knob-contracts/choice-knobs.d.ts +1 -1
  118. package/dist/knob-contracts/choice-knobs.js +1 -0
  119. package/dist/knob-contracts/code-diff-knobs.d.ts +1 -1
  120. package/dist/knob-contracts/code-diff-knobs.js +2 -0
  121. package/dist/knob-contracts/code-knobs.d.ts +1 -1
  122. package/dist/knob-contracts/code-knobs.js +2 -1
  123. package/dist/knob-contracts/collapsible-knobs.d.ts +1 -1
  124. package/dist/knob-contracts/collapsible-knobs.js +1 -1
  125. package/dist/knob-contracts/dynamic-notification-knobs.d.ts +1 -1
  126. package/dist/knob-contracts/dynamic-notification-knobs.js +2 -0
  127. package/dist/knob-contracts/emoji-picker-knobs.d.ts +4 -0
  128. package/dist/knob-contracts/emoji-picker-knobs.js +10 -0
  129. package/dist/knob-contracts/field-knobs.d.ts +1 -1
  130. package/dist/knob-contracts/field-knobs.js +5 -1
  131. package/dist/knob-contracts/filter-bar-knobs.d.ts +4 -0
  132. package/dist/knob-contracts/filter-bar-knobs.js +15 -0
  133. package/dist/knob-contracts/infinite-canvas-knobs.d.ts +1 -1
  134. package/dist/knob-contracts/infinite-canvas-knobs.js +3 -0
  135. package/dist/knob-contracts/markdown-knobs.d.ts +1 -1
  136. package/dist/knob-contracts/markdown-knobs.js +3 -1
  137. package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
  138. package/dist/knob-contracts/page-layout-knobs.js +4 -1
  139. package/dist/knob-contracts/popup-knobs.d.ts +1 -1
  140. package/dist/knob-contracts/popup-knobs.js +28 -0
  141. package/dist/knob-contracts/range-knobs.d.ts +1 -1
  142. package/dist/knob-contracts/range-knobs.js +1 -0
  143. package/dist/knob-contracts/rich-tooltip-knobs.d.ts +1 -1
  144. package/dist/knob-contracts/rich-tooltip-knobs.js +2 -1
  145. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  146. package/dist/knob-contracts/sidebar-knobs.js +27 -2
  147. package/dist/knob-contracts/spinner-knobs.d.ts +1 -1
  148. package/dist/knob-contracts/spinner-knobs.js +1 -1
  149. package/dist/knob-contracts/stepper-knobs.d.ts +1 -1
  150. package/dist/knob-contracts/stepper-knobs.js +4 -1
  151. package/dist/knob-contracts/switch-knobs.d.ts +1 -1
  152. package/dist/knob-contracts/switch-knobs.js +5 -0
  153. package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
  154. package/dist/knob-contracts/table-of-contents-knobs.js +4 -5
  155. package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
  156. package/dist/knob-contracts/tabs-knobs.js +1 -0
  157. package/dist/knob-contracts/tree-knobs.d.ts +1 -1
  158. package/dist/knob-contracts/tree-knobs.js +2 -1
  159. package/dist/lib/cn.js +0 -4
  160. package/dist/lib/contrast.d.ts +1 -0
  161. package/dist/lib/contrast.js +17 -5
  162. package/dist/lib/dropzone-validation.js +41 -28
  163. package/dist/lib/env-file.d.ts +1 -1
  164. package/dist/lib/env-file.js +5 -5
  165. package/dist/lib/motion.d.ts +4 -0
  166. package/dist/lib/motion.js +15 -0
  167. package/dist/lib/trigger-detect.js +6 -8
  168. package/dist/markdown-block.js +13 -8
  169. package/dist/popup-parts.d.ts +8 -0
  170. package/dist/popup-parts.js +43 -0
  171. package/dist/scripts/contrast-eval.js +5 -4
  172. package/dist/source-badge.js +3 -1
  173. package/dist/styles/code.css +0 -2
  174. package/dist/styles/effects.css +6 -32
  175. package/dist/styles/index.css +14 -8
  176. package/dist/styles/recipes/accordion.css +9 -6
  177. package/dist/styles/recipes/action-bar.css +0 -15
  178. package/dist/styles/recipes/activity.css +5 -11
  179. package/dist/styles/recipes/alert.css +4 -4
  180. package/dist/styles/recipes/audio-recorder.css +15 -3
  181. package/dist/styles/recipes/audio-visualizer.css +13 -2
  182. package/dist/styles/recipes/avatar.css +78 -1
  183. package/dist/styles/recipes/badge.css +14 -4
  184. package/dist/styles/recipes/breadcrumb.css +77 -0
  185. package/dist/styles/recipes/button-group.css +6 -8
  186. package/dist/styles/recipes/button-states.css +66 -0
  187. package/dist/styles/recipes/button.css +26 -85
  188. package/dist/styles/recipes/calendar.css +17 -23
  189. package/dist/styles/recipes/card.css +2 -2
  190. package/dist/styles/recipes/chat-composer-attachment.css +9 -3
  191. package/dist/styles/recipes/chat-composer.css +21 -16
  192. package/dist/styles/recipes/chat-layout.css +64 -2
  193. package/dist/styles/recipes/chat-message-social.css +123 -0
  194. package/dist/styles/recipes/chat-message.css +157 -37
  195. package/dist/styles/recipes/choice.css +25 -21
  196. package/dist/styles/recipes/code-diff.css +51 -26
  197. package/dist/styles/recipes/code.css +44 -18
  198. package/dist/styles/recipes/collapsible.css +43 -1
  199. package/dist/styles/recipes/color-picker-details.css +3 -4
  200. package/dist/styles/recipes/color-picker-values.css +9 -8
  201. package/dist/styles/recipes/color-picker.css +23 -4
  202. package/dist/styles/recipes/context.css +3 -3
  203. package/dist/styles/recipes/dockable-panel.css +18 -7
  204. package/dist/styles/recipes/dropzone.css +7 -8
  205. package/dist/styles/recipes/dynamic-notification-input.css +8 -5
  206. package/dist/styles/recipes/dynamic-notification-motion.css +12 -21
  207. package/dist/styles/recipes/dynamic-notification.css +40 -26
  208. package/dist/styles/recipes/emoji-picker.css +132 -0
  209. package/dist/styles/recipes/empty.css +5 -4
  210. package/dist/styles/recipes/environment-variables.css +4 -15
  211. package/dist/styles/recipes/field-parts.css +89 -21
  212. package/dist/styles/recipes/field.css +83 -26
  213. package/dist/styles/recipes/filter-bar.css +161 -0
  214. package/dist/styles/recipes/gradient-editor.css +18 -7
  215. package/dist/styles/recipes/infinite-canvas.css +51 -4
  216. package/dist/styles/recipes/inline-attachment.css +9 -4
  217. package/dist/styles/recipes/inline-citation.css +10 -4
  218. package/dist/styles/recipes/item.css +23 -9
  219. package/dist/styles/recipes/markdown-block.css +5 -4
  220. package/dist/styles/recipes/markdown.css +68 -26
  221. package/dist/styles/recipes/morphing-panel.css +8 -8
  222. package/dist/styles/recipes/page-layout.css +36 -10
  223. package/dist/styles/recipes/pagination.css +5 -6
  224. package/dist/styles/recipes/phone-input.css +12 -8
  225. package/dist/styles/recipes/popup-controls.css +175 -26
  226. package/dist/styles/recipes/popup-drawer.css +35 -44
  227. package/dist/styles/recipes/popup-lists.css +139 -29
  228. package/dist/styles/recipes/popup-motion.css +4 -45
  229. package/dist/styles/recipes/popup-toast.css +55 -26
  230. package/dist/styles/recipes/popup.css +149 -153
  231. package/dist/styles/recipes/range.css +55 -19
  232. package/dist/styles/recipes/resizable.css +36 -7
  233. package/dist/styles/recipes/rich-tooltip.css +24 -34
  234. package/dist/styles/recipes/scroll-area.css +8 -1
  235. package/dist/styles/recipes/sidebar-menu.css +149 -34
  236. package/dist/styles/recipes/sidebar-parts.css +154 -0
  237. package/dist/styles/recipes/sidebar.css +187 -128
  238. package/dist/styles/recipes/source-badge.css +1 -1
  239. package/dist/styles/recipes/spinner.css +12 -1
  240. package/dist/styles/recipes/stepper.css +31 -13
  241. package/dist/styles/recipes/switch.css +68 -23
  242. package/dist/styles/recipes/table-of-contents.css +49 -41
  243. package/dist/styles/recipes/table.css +14 -10
  244. package/dist/styles/recipes/tabs.css +38 -12
  245. package/dist/styles/recipes/task-list.css +7 -14
  246. package/dist/styles/recipes/thread-rail.css +42 -19
  247. package/dist/styles/recipes/timeline.css +2 -0
  248. package/dist/styles/recipes/toolbar.css +27 -25
  249. package/dist/styles/recipes/track-highlight.css +12 -8
  250. package/dist/styles/recipes/transcript-divider.css +2 -2
  251. package/dist/styles/recipes/tree.css +31 -4
  252. package/dist/styles/recipes/user-ask-details.css +0 -1
  253. package/dist/styles/recipes/user-ask.css +4 -4
  254. package/dist/styles/theme.css +287 -107
  255. package/dist/task-list.d.ts +4 -1
  256. package/dist/task-list.js +24 -8
  257. package/dist/thread-rail.d.ts +1 -1
  258. package/dist/thread-rail.js +61 -19
  259. package/dist/transcript-divider.js +2 -1
  260. package/dist/ui/alert.d.ts +3 -1
  261. package/dist/ui/alert.js +14 -8
  262. package/dist/ui/autocomplete.js +7 -1
  263. package/dist/ui/avatar.d.ts +8 -0
  264. package/dist/ui/avatar.js +23 -3
  265. package/dist/ui/badge.js +1 -1
  266. package/dist/ui/breadcrumb.d.ts +27 -0
  267. package/dist/ui/breadcrumb.js +88 -0
  268. package/dist/ui/button.d.ts +2 -1
  269. package/dist/ui/button.js +1 -1
  270. package/dist/ui/calendar.js +2 -2
  271. package/dist/ui/card.d.ts +3 -1
  272. package/dist/ui/card.js +12 -7
  273. package/dist/ui/checkbox-group.js +1 -1
  274. package/dist/ui/checkbox.d.ts +2 -0
  275. package/dist/ui/code-diff.d.ts +1 -1
  276. package/dist/ui/code-diff.js +71 -27
  277. package/dist/ui/code.d.ts +5 -3
  278. package/dist/ui/code.js +27 -28
  279. package/dist/ui/color-picker.d.ts +5 -2
  280. package/dist/ui/color-picker.js +84 -36
  281. package/dist/ui/combobox-disabled-selection.d.ts +1 -2
  282. package/dist/ui/combobox-disabled-selection.js +7 -8
  283. package/dist/ui/combobox.d.ts +5 -23
  284. package/dist/ui/combobox.js +36 -16
  285. package/dist/ui/command.d.ts +8 -2
  286. package/dist/ui/command.js +39 -15
  287. package/dist/ui/context-menu.js +3 -0
  288. package/dist/ui/dialog.d.ts +2 -1
  289. package/dist/ui/dialog.js +3 -22
  290. package/dist/ui/dockable-panel-geometry.d.ts +1 -0
  291. package/dist/ui/dockable-panel-geometry.js +7 -1
  292. package/dist/ui/dockable-panel.d.ts +9 -6
  293. package/dist/ui/dockable-panel.js +81 -33
  294. package/dist/ui/drawer.d.ts +7 -4
  295. package/dist/ui/drawer.js +35 -22
  296. package/dist/ui/dropdown-menu.js +4 -3
  297. package/dist/ui/dropzone.d.ts +5 -3
  298. package/dist/ui/dropzone.js +78 -17
  299. package/dist/ui/emoji-picker.d.ts +18 -0
  300. package/dist/ui/emoji-picker.js +136 -0
  301. package/dist/ui/empty.d.ts +3 -1
  302. package/dist/ui/empty.js +12 -7
  303. package/dist/ui/field.js +1 -1
  304. package/dist/ui/gradient-editor.d.ts +1 -1
  305. package/dist/ui/gradient-editor.js +37 -21
  306. package/dist/ui/infinite-canvas.d.ts +13 -1
  307. package/dist/ui/infinite-canvas.js +139 -20
  308. package/dist/ui/input-group.d.ts +2 -4
  309. package/dist/ui/input-group.js +13 -14
  310. package/dist/ui/input-otp.d.ts +1 -1
  311. package/dist/ui/input-otp.js +32 -15
  312. package/dist/ui/input.js +11 -2
  313. package/dist/ui/item.d.ts +2 -1
  314. package/dist/ui/item.js +11 -7
  315. package/dist/ui/live-status.d.ts +7 -0
  316. package/dist/ui/live-status.js +17 -0
  317. package/dist/ui/markdown-elements.d.ts +6 -0
  318. package/dist/ui/markdown-elements.js +42 -9
  319. package/dist/ui/menubar.js +2 -2
  320. package/dist/ui/morphing-panel.js +2 -1
  321. package/dist/ui/native-select.d.ts +1 -1
  322. package/dist/ui/native-select.js +24 -11
  323. package/dist/ui/number-field.d.ts +1 -1
  324. package/dist/ui/number-field.js +13 -2
  325. package/dist/ui/page-layout.d.ts +2 -2
  326. package/dist/ui/page-layout.js +2 -4
  327. package/dist/ui/pagination.d.ts +7 -5
  328. package/dist/ui/pagination.js +19 -13
  329. package/dist/ui/phone-input.d.ts +1 -0
  330. package/dist/ui/phone-input.js +56 -58
  331. package/dist/ui/radio-group.d.ts +3 -0
  332. package/dist/ui/radio-group.js +11 -1
  333. package/dist/ui/resizable.d.ts +20 -2
  334. package/dist/ui/resizable.js +130 -8
  335. package/dist/ui/responsive-dialog.d.ts +1 -1
  336. package/dist/ui/responsive-dialog.js +9 -23
  337. package/dist/ui/rich-tooltip.d.ts +10 -4
  338. package/dist/ui/rich-tooltip.js +81 -33
  339. package/dist/ui/scroll-area.d.ts +4 -1
  340. package/dist/ui/scroll-area.js +44 -28
  341. package/dist/ui/select.d.ts +2 -1
  342. package/dist/ui/select.js +57 -32
  343. package/dist/ui/sidebar-menu.d.ts +5 -1
  344. package/dist/ui/sidebar-menu.js +31 -33
  345. package/dist/ui/sidebar-provider.d.ts +10 -1
  346. package/dist/ui/sidebar-provider.js +38 -13
  347. package/dist/ui/sidebar-resize-rail.js +7 -3
  348. package/dist/ui/sidebar.d.ts +11 -6
  349. package/dist/ui/sidebar.js +46 -23
  350. package/dist/ui/slider.js +31 -22
  351. package/dist/ui/spinner.d.ts +3 -2
  352. package/dist/ui/spinner.js +3 -2
  353. package/dist/ui/stepper.d.ts +8 -1
  354. package/dist/ui/stepper.js +74 -25
  355. package/dist/ui/switch.d.ts +1 -0
  356. package/dist/ui/table-of-contents.d.ts +5 -4
  357. package/dist/ui/table-of-contents.js +143 -52
  358. package/dist/ui/table.js +15 -9
  359. package/dist/ui/textarea.d.ts +1 -1
  360. package/dist/ui/textarea.js +20 -9
  361. package/dist/ui/timeline.d.ts +3 -1
  362. package/dist/ui/timeline.js +17 -9
  363. package/dist/ui/toast.d.ts +11 -5
  364. package/dist/ui/toast.js +100 -54
  365. package/dist/ui/toggle.d.ts +1 -1
  366. package/dist/ui/toggle.js +2 -1
  367. package/dist/ui/toolbar.d.ts +3 -2
  368. package/dist/ui/toolbar.js +4 -2
  369. package/dist/ui/tooltip.js +3 -20
  370. package/dist/ui/tree.js +120 -80
  371. package/dist/ui/trigger-menu.js +7 -2
  372. package/dist/user-ask.d.ts +10 -5
  373. package/dist/user-ask.js +31 -11
  374. package/package.json +5 -1
  375. package/dist/hooks/use-keyboard-navigation.d.ts +0 -3
  376. package/dist/hooks/use-keyboard-navigation.js +0 -22
@@ -1,22 +1,42 @@
1
1
  "use client";
2
2
  import { cn } from "./lib/cn.js";
3
- import { useChatMessage } from "./hooks/use-chat-message.js";
4
- import { createContext, useContext } from "react";
3
+ import { ChatMessageStateProvider, chatAuthorLabels, chatMessageStatusLabels, chatMessageTransition, useChatMessage, useChatMessageContext, useChatThreadAnnounce } from "./hooks/use-chat-message.js";
4
+ import { ChatMessageReaction, ChatMessageReactions, ChatMessageReplies, ChatMessageReplySummary, ChatTypingIndicator } from "./chat-message/social.js";
5
+ import { useEffect, useRef } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/chat-message.tsx
7
- const ChatMessageContext = createContext(null);
8
- function useChatMessageContext() {
9
- const context = useContext(ChatMessageContext);
10
- if (!context) throw new Error("ChatMessage compound components must be rendered inside <ChatMessage>.");
11
- return context;
12
- }
13
- function ChatMessage({ from, state = "idle", density = "comfortable", className, children, ...props }) {
8
+ function ChatMessage({ from, state = "idle", density = "comfortable", layout = "bubble", continuation = false, authorLabel = chatAuthorLabels[from], statusLabels, className, children, ...props }) {
14
9
  const message = useChatMessage({
15
10
  from,
16
11
  state,
17
- density
12
+ density,
13
+ layout,
14
+ continuation
18
15
  });
19
- return /* @__PURE__ */ jsx(ChatMessageContext.Provider, {
16
+ const announce = useChatThreadAnnounce();
17
+ const previousState = useRef(state);
18
+ const pendingLabel = statusLabels?.pending ?? chatMessageStatusLabels.pending;
19
+ const repliedLabel = statusLabels?.replied ?? chatMessageStatusLabels.replied;
20
+ const errorLabel = statusLabels?.error ?? chatMessageStatusLabels.error;
21
+ useEffect(() => {
22
+ const previous = previousState.current;
23
+ previousState.current = state;
24
+ if (from === "user" || from === "participant") return;
25
+ const announcement = chatMessageTransition(previous, state, {
26
+ pending: pendingLabel,
27
+ replied: repliedLabel,
28
+ error: errorLabel
29
+ });
30
+ if (announcement !== null) announce(announcement);
31
+ }, [
32
+ announce,
33
+ from,
34
+ state,
35
+ pendingLabel,
36
+ repliedLabel,
37
+ errorLabel
38
+ ]);
39
+ return /* @__PURE__ */ jsx(ChatMessageStateProvider, {
20
40
  value: message,
21
41
  children: /* @__PURE__ */ jsx("article", {
22
42
  "data-control-ui": "chat-message",
@@ -25,6 +45,9 @@ function ChatMessage({ from, state = "idle", density = "comfortable", className,
25
45
  "data-role": from,
26
46
  "data-state": state,
27
47
  "data-density": density,
48
+ "data-layout": layout,
49
+ "data-continuation": continuation ? "" : void 0,
50
+ "aria-label": authorLabel,
28
51
  className: cn("w-full", className),
29
52
  ...props,
30
53
  children
@@ -37,36 +60,68 @@ function ChatMessageRow({ className, children, ...props }) {
37
60
  "data-control-ui": "chat-message",
38
61
  "data-control-family": "chat-message",
39
62
  "data-slot": "row",
40
- className: cn("flex w-full", message.isUser ? "justify-end" : "justify-start", className),
63
+ "data-layout": message.layout,
64
+ "data-density": message.density,
65
+ "data-continuation": message.continuation ? "" : void 0,
66
+ className: cn("relative flex w-full", message.isEndAligned ? "justify-end" : "justify-start", className),
41
67
  ...props,
42
68
  children
43
69
  });
44
70
  }
45
71
  function ChatMessageAvatar({ className, ...props }) {
72
+ const message = useChatMessageContext();
46
73
  return /* @__PURE__ */ jsx("div", {
47
74
  "data-control-ui": "chat-message",
48
75
  "data-control-family": "chat-message",
49
76
  "data-slot": "avatar",
77
+ "data-layout": message.layout,
78
+ "data-continuation": message.continuation ? "" : void 0,
50
79
  className: cn("flex shrink-0 items-center justify-center", className),
51
80
  ...props
52
81
  });
53
82
  }
54
83
  function ChatMessageBody({ className, ...props }) {
55
- useChatMessageContext();
84
+ const message = useChatMessageContext();
56
85
  return /* @__PURE__ */ jsx("div", {
57
86
  "data-control-ui": "chat-message",
58
87
  "data-control-family": "chat-message",
59
88
  "data-slot": "body",
60
- className: cn("min-w-0", className),
89
+ "data-layout": message.layout,
90
+ "data-role": message.from,
91
+ className: cn("flex min-w-0 flex-col", className),
61
92
  ...props
62
93
  });
63
94
  }
64
95
  function ChatMessageHeader({ className, ...props }) {
96
+ const message = useChatMessageContext();
65
97
  return /* @__PURE__ */ jsx("div", {
66
98
  "data-control-ui": "chat-message",
67
99
  "data-control-family": "chat-message",
68
100
  "data-slot": "header",
69
- className: cn("flex items-center", className),
101
+ "data-layout": message.layout,
102
+ "data-role": message.from,
103
+ "data-state": message.state,
104
+ className: cn("flex min-w-0 flex-wrap items-baseline", className),
105
+ ...props
106
+ });
107
+ }
108
+ function ChatMessageAuthor({ className, ...props }) {
109
+ const message = useChatMessageContext();
110
+ return /* @__PURE__ */ jsx("span", {
111
+ "data-control-ui": "chat-message",
112
+ "data-control-family": "chat-message",
113
+ "data-slot": "author",
114
+ "data-layout": message.layout,
115
+ className: cn("truncate", className),
116
+ ...props
117
+ });
118
+ }
119
+ function ChatMessageTime({ className, ...props }) {
120
+ return /* @__PURE__ */ jsx("time", {
121
+ "data-control-ui": "chat-message",
122
+ "data-control-family": "chat-message",
123
+ "data-slot": "time",
124
+ className: cn("whitespace-nowrap tabular-nums", className),
70
125
  ...props
71
126
  });
72
127
  }
@@ -78,35 +133,61 @@ function ChatMessageContent({ className, ...props }) {
78
133
  "data-slot": "content",
79
134
  "data-role": message.from,
80
135
  "data-streaming": message.isStreaming ? "" : void 0,
81
- className: cn(message.isUser && "px-[var(--padding-x)] py-[var(--padding-y)]", className),
136
+ className: cn(message.isBubble && "px-[var(--padding-x)] py-[var(--padding-y)]", className),
82
137
  ...props
83
138
  });
84
139
  }
85
- function ChatMessagePending({ label = "Assistant is replying", className, ...props }) {
140
+ /** Visual only: the pending transition is announced by `ChatMessage` through the thread's status region. */
141
+ function ChatMessagePending({ className, ...props }) {
86
142
  if (!useChatMessageContext().isPending) return null;
87
143
  return /* @__PURE__ */ jsxs("div", {
88
- role: "status",
89
- "aria-label": label,
144
+ "aria-hidden": "true",
90
145
  "data-control-ui": "chat-message",
91
146
  "data-control-family": "chat-message",
92
147
  "data-slot": "pending",
93
148
  className: cn("inline-flex items-center", className),
94
149
  ...props,
95
150
  children: [
96
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }),
97
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }),
98
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true" })
151
+ /* @__PURE__ */ jsx("span", {}),
152
+ /* @__PURE__ */ jsx("span", {}),
153
+ /* @__PURE__ */ jsx("span", {})
99
154
  ]
100
155
  });
101
156
  }
102
- function ChatMessageActions({ className, ...props }) {
157
+ function ChatMessageFooter({ className, ...props }) {
158
+ const message = useChatMessageContext();
103
159
  return /* @__PURE__ */ jsx("div", {
160
+ "data-control-ui": "chat-message",
161
+ "data-control-family": "chat-message",
162
+ "data-slot": "footer",
163
+ "data-layout": message.layout,
164
+ "data-role": message.from,
165
+ "data-state": message.state,
166
+ className: cn("flex flex-wrap items-center", className),
167
+ ...props
168
+ });
169
+ }
170
+ function ChatMessageActions({ className, children, ...props }) {
171
+ const { layout } = useChatMessageContext();
172
+ return /* @__PURE__ */ jsxs("div", {
104
173
  "data-control-ui": "chat-message",
105
174
  "data-control-family": "chat-message",
106
175
  "data-slot": "actions",
176
+ "data-layout": layout,
107
177
  className: cn("flex items-center", className),
108
- ...props
178
+ ...props,
179
+ children: [layout === "flat" ? /* @__PURE__ */ jsx("div", {
180
+ "aria-hidden": "true",
181
+ "data-control-ui": "chat-message",
182
+ "data-control-family": "popup",
183
+ "data-popup-kind": "toolbar",
184
+ "data-popup-part": "surface",
185
+ "data-popup-static": "",
186
+ "data-surface": "floating",
187
+ "data-slot": "actions-surface",
188
+ className: "pointer-events-none absolute inset-0 -z-1"
189
+ }) : null, children]
109
190
  });
110
191
  }
111
192
  //#endregion
112
- export { ChatMessage, ChatMessageActions, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageHeader, ChatMessagePending, ChatMessageRow };
193
+ export { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessagePending, ChatMessageReaction, ChatMessageReactions, ChatMessageReplies, ChatMessageReplySummary, ChatMessageRow, ChatMessageTime, ChatTypingIndicator };
package/dist/context.d.ts CHANGED
@@ -24,7 +24,7 @@ type ContextStyleProps<Props, Style> = Omit<Props, "style"> & {
24
24
  };
25
25
  export declare function Context({ segments, maxTokens, model: modelName, locale, open, defaultOpen, onOpenChange, className, children, ...props }: ContextProps): import("react").JSX.Element;
26
26
  export type ContextTriggerProps = ContextStyleProps<ComponentProps<typeof Button>, ButtonKnobStyle & ContextKnobStyle>;
27
- export declare function ContextTrigger({ "aria-label": ariaLabel, variant, size, className, children, ...props }: ContextTriggerProps): import("react").JSX.Element;
27
+ export declare function ContextTrigger({ "aria-describedby": describedBy, variant, size, className, children, ...props }: ContextTriggerProps): import("react").JSX.Element;
28
28
  export type ContextContentProps = ContextStyleProps<ComponentProps<typeof PopoverContent>, PopupKnobStyle & ContextKnobStyle>;
29
29
  export declare function ContextContent({ "aria-label": ariaLabel, side, align, sideOffset, collisionPadding, padding, className, children, ...props }: ContextContentProps): import("react").JSX.Element;
30
30
  export type ContextHeaderProps = ComponentProps<"div"> & {
@@ -38,7 +38,7 @@ export declare function ContextDescription({ className, children, ...props }: Co
38
38
  export type ContextSummaryProps = ContextStyleProps<ComponentProps<"div">, ContextKnobStyle>;
39
39
  export declare function ContextSummary({ className, children, ...props }: ContextSummaryProps): import("react").JSX.Element;
40
40
  export type ContextGraphProps = ContextStyleProps<Omit<ComponentProps<"svg">, "children">, ContextKnobStyle>;
41
- export declare function ContextGraph({ className, ...props }: ContextGraphProps): import("react").JSX.Element;
41
+ export declare function ContextGraph({ "aria-label": ariaLabel, className, ...props }: ContextGraphProps): import("react").JSX.Element;
42
42
  export type ContextLegendProps = ContextStyleProps<ComponentProps<"ul">, ContextKnobStyle>;
43
43
  export declare function ContextLegend({ className, children, ...props }: ContextLegendProps): import("react").JSX.Element;
44
44
  export type ContextCloseProps = ComponentProps<typeof Button>;
package/dist/context.js CHANGED
@@ -4,7 +4,7 @@ import { Button } from "./ui/button.js";
4
4
  import { ScrollArea } from "./ui/scroll-area.js";
5
5
  import { deriveContextModel } from "./context-model.js";
6
6
  import { Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "./ui/popover.js";
7
- import { createContext, useContext } from "react";
7
+ import { createContext, useContext, useId, useMemo } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { X } from "lucide-react";
10
10
  //#region src/context.tsx
@@ -16,14 +16,20 @@ function useContextValue() {
16
16
  }
17
17
  function Context({ segments, maxTokens, model: modelName, locale, open, defaultOpen, onOpenChange, className, children, ...props }) {
18
18
  const model = deriveContextModel(segments, maxTokens);
19
+ const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);
20
+ const percentageFormatter = useMemo(() => new Intl.NumberFormat(locale, {
21
+ style: "percent",
22
+ maximumFractionDigits: 1
23
+ }), [locale]);
24
+ const percentage = model.ratio === null ? null : percentageFormatter.format(model.ratio);
25
+ const usedTokens = numberFormatter.format(model.usedTokens);
19
26
  const context = {
20
27
  model,
21
28
  modelName,
22
- numberFormatter: new Intl.NumberFormat(locale),
23
- percentageFormatter: new Intl.NumberFormat(locale, {
24
- style: "percent",
25
- maximumFractionDigits: 1
26
- })
29
+ numberFormatter,
30
+ percentageFormatter,
31
+ percentage,
32
+ usage: model.maxTokens === null ? `${usedTokens} tokens used; limit unavailable` : `${usedTokens} of ${numberFormatter.format(model.maxTokens)} tokens used (${percentage})${model.overageTokens > 0 ? `; ${numberFormatter.format(model.overageTokens)} tokens over limit` : ""}`
27
33
  };
28
34
  return /* @__PURE__ */ jsx(ContextValueContext.Provider, {
29
35
  value: context,
@@ -43,24 +49,22 @@ function Context({ segments, maxTokens, model: modelName, locale, open, defaultO
43
49
  })
44
50
  });
45
51
  }
46
- function ContextTrigger({ "aria-label": ariaLabel, variant = "surface", size = "sm", className, children, ...props }) {
47
- const { model, numberFormatter, percentageFormatter } = useContextValue();
48
- const percentage = model.ratio === null ? null : percentageFormatter.format(model.ratio);
52
+ function ContextTrigger({ "aria-describedby": describedBy, variant = "surface", size = "sm", className, children, ...props }) {
53
+ const { model, percentage, usage } = useContextValue();
54
+ const usageId = useId();
49
55
  const visualPercentage = Math.min(100, Math.max(0, (model.ratio ?? 0) * 100));
50
- const shortLabel = percentage === null ? "Context unavailable" : `${percentage} context`;
51
- const accessibleLabel = model.maxTokens === null ? `Context window: ${numberFormatter.format(model.usedTokens)} tokens used; limit unavailable` : `Context window: ${numberFormatter.format(model.usedTokens)} of ${numberFormatter.format(model.maxTokens)} tokens used (${percentage})${model.overageTokens > 0 ? `; ${numberFormatter.format(model.overageTokens)} tokens over limit` : ""}`;
52
- return /* @__PURE__ */ jsx("span", {
56
+ return /* @__PURE__ */ jsxs("span", {
53
57
  "data-control-ui": "context",
54
58
  "data-control-family": "context",
55
59
  "data-slot": "trigger",
56
60
  "data-status": model.status,
57
61
  className: "relative inline-flex",
58
- children: /* @__PURE__ */ jsx(Button, {
62
+ children: [/* @__PURE__ */ jsx(Button, {
59
63
  ...props,
60
64
  render: /* @__PURE__ */ jsx(PopoverTrigger, {}),
61
65
  variant,
62
66
  size,
63
- "aria-label": ariaLabel ?? accessibleLabel,
67
+ "aria-describedby": describedBy ? `${usageId} ${describedBy}` : usageId,
64
68
  className: cn("group/context after:absolute after:-inset-1.5 after:content-['']", className),
65
69
  children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("svg", {
66
70
  "data-control-ui": "context",
@@ -96,9 +100,13 @@ function ContextTrigger({ "aria-label": ariaLabel, variant = "surface", size = "
96
100
  "data-control-ui": "context",
97
101
  "data-control-family": "context",
98
102
  "data-slot": "trigger-label",
99
- children: shortLabel
103
+ children: percentage === null ? "Context unavailable" : `${percentage} context`
100
104
  })] })
101
- })
105
+ }), /* @__PURE__ */ jsx("span", {
106
+ id: usageId,
107
+ className: "sr-only",
108
+ children: usage
109
+ })]
102
110
  });
103
111
  }
104
112
  function ContextContent({ "aria-label": ariaLabel, side = "top", align = "end", sideOffset = 8, collisionPadding = 16, padding = "none", className, children, ...props }) {
@@ -170,8 +178,7 @@ function ContextDescription({ className, children, ...props }) {
170
178
  });
171
179
  }
172
180
  function ContextSummary({ className, children, ...props }) {
173
- const { model, numberFormatter, percentageFormatter } = useContextValue();
174
- const percentage = model.ratio === null ? null : percentageFormatter.format(model.ratio);
181
+ const { model, numberFormatter, percentage } = useContextValue();
175
182
  return /* @__PURE__ */ jsx("div", {
176
183
  ...props,
177
184
  "data-control-ui": "context",
@@ -183,21 +190,29 @@ function ContextSummary({ className, children, ...props }) {
183
190
  "data-control-ui": "context",
184
191
  "data-control-family": "context",
185
192
  "data-slot": "summary-value",
186
- children: model.maxTokens === null ? "Limit unavailable" : `${numberFormatter.format(model.usedTokens)} / ${numberFormatter.format(model.maxTokens)} tokens`
193
+ children: model.maxTokens === null ? "Limit unavailable" : `${numberFormatter.format(model.usedTokens)} of ${numberFormatter.format(model.maxTokens)} tokens`
187
194
  })] })
188
195
  });
189
196
  }
190
- function ContextGraph({ className, ...props }) {
191
- const { model } = useContextValue();
197
+ function ContextGraph({ "aria-label": ariaLabel = "Context usage", className, ...props }) {
198
+ const { model, usage } = useContextValue();
199
+ const meterProps = model.maxTokens === null ? { "aria-hidden": true } : {
200
+ role: "meter",
201
+ "aria-label": ariaLabel,
202
+ "aria-valuemin": 0,
203
+ "aria-valuemax": model.maxTokens,
204
+ "aria-valuenow": Math.min(model.usedTokens, model.maxTokens),
205
+ "aria-valuetext": usage
206
+ };
192
207
  return /* @__PURE__ */ jsxs("svg", {
193
208
  ...props,
209
+ ...meterProps,
194
210
  "data-control-ui": "context",
195
211
  "data-control-family": "context",
196
212
  "data-slot": "graph",
197
213
  "data-status": model.status,
198
214
  viewBox: "0 0 100 10",
199
215
  preserveAspectRatio: "none",
200
- "aria-hidden": "true",
201
216
  className: cn("w-full overflow-hidden", className),
202
217
  children: [
203
218
  /* @__PURE__ */ jsx("rect", {
@@ -322,7 +337,7 @@ function ContextClose({ variant = "ghost", size = "xs", iconOnly = true, "aria-l
322
337
  size,
323
338
  iconOnly,
324
339
  "aria-label": ariaLabel,
325
- className: cn("ml-auto", className),
340
+ className: cn("ms-auto", className),
326
341
  children: children ?? /* @__PURE__ */ jsx(X, {
327
342
  "aria-hidden": "true",
328
343
  className: "size-4"
@@ -0,0 +1,24 @@
1
+ //#region src/dynamic-notification-canvas-loop.d.ts
2
+ export type NotificationCanvasFrame = {
3
+ reduced: boolean;
4
+ now: number;
5
+ deltaMs: number;
6
+ };
7
+ export type NotificationCanvasLoop = {
8
+ invalidate: () => void;
9
+ cancel: () => void;
10
+ destroy: () => void;
11
+ };
12
+ export type NotificationMotionValues = {
13
+ radius: number;
14
+ aurora: number;
15
+ reveal: number;
16
+ settle: number;
17
+ lift: number;
18
+ };
19
+ export declare function createNotificationMotion(initialState: string | undefined): {
20
+ values: NotificationMotionValues;
21
+ advance: (state: string | undefined, radius: number, reduced: boolean, deltaMs: number) => boolean;
22
+ };
23
+ export declare function createNotificationCanvasLoop(canvas: HTMLCanvasElement, render: (frame: NotificationCanvasFrame) => boolean): NotificationCanvasLoop;
24
+ //#endregion
@@ -0,0 +1,113 @@
1
+ import { prefersReducedMotion } from "./lib/motion.js";
2
+ //#region src/dynamic-notification-canvas-loop.ts
3
+ const FRAME_MS_AT_60HZ = 1e3 / 60;
4
+ const MAX_FRAME_DELTA_MS = 100;
5
+ function approachAt60Hz(current, target, response, deltaMs) {
6
+ const frameScale = Math.max(0, deltaMs) / FRAME_MS_AT_60HZ;
7
+ return current + (target - current) * (1 - (1 - response) ** frameScale);
8
+ }
9
+ function motionTargets(state, radius) {
10
+ const thinking = state === "thinking";
11
+ return {
12
+ radius,
13
+ aurora: thinking ? 1 : 0,
14
+ reveal: state === "collapsed" ? 0 : 1,
15
+ settle: state === "expanded" ? 1 : 0,
16
+ lift: thinking ? 0 : 1
17
+ };
18
+ }
19
+ function createNotificationMotion(initialState) {
20
+ const values = motionTargets(initialState, 0);
21
+ function advance(state, radius, reduced, deltaMs) {
22
+ const targets = motionTargets(state, radius);
23
+ if (reduced) {
24
+ Object.assign(values, targets);
25
+ return false;
26
+ }
27
+ values.radius = approachAt60Hz(values.radius, targets.radius, .25, deltaMs);
28
+ values.aurora = approachAt60Hz(values.aurora, targets.aurora, .06, deltaMs);
29
+ values.reveal = approachAt60Hz(values.reveal, targets.reveal, .07, deltaMs);
30
+ values.settle = approachAt60Hz(values.settle, targets.settle, .07, deltaMs);
31
+ values.lift = targets.lift === 1 ? Math.min(1, values.lift + deltaMs * .00216) : approachAt60Hz(values.lift, 0, .28, deltaMs);
32
+ return state === "thinking" || Math.abs(values.radius - targets.radius) > .05 || Math.abs(values.aurora - targets.aurora) > .002 || Math.abs(values.reveal - targets.reveal) > .002 || Math.abs(values.settle - targets.settle) > .002 || Math.abs(values.lift - targets.lift) > .002;
33
+ }
34
+ return {
35
+ values,
36
+ advance
37
+ };
38
+ }
39
+ function createNotificationCanvasLoop(canvas, render) {
40
+ let destroyed = false;
41
+ let intersecting = true;
42
+ let pageVisible = !document.hidden;
43
+ let rafId = 0;
44
+ let staticFrameDrawn = false;
45
+ let previousFrameAt = performance.now();
46
+ const reducedMotionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
47
+ function tick() {
48
+ rafId = 0;
49
+ if (destroyed || !intersecting || !pageVisible) return;
50
+ const now = performance.now();
51
+ const deltaMs = Math.min(MAX_FRAME_DELTA_MS, now - previousFrameAt);
52
+ previousFrameAt = now;
53
+ const reduced = prefersReducedMotion(canvas);
54
+ const keepAnimating = render({
55
+ reduced,
56
+ now,
57
+ deltaMs
58
+ }) && !reduced;
59
+ staticFrameDrawn = !keepAnimating;
60
+ if (keepAnimating) rafId = requestAnimationFrame(tick);
61
+ }
62
+ function invalidate() {
63
+ staticFrameDrawn = false;
64
+ if (destroyed || !intersecting || !pageVisible || rafId !== 0) return;
65
+ previousFrameAt = performance.now();
66
+ rafId = requestAnimationFrame(tick);
67
+ }
68
+ function cancel() {
69
+ if (rafId !== 0) cancelAnimationFrame(rafId);
70
+ rafId = 0;
71
+ }
72
+ function handleVisibility() {
73
+ pageVisible = !document.hidden;
74
+ invalidate();
75
+ }
76
+ const resizeObserver = new ResizeObserver(invalidate);
77
+ resizeObserver.observe(canvas);
78
+ const intersectionObserver = new IntersectionObserver((entries) => {
79
+ for (const entry of entries) intersecting = entry.isIntersecting;
80
+ invalidate();
81
+ }, { rootMargin: "64px" });
82
+ intersectionObserver.observe(canvas);
83
+ const motionObserver = new MutationObserver(() => {
84
+ if (!staticFrameDrawn || !prefersReducedMotion(canvas)) invalidate();
85
+ });
86
+ motionObserver.observe(document.documentElement, {
87
+ attributes: true,
88
+ attributeFilter: ["data-motion"]
89
+ });
90
+ const stateObserver = new MutationObserver(invalidate);
91
+ if (canvas.parentElement) stateObserver.observe(canvas.parentElement, {
92
+ attributes: true,
93
+ attributeFilter: ["data-state"]
94
+ });
95
+ document.addEventListener("visibilitychange", handleVisibility);
96
+ reducedMotionQuery.addEventListener("change", invalidate);
97
+ return {
98
+ invalidate,
99
+ cancel,
100
+ destroy() {
101
+ destroyed = true;
102
+ cancel();
103
+ resizeObserver.disconnect();
104
+ intersectionObserver.disconnect();
105
+ motionObserver.disconnect();
106
+ stateObserver.disconnect();
107
+ document.removeEventListener("visibilitychange", handleVisibility);
108
+ reducedMotionQuery.removeEventListener("change", invalidate);
109
+ }
110
+ };
111
+ }
112
+ //#endregion
113
+ export { createNotificationCanvasLoop, createNotificationMotion };