snice 5.2.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (653) hide show
  1. package/README.md +5 -8
  2. package/adapters/react/SniceProvider.js +1 -1
  3. package/adapters/react/SniceRouter.js +1 -1
  4. package/adapters/react/audio-recorder.d.ts +0 -4
  5. package/adapters/react/audio-recorder.d.ts.map +1 -1
  6. package/adapters/react/audio-recorder.js +1 -1
  7. package/adapters/react/audio-recorder.js.map +1 -1
  8. package/adapters/react/audio-recorder.tsx +1 -5
  9. package/adapters/react/avatar.d.ts +0 -1
  10. package/adapters/react/avatar.d.ts.map +1 -1
  11. package/adapters/react/avatar.js +1 -1
  12. package/adapters/react/avatar.js.map +1 -1
  13. package/adapters/react/avatar.tsx +1 -2
  14. package/adapters/react/breadcrumbs.d.ts +0 -1
  15. package/adapters/react/breadcrumbs.d.ts.map +1 -1
  16. package/adapters/react/breadcrumbs.js +1 -1
  17. package/adapters/react/breadcrumbs.js.map +1 -1
  18. package/adapters/react/breadcrumbs.tsx +1 -2
  19. package/adapters/react/camera-annotate.d.ts +0 -5
  20. package/adapters/react/camera-annotate.d.ts.map +1 -1
  21. package/adapters/react/camera-annotate.js +1 -1
  22. package/adapters/react/camera-annotate.js.map +1 -1
  23. package/adapters/react/camera-annotate.tsx +1 -6
  24. package/adapters/react/card.d.ts +0 -2
  25. package/adapters/react/card.d.ts.map +1 -1
  26. package/adapters/react/card.js +1 -1
  27. package/adapters/react/card.js.map +1 -1
  28. package/adapters/react/card.tsx +1 -3
  29. package/adapters/react/carousel.d.ts +0 -1
  30. package/adapters/react/carousel.d.ts.map +1 -1
  31. package/adapters/react/carousel.js +1 -1
  32. package/adapters/react/carousel.js.map +1 -1
  33. package/adapters/react/carousel.tsx +1 -2
  34. package/adapters/react/cart.d.ts +0 -1
  35. package/adapters/react/cart.d.ts.map +1 -1
  36. package/adapters/react/cart.js +1 -1
  37. package/adapters/react/cart.js.map +1 -1
  38. package/adapters/react/cart.tsx +1 -2
  39. package/adapters/react/chart.d.ts +0 -5
  40. package/adapters/react/chart.d.ts.map +1 -1
  41. package/adapters/react/chart.js +1 -1
  42. package/adapters/react/chart.js.map +1 -1
  43. package/adapters/react/chart.tsx +1 -6
  44. package/adapters/react/chat.d.ts +4 -1
  45. package/adapters/react/chat.d.ts.map +1 -1
  46. package/adapters/react/chat.js +2 -2
  47. package/adapters/react/chat.js.map +1 -1
  48. package/adapters/react/chat.tsx +6 -3
  49. package/adapters/react/chip.d.ts +0 -1
  50. package/adapters/react/chip.d.ts.map +1 -1
  51. package/adapters/react/chip.js +1 -1
  52. package/adapters/react/chip.js.map +1 -1
  53. package/adapters/react/chip.tsx +1 -2
  54. package/adapters/react/command-palette.d.ts +0 -4
  55. package/adapters/react/command-palette.d.ts.map +1 -1
  56. package/adapters/react/command-palette.js +1 -1
  57. package/adapters/react/command-palette.js.map +1 -1
  58. package/adapters/react/command-palette.tsx +1 -5
  59. package/adapters/react/comments.d.ts +0 -1
  60. package/adapters/react/comments.d.ts.map +1 -1
  61. package/adapters/react/comments.js +1 -1
  62. package/adapters/react/comments.js.map +1 -1
  63. package/adapters/react/comments.tsx +1 -2
  64. package/adapters/react/countdown.d.ts +0 -4
  65. package/adapters/react/countdown.d.ts.map +1 -1
  66. package/adapters/react/countdown.js +1 -1
  67. package/adapters/react/countdown.js.map +1 -1
  68. package/adapters/react/countdown.tsx +1 -5
  69. package/adapters/react/date-time-picker.d.ts +0 -1
  70. package/adapters/react/date-time-picker.d.ts.map +1 -1
  71. package/adapters/react/date-time-picker.js +1 -1
  72. package/adapters/react/date-time-picker.js.map +1 -1
  73. package/adapters/react/date-time-picker.tsx +1 -2
  74. package/adapters/react/file-upload.d.ts +0 -2
  75. package/adapters/react/file-upload.d.ts.map +1 -1
  76. package/adapters/react/file-upload.js +1 -1
  77. package/adapters/react/file-upload.js.map +1 -1
  78. package/adapters/react/file-upload.tsx +1 -3
  79. package/adapters/react/heatmap.d.ts +0 -4
  80. package/adapters/react/heatmap.d.ts.map +1 -1
  81. package/adapters/react/heatmap.js +1 -1
  82. package/adapters/react/heatmap.js.map +1 -1
  83. package/adapters/react/heatmap.tsx +1 -5
  84. package/adapters/react/image.d.ts +0 -2
  85. package/adapters/react/image.d.ts.map +1 -1
  86. package/adapters/react/image.js +1 -1
  87. package/adapters/react/image.js.map +1 -1
  88. package/adapters/react/image.tsx +1 -3
  89. package/adapters/react/kanban.d.ts +0 -4
  90. package/adapters/react/kanban.d.ts.map +1 -1
  91. package/adapters/react/kanban.js +1 -1
  92. package/adapters/react/kanban.js.map +1 -1
  93. package/adapters/react/kanban.tsx +1 -5
  94. package/adapters/react/key-value.d.ts +0 -2
  95. package/adapters/react/key-value.d.ts.map +1 -1
  96. package/adapters/react/key-value.js +1 -1
  97. package/adapters/react/key-value.js.map +1 -1
  98. package/adapters/react/key-value.tsx +1 -3
  99. package/adapters/react/leaderboard.d.ts +0 -1
  100. package/adapters/react/leaderboard.d.ts.map +1 -1
  101. package/adapters/react/leaderboard.js +1 -1
  102. package/adapters/react/leaderboard.js.map +1 -1
  103. package/adapters/react/leaderboard.tsx +1 -2
  104. package/adapters/react/map.d.ts +0 -3
  105. package/adapters/react/map.d.ts.map +1 -1
  106. package/adapters/react/map.js +1 -1
  107. package/adapters/react/map.js.map +1 -1
  108. package/adapters/react/map.tsx +1 -4
  109. package/adapters/react/markdown.d.ts +1 -1
  110. package/adapters/react/markdown.d.ts.map +1 -1
  111. package/adapters/react/markdown.js +1 -1
  112. package/adapters/react/markdown.js.map +1 -1
  113. package/adapters/react/markdown.tsx +2 -2
  114. package/adapters/react/matchRoute.d.ts +1 -1
  115. package/adapters/react/matchRoute.js +38 -4
  116. package/adapters/react/matchRoute.js.map +1 -1
  117. package/adapters/react/message-strip.d.ts +1 -1
  118. package/adapters/react/message-strip.js +1 -1
  119. package/adapters/react/message-strip.tsx +2 -2
  120. package/adapters/react/music-player.d.ts +0 -1
  121. package/adapters/react/music-player.d.ts.map +1 -1
  122. package/adapters/react/music-player.js +1 -1
  123. package/adapters/react/music-player.js.map +1 -1
  124. package/adapters/react/music-player.tsx +1 -2
  125. package/adapters/react/org-chart.d.ts +0 -1
  126. package/adapters/react/org-chart.d.ts.map +1 -1
  127. package/adapters/react/org-chart.js +1 -1
  128. package/adapters/react/org-chart.js.map +1 -1
  129. package/adapters/react/org-chart.tsx +1 -2
  130. package/adapters/react/paint.d.ts +0 -1
  131. package/adapters/react/paint.d.ts.map +1 -1
  132. package/adapters/react/paint.js +1 -1
  133. package/adapters/react/paint.js.map +1 -1
  134. package/adapters/react/paint.tsx +1 -2
  135. package/adapters/react/podcast-player.d.ts +0 -2
  136. package/adapters/react/podcast-player.d.ts.map +1 -1
  137. package/adapters/react/podcast-player.js +1 -1
  138. package/adapters/react/podcast-player.js.map +1 -1
  139. package/adapters/react/podcast-player.tsx +1 -3
  140. package/adapters/react/product-card.d.ts +0 -3
  141. package/adapters/react/product-card.d.ts.map +1 -1
  142. package/adapters/react/product-card.js +1 -1
  143. package/adapters/react/product-card.js.map +1 -1
  144. package/adapters/react/product-card.tsx +1 -4
  145. package/adapters/react/qr-reader.d.ts +0 -4
  146. package/adapters/react/qr-reader.d.ts.map +1 -1
  147. package/adapters/react/qr-reader.js +1 -1
  148. package/adapters/react/qr-reader.js.map +1 -1
  149. package/adapters/react/qr-reader.tsx +1 -5
  150. package/adapters/react/recipe.d.ts +0 -5
  151. package/adapters/react/recipe.d.ts.map +1 -1
  152. package/adapters/react/recipe.js +1 -1
  153. package/adapters/react/recipe.js.map +1 -1
  154. package/adapters/react/recipe.tsx +1 -6
  155. package/adapters/react/route-specificity.d.ts +1 -0
  156. package/adapters/react/spotlight.d.ts +0 -2
  157. package/adapters/react/spotlight.d.ts.map +1 -1
  158. package/adapters/react/spotlight.js +1 -1
  159. package/adapters/react/spotlight.js.map +1 -1
  160. package/adapters/react/spotlight.tsx +1 -3
  161. package/adapters/react/tag-input.d.ts +0 -4
  162. package/adapters/react/tag-input.d.ts.map +1 -1
  163. package/adapters/react/tag-input.js +1 -1
  164. package/adapters/react/tag-input.js.map +1 -1
  165. package/adapters/react/tag-input.tsx +1 -5
  166. package/adapters/react/terminal.d.ts +0 -1
  167. package/adapters/react/terminal.d.ts.map +1 -1
  168. package/adapters/react/terminal.js +1 -1
  169. package/adapters/react/terminal.js.map +1 -1
  170. package/adapters/react/terminal.tsx +1 -2
  171. package/adapters/react/time-picker.d.ts +0 -1
  172. package/adapters/react/time-picker.d.ts.map +1 -1
  173. package/adapters/react/time-picker.js +1 -1
  174. package/adapters/react/time-picker.js.map +1 -1
  175. package/adapters/react/time-picker.tsx +1 -2
  176. package/adapters/react/timer.d.ts +0 -1
  177. package/adapters/react/timer.d.ts.map +1 -1
  178. package/adapters/react/timer.js +1 -1
  179. package/adapters/react/timer.js.map +1 -1
  180. package/adapters/react/timer.tsx +1 -2
  181. package/adapters/react/useRequestHandler.js +1 -1
  182. package/adapters/react/video-player.d.ts +0 -6
  183. package/adapters/react/video-player.d.ts.map +1 -1
  184. package/adapters/react/video-player.js +1 -1
  185. package/adapters/react/video-player.js.map +1 -1
  186. package/adapters/react/video-player.tsx +1 -7
  187. package/adapters/react/virtual-scroller.d.ts +0 -1
  188. package/adapters/react/virtual-scroller.d.ts.map +1 -1
  189. package/adapters/react/virtual-scroller.js +1 -1
  190. package/adapters/react/virtual-scroller.js.map +1 -1
  191. package/adapters/react/virtual-scroller.tsx +1 -2
  192. package/bin/templates/default/tests/services/jwt.test.ts +8 -1
  193. package/bin/templates/react/tests/services/jwt.test.ts +10 -3
  194. package/dist/cdn/accordion/snice-accordion.js +1 -1
  195. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  196. package/dist/cdn/action-bar/README.md +2 -2
  197. package/dist/cdn/action-bar/snice-action-bar.js +2 -2
  198. package/dist/cdn/action-bar/snice-action-bar.js.map +1 -1
  199. package/dist/cdn/action-bar/snice-action-bar.min.js +2 -2
  200. package/dist/cdn/action-bar/snice-action-bar.min.js.map +1 -1
  201. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  202. package/dist/cdn/activity-feed/snice-activity-feed.min.js +1 -1
  203. package/dist/cdn/alert/snice-alert.js +1 -1
  204. package/dist/cdn/alert/snice-alert.js.map +1 -1
  205. package/dist/cdn/alert/snice-alert.min.js +1 -1
  206. package/dist/cdn/alert/snice-alert.min.js.map +1 -1
  207. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  208. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  209. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  210. package/dist/cdn/approval-flow/snice-approval-flow.js.map +1 -1
  211. package/dist/cdn/approval-flow/snice-approval-flow.min.js +1 -1
  212. package/dist/cdn/approval-flow/snice-approval-flow.min.js.map +1 -1
  213. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  214. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  215. package/dist/cdn/availability/snice-availability.js +1 -1
  216. package/dist/cdn/availability/snice-availability.min.js +1 -1
  217. package/dist/cdn/avatar/snice-avatar.js +1 -1
  218. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  219. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  220. package/dist/cdn/avatar-group/snice-avatar-group.min.js +1 -1
  221. package/dist/cdn/badge/snice-badge.js +1 -1
  222. package/dist/cdn/badge/snice-badge.js.map +1 -1
  223. package/dist/cdn/badge/snice-badge.min.js +1 -1
  224. package/dist/cdn/badge/snice-badge.min.js.map +1 -1
  225. package/dist/cdn/banner/README.md +1 -1
  226. package/dist/cdn/banner/snice-banner.js +2 -2
  227. package/dist/cdn/banner/snice-banner.js.map +1 -1
  228. package/dist/cdn/banner/snice-banner.min.js +2 -2
  229. package/dist/cdn/banner/snice-banner.min.js.map +1 -1
  230. package/dist/cdn/binpack/snice-binpack.js +1 -1
  231. package/dist/cdn/binpack/snice-binpack.min.js +1 -1
  232. package/dist/cdn/book/snice-book.js +1 -1
  233. package/dist/cdn/book/snice-book.min.js +1 -1
  234. package/dist/cdn/booking/snice-booking.js +1 -1
  235. package/dist/cdn/booking/snice-booking.min.js +1 -1
  236. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  237. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js.map +1 -1
  238. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  239. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js.map +1 -1
  240. package/dist/cdn/button/snice-button.js +1 -1
  241. package/dist/cdn/button/snice-button.js.map +1 -1
  242. package/dist/cdn/button/snice-button.min.js +1 -1
  243. package/dist/cdn/button/snice-button.min.js.map +1 -1
  244. package/dist/cdn/calendar/snice-calendar.js +1 -1
  245. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  246. package/dist/cdn/camera/snice-camera.js +1 -1
  247. package/dist/cdn/camera/snice-camera.min.js +1 -1
  248. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  249. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  250. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  251. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  252. package/dist/cdn/card/snice-card.js +1 -1
  253. package/dist/cdn/card/snice-card.min.js +1 -1
  254. package/dist/cdn/carousel/snice-carousel.js +1 -1
  255. package/dist/cdn/carousel/snice-carousel.min.js +1 -1
  256. package/dist/cdn/cart/snice-cart.js +1 -1
  257. package/dist/cdn/cart/snice-cart.min.js +1 -1
  258. package/dist/cdn/chart/snice-chart.js +1 -1
  259. package/dist/cdn/chart/snice-chart.js.map +1 -1
  260. package/dist/cdn/chart/snice-chart.min.js +1 -1
  261. package/dist/cdn/chart/snice-chart.min.js.map +1 -1
  262. package/dist/cdn/chat/README.md +2 -2
  263. package/dist/cdn/chat/snice-chat.js +785 -89
  264. package/dist/cdn/chat/snice-chat.js.map +1 -1
  265. package/dist/cdn/chat/snice-chat.min.js +71 -75
  266. package/dist/cdn/chat/snice-chat.min.js.map +1 -1
  267. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  268. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  269. package/dist/cdn/chip/snice-chip.js +1 -1
  270. package/dist/cdn/chip/snice-chip.js.map +1 -1
  271. package/dist/cdn/chip/snice-chip.min.js +1 -1
  272. package/dist/cdn/chip/snice-chip.min.js.map +1 -1
  273. package/dist/cdn/code-block/snice-code-block.js +1 -1
  274. package/dist/cdn/code-block/snice-code-block.min.js +1 -1
  275. package/dist/cdn/color-display/snice-color-display.js +1 -1
  276. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  277. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  278. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  279. package/dist/cdn/command-palette/README.md +1 -1
  280. package/dist/cdn/command-palette/snice-command-palette.js +2 -2
  281. package/dist/cdn/command-palette/snice-command-palette.js.map +1 -1
  282. package/dist/cdn/command-palette/snice-command-palette.min.js +2 -2
  283. package/dist/cdn/command-palette/snice-command-palette.min.js.map +1 -1
  284. package/dist/cdn/comments/snice-comments.js +1 -1
  285. package/dist/cdn/comments/snice-comments.min.js +1 -1
  286. package/dist/cdn/countdown/snice-countdown.js +1 -1
  287. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  288. package/dist/cdn/cropper/snice-cropper.js +1 -1
  289. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  290. package/dist/cdn/data-card/snice-data-card.js +1 -1
  291. package/dist/cdn/data-card/snice-data-card.js.map +1 -1
  292. package/dist/cdn/data-card/snice-data-card.min.js +1 -1
  293. package/dist/cdn/data-card/snice-data-card.min.js.map +1 -1
  294. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  295. package/dist/cdn/date-picker/snice-date-picker.min.js +1 -1
  296. package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
  297. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +1 -1
  298. package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
  299. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +1 -1
  300. package/dist/cdn/diff/snice-diff.js +1 -1
  301. package/dist/cdn/diff/snice-diff.min.js +1 -1
  302. package/dist/cdn/divider/snice-divider.js +1 -1
  303. package/dist/cdn/divider/snice-divider.min.js +1 -1
  304. package/dist/cdn/doc/snice-doc.js +1 -1
  305. package/dist/cdn/doc/snice-doc.min.js +1 -1
  306. package/dist/cdn/draw/snice-draw.js +1 -1
  307. package/dist/cdn/draw/snice-draw.min.js +1 -1
  308. package/dist/cdn/drawer/snice-drawer.js +1 -1
  309. package/dist/cdn/drawer/snice-drawer.js.map +1 -1
  310. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  311. package/dist/cdn/drawer/snice-drawer.min.js.map +1 -1
  312. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  313. package/dist/cdn/empty-state/snice-empty-state.js.map +1 -1
  314. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  315. package/dist/cdn/empty-state/snice-empty-state.min.js.map +1 -1
  316. package/dist/cdn/estimate/snice-estimate.js +1 -1
  317. package/dist/cdn/estimate/snice-estimate.min.js +1 -1
  318. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  319. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  320. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  321. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  322. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  323. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  324. package/dist/cdn/flow/snice-flow.js +1 -1
  325. package/dist/cdn/flow/snice-flow.min.js +1 -1
  326. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  327. package/dist/cdn/form-layout/snice-form-layout.min.js +1 -1
  328. package/dist/cdn/funnel/snice-funnel.js +1 -1
  329. package/dist/cdn/funnel/snice-funnel.js.map +1 -1
  330. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  331. package/dist/cdn/funnel/snice-funnel.min.js.map +1 -1
  332. package/dist/cdn/gantt/snice-gantt.js +1 -1
  333. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  334. package/dist/cdn/gauge/snice-gauge.js +1 -1
  335. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  336. package/dist/cdn/grid/snice-grid.js +1 -1
  337. package/dist/cdn/grid/snice-grid.min.js +1 -1
  338. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  339. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  340. package/dist/cdn/image/snice-image.js +1 -1
  341. package/dist/cdn/image/snice-image.js.map +1 -1
  342. package/dist/cdn/image/snice-image.min.js +1 -1
  343. package/dist/cdn/image/snice-image.min.js.map +1 -1
  344. package/dist/cdn/input/snice-input.js +1 -1
  345. package/dist/cdn/input/snice-input.js.map +1 -1
  346. package/dist/cdn/input/snice-input.min.js +1 -1
  347. package/dist/cdn/input/snice-input.min.js.map +1 -1
  348. package/dist/cdn/invoice/README.md +1 -1
  349. package/dist/cdn/invoice/snice-invoice.js +2 -2
  350. package/dist/cdn/invoice/snice-invoice.js.map +1 -1
  351. package/dist/cdn/invoice/snice-invoice.min.js +2 -2
  352. package/dist/cdn/invoice/snice-invoice.min.js.map +1 -1
  353. package/dist/cdn/kanban/snice-kanban.js +1 -1
  354. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  355. package/dist/cdn/key-value/snice-key-value.js +1 -1
  356. package/dist/cdn/key-value/snice-key-value.min.js +1 -1
  357. package/dist/cdn/kpi/snice-kpi.js +1 -1
  358. package/dist/cdn/kpi/snice-kpi.js.map +1 -1
  359. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  360. package/dist/cdn/kpi/snice-kpi.min.js.map +1 -1
  361. package/dist/cdn/layout/snice-layout.js +1 -1
  362. package/dist/cdn/layout/snice-layout.min.js +1 -1
  363. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  364. package/dist/cdn/leaderboard/snice-leaderboard.min.js +1 -1
  365. package/dist/cdn/link/snice-link.js +1 -1
  366. package/dist/cdn/link/snice-link.min.js +1 -1
  367. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  368. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  369. package/dist/cdn/list/snice-list.js +1 -1
  370. package/dist/cdn/list/snice-list.js.map +1 -1
  371. package/dist/cdn/list/snice-list.min.js +1 -1
  372. package/dist/cdn/list/snice-list.min.js.map +1 -1
  373. package/dist/cdn/location/snice-location.js +1 -1
  374. package/dist/cdn/location/snice-location.js.map +1 -1
  375. package/dist/cdn/location/snice-location.min.js +1 -1
  376. package/dist/cdn/location/snice-location.min.js.map +1 -1
  377. package/dist/cdn/login/snice-login.js +3 -1
  378. package/dist/cdn/login/snice-login.js.map +1 -1
  379. package/dist/cdn/login/snice-login.min.js +1 -1
  380. package/dist/cdn/login/snice-login.min.js.map +1 -1
  381. package/dist/cdn/map/snice-map.js +1 -1
  382. package/dist/cdn/map/snice-map.min.js +1 -1
  383. package/dist/cdn/markdown/README.md +2 -2
  384. package/dist/cdn/markdown/snice-markdown.js +16 -3
  385. package/dist/cdn/markdown/snice-markdown.js.map +1 -1
  386. package/dist/cdn/markdown/snice-markdown.min.js +3 -3
  387. package/dist/cdn/markdown/snice-markdown.min.js.map +1 -1
  388. package/dist/cdn/masonry/snice-masonry.js +1 -1
  389. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  390. package/dist/cdn/menu/snice-menu.js +2 -2
  391. package/dist/cdn/menu/snice-menu.js.map +1 -1
  392. package/dist/cdn/menu/snice-menu.min.js +2 -2
  393. package/dist/cdn/menu/snice-menu.min.js.map +1 -1
  394. package/dist/cdn/message-strip/snice-message-strip.js +9 -9
  395. package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
  396. package/dist/cdn/message-strip/snice-message-strip.min.js +3 -3
  397. package/dist/cdn/message-strip/snice-message-strip.min.js.map +1 -1
  398. package/dist/cdn/metric-table/snice-metric-table.js +1 -1
  399. package/dist/cdn/metric-table/snice-metric-table.min.js +1 -1
  400. package/dist/cdn/modal/snice-modal.js +1 -1
  401. package/dist/cdn/modal/snice-modal.js.map +1 -1
  402. package/dist/cdn/modal/snice-modal.min.js +1 -1
  403. package/dist/cdn/modal/snice-modal.min.js.map +1 -1
  404. package/dist/cdn/music-player/snice-music-player.js +1 -1
  405. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  406. package/dist/cdn/nav/snice-nav.js +1 -1
  407. package/dist/cdn/nav/snice-nav.min.js +1 -1
  408. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  409. package/dist/cdn/network-graph/snice-network-graph.js.map +1 -1
  410. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  411. package/dist/cdn/network-graph/snice-network-graph.min.js.map +1 -1
  412. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  413. package/dist/cdn/notification-center/snice-notification-center.js.map +1 -1
  414. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  415. package/dist/cdn/notification-center/snice-notification-center.min.js.map +1 -1
  416. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  417. package/dist/cdn/order-tracker/snice-order-tracker.min.js +1 -1
  418. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  419. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  420. package/dist/cdn/pagination/snice-pagination.js +1 -1
  421. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  422. package/dist/cdn/paint/snice-paint.js +1 -1
  423. package/dist/cdn/paint/snice-paint.min.js +1 -1
  424. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  425. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
  426. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  427. package/dist/cdn/permission-matrix/snice-permission-matrix.min.js +1 -1
  428. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  429. package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
  430. package/dist/cdn/popover/snice-popover.js +1 -1
  431. package/dist/cdn/popover/snice-popover.min.js +1 -1
  432. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  433. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  434. package/dist/cdn/product-card/snice-product-card.js +3 -3
  435. package/dist/cdn/product-card/snice-product-card.js.map +1 -1
  436. package/dist/cdn/product-card/snice-product-card.min.js +3 -3
  437. package/dist/cdn/product-card/snice-product-card.min.js.map +1 -1
  438. package/dist/cdn/progress/README.md +1 -1
  439. package/dist/cdn/progress/snice-progress.js +2 -2
  440. package/dist/cdn/progress/snice-progress.js.map +1 -1
  441. package/dist/cdn/progress/snice-progress.min.js +2 -2
  442. package/dist/cdn/progress/snice-progress.min.js.map +1 -1
  443. package/dist/cdn/progress-ring/snice-progress-ring.js +2 -2
  444. package/dist/cdn/progress-ring/snice-progress-ring.js.map +1 -1
  445. package/dist/cdn/progress-ring/snice-progress-ring.min.js +2 -2
  446. package/dist/cdn/progress-ring/snice-progress-ring.min.js.map +1 -1
  447. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  448. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  449. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  450. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  451. package/dist/cdn/radio/snice-radio.js +1 -1
  452. package/dist/cdn/radio/snice-radio.min.js +1 -1
  453. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  454. package/dist/cdn/range-slider/snice-range-slider.min.js +1 -1
  455. package/dist/cdn/rating/snice-rating.js +1 -1
  456. package/dist/cdn/rating/snice-rating.min.js +1 -1
  457. package/dist/cdn/receipt/snice-receipt.js +1 -1
  458. package/dist/cdn/receipt/snice-receipt.min.js +1 -1
  459. package/dist/cdn/recipe/snice-recipe.js +1 -1
  460. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  461. package/dist/cdn/runtime/README.md +2 -2
  462. package/dist/cdn/runtime/snice-runtime.esm.js +644 -172
  463. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  464. package/dist/cdn/runtime/snice-runtime.esm.min.js +8 -8
  465. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  466. package/dist/cdn/runtime/snice-runtime.js +644 -172
  467. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  468. package/dist/cdn/runtime/snice-runtime.min.js +8 -8
  469. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  470. package/dist/cdn/sankey/snice-sankey.js +1 -1
  471. package/dist/cdn/sankey/snice-sankey.js.map +1 -1
  472. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  473. package/dist/cdn/sankey/snice-sankey.min.js.map +1 -1
  474. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  475. package/dist/cdn/segmented-control/snice-segmented-control.min.js +1 -1
  476. package/dist/cdn/select/snice-select.js +1 -1
  477. package/dist/cdn/select/snice-select.min.js +1 -1
  478. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  479. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  480. package/dist/cdn/slider/snice-slider.js +1 -1
  481. package/dist/cdn/slider/snice-slider.min.js +1 -1
  482. package/dist/cdn/sortable/snice-sortable.js +1 -1
  483. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  484. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  485. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  486. package/dist/cdn/spinner/snice-spinner.js +1 -1
  487. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  488. package/dist/cdn/split-button/snice-split-button.js +1 -1
  489. package/dist/cdn/split-button/snice-split-button.js.map +1 -1
  490. package/dist/cdn/split-button/snice-split-button.min.js +1 -1
  491. package/dist/cdn/split-button/snice-split-button.min.js.map +1 -1
  492. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  493. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  494. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  495. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  496. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  497. package/dist/cdn/stat-group/snice-stat-group.min.js +1 -1
  498. package/dist/cdn/step-input/snice-step-input.js +1 -1
  499. package/dist/cdn/step-input/snice-step-input.min.js +1 -1
  500. package/dist/cdn/stepper/snice-stepper.js +1 -1
  501. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  502. package/dist/cdn/switch/snice-switch.js +1 -1
  503. package/dist/cdn/switch/snice-switch.min.js +1 -1
  504. package/dist/cdn/table/README.md +1 -1
  505. package/dist/cdn/table/snice-table.js +14 -4
  506. package/dist/cdn/table/snice-table.js.map +1 -1
  507. package/dist/cdn/table/snice-table.min.js +14 -4
  508. package/dist/cdn/table/snice-table.min.js.map +1 -1
  509. package/dist/cdn/tabs/snice-tabs.js +1 -1
  510. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  511. package/dist/cdn/tag/snice-tag.js +1 -1
  512. package/dist/cdn/tag/snice-tag.min.js +1 -1
  513. package/dist/cdn/tag-input/snice-tag-input.js +2 -2
  514. package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
  515. package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
  516. package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
  517. package/dist/cdn/terminal/snice-terminal.js +1 -1
  518. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  519. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  520. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  521. package/dist/cdn/textarea/snice-textarea.js +1 -1
  522. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  523. package/dist/cdn/time-picker/README.md +1 -1
  524. package/dist/cdn/time-picker/snice-time-picker.js +18 -13
  525. package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
  526. package/dist/cdn/time-picker/snice-time-picker.min.js +3 -3
  527. package/dist/cdn/time-picker/snice-time-picker.min.js.map +1 -1
  528. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  529. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  530. package/dist/cdn/timeline/snice-timeline.js +1 -1
  531. package/dist/cdn/timeline/snice-timeline.js.map +1 -1
  532. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  533. package/dist/cdn/timeline/snice-timeline.min.js.map +1 -1
  534. package/dist/cdn/timer/snice-timer.js +1 -1
  535. package/dist/cdn/timer/snice-timer.min.js +1 -1
  536. package/dist/cdn/toast/snice-toast.js +1 -1
  537. package/dist/cdn/toast/snice-toast.js.map +1 -1
  538. package/dist/cdn/toast/snice-toast.min.js +1 -1
  539. package/dist/cdn/toast/snice-toast.min.js.map +1 -1
  540. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  541. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  542. package/dist/cdn/tree/snice-tree.js +1 -1
  543. package/dist/cdn/tree/snice-tree.min.js +1 -1
  544. package/dist/cdn/treemap/snice-treemap.js +1 -1
  545. package/dist/cdn/treemap/snice-treemap.js.map +1 -1
  546. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  547. package/dist/cdn/treemap/snice-treemap.min.js.map +1 -1
  548. package/dist/cdn/user-card/snice-user-card.js +1 -1
  549. package/dist/cdn/user-card/snice-user-card.min.js +1 -1
  550. package/dist/cdn/video-player/snice-video-player.js +1 -1
  551. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  552. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  553. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  554. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  555. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  556. package/dist/cdn/weather/snice-weather.js +1 -1
  557. package/dist/cdn/weather/snice-weather.min.js +1 -1
  558. package/dist/cdn/work-order/snice-work-order.js +1 -1
  559. package/dist/cdn/work-order/snice-work-order.min.js +1 -1
  560. package/dist/components/action-bar/snice-action-bar.js +1 -1
  561. package/dist/components/action-bar/snice-action-bar.js.map +1 -1
  562. package/dist/components/banner/snice-banner.js +1 -1
  563. package/dist/components/banner/snice-banner.js.map +1 -1
  564. package/dist/components/chat/snice-chat-message.d.ts +32 -0
  565. package/dist/components/chat/snice-chat-message.js +127 -0
  566. package/dist/components/chat/snice-chat-message.js.map +1 -0
  567. package/dist/components/chat/snice-chat-message.types.d.ts +30 -0
  568. package/dist/components/chat/snice-chat.d.ts +31 -4
  569. package/dist/components/chat/snice-chat.js +363 -90
  570. package/dist/components/chat/snice-chat.js.map +1 -1
  571. package/dist/components/chat/snice-chat.types.d.ts +34 -3
  572. package/dist/components/command-palette/snice-command-palette.js +1 -1
  573. package/dist/components/command-palette/snice-command-palette.js.map +1 -1
  574. package/dist/components/icons/index.d.ts +4 -0
  575. package/dist/components/icons/index.js +5 -1
  576. package/dist/components/icons/index.js.map +1 -1
  577. package/dist/components/invoice/snice-invoice.js +1 -1
  578. package/dist/components/invoice/snice-invoice.js.map +1 -1
  579. package/dist/components/login/snice-login.d.ts +2 -2
  580. package/dist/components/login/snice-login.js +2 -0
  581. package/dist/components/login/snice-login.js.map +1 -1
  582. package/dist/components/login/snice-login.types.d.ts +4 -0
  583. package/dist/components/markdown/snice-markdown.d.ts +1 -0
  584. package/dist/components/markdown/snice-markdown.js +15 -2
  585. package/dist/components/markdown/snice-markdown.js.map +1 -1
  586. package/dist/components/menu/snice-menu.js +1 -1
  587. package/dist/components/menu/snice-menu.js.map +1 -1
  588. package/dist/components/message-strip/snice-message-strip.d.ts +1 -1
  589. package/dist/components/message-strip/snice-message-strip.js +8 -8
  590. package/dist/components/message-strip/snice-message-strip.types.d.ts +1 -1
  591. package/dist/components/product-card/snice-product-card.js +2 -2
  592. package/dist/components/product-card/snice-product-card.js.map +1 -1
  593. package/dist/components/progress/snice-progress.js +1 -1
  594. package/dist/components/progress/snice-progress.js.map +1 -1
  595. package/dist/components/progress-ring/snice-progress-ring.js +1 -1
  596. package/dist/components/progress-ring/snice-progress-ring.js.map +1 -1
  597. package/dist/components/table/snice-table.js +13 -3
  598. package/dist/components/table/snice-table.js.map +1 -1
  599. package/dist/components/tag-input/snice-tag-input.js +1 -1
  600. package/dist/components/tag-input/snice-tag-input.js.map +1 -1
  601. package/dist/components/time-picker/snice-time-picker.js +17 -12
  602. package/dist/components/time-picker/snice-time-picker.js.map +1 -1
  603. package/dist/components/utils.d.ts +6 -0
  604. package/dist/components/utils.js +1 -1
  605. package/dist/components/utils.js.map +1 -1
  606. package/dist/element.d.ts +2 -1
  607. package/dist/events.d.ts +6 -0
  608. package/dist/index.cjs +641 -169
  609. package/dist/index.cjs.map +1 -1
  610. package/dist/index.esm.js +641 -169
  611. package/dist/index.esm.js.map +1 -1
  612. package/dist/index.iife.js +641 -169
  613. package/dist/index.iife.js.map +1 -1
  614. package/dist/parts.d.ts +1 -8
  615. package/dist/react/SniceProvider.js +1 -1
  616. package/dist/react/SniceRouter.js +1 -1
  617. package/dist/react/index.js +1 -1
  618. package/dist/react/matchRoute.d.ts +1 -1
  619. package/dist/react/matchRoute.js +38 -4
  620. package/dist/react/matchRoute.js.map +1 -1
  621. package/dist/react/route-specificity.d.ts +1 -0
  622. package/dist/react/useRequestHandler.js +1 -1
  623. package/dist/render.d.ts +7 -0
  624. package/dist/route-specificity.d.ts +1 -0
  625. package/dist/symbols.cjs +14 -1
  626. package/dist/symbols.cjs.map +1 -1
  627. package/dist/symbols.d.ts +3 -0
  628. package/dist/symbols.esm.js +12 -2
  629. package/dist/symbols.esm.js.map +1 -1
  630. package/dist/transitions.cjs +1 -1
  631. package/dist/transitions.esm.js +1 -1
  632. package/dist/types/context.d.ts +5 -2
  633. package/dist/types/dispatch-options.d.ts +7 -0
  634. package/dist/types/index.d.ts +1 -0
  635. package/dist/types/on-options.d.ts +14 -0
  636. package/dist/types/watch-options.d.ts +9 -0
  637. package/dist/utils.d.ts +26 -0
  638. package/docs/ai/DEVELOPMENT.md +1 -1
  639. package/docs/ai/README.md +11 -0
  640. package/docs/ai/api.md +24 -5
  641. package/docs/ai/cdn.md +31 -0
  642. package/docs/ai/components/chat.md +57 -1
  643. package/docs/ai/components/message-strip.md +3 -3
  644. package/docs/ai/decorators.md +44 -5
  645. package/docs/cdn.md +56 -0
  646. package/docs/components/chat.md +108 -2
  647. package/docs/components/message-strip.md +8 -8
  648. package/docs/elements.md +21 -0
  649. package/docs/events.md +88 -0
  650. package/docs/superpowers/specs/2026-05-26-chat-styling-design.md +155 -0
  651. package/docs/superpowers/specs/2026-05-27-chat-theming-REMAINING.md +83 -0
  652. package/docs/superpowers/specs/2026-06-09-chat-custom-content-design.md +233 -0
  653. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v5.2.2
