@memberjunction/ng-conversations 6.1.3 → 6.2.0-edge.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 (113) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  3. package/dist/lib/components/conversation/conversation-chat-area.component.js +9 -26
  4. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  5. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +1 -1
  6. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -1
  7. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -1
  8. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +1 -1
  9. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  10. package/dist/lib/components/realtime/channels/client-context-channel.js +1 -1
  11. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  12. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +1 -1
  13. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  14. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +3 -0
  15. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  16. package/dist/lib/components/realtime/media/media-channel.d.ts +2 -1
  17. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  18. package/dist/lib/components/realtime/media/media-channel.js +1 -1
  19. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  20. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +1 -1
  21. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
  22. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
  23. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +1 -1
  24. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  25. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  26. package/dist/lib/components/realtime/realtime-composer.component.d.ts +3 -1
  27. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  28. package/dist/lib/components/realtime/realtime-composer.component.js +26 -8
  29. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  30. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +1 -1
  31. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
  32. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
  33. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +2 -2
  34. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  35. package/dist/lib/components/realtime/realtime-session-overlay.component.js +1 -1
  36. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  37. package/dist/lib/components/realtime/realtime-session-state.d.ts +2 -3
  38. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
  39. package/dist/lib/components/realtime/realtime-session-state.js +3 -2
  40. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
  41. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +17 -1
  42. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -1
  43. package/dist/lib/components/realtime/realtime-session-thread.component.js +122 -45
  44. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -1
  45. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +1 -9
  46. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
  47. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +13 -43
  48. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
  49. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +2 -2
  50. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  51. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  52. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +1 -1
  53. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  54. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  55. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +1 -1
  56. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  57. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +1 -1
  58. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  59. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +1 -1
  60. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  61. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +1 -1
  62. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  63. package/dist/lib/conversations.module.d.ts.map +1 -1
  64. package/dist/lib/conversations.module.js.map +1 -1
  65. package/dist/lib/services/browser-realtime-media-host.d.ts +24 -0
  66. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -0
  67. package/dist/lib/services/browser-realtime-media-host.js +95 -0
  68. package/dist/lib/services/browser-realtime-media-host.js.map +1 -0
  69. package/dist/lib/services/conversation-attachment.service.d.ts +24 -2
  70. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  71. package/dist/lib/services/conversation-attachment.service.js +43 -4
  72. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  73. package/dist/lib/services/graphql-attachment-blob-store.d.ts +44 -0
  74. package/dist/lib/services/graphql-attachment-blob-store.d.ts.map +1 -0
  75. package/dist/lib/services/graphql-attachment-blob-store.js +113 -0
  76. package/dist/lib/services/graphql-attachment-blob-store.js.map +1 -0
  77. package/dist/lib/services/mention-autocomplete.service.d.ts +17 -141
  78. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  79. package/dist/lib/services/mention-autocomplete.service.js +15 -460
  80. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  81. package/dist/lib/services/realtime-session-review.service.d.ts +1 -1
  82. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  83. package/dist/lib/services/realtime-session-review.service.js +1 -1
  84. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  85. package/dist/lib/services/realtime-session.service.d.ts +16 -1150
  86. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  87. package/dist/lib/services/realtime-session.service.js +28 -2430
  88. package/dist/lib/services/realtime-session.service.js.map +1 -1
  89. package/dist/lib/utils/realtime-session-timeline.d.ts +8 -79
  90. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -1
  91. package/dist/lib/utils/realtime-session-timeline.js +8 -89
  92. package/dist/lib/utils/realtime-session-timeline.js.map +1 -1
  93. package/dist/public-api.d.ts +2 -2
  94. package/dist/public-api.d.ts.map +1 -1
  95. package/dist/public-api.js +6 -2
  96. package/dist/public-api.js.map +1 -1
  97. package/package.json +33 -32
  98. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +0 -384
  99. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +0 -1
  100. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +0 -231
  101. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +0 -1
  102. package/dist/lib/services/delegation-result-parser.d.ts +0 -50
  103. package/dist/lib/services/delegation-result-parser.d.ts.map +0 -1
  104. package/dist/lib/services/delegation-result-parser.js +0 -60
  105. package/dist/lib/services/delegation-result-parser.js.map +0 -1
  106. package/dist/lib/services/narration-template.d.ts +0 -42
  107. package/dist/lib/services/narration-template.d.ts.map +0 -1
  108. package/dist/lib/services/narration-template.js +0 -73
  109. package/dist/lib/services/narration-template.js.map +0 -1
  110. package/dist/lib/services/skill-picker-narrowing.d.ts +0 -13
  111. package/dist/lib/services/skill-picker-narrowing.d.ts.map +0 -1
  112. package/dist/lib/services/skill-picker-narrowing.js +0 -13
  113. package/dist/lib/services/skill-picker-narrowing.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-agent-banner.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-banner.component.ts","../../../../src/lib/components/realtime/realtime-agent-banner.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RealtimeConnectionState } from '../../services/realtime-session.service';\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * The call overlay's UNIFIED APP-BAR (per Redesign A — `plans/realtime/mockups/redesign-a.html`):\n * ONE header that owns identity, state, and every session action.\n *\n * - LEFT: the glowing agent orb (motion = turn-state), agent name + \"Co-Agent\" badge,\n * \"speaking as\" subline (+ subtle realtime-model suffix), and the state pill that swaps\n * between a waveform (speaking/listening) and a spinner (connecting/thinking).\n * - RIGHT (live): STATE + WINDOW-CHROME only — the gear (level 2+, opens a popover hosting the\n * Simple/Standard/Pro/Auto INTERFACE DENSITY control — the progressive-disclosure escape hatch,\n * where Simple IS the pure-audio surface — plus the developer-links toggle) and Minimize (hide\n * the call view, call stays live). Call actions (Mute / Captions / Details / Type / End) live in\n * the bottom dock, the single home for each; Captions & End used to duplicate here and were\n * removed, and the standalone pure-audio headphones was folded into the gear's Density = Simple.\n * - RIGHT (review): \"Start live session\" (resume, affirmative leads) + Close — the\n * review session's exit lives up here in the header bar, not floating in the body.\n *\n * Which controls render is decided by the OVERLAY (it owns the disclosure model) and\n * passed down as booleans — this component stays purely presentational.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-banner',\n imports: [CommonModule],\n templateUrl: './realtime-agent-banner.component.html',\n styleUrl: './realtime-agent-banner.component.css'\n})\nexport class RealtimeAgentBannerComponent {\n /** Current connection / turn state — drives the orb animation + state label. */\n @Input({ required: true }) State!: RealtimeConnectionState;\n\n /**\n * COMPACT (orb/overlay) presentation: collapse the app-bar to a minimal identity + state\n * row. The duplicate orb, the redundant state pill, and the headphones / gear / expand\n * controls are dropped — the body already shows the big orb + name + state, and the lean\n * bottom dock (Mute / End / •••) owns the session actions. Minimize stays reachable so the\n * user can hide the call without ending it. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full console banner is unchanged).\n */\n @Input() Compact = false;\n\n /** Display name of the agent the voice session fronts (e.g. \"Sage\"). */\n @Input() AgentName = 'the agent';\n\n /**\n * Display name of the realtime model the live session runs on (e.g. \"GPT Realtime 2\").\n * Rendered as a subtle suffix in the identity line; hidden when null/empty.\n */\n @Input() ModelName: string | null = null;\n\n /** Whether developer affordances (the \"Open session\" link) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /** ID of the server-side agent session record (`MJ: AI Agent Sessions`), when known. */\n @Input() SessionID: string | null = null;\n\n /**\n * SESSION REVIEW presentation: the banner shows the past session's identity\n * (review badge, started→closed range, close-reason chip) instead of live turn-state,\n * and the action cluster swaps to Start-live + Close.\n */\n @Input() ReviewMode = false;\n\n /** When reviewing: when the past session started (`__mj_CreatedAt`). */\n @Input() ReviewStartedAt: Date | null = null;\n\n /** When reviewing: when the past session closed (null while it is still open). */\n @Input() ReviewClosedAt: Date | null = null;\n\n /** When reviewing: why the past session closed (`Explicit` | `Janitor` | `Shutdown` | `Error`), when known. */\n @Input() ReviewCloseReason: string | null = null;\n\n // ── App-bar action cluster (disclosure-gated by the overlay) ────────────────\n // STATE + WINDOW-CHROME only. Captions & End were removed (they duplicated the bottom dock's\n // controls — one home per control), and \"pure audio\" was folded into the gear's Density = Simple.\n\n /** Whether the gear (density escape hatch + dev toggle) renders (disclosure level 2+). */\n @Input() ShowGear = false;\n\n /**\n * Whether the interface-density segmented control renders inside the gear popover.\n * Default `true` (historical behaviour); a host may hide it via the overlay's\n * `[ShowDensityPicker]` input. The gear itself (and its developer-links toggle) still\n * renders when {@link ShowGear} is true even if the density picker is hidden.\n */\n @Input() ShowDensityPicker = true;\n\n /** Whether the Minimize control renders (live sessions only). */\n @Input() ShowMinimize = false;\n\n /** The user's current interface-density override (selected state in the gear popover). */\n @Input() Density: RealtimeUxDensity = 'auto';\n\n /** Emitted with the session record's ID when the dev \"Open session\" link is clicked. */\n @Output() OpenSessionRequested = new EventEmitter<string>();\n\n /** Emitted when the user toggles developer links from the gear popover. */\n @Output() DevModeToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user picks an interface density in the gear popover. */\n @Output() DensityChanged = new EventEmitter<RealtimeUxDensity>();\n\n /** Emitted when the user minimizes the call view (the call stays live). */\n @Output() MinimizeRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to RESUME the reviewed session as a new live call. */\n @Output() StartLiveRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to close the review and return to the conversation. */\n @Output() CloseRequested = new EventEmitter<void>();\n\n /** Whether the gear popover is open (closed by any outside click). */\n public GearOpen = false;\n\n /** The density choices the gear popover offers, in display order. */\n public readonly Densities: ReadonlyArray<{ Key: RealtimeUxDensity; Label: string }> = [\n { Key: 'simple', Label: 'Simple' },\n { Key: 'standard', Label: 'Standard' },\n { Key: 'pro', Label: 'Pro' },\n { Key: 'auto', Label: 'Auto' }\n ];\n\n /** True when the dev \"Open session\" link should render (gear on + session id known). */\n public get ShowOpenSession(): boolean {\n return this.DevMode && !!this.SessionID;\n }\n\n /** Emits the open-session request for the live agent session record. */\n public OpenSession(): void {\n if (this.SessionID) {\n this.OpenSessionRequested.emit(this.SessionID);\n }\n }\n\n /** Opens/closes the gear popover (stops propagation so the outside-click close skips it). */\n public ToggleGear(event: MouseEvent): void {\n event.stopPropagation();\n this.GearOpen = !this.GearOpen;\n }\n\n /** Any outside click closes the gear popover. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.GearOpen) {\n this.GearOpen = false;\n }\n }\n\n /** Gear popover: pick an interface density (the overlay applies + persists it). */\n public SelectDensity(density: RealtimeUxDensity): void {\n this.DensityChanged.emit(density);\n }\n\n /** Gear popover: toggle developer links. */\n public ToggleDev(): void {\n this.DevMode = !this.DevMode;\n this.DevModeToggled.emit(this.DevMode);\n }\n\n /** The review banner's \"started → closed\" time-range label (empty when the start is unknown). */\n public get ReviewRangeLabel(): string {\n if (!this.ReviewStartedAt) {\n return '';\n }\n const start = this.formatStamp(this.ReviewStartedAt);\n if (!this.ReviewClosedAt) {\n return start;\n }\n return `${start} → ${this.formatStamp(this.ReviewClosedAt, this.ReviewStartedAt)}`;\n }\n\n /** Human label for the close-reason chip (empty hides the chip). */\n public get ReviewCloseReasonLabel(): string {\n switch (this.ReviewCloseReason) {\n case 'Explicit': return 'Ended by user';\n case 'Janitor': return 'Closed by janitor';\n case 'Shutdown': return 'Closed at shutdown';\n case 'Error': return 'Ended with error';\n default: return '';\n }\n }\n\n /** Compact date+time stamp; same-day end stamps drop the redundant date part. */\n private formatStamp(date: Date, sameDayAs?: Date | null): string {\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();\n if (sameDayAs && date.toDateString() === sameDayAs.toDateString()) {\n return time;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n }\n\n /** Maps the realtime state to the orb's `data-state` (the orb only models active turn-states). */\n public OrbState(state: RealtimeConnectionState): 'speaking' | 'listening' | 'thinking' {\n switch (state) {\n case 'speaking': return 'speaking';\n case 'thinking': return 'thinking';\n default: return 'listening';\n }\n }\n\n /** Human-readable state label, agent-aware where it reads better. */\n public StateLabel(state: RealtimeConnectionState): string {\n switch (state) {\n case 'connecting': return 'Connecting…';\n case 'listening': return 'Listening';\n case 'speaking': return `${this.AgentName} is speaking…`;\n case 'thinking': return 'Working on it…';\n case 'error': return 'Connection error';\n case 'closed': return 'Call ended';\n default: return '';\n }\n }\n\n /** True while the state pill should show a spinner instead of the waveform. */\n public IsBusy(state: RealtimeConnectionState): boolean {\n return state === 'connecting' || state === 'thinking';\n }\n}\n","<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb · name · review badge · started→closed · close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb · overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand — the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">· {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock — the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density &amp; developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n"]}
1
+ {"version":3,"file":"realtime-agent-banner.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-banner.component.ts","../../../../src/lib/components/realtime/realtime-agent-banner.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RealtimeConnectionState } from '@memberjunction/realtime-runtime';\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * The call overlay's UNIFIED APP-BAR (per Redesign A — `plans/realtime/mockups/redesign-a.html`):\n * ONE header that owns identity, state, and every session action.\n *\n * - LEFT: the glowing agent orb (motion = turn-state), agent name + \"Co-Agent\" badge,\n * \"speaking as\" subline (+ subtle realtime-model suffix), and the state pill that swaps\n * between a waveform (speaking/listening) and a spinner (connecting/thinking).\n * - RIGHT (live): STATE + WINDOW-CHROME only — the gear (level 2+, opens a popover hosting the\n * Simple/Standard/Pro/Auto INTERFACE DENSITY control — the progressive-disclosure escape hatch,\n * where Simple IS the pure-audio surface — plus the developer-links toggle) and Minimize (hide\n * the call view, call stays live). Call actions (Mute / Captions / Details / Type / End) live in\n * the bottom dock, the single home for each; Captions & End used to duplicate here and were\n * removed, and the standalone pure-audio headphones was folded into the gear's Density = Simple.\n * - RIGHT (review): \"Start live session\" (resume, affirmative leads) + Close — the\n * review session's exit lives up here in the header bar, not floating in the body.\n *\n * Which controls render is decided by the OVERLAY (it owns the disclosure model) and\n * passed down as booleans — this component stays purely presentational.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-banner',\n imports: [CommonModule],\n templateUrl: './realtime-agent-banner.component.html',\n styleUrl: './realtime-agent-banner.component.css'\n})\nexport class RealtimeAgentBannerComponent {\n /** Current connection / turn state — drives the orb animation + state label. */\n @Input({ required: true }) State!: RealtimeConnectionState;\n\n /**\n * COMPACT (orb/overlay) presentation: collapse the app-bar to a minimal identity + state\n * row. The duplicate orb, the redundant state pill, and the headphones / gear / expand\n * controls are dropped — the body already shows the big orb + name + state, and the lean\n * bottom dock (Mute / End / •••) owns the session actions. Minimize stays reachable so the\n * user can hide the call without ending it. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full console banner is unchanged).\n */\n @Input() Compact = false;\n\n /** Display name of the agent the voice session fronts (e.g. \"Sage\"). */\n @Input() AgentName = 'the agent';\n\n /**\n * Display name of the realtime model the live session runs on (e.g. \"GPT Realtime 2\").\n * Rendered as a subtle suffix in the identity line; hidden when null/empty.\n */\n @Input() ModelName: string | null = null;\n\n /** Whether developer affordances (the \"Open session\" link) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /** ID of the server-side agent session record (`MJ: AI Agent Sessions`), when known. */\n @Input() SessionID: string | null = null;\n\n /**\n * SESSION REVIEW presentation: the banner shows the past session's identity\n * (review badge, started→closed range, close-reason chip) instead of live turn-state,\n * and the action cluster swaps to Start-live + Close.\n */\n @Input() ReviewMode = false;\n\n /** When reviewing: when the past session started (`__mj_CreatedAt`). */\n @Input() ReviewStartedAt: Date | null = null;\n\n /** When reviewing: when the past session closed (null while it is still open). */\n @Input() ReviewClosedAt: Date | null = null;\n\n /** When reviewing: why the past session closed (`Explicit` | `Janitor` | `Shutdown` | `Error`), when known. */\n @Input() ReviewCloseReason: string | null = null;\n\n // ── App-bar action cluster (disclosure-gated by the overlay) ────────────────\n // STATE + WINDOW-CHROME only. Captions & End were removed (they duplicated the bottom dock's\n // controls — one home per control), and \"pure audio\" was folded into the gear's Density = Simple.\n\n /** Whether the gear (density escape hatch + dev toggle) renders (disclosure level 2+). */\n @Input() ShowGear = false;\n\n /**\n * Whether the interface-density segmented control renders inside the gear popover.\n * Default `true` (historical behaviour); a host may hide it via the overlay's\n * `[ShowDensityPicker]` input. The gear itself (and its developer-links toggle) still\n * renders when {@link ShowGear} is true even if the density picker is hidden.\n */\n @Input() ShowDensityPicker = true;\n\n /** Whether the Minimize control renders (live sessions only). */\n @Input() ShowMinimize = false;\n\n /** The user's current interface-density override (selected state in the gear popover). */\n @Input() Density: RealtimeUxDensity = 'auto';\n\n /** Emitted with the session record's ID when the dev \"Open session\" link is clicked. */\n @Output() OpenSessionRequested = new EventEmitter<string>();\n\n /** Emitted when the user toggles developer links from the gear popover. */\n @Output() DevModeToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user picks an interface density in the gear popover. */\n @Output() DensityChanged = new EventEmitter<RealtimeUxDensity>();\n\n /** Emitted when the user minimizes the call view (the call stays live). */\n @Output() MinimizeRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to RESUME the reviewed session as a new live call. */\n @Output() StartLiveRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to close the review and return to the conversation. */\n @Output() CloseRequested = new EventEmitter<void>();\n\n /** Whether the gear popover is open (closed by any outside click). */\n public GearOpen = false;\n\n /** The density choices the gear popover offers, in display order. */\n public readonly Densities: ReadonlyArray<{ Key: RealtimeUxDensity; Label: string }> = [\n { Key: 'simple', Label: 'Simple' },\n { Key: 'standard', Label: 'Standard' },\n { Key: 'pro', Label: 'Pro' },\n { Key: 'auto', Label: 'Auto' }\n ];\n\n /** True when the dev \"Open session\" link should render (gear on + session id known). */\n public get ShowOpenSession(): boolean {\n return this.DevMode && !!this.SessionID;\n }\n\n /** Emits the open-session request for the live agent session record. */\n public OpenSession(): void {\n if (this.SessionID) {\n this.OpenSessionRequested.emit(this.SessionID);\n }\n }\n\n /** Opens/closes the gear popover (stops propagation so the outside-click close skips it). */\n public ToggleGear(event: MouseEvent): void {\n event.stopPropagation();\n this.GearOpen = !this.GearOpen;\n }\n\n /** Any outside click closes the gear popover. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.GearOpen) {\n this.GearOpen = false;\n }\n }\n\n /** Gear popover: pick an interface density (the overlay applies + persists it). */\n public SelectDensity(density: RealtimeUxDensity): void {\n this.DensityChanged.emit(density);\n }\n\n /** Gear popover: toggle developer links. */\n public ToggleDev(): void {\n this.DevMode = !this.DevMode;\n this.DevModeToggled.emit(this.DevMode);\n }\n\n /** The review banner's \"started → closed\" time-range label (empty when the start is unknown). */\n public get ReviewRangeLabel(): string {\n if (!this.ReviewStartedAt) {\n return '';\n }\n const start = this.formatStamp(this.ReviewStartedAt);\n if (!this.ReviewClosedAt) {\n return start;\n }\n return `${start} → ${this.formatStamp(this.ReviewClosedAt, this.ReviewStartedAt)}`;\n }\n\n /** Human label for the close-reason chip (empty hides the chip). */\n public get ReviewCloseReasonLabel(): string {\n switch (this.ReviewCloseReason) {\n case 'Explicit': return 'Ended by user';\n case 'Janitor': return 'Closed by janitor';\n case 'Shutdown': return 'Closed at shutdown';\n case 'Error': return 'Ended with error';\n default: return '';\n }\n }\n\n /** Compact date+time stamp; same-day end stamps drop the redundant date part. */\n private formatStamp(date: Date, sameDayAs?: Date | null): string {\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();\n if (sameDayAs && date.toDateString() === sameDayAs.toDateString()) {\n return time;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n }\n\n /** Maps the realtime state to the orb's `data-state` (the orb only models active turn-states). */\n public OrbState(state: RealtimeConnectionState): 'speaking' | 'listening' | 'thinking' {\n switch (state) {\n case 'speaking': return 'speaking';\n case 'thinking': return 'thinking';\n default: return 'listening';\n }\n }\n\n /** Human-readable state label, agent-aware where it reads better. */\n public StateLabel(state: RealtimeConnectionState): string {\n switch (state) {\n case 'connecting': return 'Connecting…';\n case 'listening': return 'Listening';\n case 'speaking': return `${this.AgentName} is speaking…`;\n case 'thinking': return 'Working on it…';\n case 'error': return 'Connection error';\n case 'closed': return 'Call ended';\n default: return '';\n }\n }\n\n /** True while the state pill should show a spinner instead of the waveform. */\n public IsBusy(state: RealtimeConnectionState): boolean {\n return state === 'connecting' || state === 'thinking';\n }\n}\n","<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb · name · review badge · started→closed · close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb · overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand — the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">· {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock — the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density &amp; developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n"]}
@@ -89,9 +89,11 @@ export declare class RealtimeComposerComponent {
89
89
  * @param text the character(s) to seed (typically the single key that opened the composer).
90
90
  */
91
91
  AppendAndFocus(text: string): void;
92
+ /** Auto-resizes the textarea up to 140px height as text grows or contracts. */
93
+ AutoResize(): void;
92
94
  /** Send the typed text into the live session, then clear the input. */
93
95
  Send(): void;
94
- /** Enter sends (Shift+Enter is free for future multiline if the input becomes a textarea). */
96
+ /** Enter sends (Shift+Enter inserts a newline in textarea). */
95
97
  OnKeydown(event: KeyboardEvent): void;
96
98
  static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeComposerComponent, never>;
97
99
  static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeComposerComponent, "mj-realtime-composer", never, { "Open": { "alias": "Open"; "required": false; }; "Compact": { "alias": "Compact"; "required": false; }; "CaptionsOn": { "alias": "CaptionsOn"; "required": false; }; "ShowDetails": { "alias": "ShowDetails"; "required": false; }; "DetailsOn": { "alias": "DetailsOn"; "required": false; }; "IsMuted": { "alias": "IsMuted"; "required": false; }; }, { "OpenChanged": "OpenChanged"; "CaptionsToggled": "CaptionsToggled"; "DetailsToggled": "DetailsToggled"; "EndRequested": "EndRequested"; "MuteChanged": "MuteChanged"; }, never, never, true, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-composer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAkD,MAAM,eAAe,CAAC;;AAKpH;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAOa,yBAAyB;IACpC;;;;OAIG;IACM,IAAI,UAAS;IAEtB;;;;;;OAMG;IACM,OAAO,UAAS;IAEzB,6FAA6F;IACnF,WAAW,wBAA+B;IAEpD,yFAAyF;IAChF,UAAU,UAAQ;IAE3B,yFAAyF;IAChF,WAAW,UAAS;IAE7B,gFAAgF;IACvE,SAAS,UAAS;IAE3B,mFAAmF;IACzE,eAAe,wBAA+B;IAExD,oFAAoF;IAC1E,cAAc,qBAA4B;IAEpD,wEAAwE;IAC9D,YAAY,qBAA4B;IAElD,wFAAwF;IAC9E,WAAW,wBAA+B;IAEpD,uDAAuD;IAChD,KAAK,SAAM;IAElB;;;;OAIG;IACM,OAAO,UAAS;IAED,OAAO,CAAC,SAAS,CAAC,CAA+B;IAEzE,OAAO,CAAC,QAAQ,CAAkC;IAElD,qDAAqD;IACrD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,kFAAkF;IAClF,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED;;;OAGG;IACI,QAAQ,UAAS;IAExB,qGAAqG;IAC9F,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK1C,2DAA2D;IAEpD,eAAe,IAAI,IAAI;IAM9B,iFAAiF;IAC1E,UAAU,IAAI,IAAI;IAKzB,yDAAyD;IAClD,cAAc,IAAI,IAAI;IAK7B,6EAA6E;IACtE,UAAU,IAAI,IAAI;IAIzB;;;;;;;;OAQG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAUzC,uEAAuE;IAChE,IAAI,IAAI,IAAI;IAQnB,8FAA8F;IACvF,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;yCAnIjC,yBAAyB;2CAAzB,yBAAyB;CAyIrC"}
1
+ {"version":3,"file":"realtime-composer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAkD,MAAM,eAAe,CAAC;;AAKpH;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAOa,yBAAyB;IACpC;;;;OAIG;IACM,IAAI,UAAS;IAEtB;;;;;;OAMG;IACM,OAAO,UAAS;IAEzB,6FAA6F;IACnF,WAAW,wBAA+B;IAEpD,yFAAyF;IAChF,UAAU,UAAQ;IAE3B,yFAAyF;IAChF,WAAW,UAAS;IAE7B,gFAAgF;IACvE,SAAS,UAAS;IAE3B,mFAAmF;IACzE,eAAe,wBAA+B;IAExD,oFAAoF;IAC1E,cAAc,qBAA4B;IAEpD,wEAAwE;IAC9D,YAAY,qBAA4B;IAElD,wFAAwF;IAC9E,WAAW,wBAA+B;IAEpD,uDAAuD;IAChD,KAAK,SAAM;IAElB;;;;OAIG;IACM,OAAO,UAAS;IAED,OAAO,CAAC,SAAS,CAAC,CAAqD;IAE/F,OAAO,CAAC,QAAQ,CAAkC;IAElD,qDAAqD;IACrD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,kFAAkF;IAClF,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED;;;OAGG;IACI,QAAQ,UAAS;IAExB,qGAAqG;IAC9F,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK1C,2DAA2D;IAEpD,eAAe,IAAI,IAAI;IAM9B,iFAAiF;IAC1E,UAAU,IAAI,IAAI;IAKzB,yDAAyD;IAClD,cAAc,IAAI,IAAI;IAK7B,6EAA6E;IACtE,UAAU,IAAI,IAAI;IAIzB;;;;;;;;OAQG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWzC,+EAA+E;IACxE,UAAU,IAAI,IAAI;IASzB,uEAAuE;IAChE,IAAI,IAAI,IAAI;IAYnB,+DAA+D;IACxD,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;yCAlJjC,yBAAyB;2CAAzB,yBAAyB;CAwJrC"}
@@ -155,9 +155,9 @@ function RealtimeComposerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1)
155
155
  i0.ɵɵelementEnd();
156
156
  i0.ɵɵconditionalCreate(6, RealtimeComposerComponent_Conditional_2_Conditional_6_Template, 2, 4, "button", 27);
157
157
  i0.ɵɵelementEnd();
158
- i0.ɵɵelementStart(7, "div", 28)(8, "input", 29, 0);
159
- i0.ɵɵtwoWayListener("ngModelChange", function RealtimeComposerComponent_Conditional_2_Template_input_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.Draft, $event) || (ctx_r2.Draft = $event); return i0.ɵɵresetView($event); });
160
- i0.ɵɵlistener("keydown", function RealtimeComposerComponent_Conditional_2_Template_input_keydown_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnKeydown($event)); });
158
+ i0.ɵɵelementStart(7, "div", 28)(8, "textarea", 29, 0);
159
+ i0.ɵɵtwoWayListener("ngModelChange", function RealtimeComposerComponent_Conditional_2_Template_textarea_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.Draft, $event) || (ctx_r2.Draft = $event); return i0.ɵɵresetView($event); });
160
+ i0.ɵɵlistener("keydown", function RealtimeComposerComponent_Conditional_2_Template_textarea_keydown_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnKeydown($event)); })("input", function RealtimeComposerComponent_Conditional_2_Template_textarea_input_8_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.AutoResize()); });
161
161
  i0.ɵɵelementEnd();
