snice 5.2.3 → 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,9 +1,32 @@
1
1
  import { __runInitializers, __esDecorate } from 'tslib';
2
- import { element, property, query, styles, ready, dispose, watch, dispatch, render, css, html } from 'snice';
2
+ import { element, property, query, styles, ready, observe, dispose, watch, dispatch, render, css, html, unsafeHTML } from 'snice';
3
+ import { PENCIL, TRASH, PAPER_CLIP, PAPER_AIRPLANE_SOLID } from '../icons/index.js';
4
+ import { FALLBACK_ACCENTS } from '../utils.js';
3
5
  import '../empty-state/snice-empty-state.js';
4
- import '../utils.js';
6
+ import '../markdown/snice-markdown.js';
7
+ import './snice-chat-message.js';
5
8
 
6
- 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}";
9
+ /**
10
+ * Types for the snice-chat component
11
+ */
12
+ /**
13
+ * How a message body is rendered
14
+ */
15
+ var MessageFormat;
16
+ (function (MessageFormat) {
17
+ MessageFormat["Text"] = "text";
18
+ MessageFormat["Markdown"] = "markdown";
19
+ })(MessageFormat || (MessageFormat = {}));
20
+ /**
21
+ * Built-in message layout for snice-chat
22
+ */
23
+ var ChatLayout;
24
+ (function (ChatLayout) {
25
+ ChatLayout["Default"] = "default";
26
+ ChatLayout["Bubbles"] = "bubbles";
27
+ })(ChatLayout || (ChatLayout = {}));
28
+
29
+ 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))}";
7
30
 
8
31
  /**
9
32
  * Generate unique ID
@@ -41,6 +64,26 @@ function getInitials(name) {
41
64
  .toUpperCase()
42
65
  .substring(0, 2);
43
66
  }
67
+ /**
68
+ * Stable color for an author name: hash → one of the 8 accent slots. Returns a
69
+ * theme accent var with the shared concrete fallback.
70
+ */
71
+ function autoAuthorColor(name) {
72
+ let hash = 0;
73
+ for (let i = 0; i < name.length; i++) {
74
+ hash = (hash * 31 + name.charCodeAt(i)) >>> 0;
75
+ }
76
+ const slot = (hash % 8) + 1;
77
+ return `var(--snice-color-accent-${slot}, ${FALLBACK_ACCENTS[slot - 1]})`;
78
+ }
79
+ /**
80
+ * Author colors ride on message data, so they can come from a backend. A CSS
81
+ * color never needs `;`, `{`, or `}` — reject values that could smuggle extra
82
+ * declarations into the inline style attribute.
83
+ */
84
+ function isSafeCssColor(value) {
85
+ return !/[;{}]/.test(value);
86
+ }
44
87
  /**
45
88
  * snice-chat - Chat interface component
46
89
  *
@@ -52,7 +95,6 @@ function getInitials(name) {
52
95
  * @fires {CustomEvent<{ messageId: string; newContent: string }>} message-edit - Fires when editing a message
53
96
  * @fires {CustomEvent<{ messageId: string }>} message-delete - Fires when deleting a message
54
97
  * @fires {CustomEvent<{ messageId: string; emoji: string }>} message-react - Fires when reacting to a message
55
- * @fires {CustomEvent<{ messageId: string }>} message-thread - Fires when starting a thread
56
98
  * @fires {CustomEvent<{}>} typing-start - Fires when user starts typing
57
99
  * @fires {CustomEvent<{}>} typing-stop - Fires when user stops typing
58
100
  */