2
+ * snice v6.0.0
3
3
  * A decorator-driven web component library with differential rendering, routing, controllers, and 130+ ready-made UI components. Use as much or as little as you want. Zero dependencies, works anywhere.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -64,6 +64,34 @@ var SniceChat = (function (exports, snice) {
64
64
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
65
65
  };
66
66
 
67
+ /**
68
+ * Built-in snice icon set — a small curated subset of Heroicons, used by
69
+ * components as their default glyph when no consumer slot or `icon` prop is
70
+ * provided. Consumers can always override by slotting their own icon library
71
+ * (Font Awesome, Material Symbols, Lucide, custom SVG, etc.).
72
+ *
73
+ * Copied from Heroicons v2 — MIT License, © Tailwind Labs.
74
+ * https://github.com/tailwindlabs/heroicons
75
+ *
76
+ * Why embed instead of depending on a package:
77
+ * - Snice ships zero runtime dependencies beyond the framework itself.
78
+ * - We only need ~15 glyphs; the full Heroicons package is 600+ icons.
79
+ * - Embedding sidesteps shadow DOM / module-resolution concerns and keeps
80
+ * default icons available even in sandboxed environments.
81
+ *
82
+ * All SVGs:
83
+ * - viewBox="0 0 24 24"
84
+ * - solid variants use `fill="currentColor"`
85
+ * - outline variants use `stroke="currentColor"` + no fill
86
+ *
87
+ * Components pass `currentColor` through by setting `color:` on the wrapper.
88
+ */
89
+ // ─── SOLID (filled) — used for status / selected / active contexts ────────
90
+ const PAPER_AIRPLANE_SOLID = /*html*/ `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 0 3.478 2.404Z"/></svg>`;
91
+ const TRASH = /*html*/ `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/></svg>`;
92
+ const PENCIL = /*html*/ `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"/></svg>`;
93
+ const PAPER_CLIP = /*html*/ `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13"/></svg>`;
94
+
67
95
  /**
68
96
  * Detects icon type and returns appropriate template
69
97
  *
@@ -120,6 +148,15 @@ var SniceChat = (function (exports, snice) {
120
148
  }
121
149
  return snice.html `<span class="${className}" part="icon">${icon}</span>`;
122
150
  }
151
+ /**
152
+ * Fallback accent hues (muted/business tones). Used when CSS vars haven't
153
+ * been applied (test environments, SSR) or when the 8 accent tokens have
154
+ * been stripped. Keep in lockstep with `theme.css` --snice-color-accent-1..8.
155
+ */
156
+ const FALLBACK_ACCENTS = [
157
+ 'hsl(214 55% 48%)', 'hsl(27 62% 50%)', 'hsl(160 40% 40%)', 'hsl(275 32% 52%)',
158
+ 'hsl(42 62% 48%)', 'hsl(340 42% 55%)', 'hsl(110 32% 42%)', 'hsl(195 45% 46%)',
159
+ ];
123
160
 
124
161
  var cssContent$1 = ":host{display:block;font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:var(--snice-spacing-2xl,3rem) var(--snice-spacing-xl,2rem);color:var(--snice-color-text-secondary,rgb(82 82 82));animation:snice-empty-in 360ms var(--snice-ease-out,ease) backwards}@keyframes snice-empty-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.empty-state--small{padding:var(--snice-spacing-xl,2rem) var(--snice-spacing-lg,1.5rem)}.empty-state--medium{padding:var(--snice-spacing-2xl,3rem) var(--snice-spacing-xl,2rem)}.empty-state--large{padding:var(--snice-spacing-3xl,4rem) var(--snice-spacing-2xl,2.5rem)}.empty-state__icon-wrapper{display:flex;align-items:center;justify-content:center;margin-bottom:var(--snice-spacing-lg,1.5rem);position:relative;width:calc(var(--snice-font-size-4xl,4rem) * 1.8);height:calc(var(--snice-font-size-4xl,4rem) * 1.8)}.empty-state__icon-wrapper::before{content:'';position:absolute;inset:0;border-radius:50%;border:1px dashed color-mix(in srgb,var(--snice-color-border,#ddd) 70%,transparent);animation:18s linear infinite snice-empty-halo}@keyframes snice-empty-halo{to{transform:rotate(360deg)}}.empty-state__icon{font-size:var(--snice-font-size-4xl, 4rem);opacity:.5;line-height:1}.empty-state__icon-wrapper ::slotted(*){display:flex;align-items:center;justify-content:center;font-size:var(--snice-font-size-4xl, 4rem);opacity:.5;line-height:1}.empty-state__icon-wrapper ::slotted(svg){width:var(--snice-font-size-4xl,4rem);height:var(--snice-font-size-4xl,4rem)}.empty-state__icon-wrapper ::slotted(img){width:var(--snice-font-size-4xl,4rem);height:var(--snice-font-size-4xl,4rem);object-fit:contain}.empty-state--small .empty-state__icon-wrapper{margin-bottom:var(--snice-spacing-md,1rem);width:calc(var(--snice-font-size-3xl,3rem) * 1.8);height:calc(var(--snice-font-size-3xl,3rem) * 1.8)}.empty-state--small .empty-state__icon{font-size:var(--snice-font-size-3xl, 3rem)}.empty-state--small .empty-state__icon-wrapper ::slotted(*){font-size:var(--snice-font-size-3xl, 3rem)}.empty-state--small .empty-state__icon-wrapper ::slotted(img),.empty-state--small .empty-state__icon-wrapper ::slotted(svg){width:var(--snice-font-size-3xl,3rem);height:var(--snice-font-size-3xl,3rem)}.empty-state--large .empty-state__icon-wrapper{margin-bottom:var(--snice-spacing-xl,2rem);width:calc(var(--snice-font-size-5xl,5rem) * 1.8);height:calc(var(--snice-font-size-5xl,5rem) * 1.8)}.empty-state--large .empty-state__icon{font-size:var(--snice-font-size-5xl, 5rem)}.empty-state--large .empty-state__icon-wrapper ::slotted(*){font-size:var(--snice-font-size-5xl, 5rem)}.empty-state--large .empty-state__icon-wrapper ::slotted(img),.empty-state--large .empty-state__icon-wrapper ::slotted(svg){width:var(--snice-font-size-5xl,5rem);height:var(--snice-font-size-5xl,5rem)}.empty-state__title{font-family:var(--snice-font-family-display);font-size:var(--snice-heading-lg, 1.25rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text,rgb(23 23 23));margin:0 0 var(--snice-spacing-xs,.5rem) 0}.empty-state--small .empty-state__title{font-family:var(--snice-font-family-display);font-size:var(--snice-heading-md, 1.125rem);margin-bottom:var(--snice-spacing-2xs,.375rem)}.empty-state--large .empty-state__title{font-family:var(--snice-font-family-display);font-size:var(--snice-heading-xl, 1.5rem);margin-bottom:var(--snice-spacing-sm,.75rem)}.empty-state__description{font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text-secondary,rgb(82 82 82));margin:0 0 var(--snice-spacing-lg,1.5rem) 0;max-width:32rem;line-height:var(--snice-line-height-normal, 1.5)}.empty-state--small .empty-state__description{font-size:var(--snice-font-size-xs, .8125rem);margin-bottom:var(--snice-spacing-md,1rem)}.empty-state--large .empty-state__description{font-size:var(--snice-font-size-md, 1rem);margin-bottom:var(--snice-spacing-xl,2rem)}.empty-state__action{display:inline-flex;align-items:center;justify-content:center;padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-md,1rem);font-size:var(--snice-font-size-sm, .875rem);font-weight:var(--snice-font-weight-medium,500);color:var(--snice-color-text-inverse,rgb(250 250 250));background:var(--snice-color-primary,rgb(37 99 235));border:none;border-radius:var(--snice-border-radius-md,.375rem);text-decoration:none;cursor:pointer;transition:background var(--snice-transition-fast, 150ms)}.empty-state__action:hover{background:var(--snice-color-primary-hover,rgb(29 78 216))}.empty-state--small .empty-state__action{padding:var(--snice-spacing-2xs,.375rem) var(--snice-spacing-sm,.75rem);font-size:var(--snice-font-size-xs, .8125rem)}.empty-state--large .empty-state__action{padding:var(--snice-spacing-sm,.625rem) var(--snice-spacing-lg,1.25rem);font-size:var(--snice-font-size-md, 1rem)}.empty-state__extra ::slotted(*){margin-top:var(--snice-spacing-md,1rem)}";
125
162
 
@@ -241,7 +278,416 @@ var SniceChat = (function (exports, snice) {
241
278
  return _classThis;
242
279
  })();
243
280
 
244
- var cssContent = ":host{display:flex;flex-direction:column;height:var(--snice-chat-height,37.5rem);font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);font-size:var(--snice-font-size-md, 1rem);line-height:1.5;color:var(--snice-color-text,rgb(23 23 23));background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);overflow:hidden;box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1))}.chat-container{display:flex;flex-direction:column;height:100%}.messages-area{flex:1;overflow-y:auto;padding:var(--snice-spacing-md,1rem);display:flex;flex-direction:column;gap:var(--snice-spacing-sm,.75rem)}.messages-area::-webkit-scrollbar{width:8px}.messages-area::-webkit-scrollbar-track{background:0 0}.messages-area::-webkit-scrollbar-thumb{background:var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem)}.messages-area::-webkit-scrollbar-thumb:hover{background:var(--snice-color-text-secondary,rgb(82 82 82))}.message{display:flex;gap:var(--snice-spacing-sm,.75rem);padding:var(--snice-spacing-2xs,.25rem) 0;position:relative}.message:hover .message-actions{opacity:1}.message-avatar{width:2.25rem;height:2.25rem;border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-color-surface-container-low,rgb(250 250 250));display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));font-weight:var(--snice-font-weight-semibold,600);font-size:var(--snice-font-size-sm, .875rem);flex-shrink:0}.message-avatar img{width:100%;height:100%;border-radius:var(--snice-border-radius-md,.25rem);object-fit:cover}.message-content{flex:1;min-width:0}.message-header{font-family:var(--snice-font-family-display);display:flex;align-items:baseline;gap:var(--snice-spacing-xs,.5rem);margin-bottom:var(--snice-spacing-3xs,.125rem)}.message-author{font-weight:var(--snice-font-weight-bold,700);color:var(--snice-color-text,rgb(23 23 23))}.message-timestamp{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.message-edited{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82));font-style:italic}.message-text{word-wrap:break-word;white-space:pre-wrap;color:var(--snice-color-text,rgb(23 23 23))}.message.system{justify-content:center}.message.system .message-text{text-align:center;color:var(--snice-color-text-secondary,rgb(82 82 82));font-size:var(--snice-font-size-sm, .875rem);font-style:italic}.message-attachment{margin-top:var(--snice-spacing-xs,.5rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);overflow:hidden;max-width:25rem}.message-attachment img{max-width:100%;display:block}.attachment-file{display:flex;align-items:center;gap:var(--snice-spacing-sm,.75rem);padding:var(--snice-spacing-sm,.75rem);background:var(--snice-color-surface-container-low,rgb(250 250 250))}.attachment-icon{width:2rem;height:2rem;display:flex;align-items:center;justify-content:center;background:var(--snice-color-surface,rgb(255 255 255));border-radius:var(--snice-border-radius-md,.25rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.attachment-info{flex:1;min-width:0}.attachment-name{font-weight:var(--snice-font-weight-medium,500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.attachment-size{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.message-reactions{display:flex;gap:var(--snice-spacing-2xs,.25rem);margin-top:var(--snice-spacing-2xs,.25rem);flex-wrap:wrap}.reaction{display:flex;align-items:center;gap:var(--snice-spacing-2xs,.25rem);padding:var(--snice-spacing-3xs,.125rem) var(--snice-spacing-xs,.5rem);background:var(--snice-color-surface-container-low,rgb(250 250 250));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:12px;font-size:var(--snice-font-size-sm, .875rem);cursor:pointer;transition:all var(--snice-transition-fast, 150ms)}.reaction:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.reaction.active{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250));border-color:var(--snice-color-primary,rgb(37 99 235))}.reaction-emoji{font-size:var(--snice-font-size-sm, .875rem)}.reaction-count{font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-medium,500)}.message-actions{position:absolute;top:-.75rem;right:var(--snice-spacing-md,1rem);background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1));display:flex;gap:var(--snice-spacing-3xs,.125rem);opacity:0;transition:opacity var(--snice-transition-fast, 150ms);padding:var(--snice-spacing-3xs,.125rem)}.action-button{width:1.75rem;height:1.75rem;border:none;background:0 0;cursor:pointer;border-radius:var(--snice-border-radius-md,.25rem);display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));transition:background var(--snice-transition-fast, 150ms)}.action-button:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.action-button svg{width:1rem;height:1rem}.typing-indicators{padding:0 var(--snice-spacing-md,1rem) var(--snice-spacing-xs,.5rem);min-height:1.5rem}.typing-indicator{display:flex;align-items:center;gap:var(--snice-spacing-xs,.5rem);font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text-secondary,rgb(82 82 82));font-style:italic}.typing-dots{display:flex;gap:.1875rem}.typing-dot{width:6px;height:6px;background:var(--snice-color-text-secondary,rgb(82 82 82));border-radius:50%;animation:1.4s ease-in-out infinite typing-bounce}.typing-dot:first-child{animation-delay:0s}.typing-dot:nth-child(2){animation-delay:.2s}.typing-dot:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,100%,60%{transform:translateY(0)}30%{transform:translateY(-4px)}}.input-area{border-top:1px solid var(--snice-color-border,rgb(226 226 226));padding:var(--snice-spacing-md,1rem);background:var(--snice-color-surface-container-high,rgb(252 251 249))}.input-container{display:flex;align-items:flex-end;gap:var(--snice-spacing-xs,.5rem);background:var(--snice-color-surface-container-lowest,rgb(255 255 255));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);padding:var(--snice-spacing-xs,.5rem);transition:border-color var(--snice-transition-fast, 150ms)}.input-container:focus-within{border-color:var(--snice-color-primary,rgb(37 99 235))}.input-field{flex:1;border:none;outline:0;resize:none;font-family:inherit;font-size:var(--snice-font-size-md, 1rem);line-height:1.5;min-height:1.375rem;max-height:9.375rem;overflow-y:auto;background:0 0;color:var(--snice-color-text,rgb(23 23 23))}.input-field::placeholder{color:var(--snice-color-text-secondary,rgb(82 82 82))}.input-field::-webkit-scrollbar{width:4px}.input-field::-webkit-scrollbar-thumb{background:var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-sm,.125rem)}.input-buttons{display:flex;gap:var(--snice-spacing-2xs,.25rem)}.input-button{width:2rem;height:2rem;border:none;background:0 0;cursor:pointer;border-radius:var(--snice-border-radius-md,.25rem);display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));transition:background var(--snice-transition-fast, 150ms)}.input-button:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.input-button:disabled{opacity:.5;cursor:not-allowed}.input-button.send{color:var(--snice-color-text-inverse,rgb(250 250 250));background:var(--snice-color-primary,rgb(37 99 235))}.input-button.send:hover:not(:disabled){background:var(--snice-color-primary-hover,rgb(29 78 216))}.input-button svg{width:1.125rem;height:1.125rem}input[type=file]{display:none}";
281
+ var markdownStyles = ":host{display:block;font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);contain:layout style paint;color:var(--snice-color-text,rgb(23 23 23));line-height:var(--snice-line-height-normal, 1.5);font-size:var(--snice-font-size-md, 1rem);word-wrap:break-word;overflow-wrap:break-word}.markdown-body{max-width:100%}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-family:var(--snice-font-family-display);color:var(--snice-color-text,rgb(23 23 23));font-weight:var(--snice-font-weight-semibold,600);line-height:1.25;margin-top:var(--snice-spacing-lg,1.5rem);margin-bottom:var(--snice-spacing-md,1rem)}.markdown-body h1{font-family:var(--snice-font-family-display);font-size:2rem;border-bottom:1px solid var(--snice-color-border,rgb(226 226 226));padding-bottom:var(--snice-spacing-xs,.5rem)}.markdown-body h2{font-family:var(--snice-font-family-display);font-size:1.5rem;border-bottom:1px solid var(--snice-color-border,rgb(226 226 226));padding-bottom:var(--snice-spacing-xs,.5rem)}.markdown-body h3{font-family:var(--snice-font-family-display);font-size:1.25rem}.markdown-body h4{font-family:var(--snice-font-family-display);font-size:1rem}.markdown-body h5{font-family:var(--snice-font-family-display);font-size:.875rem}.markdown-body h6{font-family:var(--snice-font-family-display);font-size:.875rem;color:var(--snice-color-text-tertiary,rgb(115 115 115))}.markdown-body p{margin-top:0;margin-bottom:var(--snice-spacing-md,1rem)}.markdown-body a{color:var(--snice-color-primary,rgb(37 99 235));text-decoration:none;cursor:pointer}.markdown-body a:hover{text-decoration:underline}.markdown-body strong{font-weight:var(--snice-font-weight-semibold,600)}.markdown-body em{font-style:italic}.markdown-body del{text-decoration:line-through;color:var(--snice-color-text-secondary,rgb(82 82 82))}.markdown-body ol,.markdown-body ul{margin-top:0;margin-bottom:var(--snice-spacing-md,1rem);padding-left:var(--snice-spacing-xl,2rem)}.markdown-body li{margin-bottom:var(--snice-spacing-2xs,.25rem)}.markdown-body li>ol,.markdown-body li>ul{margin-top:var(--snice-spacing-2xs,.25rem);margin-bottom:0}.markdown-body .task-list-item{list-style-type:none;margin-left:-1.5rem;padding-left:0}.markdown-body .task-list-item input[type=checkbox]{margin-right:var(--snice-spacing-xs,.5rem);vertical-align:middle}.markdown-body blockquote{margin:0 0 var(--snice-spacing-md,1rem) 0;padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-md,1rem);border-left:4px solid var(--snice-color-border,rgb(226 226 226));color:var(--snice-color-text-secondary,rgb(82 82 82));background:var(--snice-color-surface-container-high,rgb(252 251 249));border-radius:0 var(--snice-border-radius-md,.25rem) var(--snice-border-radius-md,.25rem) 0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body code{padding:.125rem .375rem;font-size:.875em;background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:nowrap}.markdown-body pre{margin-top:0;margin-bottom:var(--snice-spacing-md,1rem);padding:var(--snice-spacing-md,1rem);background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-lg,.5rem);overflow-x:auto;font-size:.875rem;line-height:1.6}.markdown-body pre code{padding:0;background:0 0;border:none;border-radius:0;white-space:pre;font-size:inherit}.markdown-body table{width:100%;border-collapse:collapse;margin-bottom:var(--snice-spacing-md,1rem);font-size:var(--snice-font-size-sm, .875rem)}.markdown-body td,.markdown-body th{padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));text-align:left}.markdown-body th{background:var(--snice-color-surface-container-high,rgb(252 251 249));font-weight:var(--snice-font-weight-semibold,600)}.markdown-body tr:nth-child(2n){background:var(--snice-color-surface-container-high,rgb(252 251 249))}.markdown-body hr{border:none;border-top:1px solid var(--snice-color-border,rgb(226 226 226));margin:var(--snice-spacing-lg,1.5rem) 0}.markdown-body img{max-width:100%;height:auto;border-radius:var(--snice-border-radius-md,.25rem)}:host([theme=github]) .markdown-body h1{font-family:var(--snice-font-family-display);font-size:2em}:host([theme=github]) .markdown-body h2{font-family:var(--snice-font-family-display);font-size:1.5em}:host([theme=github]) .markdown-body h3{font-family:var(--snice-font-family-display);font-size:1.25em}:host([theme=github]) .markdown-body blockquote{border-left-color:var(--snice-color-text-tertiary,rgb(115 115 115));background:0 0}:host([theme=github]) .markdown-body pre{background:var(--snice-color-surface-container,rgb(246 248 250));color:var(--snice-color-text,rgb(36 41 47))}:host([theme=github]) .markdown-body code{background:var(--snice-color-surface-container,rgb(246 248 250));color:var(--snice-color-text,rgb(36 41 47))}";
282
+
283
+ // Sanitization: strip dangerous tags/attributes
284
+ const DANGEROUS_TAGS = /^(script|iframe|object|embed|form|input|button|select|textarea|link|meta|style|applet|base|basefont|bgsound|blink|body|frame|frameset|head|html|isindex|ilayer|layer|marquee|param|plaintext|title|xml)$/i;
285
+ const DANGEROUS_ATTRS = /^(on\w+|style|srcdoc|action|formaction|data-bind|xmlns)$/i;
286
+ const DANGEROUS_PROTOCOLS = /^(javascript|vbscript|data):/i;
287
+ function sanitizeHtml(html) {
288
+ // Pre-strip script/style tags before DOMParser to prevent execution in some environments
289
+ const preStripped = html.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1>/gi, '').replace(/<(script|style)\b[^>]*\/?>/gi, '');
290
+ const parser = new DOMParser();
291
+ const doc = parser.parseFromString(preStripped, 'text/html');
292
+ const walk = (node) => {
293
+ const children = Array.from(node.children);
294
+ for (const child of children) {
295
+ if (DANGEROUS_TAGS.test(child.tagName)) {
296
+ child.remove();
297
+ continue;
298
+ }
299
+ const attrs = Array.from(child.attributes);
300
+ for (const attr of attrs) {
301
+ if (DANGEROUS_ATTRS.test(attr.name)) {
302
+ child.removeAttribute(attr.name);
303
+ }
304
+ if (attr.name === 'href' || attr.name === 'src') {
305
+ if (DANGEROUS_PROTOCOLS.test(attr.value.trim())) {
306
+ child.removeAttribute(attr.name);
307
+ }
308
+ }
309
+ }
310
+ walk(child);
311
+ }
312
+ };
313
+ walk(doc.body);
314
+ return doc.body.innerHTML;
315
+ }
316
+ // Escape HTML special characters
317
+ function escapeHtml(str) {
318
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
319
+ }
320
+ // Lightweight GFM-compatible markdown parser
321
+ function parseMarkdown(md) {
322
+ if (!md)
323
+ return '';
324
+ let result = md;
325
+ // Normalize line endings
326
+ result = result.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
327
+ // Extract code blocks first to protect them from parsing
328
+ const codeBlocks = [];
329
+ result = result.replace(/```(\w*)\n([\s\S]*?)```/g, (_match, lang, code) => {
330
+ const escaped = escapeHtml(code.replace(/\n$/, ''));
331
+ const langAttr = lang ? ` class="language-${escapeHtml(lang)}"` : '';
332
+ codeBlocks.push(`<pre><code${langAttr}>${escaped}</code></pre>`);
333
+ return `\x00CB${codeBlocks.length - 1}\x00`;
334
+ });
335
+ // Extract inline code
336
+ const inlineCodes = [];
337
+ result = result.replace(/`([^`\n]+)`/g, (_match, code) => {
338
+ inlineCodes.push(`<code>${escapeHtml(code)}</code>`);
339
+ return `\x00IC${inlineCodes.length - 1}\x00`;
340
+ });
341
+ // Horizontal rules (before list processing)
342
+ result = result.replace(/^([-*_]){3,}\s*$/gm, '<hr>');
343
+ // Headings
344
+ result = result.replace(/^######\s+(.+)$/gm, '<h6>$1</h6>');
345
+ result = result.replace(/^#####\s+(.+)$/gm, '<h5>$1</h5>');
346
+ result = result.replace(/^####\s+(.+)$/gm, '<h4>$1</h4>');
347
+ result = result.replace(/^###\s+(.+)$/gm, '<h3>$1</h3>');
348
+ result = result.replace(/^##\s+(.+)$/gm, '<h2>$1</h2>');
349
+ result = result.replace(/^#\s+(.+)$/gm, '<h1>$1</h1>');
350
+ // Blockquotes
351
+ result = result.replace(/^((?:>\s?.*\n?)+)/gm, (match) => {
352
+ const content = match.replace(/^>\s?/gm, '').trim();
353
+ return `<blockquote>${content}</blockquote>`;
354
+ });
355
+ // Tables (GFM)
356
+ result = result.replace(/^(\|.+\|)\n(\|[-:\s|]+\|)\n((?:\|.+\|\n?)*)/gm, (_match, headerRow, _separator, bodyRows) => {
357
+ const headers = headerRow.split('|').filter((c) => c.trim()).map((c) => `<th>${c.trim()}</th>`).join('');
358
+ const rows = bodyRows.trim().split('\n').map((row) => {
359
+ const cells = row.split('|').filter((c) => c.trim()).map((c) => `<td>${c.trim()}</td>`).join('');
360
+ return `<tr>${cells}</tr>`;
361
+ }).join('');
362
+ return `<table><thead><tr>${headers}</tr></thead><tbody>${rows}</tbody></table>`;
363
+ });
364
+ // Task lists (before regular lists)
365
+ result = result.replace(/^(\s*)- \[x\]\s+(.+)$/gm, '$1<li class="task-list-item"><input type="checkbox" checked disabled> $2</li>');
366
+ result = result.replace(/^(\s*)- \[ \]\s+(.+)$/gm, '$1<li class="task-list-item"><input type="checkbox" disabled> $2</li>');
367
+ // Unordered lists
368
+ result = result.replace(/^((?:\s*[-*+]\s+.+\n?)+)/gm, (match) => {
369
+ const items = match.trim().split('\n').map(line => {
370
+ const content = line.replace(/^\s*[-*+]\s+/, '');
371
+ if (content.startsWith('<li class="task-list-item">'))
372
+ return content;
373
+ return `<li>${content}</li>`;
374
+ }).join('');
375
+ return `<ul>${items}</ul>`;
376
+ });
377
+ // Ordered lists
378
+ result = result.replace(/^((?:\s*\d+\.\s+.+\n?)+)/gm, (match) => {
379
+ const items = match.trim().split('\n').map(line => {
380
+ const content = line.replace(/^\s*\d+\.\s+/, '');
381
+ return `<li>${content}</li>`;
382
+ }).join('');
383
+ return `<ol>${items}</ol>`;
384
+ });
385
+ // Images — escape src attribute and alt text so payloads like
386
+ // ![x](/ onerror="...") cannot break out of the attribute context.
387
+ result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_m, alt, src) => `<img src="${snice.escapeAttr(src)}" alt="${snice.escapeAttr(alt)}">`);
388
+ // Links — same escaping for href + text.
389
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, text, href) => `<a href="${snice.escapeAttr(href)}">${escapeHtml(text)}</a>`);
390
+ // Autolinks (GFM)
391
+ result = result.replace(/(^|[^"(])(https?:\/\/[^\s<>]+)/g, (_m, lead, url) => `${lead}<a href="${snice.escapeAttr(url)}">${escapeHtml(url)}</a>`);
392
+ // Bold and italic (process bold first)
393
+ result = result.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
394
+ result = result.replace(/___(.+?)___/g, '<strong><em>$1</em></strong>');
395
+ result = result.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
396
+ result = result.replace(/__(.+?)__/g, '<strong>$1</strong>');
397
+ result = result.replace(/\*(.+?)\*/g, '<em>$1</em>');
398
+ result = result.replace(/_(.+?)_/g, '<em>$1</em>');
399
+ // Strikethrough (GFM)
400
+ result = result.replace(/~~(.+?)~~/g, '<del>$1</del>');
401
+ // Paragraphs: wrap standalone text lines
402
+ result = result.replace(/^(?!<[a-z/]|$|\x00)(.+)$/gm, '<p>$1</p>');
403
+ // Clean up double paragraphs / empty paragraphs
404
+ result = result.replace(/<p><\/p>/g, '');
405
+ result = result.replace(/(<\/(?:ul|ol|blockquote|table|pre|h[1-6]|hr)>)\s*<p>/g, '$1\n<p>');
406
+ // Restore inline codes
407
+ result = result.replace(/\x00IC(\d+)\x00/g, (_match, idx) => inlineCodes[parseInt(idx)]);
408
+ // Restore code blocks
409
+ result = result.replace(/(?:<p>)?\x00CB(\d+)\x00(?:<\/p>)?/g, (_match, idx) => codeBlocks[parseInt(idx)]);
410
+ return result.trim();
411
+ }
412
+ (() => {
413
+ let _classDecorators = [snice.element('snice-markdown')];
414
+ let _classDescriptor;
415
+ let _classExtraInitializers = [];
416
+ let _classThis;
417
+ let _classSuper = HTMLElement;
418
+ let _instanceExtraInitializers = [];
419
+ let _content_decorators;
420
+ let _content_initializers = [];
421
+ let _content_extraInitializers = [];
422
+ let _sanitize_decorators;
423
+ let _sanitize_initializers = [];
424
+ let _sanitize_extraInitializers = [];
425
+ let _theme_decorators;
426
+ let _theme_initializers = [];
427
+ let _theme_extraInitializers = [];
428
+ let _renderedHtml_decorators;
429
+ let _renderedHtml_initializers = [];
430
+ let _renderedHtml_extraInitializers = [];
431
+ let _componentStyles_decorators;
432
+ let _init_decorators;
433
+ let _handleSlotChange_decorators;
434
+ let _handleContentChange_decorators;
435
+ let _handleSanitizeChange_decorators;
436
+ let _handleLinkClick_decorators;
437
+ let _emitRender_decorators;
438
+ let _emitLinkClick_decorators;
439
+ let _renderContent_decorators;
440
+ (class extends _classSuper {
441
+ static { _classThis = this; }
442
+ static {
443
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
444
+ _content_decorators = [snice.property({ attribute: false })];
445
+ _sanitize_decorators = [snice.property({ type: Boolean })];
446
+ _theme_decorators = [snice.property()];
447
+ _renderedHtml_decorators = [snice.property({ attribute: false })];
448
+ _componentStyles_decorators = [snice.styles()];
449
+ _init_decorators = [snice.ready()];
450
+ _handleSlotChange_decorators = [snice.on('slotchange', { target: 'slot' })];
451
+ _handleContentChange_decorators = [snice.watch('content')];
452
+ _handleSanitizeChange_decorators = [snice.watch('sanitize')];
453
+ _handleLinkClick_decorators = [snice.on('click', { target: 'a' })];
454
+ _emitRender_decorators = [snice.dispatch('markdown-render', { bubbles: true, composed: true })];
455
+ _emitLinkClick_decorators = [snice.dispatch('link-click', { bubbles: true, composed: true })];
456
+ _renderContent_decorators = [snice.render()];
457
+ __esDecorate(this, null, _componentStyles_decorators, { kind: "method", name: "componentStyles", static: false, private: false, access: { has: obj => "componentStyles" in obj, get: obj => obj.componentStyles }, metadata: _metadata }, null, _instanceExtraInitializers);
458
+ __esDecorate(this, null, _init_decorators, { kind: "method", name: "init", static: false, private: false, access: { has: obj => "init" in obj, get: obj => obj.init }, metadata: _metadata }, null, _instanceExtraInitializers);
459
+ __esDecorate(this, null, _handleSlotChange_decorators, { kind: "method", name: "handleSlotChange", static: false, private: false, access: { has: obj => "handleSlotChange" in obj, get: obj => obj.handleSlotChange }, metadata: _metadata }, null, _instanceExtraInitializers);
460
+ __esDecorate(this, null, _handleContentChange_decorators, { kind: "method", name: "handleContentChange", static: false, private: false, access: { has: obj => "handleContentChange" in obj, get: obj => obj.handleContentChange }, metadata: _metadata }, null, _instanceExtraInitializers);
461
+ __esDecorate(this, null, _handleSanitizeChange_decorators, { kind: "method", name: "handleSanitizeChange", static: false, private: false, access: { has: obj => "handleSanitizeChange" in obj, get: obj => obj.handleSanitizeChange }, metadata: _metadata }, null, _instanceExtraInitializers);
462
+ __esDecorate(this, null, _handleLinkClick_decorators, { kind: "method", name: "handleLinkClick", static: false, private: false, access: { has: obj => "handleLinkClick" in obj, get: obj => obj.handleLinkClick }, metadata: _metadata }, null, _instanceExtraInitializers);
463
+ __esDecorate(this, null, _emitRender_decorators, { kind: "method", name: "emitRender", static: false, private: false, access: { has: obj => "emitRender" in obj, get: obj => obj.emitRender }, metadata: _metadata }, null, _instanceExtraInitializers);
464
+ __esDecorate(this, null, _emitLinkClick_decorators, { kind: "method", name: "emitLinkClick", static: false, private: false, access: { has: obj => "emitLinkClick" in obj, get: obj => obj.emitLinkClick }, metadata: _metadata }, null, _instanceExtraInitializers);
465
+ __esDecorate(this, null, _renderContent_decorators, { kind: "method", name: "renderContent", static: false, private: false, access: { has: obj => "renderContent" in obj, get: obj => obj.renderContent }, metadata: _metadata }, null, _instanceExtraInitializers);
466
+ __esDecorate(null, null, _content_decorators, { kind: "field", name: "content", static: false, private: false, access: { has: obj => "content" in obj, get: obj => obj.content, set: (obj, value) => { obj.content = value; } }, metadata: _metadata }, _content_initializers, _content_extraInitializers);
467
+ __esDecorate(null, null, _sanitize_decorators, { kind: "field", name: "sanitize", static: false, private: false, access: { has: obj => "sanitize" in obj, get: obj => obj.sanitize, set: (obj, value) => { obj.sanitize = value; } }, metadata: _metadata }, _sanitize_initializers, _sanitize_extraInitializers);
468
+ __esDecorate(null, null, _theme_decorators, { kind: "field", name: "theme", static: false, private: false, access: { has: obj => "theme" in obj, get: obj => obj.theme, set: (obj, value) => { obj.theme = value; } }, metadata: _metadata }, _theme_initializers, _theme_extraInitializers);
469
+ __esDecorate(null, null, _renderedHtml_decorators, { kind: "field", name: "renderedHtml", static: false, private: false, access: { has: obj => "renderedHtml" in obj, get: obj => obj.renderedHtml, set: (obj, value) => { obj.renderedHtml = value; } }, metadata: _metadata }, _renderedHtml_initializers, _renderedHtml_extraInitializers);
470
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
471
+ _classThis = _classDescriptor.value;
472
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
473
+ __runInitializers(_classThis, _classExtraInitializers);
474
+ }
475
+ componentStyles() {
476
+ return snice.css /*css*/ `${markdownStyles}`;
477
+ }
478
+ init() {
479
+ if (!this.content) {
480
+ this.readSlottedContent();
481
+ }
482
+ if (this.content) {
483
+ this.renderMarkdown();
484
+ }
485
+ }
486
+ handleSlotChange() {
487
+ this.readSlottedContent();
488
+ }
489
+ readSlottedContent() {
490
+ const text = this.textContent?.trim();
491
+ if (text) {
492
+ this.content = text;
493
+ this.renderMarkdown();
494
+ }
495
+ }
496
+ handleContentChange() {
497
+ this.renderMarkdown();
498
+ }
499
+ handleSanitizeChange() {
500
+ this.renderMarkdown();
501
+ }
502
+ renderMarkdown() {
503
+ let parsed = parseMarkdown(this.content);
504
+ if (this.sanitize) {
505
+ parsed = sanitizeHtml(parsed);
506
+ }
507
+ this.renderedHtml = parsed;
508
+ this.emitRender();
509
+ }
510
+ handleLinkClick(e) {
511
+ const anchor = e.target;
512
+ if (anchor?.tagName === 'A') {
513
+ e.preventDefault();
514
+ this.emitLinkClick(anchor.getAttribute('href') || '', anchor.textContent || '');
515
+ }
516
+ }
517
+ emitRender() {
518
+ return { html: this.renderedHtml };
519
+ }
520
+ emitLinkClick(href, text) {
521
+ return { href, text };
522
+ }
523
+ /** Set content programmatically and re-render */
524
+ setContent(markdown) {
525
+ this.content = markdown;
526
+ this.renderMarkdown();
527
+ }
528
+ renderContent() {
529
+ return snice.html /*html*/ `
530
+ <slot style="display:none"></slot>
531
+ <div class="markdown-body" part="base">${snice.unsafeHTML(this.renderedHtml)}</div>
532
+ `;
533
+ }
534
+ constructor() {
535
+ super(...arguments);
536
+ // Reactive so parents can drive it via a .content template binding — a
537
+ // plain field would render once and go stale on later assignments.
538
+ this.content = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _content_initializers, ''));
539
+ this.sanitize = (__runInitializers(this, _content_extraInitializers), __runInitializers(this, _sanitize_initializers, true));
540
+ this.theme = (__runInitializers(this, _sanitize_extraInitializers), __runInitializers(this, _theme_initializers, 'default'));
541
+ this.renderedHtml = (__runInitializers(this, _theme_extraInitializers), __runInitializers(this, _renderedHtml_initializers, ''));
542
+ __runInitializers(this, _renderedHtml_extraInitializers);
543
+ }
544
+ });
545
+ return _classThis;
546
+ })();
547
+
548
+ /**
549
+ * snice-chat-message - declarative message authoring for snice-chat.
550
+ *
551
+ * A config-carrier element (same pattern as snice-column): it renders only a
552
+ * <slot> and exposes getMessageDefinition() so the parent snice-chat can read
553
+ * its props + slotted body as a ChatMessage. It does not render the message
554
+ * itself — the parent owns all rendering and the styling part surface.
555
+ *
556
+ * @element snice-chat-message
557
+ */
558
+ (() => {
559
+ let _classDecorators = [snice.element('snice-chat-message')];
560
+ let _classDescriptor;
561
+ let _classExtraInitializers = [];
562
+ let _classThis;
563
+ let _classSuper = HTMLElement;
564
+ let _instanceExtraInitializers = [];
565
+ let _author_decorators;
566
+ let _author_initializers = [];
567
+ let _author_extraInitializers = [];
568
+ let _avatar_decorators;
569
+ let _avatar_initializers = [];
570
+ let _avatar_extraInitializers = [];
571
+ let _type_decorators;
572
+ let _type_initializers = [];
573
+ let _type_extraInitializers = [];
574
+ let _format_decorators;
575
+ let _format_initializers = [];
576
+ let _format_extraInitializers = [];
577
+ let _edited_decorators;
578
+ let _edited_initializers = [];
579
+ let _edited_extraInitializers = [];
580
+ let _authorColor_decorators;
581
+ let _authorColor_initializers = [];
582
+ let _authorColor_extraInitializers = [];
583
+ let _reactions_decorators;
584
+ let _reactions_initializers = [];
585
+ let _reactions_extraInitializers = [];
586
+ let _attachment_decorators;
587
+ let _attachment_initializers = [];
588
+ let _attachment_extraInitializers = [];
589
+ let _thread_decorators;
590
+ let _thread_initializers = [];
591
+ let _thread_extraInitializers = [];
592
+ let _render_decorators;
593
+ (class extends _classSuper {
594
+ static { _classThis = this; }
595
+ static {
596
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
597
+ _author_decorators = [snice.property()];
598
+ _avatar_decorators = [snice.property()];
599
+ _type_decorators = [snice.property()];
600
+ _format_decorators = [snice.property()];
601
+ _edited_decorators = [snice.property({ type: Boolean })];
602
+ _authorColor_decorators = [snice.property({ attribute: 'author-color' })];
603
+ _reactions_decorators = [snice.property({ type: Array, attribute: false })];
604
+ _attachment_decorators = [snice.property({ type: Object, attribute: false })];
605
+ _thread_decorators = [snice.property({ type: Array, attribute: false })];
606
+ _render_decorators = [snice.render()];
607
+ __esDecorate(this, null, _render_decorators, { kind: "method", name: "render", static: false, private: false, access: { has: obj => "render" in obj, get: obj => obj.render }, metadata: _metadata }, null, _instanceExtraInitializers);
608
+ __esDecorate(null, null, _author_decorators, { kind: "field", name: "author", static: false, private: false, access: { has: obj => "author" in obj, get: obj => obj.author, set: (obj, value) => { obj.author = value; } }, metadata: _metadata }, _author_initializers, _author_extraInitializers);
609
+ __esDecorate(null, null, _avatar_decorators, { kind: "field", name: "avatar", static: false, private: false, access: { has: obj => "avatar" in obj, get: obj => obj.avatar, set: (obj, value) => { obj.avatar = value; } }, metadata: _metadata }, _avatar_initializers, _avatar_extraInitializers);
610
+ __esDecorate(null, null, _type_decorators, { kind: "field", name: "type", static: false, private: false, access: { has: obj => "type" in obj, get: obj => obj.type, set: (obj, value) => { obj.type = value; } }, metadata: _metadata }, _type_initializers, _type_extraInitializers);
611
+ __esDecorate(null, null, _format_decorators, { kind: "field", name: "format", static: false, private: false, access: { has: obj => "format" in obj, get: obj => obj.format, set: (obj, value) => { obj.format = value; } }, metadata: _metadata }, _format_initializers, _format_extraInitializers);
612
+ __esDecorate(null, null, _edited_decorators, { kind: "field", name: "edited", static: false, private: false, access: { has: obj => "edited" in obj, get: obj => obj.edited, set: (obj, value) => { obj.edited = value; } }, metadata: _metadata }, _edited_initializers, _edited_extraInitializers);
613
+ __esDecorate(null, null, _authorColor_decorators, { kind: "field", name: "authorColor", static: false, private: false, access: { has: obj => "authorColor" in obj, get: obj => obj.authorColor, set: (obj, value) => { obj.authorColor = value; } }, metadata: _metadata }, _authorColor_initializers, _authorColor_extraInitializers);
614
+ __esDecorate(null, null, _reactions_decorators, { kind: "field", name: "reactions", static: false, private: false, access: { has: obj => "reactions" in obj, get: obj => obj.reactions, set: (obj, value) => { obj.reactions = value; } }, metadata: _metadata }, _reactions_initializers, _reactions_extraInitializers);
615
+ __esDecorate(null, null, _attachment_decorators, { kind: "field", name: "attachment", static: false, private: false, access: { has: obj => "attachment" in obj, get: obj => obj.attachment, set: (obj, value) => { obj.attachment = value; } }, metadata: _metadata }, _attachment_initializers, _attachment_extraInitializers);
616
+ __esDecorate(null, null, _thread_decorators, { kind: "field", name: "thread", static: false, private: false, access: { has: obj => "thread" in obj, get: obj => obj.thread, set: (obj, value) => { obj.thread = value; } }, metadata: _metadata }, _thread_initializers, _thread_extraInitializers);
617
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
618
+ _classThis = _classDescriptor.value;
619
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
620
+ __runInitializers(_classThis, _classExtraInitializers);
621
+ }
622
+ render() {
623
+ return snice.html /*html*/ `<slot></slot>`;
624
+ }
625
+ /** Serialize this element into a ChatMessage for the parent chat. */
626
+ getMessageDefinition() {
627
+ const timestampAttr = this.getAttribute('timestamp');
628
+ const definition = {
629
+ id: '',
630
+ type: this.type,
631
+ content: (this.textContent ?? '').trim(),
632
+ author: this.author,
633
+ timestamp: timestampAttr ? new Date(timestampAttr) : new Date(),
634
+ edited: this.edited,
635
+ };
636
+ if (this.format)
637
+ definition.format = this.format;
638
+ if (this.avatar)
639
+ definition.avatar = this.avatar;
640
+ if (this.authorColor)
641
+ definition.authorColor = this.authorColor;
642
+ if (this.reactions)
643
+ definition.reactions = this.reactions;
644
+ if (this.attachment)
645
+ definition.attachment = this.attachment;
646
+ if (this.thread)
647
+ definition.thread = this.thread;
648
+ return definition;
649
+ }
650
+ constructor() {
651
+ super(...arguments);
652
+ this.author = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _author_initializers, ''));
653
+ this.avatar = (__runInitializers(this, _author_extraInitializers), __runInitializers(this, _avatar_initializers, ''));
654
+ this.type = (__runInitializers(this, _avatar_extraInitializers), __runInitializers(this, _type_initializers, 'text'));
655
+ // No default: undefined defers to the chat-level `markdown` flag, exactly
656
+ // like an imperative addMessage() without a format.
657
+ this.format = (__runInitializers(this, _type_extraInitializers), __runInitializers(this, _format_initializers, void 0));
658
+ this.edited = (__runInitializers(this, _format_extraInitializers), __runInitializers(this, _edited_initializers, false));
659
+ this.authorColor = (__runInitializers(this, _edited_extraInitializers), __runInitializers(this, _authorColor_initializers, ''));
660
+ // Rich fields have no attribute form — set them as JS properties.
661
+ this.reactions = (__runInitializers(this, _authorColor_extraInitializers), __runInitializers(this, _reactions_initializers, void 0));
662
+ this.attachment = (__runInitializers(this, _reactions_extraInitializers), __runInitializers(this, _attachment_initializers, void 0));
663
+ this.thread = (__runInitializers(this, _attachment_extraInitializers), __runInitializers(this, _thread_initializers, void 0));
664
+ __runInitializers(this, _thread_extraInitializers);
665
+ }
666
+ });
667
+ return _classThis;
668
+ })();
669
+
670
+ /**
671
+ * Types for the snice-chat component
672
+ */
673
+ /**
674
+ * How a message body is rendered
675
+ */
676
+ var MessageFormat;
677
+ (function (MessageFormat) {
678
+ MessageFormat["Text"] = "text";
679
+ MessageFormat["Markdown"] = "markdown";
680
+ })(MessageFormat || (MessageFormat = {}));
681
+ /**
682
+ * Built-in message layout for snice-chat
683
+ */
684
+ var ChatLayout;
685
+ (function (ChatLayout) {
686
+ ChatLayout["Default"] = "default";
687
+ ChatLayout["Bubbles"] = "bubbles";
688
+ })(ChatLayout || (ChatLayout = {}));
689
+
690
+ var cssContent = ":host{display:flex;flex-direction:column;height:var(--snice-chat-height,37.5rem);font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);font-size:var(--snice-font-size-md, 1rem);line-height:1.5;color:var(--snice-color-text,rgb(23 23 23));background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);overflow:hidden;box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1))}.chat-container{display:flex;flex-direction:column;height:100%}.messages-area{flex:1;overflow-y:auto;padding:var(--snice-spacing-md,1rem);display:flex;flex-direction:column;gap:var(--snice-spacing-sm,.75rem)}.messages-area::-webkit-scrollbar{width:8px}.messages-area::-webkit-scrollbar-track{background:0 0}.messages-area::-webkit-scrollbar-thumb{background:var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem)}.messages-area::-webkit-scrollbar-thumb:hover{background:var(--snice-color-text-secondary,rgb(82 82 82))}.message{display:flex;gap:var(--snice-spacing-sm,.75rem);padding:var(--snice-spacing-2xs,.25rem) 0;position:relative}.message:hover .message-actions{opacity:1}.message-avatar{width:2.25rem;height:2.25rem;border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-color-surface-container-low,rgb(250 250 250));display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));font-weight:var(--snice-font-weight-semibold,600);font-size:var(--snice-font-size-sm, .875rem);flex-shrink:0}.message-avatar img{width:100%;height:100%;border-radius:var(--snice-border-radius-md,.25rem);object-fit:cover}.message-content{flex:1;min-width:0}.message-header{font-family:var(--snice-font-family-display);display:flex;align-items:baseline;gap:var(--snice-spacing-xs,.5rem);margin-bottom:var(--snice-spacing-3xs,.125rem)}.message-author{font-weight:var(--snice-font-weight-bold,700);color:var(--snice-chat-author-color,var(--snice-color-text,rgb(23 23 23)))}.message-timestamp{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.message-edited{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82));font-style:italic}.message-text{word-wrap:break-word;white-space:pre-wrap;color:var(--snice-color-text,rgb(23 23 23))}snice-markdown.message-text{white-space:normal;display:block}.message.system{justify-content:center}.message.system .message-text{text-align:center;color:var(--snice-color-text-secondary,rgb(82 82 82));font-size:var(--snice-font-size-sm, .875rem);font-style:italic}.message-attachment{margin-top:var(--snice-spacing-xs,.5rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);overflow:hidden;max-width:25rem}.message-attachment img{max-width:100%;display:block}.attachment-file{display:flex;align-items:center;gap:var(--snice-spacing-sm,.75rem);padding:var(--snice-spacing-sm,.75rem);background:var(--snice-color-surface-container-low,rgb(250 250 250))}.attachment-icon{width:2rem;height:2rem;display:flex;align-items:center;justify-content:center;background:var(--snice-color-surface,rgb(255 255 255));border-radius:var(--snice-border-radius-md,.25rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.attachment-info{flex:1;min-width:0}.attachment-name{font-weight:var(--snice-font-weight-medium,500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.attachment-size{font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.message-reactions{display:flex;gap:var(--snice-spacing-2xs,.25rem);margin-top:var(--snice-spacing-2xs,.25rem);flex-wrap:wrap}.reaction{display:flex;align-items:center;gap:var(--snice-spacing-2xs,.25rem);padding:var(--snice-spacing-3xs,.125rem) var(--snice-spacing-xs,.5rem);background:var(--snice-color-surface-container-low,rgb(250 250 250));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:12px;font-size:var(--snice-font-size-sm, .875rem);cursor:pointer;transition:all var(--snice-transition-fast, 150ms)}.reaction:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.reaction.active{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250));border-color:var(--snice-color-primary,rgb(37 99 235))}.reaction-emoji{font-size:var(--snice-font-size-sm, .875rem)}.reaction-count{font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-medium,500)}.message-actions{position:absolute;top:-.75rem;right:var(--snice-spacing-md,1rem);background:var(--snice-color-surface-container-high,rgb(252 251 249));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1));display:flex;gap:var(--snice-spacing-3xs,.125rem);opacity:0;transition:opacity var(--snice-transition-fast, 150ms);padding:var(--snice-spacing-3xs,.125rem)}.action-button{width:1.75rem;height:1.75rem;border:none;background:0 0;cursor:pointer;border-radius:var(--snice-border-radius-md,.25rem);display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));transition:background var(--snice-transition-fast, 150ms)}.action-button:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.action-button svg{width:1rem;height:1rem}.action-emoji{font-size:var(--snice-font-size-sm, .875rem);line-height:1}.message-edit{display:flex;flex-direction:column;gap:var(--snice-spacing-xs,.5rem);margin-top:var(--snice-spacing-3xs,.125rem)}.edit-field{width:100%;box-sizing:border-box;resize:vertical;min-height:2.5rem;font-family:inherit;font-size:var(--snice-font-size-md, 1rem);line-height:1.5;color:var(--snice-color-text,rgb(23 23 23));background:var(--snice-color-surface-container-lowest,rgb(255 255 255));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);padding:var(--snice-spacing-xs,.5rem)}.edit-field:focus{outline:0;border-color:var(--snice-color-primary,rgb(37 99 235))}.confirm-actions,.edit-actions{display:flex;gap:var(--snice-spacing-xs,.5rem)}.confirm-button,.edit-button{cursor:pointer;font-family:inherit;font-size:var(--snice-font-size-sm, .875rem);font-weight:var(--snice-font-weight-medium,500);padding:var(--snice-spacing-3xs,.125rem) var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text,rgb(23 23 23));transition:background var(--snice-transition-fast, 150ms)}.confirm-button:hover,.edit-button:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.edit-save{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250));border-color:var(--snice-color-primary,rgb(37 99 235))}.edit-save:hover{background:var(--snice-color-primary-hover,rgb(29 78 216))}.message-confirm{display:flex;align-items:center;flex-wrap:wrap;gap:var(--snice-spacing-sm,.75rem);margin-top:var(--snice-spacing-xs,.5rem);padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-sm,.75rem);background:var(--snice-color-surface-container-low,rgb(250 250 250));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem)}.confirm-text{font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text-secondary,rgb(82 82 82))}.confirm-delete{background:var(--snice-color-danger,rgb(220 38 38));color:var(--snice-color-text-inverse,rgb(250 250 250));border-color:var(--snice-color-danger,rgb(220 38 38))}.confirm-delete:hover{background:var(--snice-color-danger,rgb(220 38 38));filter:brightness(.92)}.typing-indicators{padding:0 var(--snice-spacing-md,1rem) var(--snice-spacing-xs,.5rem);min-height:1.5rem}.typing-indicator{display:flex;align-items:center;gap:var(--snice-spacing-xs,.5rem);font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text-secondary,rgb(82 82 82));font-style:italic}.typing-dots{display:flex;gap:.1875rem}.typing-dot{width:6px;height:6px;background:var(--snice-color-text-secondary,rgb(82 82 82));border-radius:50%;animation:1.4s ease-in-out infinite typing-bounce}.typing-dot:first-child{animation-delay:0s}.typing-dot:nth-child(2){animation-delay:.2s}.typing-dot:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,100%,60%{transform:translateY(0)}30%{transform:translateY(-4px)}}.input-area{border-top:1px solid var(--snice-color-border,rgb(226 226 226));padding:var(--snice-spacing-md,1rem);background:var(--snice-color-surface-container-high,rgb(252 251 249))}.input-container{display:flex;align-items:flex-end;gap:var(--snice-spacing-xs,.5rem);background:var(--snice-color-surface-container-lowest,rgb(255 255 255));border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);padding:var(--snice-spacing-xs,.5rem);transition:border-color var(--snice-transition-fast, 150ms)}.input-container:focus-within{border-color:var(--snice-color-primary,rgb(37 99 235))}.input-field{flex:1;border:none;outline:0;resize:none;font-family:inherit;font-size:var(--snice-font-size-md, 1rem);line-height:1.5;min-height:1.375rem;max-height:9.375rem;overflow-y:auto;background:0 0;color:var(--snice-color-text,rgb(23 23 23))}.input-field::placeholder{color:var(--snice-color-text-secondary,rgb(82 82 82))}.input-field::-webkit-scrollbar{width:4px}.input-field::-webkit-scrollbar-thumb{background:var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-sm,.125rem)}.input-buttons{display:flex;gap:var(--snice-spacing-2xs,.25rem)}.input-button{width:2rem;height:2rem;border:none;background:0 0;cursor:pointer;border-radius:var(--snice-border-radius-md,.25rem);display:flex;align-items:center;justify-content:center;color:var(--snice-color-text-secondary,rgb(82 82 82));transition:background var(--snice-transition-fast, 150ms)}.input-button:hover{background:var(--snice-color-surface-hover,rgb(242 242 242))}.input-button:disabled{opacity:.5;cursor:not-allowed}.input-button.send{color:var(--snice-color-text-inverse,rgb(250 250 250));background:var(--snice-color-primary,rgb(37 99 235))}.input-button.send:hover:not(:disabled){background:var(--snice-color-primary-hover,rgb(29 78 216))}.input-button svg{width:1.125rem;height:1.125rem}input[type=file]{display:none}:host([layout=bubbles]) .message.own{flex-direction:row-reverse}:host([layout=bubbles]) .message.own .message-content{display:flex;flex-direction:column;align-items:flex-end}:host([layout=bubbles]) .message.own .message-header{flex-direction:row-reverse}:host([layout=bubbles]) .message .message-text{display:inline-block;padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-sm,.75rem);border-radius:var(--snice-border-radius-lg,.5rem);background:var(--snice-color-surface-container,rgb(242 242 242))}:host([layout=bubbles]) .message.own .message-text{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250))}";
245
691
 
246
692
  /**
247
693
  * Generate unique ID
@@ -279,6 +725,26 @@ var SniceChat = (function (exports, snice) {
279
725
  .toUpperCase()
280
726
  .substring(0, 2);
281
727
  }
728
+ /**
729
+ * Stable color for an author name: hash → one of the 8 accent slots. Returns a
730
+ * theme accent var with the shared concrete fallback.
731
+ */
732
+ function autoAuthorColor(name) {
733
+ let hash = 0;
734
+ for (let i = 0; i < name.length; i++) {
735
+ hash = (hash * 31 + name.charCodeAt(i)) >>> 0;
736
+ }
737
+ const slot = (hash % 8) + 1;
738
+ return `var(--snice-color-accent-${slot}, ${FALLBACK_ACCENTS[slot - 1]})`;
739
+ }
740
+ /**
741
+ * Author colors ride on message data, so they can come from a backend. A CSS
742
+ * color never needs `;`, `{`, or `}` — reject values that could smuggle extra
743
+ * declarations into the inline style attribute.
744
+ */
745
+ function isSafeCssColor(value) {
746
+ return !/[;{}]/.test(value);
747
+ }
282
748
  /**
283
749
  * snice-chat - Chat interface component
284
750
  *
@@ -290,7 +756,6 @@ var SniceChat = (function (exports, snice) {
290
756
  * @fires {CustomEvent<{ messageId: string; newContent: string }>} message-edit - Fires when editing a message
291
757
  * @fires {CustomEvent<{ messageId: string }>} message-delete - Fires when deleting a message
292
758
  * @fires {CustomEvent<{ messageId: string; emoji: string }>} message-react - Fires when reacting to a message
293
- * @fires {CustomEvent<{ messageId: string }>} message-thread - Fires when starting a thread
294
759
  * @fires {CustomEvent<{}>} typing-start - Fires when user starts typing
295
760
  * @fires {CustomEvent<{}>} typing-stop - Fires when user stops typing
296
761
  */
@@ -325,23 +790,53 @@ var SniceChat = (function (exports, snice) {
325
790
  let _showTimestamps_decorators;
326
791
  let _showTimestamps_initializers = [];
327
792
  let _showTimestamps_extraInitializers = [];
793
+ let _authorColors_decorators;
794
+ let _authorColors_initializers = [];
795
+ let _authorColors_extraInitializers = [];
796
+ let _colorAuthors_decorators;
797
+ let _colorAuthors_initializers = [];
798
+ let _colorAuthors_extraInitializers = [];
799
+ let _markdown_decorators;
800
+ let _markdown_initializers = [];
801
+ let _markdown_extraInitializers = [];
802
+ let _layout_decorators;
803
+ let _layout_initializers = [];
804
+ let _layout_extraInitializers = [];
805
+ let _editingId_decorators;
806
+ let _editingId_initializers = [];
807
+ let _editingId_extraInitializers = [];
808
+ let _confirmingDeleteId_decorators;
809
+ let _confirmingDeleteId_initializers = [];
810
+ let _confirmingDeleteId_extraInitializers = [];
328
811
  let _messagesArea_decorators;
329
812
  let _messagesArea_initializers = [];
330
813
  let _messagesArea_extraInitializers = [];
331
814
  let _inputField_decorators;
332
815
  let _inputField_initializers = [];
333
816
  let _inputField_extraInitializers = [];
817
+ let _editField_decorators;
818
+ let _editField_initializers = [];
819
+ let _editField_extraInitializers = [];
820
+ let _editBox_decorators;
821
+ let _editBox_initializers = [];
822
+ let _editBox_extraInitializers = [];
823
+ let _confirmBox_decorators;
824
+ let _confirmBox_initializers = [];
825
+ let _confirmBox_extraInitializers = [];
334
826
  let _styles_decorators;
335
827
  let _init_decorators;
828
+ let _onSlottedMessagesChanged_decorators;
829
+ let _onSlottedMessageAttributesChanged_decorators;
336
830
  let _cleanup_decorators;
337
831
  let _messagesChanged_decorators;
338
832
  let _emitMessageSend_decorators;
339
833
  let _emitMessageEdit_decorators;
340
834
  let _emitMessageDelete_decorators;
341
835
  let _emitMessageReact_decorators;
342
- let _emitMessageThread_decorators;
343
836
  let _emitTypingStart_decorators;
344
837
  let _emitTypingStop_decorators;
838
+ let _focusEditField_decorators;
839
+ let _revealDeleteConfirm_decorators;
345
840
  let _render_decorators;
346
841
  (class extends _classSuper {
347
842
  static { _classThis = this; }
@@ -355,11 +850,28 @@ var SniceChat = (function (exports, snice) {
355
850
  this.showTyping = (__runInitializers(this, _allowFiles_extraInitializers), __runInitializers(this, _showTyping_initializers, true));
356
851
  this.showAvatars = (__runInitializers(this, _showTyping_extraInitializers), __runInitializers(this, _showAvatars_initializers, true));
357
852
  this.showTimestamps = (__runInitializers(this, _showAvatars_extraInitializers), __runInitializers(this, _showTimestamps_initializers, true));
358
- this.messagesArea = (__runInitializers(this, _showTimestamps_extraInitializers), __runInitializers(this, _messagesArea_initializers, void 0));
853
+ this.authorColors = (__runInitializers(this, _showTimestamps_extraInitializers), __runInitializers(this, _authorColors_initializers, {}));
854
+ this.colorAuthors = (__runInitializers(this, _authorColors_extraInitializers), __runInitializers(this, _colorAuthors_initializers, false));
855
+ this.markdown = (__runInitializers(this, _colorAuthors_extraInitializers), __runInitializers(this, _markdown_initializers, false));
856
+ this.layout = (__runInitializers(this, _markdown_extraInitializers), __runInitializers(this, _layout_initializers, ChatLayout.Default));
857
+ // Internal reactive state: id of the message currently being edited inline.
858
+ this.editingId = (__runInitializers(this, _layout_extraInitializers), __runInitializers(this, _editingId_initializers, null));
859
+ // Internal reactive state: id of the message pending inline delete-confirm.
860
+ this.confirmingDeleteId = (__runInitializers(this, _editingId_extraInitializers), __runInitializers(this, _confirmingDeleteId_initializers, null));
861
+ this.messagesArea = (__runInitializers(this, _confirmingDeleteId_extraInitializers), __runInitializers(this, _messagesArea_initializers, void 0));
359
862
  this.inputField = (__runInitializers(this, _messagesArea_extraInitializers), __runInitializers(this, _inputField_initializers, void 0));
360
- this.typingIndicators = (__runInitializers(this, _inputField_extraInitializers), new Map());
863
+ this.editField = (__runInitializers(this, _inputField_extraInitializers), __runInitializers(this, _editField_initializers, void 0));
864
+ this.editBox = (__runInitializers(this, _editField_extraInitializers), __runInitializers(this, _editBox_initializers, void 0));
865
+ this.confirmBox = (__runInitializers(this, _editBox_extraInitializers), __runInitializers(this, _confirmBox_initializers, void 0));
866
+ this.typingIndicators = (__runInitializers(this, _confirmBox_extraInitializers), new Map());
361
867
  this.typingTimeout = null;
362
868
  this.fileInput = null;
869
+ // Element → stable message id, so re-ingesting doesn't mint new ids and
870
+ // orphan reactions/edit state keyed to the old ones.
871
+ this.slotMessageIds = new WeakMap();
872
+ // Every id ever minted for a slot element, so a removed slot child isn't
873
+ // misclassified as an imperative message and resurrected on re-ingest.
874
+ this.mintedSlotIds = new Set();
363
875
  this.handleKeyDown = (e) => {
364
876
  const target = e.target;
365
877
  if (target !== this.inputField)
@@ -380,31 +892,46 @@ var SniceChat = (function (exports, snice) {
380
892
  _showTyping_decorators = [snice.property({ type: Boolean, attribute: 'show-typing' })];
381
893
  _showAvatars_decorators = [snice.property({ type: Boolean, attribute: 'show-avatars' })];
382
894
  _showTimestamps_decorators = [snice.property({ type: Boolean, attribute: 'show-timestamps' })];
895
+ _authorColors_decorators = [snice.property({ type: Object, attribute: false })];
896
+ _colorAuthors_decorators = [snice.property({ type: Boolean, attribute: 'color-authors' })];
897
+ _markdown_decorators = [snice.property({ type: Boolean })];
898
+ _layout_decorators = [snice.property()];
899
+ _editingId_decorators = [snice.property({ attribute: false })];
900
+ _confirmingDeleteId_decorators = [snice.property({ attribute: false })];
383
901
  _messagesArea_decorators = [snice.query('.messages-area')];
384
902
  _inputField_decorators = [snice.query('.input-field')];
903
+ _editField_decorators = [snice.query('.edit-field')];
904
+ _editBox_decorators = [snice.query('.message-edit')];
905
+ _confirmBox_decorators = [snice.query('.message-confirm')];
385
906
  _styles_decorators = [snice.styles()];
386
907
  _init_decorators = [snice.ready()];
908
+ _onSlottedMessagesChanged_decorators = [snice.observe('mutation:childList')];
909
+ _onSlottedMessageAttributesChanged_decorators = [snice.observe('mutation:attributes', { subtree: true })];
387
910
  _cleanup_decorators = [snice.dispose()];
388
911
  _messagesChanged_decorators = [snice.watch('messages')];
389
912
  _emitMessageSend_decorators = [snice.dispatch('message-send', { bubbles: true, composed: true })];
390
913
  _emitMessageEdit_decorators = [snice.dispatch('message-edit', { bubbles: true, composed: true })];
391
914
  _emitMessageDelete_decorators = [snice.dispatch('message-delete', { bubbles: true, composed: true })];
392
915
  _emitMessageReact_decorators = [snice.dispatch('message-react', { bubbles: true, composed: true })];
393
- _emitMessageThread_decorators = [snice.dispatch('message-thread', { bubbles: true, composed: true })];
394
916
  _emitTypingStart_decorators = [snice.dispatch('typing-start', { bubbles: true, composed: true })];
395
917
  _emitTypingStop_decorators = [snice.dispatch('typing-stop', { bubbles: true, composed: true })];
918
+ _focusEditField_decorators = [snice.watch('editingId')];
919
+ _revealDeleteConfirm_decorators = [snice.watch('confirmingDeleteId')];
396
920
  _render_decorators = [snice.render()];
397
921
  __esDecorate(this, null, _styles_decorators, { kind: "method", name: "styles", static: false, private: false, access: { has: obj => "styles" in obj, get: obj => obj.styles }, metadata: _metadata }, null, _instanceExtraInitializers);
398
922
  __esDecorate(this, null, _init_decorators, { kind: "method", name: "init", static: false, private: false, access: { has: obj => "init" in obj, get: obj => obj.init }, metadata: _metadata }, null, _instanceExtraInitializers);
923
+ __esDecorate(this, null, _onSlottedMessagesChanged_decorators, { kind: "method", name: "onSlottedMessagesChanged", static: false, private: false, access: { has: obj => "onSlottedMessagesChanged" in obj, get: obj => obj.onSlottedMessagesChanged }, metadata: _metadata }, null, _instanceExtraInitializers);
924
+ __esDecorate(this, null, _onSlottedMessageAttributesChanged_decorators, { kind: "method", name: "onSlottedMessageAttributesChanged", static: false, private: false, access: { has: obj => "onSlottedMessageAttributesChanged" in obj, get: obj => obj.onSlottedMessageAttributesChanged }, metadata: _metadata }, null, _instanceExtraInitializers);
399
925
  __esDecorate(this, null, _cleanup_decorators, { kind: "method", name: "cleanup", static: false, private: false, access: { has: obj => "cleanup" in obj, get: obj => obj.cleanup }, metadata: _metadata }, null, _instanceExtraInitializers);
400
926
  __esDecorate(this, null, _messagesChanged_decorators, { kind: "method", name: "messagesChanged", static: false, private: false, access: { has: obj => "messagesChanged" in obj, get: obj => obj.messagesChanged }, metadata: _metadata }, null, _instanceExtraInitializers);
401
927
  __esDecorate(this, null, _emitMessageSend_decorators, { kind: "method", name: "emitMessageSend", static: false, private: false, access: { has: obj => "emitMessageSend" in obj, get: obj => obj.emitMessageSend }, metadata: _metadata }, null, _instanceExtraInitializers);
402
928
  __esDecorate(this, null, _emitMessageEdit_decorators, { kind: "method", name: "emitMessageEdit", static: false, private: false, access: { has: obj => "emitMessageEdit" in obj, get: obj => obj.emitMessageEdit }, metadata: _metadata }, null, _instanceExtraInitializers);
403
929
  __esDecorate(this, null, _emitMessageDelete_decorators, { kind: "method", name: "emitMessageDelete", static: false, private: false, access: { has: obj => "emitMessageDelete" in obj, get: obj => obj.emitMessageDelete }, metadata: _metadata }, null, _instanceExtraInitializers);
404
930
  __esDecorate(this, null, _emitMessageReact_decorators, { kind: "method", name: "emitMessageReact", static: false, private: false, access: { has: obj => "emitMessageReact" in obj, get: obj => obj.emitMessageReact }, metadata: _metadata }, null, _instanceExtraInitializers);
405
- __esDecorate(this, null, _emitMessageThread_decorators, { kind: "method", name: "emitMessageThread", static: false, private: false, access: { has: obj => "emitMessageThread" in obj, get: obj => obj.emitMessageThread }, metadata: _metadata }, null, _instanceExtraInitializers);
406
931
  __esDecorate(this, null, _emitTypingStart_decorators, { kind: "method", name: "emitTypingStart", static: false, private: false, access: { has: obj => "emitTypingStart" in obj, get: obj => obj.emitTypingStart }, metadata: _metadata }, null, _instanceExtraInitializers);
407
932
  __esDecorate(this, null, _emitTypingStop_decorators, { kind: "method", name: "emitTypingStop", static: false, private: false, access: { has: obj => "emitTypingStop" in obj, get: obj => obj.emitTypingStop }, metadata: _metadata }, null, _instanceExtraInitializers);
933
+ __esDecorate(this, null, _focusEditField_decorators, { kind: "method", name: "focusEditField", static: false, private: false, access: { has: obj => "focusEditField" in obj, get: obj => obj.focusEditField }, metadata: _metadata }, null, _instanceExtraInitializers);
934
+ __esDecorate(this, null, _revealDeleteConfirm_decorators, { kind: "method", name: "revealDeleteConfirm", static: false, private: false, access: { has: obj => "revealDeleteConfirm" in obj, get: obj => obj.revealDeleteConfirm }, metadata: _metadata }, null, _instanceExtraInitializers);
408
935
  __esDecorate(this, null, _render_decorators, { kind: "method", name: "render", static: false, private: false, access: { has: obj => "render" in obj, get: obj => obj.render }, metadata: _metadata }, null, _instanceExtraInitializers);
409
936
  __esDecorate(null, null, _messages_decorators, { kind: "field", name: "messages", static: false, private: false, access: { has: obj => "messages" in obj, get: obj => obj.messages, set: (obj, value) => { obj.messages = value; } }, metadata: _metadata }, _messages_initializers, _messages_extraInitializers);
410
937
  __esDecorate(null, null, _currentUser_decorators, { kind: "field", name: "currentUser", static: false, private: false, access: { has: obj => "currentUser" in obj, get: obj => obj.currentUser, set: (obj, value) => { obj.currentUser = value; } }, metadata: _metadata }, _currentUser_initializers, _currentUser_extraInitializers);
@@ -414,8 +941,17 @@ var SniceChat = (function (exports, snice) {
414
941
  __esDecorate(null, null, _showTyping_decorators, { kind: "field", name: "showTyping", static: false, private: false, access: { has: obj => "showTyping" in obj, get: obj => obj.showTyping, set: (obj, value) => { obj.showTyping = value; } }, metadata: _metadata }, _showTyping_initializers, _showTyping_extraInitializers);
415
942
  __esDecorate(null, null, _showAvatars_decorators, { kind: "field", name: "showAvatars", static: false, private: false, access: { has: obj => "showAvatars" in obj, get: obj => obj.showAvatars, set: (obj, value) => { obj.showAvatars = value; } }, metadata: _metadata }, _showAvatars_initializers, _showAvatars_extraInitializers);
416
943
  __esDecorate(null, null, _showTimestamps_decorators, { kind: "field", name: "showTimestamps", static: false, private: false, access: { has: obj => "showTimestamps" in obj, get: obj => obj.showTimestamps, set: (obj, value) => { obj.showTimestamps = value; } }, metadata: _metadata }, _showTimestamps_initializers, _showTimestamps_extraInitializers);
944
+ __esDecorate(null, null, _authorColors_decorators, { kind: "field", name: "authorColors", static: false, private: false, access: { has: obj => "authorColors" in obj, get: obj => obj.authorColors, set: (obj, value) => { obj.authorColors = value; } }, metadata: _metadata }, _authorColors_initializers, _authorColors_extraInitializers);
945
+ __esDecorate(null, null, _colorAuthors_decorators, { kind: "field", name: "colorAuthors", static: false, private: false, access: { has: obj => "colorAuthors" in obj, get: obj => obj.colorAuthors, set: (obj, value) => { obj.colorAuthors = value; } }, metadata: _metadata }, _colorAuthors_initializers, _colorAuthors_extraInitializers);
946
+ __esDecorate(null, null, _markdown_decorators, { kind: "field", name: "markdown", static: false, private: false, access: { has: obj => "markdown" in obj, get: obj => obj.markdown, set: (obj, value) => { obj.markdown = value; } }, metadata: _metadata }, _markdown_initializers, _markdown_extraInitializers);
947
+ __esDecorate(null, null, _layout_decorators, { kind: "field", name: "layout", static: false, private: false, access: { has: obj => "layout" in obj, get: obj => obj.layout, set: (obj, value) => { obj.layout = value; } }, metadata: _metadata }, _layout_initializers, _layout_extraInitializers);
948
+ __esDecorate(null, null, _editingId_decorators, { kind: "field", name: "editingId", static: false, private: false, access: { has: obj => "editingId" in obj, get: obj => obj.editingId, set: (obj, value) => { obj.editingId = value; } }, metadata: _metadata }, _editingId_initializers, _editingId_extraInitializers);
949
+ __esDecorate(null, null, _confirmingDeleteId_decorators, { kind: "field", name: "confirmingDeleteId", static: false, private: false, access: { has: obj => "confirmingDeleteId" in obj, get: obj => obj.confirmingDeleteId, set: (obj, value) => { obj.confirmingDeleteId = value; } }, metadata: _metadata }, _confirmingDeleteId_initializers, _confirmingDeleteId_extraInitializers);
417
950
  __esDecorate(null, null, _messagesArea_decorators, { kind: "field", name: "messagesArea", static: false, private: false, access: { has: obj => "messagesArea" in obj, get: obj => obj.messagesArea, set: (obj, value) => { obj.messagesArea = value; } }, metadata: _metadata }, _messagesArea_initializers, _messagesArea_extraInitializers);
418
951
  __esDecorate(null, null, _inputField_decorators, { kind: "field", name: "inputField", static: false, private: false, access: { has: obj => "inputField" in obj, get: obj => obj.inputField, set: (obj, value) => { obj.inputField = value; } }, metadata: _metadata }, _inputField_initializers, _inputField_extraInitializers);
952
+ __esDecorate(null, null, _editField_decorators, { kind: "field", name: "editField", static: false, private: false, access: { has: obj => "editField" in obj, get: obj => obj.editField, set: (obj, value) => { obj.editField = value; } }, metadata: _metadata }, _editField_initializers, _editField_extraInitializers);
953
+ __esDecorate(null, null, _editBox_decorators, { kind: "field", name: "editBox", static: false, private: false, access: { has: obj => "editBox" in obj, get: obj => obj.editBox, set: (obj, value) => { obj.editBox = value; } }, metadata: _metadata }, _editBox_initializers, _editBox_extraInitializers);
954
+ __esDecorate(null, null, _confirmBox_decorators, { kind: "field", name: "confirmBox", static: false, private: false, access: { has: obj => "confirmBox" in obj, get: obj => obj.confirmBox, set: (obj, value) => { obj.confirmBox = value; } }, metadata: _metadata }, _confirmBox_initializers, _confirmBox_extraInitializers);
419
955
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
420
956
  _classThis = _classDescriptor.value;
421
957
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -426,6 +962,50 @@ var SniceChat = (function (exports, snice) {
426
962
  }
427
963
  init() {
428
964
  this.addEventListener('keydown', this.handleKeyDown);
965
+ this.ingestSlottedMessages();
966
+ }
967
+ // Declarative dual-API: read slotted <snice-chat-message> children as the
968
+ // messages source. An empty slot leaves the array untouched. Mirrors
969
+ // snice-table / snice-column. Slotted messages keep a stable id across
970
+ // re-ingests (keyed per element), runtime state (reactions, inline edits)
971
+ // survives, and imperatively-added messages are appended after the slot set.
972
+ onSlottedMessagesChanged() {
973
+ this.ingestSlottedMessages();
974
+ }
975
+ onSlottedMessageAttributesChanged() {
976
+ this.ingestSlottedMessages();
977
+ }
978
+ ingestSlottedMessages() {
979
+ const els = Array.from(this.querySelectorAll('snice-chat-message'));
980
+ if (els.length === 0)
981
+ return;
982
+ const existingById = new Map(this.messages.map((m) => [m.id, m]));
983
+ const slotMessages = els.map((el) => {
984
+ let id = this.slotMessageIds.get(el);
985
+ if (!id) {
986
+ id = generateId();
987
+ this.slotMessageIds.set(el, id);
988
+ this.mintedSlotIds.add(id);
989
+ }
990
+ const definition = { ...el.getMessageDefinition(), id };
991
+ const existing = existingById.get(id);
992
+ if (!existing)
993
+ return definition;
994
+ // Runtime state outranks the (possibly stale) light DOM: keep reactions
995
+ // accumulated via the UI unless the element declares its own, and keep
996
+ // an inline edit's content over the original slotted text.
997
+ if (!definition.reactions && existing.reactions)
998
+ definition.reactions = existing.reactions;
999
+ if (existing.edited && !definition.edited) {
1000
+ definition.content = existing.content;
1001
+ definition.edited = true;
1002
+ }
1003
+ return definition;
1004
+ });
1005
+ // Imperatively-added messages (addMessage) are not backed by an element;
1006
+ // keep them, appended after the slot set.
1007
+ const imperative = this.messages.filter((m) => !this.mintedSlotIds.has(m.id));
1008
+ this.messages = [...slotMessages, ...imperative];
429
1009
  }
430
1010
  cleanup() {
431
1011
  this.removeEventListener('keydown', this.handleKeyDown);
@@ -433,9 +1013,13 @@ var SniceChat = (function (exports, snice) {
433
1013
  clearTimeout(this.typingTimeout);
434
1014
  }
435
1015
  }
436
- messagesChanged() {
437
- // Scroll to bottom when new message added
438
- setTimeout(() => this.scrollToBottom(), 0);
1016
+ messagesChanged(oldMessages, newMessages) {
1017
+ // Scroll to bottom only when a message was appended — reactions and edits
1018
+ // reassign the array too, and must not yank the viewport while the user
1019
+ // is scrolled up reading history.
1020
+ if ((newMessages?.length ?? 0) > (oldMessages?.length ?? 0)) {
1021
+ setTimeout(() => this.scrollToBottom(), 0);
1022
+ }
439
1023
  }
440
1024
  emitMessageSend(message, attachments) {
441
1025
  return { message, attachments };
@@ -449,9 +1033,6 @@ var SniceChat = (function (exports, snice) {
449
1033
  emitMessageReact(messageId, emoji) {
450
1034
  return { messageId, emoji };
451
1035
  }
452
- emitMessageThread(messageId) {
453
- return { messageId };
454
- }
455
1036
  emitTypingStart() {
456
1037
  return {};
457
1038
  }
@@ -566,26 +1147,95 @@ var SniceChat = (function (exports, snice) {
566
1147
  this.inputField.style.height = 'auto';
567
1148
  this.inputField.style.height = `${Math.min(this.inputField.scrollHeight, 150)}px`;
568
1149
  }
1150
+ // Reactions are social: anyone can react to any message. Toggle the current
1151
+ // user on/off the emoji, update the local model, and emit for a backend.
569
1152
  handleReaction(messageId, emoji) {
1153
+ const me = this.currentUser;
1154
+ this.messages = this.messages.map((m) => {
1155
+ if (m.id !== messageId)
1156
+ return m;
1157
+ const reactions = [...(m.reactions ?? [])];
1158
+ const i = reactions.findIndex((r) => r.emoji === emoji);
1159
+ if (i === -1) {
1160
+ reactions.push({ emoji, count: 1, users: [me] });
1161
+ }
1162
+ else {
1163
+ const r = reactions[i];
1164
+ const removing = r.users.includes(me);
1165
+ const users = removing ? r.users.filter((u) => u !== me) : [...r.users, me];
1166
+ // Adjust by ±1 — never recompute from users.length, which destroys
1167
+ // server counts backed by truncated user lists (count 128, users [2]).
1168
+ const count = Math.max(users.length, r.count + (removing ? -1 : 1));
1169
+ if (count === 0)
1170
+ reactions.splice(i, 1);
1171
+ else
1172
+ reactions[i] = { ...r, count, users };
1173
+ }
1174
+ return { ...m, reactions };
1175
+ });
570
1176
  this.emitMessageReact(messageId, emoji);
571
1177
  }
572
- handleEdit(messageId) {
1178
+ // Edit is inline: clicking edit swaps the body for a textarea. Owner-only.
1179
+ // Inline modes are exclusive: opening one closes the other.
1180
+ startEdit(messageId) {
1181
+ this.confirmingDeleteId = null;
1182
+ this.editingId = messageId;
1183
+ }
1184
+ cancelEdit() {
1185
+ this.editingId = null;
1186
+ }
1187
+ commitEdit(messageId) {
1188
+ const next = (this.editField?.value ?? '').trim();
573
1189
  const message = this.messages.find((m) => m.id === messageId);
574
- if (!message)
1190
+ this.editingId = null;
1191
+ if (!message || !next || next === message.content)
575
1192
  return;
576
- // Simple prompt for now - in a real app, this would be inline editing
577
- const newContent = prompt('Edit message:', message.content);
578
- if (newContent && newContent !== message.content) {
579
- this.emitMessageEdit(messageId, newContent);
1193
+ this.updateMessage(messageId, { content: next, edited: true });
1194
+ this.emitMessageEdit(messageId, next);
1195
+ }
1196
+ handleEditKeydown(e, messageId) {
1197
+ if (e.key === 'Enter' && !e.shiftKey) {
1198
+ e.preventDefault();
1199
+ this.commitEdit(messageId);
580
1200
  }
1201
+ else if (e.key === 'Escape') {
1202
+ e.preventDefault();
1203
+ this.cancelEdit();
1204
+ }
1205
+ }
1206
+ focusEditField() {
1207
+ if (this.editingId === null)
1208
+ return;
1209
+ // Watchers run before the re-render is even scheduled (renders flush on
1210
+ // a microtask), so defer to a frame where the editor exists.
1211
+ requestAnimationFrame(() => {
1212
+ this.editField?.focus();
1213
+ // The editor is taller than the message body it replaces; on the last
1214
+ // message its Save/Cancel row would clip below the scroll area.
1215
+ this.editBox?.scrollIntoView({ block: 'nearest' });
1216
+ });
581
1217
  }
1218
+ // Delete asks for inline confirmation (not a native confirm dialog).
1219
+ // Owner-only. On confirm, updates the local model and emits for a backend.
1220
+ // Inline modes are exclusive: opening one closes the other.
582
1221
  handleDelete(messageId) {
583
- if (confirm('Delete this message?')) {
584
- this.emitMessageDelete(messageId);
585
- }
1222
+ this.editingId = null;
1223
+ this.confirmingDeleteId = messageId;
1224
+ }
1225
+ revealDeleteConfirm() {
1226
+ if (this.confirmingDeleteId === null)
1227
+ return;
1228
+ // Same clipping problem as the inline editor: the confirm row extends
1229
+ // the last message past the bottom of the scroll area.
1230
+ requestAnimationFrame(() => this.confirmBox?.scrollIntoView({ block: 'nearest' }));
1231
+ }
1232
+ confirmDelete(messageId) {
1233
+ this.confirmingDeleteId = null;
1234
+ this.deleteMessage(messageId);
1235
+ this.emitMessageDelete(messageId);
586
1236
  }
587
- handleThread(messageId) {
588
- this.emitMessageThread(messageId);
1237
+ cancelDelete() {
1238
+ this.confirmingDeleteId = null;
589
1239
  }
590
1240
  render() {
591
1241
  return snice.html /*html*/ `