162
162
  i0.ɵɵelementStart(10, "span", 30);
163
163
  i0.ɵɵtext(11, "\u21B5 send");
@@ -169,6 +169,10 @@ function RealtimeComposerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1)
169
169
  i0.ɵɵelementStart(14, "button", 33);
170
170
  i0.ɵɵlistener("click", function RealtimeComposerComponent_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OpenChanged.emit(false)); });
171
171
  i0.ɵɵelement(15, "i", 34);
172
+ i0.ɵɵelementEnd();
173
+ i0.ɵɵelementStart(16, "button", 35);
174
+ i0.ɵɵlistener("click", function RealtimeComposerComponent_Conditional_2_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.EndRequested.emit()); });
175
+ i0.ɵɵelement(17, "i", 16);
172
176
  i0.ɵɵelementEnd()();
173
177
  } if (rf & 2) {
174
178
  const ctx_r2 = i0.ɵɵnextContext();
@@ -303,6 +307,16 @@ export class RealtimeComposerComponent {
303
307
  el.value = this.Draft;
304
308
  el.focus();
305
309
  el.setSelectionRange(this.Draft.length, this.Draft.length);
310
+ this.AutoResize();
311
+ }
312
+ }
313
+ /** Auto-resizes the textarea up to 140px height as text grows or contracts. */
314
+ AutoResize() {
315
+ const el = this.dockInput?.nativeElement;
316
+ if (el && el instanceof HTMLTextAreaElement) {
317
+ el.style.height = 'auto';
318
+ const newHeight = Math.max(24, Math.min(el.scrollHeight, 140));
319
+ el.style.height = `${newHeight}px`;
306
320
  }
307
321
  }