@@ -87,23 +129,53 @@ let SniceChat = (() => {
87
129
  let _showTimestamps_decorators;
88
130
  let _showTimestamps_initializers = [];
89
131
  let _showTimestamps_extraInitializers = [];
132
+ let _authorColors_decorators;
133
+ let _authorColors_initializers = [];
134
+ let _authorColors_extraInitializers = [];
135
+ let _colorAuthors_decorators;
136
+ let _colorAuthors_initializers = [];
137
+ let _colorAuthors_extraInitializers = [];
138
+ let _markdown_decorators;
139
+ let _markdown_initializers = [];
140
+ let _markdown_extraInitializers = [];
141
+ let _layout_decorators;
142
+ let _layout_initializers = [];
143
+ let _layout_extraInitializers = [];
144
+ let _editingId_decorators;
145
+ let _editingId_initializers = [];
146
+ let _editingId_extraInitializers = [];
147
+ let _confirmingDeleteId_decorators;
148
+ let _confirmingDeleteId_initializers = [];
149
+ let _confirmingDeleteId_extraInitializers = [];
90
150
  let _messagesArea_decorators;
91
151
  let _messagesArea_initializers = [];
92
152
  let _messagesArea_extraInitializers = [];
93
153
  let _inputField_decorators;
94
154
  let _inputField_initializers = [];
95
155
  let _inputField_extraInitializers = [];
156
+ let _editField_decorators;
157
+ let _editField_initializers = [];
158
+ let _editField_extraInitializers = [];
159
+ let _editBox_decorators;
160
+ let _editBox_initializers = [];
161
+ let _editBox_extraInitializers = [];
162
+ let _confirmBox_decorators;
163
+ let _confirmBox_initializers = [];
164
+ let _confirmBox_extraInitializers = [];
96
165
  let _styles_decorators;
97
166
  let _init_decorators;
167
+ let _onSlottedMessagesChanged_decorators;
168
+ let _onSlottedMessageAttributesChanged_decorators;
98
169
  let _cleanup_decorators;
99
170
  let _messagesChanged_decorators;
100
171
  let _emitMessageSend_decorators;
101
172
  let _emitMessageEdit_decorators;
102
173
  let _emitMessageDelete_decorators;
103
174
  let _emitMessageReact_decorators;
104
- let _emitMessageThread_decorators;
105
175
  let _emitTypingStart_decorators;
106
176
  let _emitTypingStop_decorators;
177
+ let _focusEditField_decorators;
178
+ let _revealDeleteConfirm_decorators;
107
179
  let _render_decorators;
108
180
  (class extends _classSuper {
109
181
  static { _classThis = this; }
@@ -117,11 +189,28 @@ let SniceChat = (() => {
117
189
  this.showTyping = (__runInitializers(this, _allowFiles_extraInitializers), __runInitializers(this, _showTyping_initializers, true));
118
190
  this.showAvatars = (__runInitializers(this, _showTyping_extraInitializers), __runInitializers(this, _showAvatars_initializers, true));
119
191
  this.showTimestamps = (__runInitializers(this, _showAvatars_extraInitializers), __runInitializers(this, _showTimestamps_initializers, true));
120
- this.messagesArea = (__runInitializers(this, _showTimestamps_extraInitializers), __runInitializers(this, _messagesArea_initializers, void 0));
192
+ this.authorColors = (__runInitializers(this, _showTimestamps_extraInitializers), __runInitializers(this, _authorColors_initializers, {}));
193
+ this.colorAuthors = (__runInitializers(this, _authorColors_extraInitializers), __runInitializers(this, _colorAuthors_initializers, false));
194
+ this.markdown = (__runInitializers(this, _colorAuthors_extraInitializers), __runInitializers(this, _markdown_initializers, false));
195
+ this.layout = (__runInitializers(this, _markdown_extraInitializers), __runInitializers(this, _layout_initializers, ChatLayout.Default));
196
+ // Internal reactive state: id of the message currently being edited inline.
197
+ this.editingId = (__runInitializers(this, _layout_extraInitializers), __runInitializers(this, _editingId_initializers, null));
198
+ // Internal reactive state: id of the message pending inline delete-confirm.
199
+ this.confirmingDeleteId = (__runInitializers(this, _editingId_extraInitializers), __runInitializers(this, _confirmingDeleteId_initializers, null));
200
+ this.messagesArea = (__runInitializers(this, _confirmingDeleteId_extraInitializers), __runInitializers(this, _messagesArea_initializers, void 0));
121
201
  this.inputField = (__runInitializers(this, _messagesArea_extraInitializers), __runInitializers(this, _inputField_initializers, void 0));
122
- this.typingIndicators = (__runInitializers(this, _inputField_extraInitializers), new Map());
202
+ this.editField = (__runInitializers(this, _inputField_extraInitializers), __runInitializers(this, _editField_initializers, void 0));
203
+ this.editBox = (__runInitializers(this, _editField_extraInitializers), __runInitializers(this, _editBox_initializers, void 0));
204
+ this.confirmBox = (__runInitializers(this, _editBox_extraInitializers), __runInitializers(this, _confirmBox_initializers, void 0));
205
+ this.typingIndicators = (__runInitializers(this, _confirmBox_extraInitializers), new Map());
123
206
  this.typingTimeout = null;
124
207
  this.fileInput = null;
208
+ // Element → stable message id, so re-ingesting doesn't mint new ids and
209
+ // orphan reactions/edit state keyed to the old ones.
210
+ this.slotMessageIds = new WeakMap();
211
+ // Every id ever minted for a slot element, so a removed slot child isn't
212
+ // misclassified as an imperative message and resurrected on re-ingest.
213
+ this.mintedSlotIds = new Set();
125
214
  this.handleKeyDown = (e) => {
126
215
  const target = e.target;
127
216
  if (target !== this.inputField)
@@ -142,31 +231,46 @@ let SniceChat = (() => {
142
231
  _showTyping_decorators = [property({ type: Boolean, attribute: 'show-typing' })];
143
232
  _showAvatars_decorators = [property({ type: Boolean, attribute: 'show-avatars' })];
144
233
  _showTimestamps_decorators = [property({ type: Boolean, attribute: 'show-timestamps' })];
234
+ _authorColors_decorators = [property({ type: Object, attribute: false })];
235
+ _colorAuthors_decorators = [property({ type: Boolean, attribute: 'color-authors' })];
236
+ _markdown_decorators = [property({ type: Boolean })];
237
+ _layout_decorators = [property()];
238
+ _editingId_decorators = [property({ attribute: false })];
239
+ _confirmingDeleteId_decorators = [property({ attribute: false })];
145
240
  _messagesArea_decorators = [query('.messages-area')];
146
241
  _inputField_decorators = [query('.input-field')];
242
+ _editField_decorators = [query('.edit-field')];
243
+ _editBox_decorators = [query('.message-edit')];
244
+ _confirmBox_decorators = [query('.message-confirm')];
147
245
  _styles_decorators = [styles()];
148
246
  _init_decorators = [ready()];
247
+ _onSlottedMessagesChanged_decorators = [observe('mutation:childList')];
248
+ _onSlottedMessageAttributesChanged_decorators = [observe('mutation:attributes', { subtree: true })];
149
249
  _cleanup_decorators = [dispose()];
150
250
  _messagesChanged_decorators = [watch('messages')];
151
251
  _emitMessageSend_decorators = [dispatch('message-send', { bubbles: true, composed: true })];
152
252
  _emitMessageEdit_decorators = [dispatch('message-edit', { bubbles: true, composed: true })];
153
253
  _emitMessageDelete_decorators = [dispatch('message-delete', { bubbles: true, composed: true })];
154
254
  _emitMessageReact_decorators = [dispatch('message-react', { bubbles: true, composed: true })];
155
- _emitMessageThread_decorators = [dispatch('message-thread', { bubbles: true, composed: true })];
156
255
  _emitTypingStart_decorators = [dispatch('typing-start', { bubbles: true, composed: true })];
157
256
  _emitTypingStop_decorators = [dispatch('typing-stop', { bubbles: true, composed: true })];
257
+ _focusEditField_decorators = [watch('editingId')];
258
+ _revealDeleteConfirm_decorators = [watch('confirmingDeleteId')];
158
259
  _render_decorators = [render()];
159
260
  __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);
160
261
  __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);
262
+ __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);
263
+ __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);
161
264
  __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);
162
265
  __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);
163
266
  __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);
164
267
  __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);
165
268
  __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);
