@memberjunction/ng-conversations 5.40.2 → 5.41.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 (378) hide show
  1. package/README.md +57 -0
  2. package/dist/__tests__/channel-optional-surface.test.d.ts +2 -0
  3. package/dist/__tests__/channel-optional-surface.test.d.ts.map +1 -0
  4. package/dist/__tests__/channel-optional-surface.test.js +53 -0
  5. package/dist/__tests__/channel-optional-surface.test.js.map +1 -0
  6. package/dist/__tests__/chat-events.test.d.ts +14 -0
  7. package/dist/__tests__/chat-events.test.d.ts.map +1 -0
  8. package/dist/__tests__/chat-events.test.js +109 -0
  9. package/dist/__tests__/chat-events.test.js.map +1 -0
  10. package/dist/__tests__/conversation-naming.test.d.ts +2 -0
  11. package/dist/__tests__/conversation-naming.test.d.ts.map +1 -0
  12. package/dist/__tests__/conversation-naming.test.js +110 -0
  13. package/dist/__tests__/conversation-naming.test.js.map +1 -0
  14. package/dist/__tests__/delegation-result-parser.test.d.ts +2 -0
  15. package/dist/__tests__/delegation-result-parser.test.d.ts.map +1 -0
  16. package/dist/__tests__/delegation-result-parser.test.js +107 -0
  17. package/dist/__tests__/delegation-result-parser.test.js.map +1 -0
  18. package/dist/__tests__/event-wiring.test.d.ts +15 -0
  19. package/dist/__tests__/event-wiring.test.d.ts.map +1 -0
  20. package/dist/__tests__/event-wiring.test.js +100 -0
  21. package/dist/__tests__/event-wiring.test.js.map +1 -0
  22. package/dist/__tests__/narration-template.test.d.ts +2 -0
  23. package/dist/__tests__/narration-template.test.d.ts.map +1 -0
  24. package/dist/__tests__/narration-template.test.js +76 -0
  25. package/dist/__tests__/narration-template.test.js.map +1 -0
  26. package/dist/__tests__/realtime-agent-picker-models.test.d.ts +2 -0
  27. package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +1 -0
  28. package/dist/__tests__/realtime-agent-picker-models.test.js +49 -0
  29. package/dist/__tests__/realtime-agent-picker-models.test.js.map +1 -0
  30. package/dist/__tests__/realtime-audio-visuals.test.d.ts +2 -0
  31. package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +1 -0
  32. package/dist/__tests__/realtime-audio-visuals.test.js +123 -0
  33. package/dist/__tests__/realtime-audio-visuals.test.js.map +1 -0
  34. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +2 -0
  35. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +1 -0
  36. package/dist/__tests__/realtime-delegation-card-cancel.test.js +48 -0
  37. package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +1 -0
  38. package/dist/__tests__/realtime-disclosure.test.d.ts +2 -0
  39. package/dist/__tests__/realtime-disclosure.test.d.ts.map +1 -0
  40. package/dist/__tests__/realtime-disclosure.test.js +164 -0
  41. package/dist/__tests__/realtime-disclosure.test.js.map +1 -0
  42. package/dist/__tests__/realtime-pairing.test.d.ts +2 -0
  43. package/dist/__tests__/realtime-pairing.test.d.ts.map +1 -0
  44. package/dist/__tests__/realtime-pairing.test.js +207 -0
  45. package/dist/__tests__/realtime-pairing.test.js.map +1 -0
  46. package/dist/__tests__/realtime-review-lifecycle.test.d.ts +2 -0
  47. package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +1 -0
  48. package/dist/__tests__/realtime-review-lifecycle.test.js +154 -0
  49. package/dist/__tests__/realtime-review-lifecycle.test.js.map +1 -0
  50. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +2 -0
  51. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +1 -0
  52. package/dist/__tests__/realtime-session-cancel-usage.test.js +230 -0
  53. package/dist/__tests__/realtime-session-cancel-usage.test.js.map +1 -0
  54. package/dist/__tests__/realtime-session-channels.test.d.ts +2 -0
  55. package/dist/__tests__/realtime-session-channels.test.d.ts.map +1 -0
  56. package/dist/__tests__/realtime-session-channels.test.js +252 -0
  57. package/dist/__tests__/realtime-session-channels.test.js.map +1 -0
  58. package/dist/__tests__/realtime-session-client-tools.test.d.ts +2 -0
  59. package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +1 -0
  60. package/dist/__tests__/realtime-session-client-tools.test.js +103 -0
  61. package/dist/__tests__/realtime-session-client-tools.test.js.map +1 -0
  62. package/dist/__tests__/realtime-session-minimized.test.d.ts +2 -0
  63. package/dist/__tests__/realtime-session-minimized.test.d.ts.map +1 -0
  64. package/dist/__tests__/realtime-session-minimized.test.js +32 -0
  65. package/dist/__tests__/realtime-session-minimized.test.js.map +1 -0
  66. package/dist/__tests__/realtime-session-mint.test.d.ts +2 -0
  67. package/dist/__tests__/realtime-session-mint.test.d.ts.map +1 -0
  68. package/dist/__tests__/realtime-session-mint.test.js +69 -0
  69. package/dist/__tests__/realtime-session-mint.test.js.map +1 -0
  70. package/dist/__tests__/realtime-session-policy.test.d.ts +2 -0
  71. package/dist/__tests__/realtime-session-policy.test.d.ts.map +1 -0
  72. package/dist/__tests__/realtime-session-policy.test.js +303 -0
  73. package/dist/__tests__/realtime-session-policy.test.js.map +1 -0
  74. package/dist/__tests__/realtime-session-review.service.test.d.ts +2 -0
  75. package/dist/__tests__/realtime-session-review.service.test.d.ts.map +1 -0
  76. package/dist/__tests__/realtime-session-review.service.test.js +743 -0
  77. package/dist/__tests__/realtime-session-review.service.test.js.map +1 -0
  78. package/dist/__tests__/realtime-session-state.test.d.ts +2 -0
  79. package/dist/__tests__/realtime-session-state.test.d.ts.map +1 -0
  80. package/dist/__tests__/realtime-session-state.test.js +83 -0
  81. package/dist/__tests__/realtime-session-state.test.js.map +1 -0
  82. package/dist/__tests__/realtime-session-timeline-card.test.d.ts +2 -0
  83. package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +1 -0
  84. package/dist/__tests__/realtime-session-timeline-card.test.js +106 -0
  85. package/dist/__tests__/realtime-session-timeline-card.test.js.map +1 -0
  86. package/dist/__tests__/realtime-session-timeline.test.d.ts +2 -0
  87. package/dist/__tests__/realtime-session-timeline.test.d.ts.map +1 -0
  88. package/dist/__tests__/realtime-session-timeline.test.js +142 -0
  89. package/dist/__tests__/realtime-session-timeline.test.js.map +1 -0
  90. package/dist/__tests__/realtime-sessions-adapter.test.d.ts +19 -0
  91. package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +1 -0
  92. package/dist/__tests__/realtime-sessions-adapter.test.js +188 -0
  93. package/dist/__tests__/realtime-sessions-adapter.test.js.map +1 -0
  94. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +2 -0
  95. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +1 -0
  96. package/dist/__tests__/realtime-surface-panel-prefs.test.js +100 -0
  97. package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +1 -0
  98. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +2 -0
  99. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +1 -0
  100. package/dist/__tests__/realtime-surface-tabs-model.test.js +193 -0
  101. package/dist/__tests__/realtime-surface-tabs-model.test.js.map +1 -0
  102. package/dist/__tests__/remote-browser-audio-player.test.d.ts +2 -0
  103. package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +1 -0
  104. package/dist/__tests__/remote-browser-audio-player.test.js +137 -0
  105. package/dist/__tests__/remote-browser-audio-player.test.js.map +1 -0
  106. package/dist/__tests__/remote-browser-channel.test.d.ts +2 -0
  107. package/dist/__tests__/remote-browser-channel.test.d.ts.map +1 -0
  108. package/dist/__tests__/remote-browser-channel.test.js +423 -0
  109. package/dist/__tests__/remote-browser-channel.test.js.map +1 -0
  110. package/dist/__tests__/slot-defaults.test.d.ts +24 -0
  111. package/dist/__tests__/slot-defaults.test.d.ts.map +1 -0
  112. package/dist/__tests__/slot-defaults.test.js +63 -0
  113. package/dist/__tests__/slot-defaults.test.js.map +1 -0
  114. package/dist/__tests__/user-authorization.test.d.ts +2 -0
  115. package/dist/__tests__/user-authorization.test.d.ts.map +1 -0
  116. package/dist/__tests__/user-authorization.test.js +97 -0
  117. package/dist/__tests__/user-authorization.test.js.map +1 -0
  118. package/dist/__tests__/voice-session-narration.test.d.ts +2 -0
  119. package/dist/__tests__/voice-session-narration.test.d.ts.map +1 -0
  120. package/dist/__tests__/voice-session-narration.test.js +609 -0
  121. package/dist/__tests__/voice-session-narration.test.js.map +1 -0
  122. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +2 -0
  123. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +1 -0
  124. package/dist/__tests__/whiteboard-artifact-viewer.test.js +101 -0
  125. package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +1 -0
  126. package/dist/__tests__/whiteboard-channel.test.d.ts +2 -0
  127. package/dist/__tests__/whiteboard-channel.test.d.ts.map +1 -0
  128. package/dist/__tests__/whiteboard-channel.test.js +260 -0
  129. package/dist/__tests__/whiteboard-channel.test.js.map +1 -0
  130. package/dist/__tests__/whiteboard-restore-state.test.d.ts +2 -0
  131. package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +1 -0
  132. package/dist/__tests__/whiteboard-restore-state.test.js +108 -0
  133. package/dist/__tests__/whiteboard-restore-state.test.js.map +1 -0
  134. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +205 -3
  135. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  136. package/dist/lib/components/conversation/conversation-chat-area.component.js +911 -342
  137. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  138. package/dist/lib/components/mention/mention-dropdown.component.js +35 -17
  139. package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
  140. package/dist/lib/components/mention/mention-editor.component.d.ts +4 -0
  141. package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
  142. package/dist/lib/components/mention/mention-editor.component.js +43 -19
  143. package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
  144. package/dist/lib/components/message/message-input-box.component.d.ts +17 -1
  145. package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
  146. package/dist/lib/components/message/message-input-box.component.js +73 -15
  147. package/dist/lib/components/message/message-input-box.component.js.map +1 -1
  148. package/dist/lib/components/message/message-input.component.d.ts +142 -6
  149. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  150. package/dist/lib/components/message/message-input.component.js +328 -82
  151. package/dist/lib/components/message/message-input.component.js.map +1 -1
  152. package/dist/lib/components/message/message-item.component.d.ts +28 -3
  153. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  154. package/dist/lib/components/message/message-item.component.js +180 -108
  155. package/dist/lib/components/message/message-item.component.js.map +1 -1
  156. package/dist/lib/components/message/message-list.component.d.ts +81 -2
  157. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  158. package/dist/lib/components/message/message-list.component.js +252 -87
  159. package/dist/lib/components/message/message-list.component.js.map +1 -1
  160. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +282 -0
  161. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -0
  162. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +158 -0
  163. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -0
  164. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +25 -0
  165. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -0
  166. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js +140 -0
  167. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -0
  168. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +35 -0
  169. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -0
  170. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +58 -0
  171. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -0
  172. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +63 -0
  173. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -0
  174. package/dist/lib/components/realtime/realtime-activity-rail.component.js +260 -0
  175. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -0
  176. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +117 -0
  177. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -0
  178. package/dist/lib/components/realtime/realtime-agent-banner.component.js +504 -0
  179. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -0
  180. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +168 -0
  181. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -0
  182. package/dist/lib/components/realtime/realtime-agent-picker.component.js +556 -0
  183. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -0
  184. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +97 -0
  185. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -0
  186. package/dist/lib/components/realtime/realtime-audio-visuals.js +139 -0
  187. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -0
  188. package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts +29 -0
  189. package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts.map +1 -0
  190. package/dist/lib/components/realtime/realtime-channel-strip.component.js +69 -0
  191. package/dist/lib/components/realtime/realtime-channel-strip.component.js.map +1 -0
  192. package/dist/lib/components/realtime/realtime-composer.component.d.ts +65 -0
  193. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -0
  194. package/dist/lib/components/realtime/realtime-composer.component.js +256 -0
  195. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -0
  196. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +71 -0
  197. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -0
  198. package/dist/lib/components/realtime/realtime-delegation-card.component.js +324 -0
  199. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -0
  200. package/dist/lib/components/realtime/realtime-disclosure.d.ts +135 -0
  201. package/dist/lib/components/realtime/realtime-disclosure.d.ts.map +1 -0
  202. package/dist/lib/components/realtime/realtime-disclosure.js +188 -0
  203. package/dist/lib/components/realtime/realtime-disclosure.js.map +1 -0
  204. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +491 -0
  205. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -0
  206. package/dist/lib/components/realtime/realtime-session-overlay.component.js +1274 -0
  207. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -0
  208. package/dist/lib/components/realtime/realtime-session-state.d.ts +191 -0
  209. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -0
  210. package/dist/lib/components/realtime/realtime-session-state.js +244 -0
  211. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -0
  212. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +56 -0
  213. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -0
  214. package/dist/lib/components/realtime/realtime-session-thread.component.js +246 -0
  215. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -0
  216. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +51 -0
  217. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -0
  218. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +193 -0
  219. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -0
  220. package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts +77 -0
  221. package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts.map +1 -0
  222. package/dist/lib/components/realtime/realtime-surface-panel-prefs.js +114 -0
  223. package/dist/lib/components/realtime/realtime-surface-panel-prefs.js.map +1 -0
  224. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +173 -0
  225. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -0
  226. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +496 -0
  227. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -0
  228. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +181 -0
  229. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -0
  230. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +223 -0
  231. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -0
  232. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts +163 -0
  233. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts.map +1 -0
  234. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js +309 -0
  235. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js.map +1 -0
  236. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +168 -0
  237. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -0
  238. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +524 -0
  239. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -0
  240. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +346 -0
  241. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -0
  242. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +851 -0
  243. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -0
  244. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts +86 -0
  245. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts.map +1 -0
  246. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js +210 -0
  247. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js.map +1 -0
  248. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts +48 -0
  249. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts.map +1 -0
  250. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js +180 -0
  251. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js.map +1 -0
  252. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +119 -0
  253. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -0
  254. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +274 -0
  255. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -0
  256. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts +11 -0
  257. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts.map +1 -0
  258. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js +98 -0
  259. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js.map +1 -0
  260. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts +9 -0
  261. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts.map +1 -0
  262. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js +35 -0
  263. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js.map +1 -0
  264. package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts +28 -0
  265. package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts.map +1 -0
  266. package/dist/lib/components/slots/mj-chat-empty-state-default.component.js +104 -0
  267. package/dist/lib/components/slots/mj-chat-empty-state-default.component.js.map +1 -0
  268. package/dist/lib/components/slots/mj-chat-header-default.component.d.ts +11 -0
  269. package/dist/lib/components/slots/mj-chat-header-default.component.d.ts.map +1 -0
  270. package/dist/lib/components/slots/mj-chat-header-default.component.js +103 -0
  271. package/dist/lib/components/slots/mj-chat-header-default.component.js.map +1 -0
  272. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts +15 -0
  273. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts.map +1 -0
  274. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js +73 -0
  275. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js.map +1 -0
  276. package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts +9 -0
  277. package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts.map +1 -0
  278. package/dist/lib/components/slots/mj-chat-message-extra-default.component.js +34 -0
  279. package/dist/lib/components/slots/mj-chat-message-extra-default.component.js.map +1 -0
  280. package/dist/lib/components/slots/slot-interfaces.d.ts +95 -0
  281. package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -0
  282. package/dist/lib/components/slots/slot-interfaces.js +18 -0
  283. package/dist/lib/components/slots/slot-interfaces.js.map +1 -0
  284. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +11 -0
  285. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  286. package/dist/lib/components/workspace/conversation-workspace.component.js +28 -4
  287. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  288. package/dist/lib/conversations.module.d.ts +12 -1
  289. package/dist/lib/conversations.module.d.ts.map +1 -1
  290. package/dist/lib/conversations.module.js +93 -5
  291. package/dist/lib/conversations.module.js.map +1 -1
  292. package/dist/lib/directives/chat-slot.directive.d.ts +44 -0
  293. package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -0
  294. package/dist/lib/directives/chat-slot.directive.js +54 -0
  295. package/dist/lib/directives/chat-slot.directive.js.map +1 -0
  296. package/dist/lib/events/chat-events.d.ts +137 -0
  297. package/dist/lib/events/chat-events.d.ts.map +1 -0
  298. package/dist/lib/events/chat-events.js +189 -0
  299. package/dist/lib/events/chat-events.js.map +1 -0
  300. package/dist/lib/models/conversation-state.model.d.ts +2 -1
  301. package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
  302. package/dist/lib/models/conversation-state.model.js.map +1 -1
  303. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  304. package/dist/lib/services/artifact-state.service.js +23 -6
  305. package/dist/lib/services/artifact-state.service.js.map +1 -1
  306. package/dist/lib/services/conversation-agent.service.d.ts +60 -74
  307. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  308. package/dist/lib/services/conversation-agent.service.js +100 -313
  309. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  310. package/dist/lib/services/conversation-bridge.service.d.ts +11 -70
  311. package/dist/lib/services/conversation-bridge.service.d.ts.map +1 -1
  312. package/dist/lib/services/conversation-bridge.service.js +51 -85
  313. package/dist/lib/services/conversation-bridge.service.js.map +1 -1
  314. package/dist/lib/services/conversation-naming.d.ts +63 -0
  315. package/dist/lib/services/conversation-naming.d.ts.map +1 -0
  316. package/dist/lib/services/conversation-naming.js +58 -0
  317. package/dist/lib/services/conversation-naming.js.map +1 -0
  318. package/dist/lib/services/conversation-streaming.service.d.ts +24 -154
  319. package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
  320. package/dist/lib/services/conversation-streaming.service.js +39 -361
  321. package/dist/lib/services/conversation-streaming.service.js.map +1 -1
  322. package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts +10 -0
  323. package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts.map +1 -0
  324. package/dist/lib/services/conversations-runtime-bootstrap.service.js +104 -0
  325. package/dist/lib/services/conversations-runtime-bootstrap.service.js.map +1 -0
  326. package/dist/lib/services/delegation-result-parser.d.ts +45 -0
  327. package/dist/lib/services/delegation-result-parser.d.ts.map +1 -0
  328. package/dist/lib/services/delegation-result-parser.js +48 -0
  329. package/dist/lib/services/delegation-result-parser.js.map +1 -0
  330. package/dist/lib/services/mention-autocomplete.service.d.ts +19 -4
  331. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  332. package/dist/lib/services/mention-autocomplete.service.js +65 -4
  333. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  334. package/dist/lib/services/mention-parser.service.d.ts +8 -53
  335. package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
  336. package/dist/lib/services/mention-parser.service.js +32 -243
  337. package/dist/lib/services/mention-parser.service.js.map +1 -1
  338. package/dist/lib/services/narration-template.d.ts +42 -0
  339. package/dist/lib/services/narration-template.d.ts.map +1 -0
  340. package/dist/lib/services/narration-template.js +73 -0
  341. package/dist/lib/services/narration-template.js.map +1 -0
  342. package/dist/lib/services/realtime-pairing.d.ts +120 -0
  343. package/dist/lib/services/realtime-pairing.d.ts.map +1 -0
  344. package/dist/lib/services/realtime-pairing.js +150 -0
  345. package/dist/lib/services/realtime-pairing.js.map +1 -0
  346. package/dist/lib/services/realtime-session-review.service.d.ts +233 -0
  347. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -0
  348. package/dist/lib/services/realtime-session-review.service.js +417 -0
  349. package/dist/lib/services/realtime-session-review.service.js.map +1 -0
  350. package/dist/lib/services/realtime-session.service.d.ts +739 -0
  351. package/dist/lib/services/realtime-session.service.d.ts.map +1 -0
  352. package/dist/lib/services/realtime-session.service.js +1647 -0
  353. package/dist/lib/services/realtime-session.service.js.map +1 -0
  354. package/dist/lib/services/realtime-sessions-adapter.d.ts +54 -0
  355. package/dist/lib/services/realtime-sessions-adapter.d.ts.map +1 -0
  356. package/dist/lib/services/realtime-sessions-adapter.js +154 -0
  357. package/dist/lib/services/realtime-sessions-adapter.js.map +1 -0
  358. package/dist/lib/services/user-authorization.d.ts +67 -0
  359. package/dist/lib/services/user-authorization.d.ts.map +1 -0
  360. package/dist/lib/services/user-authorization.js +66 -0
  361. package/dist/lib/services/user-authorization.js.map +1 -0
  362. package/dist/lib/utils/realtime-session-timeline.d.ts +84 -0
  363. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -0
  364. package/dist/lib/utils/realtime-session-timeline.js +94 -0
  365. package/dist/lib/utils/realtime-session-timeline.js.map +1 -0
  366. package/dist/public-api.d.ts +41 -0
  367. package/dist/public-api.d.ts.map +1 -1
  368. package/dist/public-api.js +50 -0
  369. package/dist/public-api.js.map +1 -1
  370. package/package.json +27 -24
  371. package/dist/__tests__/conversation-bridge.service.test.d.ts +0 -2
  372. package/dist/__tests__/conversation-bridge.service.test.d.ts.map +0 -1
  373. package/dist/__tests__/conversation-bridge.service.test.js +0 -98
  374. package/dist/__tests__/conversation-bridge.service.test.js.map +0 -1
  375. package/dist/__tests__/mention-parser.test.d.ts +0 -2
  376. package/dist/__tests__/mention-parser.test.d.ts.map +0 -1
  377. package/dist/__tests__/mention-parser.test.js +0 -154
  378. package/dist/__tests__/mention-parser.test.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-session-thread.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-session-thread.component.ts","../../../../src/lib/components/realtime/realtime-session-thread.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, EventEmitter, Input, Output, ElementRef, ViewChild, AfterViewChecked, OnInit, OnDestroy,\n ChangeDetectorRef, inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Subscription } from 'rxjs';\nimport { RealtimeSessionState, RealtimeThreadItem } from './realtime-session-state';\nimport { RealtimeDelegationCardComponent } from './realtime-delegation-card.component';\nimport { ParsedDelegationArtifact } from '../../services/delegation-result-parser';\n\n/**\n * The unified, chronological live thread for the call overlay: caption bubbles\n * interleaved with delegation cards exactly where they happened.\n *\n * PURELY PRESENTATIONAL over {@link RealtimeSessionState} — the overlay shell owns the\n * state object (which merges the service streams once) and passes it here AND to the\n * activity rail, so there is exactly one copy of the per-CallID merge logic.\n *\n * Also renders the EPHEMERAL narration \"live note\": indented, muted, italic text under\n * the ACTIVE working card (latest narration only — replaced, never accumulated).\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-session-thread',\n imports: [CommonModule, RealtimeDelegationCardComponent],\n templateUrl: './realtime-session-thread.component.html',\n styleUrl: './realtime-session-thread.component.css'\n})\nexport class RealtimeSessionThreadComponent implements OnInit, AfterViewChecked, OnDestroy {\n @ViewChild('scrollAnchor') private scrollAnchor?: ElementRef<HTMLElement>;\n\n /** Display name of the agent (caption avatar / meta line). */\n @Input() AgentName = 'Sage';\n\n /**\n * Display name of the signed-in user for their turns — consistent with the main\n * chat's sender names, and ready for multi-user sessions where \"You\" stops meaning\n * anything. Hosts bind the current user's name; the default keeps old hosts working.\n */\n @Input() UserName = 'You';\n\n /** Shared live-session state, owned by the overlay shell. */\n @Input({ required: true }) State!: RealtimeSessionState;\n\n /** Whether to render caption bubbles (toggled by the controls' captions button). */\n @Input() ShowCaptions = true;\n\n /** Whether developer affordances on delegation cards are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /** Re-emitted from a delegation card's dev \"Open run\" link (the delegated run's ID). */\n @Output() OpenRunRequested = new EventEmitter<string>();\n\n /** Re-emitted from a delegation card's \"View\" artifact chip (focuses the artifact's surface tab). */\n @Output() OpenArtifactRequested = new EventEmitter<ParsedDelegationArtifact>();\n\n /** Re-emitted from a WORKING delegation card's ✕ cancel affordance (the call's ID). */\n @Output() CancelRequested = new EventEmitter<string>();\n\n /** Item count at the last change notification, to auto-scroll only when the list grows. */\n private lastItemCount = 0;\n /** Drives auto-scroll: set whenever the list grows. */\n private pendingScroll = false;\n\n private changedSub?: Subscription;\n private cdr = inject(ChangeDetectorRef);\n\n ngOnInit(): void {\n this.changedSub = this.State.Changed$.subscribe(() => this.onStateChanged());\n this.lastItemCount = this.State.Items.length;\n }\n\n ngAfterViewChecked(): void {\n if (this.pendingScroll) {\n this.pendingScroll = false;\n this.scrollAnchor?.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'end' });\n }\n }\n\n ngOnDestroy(): void {\n this.changedSub?.unsubscribe();\n }\n\n /** track fn for the @for over thread items. */\n public TrackItem(index: number, item: RealtimeThreadItem): string {\n switch (item.Kind) {\n case 'delegation': return `d:${item.Card.CallID}`;\n case 'divider': return `s:${index}`;\n default: return `c:${index}`;\n }\n }\n\n /** True when the live narration note should render under THIS delegation item. */\n public ShowsLiveNote(item: RealtimeThreadItem): boolean {\n return item.Kind === 'delegation'\n && !item.Card.Done\n && this.State.Narration !== null\n && item.Card.CallID === this.State.ActiveCallId;\n }\n\n /** Marks for check on every state change; auto-scrolls when the thread grew. */\n private onStateChanged(): void {\n if (this.State.Items.length > this.lastItemCount) {\n this.pendingScroll = true;\n }\n this.lastItemCount = this.State.Items.length;\n this.cdr.markForCheck();\n }\n}\n","<div class=\"thread\">\n @for (item of State.Items; track TrackItem($index, item)) {\n @switch (item.Kind) {\n @case ('caption') {\n @if (ShowCaptions) {\n <div class=\"turn\" [class.turn--user]=\"item.Role === 'User'\" [class.turn--agent]=\"item.Role === 'Assistant'\">\n <div class=\"turn-avatar\">{{ (item.Role === 'User' ? UserName : AgentName).charAt(0).toUpperCase() }}</div>\n <div class=\"turn-body\">\n <div class=\"turn-meta\">\n @if (item.Role === 'User') {\n <span class=\"typed-tag\">{{ UserName }}</span>\n } @else {\n {{ AgentName }} <span class=\"muted\">· voice</span>\n }\n </div>\n <div class=\"bubble\">{{ item.Text }}</div>\n </div>\n </div>\n }\n }\n @case ('divider') {\n <!-- Session-leg boundary: subtle rule marking a resume / chained leg -->\n <div class=\"thread-divider\" role=\"separator\">\n <span class=\"thread-divider__line\" aria-hidden=\"true\"></span>\n <span class=\"thread-divider__label\">\n <i [class]=\"item.Icon\" aria-hidden=\"true\"></i>\n {{ item.Label }}\n @if (item.At) {\n <span class=\"thread-divider__time\">· {{ item.At | date:'MMM d, h:mm a' }}</span>\n }\n </span>\n @if (item.CloseReason) {\n <span class=\"thread-divider__chip\" title=\"Why the previous session leg ended\">{{ item.CloseReason }}</span>\n }\n <span class=\"thread-divider__line\" aria-hidden=\"true\"></span>\n </div>\n }\n @case ('delegation') {\n <div class=\"delegation-block\">\n <mj-realtime-delegation-card\n [Card]=\"item.Card\"\n [DevMode]=\"DevMode\"\n (OpenRunRequested)=\"OpenRunRequested.emit($event)\"\n (OpenArtifactRequested)=\"OpenArtifactRequested.emit($event)\"\n (CancelRequested)=\"CancelRequested.emit($event)\">\n </mj-realtime-delegation-card>\n @if (ShowsLiveNote(item)) {\n <!-- Ephemeral narration: latest only, never persisted, fades with completion -->\n <div class=\"live-note\" role=\"status\" aria-live=\"polite\">\n <i class=\"fa-solid fa-comment-dots\" aria-hidden=\"true\"></i>\n {{ State.Narration }}\n </div>\n }\n </div>\n }\n }\n } @empty {\n <div class=\"thread-empty\">The live transcript and any delegated work will appear here.</div>\n }\n <div #scrollAnchor></div>\n</div>\n"]}