@@ -612,23 +1262,58 @@ var SniceChat = (function (exports, snice) {
612
1262
  </div>
613
1263
  `;
614
1264
  }
1265
+ // Per-message author color. Precedence: per-message override → authorColors
1266
+ // map → auto (only when color-authors is set) → none (falls through to the
1267
+ // default token in CSS). Computed per element instance — no global registry.
1268
+ resolveAuthorColor(message) {
1269
+ if (message.authorColor && isSafeCssColor(message.authorColor))
1270
+ return message.authorColor;
1271
+ const mapped = this.authorColors[message.author];
1272
+ if (mapped && isSafeCssColor(mapped))
1273
+ return mapped;
1274
+ if (this.colorAuthors)
1275
+ return autoAuthorColor(message.author);
1276
+ return '';
1277
+ }
1278
+ // Markdown is opt-in: per-message format='markdown', or the component-wide
1279
+ // `markdown` attribute (which a per-message format='text' can override).
1280
+ shouldRenderMarkdown(message) {
1281
+ if (message.format === MessageFormat.Markdown)
1282
+ return true;
1283
+ if (this.markdown && message.format !== MessageFormat.Text)
1284
+ return true;
1285
+ return false;
1286
+ }
1287
+ renderMessageBody(message) {
1288
+ if (this.shouldRenderMarkdown(message)) {
1289
+ return snice.html /*html*/ `<snice-markdown part="message-text" class="message-text" .content=${message.content}></snice-markdown>`;
1290
+ }
1291
+ return snice.html /*html*/ `<div part="message-text" class="message-text">${message.content}</div>`;
1292
+ }
615
1293
  renderMessage(message) {
616
1294
  const isSystem = message.type === 'system';
617
1295
  const isCurrentUser = message.author === this.currentUser;
618
1296
  if (isSystem) {
619
1297
  return snice.html /*html*/ `
620
- <div class="message system" data-message-id="${message.id}">
1298
+ <div part="message system-message" class="message system" data-message-id="${message.id}">
621
1299
  <div class="message-content">
622
- <div class="message-text">${message.content}</div>
1300
+ <div part="message-text" class="message-text">${message.content}</div>
623
1301
  </div>
624
1302
  </div>
625
1303
  `;
626
1304
  }
1305
+ const ownClass = isCurrentUser ? 'own' : 'other';
1306
+ const ownPart = isCurrentUser ? 'message-own' : 'message-other';
1307
+ const authorColor = this.resolveAuthorColor(message);
1308
+ const authorStyle = authorColor ? `--snice-chat-author-color:${authorColor}` : '';
1309
+ const isEditing = this.editingId === message.id;
1310
+ const isConfirmingDelete = this.confirmingDeleteId === message.id;
1311
+ const hasReactions = !!message.reactions && message.reactions.length > 0;
627
1312
  return snice.html /*html*/ `
628
- <div class="message" data-message-id="${message.id}">
1313
+ <div part="message ${ownPart}" class="message ${ownClass}" data-message-id="${message.id}">
629
1314
  ${this.showAvatars
630
1315
  ? snice.html `
631
- <div class="message-avatar">
1316
+ <div part="avatar" class="message-avatar">
632
1317
  ${message.avatar
633
1318
  ? snice.html `<img src="${message.avatar}" alt="${message.author}" />`
634
1319
  : getInitials(message.author)}
@@ -637,55 +1322,70 @@ var SniceChat = (function (exports, snice) {
637
1322
  : ''}
638
1323
  <div class="message-content">
639
1324
  <div class="message-header">
640
- <span class="message-author">${message.author}</span>
1325
+ <span part="author" class="message-author" style="${authorStyle}">${message.author}</span>
641
1326
  ${this.showTimestamps
642
- ? snice.html `<span class="message-timestamp">${formatTime(message.timestamp)}</span>`
1327
+ ? snice.html `<span part="timestamp" class="message-timestamp">${formatTime(message.timestamp)}</span>`
643
1328
  : ''}
644
- ${message.edited ? snice.html `<span class="message-edited">(edited)</span>` : ''}
1329
+ ${message.edited ? snice.html `<span part="edited" class="message-edited">(edited)</span>` : ''}
645
1330
  </div>
646
- ${message.content ? snice.html `<div class="message-text">${message.content}</div>` : ''}
1331
+ ${isEditing
1332
+ ? this.renderEditor(message)
1333
+ : message.content ? this.renderMessageBody(message) : ''}
647
1334
  ${message.attachment ? this.renderAttachment(message.attachment) : ''}
648
- ${message.reactions && message.reactions.length > 0
649
- ? this.renderReactions(message.id, message.reactions, isCurrentUser)
650
- : ''}
1335
+ ${hasReactions ? this.renderReactions(message.id, message.reactions) : ''}
1336
+ ${isConfirmingDelete ? this.renderDeleteConfirm(message) : ''}
1337
+ </div>
1338
+ ${isEditing || isConfirmingDelete ? '' : this.renderActions(message.id, isCurrentUser)}
1339
+ </div>
1340
+ `;
1341
+ }
1342
+ // Inline message editor — replaces the body while editing. Enter saves,
1343
+ // Shift+Enter newlines, Esc cancels.
1344
+ renderEditor(message) {
1345
+ return snice.html /*html*/ `
1346
+ <div class="message-edit">
1347
+ <textarea
1348
+ part="edit-input"
1349
+ class="edit-field"
1350
+ .value=${message.content}
1351
+ @keydown=${(e) => this.handleEditKeydown(e, message.id)}
1352
+ ></textarea>
1353
+ <div class="edit-actions">
1354
+ <button part="edit-save" class="edit-button edit-save" @click=${() => this.commitEdit(message.id)}>Save</button>
1355
+ <button part="edit-cancel" class="edit-button" @click=${() => this.cancelEdit()}>Cancel</button>
651
1356
  </div>
1357
+ </div>
1358
+ `;
1359
+ }
1360
+ // Inline delete confirmation — replaces the hover actions while pending, so
1361
+ // a misclick can't destroy a message. Confirm deletes + emits; Cancel aborts.
1362
+ renderDeleteConfirm(message) {
1363
+ return snice.html /*html*/ `
1364
+ <div part="delete-confirm" class="message-confirm">
1365
+ <span class="confirm-text">Delete this message?</span>
1366
+ <div class="confirm-actions">
1367
+ <button part="delete-confirm-yes" class="confirm-button confirm-delete" @click=${() => this.confirmDelete(message.id)}>Delete</button>
1368
+ <button part="delete-confirm-no" class="confirm-button" @click=${() => this.cancelDelete()}>Cancel</button>
1369
+ </div>
1370
+ </div>
1371
+ `;
1372
+ }
1373
+ // Hover action menu. React is available on every message (you react to
1374
+ // others, not just yourself); edit and delete are owner-only.
1375
+ renderActions(messageId, isCurrentUser) {
1376
+ return snice.html /*html*/ `
1377
+ <div part="actions" class="message-actions">
1378
+ <button class="action-button" @click=${() => this.handleReaction(messageId, '👍')} title="React" aria-label="React">
1379
+ <span class="action-emoji" aria-hidden="true">🙂</span>
1380
+ </button>
652
1381
  ${isCurrentUser
653
1382
  ? snice.html `
654
- <div class="message-actions">
655
- <button
656
- class="action-button"
657
- @click="${() => this.handleReaction(message.id, '👍')}"
658
- title="React"
659
- >
660
- <svg viewBox="0 0 16 16" fill="currentColor">
661
- <path
662
- d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zM5.5 7.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm5 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM8 11c1.5 0 2.7-1 3.2-2H4.8c.5 1 1.7 2 3.2 2z"
663
- />
664
- </svg>
665
- </button>
666
- <button
667
- class="action-button"
668
- @click="${() => this.handleEdit(message.id)}"
669
- title="Edit"
670
- >
671
- <svg viewBox="0 0 16 16" fill="currentColor">
672
- <path
673
- d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25a1.75 1.75 0 0 1 .445-.758l8.61-8.61z"
674
- />
675
- </svg>
676
- </button>
677
- <button
678
- class="action-button"
679
- @click="${() => this.handleDelete(message.id)}"
680
- title="Delete"
681
- >
682
- <svg viewBox="0 0 16 16" fill="currentColor">
683
- <path
684
- d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75zM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15z"
685
- />
686
- </svg>
687
- </button>
688
- </div>
1383
+ <button class="action-button" @click=${() => this.startEdit(messageId)} title="Edit" aria-label="Edit message">
1384
+ ${snice.unsafeHTML(PENCIL)}
1385
+ </button>
1386
+ <button class="action-button" @click=${() => this.handleDelete(messageId)} title="Delete" aria-label="Delete message">
1387
+ ${snice.unsafeHTML(TRASH)}
1388
+ </button>
689
1389
  `
690
1390
  : ''}
691
1391
  </div>
@@ -696,13 +1396,13 @@ var SniceChat = (function (exports, snice) {
696
1396
  return '';
697
1397
  if (attachment.type === 'image') {
698
1398
  return snice.html /*html*/ `
699
- <div class="message-attachment">
1399
+ <div part="attachment" class="message-attachment">
700
1400
  <img src="${attachment.url}" alt="${attachment.name}" />
701
1401
  </div>
702
1402
  `;
703
1403
  }
704
1404
  return snice.html /*html*/ `
705
- <div class="message-attachment">
1405
+ <div part="attachment" class="message-attachment">
706
1406
  <div class="attachment-file">
707
1407
  <div class="attachment-icon">
708
1408
  <svg viewBox="0 0 16 16" fill="currentColor">
@@ -721,20 +1421,24 @@ var SniceChat = (function (exports, snice) {
721
1421
  </div>
722
1422
  `;
723
1423
  }
724
- renderReactions(messageId, reactions, isCurrentUser) {
1424
+ renderReactions(messageId, reactions) {
725
1425
  if (!reactions || reactions.length === 0)
726
1426
  return '';
727
1427
  return snice.html /*html*/ `
728
- <div class="message-reactions">
729
- ${reactions.map((reaction) => snice.html `
1428
+ <div part="reactions" class="message-reactions">
1429
+ ${reactions.map((reaction) => {
1430
+ const isActive = reaction.users.includes(this.currentUser);
1431
+ return snice.html `
730
1432
  <div
731
- class="reaction ${reaction.users.includes(this.currentUser) ? 'active' : ''}"
1433
+ part="reaction ${isActive ? 'reaction-active' : ''}"
1434
+ class="reaction ${isActive ? 'active' : ''}"
732
1435
  @click="${() => this.handleReaction(messageId, reaction.emoji)}"
733
1436
  >
734
1437
  <span class="reaction-emoji">${reaction.emoji}</span>
735
1438
  <span class="reaction-count">${reaction.count}</span>
736
1439
  </div>
737
- `)}
1440
+ `;
1441
+ })}
738
1442
  </div>
739
1443
  `;
740
1444
  }
@@ -744,7 +1448,7 @@ var SniceChat = (function (exports, snice) {
744
1448
  return '';
745
1449
  return snice.html /*html*/ `
746
1450
  <div class="typing-indicators">
747
- <div class="typing-indicator">
1451
+ <div part="typing-indicator" class="typing-indicator">
748
1452
  <span>${users.map((u) => u.user).join(', ')} ${users.length === 1 ? 'is' : 'are'} typing</span>
749
1453
  <div class="typing-dots">
750
1454
  <div class="typing-dot"></div>
@@ -775,20 +1479,12 @@ var SniceChat = (function (exports, snice) {
775
1479
  @click="${() => this.handleFileClick()}"
776
1480
  title="Attach file"
777
1481
  >
778
- <svg viewBox="0 0 16 16" fill="currentColor">
779
- <path
780
- d="M11.28 6.22a.75.75 0 0 0-1.06 0L7.25 9.19 5.78 7.72a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5a.75.75 0 0 0 0-1.06zM16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0z"
781
- />
782
- </svg>
1482
+ ${snice.unsafeHTML(PAPER_CLIP)}
783
1483
  </button>
784
1484
  `
785
1485
  : ''}
786
1486
  <button class="input-button send" @click="${() => this.sendMessage()}" title="Send">
787
- <svg viewBox="0 0 16 16" fill="currentColor">
788
- <path
789
- d="M1.724 2.016a.75.75 0 0 1 1.048-.964l12.5 7a.75.75 0 0 1 0 1.292l-12.5 7a.75.75 0 0 1-1.048-.964l1.5-6.5a.75.75 0 0 1 .584-.584l5.916-1.188-5.916-1.188a.75.75 0 0 1-.584-.584l-1.5-6.5z"
790
- />
791
- </svg>
1487
+ ${snice.unsafeHTML(PAPER_AIRPLANE_SOLID)}
792
1488
  </button>
793
1489
  </div>
794
1490
  </div>