166
269
  __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);
167
- __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);
168
270
  __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);
169
271
  __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);
272
+ __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);
273
+ __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);
170
274
  __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);
171
275
  __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);
172
276
  __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);
@@ -176,8 +280,17 @@ let SniceChat = (() => {
176
280
  __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);
177
281
  __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);
178
282
  __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);
283
+ __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);
284
+ __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);
285
+ __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);
286
+ __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);
287
+ __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);
288
+ __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);
179
289
  __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);
180
290
  __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);
291
+ __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);
292
+ __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);
293
+ __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);
181
294
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
182
295
  _classThis = _classDescriptor.value;
183
296
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -188,6 +301,50 @@ let SniceChat = (() => {
188
301
  }
189
302
  init() {
190
303
  this.addEventListener('keydown', this.handleKeyDown);
304
+ this.ingestSlottedMessages();
305
+ }
306
+ // Declarative dual-API: read slotted <snice-chat-message> children as the
307
+ // messages source. An empty slot leaves the array untouched. Mirrors
308
+ // snice-table / snice-column. Slotted messages keep a stable id across
309
+ // re-ingests (keyed per element), runtime state (reactions, inline edits)
310
+ // survives, and imperatively-added messages are appended after the slot set.
311
+ onSlottedMessagesChanged() {
312
+ this.ingestSlottedMessages();
313
+ }
314
+ onSlottedMessageAttributesChanged() {
315
+ this.ingestSlottedMessages();
316
+ }
317
+ ingestSlottedMessages() {
318
+ const els = Array.from(this.querySelectorAll('snice-chat-message'));
319
+ if (els.length === 0)
320
+ return;
321
+ const existingById = new Map(this.messages.map((m) => [m.id, m]));
322
+ const slotMessages = els.map((el) => {
323
+ let id = this.slotMessageIds.get(el);
324
+ if (!id) {
325
+ id = generateId();
326
+ this.slotMessageIds.set(el, id);
327
+ this.mintedSlotIds.add(id);
328
+ }
329
+ const definition = { ...el.getMessageDefinition(), id };
330
+ const existing = existingById.get(id);
331
+ if (!existing)
332
+ return definition;
333
+ // Runtime state outranks the (possibly stale) light DOM: keep reactions
334
+ // accumulated via the UI unless the element declares its own, and keep
335
+ // an inline edit's content over the original slotted text.
336
+ if (!definition.reactions && existing.reactions)
337
+ definition.reactions = existing.reactions;
338
+ if (existing.edited && !definition.edited) {
339
+ definition.content = existing.content;
340
+ definition.edited = true;
341
+ }
342
+ return definition;
343
+ });
344
+ // Imperatively-added messages (addMessage) are not backed by an element;
345
+ // keep them, appended after the slot set.
346
+ const imperative = this.messages.filter((m) => !this.mintedSlotIds.has(m.id));
347
+ this.messages = [...slotMessages, ...imperative];
191
348
  }
192
349
  cleanup() {
193
350
  this.removeEventListener('keydown', this.handleKeyDown);
@@ -195,9 +352,13 @@ let SniceChat = (() => {
195
352
  clearTimeout(this.typingTimeout);
196
353
  }
197
354
  }
198
- messagesChanged() {
199
- // Scroll to bottom when new message added
200
- setTimeout(() => this.scrollToBottom(), 0);
355
+ messagesChanged(oldMessages, newMessages) {
356
+ // Scroll to bottom only when a message was appended — reactions and edits
357
+ // reassign the array too, and must not yank the viewport while the user
358
+ // is scrolled up reading history.
359
+ if ((newMessages?.length ?? 0) > (oldMessages?.length ?? 0)) {
360
+ setTimeout(() => this.scrollToBottom(), 0);
361
+ }
201
362
  }
202
363
  emitMessageSend(message, attachments) {
203
364
  return { message, attachments };
@@ -211,9 +372,6 @@ let SniceChat = (() => {
211
372
  emitMessageReact(messageId, emoji) {
212
373
  return { messageId, emoji };
213
374
  }
214
- emitMessageThread(messageId) {
215
- return { messageId };
216
- }
217
375
  emitTypingStart() {
218
376
  return {};
219
377
  }
@@ -328,26 +486,95 @@ let SniceChat = (() => {
328
486
  this.inputField.style.height = 'auto';
329
487
  this.inputField.style.height = `${Math.min(this.inputField.scrollHeight, 150)}px`;
330
488
  }
489
+ // Reactions are social: anyone can react to any message. Toggle the current
490
+ // user on/off the emoji, update the local model, and emit for a backend.
331
491
  handleReaction(messageId, emoji) {
492
+ const me = this.currentUser;
493
+ this.messages = this.messages.map((m) => {
494
+ if (m.id !== messageId)
495
+ return m;
496
+ const reactions = [...(m.reactions ?? [])];
497
+ const i = reactions.findIndex((r) => r.emoji === emoji);
498
+ if (i === -1) {
499
+ reactions.push({ emoji, count: 1, users: [me] });
500
+ }
501
+ else {
502
+ const r = reactions[i];
503
+ const removing = r.users.includes(me);
504
+ const users = removing ? r.users.filter((u) => u !== me) : [...r.users, me];
505
+ // Adjust by ±1 — never recompute from users.length, which destroys
506
+ // server counts backed by truncated user lists (count 128, users [2]).
507
+ const count = Math.max(users.length, r.count + (removing ? -1 : 1));
508
+ if (count === 0)
509
+ reactions.splice(i, 1);
510
+ else
511
+ reactions[i] = { ...r, count, users };
512
+ }
513
+ return { ...m, reactions };
514
+ });
332
515
  this.emitMessageReact(messageId, emoji);
333
516
  }
334
- handleEdit(messageId) {
517
+ // Edit is inline: clicking edit swaps the body for a textarea. Owner-only.
518
+ // Inline modes are exclusive: opening one closes the other.
519
+ startEdit(messageId) {
520
+ this.confirmingDeleteId = null;
521
+ this.editingId = messageId;
522
+ }
523
+ cancelEdit() {
524
+ this.editingId = null;
525
+ }
526
+ commitEdit(messageId) {
527
+ const next = (this.editField?.value ?? '').trim();
335
528
  const message = this.messages.find((m) => m.id === messageId);
336
- if (!message)
529
+ this.editingId = null;
530
+ if (!message || !next || next === message.content)
337
531
  return;
338
- // Simple prompt for now - in a real app, this would be inline editing
339
- const newContent = prompt('Edit message:', message.content);
340
- if (newContent && newContent !== message.content) {
341
- this.emitMessageEdit(messageId, newContent);
532
+ this.updateMessage(messageId, { content: next, edited: true });
533
+ this.emitMessageEdit(messageId, next);
534
+ }
535
+ handleEditKeydown(e, messageId) {
536
+ if (e.key === 'Enter' && !e.shiftKey) {
537
+ e.preventDefault();
538
+ this.commitEdit(messageId);
539
+ }
540
+ else if (e.key === 'Escape') {
541
+ e.preventDefault();
542
+ this.cancelEdit();
342
543
  }
343
544
  }
545
+ focusEditField() {
546
+ if (this.editingId === null)
547
+ return;
548
+ // Watchers run before the re-render is even scheduled (renders flush on
549
+ // a microtask), so defer to a frame where the editor exists.
550
+ requestAnimationFrame(() => {
551
+ this.editField?.focus();
552
+ // The editor is taller than the message body it replaces; on the last
553
+ // message its Save/Cancel row would clip below the scroll area.
554
+ this.editBox?.scrollIntoView({ block: 'nearest' });
555
+ });
556
+ }
557
+ // Delete asks for inline confirmation (not a native confirm dialog).
558
+ // Owner-only. On confirm, updates the local model and emits for a backend.
559
+ // Inline modes are exclusive: opening one closes the other.
344
560
  handleDelete(messageId) {
345
- if (confirm('Delete this message?')) {
346
- this.emitMessageDelete(messageId);
347
- }
561
+ this.editingId = null;
562
+ this.confirmingDeleteId = messageId;
563
+ }
564
+ revealDeleteConfirm() {
565
+ if (this.confirmingDeleteId === null)
566
+ return;
567
+ // Same clipping problem as the inline editor: the confirm row extends
568
+ // the last message past the bottom of the scroll area.
569
+ requestAnimationFrame(() => this.confirmBox?.scrollIntoView({ block: 'nearest' }));
570
+ }
571
+ confirmDelete(messageId) {
572
+ this.confirmingDeleteId = null;
573
+ this.deleteMessage(messageId);
574
+ this.emitMessageDelete(messageId);
348
575
  }
349
- handleThread(messageId) {
350
- this.emitMessageThread(messageId);
576
+ cancelDelete() {
577
+ this.confirmingDeleteId = null;
351
578
  }
352
579
  render() {
353
580
  return html /*html*/ `
@@ -374,23 +601,58 @@ let SniceChat = (() => {
374
601
  </div>
375
602
  `;
376
603
  }
604
+ // Per-message author color. Precedence: per-message override → authorColors
605
+ // map → auto (only when color-authors is set) → none (falls through to the
606
+ // default token in CSS). Computed per element instance — no global registry.
607
+ resolveAuthorColor(message) {
608
+ if (message.authorColor && isSafeCssColor(message.authorColor))
609
+ return message.authorColor;
610
+ const mapped = this.authorColors[message.author];
611
+ if (mapped && isSafeCssColor(mapped))
612
+ return mapped;
613
+ if (this.colorAuthors)
614
+ return autoAuthorColor(message.author);
615
+ return '';
616
+ }
617
+ // Markdown is opt-in: per-message format='markdown', or the component-wide
618
+ // `markdown` attribute (which a per-message format='text' can override).
619
+ shouldRenderMarkdown(message) {
620
+ if (message.format === MessageFormat.Markdown)
621
+ return true;
622
+ if (this.markdown && message.format !== MessageFormat.Text)
623
+ return true;
624
+ return false;
625
+ }
626
+ renderMessageBody(message) {
627
+ if (this.shouldRenderMarkdown(message)) {
628
+ return html /*html*/ `<snice-markdown part="message-text" class="message-text" .content=${message.content}></snice-markdown>`;
629
+ }
630
+ return html /*html*/ `<div part="message-text" class="message-text">${message.content}</div>`;
631
+ }
377
632
  renderMessage(message) {
378
633
  const isSystem = message.type === 'system';
379
634
  const isCurrentUser = message.author === this.currentUser;
380
635
  if (isSystem) {
381
636
  return html /*html*/ `
382
- <div class="message system" data-message-id="${message.id}">
637
+ <div part="message system-message" class="message system" data-message-id="${message.id}">
383
638
  <div class="message-content">
384
- <div class="message-text">${message.content}</div>
639
+ <div part="message-text" class="message-text">${message.content}</div>
385
640
  </div>
386
641
  </div>
387
642
  `;
388
643
  }
644
+ const ownClass = isCurrentUser ? 'own' : 'other';
645
+ const ownPart = isCurrentUser ? 'message-own' : 'message-other';
646
+ const authorColor = this.resolveAuthorColor(message);
647
+ const authorStyle = authorColor ? `--snice-chat-author-color:${authorColor}` : '';
648
+ const isEditing = this.editingId === message.id;
649
+ const isConfirmingDelete = this.confirmingDeleteId === message.id;
650
+ const hasReactions = !!message.reactions && message.reactions.length > 0;
389
651
  return html /*html*/ `
390
- <div class="message" data-message-id="${message.id}">
652
+ <div part="message ${ownPart}" class="message ${ownClass}" data-message-id="${message.id}">
391
653
  ${this.showAvatars
392
654
  ? html `
393
- <div class="message-avatar">
655
+ <div part="avatar" class="message-avatar">
394
656
  ${message.avatar
395
657
  ? html `<img src="${message.avatar}" alt="${message.author}" />`
396
658
  : getInitials(message.author)}
@@ -399,55 +661,70 @@ let SniceChat = (() => {
399
661
  : ''}
400
662
  <div class="message-content">
401
663
  <div class="message-header">
402
- <span class="message-author">${message.author}</span>
664
+ <span part="author" class="message-author" style="${authorStyle}">${message.author}</span>
403
665
  ${this.showTimestamps
404
- ? html `<span class="message-timestamp">${formatTime(message.timestamp)}</span>`
666
+ ? html `<span part="timestamp" class="message-timestamp">${formatTime(message.timestamp)}</span>`
405
667
  : ''}
406
- ${message.edited ? html `<span class="message-edited">(edited)</span>` : ''}
668
+ ${message.edited ? html `<span part="edited" class="message-edited">(edited)</span>` : ''}
407
669
  </div>
408
- ${message.content ? html `<div class="message-text">${message.content}</div>` : ''}
670
+ ${isEditing
671
+ ? this.renderEditor(message)
672
+ : message.content ? this.renderMessageBody(message) : ''}
409
673
  ${message.attachment ? this.renderAttachment(message.attachment) : ''}
410
- ${message.reactions && message.reactions.length > 0
411
- ? this.renderReactions(message.id, message.reactions, isCurrentUser)
412
- : ''}
674
+ ${hasReactions ? this.renderReactions(message.id, message.reactions) : ''}
675
+ ${isConfirmingDelete ? this.renderDeleteConfirm(message) : ''}
676
+ </div>
677
+ ${isEditing || isConfirmingDelete ? '' : this.renderActions(message.id, isCurrentUser)}
678
+ </div>
679
+ `;
680
+ }
681
+ // Inline message editor — replaces the body while editing. Enter saves,
682
+ // Shift+Enter newlines, Esc cancels.
683
+ renderEditor(message) {
684
+ return html /*html*/ `
685
+ <div class="message-edit">
686
+ <textarea
687
+ part="edit-input"
688
+ class="edit-field"
689
+ .value=${message.content}
690
+ @keydown=${(e) => this.handleEditKeydown(e, message.id)}
691
+ ></textarea>
692
+ <div class="edit-actions">
693
+ <button part="edit-save" class="edit-button edit-save" @click=${() => this.commitEdit(message.id)}>Save</button>
694
+ <button part="edit-cancel" class="edit-button" @click=${() => this.cancelEdit()}>Cancel</button>
695
+ </div>
696
+ </div>
697
+ `;
698
+ }
699
+ // Inline delete confirmation — replaces the hover actions while pending, so
700
+ // a misclick can't destroy a message. Confirm deletes + emits; Cancel aborts.
701
+ renderDeleteConfirm(message) {
702
+ return html /*html*/ `
703
+ <div part="delete-confirm" class="message-confirm">
704
+ <span class="confirm-text">Delete this message?</span>
705
+ <div class="confirm-actions">
706
+ <button part="delete-confirm-yes" class="confirm-button confirm-delete" @click=${() => this.confirmDelete(message.id)}>Delete</button>
707
+ <button part="delete-confirm-no" class="confirm-button" @click=${() => this.cancelDelete()}>Cancel</button>
413
708
  </div>
709
+ </div>
710
+ `;
711
+ }
712
+ // Hover action menu. React is available on every message (you react to
713
+ // others, not just yourself); edit and delete are owner-only.
714
+ renderActions(messageId, isCurrentUser) {
715
+ return html /*html*/ `
716
+ <div part="actions" class="message-actions">
717
+ <button class="action-button" @click=${() => this.handleReaction(messageId, '👍')} title="React" aria-label="React">
718
+ <span class="action-emoji" aria-hidden="true">🙂</span>
719
+ </button>
414
720
  ${isCurrentUser
415
721
  ? html `
416
- <div class="message-actions">
417
- <button
418
- class="action-button"
419
- @click="${() => this.handleReaction(message.id, '👍')}"
420
- title="React"
421
- >
422
- <svg viewBox="0 0 16 16" fill="currentColor">
423
- <path
424
- 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"
425
- />
426
- </svg>
427
- </button>
428
- <button
429
- class="action-button"
430
- @click="${() => this.handleEdit(message.id)}"
431
- title="Edit"
432
- >
433
- <svg viewBox="0 0 16 16" fill="currentColor">
434
- <path
435
- 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"
436
- />
437
- </svg>
438
- </button>
439
- <button
440
- class="action-button"
441
- @click="${() => this.handleDelete(message.id)}"
442
- title="Delete"
443
- >
444
- <svg viewBox="0 0 16 16" fill="currentColor">
445
- <path
446
- 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"
447
- />
448
- </svg>
449
- </button>
450
- </div>
722
+ <button class="action-button" @click=${() => this.startEdit(messageId)} title="Edit" aria-label="Edit message">
723
+ ${unsafeHTML(PENCIL)}
724
+ </button>
725
+ <button class="action-button" @click=${() => this.handleDelete(messageId)} title="Delete" aria-label="Delete message">
726
+ ${unsafeHTML(TRASH)}
727
+ </button>
451
728
  `
452
729
  : ''}
453
730
  </div>
@@ -458,13 +735,13 @@ let SniceChat = (() => {
458
735
  return '';
459
736
  if (attachment.type === 'image') {
460
737
  return html /*html*/ `
461
- <div class="message-attachment">
738
+ <div part="attachment" class="message-attachment">
462
739
  <img src="${attachment.url}" alt="${attachment.name}" />
463
740
  </div>
464
741
  `;
465
742
  }
466
743
  return html /*html*/ `
467
- <div class="message-attachment">
744
+ <div part="attachment" class="message-attachment">
468
745
  <div class="attachment-file">
469
746
  <div class="attachment-icon">
470
747
  <svg viewBox="0 0 16 16" fill="currentColor">
@@ -483,20 +760,24 @@ let SniceChat = (() => {
483
760
  </div>
484
761
  `;
485
762
  }
486
- renderReactions(messageId, reactions, isCurrentUser) {
763
+ renderReactions(messageId, reactions) {
487
764
  if (!reactions || reactions.length === 0)
488
765
  return '';
489
766
  return html /*html*/ `
490
- <div class="message-reactions">
491
- ${reactions.map((reaction) => html `
767
+ <div part="reactions" class="message-reactions">
768
+ ${reactions.map((reaction) => {
769
+ const isActive = reaction.users.includes(this.currentUser);
770
+ return html `
492
771
  <div
493
- class="reaction ${reaction.users.includes(this.currentUser) ? 'active' : ''}"
772
+ part="reaction ${isActive ? 'reaction-active' : ''}"
773
+ class="reaction ${isActive ? 'active' : ''}"
494
774
  @click="${() => this.handleReaction(messageId, reaction.emoji)}"
495
775
  >
496
776
  <span class="reaction-emoji">${reaction.emoji}</span>
497
777
  <span class="reaction-count">${reaction.count}</span>
498
778
  </div>
499
- `)}
779
+ `;
780
+ })}
500
781
  </div>
501
782
  `;
502
783
  }
@@ -506,7 +787,7 @@ let SniceChat = (() => {
506
787
  return '';
507
788
  return html /*html*/ `
508
789
  <div class="typing-indicators">
509
- <div class="typing-indicator">
790
+ <div part="typing-indicator" class="typing-indicator">
510
791
  <span>${users.map((u) => u.user).join(', ')} ${users.length === 1 ? 'is' : 'are'} typing</span>
511
792
  <div class="typing-dots">
512
793
  <div class="typing-dot"></div>
@@ -537,20 +818,12 @@ let SniceChat = (() => {
537
818
  @click="${() => this.handleFileClick()}"
538
819
  title="Attach file"
539
820
  >
540
- <svg viewBox="0 0 16 16" fill="currentColor">
541
- <path
542
- 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"
543
- />
544
- </svg>
821
+ ${unsafeHTML(PAPER_CLIP)}
545
822
  </button>
546
823
  `
547
824
  : ''}
548
825
  <button class="input-button send" @click="${() => this.sendMessage()}" title="Send">
549
- <svg viewBox="0 0 16 16" fill="currentColor">
550
- <path
551
- 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"
552
- />
553
- </svg>
826
+ ${unsafeHTML(PAPER_AIRPLANE_SOLID)}
554
827
  </button>
555
828
  </div>
556
829
  </div>