308
322
  /** Send the typed text into the live session, then clear the input. */
@@ -312,8 +326,12 @@ export class RealtimeComposerComponent {
312
326
  }
313
327
  this.realtime.SendText(this.Draft);
314
328
  this.Draft = '';
329
+ const el = this.dockInput?.nativeElement;
330
+ if (el && el instanceof HTMLTextAreaElement) {
331
+ el.style.height = 'auto';
332
+ }
315
333
  }
316
- /** Enter sends (Shift+Enter is free for future multiline if the input becomes a textarea). */
334
+ /** Enter sends (Shift+Enter inserts a newline in textarea). */
317
335
  OnKeydown(event) {
318
336
  if (event.key === 'Enter' && !event.shiftKey) {
319
337
  event.preventDefault();
@@ -328,15 +346,15 @@ export class RealtimeComposerComponent {
328
346
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.dockInput = _t.first);
329
347
  } }, hostBindings: function RealtimeComposerComponent_HostBindings(rf, ctx) { if (rf & 1) {
330
348
  i0.ɵɵlistener("click", function RealtimeComposerComponent_click_HostBindingHandler() { return ctx.OnDocumentClick(); }, i0.ɵɵresolveDocument);
331
- } }, inputs: { Open: "Open", Compact: "Compact", CaptionsOn: "CaptionsOn", ShowDetails: "ShowDetails", DetailsOn: "DetailsOn", IsMuted: "IsMuted" }, outputs: { OpenChanged: "OpenChanged", CaptionsToggled: "CaptionsToggled", DetailsToggled: "DetailsToggled", EndRequested: "EndRequested", MuteChanged: "MuteChanged" }, decls: 3, vars: 1, consts: [["dockInput", ""], ["role", "group", "aria-label", "Call controls", 1, "dock-lean"], ["role", "group", "aria-label", "Call controls", 1, "strip"], [1, "dock"], [1, "lean-more"], ["role", "menu", "aria-label", "More call controls", 1, "lean-sheet", 3, "click"], ["type", "button", 1, "lean-sheet__btn", 3, "lean-sheet__btn--on", "title"], ["type", "button", "title", "Type into the live session", "aria-label", "Open the typed-input composer", 1, "lean-sheet__btn", 3, "click"], ["aria-hidden", "true", 1, "fa-regular", "fa-keyboard"], ["type", "button", "title", "More controls", "aria-label", "More call controls", 1, "lean-ctrl", "lean-ctrl--more", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-ellipsis"], ["type", "button", 1, "lean-ctrl", "lean-ctrl--more", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-closed-captioning"], ["type", "button", 1, "lean-ctrl", "lean-ctrl--lg", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", 3, "ngClass"], ["type", "button", "title", "End call", "aria-label", "End call", 1, "lean-ctrl", "lean-ctrl--lg", "lean-ctrl--end", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone-slash"], ["type", "button", 1, "lean-sheet__btn", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-table-columns"], [1, "ctrl-group"], ["type", "button", 1, "ctrl", 3, "click", "title"], [1, "ctrl-label"], ["type", "button", "title", "Type into the live session", "aria-label", "Open the typed-input composer", 1, "ctrl", 3, "click"], ["type", "button", "title", "End call", "aria-label", "End call", 1, "ctrl", "ctrl--end", 3, "click"], [1, "ctrl-label", "ctrl-label--end"], [1, "dock__minis"], ["type", "button", 1, "mini", 3, "click", "title"], ["type", "button", 1, "mini", 3, "mini--on", "title"], [1, "dock__box"], ["type", "text", "placeholder", "Type into the live session \u2014 joins this same voice call\u2026", "aria-label", "Type a message into the live voice session", 1, "dock__input", 3, "ngModelChange", "keydown", "ngModel"], ["aria-hidden", "true", 1, "dock__hint"], ["type", "button", "title", "Send into live session", "aria-label", "Send", 1, "dock__send", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-paper-plane"], ["type", "button", "title", "Hide typing \u2014 back to the voice controls", "aria-label", "Close the typed-input composer", 1, "mini", "dock__hide", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"]], template: function RealtimeComposerComponent_Template(rf, ctx) { if (rf & 1) {
332
- i0.ɵɵconditionalCreate(0, RealtimeComposerComponent_Conditional_0_Template, 16, 15, "div", 1)(1, RealtimeComposerComponent_Conditional_1_Template, 22, 11, "div", 2)(2, RealtimeComposerComponent_Conditional_2_Template, 16, 12, "div", 3);
349
+ } }, inputs: { Open: "Open", Compact: "Compact", CaptionsOn: "CaptionsOn", ShowDetails: "ShowDetails", DetailsOn: "DetailsOn", IsMuted: "IsMuted" }, outputs: { OpenChanged: "OpenChanged", CaptionsToggled: "CaptionsToggled", DetailsToggled: "DetailsToggled", EndRequested: "EndRequested", MuteChanged: "MuteChanged" }, decls: 3, vars: 1, consts: [["dockInput", ""], ["role", "group", "aria-label", "Call controls", 1, "dock-lean"], ["role", "group", "aria-label", "Call controls", 1, "strip"], [1, "dock"], [1, "lean-more"], ["role", "menu", "aria-label", "More call controls", 1, "lean-sheet", 3, "click"], ["type", "button", 1, "lean-sheet__btn", 3, "lean-sheet__btn--on", "title"], ["type", "button", "title", "Type into the live session", "aria-label", "Open the typed-input composer", 1, "lean-sheet__btn", 3, "click"], ["aria-hidden", "true", 1, "fa-regular", "fa-keyboard"], ["type", "button", "title", "More controls", "aria-label", "More call controls", 1, "lean-ctrl", "lean-ctrl--more", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-ellipsis"], ["type", "button", 1, "lean-ctrl", "lean-ctrl--more", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-closed-captioning"], ["type", "button", 1, "lean-ctrl", "lean-ctrl--lg", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", 3, "ngClass"], ["type", "button", "title", "End call", "aria-label", "End call", 1, "lean-ctrl", "lean-ctrl--lg", "lean-ctrl--end", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone-slash"], ["type", "button", 1, "lean-sheet__btn", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-table-columns"], [1, "ctrl-group"], ["type", "button", 1, "ctrl", 3, "click", "title"], [1, "ctrl-label"], ["type", "button", "title", "Type into the live session", "aria-label", "Open the typed-input composer", 1, "ctrl", 3, "click"], ["type", "button", "title", "End call", "aria-label", "End call", 1, "ctrl", "ctrl--end", 3, "click"], [1, "ctrl-label", "ctrl-label--end"], [1, "dock__minis"], ["type", "button", 1, "mini", 3, "click", "title"], ["type", "button", 1, "mini", 3, "mini--on", "title"], [1, "dock__box"], ["rows", "1", "placeholder", "Type into the live session \u2014 joins this same voice call\u2026", "aria-label", "Type a message into the live voice session", 1, "dock__input", 3, "ngModelChange", "keydown", "input", "ngModel"], ["aria-hidden", "true", 1, "dock__hint"], ["type", "button", "title", "Send into live session", "aria-label", "Send", 1, "dock__send", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-paper-plane"], ["type", "button", "title", "Hide typing \u2014 back to the voice controls", "aria-label", "Close the typed-input composer", 1, "mini", "dock__hide", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"], ["type", "button", "title", "End call", "aria-label", "End call", 1, "mini", "mini--end", 3, "click"]], template: function RealtimeComposerComponent_Template(rf, ctx) { if (rf & 1) {
350
+ i0.ɵɵconditionalCreate(0, RealtimeComposerComponent_Conditional_0_Template, 16, 15, "div", 1)(1, RealtimeComposerComponent_Conditional_1_Template, 22, 11, "div", 2)(2, RealtimeComposerComponent_Conditional_2_Template, 18, 12, "div", 3);
333
351
  } if (rf & 2) {
334
352
  i0.ɵɵconditional(ctx.StripMode && ctx.Compact ? 0 : ctx.StripMode ? 1 : 2);
335
- } }, dependencies: [CommonModule, i1.NgClass, FormsModule, i2.DefaultValueAccessor, i2.NgControlStatus, i2.NgModel], styles: ["[_nghost-%COMP%] {\n display: block;\n}\n\n\n.strip[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n gap: 22px;\n padding: 20px 22px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.ctrl-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.ctrl[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 18px;\n transition: all 150ms ease;\n}\n.ctrl[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.ctrl--on[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.ctrl--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.ctrl--end[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.ctrl--end[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n.ctrl-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n margin-top: 6px;\n font-weight: 500;\n}\n.ctrl-label--end[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n.dock[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n animation: _ngcontent-%COMP%_dock-in 320ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_dock-in {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.dock__minis[_ngcontent-%COMP%] {\n display: flex;\n gap: 7px;\n flex-shrink: 0;\n}\n.mini[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 13.5px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n transition: all 140ms ease;\n}\n.mini[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mini--on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.mini--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.dock__box[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 5px 6px 5px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n transition: border-color 140ms ease, box-shadow 140ms ease;\n}\n.dock__box[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.dock__input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13.5px;\n}\n.dock__input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.dock__hint[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n}\n\n.dock__send[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n border: 0;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 12px;\n flex-shrink: 0;\n transition: background 150ms ease;\n}\n.dock__send[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n}\n.dock__send[_ngcontent-%COMP%]:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n\n.dock__hide[_ngcontent-%COMP%] {\n border-style: dashed;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n}\n.dock__hide[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n\n\n\n.dock-lean[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 14px;\n padding: 16px 18px 20px;\n background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--mj-bg-page) 35%, transparent));\n}\n\n.lean-ctrl[_ngcontent-%COMP%] {\n display: grid;\n place-items: center;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n.lean-ctrl[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n transform: translateY(-1px);\n}\n.lean-ctrl--lg[_ngcontent-%COMP%] {\n width: 58px;\n height: 58px;\n font-size: 19px;\n}\n.lean-ctrl--more[_ngcontent-%COMP%] {\n width: 46px;\n height: 46px;\n font-size: 16px;\n}\n.lean-ctrl--on[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.lean-ctrl--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.lean-ctrl--end[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.lean-ctrl--end[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n filter: brightness(0.94);\n}\n\n\n.lean-more[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n}\n.lean-sheet[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 12px);\n left: 50%;\n transform: translateX(-50%) translateY(8px);\n display: flex;\n gap: 10px;\n padding: 10px;\n border-radius: var(--mj-radius-lg, 16px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 18px 50px -22px rgba(0, 0, 0, 0.6);\n opacity: 0;\n pointer-events: none;\n transition: opacity 200ms ease, transform 200ms ease;\n z-index: 5;\n}\n.lean-more--open[_ngcontent-%COMP%] .lean-sheet[_ngcontent-%COMP%] {\n opacity: 1;\n pointer-events: auto;\n transform: translateX(-50%) translateY(0);\n}\n.lean-sheet__btn[_ngcontent-%COMP%] {\n display: grid;\n place-items: center;\n gap: 3px;\n width: 56px;\n padding: 8px 4px;\n border-radius: var(--mj-radius-md, 10px);\n border: 1px solid transparent;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 16px;\n transition: all 140ms ease;\n}\n.lean-sheet__btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.lean-sheet__btn--on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.lean-sheet__btn[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.lean-sheet__btn--on[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}"] });
353
+ } }, dependencies: [CommonModule, i1.NgClass, FormsModule, i2.DefaultValueAccessor, i2.NgControlStatus, i2.NgModel], styles: ["[_nghost-%COMP%] {\n display: block;\n}\n\n\n.strip[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n gap: 22px;\n padding: 20px 22px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.ctrl-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.ctrl[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 18px;\n transition: all 150ms ease;\n}\n.ctrl[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.ctrl--on[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.ctrl--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.ctrl--end[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.ctrl--end[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n.ctrl-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n margin-top: 6px;\n font-weight: 500;\n}\n.ctrl-label--end[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n.dock[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n animation: _ngcontent-%COMP%_dock-in 320ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_dock-in {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.dock__minis[_ngcontent-%COMP%] {\n display: flex;\n gap: 7px;\n flex-shrink: 0;\n}\n.mini[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 13.5px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n transition: all 140ms ease;\n}\n.mini[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mini--on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.mini--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.dock__box[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 9px;\n padding: 5px 6px 5px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 20px;\n background: var(--mj-bg-surface-card);\n transition: border-color 140ms ease, box-shadow 140ms ease, border-radius 140ms ease;\n}\n.dock__box[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.dock__input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13.5px;\n line-height: 1.45;\n resize: none;\n height: 24px;\n max-height: 140px;\n overflow-y: auto;\n padding: 3px 0 4px 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.dock__input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.dock__hint[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n}\n\n.dock__send[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n border: 0;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 12px;\n flex-shrink: 0;\n transition: background 150ms ease;\n}\n.dock__send[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n}\n.dock__send[_ngcontent-%COMP%]:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n\n.dock__hide[_ngcontent-%COMP%] {\n border-style: dashed;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n}\n.dock__hide[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.mini--end[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n flex-shrink: 0;\n}\n.mini--end[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n\n\n\n.dock-lean[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 14px;\n padding: 16px 18px 20px;\n background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--mj-bg-page) 35%, transparent));\n}\n\n.lean-ctrl[_ngcontent-%COMP%] {\n display: grid;\n place-items: center;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n.lean-ctrl[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n transform: translateY(-1px);\n}\n.lean-ctrl--lg[_ngcontent-%COMP%] {\n width: 58px;\n height: 58px;\n font-size: 19px;\n}\n.lean-ctrl--more[_ngcontent-%COMP%] {\n width: 46px;\n height: 46px;\n font-size: 16px;\n}\n.lean-ctrl--on[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.lean-ctrl--muted[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.lean-ctrl--end[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.lean-ctrl--end[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n filter: brightness(0.94);\n}\n\n\n.lean-more[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n}\n.lean-sheet[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 12px);\n left: 50%;\n transform: translateX(-50%) translateY(8px);\n display: flex;\n gap: 10px;\n padding: 10px;\n border-radius: var(--mj-radius-lg, 16px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 18px 50px -22px rgba(0, 0, 0, 0.6);\n opacity: 0;\n pointer-events: none;\n transition: opacity 200ms ease, transform 200ms ease;\n z-index: 5;\n}\n.lean-more--open[_ngcontent-%COMP%] .lean-sheet[_ngcontent-%COMP%] {\n opacity: 1;\n pointer-events: auto;\n transform: translateX(-50%) translateY(0);\n}\n.lean-sheet__btn[_ngcontent-%COMP%] {\n display: grid;\n place-items: center;\n gap: 3px;\n width: 56px;\n padding: 8px 4px;\n border-radius: var(--mj-radius-md, 10px);\n border: 1px solid transparent;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 16px;\n transition: all 140ms ease;\n}\n.lean-sheet__btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.lean-sheet__btn--on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.lean-sheet__btn[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.lean-sheet__btn--on[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}"] });
336
354
  }
