@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,851 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, NgZone, Output, ViewChild, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@memberjunction/ng-shared-generic";
6
+ const _c0 = ["frameCanvas"];
7
+ const _c1 = ["cursorCanvas"];
8
+ function RemoteBrowserSurfaceComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
9
+ i0.ɵɵelementStart(0, "span", 7);
10
+ i0.ɵɵelement(1, "i", 12);
11
+ i0.ɵɵtext(2, " You're driving ");
12
+ i0.ɵɵelementEnd();
13
+ } }
14
+ function RemoteBrowserSurfaceComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
15
+ const _r1 = i0.ɵɵgetCurrentView();
16
+ i0.ɵɵelementStart(0, "button", 13);
17
+ i0.ɵɵlistener("click", function RemoteBrowserSurfaceComponent_Conditional_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleAudioMuted()); });
18
+ i0.ɵɵelement(1, "i", 14);
19
+ i0.ɵɵelementEnd();
20
+ } if (rf & 2) {
21
+ const ctx_r1 = i0.ɵɵnextContext();
22
+ i0.ɵɵclassProp("rb-speaker--muted", ctx_r1.AudioMuted);
23
+ i0.ɵɵproperty("title", ctx_r1.AudioMuted ? "Unmute browser audio" : "Mute browser audio");
24
+ i0.ɵɵattribute("aria-pressed", !ctx_r1.AudioMuted)("aria-label", ctx_r1.AudioMuted ? "Unmute browser audio" : "Mute browser audio");
25
+ i0.ɵɵadvance();
26
+ i0.ɵɵclassProp("fa-volume-high", !ctx_r1.AudioMuted)("fa-volume-xmark", ctx_r1.AudioMuted);
27
+ } }
28
+ function RemoteBrowserSurfaceComponent_Conditional_10_Conditional_3_Template(rf, ctx) { if (rf & 1) {
29
+ i0.ɵɵelement(0, "canvas", 17, 1);
30
+ } }
31
+ function RemoteBrowserSurfaceComponent_Conditional_10_Conditional_4_Template(rf, ctx) { if (rf & 1) {
32
+ i0.ɵɵelementStart(0, "div", 11);
33
+ i0.ɵɵelement(1, "mj-loading", 18);
34
+ i0.ɵɵelementEnd();
35
+ } }
36
+ function RemoteBrowserSurfaceComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
37
+ i0.ɵɵelementStart(0, "div", 15);
38
+ i0.ɵɵelement(1, "canvas", 16, 0);
39
+ i0.ɵɵconditionalCreate(3, RemoteBrowserSurfaceComponent_Conditional_10_Conditional_3_Template, 2, 0, "canvas", 17);
40
+ i0.ɵɵelementEnd();
41
+ i0.ɵɵconditionalCreate(4, RemoteBrowserSurfaceComponent_Conditional_10_Conditional_4_Template, 2, 0, "div", 11);
42
+ } if (rf & 2) {
43
+ const ctx_r1 = i0.ɵɵnextContext();
44
+ i0.ɵɵclassProp("rb-hidden", !ctx_r1.HasFrame);
45
+ i0.ɵɵadvance();
46
+ i0.ɵɵclassProp("rb-screenshot--interactive", ctx_r1.CanTakeOver);
47
+ i0.ɵɵadvance(2);
48
+ i0.ɵɵconditional(ctx_r1.CanTakeOver ? 3 : -1);
49
+ i0.ɵɵadvance();
50
+ i0.ɵɵconditional(!ctx_r1.HasFrame ? 4 : -1);
51
+ } }
52
+ function RemoteBrowserSurfaceComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
53
+ i0.ɵɵelement(0, "img", 10);
54
+ } if (rf & 2) {
55
+ const ctx_r1 = i0.ɵɵnextContext();
56
+ i0.ɵɵproperty("src", ctx_r1.ScreenshotDataUrl, i0.ɵɵsanitizeUrl);
57
+ } }
58
+ function RemoteBrowserSurfaceComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
59
+ i0.ɵɵelementStart(0, "div", 11);
60
+ i0.ɵɵelement(1, "mj-loading", 18);
61
+ i0.ɵɵelementEnd();
62
+ } }
63
+ /** How often the surface polls the server for a fresh page screenshot while bound (~1.4 fps). */
64
+ const SNAPSHOT_POLL_MS = 700;
65
+ /** Min interval between forwarded pointer-move samples during takeover (~20 moves/sec). */
66
+ const POINTER_MOVE_THROTTLE_MS = 50;
67
+ /** Min interval between forwarded scroll samples during takeover; the deltas coalesce between sends (~25/sec). */
68
+ const SCROLL_THROTTLE_MS = 40;
69
+ /** Radius (px) of the synthetic cursor ring drawn on the overlay so the user can see their pointer. */
70
+ const SYNTHETIC_CURSOR_RADIUS = 6;
71
+ /**
72
+ * Keys forwarded into the page during takeover even though they aren't single printable characters —
73
+ * navigation/editing keys the page (not the host app) should receive. `preventDefault` is applied only to
74
+ * forwarded keys so the host app's own shortcuts on un-forwarded keys still work.
75
+ */
76
+ const FORWARDED_CONTROL_KEYS = new Set([
77
+ 'Enter', 'Tab', 'Backspace', 'Delete', 'Escape',
78
+ 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight',
79
+ 'Home', 'End', 'PageUp', 'PageDown',
80
+ ]);
81
+ /**
82
+ * The modifier keys themselves — pressing one alone is never forwarded as a key (it only rides as a
83
+ * modifier on the NEXT non-modifier key / click), so the page never receives a lone `'Shift'` keypress.
84
+ */
85
+ const MODIFIER_KEYS = new Set(['Shift', 'Control', 'Alt', 'Meta', 'CapsLock']);
86
+ /**
87
+ * Maps a display-space pointer position on the live canvas to the server browser's VIEWPORT pixel space.
88
+ *
89
+ * The canvas's internal resolution (`canvasWidth`/`canvasHeight`, set from each pushed frame) IS the
90
+ * viewport pixel space; the canvas is displayed scaled to its bounding rect. So a display point maps as
91
+ * `vx = (clientX - rect.left) / rect.width * canvasWidth` (and likewise for y), rounded to ints. Returns
92
+ * `null` for a zero-size rect or un-sized canvas (divide-by-zero / not-ready guard).
93
+ *
94
+ * Pure + framework-free so it's unit-testable without a DOM.
95
+ *
96
+ * @param clientX The pointer's viewport X in the DOM (`event.clientX`).
97
+ * @param clientY The pointer's viewport Y in the DOM (`event.clientY`).
98
+ * @param rect The canvas's bounding rect (`getBoundingClientRect()`).
99
+ * @param canvasWidth The canvas's internal pixel width (= frame/viewport width).
100
+ * @param canvasHeight The canvas's internal pixel height (= frame/viewport height).
101
+ * @returns Integer viewport coordinates, or `null` when mapping isn't possible.
102
+ */
103
+ export function MapToViewportCoords(clientX, clientY, rect, canvasWidth, canvasHeight) {
104
+ if (rect.width <= 0 || rect.height <= 0 || canvasWidth <= 0 || canvasHeight <= 0) {
105
+ return null;
106
+ }
107
+ const x = Math.round((clientX - rect.left) / rect.width * canvasWidth);
108
+ const y = Math.round((clientY - rect.top) / rect.height * canvasHeight);
109
+ return { x, y };
110
+ }
111
+ /**
112
+ * LIVE REMOTE-BROWSER surface (`mj-realtime-remote-browser-surface`) — the Browser channel
113
+ * tab's pane. It renders the SERVER-hosted browser the agent drives: a refreshing screenshot
114
+ * `<img>` with the current URL above it and a small "live" indicator. The agent's
115
+ * `browser_*` tools mutate the page through the channel plugin; this surface only PERCEIVES
116
+ * it, polling its {@link Fetch} callback every {@link SNAPSHOT_POLL_MS} ms while bound.
117
+ *
118
+ * The surface is transport-agnostic — it never touches GraphQL directly. The channel plugin
119
+ * wires the {@link Fetch} callback (closing over the session id + provider) in `BindSurface`
120
+ * before the surface's first change detection, so the `ngOnInit` poll has it. Polling stops
121
+ * in `ngOnDestroy` (pane collapsed / overlay torn down) so no traffic continues after unbind.
122
+ * View-only in v1 — there is no takeover input.
123
+ *
124
+ * ### Two render paths: pushed screencast (preferred) vs. snapshot poll (fallback)
125
+ * When the backend advertises the `ScreenStreaming` capability, the server PUSHES encoded CDP
126
+ * frames and the channel plugin sets {@link Streaming} = `true`. In that mode the surface paints
127
+ * each frame onto a `<canvas>` via {@link RenderFrame} and DOES NOT start the poll. When streaming
128
+ * is off (capability absent or start failed) the original behavior is unchanged: the surface polls
129
+ * {@link Fetch} every {@link SNAPSHOT_POLL_MS} ms and renders the screenshot `<img>`.
130
+ */
131
+ export class RemoteBrowserSurfaceComponent {
132
+ /** Snapshot fetcher supplied by the channel plugin (closes over the session id + provider). */
133
+ Fetch = null;
134
+ /**
135
+ * Whether the server is PUSHING live screencast frames for this session (the backend advertised the
136
+ * `ScreenStreaming` capability and the start succeeded). When `true` the surface paints pushed frames
137
+ * onto its `<canvas>` via {@link RenderFrame} and does NOT poll; when `false` it uses the snapshot
138
+ * `<img>` poll fallback. Set by the channel plugin in `BindSurface` from the start-screencast result.
139
+ *
140
+ * The start-screencast result is async, so this may flip to `true` AFTER `ngOnInit` has already begun
141
+ * polling — the setter tears the poll down in that case so the two render paths never run at once.
142
+ */
143
+ set Streaming(value) {
144
+ if (value === this._streaming) {
145
+ return;
146
+ }
147
+ this._streaming = value;
148
+ if (value) {
149
+ // Late flip after the poll-fallback already started: stop polling, switch to canvas frames.
150
+ this.stopPolling();
151
+ this.zone.run(() => this.cdr.markForCheck());
152
+ }
153
+ // Takeover only attaches on the canvas path — (de)attach as streaming flips.
154
+ this.syncTakeoverListeners();
155
+ }
156
+ get Streaming() {
157
+ return this._streaming;
158
+ }
159
+ _streaming = false;
160
+ /**
161
+ * Whether HUMAN TAKEOVER is enabled — the user watching the live view can click/type into the page and
162
+ * those events are relayed into the server browser (Collaborative control). Takeover only attaches to the
163
+ * canvas render path (pushed screencast); the `<img>` poll fallback stays view-only. When enabled while
164
+ * already streaming the setter attaches listeners; flipping it off (or streaming off) detaches them.
165
+ */
166
+ set Interactive(value) {
167
+ if (value === this._interactive) {
168
+ return;
169
+ }
170
+ this._interactive = value;
171
+ this.syncTakeoverListeners();
172
+ this.zone.run(() => this.cdr.markForCheck());
173
+ }
174
+ get Interactive() {
175
+ return this._interactive;
176
+ }
177
+ _interactive = false;
178
+ /** Emits each human-takeover input (pointer move/click, key) the user performs on the live canvas. */
179
+ HumanInput = new EventEmitter();
180
+ /**
181
+ * Whether the live tab-audio stream is available — the channel sets this `true` when the server confirms
182
+ * it is pushing audio. Drives whether the speaker toggle renders in the live-view bar.
183
+ */
184
+ AudioAvailable = false;
185
+ /**
186
+ * Whether tab audio is currently muted. Two-way: the channel sets the initial value (un-muted when audio
187
+ * starts) and the toggle updates it; {@link AudioMutedChange} relays each user change to the channel,
188
+ * which mutes/unmutes the player.
189
+ */
190
+ AudioMuted = false;
191
+ /** Emits the new muted state each time the user toggles the speaker (two-way `AudioMuted`). */
192
+ AudioMutedChange = new EventEmitter();
193
+ /** Toggles the speaker mute state and relays it to the channel (which mutes/unmutes the audio player). */
194
+ ToggleAudioMuted() {
195
+ this.AudioMuted = !this.AudioMuted;
196
+ this.AudioMutedChange.emit(this.AudioMuted);
197
+ }
198
+ /** True when takeover is both enabled AND on the canvas path — drives the cursor + "driving" pill. */
199
+ get CanTakeOver() {
200
+ return this._interactive && this._streaming;
201
+ }
202
+ /**
203
+ * True while the user is actively driving the remote browser with the keyboard — the takeover canvas
204
+ * holds focus. The host overlay reads this to stand down its own global keyboard shortcuts (e.g.
205
+ * T-to-type opening the local composer) so keystrokes go to the remote page, not the local input.
206
+ */
207
+ get IsCapturingInput() {
208
+ return this.surfaceFocused && this.CanTakeOver;
209
+ }
210
+ /** The current screenshot as a `data:` URL, or `null` before the first snapshot arrives. */
211
+ ScreenshotDataUrl = null;
212
+ /** The current page URL reported by the server, or `null` when none. */
213
+ CurrentUrl = null;
214
+ /** Whether at least one pushed screencast frame has been painted (drives the canvas placeholder). */
215
+ HasFrame = false;
216
+ /** The canvas the pushed screencast frames are painted onto (present only while {@link Streaming}). */
217
+ frameCanvas;
218
+ /** The transparent overlay the synthetic cursor is drawn onto (present only while {@link CanTakeOver}). */
219
+ cursorCanvas;
220
+ /** Whether at least one screenshot OR frame has been rendered (drives the "Live" indicator). */
221
+ get HasSnapshot() {
222
+ return this.ScreenshotDataUrl !== null || this.HasFrame;
223
+ }
224
+ cdr = inject(ChangeDetectorRef);
225
+ zone = inject(NgZone);
226
+ /** Active poll timer; `null` when polling is stopped. */
227
+ pollTimer = null;
228
+ /** Guards against overlapping polls when a request runs longer than the interval. */
229
+ polling = false;
230
+ /** Set on destroy so an in-flight poll's late resolution doesn't touch a torn-down view. */
231
+ destroyed = false;
232
+ /** Reused decode target for pushed frames — avoids allocating an `Image` per frame. */
233
+ frameImage = new Image();
234
+ /** The most recent un-painted frame data URL, drained on the next animation frame (drop-old coalescing). */
235
+ pendingFrameDataUrl = null;
236
+ /** True while a paint is scheduled, so rapid frames coalesce to one `requestAnimationFrame`. */
237
+ framePaintScheduled = false;
238
+ /** The canvas element takeover listeners are currently bound to, or `null` when detached. */
239
+ takeoverCanvas = null;
240
+ /** Timestamp (ms) of the last forwarded pointer-move, for throttling the high-frequency stream. */
241
+ lastPointerMoveAt = 0;
242
+ /** Timestamp (ms) of the last forwarded scroll, for throttling the high-frequency wheel stream. */
243
+ lastScrollAt = 0;
244
+ /** Horizontal wheel delta accumulated since the last forwarded scroll (coalesced across throttled events). */
245
+ pendingScrollDeltaX = 0;
246
+ /** Vertical wheel delta accumulated since the last forwarded scroll (coalesced across throttled events). */
247
+ pendingScrollDeltaY = 0;
248
+ /** Last canvas-relative mouse position in VIEWPORT pixel space, or `null` when the pointer is off-canvas. */
249
+ cursorViewportPoint = null;
250
+ /** True while a synthetic-cursor repaint is queued, so rapid moves coalesce to one `requestAnimationFrame`. */
251
+ cursorPaintScheduled = false;
252
+ /**
253
+ * True while the user is mid-drag on the canvas (a `mousedown` not yet released) — drives forwarding
254
+ * intermediate moves as a drag and emitting the closing `pointer-up`. Click-drag text selection relies on
255
+ * this so the drag relays as down → moves → up rather than a single discrete click.
256
+ */
257
+ dragging = false;
258
+ /**
259
+ * True when the most recent `mousedown`→`mouseup` actually MOVED (a real drag), so the synthetic `click`
260
+ * the browser fires right after should be suppressed — the drag's down/move/up already conveyed the intent,
261
+ * and a trailing click would collapse a just-made text selection.
262
+ */
263
+ suppressNextClick = false;
264
+ /** Viewport point of the active drag's mousedown, used to tell a real drag from a stationary click. */
265
+ dragStartPoint = null;
266
+ /**
267
+ * True while the takeover canvas currently HOLDS keyboard focus. The host overlay reads this (via
268
+ * {@link IsCapturingInput}) to suppress its own global key shortcuts (e.g. T-to-type) so the user's
269
+ * keystrokes land in the remote browser, not the local composer — fixing the "greedy textbox" focus theft.
270
+ */
271
+ surfaceFocused = false;
272
+ /** Bound handlers — stored so the exact same references can be removed on detach. */
273
+ onCanvasMouseMove = (e) => this.handlePointerMove(e);
274
+ onCanvasMouseDown = (e) => this.handlePointerDown(e);
275
+ onCanvasMouseUp = (e) => this.handlePointerUp(e);
276
+ onCanvasClick = (e) => this.handlePointerClick(e);
277
+ onCanvasKeyDown = (e) => this.handleKeyDown(e);
278
+ onCanvasMouseLeave = () => this.handleMouseLeave();
279
+ onCanvasWheel = (e) => this.handleWheel(e);
280
+ onCanvasFocus = () => { this.surfaceFocused = true; };
281
+ onCanvasBlur = () => { this.surfaceFocused = false; };
282
+ ngOnInit() {
283
+ // In streaming mode the server pushes frames — never start the poll (it would be redundant traffic).
284
+ if (this.Streaming) {
285
+ return;
286
+ }
287
+ void this.pollOnce();
288
+ this.startPolling();
289
+ }
290
+ ngOnDestroy() {
291
+ this.destroyed = true;
292
+ this.stopPolling();
293
+ this.detachTakeoverListeners();
294
+ }
295
+ /** Starts the interval poll OUTSIDE Angular's zone so it doesn't trigger CD on every tick. */
296
+ startPolling() {
297
+ if (this.pollTimer !== null) {
298
+ return;
299
+ }
300
+ this.zone.runOutsideAngular(() => {
301
+ this.pollTimer = setInterval(() => void this.pollOnce(), SNAPSHOT_POLL_MS);
302
+ });
303
+ }
304
+ /** Stops the interval poll (no further snapshot requests are issued). */
305
+ stopPolling() {
306
+ if (this.pollTimer !== null) {
307
+ clearInterval(this.pollTimer);
308
+ this.pollTimer = null;
309
+ }
310
+ }
311
+ /**
312
+ * Fetches one snapshot and applies it to the view. Best-effort: the fetcher resolves to
313
+ * `null` on failure (the prior frame stays on screen) so a single failed poll never breaks
314
+ * the live view. Skips when a prior poll is still in flight, the fetcher isn't wired, or
315
+ * after destroy.
316
+ */
317
+ async pollOnce() {
318
+ if (this.polling || this.destroyed || !this.Fetch) {
319
+ return;
320
+ }
321
+ this.polling = true;
322
+ try {
323
+ const snapshot = await this.Fetch();
324
+ this.applySnapshot(snapshot);
325
+ }
326
+ catch {
327
+ // Defensive — the fetcher is contractually non-throwing, but never let a poll break the view.
328
+ }
329
+ finally {
330
+ this.polling = false;
331
+ }
332
+ }
333
+ /** Applies a fetched snapshot to the view fields and triggers OnPush change detection. */
334
+ applySnapshot(snapshot) {
335
+ if (this.destroyed) {
336
+ return;
337
+ }
338
+ const base64 = snapshot?.ScreenshotBase64 ?? null;
339
+ const nextUrl = snapshot?.CurrentUrl ?? null;
340
+ const nextDataUrl = base64 ? `data:image/png;base64,${base64}` : this.ScreenshotDataUrl;
341
+ if (nextDataUrl === this.ScreenshotDataUrl && nextUrl === this.CurrentUrl) {
342
+ return; // nothing changed — skip the CD pass
343
+ }
344
+ this.ScreenshotDataUrl = nextDataUrl;
345
+ this.CurrentUrl = nextUrl;
346
+ // Re-enter the zone for the OnPush update (the poll runs outside Angular).
347
+ this.zone.run(() => this.cdr.markForCheck());
348
+ }
349
+ /**
350
+ * Paints one PUSHED screencast frame (base64 JPEG) onto the canvas. Called by the channel plugin for
351
+ * each frame the server pushes while {@link Streaming}. Coalesces a burst of frames to one paint per
352
+ * animation frame (the newest wins) so a fast stream never floods the main thread, and reuses a single
353
+ * `Image` decode target to avoid per-frame allocation. No-op after destroy or when not in streaming mode.
354
+ *
355
+ * @param dataBase64 The frame image as raw base64 JPEG (no `data:` prefix).
356
+ */
357
+ RenderFrame(dataBase64) {
358
+ if (this.destroyed || !this.Streaming || !dataBase64) {
359
+ return;
360
+ }
361
+ this.pendingFrameDataUrl = `data:image/jpeg;base64,${dataBase64}`;
362
+ if (this.framePaintScheduled) {
363
+ return; // a paint is already queued — it will pick up this newest frame
364
+ }
365
+ this.framePaintScheduled = true;
366
+ this.zone.runOutsideAngular(() => requestAnimationFrame(() => this.paintPendingFrame()));
367
+ }
368
+ /**
369
+ * Updates the URL shown above the live view. In streaming (canvas) mode the snapshot poll is stopped, so
370
+ * the channel pushes the current URL here after a navigation/action reports one — otherwise the bar would
371
+ * stay stuck on "No page loaded yet" even though the page is live. No-op for an unchanged / empty value.
372
+ *
373
+ * @param url The current page URL, or null/empty to leave the bar unchanged.
374
+ */
375
+ SetCurrentUrl(url) {
376
+ if (this.destroyed || !url || url === this.CurrentUrl) {
377
+ return;
378
+ }
379
+ this.CurrentUrl = url;
380
+ this.zone.run(() => this.cdr.markForCheck());
381
+ }
382
+ /** Drains the most recent pending frame onto the canvas (drop-old coalescing target). */
383
+ paintPendingFrame() {
384
+ this.framePaintScheduled = false;
385
+ const dataUrl = this.pendingFrameDataUrl;
386
+ this.pendingFrameDataUrl = null;
387
+ if (this.destroyed || !dataUrl) {
388
+ return;
389
+ }
390
+ this.frameImage.onload = () => this.drawFrameImage();
391
+ this.frameImage.src = dataUrl;
392
+ }
393
+ /** Draws the decoded frame image onto the canvas, sizing the canvas to the frame on the first paint. */
394
+ drawFrameImage() {
395
+ const canvas = this.frameCanvas?.nativeElement;
396
+ if (this.destroyed || !canvas) {
397
+ return;
398
+ }
399
+ const ctx = canvas.getContext('2d');
400
+ if (!ctx) {
401
+ return;
402
+ }
403
+ const { naturalWidth: w, naturalHeight: h } = this.frameImage;
404
+ if (w > 0 && h > 0 && (canvas.width !== w || canvas.height !== h)) {
405
+ canvas.width = w;
406
+ canvas.height = h;
407
+ }
408
+ ctx.drawImage(this.frameImage, 0, 0);
409
+ if (!this.HasFrame) {
410
+ // First frame arrived — re-enter the zone to clear the placeholder + flip the "Live" indicator,
411
+ // and attach takeover listeners now that the canvas element exists in the DOM.
412
+ this.zone.run(() => {
413
+ this.HasFrame = true;
414
+ this.cdr.markForCheck();
415
+ });
416
+ this.syncTakeoverListeners();
417
+ }
418
+ }
419
+ // ----- human takeover (Collaborative control) --------------------------------------------
420
+ /**
421
+ * Attaches or detaches the canvas takeover listeners so they're bound exactly when takeover is live —
422
+ * {@link CanTakeOver} is true AND the canvas element exists. Idempotent: re-binds only when the target
423
+ * canvas changed, detaches when the conditions no longer hold. Safe to call from any state-flip path
424
+ * (the `Interactive`/`Streaming` setters, the first-frame paint, destroy).
425
+ */
426
+ syncTakeoverListeners() {
427
+ const canvas = this.CanTakeOver && !this.destroyed ? (this.frameCanvas?.nativeElement ?? null) : null;
428
+ if (canvas === this.takeoverCanvas) {
429
+ return; // already in the desired state
430
+ }
431
+ this.detachTakeoverListeners();
432
+ if (canvas) {
433
+ this.attachTakeoverListeners(canvas);
434
+ }
435
+ }
436
+ /** Binds the pointer/keyboard/wheel listeners to the canvas OUTSIDE the zone (mousemove/wheel are high-frequency). */
437
+ attachTakeoverListeners(canvas) {
438
+ canvas.tabIndex = 0; // focusable so it can receive keydown
439
+ // Marks this canvas as a keyboard-capturing surface so the host overlay's global shortcuts (e.g.
440
+ // T-to-type) stand down while it holds focus — see the overlay's isKeyboardCapturingSurfaceFocused().
441
+ canvas.setAttribute('data-mj-capture-keys', '');
442
+ this.zone.runOutsideAngular(() => {
443
+ canvas.addEventListener('mousemove', this.onCanvasMouseMove);
444
+ canvas.addEventListener('mousedown', this.onCanvasMouseDown);
445
+ canvas.addEventListener('mouseup', this.onCanvasMouseUp);
446
+ canvas.addEventListener('click', this.onCanvasClick);
447
+ canvas.addEventListener('keydown', this.onCanvasKeyDown);
448
+ canvas.addEventListener('mouseleave', this.onCanvasMouseLeave);
449
+ canvas.addEventListener('focus', this.onCanvasFocus);
450
+ canvas.addEventListener('blur', this.onCanvasBlur);
451
+ // `passive: false` so preventDefault stops the host page from scrolling while the user drives the page.
452
+ canvas.addEventListener('wheel', this.onCanvasWheel, { passive: false });
453
+ });
454
+ this.takeoverCanvas = canvas;
455
+ }
456
+ /** Removes the listeners from the currently-bound canvas (no-op when none are bound) and clears the cursor. */
457
+ detachTakeoverListeners() {
458
+ const canvas = this.takeoverCanvas;
459
+ if (!canvas) {
460
+ return;
461
+ }
462
+ canvas.removeEventListener('mousemove', this.onCanvasMouseMove);
463
+ canvas.removeEventListener('mousedown', this.onCanvasMouseDown);
464
+ canvas.removeEventListener('mouseup', this.onCanvasMouseUp);
465
+ canvas.removeEventListener('click', this.onCanvasClick);
466
+ canvas.removeEventListener('keydown', this.onCanvasKeyDown);
467
+ canvas.removeEventListener('mouseleave', this.onCanvasMouseLeave);
468
+ canvas.removeEventListener('focus', this.onCanvasFocus);
469
+ canvas.removeEventListener('blur', this.onCanvasBlur);
470
+ canvas.removeEventListener('wheel', this.onCanvasWheel);
471
+ canvas.removeAttribute('data-mj-capture-keys');
472
+ this.takeoverCanvas = null;
473
+ this.cursorViewportPoint = null;
474
+ this.dragging = false;
475
+ this.suppressNextClick = false;
476
+ this.dragStartPoint = null;
477
+ this.surfaceFocused = false;
478
+ this.clearSyntheticCursor();
479
+ }
480
+ /**
481
+ * Pointer-move → tracks the cursor for the synthetic-cursor overlay (every move, immediate, no
482
+ * round-trip) AND emits a throttled viewport-mapped move to the server. Runs outside the zone (no CD
483
+ * per move).
484
+ */
485
+ handlePointerMove(event) {
486
+ const point = this.toViewportCoords(event);
487
+ if (point) {
488
+ // Always update the local cursor for instant feedback — independent of the server-relay throttle.
489
+ this.cursorViewportPoint = point;
490
+ this.scheduleCursorPaint();
491
+ }
492
+ const now = Date.now();
493
+ if (now - this.lastPointerMoveAt < POINTER_MOVE_THROTTLE_MS) {
494
+ return;
495
+ }
496
+ this.lastPointerMoveAt = now;
497
+ if (point) {
498
+ this.emitInput({ kind: 'pointer-move', x: point.x, y: point.y });
499
+ }
500
+ }
501
+ /** Mouse leaves the canvas → hide the synthetic cursor (nothing to relay). */
502
+ handleMouseLeave() {
503
+ this.cursorViewportPoint = null;
504
+ this.scheduleCursorPaint();
505
+ }
506
+ /**
507
+ * Wheel/trackpad/Magic-Mouse scroll over the canvas → forwards a viewport-mapped scroll to the server.
508
+ * Calls `preventDefault` so the host page doesn't scroll while the user drives the live page. Throttled
509
+ * to {@link SCROLL_THROTTLE_MS}, coalescing the skipped deltas so no scroll distance is lost.
510
+ */
511
+ handleWheel(event) {
512
+ event.preventDefault();
513
+ this.pendingScrollDeltaX += event.deltaX;
514
+ this.pendingScrollDeltaY += event.deltaY;
515
+ const point = this.toViewportCoords(event);
516
+ if (point) {
517
+ this.cursorViewportPoint = point;
518
+ this.scheduleCursorPaint();
519
+ }
520
+ const now = Date.now();
521
+ if (now - this.lastScrollAt < SCROLL_THROTTLE_MS) {
522
+ return; // accumulate into pendingScrollDelta* until the throttle window opens
523
+ }
524
+ this.lastScrollAt = now;
525
+ const target = point ?? this.cursorViewportPoint;
526
+ if (target && (this.pendingScrollDeltaX !== 0 || this.pendingScrollDeltaY !== 0)) {
527
+ this.emitInput({ kind: 'scroll', x: target.x, y: target.y, deltaX: this.pendingScrollDeltaX, deltaY: this.pendingScrollDeltaY });
528
+ this.pendingScrollDeltaX = 0;
529
+ this.pendingScrollDeltaY = 0;
530
+ }
531
+ }
532
+ /**
533
+ * Mouse-down on the canvas → focuses the canvas (so subsequent keys are captured) and BEGINS a drag:
534
+ * emits a `pointer-down` and arms drag mode so the following moves relay as drag motion and the matching
535
+ * `pointer-up` closes it. This is what makes click-drag text selection work (rather than a discrete click).
536
+ */
537
+ handlePointerDown(event) {
538
+ this.takeoverCanvas?.focus();
539
+ const point = this.toViewportCoords(event);
540
+ if (!point) {
541
+ return;
542
+ }
543
+ this.dragging = true;
544
+ this.dragStartPoint = point;
545
+ this.suppressNextClick = false;
546
+ this.cursorViewportPoint = point;
547
+ this.scheduleCursorPaint();
548
+ this.emitInput({ kind: 'pointer-down', x: point.x, y: point.y, button: this.mapButton(event.button), modifiers: this.collectModifiers(event) });
549
+ }
550
+ /**
551
+ * Mouse-up on the canvas → closes a drag with a `pointer-up` at the release point, disarming drag mode.
552
+ * If the pointer actually moved between down and up, marks the following synthetic `click` to be suppressed
553
+ * (so the drag selection isn't immediately collapsed by a trailing click).
554
+ */
555
+ handlePointerUp(event) {
556
+ if (!this.dragging) {
557
+ return;
558
+ }
559
+ this.dragging = false;
560
+ const point = this.toViewportCoords(event);
561
+ if (point) {
562
+ const start = this.dragStartPoint;
563
+ this.suppressNextClick = !!start && (start.x !== point.x || start.y !== point.y);
564
+ this.emitInput({ kind: 'pointer-up', x: point.x, y: point.y, button: this.mapButton(event.button), modifiers: this.collectModifiers(event) });
565
+ }
566
+ this.dragStartPoint = null;
567
+ }
568
+ /**
569
+ * Click → emits a viewport-mapped click WITH any held modifiers (e.g. Shift-click text selection). The
570
+ * server browser receives the press/release of a drag via {@link handlePointerDown}/{@link handlePointerUp};
571
+ * a plain click (down+up with no motion) still fires this `click` event, so a simple click relays as one
572
+ * click action — but we skip emitting it when it terminates a real drag (where down/up already covered it).
573
+ */
574
+ handlePointerClick(event) {
575
+ this.takeoverCanvas?.focus();
576
+ if (this.suppressNextClick) {
577
+ // This click terminates a real drag (selection) — the down/move/up already conveyed it.
578
+ this.suppressNextClick = false;
579
+ return;
580
+ }
581
+ const point = this.toViewportCoords(event);
582
+ if (point) {
583
+ this.emitInput({ kind: 'pointer-click', x: point.x, y: point.y, button: this.mapButton(event.button), modifiers: this.collectModifiers(event) });
584
+ }
585
+ }
586
+ /**
587
+ * Keydown → forwards printable keys, a curated set of control keys ({@link FORWARDED_CONTROL_KEYS}), AND
588
+ * any key combined with a Ctrl/Cmd/Alt modifier (so combos like Ctrl/Cmd+A select-all, Cmd+C/Cmd+V relay).
589
+ * Calls `preventDefault` + `stopPropagation` ONLY on forwarded keys, so (a) the host app keeps its own
590
+ * shortcuts on un-forwarded keys and (b) forwarded keys never bubble to the host overlay's global shortcuts
591
+ * (the T-to-type focus-steal). Lone modifier keys are never forwarded — they ride as `modifiers` on the
592
+ * next key/click.
593
+ */
594
+ handleKeyDown(event) {
595
+ const key = event.key;
596
+ if (MODIFIER_KEYS.has(key)) {
597
+ return; // a modifier on its own is not a keypress — it rides on the next key/click
598
+ }
599
+ const isPrintable = key.length === 1;
600
+ const hasComboModifier = event.ctrlKey || event.metaKey || event.altKey;
601
+ const isForwardable = isPrintable || FORWARDED_CONTROL_KEYS.has(key) || hasComboModifier;
602
+ if (!isForwardable) {
603
+ return; // leave non-forwarded keys to the host app
604
+ }
605
+ event.preventDefault();
606
+ // Stop the keystroke from reaching document-level handlers (e.g. the overlay's T-to-type) so the user's
607
+ // typing lands in the remote browser, not the local composer.
608
+ event.stopPropagation();
609
+ this.emitInput({ kind: 'key', key, modifiers: this.collectModifiers(event) });
610
+ }
611
+ /**
612
+ * Collects the modifier keys currently held during a DOM mouse/keyboard event into the relayed
613
+ * {@link RemoteBrowserModifier} list (empty when none are held).
614
+ *
615
+ * @param event The DOM event whose modifier flags to read.
616
+ * @returns The held modifiers, in a stable order.
617
+ */
618
+ collectModifiers(event) {
619
+ const modifiers = [];
620
+ if (event.shiftKey) {
621
+ modifiers.push('Shift');
622
+ }
623
+ if (event.ctrlKey) {
624
+ modifiers.push('Control');
625
+ }
626
+ if (event.altKey) {
627
+ modifiers.push('Alt');
628
+ }
629
+ if (event.metaKey) {
630
+ modifiers.push('Meta');
631
+ }
632
+ return modifiers;
633
+ }
634
+ /** Re-enters the zone to emit one human input (so subscribers see it inside Angular). */
635
+ emitInput(input) {
636
+ this.zone.run(() => this.HumanInput.emit(input));
637
+ }
638
+ /**
639
+ * Maps a DOM pointer event on the live canvas to VIEWPORT coordinates via {@link MapToViewportCoords}
640
+ * (the pure, unit-tested mapping). Returns `null` when no canvas is bound or mapping isn't possible yet.
641
+ *
642
+ * @param event The pointer event on the canvas.
643
+ * @returns The integer viewport coordinates, or `null` when mapping isn't possible yet.
644
+ */
645
+ toViewportCoords(event) {
646
+ const canvas = this.takeoverCanvas;
647
+ if (!canvas) {
648
+ return null;
649
+ }
650
+ return MapToViewportCoords(event.clientX, event.clientY, canvas.getBoundingClientRect(), canvas.width, canvas.height);
651
+ }
652
+ // ----- synthetic cursor (local feedback — CDP frames don't include the OS cursor) -----------
653
+ /**
654
+ * Schedules a synthetic-cursor repaint on the next animation frame, coalescing a burst of moves to one
655
+ * paint (the newest position wins). Runs outside the zone — drawing the cursor never triggers Angular CD.
656
+ */
657
+ scheduleCursorPaint() {
658
+ if (this.cursorPaintScheduled) {
659
+ return;
660
+ }
661
+ this.cursorPaintScheduled = true;
662
+ this.zone.runOutsideAngular(() => requestAnimationFrame(() => this.paintSyntheticCursor()));
663
+ }
664
+ /**
665
+ * Draws (or clears) the synthetic cursor on the overlay canvas at {@link cursorViewportPoint}. The overlay
666
+ * shares the frame canvas's internal resolution (sized here to match), so a point drawn at viewport coords
667
+ * aligns exactly with the page underneath. A small brand-tinted ring with a center dot reads as a pointer
668
+ * without obscuring what it's over. No-op after destroy or when the overlay isn't mounted.
669
+ */
670
+ paintSyntheticCursor() {
671
+ this.cursorPaintScheduled = false;
672
+ const overlay = this.cursorCanvas?.nativeElement;
673
+ const frame = this.frameCanvas?.nativeElement;
674
+ if (this.destroyed || !overlay || !frame) {
675
+ return;
676
+ }
677
+ // Keep the overlay's internal resolution locked to the frame canvas so coordinate spaces match.
678
+ if (overlay.width !== frame.width || overlay.height !== frame.height) {
679
+ overlay.width = frame.width;
680
+ overlay.height = frame.height;
681
+ }
682
+ const ctx = overlay.getContext('2d');
683
+ if (!ctx) {
684
+ return;
685
+ }
686
+ ctx.clearRect(0, 0, overlay.width, overlay.height);
687
+ const point = this.cursorViewportPoint;
688
+ if (!point) {
689
+ return; // pointer left the canvas — leave the overlay cleared
690
+ }
691
+ const ring = this.resolveCssColor('--mj-brand-primary', '#264FAF');
692
+ ctx.beginPath();
693
+ ctx.arc(point.x, point.y, SYNTHETIC_CURSOR_RADIUS, 0, Math.PI * 2);
694
+ ctx.lineWidth = 2;
695
+ ctx.strokeStyle = ring;
696
+ ctx.stroke();
697
+ ctx.beginPath();
698
+ ctx.arc(point.x, point.y, 1.5, 0, Math.PI * 2);
699
+ ctx.fillStyle = ring;
700
+ ctx.fill();
701
+ }
702
+ /** Clears the synthetic-cursor overlay (e.g. on detach). No-op when the overlay isn't mounted. */
703
+ clearSyntheticCursor() {
704
+ const overlay = this.cursorCanvas?.nativeElement;
705
+ const ctx = overlay?.getContext('2d');
706
+ if (overlay && ctx) {
707
+ ctx.clearRect(0, 0, overlay.width, overlay.height);
708
+ }
709
+ }
710
+ /**
711
+ * Resolves a CSS custom property (design token) to its computed color value off the host element, so the
712
+ * canvas-drawn cursor honors theming. Falls back to the supplied default when the token is unset or the
713
+ * host isn't measurable.
714
+ *
715
+ * @param token The CSS custom property name (e.g. `'--mj-brand-primary'`).
716
+ * @param fallback The color to use when the token resolves empty.
717
+ * @returns The resolved color string.
718
+ */
719
+ resolveCssColor(token, fallback) {
720
+ const host = this.frameCanvas?.nativeElement;
721
+ if (!host) {
722
+ return fallback;
723
+ }
724
+ const value = getComputedStyle(host).getPropertyValue(token).trim();
725
+ return value.length > 0 ? value : fallback;
726
+ }
727
+ /** Maps a DOM `MouseEvent.button` (0/1/2) to the relayed button union, defaulting to `'left'`. */
728
+ mapButton(button) {
729
+ if (button === 1) {
730
+ return 'middle';
731
+ }
732
+ if (button === 2) {
733
+ return 'right';
734
+ }
735
+ return 'left';
736
+ }
737
+ static ɵfac = function RemoteBrowserSurfaceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RemoteBrowserSurfaceComponent)(); };
738
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RemoteBrowserSurfaceComponent, selectors: [["mj-realtime-remote-browser-surface"]], viewQuery: function RemoteBrowserSurfaceComponent_Query(rf, ctx) { if (rf & 1) {
739
+ i0.ɵɵviewQuery(_c0, 5)(_c1, 5);
740
+ } if (rf & 2) {
741
+ let _t;
742
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.frameCanvas = _t.first);
743
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.cursorCanvas = _t.first);
744
+ } }, inputs: { Fetch: "Fetch", Streaming: "Streaming", Interactive: "Interactive", AudioAvailable: "AudioAvailable", AudioMuted: "AudioMuted" }, outputs: { HumanInput: "HumanInput", AudioMutedChange: "AudioMutedChange" }, decls: 13, vars: 8, consts: [["frameCanvas", ""], ["cursorCanvas", ""], [1, "rb-surface"], [1, "rb-bar"], ["aria-hidden", "true", 1, "rb-live"], [1, "rb-live-label"], [1, "rb-url", 3, "title"], ["title", "Click and type to control the live page", 1, "rb-driving"], ["type", "button", 1, "rb-speaker", 3, "rb-speaker--muted", "title"], [1, "rb-viewport"], ["alt", "Live view of the shared browser", 1, "rb-screenshot", 3, "src"], [1, "rb-placeholder"], ["aria-hidden", "true", 1, "fa-solid", "fa-hand-pointer"], ["type", "button", 1, "rb-speaker", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid"], [1, "rb-canvas-stack"], [1, "rb-screenshot"], [1, "rb-screenshot", "rb-cursor-overlay"], ["text", "Waiting for the browser\u2026", "size", "medium"]], template: function RemoteBrowserSurfaceComponent_Template(rf, ctx) { if (rf & 1) {
745
+ i0.ɵɵelementStart(0, "div", 2)(1, "div", 3);
746
+ i0.ɵɵelement(2, "span", 4);
747
+ i0.ɵɵelementStart(3, "span", 5);
748
+ i0.ɵɵtext(4);
749
+ i0.ɵɵelementEnd();
750
+ i0.ɵɵelementStart(5, "span", 6);
751
+ i0.ɵɵtext(6);
752
+ i0.ɵɵelementEnd();
753
+ i0.ɵɵconditionalCreate(7, RemoteBrowserSurfaceComponent_Conditional_7_Template, 3, 0, "span", 7);
754
+ i0.ɵɵconditionalCreate(8, RemoteBrowserSurfaceComponent_Conditional_8_Template, 2, 9, "button", 8);
755
+ i0.ɵɵelementEnd();
756
+ i0.ɵɵelementStart(9, "div", 9);
757
+ i0.ɵɵconditionalCreate(10, RemoteBrowserSurfaceComponent_Conditional_10_Template, 5, 6)(11, RemoteBrowserSurfaceComponent_Conditional_11_Template, 1, 1, "img", 10)(12, RemoteBrowserSurfaceComponent_Conditional_12_Template, 2, 0, "div", 11);
758
+ i0.ɵɵelementEnd()();
759
+ } if (rf & 2) {
760
+ i0.ɵɵadvance(2);
761
+ i0.ɵɵclassProp("rb-live--on", ctx.HasSnapshot);
762
+ i0.ɵɵadvance(2);
763
+ i0.ɵɵtextInterpolate(ctx.HasSnapshot ? "Live" : "Connecting\u2026");
764
+ i0.ɵɵadvance();
765
+ i0.ɵɵproperty("title", ctx.CurrentUrl || "");
766
+ i0.ɵɵadvance();
767
+ i0.ɵɵtextInterpolate(ctx.CurrentUrl || "No page loaded yet");
768
+ i0.ɵɵadvance();
769
+ i0.ɵɵconditional(ctx.CanTakeOver ? 7 : -1);
770
+ i0.ɵɵadvance();
771
+ i0.ɵɵconditional(ctx.AudioAvailable ? 8 : -1);
772
+ i0.ɵɵadvance(2);
773
+ i0.ɵɵconditional(ctx.Streaming ? 10 : ctx.ScreenshotDataUrl ? 11 : 12);
774
+ } }, dependencies: [CommonModule, SharedGenericModule, i1.LoadingComponent], styles: ["[_nghost-%COMP%] { display: block; height: 100%; }\n .rb-surface[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n .rb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface);\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n }\n .rb-live[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: var(--mj-radius-full, 50%);\n background: var(--mj-text-disabled);\n flex: 0 0 auto;\n }\n .rb-live--on[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 25%, transparent);\n }\n .rb-live-label[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n .rb-url[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mj-font-mono, monospace);\n }\n .rb-viewport[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: auto;\n padding: 12px;\n }\n .rb-screenshot[_ngcontent-%COMP%] {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 6px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px color-mix(in srgb, var(--mj-text-primary) 12%, transparent));\n background: var(--mj-bg-surface);\n }\n .rb-screenshot--interactive[_ngcontent-%COMP%] {\n \n\n\n cursor: none;\n outline: none;\n }\n .rb-screenshot--interactive[_ngcontent-%COMP%]:focus-visible {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n \n\n\n .rb-canvas-stack[_ngcontent-%COMP%] {\n position: relative;\n display: inline-flex;\n max-width: 100%;\n max-height: 100%;\n min-height: 0;\n }\n .rb-cursor-overlay[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n \n\n\n border: none;\n box-shadow: none;\n background: transparent;\n pointer-events: none;\n }\n .rb-driving[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n .rb-placeholder[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .rb-hidden[_ngcontent-%COMP%] {\n display: none;\n }\n .rb-speaker[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 6px);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 0.8125rem;\n transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;\n }\n .rb-speaker[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n .rb-speaker[_ngcontent-%COMP%]:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n .rb-speaker--muted[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n }"], changeDetection: 0 });
775
+ }
776
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RemoteBrowserSurfaceComponent, [{
777
+ type: Component,
778
+ args: [{ standalone: true, selector: 'mj-realtime-remote-browser-surface', imports: [CommonModule, SharedGenericModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
779
+ <div class="rb-surface">
780
+ <div class="rb-bar">
781
+ <span class="rb-live" [class.rb-live--on]="HasSnapshot" aria-hidden="true"></span>
782
+ <span class="rb-live-label">{{ HasSnapshot ? 'Live' : 'Connecting…' }}</span>
783
+ <span class="rb-url" [title]="CurrentUrl || ''">{{ CurrentUrl || 'No page loaded yet' }}</span>
784
+ @if (CanTakeOver) {
785
+ <span class="rb-driving" title="Click and type to control the live page">
786
+ <i class="fa-solid fa-hand-pointer" aria-hidden="true"></i> You're driving
787
+ </span>
788
+ }
789
+ @if (AudioAvailable) {
790
+ <button
791
+ type="button"
792
+ class="rb-speaker"
793
+ [class.rb-speaker--muted]="AudioMuted"
794
+ [attr.aria-pressed]="!AudioMuted"
795
+ [attr.aria-label]="AudioMuted ? 'Unmute browser audio' : 'Mute browser audio'"
796
+ [title]="AudioMuted ? 'Unmute browser audio' : 'Mute browser audio'"
797
+ (click)="ToggleAudioMuted()"
798
+ >
799
+ <i class="fa-solid" [class.fa-volume-high]="!AudioMuted" [class.fa-volume-xmark]="AudioMuted" aria-hidden="true"></i>
800
+ </button>
801
+ }
802
+ </div>
803
+ <div class="rb-viewport">
804
+ @if (Streaming) {
805
+ <div class="rb-canvas-stack" [class.rb-hidden]="!HasFrame">
806
+ <canvas #frameCanvas class="rb-screenshot" [class.rb-screenshot--interactive]="CanTakeOver"></canvas>
807
+ @if (CanTakeOver) {
808
+ <!-- Synthetic cursor overlay: same internal resolution + CSS box as the frame canvas, so a
809
+ point drawn at viewport coords aligns exactly. CDP screencast frames don't include the OS
810
+ cursor, so we render the user's pointer locally for immediate, round-trip-free feedback. -->
811
+ <canvas #cursorCanvas class="rb-screenshot rb-cursor-overlay"></canvas>
812
+ }
813
+ </div>
814
+ @if (!HasFrame) {
815
+ <div class="rb-placeholder">
816
+ <mj-loading text="Waiting for the browser…" size="medium"></mj-loading>
817
+ </div>
818
+ }
819
+ } @else if (ScreenshotDataUrl) {
820
+ <img class="rb-screenshot" [src]="ScreenshotDataUrl" alt="Live view of the shared browser" />
821
+ } @else {
822
+ <div class="rb-placeholder">
823
+ <mj-loading text="Waiting for the browser…" size="medium"></mj-loading>
824
+ </div>
825
+ }
826
+ </div>
827
+ </div>
828
+ `, styles: ["\n :host { display: block; height: 100%; }\n .rb-surface {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n .rb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface);\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n }\n .rb-live {\n width: 8px;\n height: 8px;\n border-radius: var(--mj-radius-full, 50%);\n background: var(--mj-text-disabled);\n flex: 0 0 auto;\n }\n .rb-live--on {\n background: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 25%, transparent);\n }\n .rb-live-label {\n flex: 0 0 auto;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n .rb-url {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mj-font-mono, monospace);\n }\n .rb-viewport {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: auto;\n padding: 12px;\n }\n .rb-screenshot {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 6px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px color-mix(in srgb, var(--mj-text-primary) 12%, transparent));\n background: var(--mj-bg-surface);\n }\n .rb-screenshot--interactive {\n /* Hide the OS cursor \u2014 we render a synthetic cursor on the overlay so there's exactly one pointer\n and it reads naturally for clicking on a web page (not the old crosshair). */\n cursor: none;\n outline: none;\n }\n .rb-screenshot--interactive:focus-visible {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n /* Frame canvas + synthetic-cursor overlay share one box; the stack shrinks to the frame canvas so the\n absolutely-positioned overlay (inset:0, same object-fit) lines up pixel-for-pixel with it. */\n .rb-canvas-stack {\n position: relative;\n display: inline-flex;\n max-width: 100%;\n max-height: 100%;\n min-height: 0;\n }\n .rb-cursor-overlay {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n /* Transparent passthrough layer \u2014 no chrome of its own, and never steals pointer/wheel events from\n the frame canvas underneath (those listeners drive takeover). */\n border: none;\n box-shadow: none;\n background: transparent;\n pointer-events: none;\n }\n .rb-driving {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n .rb-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .rb-hidden {\n display: none;\n }\n .rb-speaker {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 6px);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 0.8125rem;\n transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;\n }\n .rb-speaker:hover {\n background: var(--mj-bg-surface-hover);\n }\n .rb-speaker:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n .rb-speaker--muted {\n color: var(--mj-text-muted);\n }\n "] }]
829
+ }], null, { Fetch: [{
830
+ type: Input
831
+ }], Streaming: [{
832
+ type: Input
833
+ }], Interactive: [{
834
+ type: Input
835
+ }], HumanInput: [{
836
+ type: Output
837
+ }], AudioAvailable: [{
838
+ type: Input
839
+ }], AudioMuted: [{
840
+ type: Input
841
+ }], AudioMutedChange: [{
842
+ type: Output
843
+ }], frameCanvas: [{
844
+ type: ViewChild,
845
+ args: ['frameCanvas']
846
+ }], cursorCanvas: [{
847
+ type: ViewChild,
848
+ args: ['cursorCanvas']
849
+ }] }); })();
850
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RemoteBrowserSurfaceComponent, { className: "RemoteBrowserSurfaceComponent", filePath: "src/lib/components/realtime/remote-browser/remote-browser-surface.component.ts", lineNumber: 331 }); })();
851
+ //# sourceMappingURL=remote-browser-surface.component.js.map