@@ -0,0 +1,51 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import { RealtimeSessionTimelineGroup, RealtimeSessionTimelineMeta } from '../../utils/realtime-session-timeline';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * The ONE timeline element a realtime session collapses to in the standard conversation
6
+ * message list (see `BuildConversationTimeline`): a visually distinct card at the
7
+ * session's chronological position carrying the session identity (broadcast icon +
8
+ * "Realtime session · <agent>"), its time range, a status / close-reason chip when
9
+ * known, the visible-turn count, and a one-line preview of the last turn.
10
+ *
11
+ * The card's **Open** button emits {@link OpenRequested} with the session id; the
12
+ * message list bubbles it up so the chat area can host the existing SESSION REVIEW
13
+ * overlay via `ConversationChatAreaComponent.OpenRealtimeSessionReview` (Resume /
14
+ * Close live inside that overlay, unchanged).
15
+ *
16
+ * Rendered DYNAMICALLY by `MessageListComponent` (same `createComponent` path the
17
+ * message items use) — standalone by design, no module declaration needed.
18
+ */
19
+ export declare class RealtimeSessionTimelineCardComponent {
20
+ /** The collapsed session block computed from the conversation's stamped detail rows. */
21
+ Group: RealtimeSessionTimelineGroup;
22
+ /** Optional session-row enrichment (agent name / status / close reason); null degrades gracefully. */
23
+ Meta: RealtimeSessionTimelineMeta | null;
24
+ /** Display name of the signed-in user for the last-turn preview (matches the chat's sender names). */
25
+ UserName: string;
26
+ /** Emitted with the `MJ: AI Agent Sessions.ID` when the user asks to open the session review. */
27
+ OpenRequested: EventEmitter<string>;
28
+ /** Card title: "Realtime session · <agent>" when the agent name is known, else the generic label. */
29
+ get Title(): string;
30
+ /** Whether the start and end fall on the same calendar day (drives the end-time format). */
31
+ get SameDayRange(): boolean;
32
+ /**
33
+ * The status chip label, or null to hide the chip entirely:
34
+ * - Closed sessions show the close reason (`Error` / `Explicit` / `Janitor` / `Shutdown`)
35
+ * humanized, falling back to "Closed" for legacy rows without one;
36
+ * - Active sessions show "Live"; Idle shows "Idle";
37
+ * - no meta (lookup unavailable) → no chip.
38
+ */
39
+ get StatusChip(): string | null;
40
+ /** Whether the chip represents an error close (drives the error chip styling). */
41
+ get IsErrorChip(): boolean;
42
+ /** Whether the chip represents a live session (drives the live chip styling). */
43
+ get IsLiveChip(): boolean;
44
+ /** Emits {@link OpenRequested} for the whole-card / Open-button click. */
45
+ Open(event?: MouseEvent): void;
46
+ /** Human label for the session's close reason ("Closed" when the column is null/unknown). */
47
+ private closeReasonLabel;
48
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeSessionTimelineCardComponent, never>;
49
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeSessionTimelineCardComponent, "mj-realtime-session-timeline-card", never, { "Group": { "alias": "Group"; "required": true; }; "Meta": { "alias": "Meta"; "required": false; }; "UserName": { "alias": "UserName"; "required": false; }; }, { "OpenRequested": "OpenRequested"; }, never, never, true, never>;
50
+ }
51
+ //# sourceMappingURL=realtime-session-timeline-card.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-session-timeline-card.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-session-timeline-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;;AAElH;;;;;;;;;;;;;;GAcG;AACH,qBAOa,oCAAoC;IAC/C,wFAAwF;IAC7D,KAAK,EAAG,4BAA4B,CAAC;IAEhE,sGAAsG;IAC7F,IAAI,EAAE,2BAA2B,GAAG,IAAI,CAAQ;IAEzD,sGAAsG;IAC7F,QAAQ,SAAS;IAE1B,iGAAiG;IACvF,aAAa,uBAA8B;IAErD,qGAAqG;IACrG,IAAW,KAAK,IAAI,MAAM,CAGzB;IAED,4FAA4F;IAC5F,IAAW,YAAY,IAAI,OAAO,CAOjC;IAED;;;;;;OAMG;IACH,IAAW,UAAU,IAAI,MAAM,GAAG,IAAI,CAWrC;IAED,kFAAkF;IAClF,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,iFAAiF;IACjF,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,0EAA0E;IACnE,IAAI,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI;IAQrC,6FAA6F;IAC7F,OAAO,CAAC,gBAAgB;yCArEb,oCAAoC;2CAApC,oCAAoC;CAmFhD"}
@@ -0,0 +1,193 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { DatePipe } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ function RealtimeSessionTimelineCardComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
5
+ i0.ɵɵdomElementStart(0, "span", 12);
6
+ i0.ɵɵtext(1);
7
+ i0.ɵɵdomElementEnd();
8
+ } if (rf & 2) {
9
+ const ctx_r0 = i0.ɵɵnextContext();
10
+ i0.ɵɵclassProp("session-card__chip--error", ctx_r0.IsErrorChip)("session-card__chip--live", ctx_r0.IsLiveChip);
11
+ i0.ɵɵadvance();
12
+ i0.ɵɵtextInterpolate(ctx_r0.StatusChip);
13
+ } }
14
+ function RealtimeSessionTimelineCardComponent_Conditional_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵdomElement(0, "i", 15);
16
+ i0.ɵɵtext(1);
17
+ i0.ɵɵpipe(2, "date");
18
+ } if (rf & 2) {
19
+ const ctx_r0 = i0.ɵɵnextContext(2);
20
+ i0.ɵɵadvance();
21
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(2, 1, ctx_r0.Group.EndedAt, ctx_r0.SameDayRange ? "h:mm a" : "MMM d, h:mm a"), " ");
22
+ } }
23
+ function RealtimeSessionTimelineCardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
24
+ i0.ɵɵdomElementStart(0, "span", 13);
25
+ i0.ɵɵtext(1);
26
+ i0.ɵɵpipe(2, "date");
27
+ i0.ɵɵconditionalCreate(3, RealtimeSessionTimelineCardComponent_Conditional_9_Conditional_3_Template, 3, 4);
28
+ i0.ɵɵdomElementEnd();
29
+ i0.ɵɵdomElementStart(4, "span", 14);
30
+ i0.ɵɵtext(5, "\u00B7");
31
+ i0.ɵɵdomElementEnd();
32
+ } if (rf & 2) {
33
+ const ctx_r0 = i0.ɵɵnextContext();
34
+ i0.ɵɵadvance();
35
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(2, 2, ctx_r0.Group.StartedAt, "MMM d, h:mm a"), " ");
36
+ i0.ɵɵadvance(2);
37
+ i0.ɵɵconditional(ctx_r0.Group.EndedAt && ctx_r0.Group.EndedAt !== ctx_r0.Group.StartedAt ? 3 : -1);
38
+ } }
39
+ function RealtimeSessionTimelineCardComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
40
+ i0.ɵɵdomElementStart(0, "div", 9)(1, "span", 16);
41
+ i0.ɵɵtext(2);
42
+ i0.ɵɵdomElementEnd();
43
+ i0.ɵɵtext(3);
44
+ i0.ɵɵdomElementEnd();
45
+ } if (rf & 2) {
46
+ const ctx_r0 = i0.ɵɵnextContext();
47
+ i0.ɵɵadvance(2);
48
+ i0.ɵɵtextInterpolate1("", ctx_r0.Group.LastTurnRole === "User" ? ctx_r0.UserName : "Agent", ":");
49
+ i0.ɵɵadvance();
50
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.Group.LastTurnPreview, " ");
51
+ } }
52
+ /**
53
+ * The ONE timeline element a realtime session collapses to in the standard conversation
54
+ * message list (see `BuildConversationTimeline`): a visually distinct card at the
55
+ * session's chronological position carrying the session identity (broadcast icon +
56
+ * "Realtime session · <agent>"), its time range, a status / close-reason chip when
57
+ * known, the visible-turn count, and a one-line preview of the last turn.
58
+ *
59
+ * The card's **Open** button emits {@link OpenRequested} with the session id; the
60
+ * message list bubbles it up so the chat area can host the existing SESSION REVIEW
61
+ * overlay via `ConversationChatAreaComponent.OpenRealtimeSessionReview` (Resume /
62
+ * Close live inside that overlay, unchanged).
63
+ *
64
+ * Rendered DYNAMICALLY by `MessageListComponent` (same `createComponent` path the
65
+ * message items use) — standalone by design, no module declaration needed.
66
+ */
67
+ export class RealtimeSessionTimelineCardComponent {
68
+ /** The collapsed session block computed from the conversation's stamped detail rows. */
69
+ Group;
70
+ /** Optional session-row enrichment (agent name / status / close reason); null degrades gracefully. */
71
+ Meta = null;
72
+ /** Display name of the signed-in user for the last-turn preview (matches the chat's sender names). */
73
+ UserName = 'You';
74
+ /** Emitted with the `MJ: AI Agent Sessions.ID` when the user asks to open the session review. */
75
+ OpenRequested = new EventEmitter();
76
+ /** Card title: "Realtime session · <agent>" when the agent name is known, else the generic label. */
77
+ get Title() {
78
+ const agent = this.Meta?.AgentName?.trim();
79
+ return agent ? `Realtime session · ${agent}` : 'Realtime session';
80
+ }
81
+ /** Whether the start and end fall on the same calendar day (drives the end-time format). */
82
+ get SameDayRange() {
83
+ const start = this.Group?.StartedAt;
84
+ const end = this.Group?.EndedAt;
85
+ if (!start || !end) {
86
+ return true;
87
+ }
88
+ return start.toDateString() === end.toDateString();
89
+ }
90
+ /**
91
+ * The status chip label, or null to hide the chip entirely:
92
+ * - Closed sessions show the close reason (`Error` / `Explicit` / `Janitor` / `Shutdown`)
93
+ * humanized, falling back to "Closed" for legacy rows without one;
94
+ * - Active sessions show "Live"; Idle shows "Idle";
95
+ * - no meta (lookup unavailable) → no chip.
96
+ */
97
+ get StatusChip() {
98
+ switch (this.Meta?.Status) {
99
+ case 'Closed':
100
+ return this.closeReasonLabel();
101
+ case 'Active':
102
+ return 'Live';
103
+ case 'Idle':
104
+ return 'Idle';
105
+ default:
106
+ return null;
107
+ }
108
+ }
109
+ /** Whether the chip represents an error close (drives the error chip styling). */
110
+ get IsErrorChip() {
111
+ return this.Meta?.Status === 'Closed' && this.Meta?.CloseReason === 'Error';
112
+ }
113
+ /** Whether the chip represents a live session (drives the live chip styling). */
114
+ get IsLiveChip() {
115
+ return this.Meta?.Status === 'Active';
116
+ }
117
+ /** Emits {@link OpenRequested} for the whole-card / Open-button click. */
118
+ Open(event) {
119
+ event?.stopPropagation();
120
+ const sessionId = this.Group?.SessionID;
121
+ if (sessionId) {
122
+ this.OpenRequested.emit(sessionId);
123
+ }
124
+ }
125
+ /** Human label for the session's close reason ("Closed" when the column is null/unknown). */
126
+ closeReasonLabel() {
127
+ switch (this.Meta?.CloseReason) {
128
+ case 'Explicit':
129
+ return 'Ended';
130
+ case 'Error':
131
+ return 'Error';
132
+ case 'Janitor':
133
+ return 'Timed out';
134
+ case 'Shutdown':
135
+ return 'Server shutdown';
136
+ default:
137
+ return 'Closed';
138
+ }
139
+ }
140
+ static ɵfac = function RealtimeSessionTimelineCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeSessionTimelineCardComponent)(); };
141
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeSessionTimelineCardComponent, selectors: [["mj-realtime-session-timeline-card"]], inputs: { Group: "Group", Meta: "Meta", UserName: "UserName" }, outputs: { OpenRequested: "OpenRequested" }, decls: 17, vars: 7, consts: [["role", "group", 1, "session-card", 3, "click"], ["aria-hidden", "true", 1, "session-card__icon"], [1, "fa-solid", "fa-tower-broadcast"], [1, "session-card__body"], [1, "session-card__head"], [1, "session-card__title"], [1, "session-card__chip", 3, "session-card__chip--error", "session-card__chip--live"], [1, "session-card__meta"], [1, "session-card__turns"], [1, "session-card__preview"], ["type", "button", "title", "Open this realtime session in review mode", 1, "session-card__open", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-up-right-from-square"], [1, "session-card__chip"], [1, "session-card__range"], ["aria-hidden", "true", 1, "session-card__dot"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-right-long", "session-card__range-arrow"], [1, "session-card__preview-role"]], template: function RealtimeSessionTimelineCardComponent_Template(rf, ctx) { if (rf & 1) {
142
+ i0.ɵɵdomElementStart(0, "div", 0);
143
+ i0.ɵɵdomListener("click", function RealtimeSessionTimelineCardComponent_Template_div_click_0_listener($event) { return ctx.Open($event); });
144
+ i0.ɵɵdomElementStart(1, "div", 1);
145
+ i0.ɵɵdomElement(2, "i", 2);
146
+ i0.ɵɵdomElementEnd();
147
+ i0.ɵɵdomElementStart(3, "div", 3)(4, "div", 4)(5, "span", 5);
148
+ i0.ɵɵtext(6);
149
+ i0.ɵɵdomElementEnd();
150
+ i0.ɵɵconditionalCreate(7, RealtimeSessionTimelineCardComponent_Conditional_7_Template, 2, 5, "span", 6);
151
+ i0.ɵɵdomElementEnd();
152
+ i0.ɵɵdomElementStart(8, "div", 7);
153
+ i0.ɵɵconditionalCreate(9, RealtimeSessionTimelineCardComponent_Conditional_9_Template, 6, 5);
154
+ i0.ɵɵdomElementStart(10, "span", 8);
155
+ i0.ɵɵtext(11);
156
+ i0.ɵɵdomElementEnd()();
157
+ i0.ɵɵconditionalCreate(12, RealtimeSessionTimelineCardComponent_Conditional_12_Template, 4, 2, "div", 9);
158
+ i0.ɵɵdomElementEnd();
159
+ i0.ɵɵdomElementStart(13, "button", 10);
160
+ i0.ɵɵdomListener("click", function RealtimeSessionTimelineCardComponent_Template_button_click_13_listener($event) { return ctx.Open($event); });
161
+ i0.ɵɵdomElement(14, "i", 11);
162
+ i0.ɵɵdomElementStart(15, "span");
163
+ i0.ɵɵtext(16, "Open");
164
+ i0.ɵɵdomElementEnd()()();
165
+ } if (rf & 2) {
166
+ i0.ɵɵattribute("aria-label", ctx.Title);
167
+ i0.ɵɵadvance(6);
168
+ i0.ɵɵtextInterpolate(ctx.Title);
169
+ i0.ɵɵadvance();
170
+ i0.ɵɵconditional(ctx.StatusChip ? 7 : -1);
171
+ i0.ɵɵadvance(2);
172
+ i0.ɵɵconditional(ctx.Group.StartedAt ? 9 : -1);
173
+ i0.ɵɵadvance(2);
174
+ i0.ɵɵtextInterpolate2("", ctx.Group.TurnCount, " ", ctx.Group.TurnCount === 1 ? "turn" : "turns");
175
+ i0.ɵɵadvance();
176
+ i0.ɵɵconditional(ctx.Group.LastTurnPreview ? 12 : -1);
177
+ } }, dependencies: [DatePipe], styles: ["[_nghost-%COMP%] {\n display: block;\n margin: 12px 0;\n}\n\n\n\n\n.session-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-lg, 12px);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n.session-card[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 45%, var(--mj-border-default));\n}\n\n.session-card__icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n flex-shrink: 0;\n font-size: 15px;\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n}\n\n.session-card__body[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.session-card__head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.session-card__title[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: 13.5px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.session-card__chip[_ngcontent-%COMP%] {\n flex-shrink: 0;\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n padding: 3px 8px;\n border-radius: var(--mj-radius-full, 999px);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n}\n.session-card__chip--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\n}\n.session-card__chip--live[_ngcontent-%COMP%] {\n color: var(--mj-status-success-text);\n background: var(--mj-status-success-bg);\n border-color: var(--mj-status-success-border);\n}\n\n.session-card__meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 3px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n.session-card__range-arrow[_ngcontent-%COMP%] {\n font-size: 10px;\n margin: 0 3px;\n}\n\n.session-card__preview[_ngcontent-%COMP%] {\n margin-top: 5px;\n font-size: 12.5px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.session-card__preview-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n.session-card__open[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n padding: 6px 12px;\n font-size: 12.5px;\n font-weight: 600;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease;\n}\n.session-card__open[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}"] });
178
+ }
179
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeSessionTimelineCardComponent, [{
180
+ type: Component,
181
+ args: [{ standalone: true, selector: 'mj-realtime-session-timeline-card', imports: [DatePipe], template: "<div class=\"session-card\" role=\"group\" [attr.aria-label]=\"Title\" (click)=\"Open($event)\">\n <div class=\"session-card__icon\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-tower-broadcast\"></i>\n </div>\n\n <div class=\"session-card__body\">\n <div class=\"session-card__head\">\n <span class=\"session-card__title\">{{ Title }}</span>\n @if (StatusChip) {\n <span class=\"session-card__chip\"\n [class.session-card__chip--error]=\"IsErrorChip\"\n [class.session-card__chip--live]=\"IsLiveChip\">{{ StatusChip }}</span>\n }\n </div>\n\n <div class=\"session-card__meta\">\n @if (Group.StartedAt) {\n <span class=\"session-card__range\">\n {{ Group.StartedAt | date:'MMM d, h:mm a' }}\n @if (Group.EndedAt && Group.EndedAt !== Group.StartedAt) {\n <i class=\"fa-solid fa-arrow-right-long session-card__range-arrow\" aria-hidden=\"true\"></i>\n {{ Group.EndedAt | date:(SameDayRange ? 'h:mm a' : 'MMM d, h:mm a') }}\n }\n </span>\n <span class=\"session-card__dot\" aria-hidden=\"true\">\u00B7</span>\n }\n <span class=\"session-card__turns\">{{ Group.TurnCount }} {{ Group.TurnCount === 1 ? 'turn' : 'turns' }}</span>\n </div>\n\n @if (Group.LastTurnPreview) {\n <div class=\"session-card__preview\">\n <span class=\"session-card__preview-role\">{{ Group.LastTurnRole === 'User' ? UserName : 'Agent' }}:</span>\n {{ Group.LastTurnPreview }}\n </div>\n }\n </div>\n\n <button type=\"button\" class=\"session-card__open\" (click)=\"Open($event)\"\n title=\"Open this realtime session in review mode\">\n <i class=\"fa-solid fa-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open</span>\n </button>\n</div>\n", styles: [":host {\n display: block;\n margin: 12px 0;\n}\n\n/* A visually distinct block \u2014 clearly NOT a chat bubble: full-row card with a\n brand-tinted broadcast badge, hover affordance, and an explicit Open button. */\n.session-card {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-border-default));\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-lg, 12px);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n.session-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 45%, var(--mj-border-default));\n}\n\n.session-card__icon {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n flex-shrink: 0;\n font-size: 15px;\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n}\n\n.session-card__body {\n flex: 1;\n min-width: 0;\n}\n\n.session-card__head {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.session-card__title {\n font-weight: 700;\n font-size: 13.5px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.session-card__chip {\n flex-shrink: 0;\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n padding: 3px 8px;\n border-radius: var(--mj-radius-full, 999px);\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n}\n.session-card__chip--error {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\n}\n.session-card__chip--live {\n color: var(--mj-status-success-text);\n background: var(--mj-status-success-bg);\n border-color: var(--mj-status-success-border);\n}\n\n.session-card__meta {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 3px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n.session-card__range-arrow {\n font-size: 10px;\n margin: 0 3px;\n}\n\n.session-card__preview {\n margin-top: 5px;\n font-size: 12.5px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.session-card__preview-role {\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n.session-card__open {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n padding: 6px 12px;\n font-size: 12.5px;\n font-weight: 600;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease;\n}\n.session-card__open:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n"] }]
182
+ }], null, { Group: [{
183
+ type: Input,
184
+ args: [{ required: true }]
185
+ }], Meta: [{
186
+ type: Input
187
+ }], UserName: [{
188
+ type: Input
189
+ }], OpenRequested: [{
190
+ type: Output
191
+ }] }); })();
192
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeSessionTimelineCardComponent, { className: "RealtimeSessionTimelineCardComponent", filePath: "src/lib/components/realtime/realtime-session-timeline-card.component.ts", lineNumber: 27 }); })();
193
+ //# sourceMappingURL=realtime-session-timeline-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-session-timeline-card.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-session-timeline-card.component.ts","../../../../src/lib/components/realtime/realtime-session-timeline-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { RealtimeSessionTimelineGroup, RealtimeSessionTimelineMeta } from '../../utils/realtime-session-timeline';\n\n/**\n * The ONE timeline element a realtime session collapses to in the standard conversation\n * message list (see `BuildConversationTimeline`): a visually distinct card at the\n * session's chronological position carrying the session identity (broadcast icon +\n * \"Realtime session · <agent>\"), its time range, a status / close-reason chip when\n * known, the visible-turn count, and a one-line preview of the last turn.\n *\n * The card's **Open** button emits {@link OpenRequested} with the session id; the\n * message list bubbles it up so the chat area can host the existing SESSION REVIEW\n * overlay via `ConversationChatAreaComponent.OpenRealtimeSessionReview` (Resume /\n * Close live inside that overlay, unchanged).\n *\n * Rendered DYNAMICALLY by `MessageListComponent` (same `createComponent` path the\n * message items use) — standalone by design, no module declaration needed.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-session-timeline-card',\n imports: [DatePipe],\n templateUrl: './realtime-session-timeline-card.component.html',\n styleUrl: './realtime-session-timeline-card.component.css'\n})\nexport class RealtimeSessionTimelineCardComponent {\n /** The collapsed session block computed from the conversation's stamped detail rows. */\n @Input({ required: true }) Group!: RealtimeSessionTimelineGroup;\n\n /** Optional session-row enrichment (agent name / status / close reason); null degrades gracefully. */\n @Input() Meta: RealtimeSessionTimelineMeta | null = null;\n\n /** Display name of the signed-in user for the last-turn preview (matches the chat's sender names). */\n @Input() UserName = 'You';\n\n /** Emitted with the `MJ: AI Agent Sessions.ID` when the user asks to open the session review. */\n @Output() OpenRequested = new EventEmitter<string>();\n\n /** Card title: \"Realtime session · <agent>\" when the agent name is known, else the generic label. */\n public get Title(): string {\n const agent = this.Meta?.AgentName?.trim();\n return agent ? `Realtime session · ${agent}` : 'Realtime session';\n }\n\n /** Whether the start and end fall on the same calendar day (drives the end-time format). */\n public get SameDayRange(): boolean {\n const start = this.Group?.StartedAt;\n const end = this.Group?.EndedAt;\n if (!start || !end) {\n return true;\n }\n return start.toDateString() === end.toDateString();\n }\n\n /**\n * The status chip label, or null to hide the chip entirely:\n * - Closed sessions show the close reason (`Error` / `Explicit` / `Janitor` / `Shutdown`)\n * humanized, falling back to \"Closed\" for legacy rows without one;\n * - Active sessions show \"Live\"; Idle shows \"Idle\";\n * - no meta (lookup unavailable) → no chip.\n */\n public get StatusChip(): string | null {\n switch (this.Meta?.Status) {\n case 'Closed':\n return this.closeReasonLabel();\n case 'Active':\n return 'Live';\n case 'Idle':\n return 'Idle';\n default:\n return null;\n }\n }\n\n /** Whether the chip represents an error close (drives the error chip styling). */\n public get IsErrorChip(): boolean {\n return this.Meta?.Status === 'Closed' && this.Meta?.CloseReason === 'Error';\n }\n\n /** Whether the chip represents a live session (drives the live chip styling). */\n public get IsLiveChip(): boolean {\n return this.Meta?.Status === 'Active';\n }\n\n /** Emits {@link OpenRequested} for the whole-card / Open-button click. */\n public Open(event?: MouseEvent): void {\n event?.stopPropagation();\n const sessionId = this.Group?.SessionID;\n if (sessionId) {\n this.OpenRequested.emit(sessionId);\n }\n }\n\n /** Human label for the session's close reason (\"Closed\" when the column is null/unknown). */\n private closeReasonLabel(): string {\n switch (this.Meta?.CloseReason) {\n case 'Explicit':\n return 'Ended';\n case 'Error':\n return 'Error';\n case 'Janitor':\n return 'Timed out';\n case 'Shutdown':\n return 'Server shutdown';\n default:\n return 'Closed';\n }\n }\n}\n","<div class=\"session-card\" role=\"group\" [attr.aria-label]=\"Title\" (click)=\"Open($event)\">\n <div class=\"session-card__icon\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-tower-broadcast\"></i>\n </div>\n\n <div class=\"session-card__body\">\n <div class=\"session-card__head\">\n <span class=\"session-card__title\">{{ Title }}</span>\n @if (StatusChip) {\n <span class=\"session-card__chip\"\n [class.session-card__chip--error]=\"IsErrorChip\"\n [class.session-card__chip--live]=\"IsLiveChip\">{{ StatusChip }}</span>\n }\n </div>\n\n <div class=\"session-card__meta\">\n @if (Group.StartedAt) {\n <span class=\"session-card__range\">\n {{ Group.StartedAt | date:'MMM d, h:mm a' }}\n @if (Group.EndedAt && Group.EndedAt !== Group.StartedAt) {\n <i class=\"fa-solid fa-arrow-right-long session-card__range-arrow\" aria-hidden=\"true\"></i>\n {{ Group.EndedAt | date:(SameDayRange ? 'h:mm a' : 'MMM d, h:mm a') }}\n }\n </span>\n <span class=\"session-card__dot\" aria-hidden=\"true\">·</span>\n }\n <span class=\"session-card__turns\">{{ Group.TurnCount }} {{ Group.TurnCount === 1 ? 'turn' : 'turns' }}</span>\n </div>\n\n @if (Group.LastTurnPreview) {\n <div class=\"session-card__preview\">\n <span class=\"session-card__preview-role\">{{ Group.LastTurnRole === 'User' ? UserName : 'Agent' }}:</span>\n {{ Group.LastTurnPreview }}\n </div>\n }\n </div>\n\n <button type=\"button\" class=\"session-card__open\" (click)=\"Open($event)\"\n title=\"Open this realtime session in review mode\">\n <i class=\"fa-solid fa-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open</span>\n </button>\n</div>\n"]}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Framework-free helpers for the call overlay's SURFACE PANEL width preference —
3
+ * the user-dragged width of the right tabbed panel, persisted per-user via
4
+ * `UserInfoEngine` (key {@link SURFACE_PANEL_PREF_KEY}, JSON `{ "width": number }`).
5
+ *
6
+ * Kept free of Angular imports so the clamp / parse / serialize rules are
7
+ * unit-testable in isolation (plain-node vitest).
8
+ */
9
+ /** `MJ: User Settings` key for the surface panel width preference (versioned shape). */
10
+ export declare const SURFACE_PANEL_PREF_KEY = "mj.realtimeVoice.surfacePanel.v1";
11
+ /** The narrowest the user may drag the panel. */
12
+ export declare const SURFACE_PANEL_MIN_WIDTH = 340;
13
+ /** The widest the panel may grow, as a fraction of the overlay's width. */
14
+ export declare const SURFACE_PANEL_MAX_FRACTION = 0.7;
15
+ /** The collapsed slim-strip width (the chevron rail the panel collapses to). */
16
+ export declare const SURFACE_PANEL_COLLAPSED_WIDTH = 40;
17
+ /** Default panel width (Activity tab focused, user never resized). */
18
+ export declare const SURFACE_PANEL_DEFAULT_WIDTH = 308;
19
+ /** Wide-tier floor: a focused content tab widens the panel to at least this. */
20
+ export declare const SURFACE_PANEL_WIDE_MIN_WIDTH = 380;
21
+ /** Wide-tier ceiling: the auto-widened panel never exceeds this. */
22
+ export declare const SURFACE_PANEL_WIDE_MAX_WIDTH = 640;
23
+ /** Wide-tier preferred size, as a fraction of the overlay's width. */
24
+ export declare const SURFACE_PANEL_WIDE_FRACTION = 0.44;
25
+ /**
26
+ * The panel's DEFAULT width when the user has never dragged it: the Activity tier
27
+ * ({@link SURFACE_PANEL_DEFAULT_WIDTH}) normally, auto-widening to
28
+ * `clamp(380px, 44% of the overlay, 640px)` while a content tab (artifact / channel)
29
+ * is focused. An unknown overlay width (`<= 0`, `NaN`) resolves the wide tier to its
30
+ * floor.
31
+ */
32
+ export declare function DefaultSurfacePanelWidth(wide: boolean, overlayWidth: number): number;
33
+ /** The persisted shape of the surface panel preference. */
34
+ export interface SurfacePanelPref {
35
+ /** The user's explicit panel width in px. */
36
+ Width: number;
37
+ }
38
+ /**
39
+ * Clamps a candidate panel width to `[SURFACE_PANEL_MIN_WIDTH, 70% of the overlay]`.
40
+ * When the overlay width is unknown / not yet measurable (`<= 0`, `NaN`), only the
41
+ * minimum is enforced. The upper bound never drops below the minimum (tiny overlays
42
+ * resolve to the minimum width).
43
+ */
44
+ export declare function ClampSurfacePanelWidth(width: number, overlayWidth: number): number;
45
+ /**
46
+ * Pointer movement (px) below which a completed resize-handle gesture is treated as a
47
+ * bare CLICK rather than a drag — clicks must never move, adopt, or persist a width.
48
+ */
49
+ export declare const SURFACE_PANEL_DRAG_CLICK_TOLERANCE = 3;
50
+ /**
51
+ * The live panel width while the resize handle is being dragged. The panel sits on the
52
+ * RIGHT of the overlay, so moving the pointer LEFT grows it:
53
+ * `startWidth + (startX - clientX)`, clamped to the standard
54
+ * [{@link SURFACE_PANEL_MIN_WIDTH}, 70% of the overlay] band.
55
+ */
56
+ export declare function SurfacePanelDragWidth(startWidth: number, startX: number, clientX: number, overlayWidth: number): number;
57
+ /**
58
+ * Click-vs-drag guard: a completed handle gesture only counts as a DRAG (adopt + persist
59
+ * the resulting width) when the pointer moved at least
60
+ * {@link SURFACE_PANEL_DRAG_CLICK_TOLERANCE}px horizontally. Non-finite coordinates
61
+ * (degenerate events) are never a drag.
62
+ */
63
+ export declare function IsSurfacePanelDrag(startX: number, endX: number): boolean;
64
+ /**
65
+ * Parses a raw persisted preference value. Returns `null` (no preference) for
66
+ * missing / blank / malformed JSON, non-object payloads, and non-finite or
67
+ * non-positive widths — a reset is stored as `{ "width": null }`, which also
68
+ * parses to `null`. Never throws.
69
+ */
70
+ export declare function ParseSurfacePanelPref(raw: string | null | undefined): SurfacePanelPref | null;
71
+ /**
72
+ * Serializes the preference for persistence. `null` serializes a reset
73
+ * (`{ "width": null }`) — written instead of a delete so a pending debounced
74
+ * width write can never resurrect the old value.
75
+ */
76
+ export declare function SerializeSurfacePanelPref(width: number | null): string;
77
+ //# sourceMappingURL=realtime-surface-panel-prefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-surface-panel-prefs.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-panel-prefs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wFAAwF;AACxF,eAAO,MAAM,sBAAsB,qCAAqC,CAAC;AAEzE,iDAAiD;AACjD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,gFAAgF;AAChF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,sEAAsE;AACtE,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,oEAAoE;AACpE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,sEAAsE;AACtE,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAWpF;AAED,2DAA2D;AAC3D,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CASlF;AAED;;;GAGG;AACH,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvH;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,GAAG,IAAI,CAiB7F;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEtE"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Framework-free helpers for the call overlay's SURFACE PANEL width preference —
3
+ * the user-dragged width of the right tabbed panel, persisted per-user via
4
+ * `UserInfoEngine` (key {@link SURFACE_PANEL_PREF_KEY}, JSON `{ "width": number }`).
5
+ *
6
+ * Kept free of Angular imports so the clamp / parse / serialize rules are
7
+ * unit-testable in isolation (plain-node vitest).
8
+ */
9
+ /** `MJ: User Settings` key for the surface panel width preference (versioned shape). */
10
+ export const SURFACE_PANEL_PREF_KEY = 'mj.realtimeVoice.surfacePanel.v1';
11
+ /** The narrowest the user may drag the panel. */
12
+ export const SURFACE_PANEL_MIN_WIDTH = 340;
13
+ /** The widest the panel may grow, as a fraction of the overlay's width. */
14
+ export const SURFACE_PANEL_MAX_FRACTION = 0.7;
15
+ /** The collapsed slim-strip width (the chevron rail the panel collapses to). */
16
+ export const SURFACE_PANEL_COLLAPSED_WIDTH = 40;
17
+ /** Default panel width (Activity tab focused, user never resized). */
18
+ export const SURFACE_PANEL_DEFAULT_WIDTH = 308;
19
+ /** Wide-tier floor: a focused content tab widens the panel to at least this. */
20
+ export const SURFACE_PANEL_WIDE_MIN_WIDTH = 380;
21
+ /** Wide-tier ceiling: the auto-widened panel never exceeds this. */
22
+ export const SURFACE_PANEL_WIDE_MAX_WIDTH = 640;
23
+ /** Wide-tier preferred size, as a fraction of the overlay's width. */
24
+ export const SURFACE_PANEL_WIDE_FRACTION = 0.44;
25
+ /**
26
+ * The panel's DEFAULT width when the user has never dragged it: the Activity tier
27
+ * ({@link SURFACE_PANEL_DEFAULT_WIDTH}) normally, auto-widening to
28
+ * `clamp(380px, 44% of the overlay, 640px)` while a content tab (artifact / channel)
29
+ * is focused. An unknown overlay width (`<= 0`, `NaN`) resolves the wide tier to its
30
+ * floor.
31
+ */
32
+ export function DefaultSurfacePanelWidth(wide, overlayWidth) {
33
+ if (!wide) {
34
+ return SURFACE_PANEL_DEFAULT_WIDTH;
35
+ }
36
+ if (!Number.isFinite(overlayWidth) || overlayWidth <= 0) {
37
+ return SURFACE_PANEL_WIDE_MIN_WIDTH;
38
+ }
39
+ return Math.min(Math.max(SURFACE_PANEL_WIDE_MIN_WIDTH, overlayWidth * SURFACE_PANEL_WIDE_FRACTION), SURFACE_PANEL_WIDE_MAX_WIDTH);
40
+ }
41
+ /**
42
+ * Clamps a candidate panel width to `[SURFACE_PANEL_MIN_WIDTH, 70% of the overlay]`.
43
+ * When the overlay width is unknown / not yet measurable (`<= 0`, `NaN`), only the
44
+ * minimum is enforced. The upper bound never drops below the minimum (tiny overlays
45
+ * resolve to the minimum width).
46
+ */
47
+ export function ClampSurfacePanelWidth(width, overlayWidth) {
48
+ const min = SURFACE_PANEL_MIN_WIDTH;
49
+ if (!Number.isFinite(width)) {
50
+ return min;
51
+ }
52
+ const max = Number.isFinite(overlayWidth) && overlayWidth > 0
53
+ ? Math.max(min, overlayWidth * SURFACE_PANEL_MAX_FRACTION)
54
+ : Number.POSITIVE_INFINITY;
55
+ return Math.min(Math.max(width, min), max);
56
+ }
57
+ /**
58
+ * Pointer movement (px) below which a completed resize-handle gesture is treated as a
59
+ * bare CLICK rather than a drag — clicks must never move, adopt, or persist a width.
60
+ */
61
+ export const SURFACE_PANEL_DRAG_CLICK_TOLERANCE = 3;
62
+ /**
63
+ * The live panel width while the resize handle is being dragged. The panel sits on the
64
+ * RIGHT of the overlay, so moving the pointer LEFT grows it:
65
+ * `startWidth + (startX - clientX)`, clamped to the standard
66
+ * [{@link SURFACE_PANEL_MIN_WIDTH}, 70% of the overlay] band.
67
+ */
68
+ export function SurfacePanelDragWidth(startWidth, startX, clientX, overlayWidth) {
69
+ return ClampSurfacePanelWidth(startWidth + (startX - clientX), overlayWidth);
70
+ }
71
+ /**
72
+ * Click-vs-drag guard: a completed handle gesture only counts as a DRAG (adopt + persist
73
+ * the resulting width) when the pointer moved at least
74
+ * {@link SURFACE_PANEL_DRAG_CLICK_TOLERANCE}px horizontally. Non-finite coordinates
75
+ * (degenerate events) are never a drag.
76
+ */
77
+ export function IsSurfacePanelDrag(startX, endX) {
78
+ return Number.isFinite(startX) && Number.isFinite(endX)
79
+ && Math.abs(endX - startX) >= SURFACE_PANEL_DRAG_CLICK_TOLERANCE;
80
+ }
81
+ /**
82
+ * Parses a raw persisted preference value. Returns `null` (no preference) for
83
+ * missing / blank / malformed JSON, non-object payloads, and non-finite or
84
+ * non-positive widths — a reset is stored as `{ "width": null }`, which also
85
+ * parses to `null`. Never throws.
86
+ */
87
+ export function ParseSurfacePanelPref(raw) {
88
+ if (!raw) {
89
+ return null;
90
+ }
91
+ try {
92
+ const parsed = JSON.parse(raw);
93
+ if (parsed === null || typeof parsed !== 'object') {
94
+ return null;
95
+ }
96
+ const width = parsed.width;
97
+ if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {
98
+ return null;
99
+ }
100
+ return { Width: width };
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ /**
107
+ * Serializes the preference for persistence. `null` serializes a reset
108
+ * (`{ "width": null }`) — written instead of a delete so a pending debounced
109
+ * width write can never resurrect the old value.
110
+ */
111
+ export function SerializeSurfacePanelPref(width) {
112
+ return JSON.stringify({ width });
113
+ }
114
+ //# sourceMappingURL=realtime-surface-panel-prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-surface-panel-prefs.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-panel-prefs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Framework-free helpers for the call overlay's SURFACE PANEL width preference —\n * the user-dragged width of the right tabbed panel, persisted per-user via\n * `UserInfoEngine` (key {@link SURFACE_PANEL_PREF_KEY}, JSON `{ \"width\": number }`).\n *\n * Kept free of Angular imports so the clamp / parse / serialize rules are\n * unit-testable in isolation (plain-node vitest).\n */\n\n/** `MJ: User Settings` key for the surface panel width preference (versioned shape). */\nexport const SURFACE_PANEL_PREF_KEY = 'mj.realtimeVoice.surfacePanel.v1';\n\n/** The narrowest the user may drag the panel. */\nexport const SURFACE_PANEL_MIN_WIDTH = 340;\n\n/** The widest the panel may grow, as a fraction of the overlay's width. */\nexport const SURFACE_PANEL_MAX_FRACTION = 0.7;\n\n/** The collapsed slim-strip width (the chevron rail the panel collapses to). */\nexport const SURFACE_PANEL_COLLAPSED_WIDTH = 40;\n\n/** Default panel width (Activity tab focused, user never resized). */\nexport const SURFACE_PANEL_DEFAULT_WIDTH = 308;\n\n/** Wide-tier floor: a focused content tab widens the panel to at least this. */\nexport const SURFACE_PANEL_WIDE_MIN_WIDTH = 380;\n\n/** Wide-tier ceiling: the auto-widened panel never exceeds this. */\nexport const SURFACE_PANEL_WIDE_MAX_WIDTH = 640;\n\n/** Wide-tier preferred size, as a fraction of the overlay's width. */\nexport const SURFACE_PANEL_WIDE_FRACTION = 0.44;\n\n/**\n * The panel's DEFAULT width when the user has never dragged it: the Activity tier\n * ({@link SURFACE_PANEL_DEFAULT_WIDTH}) normally, auto-widening to\n * `clamp(380px, 44% of the overlay, 640px)` while a content tab (artifact / channel)\n * is focused. An unknown overlay width (`<= 0`, `NaN`) resolves the wide tier to its\n * floor.\n */\nexport function DefaultSurfacePanelWidth(wide: boolean, overlayWidth: number): number {\n if (!wide) {\n return SURFACE_PANEL_DEFAULT_WIDTH;\n }\n if (!Number.isFinite(overlayWidth) || overlayWidth <= 0) {\n return SURFACE_PANEL_WIDE_MIN_WIDTH;\n }\n return Math.min(\n Math.max(SURFACE_PANEL_WIDE_MIN_WIDTH, overlayWidth * SURFACE_PANEL_WIDE_FRACTION),\n SURFACE_PANEL_WIDE_MAX_WIDTH\n );\n}\n\n/** The persisted shape of the surface panel preference. */\nexport interface SurfacePanelPref {\n /** The user's explicit panel width in px. */\n Width: number;\n}\n\n/**\n * Clamps a candidate panel width to `[SURFACE_PANEL_MIN_WIDTH, 70% of the overlay]`.\n * When the overlay width is unknown / not yet measurable (`<= 0`, `NaN`), only the\n * minimum is enforced. The upper bound never drops below the minimum (tiny overlays\n * resolve to the minimum width).\n */\nexport function ClampSurfacePanelWidth(width: number, overlayWidth: number): number {\n const min = SURFACE_PANEL_MIN_WIDTH;\n if (!Number.isFinite(width)) {\n return min;\n }\n const max = Number.isFinite(overlayWidth) && overlayWidth > 0\n ? Math.max(min, overlayWidth * SURFACE_PANEL_MAX_FRACTION)\n : Number.POSITIVE_INFINITY;\n return Math.min(Math.max(width, min), max);\n}\n\n/**\n * Pointer movement (px) below which a completed resize-handle gesture is treated as a\n * bare CLICK rather than a drag — clicks must never move, adopt, or persist a width.\n */\nexport const SURFACE_PANEL_DRAG_CLICK_TOLERANCE = 3;\n\n/**\n * The live panel width while the resize handle is being dragged. The panel sits on the\n * RIGHT of the overlay, so moving the pointer LEFT grows it:\n * `startWidth + (startX - clientX)`, clamped to the standard\n * [{@link SURFACE_PANEL_MIN_WIDTH}, 70% of the overlay] band.\n */\nexport function SurfacePanelDragWidth(startWidth: number, startX: number, clientX: number, overlayWidth: number): number {\n return ClampSurfacePanelWidth(startWidth + (startX - clientX), overlayWidth);\n}\n\n/**\n * Click-vs-drag guard: a completed handle gesture only counts as a DRAG (adopt + persist\n * the resulting width) when the pointer moved at least\n * {@link SURFACE_PANEL_DRAG_CLICK_TOLERANCE}px horizontally. Non-finite coordinates\n * (degenerate events) are never a drag.\n */\nexport function IsSurfacePanelDrag(startX: number, endX: number): boolean {\n return Number.isFinite(startX) && Number.isFinite(endX)\n && Math.abs(endX - startX) >= SURFACE_PANEL_DRAG_CLICK_TOLERANCE;\n}\n\n/**\n * Parses a raw persisted preference value. Returns `null` (no preference) for\n * missing / blank / malformed JSON, non-object payloads, and non-finite or\n * non-positive widths — a reset is stored as `{ \"width\": null }`, which also\n * parses to `null`. Never throws.\n */\nexport function ParseSurfacePanelPref(raw: string | null | undefined): SurfacePanelPref | null {\n if (!raw) {\n return null;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed === null || typeof parsed !== 'object') {\n return null;\n }\n const width = (parsed as { width?: unknown }).width;\n if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {\n return null;\n }\n return { Width: width };\n } catch {\n return null;\n }\n}\n\n/**\n * Serializes the preference for persistence. `null` serializes a reset\n * (`{ \"width\": null }`) — written instead of a delete so a pending debounced\n * width write can never resurrect the old value.\n */\nexport function SerializeSurfacePanelPref(width: number | null): string {\n return JSON.stringify({ width });\n}\n"]}