337
355
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeComposerComponent, [{
338
356
  type: Component,
339
- args: [{ standalone: true, selector: 'mj-realtime-composer', imports: [CommonModule, FormsModule], template: "@if (StripMode && Compact) {\n <!-- COMPACT (Calm Orb \u00B7 overlay): the lean dock \u2014 Mute + End + a first-class Captions toggle\n (kept out of the \"\u2022\u2022\u2022\" so text stays ONE TAP in the overlay, where the banner no longer\n carries a duplicate CC) + a \"\u2022\u2022\u2022\" that blooms a small sheet with the remaining secondary\n actions (Details / Type). Round controls, red End \u2014 matches the mockup. -->\n <div class=\"dock-lean\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"lean-more\" [class.lean-more--open]=\"MoreOpen\">\n <div class=\"lean-sheet\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"More call controls\">\n @if (ShowDetails) {\n <button type=\"button\" class=\"lean-sheet__btn\" [class.lean-sheet__btn--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit(); MoreOpen = false\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n <small>Details</small>\n </button>\n }\n <button type=\"button\" class=\"lean-sheet__btn\"\n (click)=\"OpenChanged.emit(true); MoreOpen = false\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n <small>Type</small>\n </button>\n </div>\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"MoreOpen\"\n (click)=\"ToggleMore($event)\"\n title=\"More controls\" aria-label=\"More call controls\"\n [attr.aria-expanded]=\"MoreOpen\">\n <i class=\"fa-solid fa-ellipsis\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- Captions: first-class in the lean dock (the overlay's only text toggle now). -->\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg\" [class.lean-ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg lean-ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n} @else if (StripMode) {\n <!-- Levels 0\u20131: phone-call strip \u2014 big round controls, nothing to configure.\n Captions arrives at level 1 WITH the text it controls; Details peeks at the\n surface panels on demand; End stays the deliberate rightmost action. -->\n <div class=\"strip\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">{{ IsMuted ? 'Unmute' : 'Mute' }}</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Captions</span>\n </div>\n\n @if (ShowDetails) {\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Details</span>\n </div>\n }\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" (click)=\"OpenChanged.emit(true)\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Type</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label ctrl-label--end\">End call</span>\n </div>\n </div>\n} @else {\n <!-- Level 2+: the fused dock \u2014 compact minis + the in-call composer in ONE bottom bar. -->\n <div class=\"dock\">\n <div class=\"dock__minis\">\n <button type=\"button\" class=\"mini\" [class.mini--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n @if (ShowDetails) {\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Show the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dock__box\">\n <input\n #dockInput\n type=\"text\"\n class=\"dock__input\"\n placeholder=\"Type into the live session \u2014 joins this same voice call\u2026\"\n [(ngModel)]=\"Draft\"\n (keydown)=\"OnKeydown($event)\"\n aria-label=\"Type a message into the live voice session\" />\n <span class=\"dock__hint\" aria-hidden=\"true\">\u21B5 send</span>\n <button\n class=\"dock__send\"\n type=\"button\"\n [disabled]=\"!CanSend\"\n (click)=\"Send()\"\n title=\"Send into live session\"\n aria-label=\"Send\">\n <i class=\"fa-solid fa-paper-plane\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button type=\"button\" class=\"mini dock__hide\" (click)=\"OpenChanged.emit(false)\"\n title=\"Hide typing \u2014 back to the voice controls\"\n aria-label=\"Close the typed-input composer\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n}\n", styles: [":host {\n display: block;\n}\n\n/* ---------- Levels 0\u20131: phone-call strip (big round controls, centered) ---------- */\n.strip {\n position: relative;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n gap: 22px;\n padding: 20px 22px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.ctrl-group {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.ctrl {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 18px;\n transition: all 150ms ease;\n}\n.ctrl:hover {\n background: var(--mj-bg-surface-hover);\n}\n.ctrl--on {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.ctrl--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.ctrl--end {\n width: 60px;\n height: 60px;\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.ctrl--end:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n.ctrl-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n margin-top: 6px;\n font-weight: 500;\n}\n.ctrl-label--end {\n color: var(--mj-status-error);\n}\n\n/* ---------- Level 2+: the fused dock (minis + composer in one bar) ---------- */\n.dock {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n animation: dock-in 320ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes dock-in {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.dock__minis {\n display: flex;\n gap: 7px;\n flex-shrink: 0;\n}\n.mini {\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 13.5px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n transition: all 140ms ease;\n}\n.mini:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mini--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.mini--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.dock__box {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 5px 6px 5px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n transition: border-color 140ms ease, box-shadow 140ms ease;\n}\n.dock__box:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.dock__input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13.5px;\n}\n.dock__input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.dock__hint {\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n}\n\n.dock__send {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n border: 0;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 12px;\n flex-shrink: 0;\n transition: background 150ms ease;\n}\n.dock__send:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n}\n.dock__send:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n/* The dock's hide control \u2014 typing is a two-way door, never permanent chrome. */\n.dock__hide {\n border-style: dashed;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n}\n.dock__hide:hover {\n color: var(--mj-text-primary);\n}\n\n/* ============================================================= COMPACT (Calm Orb \u00B7 overlay)\n The lean dock \u2014 Mute + End + a \"\u2022\u2022\u2022\" that blooms a small sheet (Captions / Details / Type).\n Round controls, red End \u2014 matches the mockup. No 5-button bar, no overlapping hint. */\n.dock-lean {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 14px;\n padding: 16px 18px 20px;\n background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--mj-bg-page) 35%, transparent));\n}\n\n.lean-ctrl {\n display: grid;\n place-items: center;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n.lean-ctrl:hover {\n background: var(--mj-bg-surface-hover);\n transform: translateY(-1px);\n}\n.lean-ctrl--lg {\n width: 58px;\n height: 58px;\n font-size: 19px;\n}\n.lean-ctrl--more {\n width: 46px;\n height: 46px;\n font-size: 16px;\n}\n.lean-ctrl--on {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.lean-ctrl--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.lean-ctrl--end {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.lean-ctrl--end:hover {\n background: var(--mj-status-error);\n filter: brightness(0.94);\n}\n\n/* The \"\u2022\u2022\u2022\" overflow + its blooming sheet. */\n.lean-more {\n position: relative;\n display: flex;\n align-items: center;\n}\n.lean-sheet {\n position: absolute;\n bottom: calc(100% + 12px);\n left: 50%;\n transform: translateX(-50%) translateY(8px);\n display: flex;\n gap: 10px;\n padding: 10px;\n border-radius: var(--mj-radius-lg, 16px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 18px 50px -22px rgba(0, 0, 0, 0.6);\n opacity: 0;\n pointer-events: none;\n transition: opacity 200ms ease, transform 200ms ease;\n z-index: 5;\n}\n.lean-more--open .lean-sheet {\n opacity: 1;\n pointer-events: auto;\n transform: translateX(-50%) translateY(0);\n}\n.lean-sheet__btn {\n display: grid;\n place-items: center;\n gap: 3px;\n width: 56px;\n padding: 8px 4px;\n border-radius: var(--mj-radius-md, 10px);\n border: 1px solid transparent;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 16px;\n transition: all 140ms ease;\n}\n.lean-sheet__btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.lean-sheet__btn--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.lean-sheet__btn small {\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.lean-sheet__btn--on small {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n"] }]
357
+ args: [{ standalone: true, selector: 'mj-realtime-composer', imports: [CommonModule, FormsModule], template: "@if (StripMode && Compact) {\n <!-- COMPACT (Calm Orb \u00B7 overlay): the lean dock \u2014 Mute + End + a first-class Captions toggle\n (kept out of the \"\u2022\u2022\u2022\" so text stays ONE TAP in the overlay, where the banner no longer\n carries a duplicate CC) + a \"\u2022\u2022\u2022\" that blooms a small sheet with the remaining secondary\n actions (Details / Type). Round controls, red End \u2014 matches the mockup. -->\n <div class=\"dock-lean\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"lean-more\" [class.lean-more--open]=\"MoreOpen\">\n <div class=\"lean-sheet\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"More call controls\">\n @if (ShowDetails) {\n <button type=\"button\" class=\"lean-sheet__btn\" [class.lean-sheet__btn--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit(); MoreOpen = false\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n <small>Details</small>\n </button>\n }\n <button type=\"button\" class=\"lean-sheet__btn\"\n (click)=\"OpenChanged.emit(true); MoreOpen = false\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n <small>Type</small>\n </button>\n </div>\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"MoreOpen\"\n (click)=\"ToggleMore($event)\"\n title=\"More controls\" aria-label=\"More call controls\"\n [attr.aria-expanded]=\"MoreOpen\">\n <i class=\"fa-solid fa-ellipsis\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- Captions: first-class in the lean dock (the overlay's only text toggle now). -->\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg\" [class.lean-ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg lean-ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n} @else if (StripMode) {\n <!-- Levels 0\u20131: phone-call strip \u2014 big round controls, nothing to configure.\n Captions arrives at level 1 WITH the text it controls; Details peeks at the\n surface panels on demand; End stays the deliberate rightmost action. -->\n <div class=\"strip\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">{{ IsMuted ? 'Unmute' : 'Mute' }}</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Captions</span>\n </div>\n\n @if (ShowDetails) {\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Details</span>\n </div>\n }\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" (click)=\"OpenChanged.emit(true)\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Type</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label ctrl-label--end\">End call</span>\n </div>\n </div>\n} @else {\n <!-- Level 2+: the fused dock \u2014 compact minis + the in-call composer in ONE bottom bar. -->\n <div class=\"dock\">\n <div class=\"dock__minis\">\n <button type=\"button\" class=\"mini\" [class.mini--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first \u2014 back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n @if (ShowDetails) {\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Show the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dock__box\">\n <textarea\n #dockInput\n class=\"dock__input\"\n rows=\"1\"\n placeholder=\"Type into the live session \u2014 joins this same voice call\u2026\"\n [(ngModel)]=\"Draft\"\n (keydown)=\"OnKeydown($event)\"\n (input)=\"AutoResize()\"\n aria-label=\"Type a message into the live voice session\"></textarea>\n <span class=\"dock__hint\" aria-hidden=\"true\">\u21B5 send</span>\n <button\n class=\"dock__send\"\n type=\"button\"\n [disabled]=\"!CanSend\"\n (click)=\"Send()\"\n title=\"Send into live session\"\n aria-label=\"Send\">\n <i class=\"fa-solid fa-paper-plane\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button type=\"button\" class=\"mini dock__hide\" (click)=\"OpenChanged.emit(false)\"\n title=\"Hide typing \u2014 back to the voice controls\"\n aria-label=\"Close the typed-input composer\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini mini--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n}\n", styles: [":host {\n display: block;\n}\n\n/* ---------- Levels 0\u20131: phone-call strip (big round controls, centered) ---------- */\n.strip {\n position: relative;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n gap: 22px;\n padding: 20px 22px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.ctrl-group {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.ctrl {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 18px;\n transition: all 150ms ease;\n}\n.ctrl:hover {\n background: var(--mj-bg-surface-hover);\n}\n.ctrl--on {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.ctrl--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.ctrl--end {\n width: 60px;\n height: 60px;\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.ctrl--end:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n.ctrl-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n margin-top: 6px;\n font-weight: 500;\n}\n.ctrl-label--end {\n color: var(--mj-status-error);\n}\n\n/* ---------- Level 2+: the fused dock (minis + composer in one bar) ---------- */\n.dock {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 18px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n animation: dock-in 320ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes dock-in {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.dock__minis {\n display: flex;\n gap: 7px;\n flex-shrink: 0;\n}\n.mini {\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 13.5px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n transition: all 140ms ease;\n}\n.mini:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mini--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.mini--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.dock__box {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 9px;\n padding: 5px 6px 5px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 20px;\n background: var(--mj-bg-surface-card);\n transition: border-color 140ms ease, box-shadow 140ms ease, border-radius 140ms ease;\n}\n.dock__box:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.dock__input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13.5px;\n line-height: 1.45;\n resize: none;\n height: 24px;\n max-height: 140px;\n overflow-y: auto;\n padding: 3px 0 4px 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.dock__input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.dock__hint {\n font-size: 10.5px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n}\n\n.dock__send {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n border: 0;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-size: 12px;\n flex-shrink: 0;\n transition: background 150ms ease;\n}\n.dock__send:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n}\n.dock__send:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n/* The dock's hide control \u2014 typing is a two-way door, never permanent chrome. */\n.dock__hide {\n border-style: dashed;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n}\n.dock__hide:hover {\n color: var(--mj-text-primary);\n}\n\n.mini--end {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n flex-shrink: 0;\n}\n.mini--end:hover {\n background: var(--mj-status-error);\n filter: brightness(0.92);\n}\n\n/* ============================================================= COMPACT (Calm Orb \u00B7 overlay)\n The lean dock \u2014 Mute + End + a \"\u2022\u2022\u2022\" that blooms a small sheet (Captions / Details / Type).\n Round controls, red End \u2014 matches the mockup. No 5-button bar, no overlapping hint. */\n.dock-lean {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 14px;\n padding: 16px 18px 20px;\n background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--mj-bg-page) 35%, transparent));\n}\n\n.lean-ctrl {\n display: grid;\n place-items: center;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n.lean-ctrl:hover {\n background: var(--mj-bg-surface-hover);\n transform: translateY(-1px);\n}\n.lean-ctrl--lg {\n width: 58px;\n height: 58px;\n font-size: 19px;\n}\n.lean-ctrl--more {\n width: 46px;\n height: 46px;\n font-size: 16px;\n}\n.lean-ctrl--on {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.lean-ctrl--muted {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n.lean-ctrl--end {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n font-size: 20px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n.lean-ctrl--end:hover {\n background: var(--mj-status-error);\n filter: brightness(0.94);\n}\n\n/* The \"\u2022\u2022\u2022\" overflow + its blooming sheet. */\n.lean-more {\n position: relative;\n display: flex;\n align-items: center;\n}\n.lean-sheet {\n position: absolute;\n bottom: calc(100% + 12px);\n left: 50%;\n transform: translateX(-50%) translateY(8px);\n display: flex;\n gap: 10px;\n padding: 10px;\n border-radius: var(--mj-radius-lg, 16px);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 18px 50px -22px rgba(0, 0, 0, 0.6);\n opacity: 0;\n pointer-events: none;\n transition: opacity 200ms ease, transform 200ms ease;\n z-index: 5;\n}\n.lean-more--open .lean-sheet {\n opacity: 1;\n pointer-events: auto;\n transform: translateX(-50%) translateY(0);\n}\n.lean-sheet__btn {\n display: grid;\n place-items: center;\n gap: 3px;\n width: 56px;\n padding: 8px 4px;\n border-radius: var(--mj-radius-md, 10px);\n border: 1px solid transparent;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 16px;\n transition: all 140ms ease;\n}\n.lean-sheet__btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.lean-sheet__btn--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.lean-sheet__btn small {\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.lean-sheet__btn--on small {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n"] }]
340
358
  }], null, { Open: [{
341
359
  type: Input
342
360
  }], Compact: [{
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-composer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts","../../../../src/lib/components/realtime/realtime-composer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ElementRef, EventEmitter, HostListener, Input, Output, ViewChild, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RealtimeSessionService } from '../../services/realtime-session.service';\n\n/**\n * The call overlay's BOTTOM DOCK — the progressive-disclosure composer\n * (`plans/realtime/mockups/redesign-a-progressive.html`). One component, two shapes,\n * keyed off the overlay's disclosure {@link Level}:\n *\n * - **Levels 0–1 (phone-call strip)** — big round call controls, centered: Mute, the\n * Captions toggle (level 1+, arriving WITH the text it controls), the Details peek\n * (level 0 paths where the surface panel isn't earned yet — lets the user look at the\n * Activity/Whiteboard panels on demand), the Type control, and End call. There's no visible\n * composer yet — the Type control opens it, and so does simply starting to type (the overlay\n * captures the first printable keystroke and seeds it via {@link AppendAndFocus}).\n * - **Level 2+ (the dock)** — mute/captions shrink to compact minis and the in-call text\n * input docks beside them (one bottom bar, per Redesign A's fused composer+controls).\n * Submit calls {@link RealtimeSessionService.SendText}, which injects the text as a user\n * turn into the SAME live voice call.\n *\n * Mute talks to the session service directly (pure local toggle); captions / Details /\n * End are emitted up so the overlay shell owns that state and lifecycle.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-composer',\n imports: [CommonModule, FormsModule],\n templateUrl: './realtime-composer.component.html',\n styleUrl: './realtime-composer.component.css'\n})\nexport class RealtimeComposerComponent {\n /**\n * Whether the typed-input dock is OPEN. A two-way door owned by the user: the strip's\n * Type control (or the T hotkey) opens it; the dock's hide control closes it — typing\n * never becomes permanent chrome. Default closed (voice-first), reset per session.\n */\n @Input() Open = false;\n\n /**\n * COMPACT (Calm Orb · overlay) presentation: collapse the phone-call strip to the\n * mockup's lean dock — **Mute + End + a \"•••\"** overflow button. The \"•••\" blooms a small\n * sheet hosting the secondary actions (Captions / Details / Type). The fused level-2 dock\n * (minis + text input) is unchanged. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full 5-button strip is unchanged).\n */\n @Input() Compact = false;\n\n /** Emitted when the user opens (Type control / typing) or closes (hide control) the dock. */\n @Output() OpenChanged = new EventEmitter<boolean>();\n\n /** Whether captions are currently shown (drives the captions control's active state). */\n @Input() CaptionsOn = true;\n\n /** Whether the Details peek control renders (true until the surface panel is earned). */\n @Input() ShowDetails = false;\n\n /** Whether the Details peek is currently open (active state on the control). */\n @Input() DetailsOn = false;\n\n /** Emitted when the user toggles captions; the overlay flips its caption state. */\n @Output() CaptionsToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user toggles the Details peek (the on-demand surface panel). */\n @Output() DetailsToggled = new EventEmitter<void>();\n\n /** Emitted when the user ends the call from the strip's End control. */\n @Output() EndRequested = new EventEmitter<void>();\n\n /** Emitted with the new muted state whenever the user toggles the mic from the dock. */\n @Output() MuteChanged = new EventEmitter<boolean>();\n\n /** Current draft text in the dock's composer input. */\n public Draft = '';\n\n /**\n * The mic mute state. A two-way reflection: the overlay may push it down (e.g. its\n * `SetMuted()` / focus-pill toggle) so all mute affordances stay in sync, and this\n * component updates it locally + emits {@link MuteChanged} when its own button is used.\n */\n @Input() IsMuted = false;\n\n @ViewChild('dockInput') private dockInput?: ElementRef<HTMLInputElement>;\n\n private realtime = inject(RealtimeSessionService);\n\n /** True when there's non-whitespace text to send. */\n public get CanSend(): boolean {\n return this.Draft.trim().length > 0;\n }\n\n /** True while the big-controls phone-call strip renders (instead of the dock). */\n public get StripMode(): boolean {\n return !this.Open;\n }\n\n /**\n * Whether the compact \"•••\" overflow sheet (Captions / Details / Type) is open. Only used\n * in {@link Compact} strip mode; any outside click or action selection closes it.\n */\n public MoreOpen = false;\n\n /** Open/close the compact overflow sheet (stops propagation so the outside-click close skips it). */\n public ToggleMore(event: MouseEvent): void {\n event.stopPropagation();\n this.MoreOpen = !this.MoreOpen;\n }\n\n /** Any outside click closes the compact overflow sheet. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.MoreOpen) {\n this.MoreOpen = false;\n }\n }\n\n /** Toggle the local microphone mute and surface the new state to the overlay. */\n public ToggleMute(): void {\n this.IsMuted = this.realtime.ToggleMute();\n this.MuteChanged.emit(this.IsMuted);\n }\n\n /** Toggle captions visibility and notify the overlay. */\n public ToggleCaptions(): void {\n this.CaptionsOn = !this.CaptionsOn;\n this.CaptionsToggled.emit(this.CaptionsOn);\n }\n\n /** Focuses the dock's text input (the overlay's Type control lands here). */\n public FocusInput(): void {\n this.dockInput?.nativeElement.focus();\n }\n\n /**\n * TYPE-TO-COMPOSE: the overlay captured a printable keystroke while nothing was focused, so seed\n * the draft with that character, focus the input, and put the caret at the end — the user just\n * keeps typing and their first key isn't lost. Appends (rather than replaces) so a leftover draft\n * is preserved. The native value is synced inline so the caret math is correct before Angular's\n * next change-detection pass reconciles ngModel.\n *\n * @param text the character(s) to seed (typically the single key that opened the composer).\n */\n public AppendAndFocus(text: string): void {\n this.Draft = (this.Draft ?? '') + text;\n const el = this.dockInput?.nativeElement;\n if (el) {\n el.value = this.Draft;\n el.focus();\n el.setSelectionRange(this.Draft.length, this.Draft.length);\n }\n }\n\n /** Send the typed text into the live session, then clear the input. */\n public Send(): void {\n if (!this.CanSend) {\n return;\n }\n this.realtime.SendText(this.Draft);\n this.Draft = '';\n }\n\n /** Enter sends (Shift+Enter is free for future multiline if the input becomes a textarea). */\n public OnKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.Send();\n }\n }\n}\n","@if (StripMode && Compact) {\n <!-- COMPACT (Calm Orb · overlay): the lean dock — Mute + End + a first-class Captions toggle\n (kept out of the \"•••\" so text stays ONE TAP in the overlay, where the banner no longer\n carries a duplicate CC) + a \"•••\" that blooms a small sheet with the remaining secondary\n actions (Details / Type). Round controls, red End — matches the mockup. -->\n <div class=\"dock-lean\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"lean-more\" [class.lean-more--open]=\"MoreOpen\">\n <div class=\"lean-sheet\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"More call controls\">\n @if (ShowDetails) {\n <button type=\"button\" class=\"lean-sheet__btn\" [class.lean-sheet__btn--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit(); MoreOpen = false\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n <small>Details</small>\n </button>\n }\n <button type=\"button\" class=\"lean-sheet__btn\"\n (click)=\"OpenChanged.emit(true); MoreOpen = false\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n <small>Type</small>\n </button>\n </div>\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"MoreOpen\"\n (click)=\"ToggleMore($event)\"\n title=\"More controls\" aria-label=\"More call controls\"\n [attr.aria-expanded]=\"MoreOpen\">\n <i class=\"fa-solid fa-ellipsis\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- Captions: first-class in the lean dock (the overlay's only text toggle now). -->\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg\" [class.lean-ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg lean-ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n} @else if (StripMode) {\n <!-- Levels 0–1: phone-call strip — big round controls, nothing to configure.\n Captions arrives at level 1 WITH the text it controls; Details peeks at the\n surface panels on demand; End stays the deliberate rightmost action. -->\n <div class=\"strip\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">{{ IsMuted ? 'Unmute' : 'Mute' }}</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Captions</span>\n </div>\n\n @if (ShowDetails) {\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Details</span>\n </div>\n }\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" (click)=\"OpenChanged.emit(true)\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Type</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label ctrl-label--end\">End call</span>\n </div>\n </div>\n} @else {\n <!-- Level 2+: the fused dock — compact minis + the in-call composer in ONE bottom bar. -->\n <div class=\"dock\">\n <div class=\"dock__minis\">\n <button type=\"button\" class=\"mini\" [class.mini--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n @if (ShowDetails) {\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Show the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dock__box\">\n <input\n #dockInput\n type=\"text\"\n class=\"dock__input\"\n placeholder=\"Type into the live session — joins this same voice call…\"\n [(ngModel)]=\"Draft\"\n (keydown)=\"OnKeydown($event)\"\n aria-label=\"Type a message into the live voice session\" />\n <span class=\"dock__hint\" aria-hidden=\"true\">↵ send</span>\n <button\n class=\"dock__send\"\n type=\"button\"\n [disabled]=\"!CanSend\"\n (click)=\"Send()\"\n title=\"Send into live session\"\n aria-label=\"Send\">\n <i class=\"fa-solid fa-paper-plane\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button type=\"button\" class=\"mini dock__hide\" (click)=\"OpenChanged.emit(false)\"\n title=\"Hide typing — back to the voice controls\"\n aria-label=\"Close the typed-input composer\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n}\n"]}
1
+ {"version":3,"file":"realtime-composer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts","../../../../src/lib/components/realtime/realtime-composer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ElementRef, EventEmitter, HostListener, Input, Output, ViewChild, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RealtimeSessionService } from '../../services/realtime-session.service';\n\n/**\n * The call overlay's BOTTOM DOCK — the progressive-disclosure composer\n * (`plans/realtime/mockups/redesign-a-progressive.html`). One component, two shapes,\n * keyed off the overlay's disclosure {@link Level}:\n *\n * - **Levels 0–1 (phone-call strip)** — big round call controls, centered: Mute, the\n * Captions toggle (level 1+, arriving WITH the text it controls), the Details peek\n * (level 0 paths where the surface panel isn't earned yet — lets the user look at the\n * Activity/Whiteboard panels on demand), the Type control, and End call. There's no visible\n * composer yet — the Type control opens it, and so does simply starting to type (the overlay\n * captures the first printable keystroke and seeds it via {@link AppendAndFocus}).\n * - **Level 2+ (the dock)** — mute/captions shrink to compact minis and the in-call text\n * input docks beside them (one bottom bar, per Redesign A's fused composer+controls).\n * Submit calls {@link RealtimeSessionService.SendText}, which injects the text as a user\n * turn into the SAME live voice call.\n *\n * Mute talks to the session service directly (pure local toggle); captions / Details /\n * End are emitted up so the overlay shell owns that state and lifecycle.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-composer',\n imports: [CommonModule, FormsModule],\n templateUrl: './realtime-composer.component.html',\n styleUrl: './realtime-composer.component.css'\n})\nexport class RealtimeComposerComponent {\n /**\n * Whether the typed-input dock is OPEN. A two-way door owned by the user: the strip's\n * Type control (or the T hotkey) opens it; the dock's hide control closes it — typing\n * never becomes permanent chrome. Default closed (voice-first), reset per session.\n */\n @Input() Open = false;\n\n /**\n * COMPACT (Calm Orb · overlay) presentation: collapse the phone-call strip to the\n * mockup's lean dock — **Mute + End + a \"•••\"** overflow button. The \"•••\" blooms a small\n * sheet hosting the secondary actions (Captions / Details / Type). The fused level-2 dock\n * (minis + text input) is unchanged. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full 5-button strip is unchanged).\n */\n @Input() Compact = false;\n\n /** Emitted when the user opens (Type control / typing) or closes (hide control) the dock. */\n @Output() OpenChanged = new EventEmitter<boolean>();\n\n /** Whether captions are currently shown (drives the captions control's active state). */\n @Input() CaptionsOn = true;\n\n /** Whether the Details peek control renders (true until the surface panel is earned). */\n @Input() ShowDetails = false;\n\n /** Whether the Details peek is currently open (active state on the control). */\n @Input() DetailsOn = false;\n\n /** Emitted when the user toggles captions; the overlay flips its caption state. */\n @Output() CaptionsToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user toggles the Details peek (the on-demand surface panel). */\n @Output() DetailsToggled = new EventEmitter<void>();\n\n /** Emitted when the user ends the call from the strip's End control. */\n @Output() EndRequested = new EventEmitter<void>();\n\n /** Emitted with the new muted state whenever the user toggles the mic from the dock. */\n @Output() MuteChanged = new EventEmitter<boolean>();\n\n /** Current draft text in the dock's composer input. */\n public Draft = '';\n\n /**\n * The mic mute state. A two-way reflection: the overlay may push it down (e.g. its\n * `SetMuted()` / focus-pill toggle) so all mute affordances stay in sync, and this\n * component updates it locally + emits {@link MuteChanged} when its own button is used.\n */\n @Input() IsMuted = false;\n\n @ViewChild('dockInput') private dockInput?: ElementRef<HTMLInputElement | HTMLTextAreaElement>;\n\n private realtime = inject(RealtimeSessionService);\n\n /** True when there's non-whitespace text to send. */\n public get CanSend(): boolean {\n return this.Draft.trim().length > 0;\n }\n\n /** True while the big-controls phone-call strip renders (instead of the dock). */\n public get StripMode(): boolean {\n return !this.Open;\n }\n\n /**\n * Whether the compact \"•••\" overflow sheet (Captions / Details / Type) is open. Only used\n * in {@link Compact} strip mode; any outside click or action selection closes it.\n */\n public MoreOpen = false;\n\n /** Open/close the compact overflow sheet (stops propagation so the outside-click close skips it). */\n public ToggleMore(event: MouseEvent): void {\n event.stopPropagation();\n this.MoreOpen = !this.MoreOpen;\n }\n\n /** Any outside click closes the compact overflow sheet. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.MoreOpen) {\n this.MoreOpen = false;\n }\n }\n\n /** Toggle the local microphone mute and surface the new state to the overlay. */\n public ToggleMute(): void {\n this.IsMuted = this.realtime.ToggleMute();\n this.MuteChanged.emit(this.IsMuted);\n }\n\n /** Toggle captions visibility and notify the overlay. */\n public ToggleCaptions(): void {\n this.CaptionsOn = !this.CaptionsOn;\n this.CaptionsToggled.emit(this.CaptionsOn);\n }\n\n /** Focuses the dock's text input (the overlay's Type control lands here). */\n public FocusInput(): void {\n this.dockInput?.nativeElement.focus();\n }\n\n /**\n * TYPE-TO-COMPOSE: the overlay captured a printable keystroke while nothing was focused, so seed\n * the draft with that character, focus the input, and put the caret at the end — the user just\n * keeps typing and their first key isn't lost. Appends (rather than replaces) so a leftover draft\n * is preserved. The native value is synced inline so the caret math is correct before Angular's\n * next change-detection pass reconciles ngModel.\n *\n * @param text the character(s) to seed (typically the single key that opened the composer).\n */\n public AppendAndFocus(text: string): void {\n this.Draft = (this.Draft ?? '') + text;\n const el = this.dockInput?.nativeElement;\n if (el) {\n el.value = this.Draft;\n el.focus();\n el.setSelectionRange(this.Draft.length, this.Draft.length);\n this.AutoResize();\n }\n }\n\n /** Auto-resizes the textarea up to 140px height as text grows or contracts. */\n public AutoResize(): void {\n const el = this.dockInput?.nativeElement;\n if (el && el instanceof HTMLTextAreaElement) {\n el.style.height = 'auto';\n const newHeight = Math.max(24, Math.min(el.scrollHeight, 140));\n el.style.height = `${newHeight}px`;\n }\n }\n\n /** Send the typed text into the live session, then clear the input. */\n public Send(): void {\n if (!this.CanSend) {\n return;\n }\n this.realtime.SendText(this.Draft);\n this.Draft = '';\n const el = this.dockInput?.nativeElement;\n if (el && el instanceof HTMLTextAreaElement) {\n el.style.height = 'auto';\n }\n }\n\n /** Enter sends (Shift+Enter inserts a newline in textarea). */\n public OnKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.Send();\n }\n }\n}\n","@if (StripMode && Compact) {\n <!-- COMPACT (Calm Orb · overlay): the lean dock — Mute + End + a first-class Captions toggle\n (kept out of the \"•••\" so text stays ONE TAP in the overlay, where the banner no longer\n carries a duplicate CC) + a \"•••\" that blooms a small sheet with the remaining secondary\n actions (Details / Type). Round controls, red End — matches the mockup. -->\n <div class=\"dock-lean\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"lean-more\" [class.lean-more--open]=\"MoreOpen\">\n <div class=\"lean-sheet\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"More call controls\">\n @if (ShowDetails) {\n <button type=\"button\" class=\"lean-sheet__btn\" [class.lean-sheet__btn--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit(); MoreOpen = false\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n <small>Details</small>\n </button>\n }\n <button type=\"button\" class=\"lean-sheet__btn\"\n (click)=\"OpenChanged.emit(true); MoreOpen = false\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n <small>Type</small>\n </button>\n </div>\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"MoreOpen\"\n (click)=\"ToggleMore($event)\"\n title=\"More controls\" aria-label=\"More call controls\"\n [attr.aria-expanded]=\"MoreOpen\">\n <i class=\"fa-solid fa-ellipsis\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- Captions: first-class in the lean dock (the overlay's only text toggle now). -->\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--more\" [class.lean-ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg\" [class.lean-ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n\n <button type=\"button\" class=\"lean-ctrl lean-ctrl--lg lean-ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n} @else if (StripMode) {\n <!-- Levels 0–1: phone-call strip — big round controls, nothing to configure.\n Captions arrives at level 1 WITH the text it controls; Details peeks at the\n surface panels on demand; End stays the deliberate rightmost action. -->\n <div class=\"strip\" role=\"group\" aria-label=\"Call controls\">\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">{{ IsMuted ? 'Unmute' : 'Mute' }}</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Captions</span>\n </div>\n\n @if (ShowDetails) {\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" [class.ctrl--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Peek at the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Details</span>\n </div>\n }\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl\" (click)=\"OpenChanged.emit(true)\"\n title=\"Type into the live session\" aria-label=\"Open the typed-input composer\">\n <i class=\"fa-regular fa-keyboard\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label\">Type</span>\n </div>\n\n <div class=\"ctrl-group\">\n <button type=\"button\" class=\"ctrl ctrl--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n <span class=\"ctrl-label ctrl-label--end\">End call</span>\n </div>\n </div>\n} @else {\n <!-- Level 2+: the fused dock — compact minis + the in-call composer in ONE bottom bar. -->\n <div class=\"dock\">\n <div class=\"dock__minis\">\n <button type=\"button\" class=\"mini\" [class.mini--muted]=\"IsMuted\"\n (click)=\"ToggleMute()\"\n [title]=\"IsMuted ? 'Unmute microphone' : 'Mute microphone'\"\n [attr.aria-pressed]=\"IsMuted\">\n <i class=\"fa-solid\" [ngClass]=\"IsMuted ? 'fa-microphone-slash' : 'fa-microphone'\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"CaptionsOn\"\n (click)=\"ToggleCaptions()\"\n [title]=\"CaptionsOn ? 'Voice-first — back to the orb' : 'Show the conversation as text'\"\n [attr.aria-pressed]=\"CaptionsOn\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n @if (ShowDetails) {\n <button type=\"button\" class=\"mini\" [class.mini--on]=\"DetailsOn\"\n (click)=\"DetailsToggled.emit()\"\n [title]=\"DetailsOn ? 'Hide the session panels' : 'Show the session panels'\"\n [attr.aria-pressed]=\"DetailsOn\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dock__box\">\n <textarea\n #dockInput\n class=\"dock__input\"\n rows=\"1\"\n placeholder=\"Type into the live session — joins this same voice call…\"\n [(ngModel)]=\"Draft\"\n (keydown)=\"OnKeydown($event)\"\n (input)=\"AutoResize()\"\n aria-label=\"Type a message into the live voice session\"></textarea>\n <span class=\"dock__hint\" aria-hidden=\"true\">↵ send</span>\n <button\n class=\"dock__send\"\n type=\"button\"\n [disabled]=\"!CanSend\"\n (click)=\"Send()\"\n title=\"Send into live session\"\n aria-label=\"Send\">\n <i class=\"fa-solid fa-paper-plane\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button type=\"button\" class=\"mini dock__hide\" (click)=\"OpenChanged.emit(false)\"\n title=\"Hide typing — back to the voice controls\"\n aria-label=\"Close the typed-input composer\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"mini mini--end\" (click)=\"EndRequested.emit()\"\n title=\"End call\" aria-label=\"End call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from '@angular/core';
2
2
  import { RealtimeDelegationCardVM } from './realtime-session-state';
3
- import { ParsedDelegationArtifact } from '../../services/delegation-result-parser';
3
+ import { ParsedDelegationArtifact } from '@memberjunction/realtime-runtime';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
6
  * Renders a single delegation in the live session thread:
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-delegation-card.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-delegation-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAGvE,OAAO,EAAE,wBAAwB,EAAqB,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;;AAEnF;;;;;;;;;;;;;;;;GAgBG;AACH,qBAOa,+BAA+B;IAC1C,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAO;IAE9C,uFAAuF;IAC5D,IAAI,EAAG,wBAAwB,CAAC;IAE3D,wEAAwE;IAC/D,OAAO,UAAS;IAEzB,mFAAmF;IACzE,gBAAgB,uBAA8B;IAExD,+FAA+F;IACrF,qBAAqB,yCAAgD;IAE/E;;;;;;OAMG;IACO,eAAe,uBAA8B;IAEvD,6EAA6E;IACtE,QAAQ,UAAS;IAExB,0IAA0I;IAC1I,IAAW,SAAS,IAAI,wBAAwB,EAAE,CAEjD;IAED,iFAAiF;IAC1E,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,GAAG,IAAI;IAKhF,6HAA6H;IAC7H,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,gEAAgE;IACzD,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAOvC,oEAAoE;IAC7D,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAO1C,gFAAgF;IAChF,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED;;;OAGG;IACH,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,mFAAmF;IACnF,IAAW,UAAU,IAAI,MAAM,CAQ9B;IAED,wEAAwE;IACxE,IAAW,aAAa,IAAI,MAAM,CAIjC;IAED,mDAAmD;IACnD,IAAW,eAAe,IAAI,MAAM,CASnC;yCArGU,+BAA+B;2CAA/B,+BAA+B;CAsG3C"}
1
+ {"version":3,"file":"realtime-delegation-card.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-delegation-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAGvE,OAAO,EAAE,wBAAwB,EAAqB,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;;AAE5E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAOa,+BAA+B;IAC1C,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAO;IAE9C,uFAAuF;IAC5D,IAAI,EAAG,wBAAwB,CAAC;IAE3D,wEAAwE;IAC/D,OAAO,UAAS;IAEzB,mFAAmF;IACzE,gBAAgB,uBAA8B;IAExD,+FAA+F;IACrF,qBAAqB,yCAAgD;IAE/E;;;;;;OAMG;IACO,eAAe,uBAA8B;IAEvD,6EAA6E;IACtE,QAAQ,UAAS;IAExB,0IAA0I;IAC1I,IAAW,SAAS,IAAI,wBAAwB,EAAE,CAEjD;IAED,iFAAiF;IAC1E,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,GAAG,IAAI;IAKhF,6HAA6H;IAC7H,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,gEAAgE;IACzD,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAOvC,oEAAoE;IAC7D,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAO1C,gFAAgF;IAChF,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED;;;OAGG;IACH,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,mFAAmF;IACnF,IAAW,UAAU,IAAI,MAAM,CAQ9B;IAED,wEAAwE;IACxE,IAAW,aAAa,IAAI,MAAM,CAIjC;IAED,mDAAmD;IACnD,IAAW,eAAe,IAAI,MAAM,CASnC;yCArGU,+BAA+B;2CAA/B,+BAA+B;CAsG3C"}