@memberjunction/ng-conversations 6.2.0-edge.0 → 6.2.0-edge.1
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.
- package/README.md +35 -2
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +19 -3
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js +39 -7
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts +74 -6
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -1
- package/dist/lib/components/agent/active-agent-indicator.component.js +111 -21
- package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -1
- package/dist/lib/components/agent/agent-process-panel.component.d.ts +31 -5
- package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
- package/dist/lib/components/agent/agent-process-panel.component.js +71 -15
- package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +65 -9
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.js +169 -57
- package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
- package/dist/lib/components/attachment/image-viewer.component.d.ts +77 -11
- package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/attachment/image-viewer.component.js +181 -47
- package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +129 -19
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +350 -116
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
- package/dist/lib/components/collection/artifact-create-modal.component.d.ts +60 -8
- package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/artifact-create-modal.component.js +130 -46
- package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts +63 -3
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.js +113 -19
- package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.d.ts +54 -8
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.js +130 -46
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts +70 -10
- package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.js +175 -53
- package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts +89 -9
- package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.js +220 -70
- package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts +89 -11
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +154 -40
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +390 -38
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +951 -367
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +213 -18
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +388 -44
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +12 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +26 -4
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +1090 -123
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2399 -706
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +139 -19
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.js +296 -59
- package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +579 -78
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +2322 -823
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +40 -4
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +72 -14
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/dialogs/input-dialog.component.d.ts +57 -11
- package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/dialogs/input-dialog.component.js +128 -16
- package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts +68 -10
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.js +151 -27
- package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -1
- package/dist/lib/components/export/export-modal.component.d.ts +84 -10
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +173 -49
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +29 -3
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js +58 -12
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/library/library-full-view.component.d.ts +57 -8
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/library/library-full-view.component.js +119 -35
- package/dist/lib/components/library/library-full-view.component.js.map +1 -1
- package/dist/lib/components/members/members-modal.component.d.ts +76 -10
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
- package/dist/lib/components/members/members-modal.component.js +164 -50
- package/dist/lib/components/members/members-modal.component.js.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.d.ts +37 -5
- package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.js +82 -16
- package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts +46 -10
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +120 -36
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +549 -74
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +1250 -421
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +411 -29
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +896 -222
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +288 -29
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +561 -123
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts +64 -5
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.js +101 -11
- package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
- package/dist/lib/components/notification/activity-indicator.component.d.ts +6 -2
- package/dist/lib/components/notification/activity-indicator.component.d.ts.map +1 -1
- package/dist/lib/components/notification/activity-indicator.component.js +13 -3
- package/dist/lib/components/notification/activity-indicator.component.js.map +1 -1
- package/dist/lib/components/notification/notification-badge.component.d.ts +15 -3
- package/dist/lib/components/notification/notification-badge.component.d.ts.map +1 -1
- package/dist/lib/components/notification/notification-badge.component.js +36 -8
- package/dist/lib/components/notification/notification-badge.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +4 -4
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts +93 -11
- package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.js +348 -87
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
- package/dist/lib/components/project/project-selector.component.d.ts +78 -8
- package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-selector.component.js +177 -46
- package/dist/lib/components/project/project-selector.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +2 -2
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +2 -2
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +18 -18
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +47 -23
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +136 -92
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +4 -4
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +3 -3
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +13 -11
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +29 -25
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +3 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +6 -2
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- package/dist/lib/components/search/search-panel.component.d.ts +133 -22
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +312 -83
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/share/share-modal.component.d.ts +69 -9
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/share/share-modal.component.js +139 -31
- package/dist/lib/components/share/share-modal.component.js.map +1 -1
- package/dist/lib/components/shared/user-picker.component.d.ts +48 -8
- package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
- package/dist/lib/components/shared/user-picker.component.js +110 -30
- package/dist/lib/components/shared/user-picker.component.js.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +114 -11
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.js +199 -21
- package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts +20 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js +25 -5
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/slots/slot-interfaces.d.ts +19 -0
- package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -1
- package/dist/lib/components/slots/slot-interfaces.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +95 -13
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +223 -75
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/task-widget.component.d.ts +46 -6
- package/dist/lib/components/tasks/task-widget.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/task-widget.component.js +100 -16
- package/dist/lib/components/tasks/task-widget.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +64 -7
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +127 -27
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/thread/thread-panel.component.d.ts +66 -8
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -1
- package/dist/lib/components/thread/thread-panel.component.js +146 -36
- package/dist/lib/components/thread/thread-panel.component.js.map +1 -1
- package/dist/lib/components/toast/toast.component.d.ts +11 -1
- package/dist/lib/components/toast/toast.component.d.ts.map +1 -1
- package/dist/lib/components/toast/toast.component.js +25 -5
- package/dist/lib/components/toast/toast.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +385 -42
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +887 -291
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +8 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js +8 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -1
- package/dist/lib/directives/chat-slot.directive.d.ts +5 -1
- package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -1
- package/dist/lib/directives/chat-slot.directive.js.map +1 -1
- package/dist/lib/directives/search-shortcut.directive.d.ts +9 -1
- package/dist/lib/directives/search-shortcut.directive.d.ts.map +1 -1
- package/dist/lib/directives/search-shortcut.directive.js +14 -4
- package/dist/lib/directives/search-shortcut.directive.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +34 -7
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +37 -7
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +103 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -0
- package/dist/lib/models/agent-turn.model.js +12 -0
- package/dist/lib/models/agent-turn.model.js.map +1 -0
- package/dist/lib/models/collection-view.model.js.map +1 -1
- package/dist/lib/models/conversation-state.model.d.ts +8 -0
- package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
- package/dist/lib/models/conversation-state.model.js.map +1 -1
- package/dist/lib/models/lazy-artifact-info.d.ts +44 -12
- package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
- package/dist/lib/models/lazy-artifact-info.js +98 -34
- package/dist/lib/models/lazy-artifact-info.js.map +1 -1
- package/dist/lib/services/active-tasks.service.d.ts +30 -4
- package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
- package/dist/lib/services/active-tasks.service.js +71 -19
- package/dist/lib/services/active-tasks.service.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +17 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +48 -16
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-permission.service.d.ts +39 -0
- package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-permission.service.js +152 -17
- package/dist/lib/services/artifact-permission.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +58 -5
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +135 -35
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/collection-permission.service.d.ts +28 -0
- package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
- package/dist/lib/services/collection-permission.service.js +88 -32
- package/dist/lib/services/collection-permission.service.js.map +1 -1
- package/dist/lib/services/collection-state.service.d.ts +11 -1
- package/dist/lib/services/collection-state.service.d.ts.map +1 -1
- package/dist/lib/services/collection-state.service.js +25 -5
- package/dist/lib/services/collection-state.service.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +26 -4
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +57 -18
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts +17 -0
- package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-attachment.service.js +38 -10
- package/dist/lib/services/conversation-attachment.service.js.map +1 -1
- package/dist/lib/services/conversation-streaming.service.d.ts +22 -0
- package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-streaming.service.js +50 -10
- package/dist/lib/services/conversation-streaming.service.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +31 -0
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +71 -15
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/dialog.service.d.ts +13 -0
- package/dist/lib/services/dialog.service.d.ts.map +1 -1
- package/dist/lib/services/dialog.service.js +25 -5
- package/dist/lib/services/dialog.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +2 -0
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +5 -1
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/mention-parser.service.d.ts +10 -0
- package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
- package/dist/lib/services/mention-parser.service.js +25 -5
- package/dist/lib/services/mention-parser.service.js.map +1 -1
- package/dist/lib/services/notification.service.d.ts +54 -6
- package/dist/lib/services/notification.service.d.ts.map +1 -1
- package/dist/lib/services/notification.service.js +123 -27
- package/dist/lib/services/notification.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +4 -4
- package/dist/lib/services/realtime-audio-recorder.js +12 -12
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pcm-wav.d.ts +4 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -1
- package/dist/lib/services/realtime-pcm-wav.js +10 -2
- package/dist/lib/services/realtime-pcm-wav.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +42 -9
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +103 -23
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/services/toast.service.d.ts +19 -1
- package/dist/lib/services/toast.service.d.ts.map +1 -1
- package/dist/lib/services/toast.service.js +45 -9
- package/dist/lib/services/toast.service.js.map +1 -1
- package/dist/lib/services/ui-command-handler.service.d.ts +16 -2
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +36 -8
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/utils/agent-artifact-summary.d.ts +2 -2
- package/dist/lib/utils/agent-artifact-summary.js +3 -3
- package/dist/lib/utils/agent-artifact-summary.js.map +1 -1
- package/dist/lib/utils/agent-turn-routing.d.ts +69 -0
- package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -0
- package/dist/lib/utils/agent-turn-routing.js +96 -0
- package/dist/lib/utils/agent-turn-routing.js.map +1 -0
- package/dist/lib/utils/artifact-panel-action.d.ts +15 -4
- package/dist/lib/utils/artifact-panel-action.d.ts.map +1 -1
- package/dist/lib/utils/artifact-panel-action.js +10 -2
- package/dist/lib/utils/artifact-panel-action.js.map +1 -1
- package/dist/lib/utils/distinct-artifacts.d.ts +2 -0
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +5 -1
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- package/dist/lib/utils/plan-mode-preference.d.ts +2 -2
- package/dist/lib/utils/plan-mode-preference.js +6 -6
- package/dist/lib/utils/plan-mode-preference.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +32 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-surface-tabs.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-tabs.component.ts","../../../../src/lib/components/realtime/realtime-surface-tabs.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, EventEmitter, Input, Output, OnInit, OnDestroy, ChangeDetectorRef, ViewChild, inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Subscription } from 'rxjs';\nimport { UserInfo } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { ArtifactsModule } from '@memberjunction/ng-artifacts';\nimport { RealtimeSessionState } from './realtime-session-state';\nimport { RealtimeActivityRailComponent } from './realtime-activity-rail.component';\nimport { RealtimeChannelPaneComponent } from './channels/realtime-channel-pane.component';\nimport { ChannelOnboardingPanelComponent } from './channels/channel-onboarding-panel.component';\nimport { ChannelOnboardingDetails } from '@memberjunction/realtime-runtime';\nimport {\n RealtimeSurfaceTabsModel, RealtimeSurfaceTab, RealtimeChannelTabRegistration\n} from './realtime-surface-tabs.model';\nimport { ParsedDelegationArtifact } from '@memberjunction/realtime-runtime';\n\n/**\n * User-settings key (NOT localStorage — see `UserInfoEngine`) under which the per-user \"which\n * channel intros have been seen\" map is persisted: a JSON object of `{ [channelName]: true }`,\n * so the first-run onboarding for each interactive channel shows exactly once per user and\n * follows them across devices.\n */\nconst CHANNEL_ONBOARDING_SEEN_SETTING_KEY = 'mj.realtimeChannels.onboardingSeen.v1';\n\n/**\n * The call overlay's TABBED SURFACE PANEL (the right panel) — decluttered redesign:\n *\n * - **Channel tabs** (LEFT cluster) — one per channel that has come into play. The whiteboard\n * tabs immediately at session start; every other channel tabs only once the agent first\n * USES it. Each carries a distinct accent color + its plugin icon. The pane creates the\n * plugin's surface component dynamically (via `mj-realtime-channel-pane`); a placeholder\n * shows the \"coming online…\" state until a plugin/template is supplied.\n * - **Activity** (RIGHT-aligned, pinned LAST) — gated: appears only once ≥1 agent run has\n * occurred (or in review mode). Hosts {@link RealtimeActivityRailComponent}, which now also\n * renders inline artifact previews and a split-pane artifact viewer. Styled distinctly from\n * channel tabs (activity-pulse icon + its own accent) and separated from the channel cluster\n * by a flex spacer.\n *\n * Artifacts NO LONGER get their own tab — they live inside the Activity tab (cleaner than a\n * row of per-artifact tabs).\n *\n * Panes are kept ALIVE while hidden (CSS `display:none`) so switching tabs never reloads a\n * channel surface or resets the rail. The whole panel collapses to a slim strip via the chevron.\n *\n * SIZING IS EXTERNAL: the overlay shell hosts this panel in a fixed-width flex item and owns\n * the width. This panel just fills it and REPORTS the layout signals the shell sizes from:\n * {@link CollapsedChange} (slim-strip toggle) and {@link WideChanged} (a channel tab is focused\n * → the default width tier widens).\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-surface-tabs',\n imports: [\n CommonModule, ArtifactsModule, RealtimeActivityRailComponent, RealtimeChannelPaneComponent,\n ChannelOnboardingPanelComponent\n ],\n templateUrl: './realtime-surface-tabs.component.html',\n styleUrl: './realtime-surface-tabs.component.css'\n})\nexport class RealtimeSurfaceTabsComponent implements OnInit, OnDestroy {\n /** How long a just-revealed channel tab keeps its flash highlight. */\n private static readonly FlashDurationMs = 1400;\n\n /** Shared live-session state, owned by the overlay shell (feeds the Activity rail). */\n @Input({ required: true }) State!: RealtimeSessionState;\n\n /** Whether developer affordances (\"Open run\" links) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /**\n * FILL presentation: the panel stretches to the overlay's full width (the board-focus\n * layout, where the main call column is hidden and a channel surface owns the screen).\n * Bound by the overlay shell; overrides the normal / wide width tiers.\n */\n @Input() Fill = false;\n\n /** The signed-in user, threaded to the artifact viewer panel. */\n @Input() CurrentUser: UserInfo | null = null;\n\n /** The active environment id, threaded to the artifact viewer panel. */\n @Input() EnvironmentID = '';\n\n /**\n * Extra (review-carryover) artifacts to surface in the Activity tab, NOT tied to a live\n * activity card. Forwarded to the rail's \"Session artifacts\" group. Empty for a live session.\n */\n @Input() ExtraArtifacts: ParsedDelegationArtifact[] = [];\n\n /**\n * Whether the gated Activity tab should be shown — driven by the overlay shell once ≥1\n * agent run has occurred (or in review mode). A getter/setter so a late \"first run\" flips\n * the tab into the strip reactively.\n */\n private _showActivityTab = false;\n @Input()\n set ShowActivityTab(value: boolean) {\n if (value !== this._showActivityTab) {\n this._showActivityTab = value;\n this.Model.SetShowActivityTab(value);\n this.cdr.markForCheck();\n }\n }\n get ShowActivityTab(): boolean {\n return this._showActivityTab;\n }\n\n /** Re-emitted from the Activity rail's dev \"Open run\" links. */\n @Output() OpenRunRequested = new EventEmitter<string>();\n\n /**\n * Emitted when the panel toggles between expanded and the slim collapsed strip —\n * the overlay shell resizes this panel's split area to the strip width.\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when {@link IsWide} flips (a channel tab gained / lost focus) — the\n * overlay shell widens the panel's DEFAULT split-area size while wide (only when\n * the user has never dragged an explicit width).\n */\n @Output() WideChanged = new EventEmitter<boolean>();\n\n /** The panel's tab state (add / focus / dedupe / flash) — see the model for the rules. */\n public readonly Model = new RealtimeSurfaceTabsModel();\n\n /** Whether the panel is collapsed to its slim strip. */\n public Collapsed = false;\n\n /** The embedded Activity rail (owns the inline artifact previews + the split-pane viewer). */\n @ViewChild(RealtimeActivityRailComponent) private activityRail?: RealtimeActivityRailComponent;\n\n private flashTimer: ReturnType<typeof setTimeout> | null = null;\n private subs: Subscription[] = [];\n private lastWide = false;\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * The channel whose first-run intro is currently being shown (its `ChannelName`), or `null`\n * when no intro is up. Set when the user opens a channel tab they've never seen the intro\n * for; cleared on dismiss. Only one intro shows at a time (the active channel's).\n */\n private onboardingChannelName: string | null = null;\n /** The intro content for {@link onboardingChannelName}, mirrored for the template binding. */\n public OnboardingContent: ChannelOnboardingDetails | null = null;\n\n /** The currently focused tab. */\n public get ActiveTab(): RealtimeSurfaceTab {\n return this.Model.ActiveTab;\n }\n\n /** Wide presentation when a channel tab is focused (the Activity tab keeps the normal tier). */\n public get IsWide(): boolean {\n return !this.Collapsed && this.ActiveTab.Kind === 'channel';\n }\n\n ngOnInit(): void {\n this.subs.push(\n this.Model.Changed$.subscribe(() => this.onModelChanged())\n );\n }\n\n ngOnDestroy(): void {\n for (const s of this.subs) {\n s.unsubscribe();\n }\n this.subs = [];\n if (this.flashTimer) {\n clearTimeout(this.flashTimer);\n this.flashTimer = null;\n }\n }\n\n /** Toggle the panel between expanded and slim-collapsed. */\n public ToggleCollapsed(): void {\n this.setCollapsed(!this.Collapsed);\n }\n\n /** Collapse-state transitions funnel through here so the shell always hears about them. */\n private setCollapsed(value: boolean): void {\n if (this.Collapsed !== value) {\n this.Collapsed = value;\n this.CollapsedChange.emit(value);\n this.syncWide();\n }\n }\n\n /** Emits {@link WideChanged} when the wide tier flips (channel tab focus / collapse). */\n private syncWide(): void {\n const wide = this.IsWide;\n if (wide !== this.lastWide) {\n this.lastWide = wide;\n this.WideChanged.emit(wide);\n }\n }\n\n /** track fn for the @for over tabs. */\n public TrackTab(index: number, tab: RealtimeSurfaceTab): string {\n return tab.Key;\n }\n\n /**\n * Focuses the Activity tab and opens the given artifact in the rail's split-pane viewer —\n * the \"View →\" affordance target on done delegation cards / thread entries. Expands the\n * panel if it was collapsed. Replaces the old \"open a tab per artifact\" behavior.\n */\n public FocusArtifact(artifact: ParsedDelegationArtifact): void {\n this.setCollapsed(false);\n // An artifact implies a run happened — ensure the Activity tab is present before focusing it.\n this.Model.SetShowActivityTab(true);\n this.Model.Focus(RealtimeSurfaceTabsModel.ActivityTabKey);\n // The rail may not be created yet (panel just expanded) — defer so it exists.\n if (this.activityRail) {\n this.activityRail.OpenArtifact(artifact);\n } else {\n setTimeout(() => this.activityRail?.OpenArtifact(artifact));\n }\n this.cdr.markForCheck();\n }\n\n /**\n * Registers (or updates) an interactive-channel tab — one per used channel plugin,\n * forwarded from `RealtimeSessionOverlayComponent.RegisterChannelTab`.\n */\n public RegisterChannelTab(registration: RealtimeChannelTabRegistration): void {\n // Microtask defer: the overlay forwards this while handling agent/channel activity, which can\n // land mid change-detection. Adding a tab to Model synchronously then trips NG0100 on the\n // tab-strip bindings (s-tab--active). A microtask lands the mutation in a fresh CD turn —\n // imperceptible for an async reveal, and ordered with any follow-on RevealChannel.\n Promise.resolve().then(() => {\n this.Model.RegisterChannelTab(registration);\n this.cdr.markForCheck();\n });\n }\n\n /**\n * AUTO-REVEALS a channel surface the moment the agent first acts on it: expands the\n * panel if collapsed, focuses the channel's tab and flashes it — so the user discovers\n * the whiteboard (or any channel) exists the instant it comes alive. No-op for unknown keys.\n */\n public RevealChannel(key: string): void {\n // Microtask defer (same NG0100 reason as RegisterChannelTab): the agent-activity reveal mutates\n // ActiveKey/FlashKey, which feed the tab-strip class bindings; doing it mid-CD trips the\n // ExpressionChanged check. Deferring lands it in a fresh CD turn and stays ordered after any\n // RegisterChannelTab queued just before it.\n Promise.resolve().then(() => {\n this.setCollapsed(false);\n this.Model.Focus(key);\n this.Model.FlashTab(key);\n this.cdr.markForCheck();\n });\n }\n\n /**\n * Removes a tab from the panel (Activity is irremovable; focus falls back per the model's\n * rules). Used by the overlay shell on a review→live continuation whose live channel set\n * resolved WITHOUT the channel a stale review tab represents (e.g. no Whiteboard channel →\n * drop the read-only review board tab).\n *\n * @returns `true` when a tab was removed.\n */\n public RemoveTab(key: string): boolean {\n const removed = this.Model.RemoveTab(key);\n if (removed) {\n this.cdr.markForCheck();\n }\n return removed;\n }\n\n /**\n * Registers the reviewed chain's history artifacts so they surface inside the Activity tab.\n * In the redesign there are no per-artifact tabs — the rail picks artifacts up from the\n * session state's cards, so this only needs to ensure the Activity tab is shown (review\n * mode always shows it) and, when `focus` is set, open the artifact in the split viewer.\n */\n public RegisterArtifactTab(artifact: ParsedDelegationArtifact, focus: boolean = false): void {\n this.Model.SetShowActivityTab(true);\n if (focus) {\n this.FocusArtifact(artifact);\n }\n this.cdr.markForCheck();\n }\n\n /** On model changes: schedule the flash clear, report a wide-tier flip, re-render. */\n private onModelChanged(): void {\n this.scheduleFlashClear();\n this.syncWide();\n this.evaluateOnboarding();\n this.cdr.markForCheck();\n }\n\n /**\n * Decides whether the first-run channel intro should be visible for the ACTIVE tab: shows it\n * the first time the user opens (focuses) a channel tab whose plugin supplies onboarding and\n * which this user hasn't dismissed before. Re-runs on every model change so switching away\n * from a channel tab tears the intro down (only the active channel's intro is ever up).\n */\n private evaluateOnboarding(): void {\n const tab = this.ActiveTab;\n const plugin = tab.Kind === 'channel' ? tab.Data?.Plugin ?? null : null;\n const details = plugin?.GetOnboardingDetails() ?? null;\n if (!plugin || !details || this.HasSeenOnboarding(plugin.ChannelName)) {\n this.onboardingChannelName = null;\n this.OnboardingContent = null;\n return;\n }\n this.onboardingChannelName = plugin.ChannelName;\n this.OnboardingContent = details;\n }\n\n /**\n * Dismisses the current channel intro: marks that channel seen for this user (persisted via\n * `UserInfoEngine`, debounced — NOT localStorage) and hides the panel so it never re-appears.\n */\n public DismissOnboarding(): void {\n const channelName = this.onboardingChannelName;\n this.onboardingChannelName = null;\n this.OnboardingContent = null;\n if (channelName) {\n this.markOnboardingSeen(channelName);\n }\n this.cdr.markForCheck();\n }\n\n /** Reads the per-user seen-map and reports whether this channel's intro has been dismissed. */\n private HasSeenOnboarding(channelName: string): boolean {\n return this.readOnboardingSeen()[channelName] === true;\n }\n\n /** Persists `channelName` into the per-user seen-map (merge + debounced save). */\n private markOnboardingSeen(channelName: string): void {\n const map = this.readOnboardingSeen();\n if (map[channelName] === true) {\n return;\n }\n map[channelName] = true;\n UserInfoEngine.Instance.SetSettingDebounced(CHANNEL_ONBOARDING_SEEN_SETTING_KEY, JSON.stringify(map));\n }\n\n /** Reads + parses the per-user seen-map setting (tolerant: malformed / unset → empty map). */\n private readOnboardingSeen(): Record<string, boolean> {\n const raw = UserInfoEngine.Instance.GetSetting(CHANNEL_ONBOARDING_SEEN_SETTING_KEY);\n if (!raw) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, boolean>)\n : {};\n } catch {\n return {};\n }\n }\n\n /**\n * Focuses the FIRST tab in the strip — channels lead, so a Details peek lands on the\n * marquee surface (e.g. the Whiteboard) when one exists, else on Activity.\n */\n public FocusFirstTab(): void {\n const first = this.Model.Tabs[0];\n if (first) {\n this.Model.Focus(first.Key);\n this.cdr.markForCheck();\n }\n }\n\n /** Clears the model's flash highlight after a beat (one timer; latest flash wins). */\n private scheduleFlashClear(): void {\n if (this.Model.FlashKey === null) {\n return;\n }\n if (this.flashTimer) {\n clearTimeout(this.flashTimer);\n }\n this.flashTimer = setTimeout(() => {\n this.flashTimer = null;\n this.Model.ClearFlash();\n }, RealtimeSurfaceTabsComponent.FlashDurationMs);\n }\n}\n","<!-- SIZING IS EXTERNAL: the overlay hosts this panel inside a fixed-width flex item and\n owns its width (drag, persistence, default tiers) — the panel just fills it. -->\n<aside class=\"surface\"\n [class.surface--collapsed]=\"Collapsed\"\n [class.surface--fill]=\"Fill && !Collapsed\"\n aria-label=\"Session surfaces\">\n\n @if (Collapsed) {\n <!-- Slim strip: the panel's collapse target -->\n <div class=\"surface__strip\">\n <button type=\"button\"\n class=\"surface__toggle\"\n (click)=\"ToggleCollapsed()\"\n title=\"Show session panel\"\n aria-expanded=\"false\">\n <i class=\"fa-solid fa-chevron-left\" aria-hidden=\"true\"></i>\n </button>\n <i class=\"fa-solid fa-wave-square surface__strip-icon\" aria-hidden=\"true\" title=\"Session activity\"></i>\n </div>\n } @else {\n <!-- Tab strip: channel tabs (left cluster) … | spacer | Activity (right-aligned) -->\n <div class=\"surface-tabs\" role=\"tablist\">\n @for (tab of Model.Tabs; track TrackTab($index, tab)) {\n @if (tab.Kind === 'activity') {\n <!-- Flex spacer pushes the Activity tab to the far right -->\n <span class=\"tabs-spacer\" aria-hidden=\"true\"></span>\n }\n <button type=\"button\"\n class=\"s-tab\"\n role=\"tab\"\n [class.s-tab--activity]=\"tab.Kind === 'activity'\"\n [class.s-tab--channel]=\"tab.Kind === 'channel'\"\n [class.s-tab--active]=\"tab.Key === Model.ActiveKey\"\n [class.s-tab--flash]=\"tab.Key === Model.FlashKey\"\n [style.--tab-accent]=\"tab.Color || null\"\n [attr.aria-selected]=\"tab.Key === Model.ActiveKey\"\n [title]=\"tab.Title\"\n (click)=\"Model.Focus(tab.Key)\">\n @if (tab.Kind === 'channel') {\n <span class=\"s-tab__dot\" aria-hidden=\"true\"></span>\n }\n <i [class]=\"tab.Icon\" aria-hidden=\"true\"></i>\n <span class=\"s-tab__title\">{{ tab.Title }}</span>\n @if (tab.Kind === 'activity' && State.Cards.length > 0) {\n <span class=\"s-tab__badge\" aria-hidden=\"true\">{{ State.Cards.length }}</span>\n }\n </button>\n }\n <div class=\"tabs-end\">\n <button type=\"button\"\n class=\"surface__toggle\"\n (click)=\"ToggleCollapsed()\"\n title=\"Hide session panel\"\n aria-expanded=\"true\">\n <i class=\"fa-solid fa-chevron-right\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- Panes: ALL kept alive; only the active one is displayed -->\n @for (tab of Model.Tabs; track TrackTab($index, tab)) {\n <div class=\"s-pane\" [class.s-pane--active]=\"tab.Key === Model.ActiveKey\" role=\"tabpanel\">\n @switch (tab.Kind) {\n @case ('activity') {\n <mj-realtime-activity-rail\n [State]=\"State\"\n [DevMode]=\"DevMode\"\n [Embedded]=\"true\"\n [CurrentUser]=\"CurrentUser\"\n [EnvironmentID]=\"EnvironmentID\"\n [ExtraArtifacts]=\"ExtraArtifacts\"\n (OpenRunRequested)=\"OpenRunRequested.emit($event)\">\n </mj-realtime-activity-rail>\n }\n @case ('channel') {\n @if (tab.Data?.Plugin; as plugin) {\n <!-- Registry-resolved channel: the pane host creates the plugin's surface\n component dynamically and hands the instance back for binding -->\n <mj-realtime-channel-pane [Plugin]=\"plugin\"></mj-realtime-channel-pane>\n <!-- First-run intro: overlaid over the active channel pane the first time this user\n opens it; the pane host renders display:none + a sibling surface, so the overlay\n sits here (inside the positioned .s-pane) rather than inside the pane host. -->\n @if (tab.Key === Model.ActiveKey && OnboardingContent) {\n <mj-channel-onboarding-panel\n [Content]=\"OnboardingContent\"\n (Dismissed)=\"DismissOnboarding()\">\n </mj-channel-onboarding-panel>\n }\n } @else if (tab.Data?.Content; as content) {\n <ng-container [ngTemplateOutlet]=\"content\"></ng-container>\n } @else {\n <!-- Placeholder until the channel registration supplies a plugin / template -->\n <div class=\"channel-placeholder\" role=\"status\">\n <i class=\"fa-solid fa-chalkboard\" aria-hidden=\"true\"></i>\n <span>{{ tab.Title }} coming online…</span>\n </div>\n }\n }\n }\n </div>\n }\n\n @if (Model.Tabs.length === 0) {\n <!-- Nothing in play yet (idle voice-first session): a gentle hint, not an empty grid -->\n <div class=\"surface__empty\" role=\"status\">\n <i class=\"fa-solid fa-wave-square\" aria-hidden=\"true\"></i>\n <span>Surfaces appear here as the call gets going.</span>\n </div>\n }\n }\n</aside>\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-surface-tabs.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-tabs.component.ts","../../../../src/lib/components/realtime/realtime-surface-tabs.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, EventEmitter, Input, Output, OnInit, OnDestroy, ChangeDetectorRef, ViewChild, inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Subscription } from 'rxjs';\nimport { UserInfo } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { ArtifactsModule } from '@memberjunction/ng-artifacts';\nimport { RealtimeSessionState } from './realtime-session-state';\nimport { RealtimeActivityRailComponent } from './realtime-activity-rail.component';\nimport { RealtimeChannelPaneComponent } from './channels/realtime-channel-pane.component';\nimport { ChannelOnboardingPanelComponent } from './channels/channel-onboarding-panel.component';\nimport { ChannelOnboardingDetails } from '@memberjunction/realtime-runtime';\nimport {\n RealtimeSurfaceTabsModel, RealtimeSurfaceTab, RealtimeChannelTabRegistration\n} from './realtime-surface-tabs.model';\nimport { ParsedDelegationArtifact } from '@memberjunction/realtime-runtime';\n\n/**\n * User-settings key (NOT localStorage — see `UserInfoEngine`) under which the per-user \"which\n * channel intros have been seen\" map is persisted: a JSON object of `{ [channelName]: true }`,\n * so the first-run onboarding for each interactive channel shows exactly once per user and\n * follows them across devices.\n */\nconst CHANNEL_ONBOARDING_SEEN_SETTING_KEY = 'mj.realtimeChannels.onboardingSeen.v1';\n\n/**\n * The call overlay's TABBED SURFACE PANEL (the right panel) — decluttered redesign:\n *\n * - **Channel tabs** (LEFT cluster) — one per channel that has come into play. The whiteboard\n * tabs immediately at session start; every other channel tabs only once the agent first\n * USES it. Each carries a distinct accent color + its plugin icon. The pane creates the\n * plugin's surface component dynamically (via `mj-realtime-channel-pane`); a placeholder\n * shows the \"coming online…\" state until a plugin/template is supplied.\n * - **Activity** (RIGHT-aligned, pinned LAST) — gated: appears only once ≥1 agent run has\n * occurred (or in review mode). Hosts {@link RealtimeActivityRailComponent}, which now also\n * renders inline artifact previews and a split-pane artifact viewer. Styled distinctly from\n * channel tabs (activity-pulse icon + its own accent) and separated from the channel cluster\n * by a flex spacer.\n *\n * Artifacts NO LONGER get their own tab — they live inside the Activity tab (cleaner than a\n * row of per-artifact tabs).\n *\n * Panes are kept ALIVE while hidden (CSS `display:none`) so switching tabs never reloads a\n * channel surface or resets the rail. The whole panel collapses to a slim strip via the chevron.\n *\n * SIZING IS EXTERNAL: the overlay shell hosts this panel in a fixed-width flex item and owns\n * the width. This panel just fills it and REPORTS the layout signals the shell sizes from:\n * {@link CollapsedChange} (slim-strip toggle) and {@link WideChanged} (a channel tab is focused\n * → the default width tier widens).\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-surface-tabs',\n imports: [\n CommonModule, ArtifactsModule, RealtimeActivityRailComponent, RealtimeChannelPaneComponent,\n ChannelOnboardingPanelComponent\n ],\n templateUrl: './realtime-surface-tabs.component.html',\n styleUrl: './realtime-surface-tabs.component.css'\n})\nexport class RealtimeSurfaceTabsComponent implements OnInit, OnDestroy {\n /** How long a just-revealed channel tab keeps its flash highlight. */\n private static readonly flashDurationMs = 1400;\n\n /** Shared live-session state, owned by the overlay shell (feeds the Activity rail). */\n @Input({ required: true }) State!: RealtimeSessionState;\n\n /** Whether developer affordances (\"Open run\" links) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /**\n * FILL presentation: the panel stretches to the overlay's full width (the board-focus\n * layout, where the main call column is hidden and a channel surface owns the screen).\n * Bound by the overlay shell; overrides the normal / wide width tiers.\n */\n @Input() Fill = false;\n\n /** The signed-in user, threaded to the artifact viewer panel. */\n @Input() CurrentUser: UserInfo | null = null;\n\n /** The active environment id, threaded to the artifact viewer panel. */\n @Input() EnvironmentID = '';\n\n /**\n * Extra (review-carryover) artifacts to surface in the Activity tab, NOT tied to a live\n * activity card. Forwarded to the rail's \"Session artifacts\" group. Empty for a live session.\n */\n @Input() ExtraArtifacts: ParsedDelegationArtifact[] = [];\n\n /**\n * Whether the gated Activity tab should be shown — driven by the overlay shell once ≥1\n * agent run has occurred (or in review mode). A getter/setter so a late \"first run\" flips\n * the tab into the strip reactively.\n */\n private _showActivityTab = false;\n @Input()\n set ShowActivityTab(value: boolean) {\n if (value !== this._showActivityTab) {\n this._showActivityTab = value;\n this.Model.SetShowActivityTab(value);\n this.cdr.markForCheck();\n }\n }\n get ShowActivityTab(): boolean {\n return this._showActivityTab;\n }\n\n /** Re-emitted from the Activity rail's dev \"Open run\" links. */\n @Output() OpenRunRequested = new EventEmitter<string>();\n\n /**\n * Emitted when the panel toggles between expanded and the slim collapsed strip —\n * the overlay shell resizes this panel's split area to the strip width.\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when {@link IsWide} flips (a channel tab gained / lost focus) — the\n * overlay shell widens the panel's DEFAULT split-area size while wide (only when\n * the user has never dragged an explicit width).\n */\n @Output() WideChanged = new EventEmitter<boolean>();\n\n /** The panel's tab state (add / focus / dedupe / flash) — see the model for the rules. */\n public readonly Model = new RealtimeSurfaceTabsModel();\n\n /** Whether the panel is collapsed to its slim strip. */\n public Collapsed = false;\n\n /** The embedded Activity rail (owns the inline artifact previews + the split-pane viewer). */\n @ViewChild(RealtimeActivityRailComponent) private activityRail?: RealtimeActivityRailComponent;\n\n private flashTimer: ReturnType<typeof setTimeout> | null = null;\n private subs: Subscription[] = [];\n private lastWide = false;\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * The channel whose first-run intro is currently being shown (its `ChannelName`), or `null`\n * when no intro is up. Set when the user opens a channel tab they've never seen the intro\n * for; cleared on dismiss. Only one intro shows at a time (the active channel's).\n */\n private onboardingChannelName: string | null = null;\n /** The intro content for {@link onboardingChannelName}, mirrored for the template binding. */\n public OnboardingContent: ChannelOnboardingDetails | null = null;\n\n /** The currently focused tab. */\n public get ActiveTab(): RealtimeSurfaceTab {\n return this.Model.ActiveTab;\n }\n\n /** Wide presentation when a channel tab is focused (the Activity tab keeps the normal tier). */\n public get IsWide(): boolean {\n return !this.Collapsed && this.ActiveTab.Kind === 'channel';\n }\n\n ngOnInit(): void {\n this.subs.push(\n this.Model.Changed$.subscribe(() => this.onModelChanged())\n );\n }\n\n ngOnDestroy(): void {\n for (const s of this.subs) {\n s.unsubscribe();\n }\n this.subs = [];\n if (this.flashTimer) {\n clearTimeout(this.flashTimer);\n this.flashTimer = null;\n }\n }\n\n /** Toggle the panel between expanded and slim-collapsed. */\n public ToggleCollapsed(): void {\n this.setCollapsed(!this.Collapsed);\n }\n\n /** Collapse-state transitions funnel through here so the shell always hears about them. */\n private setCollapsed(value: boolean): void {\n if (this.Collapsed !== value) {\n this.Collapsed = value;\n this.CollapsedChange.emit(value);\n this.syncWide();\n }\n }\n\n /** Emits {@link WideChanged} when the wide tier flips (channel tab focus / collapse). */\n private syncWide(): void {\n const wide = this.IsWide;\n if (wide !== this.lastWide) {\n this.lastWide = wide;\n this.WideChanged.emit(wide);\n }\n }\n\n /** track fn for the @for over tabs. */\n public TrackTab(index: number, tab: RealtimeSurfaceTab): string {\n return tab.Key;\n }\n\n /**\n * Focuses the Activity tab and opens the given artifact in the rail's split-pane viewer —\n * the \"View →\" affordance target on done delegation cards / thread entries. Expands the\n * panel if it was collapsed. Replaces the old \"open a tab per artifact\" behavior.\n */\n public FocusArtifact(artifact: ParsedDelegationArtifact): void {\n this.setCollapsed(false);\n // An artifact implies a run happened — ensure the Activity tab is present before focusing it.\n this.Model.SetShowActivityTab(true);\n this.Model.Focus(RealtimeSurfaceTabsModel.ActivityTabKey);\n // The rail may not be created yet (panel just expanded) — defer so it exists.\n if (this.activityRail) {\n this.activityRail.OpenArtifact(artifact);\n } else {\n setTimeout(() => this.activityRail?.OpenArtifact(artifact));\n }\n this.cdr.markForCheck();\n }\n\n /**\n * Registers (or updates) an interactive-channel tab — one per used channel plugin,\n * forwarded from `RealtimeSessionOverlayComponent.RegisterChannelTab`.\n */\n public RegisterChannelTab(registration: RealtimeChannelTabRegistration): void {\n // Microtask defer: the overlay forwards this while handling agent/channel activity, which can\n // land mid change-detection. Adding a tab to Model synchronously then trips NG0100 on the\n // tab-strip bindings (s-tab--active). A microtask lands the mutation in a fresh CD turn —\n // imperceptible for an async reveal, and ordered with any follow-on RevealChannel.\n Promise.resolve().then(() => {\n this.Model.RegisterChannelTab(registration);\n this.cdr.markForCheck();\n });\n }\n\n /**\n * AUTO-REVEALS a channel surface the moment the agent first acts on it: expands the\n * panel if collapsed, focuses the channel's tab and flashes it — so the user discovers\n * the whiteboard (or any channel) exists the instant it comes alive. No-op for unknown keys.\n */\n public RevealChannel(key: string): void {\n // Microtask defer (same NG0100 reason as RegisterChannelTab): the agent-activity reveal mutates\n // ActiveKey/FlashKey, which feed the tab-strip class bindings; doing it mid-CD trips the\n // ExpressionChanged check. Deferring lands it in a fresh CD turn and stays ordered after any\n // RegisterChannelTab queued just before it.\n Promise.resolve().then(() => {\n this.setCollapsed(false);\n this.Model.Focus(key);\n this.Model.FlashTab(key);\n this.cdr.markForCheck();\n });\n }\n\n /**\n * Removes a tab from the panel (Activity is irremovable; focus falls back per the model's\n * rules). Used by the overlay shell on a review→live continuation whose live channel set\n * resolved WITHOUT the channel a stale review tab represents (e.g. no Whiteboard channel →\n * drop the read-only review board tab).\n *\n * @returns `true` when a tab was removed.\n */\n public RemoveTab(key: string): boolean {\n const removed = this.Model.RemoveTab(key);\n if (removed) {\n this.cdr.markForCheck();\n }\n return removed;\n }\n\n /**\n * Registers the reviewed chain's history artifacts so they surface inside the Activity tab.\n * In the redesign there are no per-artifact tabs — the rail picks artifacts up from the\n * session state's cards, so this only needs to ensure the Activity tab is shown (review\n * mode always shows it) and, when `focus` is set, open the artifact in the split viewer.\n */\n public RegisterArtifactTab(artifact: ParsedDelegationArtifact, focus: boolean = false): void {\n this.Model.SetShowActivityTab(true);\n if (focus) {\n this.FocusArtifact(artifact);\n }\n this.cdr.markForCheck();\n }\n\n /** On model changes: schedule the flash clear, report a wide-tier flip, re-render. */\n private onModelChanged(): void {\n this.scheduleFlashClear();\n this.syncWide();\n this.evaluateOnboarding();\n this.cdr.markForCheck();\n }\n\n /**\n * Decides whether the first-run channel intro should be visible for the ACTIVE tab: shows it\n * the first time the user opens (focuses) a channel tab whose plugin supplies onboarding and\n * which this user hasn't dismissed before. Re-runs on every model change so switching away\n * from a channel tab tears the intro down (only the active channel's intro is ever up).\n */\n private evaluateOnboarding(): void {\n const tab = this.ActiveTab;\n const plugin = tab.Kind === 'channel' ? tab.Data?.Plugin ?? null : null;\n const details = plugin?.GetOnboardingDetails() ?? null;\n if (!plugin || !details || this.hasSeenOnboarding(plugin.ChannelName)) {\n this.onboardingChannelName = null;\n this.OnboardingContent = null;\n return;\n }\n this.onboardingChannelName = plugin.ChannelName;\n this.OnboardingContent = details;\n }\n\n /**\n * Dismisses the current channel intro: marks that channel seen for this user (persisted via\n * `UserInfoEngine`, debounced — NOT localStorage) and hides the panel so it never re-appears.\n */\n public DismissOnboarding(): void {\n const channelName = this.onboardingChannelName;\n this.onboardingChannelName = null;\n this.OnboardingContent = null;\n if (channelName) {\n this.markOnboardingSeen(channelName);\n }\n this.cdr.markForCheck();\n }\n\n /** Reads the per-user seen-map and reports whether this channel's intro has been dismissed. */\n private hasSeenOnboarding(channelName: string): boolean {\n return this.readOnboardingSeen()[channelName] === true;\n }\n\n /** Persists `channelName` into the per-user seen-map (merge + debounced save). */\n private markOnboardingSeen(channelName: string): void {\n const map = this.readOnboardingSeen();\n if (map[channelName] === true) {\n return;\n }\n map[channelName] = true;\n UserInfoEngine.Instance.SetSettingDebounced(CHANNEL_ONBOARDING_SEEN_SETTING_KEY, JSON.stringify(map));\n }\n\n /** Reads + parses the per-user seen-map setting (tolerant: malformed / unset → empty map). */\n private readOnboardingSeen(): Record<string, boolean> {\n const raw = UserInfoEngine.Instance.GetSetting(CHANNEL_ONBOARDING_SEEN_SETTING_KEY);\n if (!raw) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, boolean>)\n : {};\n } catch {\n return {};\n }\n }\n\n /**\n * Focuses the FIRST tab in the strip — channels lead, so a Details peek lands on the\n * marquee surface (e.g. the Whiteboard) when one exists, else on Activity.\n */\n public FocusFirstTab(): void {\n const first = this.Model.Tabs[0];\n if (first) {\n this.Model.Focus(first.Key);\n this.cdr.markForCheck();\n }\n }\n\n /** Clears the model's flash highlight after a beat (one timer; latest flash wins). */\n private scheduleFlashClear(): void {\n if (this.Model.FlashKey === null) {\n return;\n }\n if (this.flashTimer) {\n clearTimeout(this.flashTimer);\n }\n this.flashTimer = setTimeout(() => {\n this.flashTimer = null;\n this.Model.ClearFlash();\n }, RealtimeSurfaceTabsComponent.flashDurationMs);\n }\n}\n","<!-- SIZING IS EXTERNAL: the overlay hosts this panel inside a fixed-width flex item and\n owns its width (drag, persistence, default tiers) — the panel just fills it. -->\n<aside class=\"surface\"\n [class.surface--collapsed]=\"Collapsed\"\n [class.surface--fill]=\"Fill && !Collapsed\"\n aria-label=\"Session surfaces\">\n\n @if (Collapsed) {\n <!-- Slim strip: the panel's collapse target -->\n <div class=\"surface__strip\">\n <button type=\"button\"\n class=\"surface__toggle\"\n (click)=\"ToggleCollapsed()\"\n title=\"Show session panel\"\n aria-expanded=\"false\">\n <i class=\"fa-solid fa-chevron-left\" aria-hidden=\"true\"></i>\n </button>\n <i class=\"fa-solid fa-wave-square surface__strip-icon\" aria-hidden=\"true\" title=\"Session activity\"></i>\n </div>\n } @else {\n <!-- Tab strip: channel tabs (left cluster) … | spacer | Activity (right-aligned) -->\n <div class=\"surface-tabs\" role=\"tablist\">\n @for (tab of Model.Tabs; track TrackTab($index, tab)) {\n @if (tab.Kind === 'activity') {\n <!-- Flex spacer pushes the Activity tab to the far right -->\n <span class=\"tabs-spacer\" aria-hidden=\"true\"></span>\n }\n <button type=\"button\"\n class=\"s-tab\"\n role=\"tab\"\n [class.s-tab--activity]=\"tab.Kind === 'activity'\"\n [class.s-tab--channel]=\"tab.Kind === 'channel'\"\n [class.s-tab--active]=\"tab.Key === Model.ActiveKey\"\n [class.s-tab--flash]=\"tab.Key === Model.FlashKey\"\n [style.--tab-accent]=\"tab.Color || null\"\n [attr.aria-selected]=\"tab.Key === Model.ActiveKey\"\n [title]=\"tab.Title\"\n (click)=\"Model.Focus(tab.Key)\">\n @if (tab.Kind === 'channel') {\n <span class=\"s-tab__dot\" aria-hidden=\"true\"></span>\n }\n <i [class]=\"tab.Icon\" aria-hidden=\"true\"></i>\n <span class=\"s-tab__title\">{{ tab.Title }}</span>\n @if (tab.Kind === 'activity' && State.Cards.length > 0) {\n <span class=\"s-tab__badge\" aria-hidden=\"true\">{{ State.Cards.length }}</span>\n }\n </button>\n }\n <div class=\"tabs-end\">\n <button type=\"button\"\n class=\"surface__toggle\"\n (click)=\"ToggleCollapsed()\"\n title=\"Hide session panel\"\n aria-expanded=\"true\">\n <i class=\"fa-solid fa-chevron-right\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- Panes: ALL kept alive; only the active one is displayed -->\n @for (tab of Model.Tabs; track TrackTab($index, tab)) {\n <div class=\"s-pane\" [class.s-pane--active]=\"tab.Key === Model.ActiveKey\" role=\"tabpanel\">\n @switch (tab.Kind) {\n @case ('activity') {\n <mj-realtime-activity-rail\n [State]=\"State\"\n [DevMode]=\"DevMode\"\n [Embedded]=\"true\"\n [CurrentUser]=\"CurrentUser\"\n [EnvironmentID]=\"EnvironmentID\"\n [ExtraArtifacts]=\"ExtraArtifacts\"\n (OpenRunRequested)=\"OpenRunRequested.emit($event)\">\n </mj-realtime-activity-rail>\n }\n @case ('channel') {\n @if (tab.Data?.Plugin; as plugin) {\n <!-- Registry-resolved channel: the pane host creates the plugin's surface\n component dynamically and hands the instance back for binding -->\n <mj-realtime-channel-pane [Plugin]=\"plugin\"></mj-realtime-channel-pane>\n <!-- First-run intro: overlaid over the active channel pane the first time this user\n opens it; the pane host renders display:none + a sibling surface, so the overlay\n sits here (inside the positioned .s-pane) rather than inside the pane host. -->\n @if (tab.Key === Model.ActiveKey && OnboardingContent) {\n <mj-channel-onboarding-panel\n [Content]=\"OnboardingContent\"\n (Dismissed)=\"DismissOnboarding()\">\n </mj-channel-onboarding-panel>\n }\n } @else if (tab.Data?.Content; as content) {\n <ng-container [ngTemplateOutlet]=\"content\"></ng-container>\n } @else {\n <!-- Placeholder until the channel registration supplies a plugin / template -->\n <div class=\"channel-placeholder\" role=\"status\">\n <i class=\"fa-solid fa-chalkboard\" aria-hidden=\"true\"></i>\n <span>{{ tab.Title }} coming online…</span>\n </div>\n }\n }\n }\n </div>\n }\n\n @if (Model.Tabs.length === 0) {\n <!-- Nothing in play yet (idle voice-first session): a gentle hint, not an empty grid -->\n <div class=\"surface__empty\" role=\"status\">\n <i class=\"fa-solid fa-wave-square\" aria-hidden=\"true\"></i>\n <span>Surfaces appear here as the call gets going.</span>\n </div>\n }\n }\n</aside>\n"]}
|
|
@@ -100,7 +100,7 @@ export declare class RealtimeSurfaceTabsModel {
|
|
|
100
100
|
/** The fixed key of the session-activity tab (pinned LAST, right-aligned). */
|
|
101
101
|
static readonly ActivityTabKey = "activity";
|
|
102
102
|
/** The activity tab definition, appended last whenever {@link showActivity} is true. */
|
|
103
|
-
private static readonly
|
|
103
|
+
private static readonly activityTab;
|
|
104
104
|
/** Channel tabs (left cluster), in registration order. Replaced immutably on change. */
|
|
105
105
|
private channelTabs;
|
|
106
106
|
/** Whether the gated Activity tab is currently shown (≥1 agent run, or review mode). */
|
|
@@ -19,7 +19,7 @@ export class RealtimeSurfaceTabsModel {
|
|
|
19
19
|
/** The fixed key of the session-activity tab (pinned LAST, right-aligned). */
|
|
20
20
|
static ActivityTabKey = 'activity';
|
|
21
21
|
/** The activity tab definition, appended last whenever {@link showActivity} is true. */
|
|
22
|
-
static
|
|
22
|
+
static activityTab = {
|
|
23
23
|
Key: RealtimeSurfaceTabsModel.ActivityTabKey,
|
|
24
24
|
Title: 'Activity',
|
|
25
25
|
Icon: 'fa-solid fa-wave-square',
|
|
@@ -45,7 +45,7 @@ export class RealtimeSurfaceTabsModel {
|
|
|
45
45
|
*/
|
|
46
46
|
get Tabs() {
|
|
47
47
|
return this.showActivity
|
|
48
|
-
? [...this.channelTabs, RealtimeSurfaceTabsModel.
|
|
48
|
+
? [...this.channelTabs, RealtimeSurfaceTabsModel.activityTab]
|
|
49
49
|
: [...this.channelTabs];
|
|
50
50
|
}
|
|
51
51
|
/** Whether the Activity tab is currently part of the strip. */
|
|
@@ -62,7 +62,7 @@ export class RealtimeSurfaceTabsModel {
|
|
|
62
62
|
return tabs.find(t => t.Key === this.ActiveKey)
|
|
63
63
|
?? tabs.find(t => t.Key === RealtimeSurfaceTabsModel.ActivityTabKey)
|
|
64
64
|
?? tabs[0]
|
|
65
|
-
?? RealtimeSurfaceTabsModel.
|
|
65
|
+
?? RealtimeSurfaceTabsModel.activityTab;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Shows or hides the gated Activity tab. Turning it ON when an empty strip was implicitly
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-surface-tabs.model.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-tabs.model.ts"],"names":[],"mappings":"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","sourcesContent":["import { Subject } from 'rxjs';\nimport type { TemplateRef } from '@angular/core';\nimport type { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';\nimport { ChannelTabColor } from './realtime-surface-tab-style';\n\n/**\n * The kind of a surface-panel tab:\n * - `activity` — the session-activity tab (pinned LAST, right-aligned). Hosts the activity\n * rail AND, since the artifact redesign, the inline artifact previews + the split-pane\n * artifact viewer. Shown only once ≥1 agent run has occurred (see\n * {@link RealtimeSurfaceTabsModel.SetShowActivityTab}).\n * - `channel` — an interactive-channel surface (e.g. the Whiteboard). Registered per\n * used channel via {@link RealtimeSurfaceTabsModel.RegisterChannelTab}; renders the\n * plugin's dynamically-created surface component (or a registered template for\n * legacy/template-based panes), with the \"coming online…\" placeholder until either\n * is supplied.\n *\n * NOTE: artifacts NO LONGER get their own tab. A delegated run's artifacts now render\n * INSIDE the Activity tab (inline previews + an `as-split` viewer pane) — see\n * `RealtimeActivityRailComponent`.\n */\nexport type RealtimeSurfaceTabKind = 'activity' | 'channel';\n\n/**\n * Per-kind payload carried on a {@link RealtimeSurfaceTab}.\n */\nexport interface RealtimeSurfaceTabData {\n /**\n * For `channel` tabs: the channel PLUGIN whose surface component the pane creates\n * dynamically (and binds back to the plugin) — the registry-driven path every real\n * channel uses. Takes precedence over {@link Content}.\n */\n Plugin?: BaseRealtimeChannelClient;\n /**\n * For `channel` tabs: a TEMPLATE-based pane body. Backward-compatible alternative to\n * {@link Plugin} for hosts that render a bespoke surface without a channel plugin.\n * When BOTH are absent the pane renders the built-in \"coming online…\" placeholder.\n */\n Content?: TemplateRef<unknown>;\n}\n\n/**\n * One tab on the call overlay's tabbed surface panel (the right panel): a channel surface\n * (left cluster) or the session-activity tab (right-aligned).\n */\nexport interface RealtimeSurfaceTab {\n /** Stable unique key (`activity`, or the channel's registered key). */\n Key: string;\n /** Tab strip label (channel name, or \"Activity\"). */\n Title: string;\n /** Font Awesome icon class for the tab strip (e.g. `fa-solid fa-chalkboard`). */\n Icon: string;\n /** What the tab renders. */\n Kind: RealtimeSurfaceTabKind;\n /**\n * Accent color for the tab's dot + active underline. Channel tabs carry a distinct color\n * (plugin-supplied or a deterministic hash of the name); the Activity tab uses its own\n * fixed accent in CSS, so its `Color` is left undefined.\n */\n Color?: string;\n /** Kind-specific payload. */\n Data?: RealtimeSurfaceTabData;\n}\n\n/**\n * Registration for an interactive-channel tab. The overlay shell registers one per\n * USED channel plugin (supplying {@link Plugin}); supplying {@link Plugin} or\n * {@link Content} later under the same `Key` upgrades a placeholder tab to the real surface.\n */\nexport interface RealtimeChannelTabRegistration {\n /** Stable channel key (the plugin's `ChannelName`, e.g. `Whiteboard`). Re-registering the same key updates the tab. */\n Key: string;\n /** Tab strip label (e.g. `Whiteboard`). */\n Title: string;\n /** Font Awesome icon class (e.g. `fa-solid fa-chalkboard`). */\n Icon: string;\n /**\n * Optional explicit accent color for the tab. When omitted, a deterministic color is\n * derived from {@link Key} so every channel tab still reads as a distinct surface.\n */\n Color?: string | null;\n /** The channel plugin whose surface the pane creates + binds. Preferred over {@link Content}. */\n Plugin?: BaseRealtimeChannelClient;\n /** A template-based pane body (legacy/bespoke panes). Omit both to show the \"coming online…\" placeholder. */\n Content?: TemplateRef<unknown>;\n /** Focus the tab immediately after registration (default `false`). */\n Focus?: boolean;\n}\n\n/**\n * Framework-free state for the call overlay's tabbed surface panel: the ordered tab list\n * (CHANNEL tabs first — the marquee surfaces, left cluster — with the session-activity tab\n * pinned LAST and right-aligned by the strip), the active tab, and the transient \"flash\"\n * highlight for a just-revealed channel tab.\n *\n * The Activity tab is GATED: it isn't listed until {@link SetShowActivityTab}(true) — i.e.\n * once ≥1 agent run has occurred (or in review mode). Channel tabs appear only as channels\n * come into play (the whiteboard up-front; every other channel on first use), so an\n * idle voice-first session shows an empty/near-empty strip rather than a row of unused tabs.\n *\n * Owned by `RealtimeSurfaceTabsComponent`; kept free of Angular runtime imports so the\n * add / focus / dedupe / flash logic is unit-testable in isolation. All collections are\n * REPLACED (never mutated) on change, and every change emits {@link Changed$}.\n */\nexport class RealtimeSurfaceTabsModel {\n /** The fixed key of the session-activity tab (pinned LAST, right-aligned). */\n public static readonly ActivityTabKey = 'activity';\n\n /** The activity tab definition, appended last whenever {@link showActivity} is true. */\n private static readonly ActivityTab: RealtimeSurfaceTab = {\n Key: RealtimeSurfaceTabsModel.ActivityTabKey,\n Title: 'Activity',\n Icon: 'fa-solid fa-wave-square',\n Kind: 'activity'\n };\n\n /** Channel tabs (left cluster), in registration order. Replaced immutably on change. */\n private channelTabs: RealtimeSurfaceTab[] = [];\n\n /** Whether the gated Activity tab is currently shown (≥1 agent run, or review mode). */\n private showActivity = false;\n\n /** Key of the currently focused tab. */\n public ActiveKey: string = RealtimeSurfaceTabsModel.ActivityTabKey;\n\n /**\n * Key of the tab currently \"flashing\" (the brief highlight a just-revealed channel tab\n * gets when the agent first acts on it). Cleared by the owning component after a beat via\n * {@link ClearFlash}.\n */\n public FlashKey: string | null = null;\n\n /** Emits after every model change so the owning component can mark for check. */\n public readonly Changed$ = new Subject<void>();\n\n /**\n * The ordered tabs: channel tabs (left), then the Activity tab LAST when shown. The strip\n * right-aligns the Activity tab via a flex spacer, so this order also matches reading order.\n */\n public get Tabs(): RealtimeSurfaceTab[] {\n return this.showActivity\n ? [...this.channelTabs, RealtimeSurfaceTabsModel.ActivityTab]\n : [...this.channelTabs];\n }\n\n /** Whether the Activity tab is currently part of the strip. */\n public get IsActivityShown(): boolean {\n return this.showActivity;\n }\n\n /**\n * The currently focused tab. Resolves to the active key when it still exists, else falls\n * back to the Activity tab (when shown), else the first channel tab, else the Activity tab\n * definition (so a consumer always has SOMETHING to render even on an empty strip).\n */\n public get ActiveTab(): RealtimeSurfaceTab {\n const tabs = this.Tabs;\n return tabs.find(t => t.Key === this.ActiveKey)\n ?? tabs.find(t => t.Key === RealtimeSurfaceTabsModel.ActivityTabKey)\n ?? tabs[0]\n ?? RealtimeSurfaceTabsModel.ActivityTab;\n }\n\n /**\n * Shows or hides the gated Activity tab. Turning it ON when an empty strip was implicitly\n * focusing Activity keeps focus on Activity; turning it OFF while it was focused falls\n * focus back to the first channel tab (if any). No-op (no emission) when unchanged.\n *\n * @param show Whether ≥1 agent run has occurred (or review mode) — the gate.\n */\n public SetShowActivityTab(show: boolean): void {\n if (this.showActivity === show) {\n return;\n }\n this.showActivity = show;\n if (!show && this.ActiveKey === RealtimeSurfaceTabsModel.ActivityTabKey) {\n this.ActiveKey = this.channelTabs[0]?.Key ?? RealtimeSurfaceTabsModel.ActivityTabKey;\n }\n this.Changed$.next();\n }\n\n /**\n * Registers (or updates) an interactive-channel tab. Re-registering an existing key\n * replaces its title/icon/color/plugin/content in place (this is how a placeholder\n * upgrades to the real surface once the channel comes online). New channel tabs join the\n * left cluster in registration order. A registration without an explicit {@link\n * RealtimeChannelTabRegistration.Color} gets a deterministic color from its key.\n *\n * @param registration The channel tab registration.\n * @returns The (new or updated) tab.\n */\n public RegisterChannelTab(registration: RealtimeChannelTabRegistration): RealtimeSurfaceTab {\n const tab: RealtimeSurfaceTab = {\n Key: registration.Key,\n Title: registration.Title,\n Icon: registration.Icon,\n Kind: 'channel',\n Color: registration.Color ?? ChannelTabColor(registration.Key),\n Data: { Plugin: registration.Plugin, Content: registration.Content }\n };\n const idx = this.channelTabs.findIndex(t => t.Key === registration.Key);\n if (idx >= 0) {\n const next = [...this.channelTabs];\n next[idx] = tab;\n this.channelTabs = next;\n } else {\n this.channelTabs = [...this.channelTabs, tab];\n }\n if (registration.Focus) {\n this.ActiveKey = tab.Key;\n }\n this.Changed$.next();\n return tab;\n }\n\n /** Focuses the tab with `key` (no-op when it doesn't exist or is already active). */\n public Focus(key: string): void {\n if (!this.Tabs.some(t => t.Key === key) || this.ActiveKey === key) {\n return;\n }\n this.ActiveKey = key;\n this.Changed$.next();\n }\n\n /**\n * Marks the tab with `key` as the {@link FlashKey} (the brief \"just arrived\" highlight)\n * WITHOUT changing focus — used by the auto-reveal path when the agent first acts on a\n * channel, so the user's eye lands on the tab that just came alive. No-op for unknown\n * keys; the owning component clears it after a beat via {@link ClearFlash}.\n */\n public FlashTab(key: string): void {\n if (this.FlashKey === key || !this.Tabs.some(t => t.Key === key)) {\n return;\n }\n this.FlashKey = key;\n this.Changed$.next();\n }\n\n /**\n * Removes the channel tab with `key`. Rules:\n * - the Activity tab is IRREMOVABLE — removing it is a no-op;\n * - an unknown key is a no-op (returns `false`);\n * - when the removed tab was focused, focus falls back to the Activity tab (if shown),\n * else the first remaining channel tab;\n * - a pending flash on the removed tab is cleaned up so the highlight can't dangle.\n *\n * @param key The tab key to remove.\n * @returns `true` when a tab was removed.\n */\n public RemoveTab(key: string): boolean {\n if (key === RealtimeSurfaceTabsModel.ActivityTabKey || !this.channelTabs.some(t => t.Key === key)) {\n return false;\n }\n this.channelTabs = this.channelTabs.filter(t => t.Key !== key);\n if (this.ActiveKey === key) {\n this.ActiveKey = this.showActivity\n ? RealtimeSurfaceTabsModel.ActivityTabKey\n : (this.channelTabs[0]?.Key ?? RealtimeSurfaceTabsModel.ActivityTabKey);\n }\n if (this.FlashKey === key) {\n this.FlashKey = null;\n }\n this.Changed$.next();\n return true;\n }\n\n /** Clears the transient flash highlight (called by the component after a beat). */\n public ClearFlash(): void {\n if (this.FlashKey !== null) {\n this.FlashKey = null;\n this.Changed$.next();\n }\n }\n}\n\n/**\n * Pure decision helper for the REVIEW→LIVE continuation edge: should the overlay REMOVE the\n * review-registered (template-based, read-only) Whiteboard tab?\n *\n * Yes only when ALL hold:\n * - a live session is active (the channel set emission belongs to a real session start, not\n * the initial/teardown `[]` replay);\n * - review mode actually registered a whiteboard tab (otherwise there is nothing stale);\n * - the live session's resolved channel set has NO Whiteboard channel — when it HAS one, the\n * live plugin re-registers the same tab key and upgrades the pane in place instead.\n *\n * Kept framework-free (like the model) so the rule is unit-testable in isolation.\n */\nexport function ShouldRemoveReviewWhiteboardTab(\n liveSessionActive: boolean,\n reviewWhiteboardTabRegistered: boolean,\n liveChannels: ReadonlyArray<{ ChannelName: string }>\n): boolean {\n if (!liveSessionActive || !reviewWhiteboardTabRegistered) {\n return false;\n }\n return !liveChannels.some(c => c.ChannelName?.trim().toLowerCase() === 'whiteboard');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-surface-tabs.model.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-surface-tabs.model.ts"],"names":[],"mappings":"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","sourcesContent":["import { Subject } from 'rxjs';\nimport type { TemplateRef } from '@angular/core';\nimport type { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';\nimport { ChannelTabColor } from './realtime-surface-tab-style';\n\n/**\n * The kind of a surface-panel tab:\n * - `activity` — the session-activity tab (pinned LAST, right-aligned). Hosts the activity\n * rail AND, since the artifact redesign, the inline artifact previews + the split-pane\n * artifact viewer. Shown only once ≥1 agent run has occurred (see\n * {@link RealtimeSurfaceTabsModel.SetShowActivityTab}).\n * - `channel` — an interactive-channel surface (e.g. the Whiteboard). Registered per\n * used channel via {@link RealtimeSurfaceTabsModel.RegisterChannelTab}; renders the\n * plugin's dynamically-created surface component (or a registered template for\n * legacy/template-based panes), with the \"coming online…\" placeholder until either\n * is supplied.\n *\n * NOTE: artifacts NO LONGER get their own tab. A delegated run's artifacts now render\n * INSIDE the Activity tab (inline previews + an `as-split` viewer pane) — see\n * `RealtimeActivityRailComponent`.\n */\nexport type RealtimeSurfaceTabKind = 'activity' | 'channel';\n\n/**\n * Per-kind payload carried on a {@link RealtimeSurfaceTab}.\n */\nexport interface RealtimeSurfaceTabData {\n /**\n * For `channel` tabs: the channel PLUGIN whose surface component the pane creates\n * dynamically (and binds back to the plugin) — the registry-driven path every real\n * channel uses. Takes precedence over {@link Content}.\n */\n Plugin?: BaseRealtimeChannelClient;\n /**\n * For `channel` tabs: a TEMPLATE-based pane body. Backward-compatible alternative to\n * {@link Plugin} for hosts that render a bespoke surface without a channel plugin.\n * When BOTH are absent the pane renders the built-in \"coming online…\" placeholder.\n */\n Content?: TemplateRef<unknown>;\n}\n\n/**\n * One tab on the call overlay's tabbed surface panel (the right panel): a channel surface\n * (left cluster) or the session-activity tab (right-aligned).\n */\nexport interface RealtimeSurfaceTab {\n /** Stable unique key (`activity`, or the channel's registered key). */\n Key: string;\n /** Tab strip label (channel name, or \"Activity\"). */\n Title: string;\n /** Font Awesome icon class for the tab strip (e.g. `fa-solid fa-chalkboard`). */\n Icon: string;\n /** What the tab renders. */\n Kind: RealtimeSurfaceTabKind;\n /**\n * Accent color for the tab's dot + active underline. Channel tabs carry a distinct color\n * (plugin-supplied or a deterministic hash of the name); the Activity tab uses its own\n * fixed accent in CSS, so its `Color` is left undefined.\n */\n Color?: string;\n /** Kind-specific payload. */\n Data?: RealtimeSurfaceTabData;\n}\n\n/**\n * Registration for an interactive-channel tab. The overlay shell registers one per\n * USED channel plugin (supplying {@link Plugin}); supplying {@link Plugin} or\n * {@link Content} later under the same `Key` upgrades a placeholder tab to the real surface.\n */\nexport interface RealtimeChannelTabRegistration {\n /** Stable channel key (the plugin's `ChannelName`, e.g. `Whiteboard`). Re-registering the same key updates the tab. */\n Key: string;\n /** Tab strip label (e.g. `Whiteboard`). */\n Title: string;\n /** Font Awesome icon class (e.g. `fa-solid fa-chalkboard`). */\n Icon: string;\n /**\n * Optional explicit accent color for the tab. When omitted, a deterministic color is\n * derived from {@link Key} so every channel tab still reads as a distinct surface.\n */\n Color?: string | null;\n /** The channel plugin whose surface the pane creates + binds. Preferred over {@link Content}. */\n Plugin?: BaseRealtimeChannelClient;\n /** A template-based pane body (legacy/bespoke panes). Omit both to show the \"coming online…\" placeholder. */\n Content?: TemplateRef<unknown>;\n /** Focus the tab immediately after registration (default `false`). */\n Focus?: boolean;\n}\n\n/**\n * Framework-free state for the call overlay's tabbed surface panel: the ordered tab list\n * (CHANNEL tabs first — the marquee surfaces, left cluster — with the session-activity tab\n * pinned LAST and right-aligned by the strip), the active tab, and the transient \"flash\"\n * highlight for a just-revealed channel tab.\n *\n * The Activity tab is GATED: it isn't listed until {@link SetShowActivityTab}(true) — i.e.\n * once ≥1 agent run has occurred (or in review mode). Channel tabs appear only as channels\n * come into play (the whiteboard up-front; every other channel on first use), so an\n * idle voice-first session shows an empty/near-empty strip rather than a row of unused tabs.\n *\n * Owned by `RealtimeSurfaceTabsComponent`; kept free of Angular runtime imports so the\n * add / focus / dedupe / flash logic is unit-testable in isolation. All collections are\n * REPLACED (never mutated) on change, and every change emits {@link Changed$}.\n */\nexport class RealtimeSurfaceTabsModel {\n /** The fixed key of the session-activity tab (pinned LAST, right-aligned). */\n public static readonly ActivityTabKey = 'activity';\n\n /** The activity tab definition, appended last whenever {@link showActivity} is true. */\n private static readonly activityTab: RealtimeSurfaceTab = {\n Key: RealtimeSurfaceTabsModel.ActivityTabKey,\n Title: 'Activity',\n Icon: 'fa-solid fa-wave-square',\n Kind: 'activity'\n };\n\n /** Channel tabs (left cluster), in registration order. Replaced immutably on change. */\n private channelTabs: RealtimeSurfaceTab[] = [];\n\n /** Whether the gated Activity tab is currently shown (≥1 agent run, or review mode). */\n private showActivity = false;\n\n /** Key of the currently focused tab. */\n public ActiveKey: string = RealtimeSurfaceTabsModel.ActivityTabKey;\n\n /**\n * Key of the tab currently \"flashing\" (the brief highlight a just-revealed channel tab\n * gets when the agent first acts on it). Cleared by the owning component after a beat via\n * {@link ClearFlash}.\n */\n public FlashKey: string | null = null;\n\n /** Emits after every model change so the owning component can mark for check. */\n public readonly Changed$ = new Subject<void>();\n\n /**\n * The ordered tabs: channel tabs (left), then the Activity tab LAST when shown. The strip\n * right-aligns the Activity tab via a flex spacer, so this order also matches reading order.\n */\n public get Tabs(): RealtimeSurfaceTab[] {\n return this.showActivity\n ? [...this.channelTabs, RealtimeSurfaceTabsModel.activityTab]\n : [...this.channelTabs];\n }\n\n /** Whether the Activity tab is currently part of the strip. */\n public get IsActivityShown(): boolean {\n return this.showActivity;\n }\n\n /**\n * The currently focused tab. Resolves to the active key when it still exists, else falls\n * back to the Activity tab (when shown), else the first channel tab, else the Activity tab\n * definition (so a consumer always has SOMETHING to render even on an empty strip).\n */\n public get ActiveTab(): RealtimeSurfaceTab {\n const tabs = this.Tabs;\n return tabs.find(t => t.Key === this.ActiveKey)\n ?? tabs.find(t => t.Key === RealtimeSurfaceTabsModel.ActivityTabKey)\n ?? tabs[0]\n ?? RealtimeSurfaceTabsModel.activityTab;\n }\n\n /**\n * Shows or hides the gated Activity tab. Turning it ON when an empty strip was implicitly\n * focusing Activity keeps focus on Activity; turning it OFF while it was focused falls\n * focus back to the first channel tab (if any). No-op (no emission) when unchanged.\n *\n * @param show Whether ≥1 agent run has occurred (or review mode) — the gate.\n */\n public SetShowActivityTab(show: boolean): void {\n if (this.showActivity === show) {\n return;\n }\n this.showActivity = show;\n if (!show && this.ActiveKey === RealtimeSurfaceTabsModel.ActivityTabKey) {\n this.ActiveKey = this.channelTabs[0]?.Key ?? RealtimeSurfaceTabsModel.ActivityTabKey;\n }\n this.Changed$.next();\n }\n\n /**\n * Registers (or updates) an interactive-channel tab. Re-registering an existing key\n * replaces its title/icon/color/plugin/content in place (this is how a placeholder\n * upgrades to the real surface once the channel comes online). New channel tabs join the\n * left cluster in registration order. A registration without an explicit {@link\n * RealtimeChannelTabRegistration.Color} gets a deterministic color from its key.\n *\n * @param registration The channel tab registration.\n * @returns The (new or updated) tab.\n */\n public RegisterChannelTab(registration: RealtimeChannelTabRegistration): RealtimeSurfaceTab {\n const tab: RealtimeSurfaceTab = {\n Key: registration.Key,\n Title: registration.Title,\n Icon: registration.Icon,\n Kind: 'channel',\n Color: registration.Color ?? ChannelTabColor(registration.Key),\n Data: { Plugin: registration.Plugin, Content: registration.Content }\n };\n const idx = this.channelTabs.findIndex(t => t.Key === registration.Key);\n if (idx >= 0) {\n const next = [...this.channelTabs];\n next[idx] = tab;\n this.channelTabs = next;\n } else {\n this.channelTabs = [...this.channelTabs, tab];\n }\n if (registration.Focus) {\n this.ActiveKey = tab.Key;\n }\n this.Changed$.next();\n return tab;\n }\n\n /** Focuses the tab with `key` (no-op when it doesn't exist or is already active). */\n public Focus(key: string): void {\n if (!this.Tabs.some(t => t.Key === key) || this.ActiveKey === key) {\n return;\n }\n this.ActiveKey = key;\n this.Changed$.next();\n }\n\n /**\n * Marks the tab with `key` as the {@link FlashKey} (the brief \"just arrived\" highlight)\n * WITHOUT changing focus — used by the auto-reveal path when the agent first acts on a\n * channel, so the user's eye lands on the tab that just came alive. No-op for unknown\n * keys; the owning component clears it after a beat via {@link ClearFlash}.\n */\n public FlashTab(key: string): void {\n if (this.FlashKey === key || !this.Tabs.some(t => t.Key === key)) {\n return;\n }\n this.FlashKey = key;\n this.Changed$.next();\n }\n\n /**\n * Removes the channel tab with `key`. Rules:\n * - the Activity tab is IRREMOVABLE — removing it is a no-op;\n * - an unknown key is a no-op (returns `false`);\n * - when the removed tab was focused, focus falls back to the Activity tab (if shown),\n * else the first remaining channel tab;\n * - a pending flash on the removed tab is cleaned up so the highlight can't dangle.\n *\n * @param key The tab key to remove.\n * @returns `true` when a tab was removed.\n */\n public RemoveTab(key: string): boolean {\n if (key === RealtimeSurfaceTabsModel.ActivityTabKey || !this.channelTabs.some(t => t.Key === key)) {\n return false;\n }\n this.channelTabs = this.channelTabs.filter(t => t.Key !== key);\n if (this.ActiveKey === key) {\n this.ActiveKey = this.showActivity\n ? RealtimeSurfaceTabsModel.ActivityTabKey\n : (this.channelTabs[0]?.Key ?? RealtimeSurfaceTabsModel.ActivityTabKey);\n }\n if (this.FlashKey === key) {\n this.FlashKey = null;\n }\n this.Changed$.next();\n return true;\n }\n\n /** Clears the transient flash highlight (called by the component after a beat). */\n public ClearFlash(): void {\n if (this.FlashKey !== null) {\n this.FlashKey = null;\n this.Changed$.next();\n }\n }\n}\n\n/**\n * Pure decision helper for the REVIEW→LIVE continuation edge: should the overlay REMOVE the\n * review-registered (template-based, read-only) Whiteboard tab?\n *\n * Yes only when ALL hold:\n * - a live session is active (the channel set emission belongs to a real session start, not\n * the initial/teardown `[]` replay);\n * - review mode actually registered a whiteboard tab (otherwise there is nothing stale);\n * - the live session's resolved channel set has NO Whiteboard channel — when it HAS one, the\n * live plugin re-registers the same tab key and upgrades the pane in place instead.\n *\n * Kept framework-free (like the model) so the rule is unit-testable in isolation.\n */\nexport function ShouldRemoveReviewWhiteboardTab(\n liveSessionActive: boolean,\n reviewWhiteboardTabRegistered: boolean,\n liveChannels: ReadonlyArray<{ ChannelName: string }>\n): boolean {\n if (!liveSessionActive || !reviewWhiteboardTabRegistered) {\n return false;\n }\n return !liveChannels.some(c => c.ChannelName?.trim().toLowerCase() === 'whiteboard');\n}\n"]}
|
|
@@ -156,35 +156,35 @@ export declare const DEFAULT_REALTIME_UI_INPUTS: Required<RealtimeUiInputs>;
|
|
|
156
156
|
*/
|
|
157
157
|
export interface RealtimeUiSignals {
|
|
158
158
|
/** Current width of the widget's container, in px (from a `ResizeObserver`). */
|
|
159
|
-
|
|
159
|
+
ContainerWidthPx: number;
|
|
160
160
|
/**
|
|
161
161
|
* Has the user revealed text this session? (i.e. tapped "show the
|
|
162
162
|
* conversation" / engaged the composer — disclosure level ≥ 1.) This is the
|
|
163
163
|
* intent half of the auto orb↔console rule.
|
|
164
164
|
*/
|
|
165
|
-
|
|
165
|
+
TextRevealed: boolean;
|
|
166
166
|
/** Disclosure model says a transcript may be shown. */
|
|
167
|
-
|
|
167
|
+
DisclosureShowThread: boolean;
|
|
168
168
|
/** Disclosure model says the composer/text dock may be shown. */
|
|
169
|
-
|
|
169
|
+
DisclosureShowComposer: boolean;
|
|
170
170
|
/** Disclosure model says a surface panel may be shown. */
|
|
171
|
-
|
|
171
|
+
DisclosureShowPanel: boolean;
|
|
172
172
|
/** Disclosure model says the gear/settings menu may be shown. */
|
|
173
|
-
|
|
173
|
+
DisclosureShowGear: boolean;
|
|
174
174
|
/** A surface/channel actually exists to populate the panel. */
|
|
175
|
-
|
|
175
|
+
SurfacePanelEarned: boolean;
|
|
176
176
|
/** ≥ 1 interactive channel is active. */
|
|
177
177
|
hasChannels: boolean;
|
|
178
178
|
/** ≥ 1 delegation/activity has occurred (Activity rail has content). */
|
|
179
|
-
|
|
179
|
+
HasActivity: boolean;
|
|
180
180
|
/** Per-session developer mode is on. */
|
|
181
|
-
|
|
181
|
+
DevMode: boolean;
|
|
182
182
|
/** The widget is reviewing a past (recorded) session, not a live call. */
|
|
183
|
-
|
|
183
|
+
IsReviewing: boolean;
|
|
184
184
|
/** A single channel surface is maximized (focus mode); the main column is hidden. */
|
|
185
185
|
channelFocus: boolean;
|
|
186
186
|
/** Current connection lifecycle state. */
|
|
187
|
-
|
|
187
|
+
ConnectionState: RealtimeUiConnectionState;
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* The resolved, render-ready view-model. Every field is a final boolean (or the
|
|
@@ -266,5 +266,7 @@ export declare const DEFAULT_REALTIME_UI_SIGNALS: RealtimeUiSignals;
|
|
|
266
266
|
* resolveRealtimeUi({ chrome: 'auto', consoleBreakpointPx: 480 }, wideSignals);
|
|
267
267
|
* ```
|
|
268
268
|
*/
|
|
269
|
+
export declare function ResolveRealtimeUi(inputs: RealtimeUiInputs | null | undefined, signals: RealtimeUiSignals): ResolvedRealtimeUi;
|
|
270
|
+
/** @deprecated Use {@link ResolveRealtimeUi}. */
|
|
269
271
|
export declare function resolveRealtimeUi(inputs: RealtimeUiInputs | null | undefined, signals: RealtimeUiSignals): ResolvedRealtimeUi;
|
|
270
272
|
//# sourceMappingURL=realtime-ui-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-ui-config.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-ui-config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"realtime-ui-config.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-ui-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,19 +84,19 @@ export const DEFAULT_REALTIME_UI_INPUTS = {
|
|
|
84
84
|
* runs with real signals. Never read `this` to build the first value.
|
|
85
85
|
*/
|
|
86
86
|
export const DEFAULT_REALTIME_UI_SIGNALS = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
ContainerWidthPx: 0,
|
|
88
|
+
TextRevealed: false,
|
|
89
|
+
DisclosureShowThread: false,
|
|
90
|
+
DisclosureShowComposer: false,
|
|
91
|
+
DisclosureShowPanel: false,
|
|
92
|
+
DisclosureShowGear: false,
|
|
93
|
+
SurfacePanelEarned: false,
|
|
94
94
|
hasChannels: false,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
HasActivity: false,
|
|
96
|
+
DevMode: false,
|
|
97
|
+
IsReviewing: false,
|
|
98
98
|
channelFocus: false,
|
|
99
|
-
|
|
99
|
+
ConnectionState: 'connecting',
|
|
100
100
|
};
|
|
101
101
|
/**
|
|
102
102
|
* Resolve the consumer config + live signals into a render-ready view-model.
|
|
@@ -126,22 +126,22 @@ export const DEFAULT_REALTIME_UI_SIGNALS = {
|
|
|
126
126
|
* resolveRealtimeUi({ chrome: 'auto', consoleBreakpointPx: 480 }, wideSignals);
|
|
127
127
|
* ```
|
|
128
128
|
*/
|
|
129
|
-
export function
|
|
129
|
+
export function ResolveRealtimeUi(inputs, signals) {
|
|
130
130
|
const cfg = { ...DEFAULT_REALTIME_UI_INPUTS, ...(inputs ?? {}) };
|
|
131
|
-
const connecting = signals.
|
|
131
|
+
const connecting = signals.ConnectionState === 'connecting';
|
|
132
132
|
const allowTextReveal = cfg.allowTextReveal;
|
|
133
133
|
const chrome = resolveChrome(cfg, signals, allowTextReveal);
|
|
134
134
|
const isConsole = chrome === 'console';
|
|
135
|
-
const compact = cfg.compact || signals.
|
|
135
|
+
const compact = cfg.compact || signals.ContainerWidthPx < cfg.consoleBreakpointPx;
|
|
136
136
|
// The transcript shows when the user has EXPLICITLY revealed text this session
|
|
137
137
|
// (`textRevealed`), OR we're in a console (consoles always carry the thread), OR we're
|
|
138
138
|
// reviewing a recording. We deliberately do NOT consult the disclosure ratchet here: a
|
|
139
139
|
// power user with a high base level still opens to the calm orb, exactly like the historical
|
|
140
140
|
// `ShowHero = !ShowCaptions` behaviour — "keep the orb until the user asks for text".
|
|
141
|
-
const showThread = allowTextReveal && (signals.
|
|
141
|
+
const showThread = allowTextReveal && (signals.TextRevealed || isConsole || signals.IsReviewing);
|
|
142
142
|
// The hero orb owns the surface in orb chrome (and there's nothing else to show).
|
|
143
143
|
const showHero = chrome === 'orb' && !showThread;
|
|
144
|
-
const showComposer = isConsole && allowTextReveal && signals.
|
|
144
|
+
const showComposer = isConsole && allowTextReveal && signals.DisclosureShowComposer && !signals.IsReviewing;
|
|
145
145
|
// The surface/Details panel opens ON DEMAND when earned (the Details peek, the agent's
|
|
146
146
|
// OpenSurfacePanel, content auto-reveal — all set surfacePanelEarned). It is an INDEPENDENT
|
|
147
147
|
// right-hand peek that rides ALONGSIDE whatever the main column shows — it must NOT require the
|
|
@@ -157,11 +157,11 @@ export function resolveRealtimeUi(inputs, signals) {
|
|
|
157
157
|
// beside the orb. So we keep only the ROOM half: the panel shows when earned and either the chrome
|
|
158
158
|
// is already a console (incl. review / forced-console at any width) OR the container is at least as
|
|
159
159
|
// wide as the console breakpoint — never in a cramped narrow overlay, and never dependent on text.
|
|
160
|
-
const roomForSurfacePanel = isConsole || signals.
|
|
161
|
-
const showSurfacePanel = cfg.showSurfacePanel && signals.
|
|
162
|
-
const showActivityTab = cfg.showActivityRail && (signals.
|
|
160
|
+
const roomForSurfacePanel = isConsole || signals.ContainerWidthPx >= cfg.consoleBreakpointPx;
|
|
161
|
+
const showSurfacePanel = cfg.showSurfacePanel && signals.SurfacePanelEarned && !signals.channelFocus && roomForSurfacePanel;
|
|
162
|
+
const showActivityTab = cfg.showActivityRail && (signals.HasActivity || signals.IsReviewing) && isConsole;
|
|
163
163
|
const showChannelStrip = cfg.showChannels && signals.hasChannels && isConsole && !signals.channelFocus;
|
|
164
|
-
const showGear = signals.
|
|
164
|
+
const showGear = signals.DisclosureShowGear || isConsole;
|
|
165
165
|
return {
|
|
166
166
|
chrome,
|
|
167
167
|
compact,
|
|
@@ -175,14 +175,18 @@ export function resolveRealtimeUi(inputs, signals) {
|
|
|
175
175
|
showCaptionsControl: cfg.showCaptionsControl,
|
|
176
176
|
showDensityPicker: cfg.showDensityPicker && showGear,
|
|
177
177
|
showGear,
|
|
178
|
-
showDevLinks: cfg.showDevLinks && signals.
|
|
179
|
-
showMinimize: cfg.showMinimize && !signals.
|
|
178
|
+
showDevLinks: cfg.showDevLinks && signals.DevMode,
|
|
179
|
+
showMinimize: cfg.showMinimize && !signals.IsReviewing,
|
|
180
180
|
showEnd: cfg.showEnd,
|
|
181
181
|
allowResize: cfg.allowResize && showSurfacePanel,
|
|
182
182
|
allowTextReveal,
|
|
183
183
|
autoHideControls: cfg.autoHideControls && chrome === 'orb',
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
|
+
/** @deprecated Use {@link ResolveRealtimeUi}. */
|
|
187
|
+
export function resolveRealtimeUi(inputs, signals) {
|
|
188
|
+
return ResolveRealtimeUi(inputs, signals);
|
|
189
|
+
}
|
|
186
190
|
/**
|
|
187
191
|
* Decide the effective chrome. Forced modes win outright; `'auto'` graduates to a
|
|
188
192
|
* console only when there's both **room** (width ≥ breakpoint) and **intent**
|
|
@@ -198,7 +202,7 @@ function resolveChrome(cfg, signals, allowTextReveal) {
|
|
|
198
202
|
return 'console';
|
|
199
203
|
}
|
|
200
204
|
// auto
|
|
201
|
-
if (signals.
|
|
205
|
+
if (signals.IsReviewing) {
|
|
202
206
|
return 'console';
|
|
203
207
|
}
|
|
204
208
|
if (!allowTextReveal) {
|
|
@@ -206,7 +210,7 @@ function resolveChrome(cfg, signals, allowTextReveal) {
|
|
|
206
210
|
}
|
|
207
211
|
// Intent is the USER explicitly revealing text this session — NOT the disclosure ratchet.
|
|
208
212
|
// Wider-alone keeps the orb; a power user who hasn't asked for text keeps the orb too.
|
|
209
|
-
const hasRoom = signals.
|
|
210
|
-
return hasRoom && signals.
|
|
213
|
+
const hasRoom = signals.ContainerWidthPx >= cfg.consoleBreakpointPx;
|
|
214
|
+
return hasRoom && signals.TextRevealed ? 'console' : 'orb';
|
|
211
215
|
}
|
|
212
216
|
//# sourceMappingURL=realtime-ui-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-ui-config.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-ui-config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Declarative UI configuration for the realtime voice widget.\n *\n * The realtime widget historically decided *what to show* from an internal\n * \"disclosure ratchet\" ({@link import('./realtime-disclosure').RealtimeDisclosureModel})\n * plus a handful of scattered getters. That made it impossible for a host\n * (the chat overlay, a full-screen route, an embedded demo surface, a kiosk,\n * a mobile sheet…) to tailor the surface to its context.\n *\n * This module introduces a single, pure, side-effect-free resolution step that\n * sits between three concerns:\n *\n * 1. **{@link RealtimeUiInputs}** — the *consumer's intent*. A flat bag of\n * `@Input()`-friendly feature switches (\"show the surface panel?\",\n * \"allow text?\", \"which chrome?\") with documented defaults. A host sets\n * only what it cares about; everything else stays on its sensible default,\n * so the widget behaves exactly as before when no inputs are provided.\n *\n * 2. **{@link RealtimeUiSignals}** — the *live runtime state*. Read-only facts\n * the widget already knows: how wide its container is, whether the user has\n * revealed text, what the disclosure model currently permits, whether a\n * surface/channel/activity exists, the connection state, review/focus modes.\n *\n * 3. **{@link ResolvedRealtimeUi}** — the *answer*. A fully-resolved, boolean\n * view-model the template binds to directly. No `&&` chains in the HTML; no\n * business logic in getters. One source of truth, trivially unit-testable.\n *\n * ## The headline behaviour: auto orb ↔ console\n *\n * The default {@link RealtimeChromeMode} is `'auto'`. In auto mode the widget is\n * a calm **orb** until *two* things are true at once:\n *\n * - the container is at least {@link RealtimeUiInputs.consoleBreakpointPx}\n * wide (there's room for a structured console), **and**\n * - the user has actually asked to see text (`textRevealed`), or the widget\n * is reviewing a past session (which always shows the transcript).\n *\n * In other words: **getting bigger is not enough — if the user hasn't asked for\n * text, we keep the orb.** This preserves the loved \"ambient by default\"\n * feeling while letting the experience graduate to a full command console the\n * moment it earns the space *and* the intent. Hosts that want to force one\n * chrome forever can pass `chrome: 'orb'` or `chrome: 'console'`.\n *\n * The resolver is intentionally framework-free (no Angular import) so it can be\n * unit-tested in isolation and reused by any host.\n *\n * @module realtime-ui-config\n */\n\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * Which visual chrome the widget renders.\n *\n * - `'orb'` — the ambient hero orb. Minimal controls; transcript/console hidden\n * unless the user reveals them. Best for narrow/overlay/mobile contexts.\n * - `'console'` — the structured command console: header, transcript, composer\n * dock, and (when room allows) the surface panel. Best for full-screen.\n * - `'auto'` — *(default)* start as an orb; graduate to a console when the\n * container is wide enough **and** the user has revealed text. See the module\n * docs for the exact rule.\n */\nexport type RealtimeChromeMode = 'orb' | 'console' | 'auto';\n\n/**\n * Identifies a control the user invoked. Emitted by the widget's `ControlInvoked`\n * output so a host can observe (or react to) any control — even one it has hidden\n * via inputs and re-rendered itself. Extend the union as new controls are added.\n */\nexport type RealtimeControlId =\n | 'mute'\n | 'captions'\n | 'type'\n | 'end'\n | 'minimize'\n | 'surface'\n | 'gear'\n | 'reveal-text'\n | 'pure-audio'\n | 'density';\n\n/**\n * The connection lifecycle states the widget cares about for layout decisions.\n * Mirrors the widget's runtime `RealtimeConnectionState`; duplicated as a string\n * union here so this module stays import-free of the Angular component.\n */\nexport type RealtimeUiConnectionState =\n | 'connecting'\n | 'listening'\n | 'speaking'\n | 'thinking'\n | 'idle'\n | 'error';\n\n/**\n * The default container width (px) at or above which `'auto'` chrome is *allowed*\n * to graduate from orb to console — provided the user has also revealed text.\n * Chosen so a typical 390px chat overlay stays an orb, while a half-screen or\n * full-screen surface can become a console. Override per-host via\n * {@link RealtimeUiInputs.consoleBreakpointPx}.\n */\nexport const REALTIME_CONSOLE_BREAKPOINT_DEFAULT = 560;\n\n/**\n * Consumer-facing configuration for the realtime widget — every field is a\n * declarative switch a host can set via an `@Input()`. **All fields are\n * optional**; omitted fields fall back to {@link DEFAULT_REALTIME_UI_INPUTS},\n * which reproduces the widget's historical behaviour. This is the surface that\n * lets the chat overlay slim the widget down, a full-screen route open it up,\n * and unexpected hosts (kiosks, demos, embeds) compose their own variant.\n *\n * A `false` here is a **hard disable** — it removes the affordance regardless of\n * what the disclosure model or runtime state would otherwise permit. A `true`\n * means \"allow it\"; the affordance still only appears when it's also *earned* by\n * the runtime (e.g. a surface panel only renders once a channel actually exists).\n */\nexport interface RealtimeUiInputs {\n /** Which chrome to render. Default `'auto'`. */\n chrome?: RealtimeChromeMode;\n /**\n * In `'auto'` chrome, the container width (px) at/above which the widget may\n * graduate to a console (still gated on text being revealed). Default\n * {@link REALTIME_CONSOLE_BREAKPOINT_DEFAULT}.\n */\n consoleBreakpointPx?: number;\n /**\n * Force compact spacing/typography regardless of size — useful for dense\n * mobile sheets. Default `false` (the widget infers compactness from width).\n */\n compact?: boolean;\n /**\n * Fade non-essential controls when the session is idle (orb chrome only), for\n * a cinematic feel. Default `true`.\n */\n autoHideControls?: boolean;\n /**\n * May the user reveal the transcript at all? When `false`, the widget is a\n * pure voice orb with no path to text (and therefore never graduates to a\n * console in `'auto'` mode). Default `true`.\n */\n allowTextReveal?: boolean;\n\n /** Show the captions toggle. Default `true`. */\n showCaptionsControl?: boolean;\n /** Show the density picker inside the gear menu. Default `true`. */\n showDensityPicker?: boolean;\n /** Show the minimize control (collapse the call without ending it). Default `true`. */\n showMinimize?: boolean;\n /** Show the end-call control. Default `true`. (Hosts that own their own end button may hide it.) */\n showEnd?: boolean;\n /**\n * Show the right-hand surface panel (whiteboard / browser / interactive\n * channels). Default `true`. Only renders in console chrome and once a panel\n * is actually earned.\n */\n showSurfacePanel?: boolean;\n /** Show the channel strip (active interactive channels). Default `true`. */\n showChannels?: boolean;\n /** Show the Activity rail/tab (delegations, artifacts timeline). Default `true`. */\n showActivityRail?: boolean;\n /**\n * Show developer affordances (\"open session / open run\" links, dev-only\n * panels). Default `true`, but still additionally gated by the per-session\n * dev-mode toggle, so this is a hard *ceiling*, not a force-on.\n */\n showDevLinks?: boolean;\n /** Allow drag-to-resize of the surface panel. Default `true`. */\n allowResize?: boolean;\n}\n\n/**\n * The complete, defaulted input set. Spreading this over a partial\n * {@link RealtimeUiInputs} yields a fully-populated config; the resolver does\n * exactly that, so callers never deal with `undefined`.\n */\nexport const DEFAULT_REALTIME_UI_INPUTS: Required<RealtimeUiInputs> = {\n chrome: 'auto',\n consoleBreakpointPx: REALTIME_CONSOLE_BREAKPOINT_DEFAULT,\n compact: false,\n autoHideControls: true,\n allowTextReveal: true,\n showCaptionsControl: true,\n showDensityPicker: true,\n showMinimize: true,\n showEnd: true,\n showSurfacePanel: true,\n showChannels: true,\n showActivityRail: true,\n showDevLinks: true,\n allowResize: true,\n};\n\n/**\n * Live runtime facts the widget feeds into the resolver. These are *observed*,\n * not configured — they come from the disclosure model, a `ResizeObserver`, and\n * the session/channel state. Pure data so the resolver stays testable.\n */\nexport interface RealtimeUiSignals {\n /** Current width of the widget's container, in px (from a `ResizeObserver`). */\n containerWidthPx: number;\n /**\n * Has the user revealed text this session? (i.e. tapped \"show the\n * conversation\" / engaged the composer — disclosure level ≥ 1.) This is the\n * intent half of the auto orb↔console rule.\n */\n textRevealed: boolean;\n /** Disclosure model says a transcript may be shown. */\n disclosureShowThread: boolean;\n /** Disclosure model says the composer/text dock may be shown. */\n disclosureShowComposer: boolean;\n /** Disclosure model says a surface panel may be shown. */\n disclosureShowPanel: boolean;\n /** Disclosure model says the gear/settings menu may be shown. */\n disclosureShowGear: boolean;\n /** A surface/channel actually exists to populate the panel. */\n surfacePanelEarned: boolean;\n /** ≥ 1 interactive channel is active. */\n hasChannels: boolean;\n /** ≥ 1 delegation/activity has occurred (Activity rail has content). */\n hasActivity: boolean;\n /** Per-session developer mode is on. */\n devMode: boolean;\n /** The widget is reviewing a past (recorded) session, not a live call. */\n isReviewing: boolean;\n /** A single channel surface is maximized (focus mode); the main column is hidden. */\n channelFocus: boolean;\n /** Current connection lifecycle state. */\n connectionState: RealtimeUiConnectionState;\n}\n\n/**\n * The resolved, render-ready view-model. Every field is a final boolean (or the\n * effective chrome) — the template binds straight to these with no further\n * logic. This is the single source of truth for \"what is on screen right now\".\n */\nexport interface ResolvedRealtimeUi {\n /** The effective chrome after resolving `'auto'`. */\n chrome: 'orb' | 'console';\n /** Whether compact spacing/typography applies. */\n compact: boolean;\n /** True while connecting — hosts can show a single, size-independent loader. */\n connecting: boolean;\n\n /** The big ambient hero orb is the primary surface. */\n showHero: boolean;\n /** The transcript/thread is visible. */\n showThread: boolean;\n /** The text composer dock is visible. */\n showComposer: boolean;\n /** The right-hand surface panel is visible. */\n showSurfacePanel: boolean;\n /** The Activity tab/rail is available. */\n showActivityTab: boolean;\n /** The channel strip is visible. */\n showChannelStrip: boolean;\n\n /** The captions toggle is available. */\n showCaptionsControl: boolean;\n /** The density picker is available (inside the gear). */\n showDensityPicker: boolean;\n /** The gear/settings affordance is available. */\n showGear: boolean;\n /** Developer links/panels are available. */\n showDevLinks: boolean;\n /** The minimize control is available. */\n showMinimize: boolean;\n /** The end-call control is available. */\n showEnd: boolean;\n\n /** The surface panel may be drag-resized. */\n allowResize: boolean;\n /** The user has a path to reveal text. */\n allowTextReveal: boolean;\n /** Non-essential controls should auto-fade when idle. */\n autoHideControls: boolean;\n}\n\n/**\n * A safe, dependency-free baseline {@link RealtimeUiSignals}. Use this to seed a\n * resolved view-model **before** the component's runtime dependencies (the\n * disclosure model, the session state, the `ResizeObserver`) exist — e.g. in a\n * field initializer. It describes a freshly-connecting widget at zero width with\n * nothing earned yet, so the first paint is a calm orb until `recomputeUi()`\n * runs with real signals. Never read `this` to build the first value.\n */\nexport const DEFAULT_REALTIME_UI_SIGNALS: RealtimeUiSignals = {\n containerWidthPx: 0,\n textRevealed: false,\n disclosureShowThread: false,\n disclosureShowComposer: false,\n disclosureShowPanel: false,\n disclosureShowGear: false,\n surfacePanelEarned: false,\n hasChannels: false,\n hasActivity: false,\n devMode: false,\n isReviewing: false,\n channelFocus: false,\n connectionState: 'connecting',\n};\n\n/**\n * Resolve the consumer config + live signals into a render-ready view-model.\n *\n * Pure and deterministic: same inputs ⇒ same output, no side effects, no clock,\n * no DOM. Safe to call on every change-detection pass and trivial to unit test.\n *\n * The resolution order is:\n * 1. fill defaults,\n * 2. decide the effective {@link RealtimeChromeMode} (the orb↔console rule),\n * 3. for each affordance, AND the consumer's switch with the runtime gate.\n *\n * @param inputs consumer configuration (partial; defaults fill the rest)\n * @param signals live runtime facts\n * @returns the fully-resolved {@link ResolvedRealtimeUi}\n *\n * @example Chat overlay (lean, ambient):\n * ```ts\n * resolveRealtimeUi(\n * { chrome: 'auto', showSurfacePanel: false, showActivityRail: false, showDevLinks: false },\n * signals\n * );\n * ```\n *\n * @example Full-screen route (rich console):\n * ```ts\n * resolveRealtimeUi({ chrome: 'auto', consoleBreakpointPx: 480 }, wideSignals);\n * ```\n */\nexport function resolveRealtimeUi(\n inputs: RealtimeUiInputs | null | undefined,\n signals: RealtimeUiSignals,\n): ResolvedRealtimeUi {\n const cfg: Required<RealtimeUiInputs> = { ...DEFAULT_REALTIME_UI_INPUTS, ...(inputs ?? {}) };\n\n const connecting = signals.connectionState === 'connecting';\n const allowTextReveal = cfg.allowTextReveal;\n const chrome = resolveChrome(cfg, signals, allowTextReveal);\n const isConsole = chrome === 'console';\n const compact = cfg.compact || signals.containerWidthPx < cfg.consoleBreakpointPx;\n\n // The transcript shows when the user has EXPLICITLY revealed text this session\n // (`textRevealed`), OR we're in a console (consoles always carry the thread), OR we're\n // reviewing a recording. We deliberately do NOT consult the disclosure ratchet here: a\n // power user with a high base level still opens to the calm orb, exactly like the historical\n // `ShowHero = !ShowCaptions` behaviour — \"keep the orb until the user asks for text\".\n const showThread = allowTextReveal && (signals.textRevealed || isConsole || signals.isReviewing);\n\n // The hero orb owns the surface in orb chrome (and there's nothing else to show).\n const showHero = chrome === 'orb' && !showThread;\n\n const showComposer = isConsole && allowTextReveal && signals.disclosureShowComposer && !signals.isReviewing;\n\n // The surface/Details panel opens ON DEMAND when earned (the Details peek, the agent's\n // OpenSurfacePanel, content auto-reveal — all set surfacePanelEarned). It is an INDEPENDENT\n // right-hand peek that rides ALONGSIDE whatever the main column shows — it must NOT require the\n // cross-session disclosure ratchet (disclosureShowPanel = SessionLevel >= 2), and it must NOT\n // require the user to have revealed text.\n //\n // It was previously gated on `isConsole`, which bundled TWO things: \"there's room\" (legitimate —\n // don't cram a side panel into a narrow overlay) AND \"the user revealed text\" (wrong for a peek).\n // The text-reveal coupling meant opening Details with captions OFF flipped the whole left column\n // from the hero orb to an empty transcript (the orb vanished), and toggling captions back off\n // yanked the panel out from under an open peek. The design intent (see the auto-reveal comment in\n // the overlay component: \"the left column stays exactly as it was, pure audio included\") is a peek\n // beside the orb. So we keep only the ROOM half: the panel shows when earned and either the chrome\n // is already a console (incl. review / forced-console at any width) OR the container is at least as\n // wide as the console breakpoint — never in a cramped narrow overlay, and never dependent on text.\n const roomForSurfacePanel = isConsole || signals.containerWidthPx >= cfg.consoleBreakpointPx;\n const showSurfacePanel =\n cfg.showSurfacePanel && signals.surfacePanelEarned && !signals.channelFocus && roomForSurfacePanel;\n\n const showActivityTab = cfg.showActivityRail && (signals.hasActivity || signals.isReviewing) && isConsole;\n\n const showChannelStrip = cfg.showChannels && signals.hasChannels && isConsole && !signals.channelFocus;\n\n const showGear = signals.disclosureShowGear || isConsole;\n\n return {\n chrome,\n compact,\n connecting,\n showHero,\n showThread,\n showComposer,\n showSurfacePanel,\n showActivityTab,\n showChannelStrip,\n showCaptionsControl: cfg.showCaptionsControl,\n showDensityPicker: cfg.showDensityPicker && showGear,\n showGear,\n showDevLinks: cfg.showDevLinks && signals.devMode,\n showMinimize: cfg.showMinimize && !signals.isReviewing,\n showEnd: cfg.showEnd,\n allowResize: cfg.allowResize && showSurfacePanel,\n allowTextReveal,\n autoHideControls: cfg.autoHideControls && chrome === 'orb',\n };\n}\n\n/**\n * Decide the effective chrome. Forced modes win outright; `'auto'` graduates to a\n * console only when there's both **room** (width ≥ breakpoint) and **intent**\n * (text revealed) — or when reviewing, which always wants the transcript.\n *\n * @internal\n */\nfunction resolveChrome(\n cfg: Required<RealtimeUiInputs>,\n signals: RealtimeUiSignals,\n allowTextReveal: boolean,\n): 'orb' | 'console' {\n if (cfg.chrome === 'orb') {\n return 'orb';\n }\n if (cfg.chrome === 'console') {\n return 'console';\n }\n // auto\n if (signals.isReviewing) {\n return 'console';\n }\n if (!allowTextReveal) {\n return 'orb';\n }\n // Intent is the USER explicitly revealing text this session — NOT the disclosure ratchet.\n // Wider-alone keeps the orb; a power user who hasn't asked for text keeps the orb too.\n const hasRoom = signals.containerWidthPx >= cfg.consoleBreakpointPx;\n return hasRoom && signals.textRevealed ? 'console' : 'orb';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-ui-config.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-ui-config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Declarative UI configuration for the realtime voice widget.\n *\n * The realtime widget historically decided *what to show* from an internal\n * \"disclosure ratchet\" ({@link import('./realtime-disclosure').RealtimeDisclosureModel})\n * plus a handful of scattered getters. That made it impossible for a host\n * (the chat overlay, a full-screen route, an embedded demo surface, a kiosk,\n * a mobile sheet…) to tailor the surface to its context.\n *\n * This module introduces a single, pure, side-effect-free resolution step that\n * sits between three concerns:\n *\n * 1. **{@link RealtimeUiInputs}** — the *consumer's intent*. A flat bag of\n * `@Input()`-friendly feature switches (\"show the surface panel?\",\n * \"allow text?\", \"which chrome?\") with documented defaults. A host sets\n * only what it cares about; everything else stays on its sensible default,\n * so the widget behaves exactly as before when no inputs are provided.\n *\n * 2. **{@link RealtimeUiSignals}** — the *live runtime state*. Read-only facts\n * the widget already knows: how wide its container is, whether the user has\n * revealed text, what the disclosure model currently permits, whether a\n * surface/channel/activity exists, the connection state, review/focus modes.\n *\n * 3. **{@link ResolvedRealtimeUi}** — the *answer*. A fully-resolved, boolean\n * view-model the template binds to directly. No `&&` chains in the HTML; no\n * business logic in getters. One source of truth, trivially unit-testable.\n *\n * ## The headline behaviour: auto orb ↔ console\n *\n * The default {@link RealtimeChromeMode} is `'auto'`. In auto mode the widget is\n * a calm **orb** until *two* things are true at once:\n *\n * - the container is at least {@link RealtimeUiInputs.consoleBreakpointPx}\n * wide (there's room for a structured console), **and**\n * - the user has actually asked to see text (`textRevealed`), or the widget\n * is reviewing a past session (which always shows the transcript).\n *\n * In other words: **getting bigger is not enough — if the user hasn't asked for\n * text, we keep the orb.** This preserves the loved \"ambient by default\"\n * feeling while letting the experience graduate to a full command console the\n * moment it earns the space *and* the intent. Hosts that want to force one\n * chrome forever can pass `chrome: 'orb'` or `chrome: 'console'`.\n *\n * The resolver is intentionally framework-free (no Angular import) so it can be\n * unit-tested in isolation and reused by any host.\n *\n * @module realtime-ui-config\n */\n\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * Which visual chrome the widget renders.\n *\n * - `'orb'` — the ambient hero orb. Minimal controls; transcript/console hidden\n * unless the user reveals them. Best for narrow/overlay/mobile contexts.\n * - `'console'` — the structured command console: header, transcript, composer\n * dock, and (when room allows) the surface panel. Best for full-screen.\n * - `'auto'` — *(default)* start as an orb; graduate to a console when the\n * container is wide enough **and** the user has revealed text. See the module\n * docs for the exact rule.\n */\nexport type RealtimeChromeMode = 'orb' | 'console' | 'auto';\n\n/**\n * Identifies a control the user invoked. Emitted by the widget's `ControlInvoked`\n * output so a host can observe (or react to) any control — even one it has hidden\n * via inputs and re-rendered itself. Extend the union as new controls are added.\n */\nexport type RealtimeControlId =\n | 'mute'\n | 'captions'\n | 'type'\n | 'end'\n | 'minimize'\n | 'surface'\n | 'gear'\n | 'reveal-text'\n | 'pure-audio'\n | 'density';\n\n/**\n * The connection lifecycle states the widget cares about for layout decisions.\n * Mirrors the widget's runtime `RealtimeConnectionState`; duplicated as a string\n * union here so this module stays import-free of the Angular component.\n */\nexport type RealtimeUiConnectionState =\n | 'connecting'\n | 'listening'\n | 'speaking'\n | 'thinking'\n | 'idle'\n | 'error';\n\n/**\n * The default container width (px) at or above which `'auto'` chrome is *allowed*\n * to graduate from orb to console — provided the user has also revealed text.\n * Chosen so a typical 390px chat overlay stays an orb, while a half-screen or\n * full-screen surface can become a console. Override per-host via\n * {@link RealtimeUiInputs.consoleBreakpointPx}.\n */\nexport const REALTIME_CONSOLE_BREAKPOINT_DEFAULT = 560;\n\n/**\n * Consumer-facing configuration for the realtime widget — every field is a\n * declarative switch a host can set via an `@Input()`. **All fields are\n * optional**; omitted fields fall back to {@link DEFAULT_REALTIME_UI_INPUTS},\n * which reproduces the widget's historical behaviour. This is the surface that\n * lets the chat overlay slim the widget down, a full-screen route open it up,\n * and unexpected hosts (kiosks, demos, embeds) compose their own variant.\n *\n * A `false` here is a **hard disable** — it removes the affordance regardless of\n * what the disclosure model or runtime state would otherwise permit. A `true`\n * means \"allow it\"; the affordance still only appears when it's also *earned* by\n * the runtime (e.g. a surface panel only renders once a channel actually exists).\n */\nexport interface RealtimeUiInputs {\n /** Which chrome to render. Default `'auto'`. */\n chrome?: RealtimeChromeMode; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * In `'auto'` chrome, the container width (px) at/above which the widget may\n * graduate to a console (still gated on text being revealed). Default\n * {@link REALTIME_CONSOLE_BREAKPOINT_DEFAULT}.\n */\n consoleBreakpointPx?: number; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * Force compact spacing/typography regardless of size — useful for dense\n * mobile sheets. Default `false` (the widget infers compactness from width).\n */\n compact?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * Fade non-essential controls when the session is idle (orb chrome only), for\n * a cinematic feel. Default `true`.\n */\n autoHideControls?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * May the user reveal the transcript at all? When `false`, the widget is a\n * pure voice orb with no path to text (and therefore never graduates to a\n * console in `'auto'` mode). Default `true`.\n */\n allowTextReveal?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /** Show the captions toggle. Default `true`. */\n showCaptionsControl?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Show the density picker inside the gear menu. Default `true`. */\n showDensityPicker?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Show the minimize control (collapse the call without ending it). Default `true`. */\n showMinimize?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Show the end-call control. Default `true`. (Hosts that own their own end button may hide it.) */\n showEnd?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * Show the right-hand surface panel (whiteboard / browser / interactive\n * channels). Default `true`. Only renders in console chrome and once a panel\n * is actually earned.\n */\n showSurfacePanel?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Show the channel strip (active interactive channels). Default `true`. */\n showChannels?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Show the Activity rail/tab (delegations, artifacts timeline). Default `true`. */\n showActivityRail?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /**\n * Show developer affordances (\"open session / open run\" links, dev-only\n * panels). Default `true`, but still additionally gated by the per-session\n * dev-mode toggle, so this is a hard *ceiling*, not a force-on.\n */\n showDevLinks?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Allow drag-to-resize of the surface panel. Default `true`. */\n allowResize?: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n}\n\n/**\n * The complete, defaulted input set. Spreading this over a partial\n * {@link RealtimeUiInputs} yields a fully-populated config; the resolver does\n * exactly that, so callers never deal with `undefined`.\n */\nexport const DEFAULT_REALTIME_UI_INPUTS: Required<RealtimeUiInputs> = {\n chrome: 'auto',\n consoleBreakpointPx: REALTIME_CONSOLE_BREAKPOINT_DEFAULT,\n compact: false,\n autoHideControls: true,\n allowTextReveal: true,\n showCaptionsControl: true,\n showDensityPicker: true,\n showMinimize: true,\n showEnd: true,\n showSurfacePanel: true,\n showChannels: true,\n showActivityRail: true,\n showDevLinks: true,\n allowResize: true,\n};\n\n/**\n * Live runtime facts the widget feeds into the resolver. These are *observed*,\n * not configured — they come from the disclosure model, a `ResizeObserver`, and\n * the session/channel state. Pure data so the resolver stays testable.\n */\nexport interface RealtimeUiSignals {\n /** Current width of the widget's container, in px (from a `ResizeObserver`). */\n ContainerWidthPx: number;\n /**\n * Has the user revealed text this session? (i.e. tapped \"show the\n * conversation\" / engaged the composer — disclosure level ≥ 1.) This is the\n * intent half of the auto orb↔console rule.\n */\n TextRevealed: boolean;\n /** Disclosure model says a transcript may be shown. */\n DisclosureShowThread: boolean;\n /** Disclosure model says the composer/text dock may be shown. */\n DisclosureShowComposer: boolean;\n /** Disclosure model says a surface panel may be shown. */\n DisclosureShowPanel: boolean;\n /** Disclosure model says the gear/settings menu may be shown. */\n DisclosureShowGear: boolean;\n /** A surface/channel actually exists to populate the panel. */\n SurfacePanelEarned: boolean;\n /** ≥ 1 interactive channel is active. */\n hasChannels: boolean; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** ≥ 1 delegation/activity has occurred (Activity rail has content). */\n HasActivity: boolean;\n /** Per-session developer mode is on. */\n DevMode: boolean;\n /** The widget is reviewing a past (recorded) session, not a live call. */\n IsReviewing: boolean;\n /** A single channel surface is maximized (focus mode); the main column is hidden. */\n channelFocus: boolean; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Current connection lifecycle state. */\n ConnectionState: RealtimeUiConnectionState;\n}\n\n/**\n * The resolved, render-ready view-model. Every field is a final boolean (or the\n * effective chrome) — the template binds straight to these with no further\n * logic. This is the single source of truth for \"what is on screen right now\".\n */\nexport interface ResolvedRealtimeUi {\n /** The effective chrome after resolving `'auto'`. */\n chrome: 'orb' | 'console'; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Whether compact spacing/typography applies. */\n compact: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** True while connecting — hosts can show a single, size-independent loader. */\n connecting: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /** The big ambient hero orb is the primary surface. */\n showHero: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The transcript/thread is visible. */\n showThread: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The text composer dock is visible. */\n showComposer: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The right-hand surface panel is visible. */\n showSurfacePanel: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The Activity tab/rail is available. */\n showActivityTab: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The channel strip is visible. */\n showChannelStrip: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /** The captions toggle is available. */\n showCaptionsControl: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The density picker is available (inside the gear). */\n showDensityPicker: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The gear/settings affordance is available. */\n showGear: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Developer links/panels are available. */\n showDevLinks: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The minimize control is available. */\n showMinimize: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The end-call control is available. */\n showEnd: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /** The surface panel may be drag-resized. */\n allowResize: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** The user has a path to reveal text. */\n allowTextReveal: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n /** Non-essential controls should auto-fade when idle. */\n autoHideControls: boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n}\n\n/**\n * A safe, dependency-free baseline {@link RealtimeUiSignals}. Use this to seed a\n * resolved view-model **before** the component's runtime dependencies (the\n * disclosure model, the session state, the `ResizeObserver`) exist — e.g. in a\n * field initializer. It describes a freshly-connecting widget at zero width with\n * nothing earned yet, so the first paint is a calm orb until `recomputeUi()`\n * runs with real signals. Never read `this` to build the first value.\n */\nexport const DEFAULT_REALTIME_UI_SIGNALS: RealtimeUiSignals = {\n ContainerWidthPx: 0,\n TextRevealed: false,\n DisclosureShowThread: false,\n DisclosureShowComposer: false,\n DisclosureShowPanel: false,\n DisclosureShowGear: false,\n SurfacePanelEarned: false,\n hasChannels: false,\n HasActivity: false,\n DevMode: false,\n IsReviewing: false,\n channelFocus: false,\n ConnectionState: 'connecting',\n};\n\n/**\n * Resolve the consumer config + live signals into a render-ready view-model.\n *\n * Pure and deterministic: same inputs ⇒ same output, no side effects, no clock,\n * no DOM. Safe to call on every change-detection pass and trivial to unit test.\n *\n * The resolution order is:\n * 1. fill defaults,\n * 2. decide the effective {@link RealtimeChromeMode} (the orb↔console rule),\n * 3. for each affordance, AND the consumer's switch with the runtime gate.\n *\n * @param inputs consumer configuration (partial; defaults fill the rest)\n * @param signals live runtime facts\n * @returns the fully-resolved {@link ResolvedRealtimeUi}\n *\n * @example Chat overlay (lean, ambient):\n * ```ts\n * resolveRealtimeUi(\n * { chrome: 'auto', showSurfacePanel: false, showActivityRail: false, showDevLinks: false },\n * signals\n * );\n * ```\n *\n * @example Full-screen route (rich console):\n * ```ts\n * resolveRealtimeUi({ chrome: 'auto', consoleBreakpointPx: 480 }, wideSignals);\n * ```\n */\nexport function ResolveRealtimeUi(\n inputs: RealtimeUiInputs | null | undefined,\n signals: RealtimeUiSignals,\n): ResolvedRealtimeUi {\n const cfg: Required<RealtimeUiInputs> = { ...DEFAULT_REALTIME_UI_INPUTS, ...(inputs ?? {}) };\n\n const connecting = signals.ConnectionState === 'connecting';\n const allowTextReveal = cfg.allowTextReveal;\n const chrome = resolveChrome(cfg, signals, allowTextReveal);\n const isConsole = chrome === 'console';\n const compact = cfg.compact || signals.ContainerWidthPx < cfg.consoleBreakpointPx;\n\n // The transcript shows when the user has EXPLICITLY revealed text this session\n // (`textRevealed`), OR we're in a console (consoles always carry the thread), OR we're\n // reviewing a recording. We deliberately do NOT consult the disclosure ratchet here: a\n // power user with a high base level still opens to the calm orb, exactly like the historical\n // `ShowHero = !ShowCaptions` behaviour — \"keep the orb until the user asks for text\".\n const showThread = allowTextReveal && (signals.TextRevealed || isConsole || signals.IsReviewing);\n\n // The hero orb owns the surface in orb chrome (and there's nothing else to show).\n const showHero = chrome === 'orb' && !showThread;\n\n const showComposer = isConsole && allowTextReveal && signals.DisclosureShowComposer && !signals.IsReviewing;\n\n // The surface/Details panel opens ON DEMAND when earned (the Details peek, the agent's\n // OpenSurfacePanel, content auto-reveal — all set surfacePanelEarned). It is an INDEPENDENT\n // right-hand peek that rides ALONGSIDE whatever the main column shows — it must NOT require the\n // cross-session disclosure ratchet (disclosureShowPanel = SessionLevel >= 2), and it must NOT\n // require the user to have revealed text.\n //\n // It was previously gated on `isConsole`, which bundled TWO things: \"there's room\" (legitimate —\n // don't cram a side panel into a narrow overlay) AND \"the user revealed text\" (wrong for a peek).\n // The text-reveal coupling meant opening Details with captions OFF flipped the whole left column\n // from the hero orb to an empty transcript (the orb vanished), and toggling captions back off\n // yanked the panel out from under an open peek. The design intent (see the auto-reveal comment in\n // the overlay component: \"the left column stays exactly as it was, pure audio included\") is a peek\n // beside the orb. So we keep only the ROOM half: the panel shows when earned and either the chrome\n // is already a console (incl. review / forced-console at any width) OR the container is at least as\n // wide as the console breakpoint — never in a cramped narrow overlay, and never dependent on text.\n const roomForSurfacePanel = isConsole || signals.ContainerWidthPx >= cfg.consoleBreakpointPx;\n const showSurfacePanel =\n cfg.showSurfacePanel && signals.SurfacePanelEarned && !signals.channelFocus && roomForSurfacePanel;\n\n const showActivityTab = cfg.showActivityRail && (signals.HasActivity || signals.IsReviewing) && isConsole;\n\n const showChannelStrip = cfg.showChannels && signals.hasChannels && isConsole && !signals.channelFocus;\n\n const showGear = signals.DisclosureShowGear || isConsole;\n\n return {\n chrome,\n compact,\n connecting,\n showHero,\n showThread,\n showComposer,\n showSurfacePanel,\n showActivityTab,\n showChannelStrip,\n showCaptionsControl: cfg.showCaptionsControl,\n showDensityPicker: cfg.showDensityPicker && showGear,\n showGear,\n showDevLinks: cfg.showDevLinks && signals.DevMode,\n showMinimize: cfg.showMinimize && !signals.IsReviewing,\n showEnd: cfg.showEnd,\n allowResize: cfg.allowResize && showSurfacePanel,\n allowTextReveal,\n autoHideControls: cfg.autoHideControls && chrome === 'orb',\n };\n}\n\n/** @deprecated Use {@link ResolveRealtimeUi}. */\nexport function resolveRealtimeUi(\n inputs: RealtimeUiInputs | null | undefined,\n signals: RealtimeUiSignals,\n): ResolvedRealtimeUi {\n return ResolveRealtimeUi(inputs, signals);\n}\n\n/**\n * Decide the effective chrome. Forced modes win outright; `'auto'` graduates to a\n * console only when there's both **room** (width ≥ breakpoint) and **intent**\n * (text revealed) — or when reviewing, which always wants the transcript.\n *\n * @internal\n */\nfunction resolveChrome(\n cfg: Required<RealtimeUiInputs>,\n signals: RealtimeUiSignals,\n allowTextReveal: boolean,\n): 'orb' | 'console' {\n if (cfg.chrome === 'orb') {\n return 'orb';\n }\n if (cfg.chrome === 'console') {\n return 'console';\n }\n // auto\n if (signals.IsReviewing) {\n return 'console';\n }\n if (!allowTextReveal) {\n return 'orb';\n }\n // Intent is the USER explicitly revealing text this session — NOT the disclosure ratchet.\n // Wider-alone keeps the orb; a power user who hasn't asked for text keeps the orb too.\n const hasRoom = signals.ContainerWidthPx >= cfg.consoleBreakpointPx;\n return hasRoom && signals.TextRevealed ? 'console' : 'orb';\n}\n"]}
|
|
@@ -7,7 +7,7 @@ import { RealtimeWhiteboardHostComponent, WhiteboardState } from '@memberjunctio
|
|
|
7
7
|
* Asynchronously rasterizes an SVG string to a JPEG base64 string (without the `data:image/jpeg;base64,` prefix)
|
|
8
8
|
* using an offscreen canvas. Returns null in non-DOM environments or when rendering fails.
|
|
9
9
|
*/
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function RasterizeSvgToJpegBase64(svg: string, width?: number, height?: number): Promise<string | null>;
|
|
11
11
|
/**
|
|
12
12
|
* Per-widget throttle window for AMBIENT interaction context notes: at most one note per
|
|
13
13
|
* widget per this many ms — within the window the LATEST summary wins (chatty widgets
|
|
@@ -165,4 +165,6 @@ export declare class RealtimeWhiteboardChannel extends BaseRealtimeChannelClient
|
|
|
165
165
|
* Called by `RealtimeSessionService` alongside the realtime-client driver Load calls.
|
|
166
166
|
*/
|
|
167
167
|
export declare function LoadRealtimeWhiteboardChannel(): void;
|
|
168
|
+
/** @deprecated Use {@link RasterizeSvgToJpegBase64}. */
|
|
169
|
+
export declare function rasterizeSvgToJpegBase64(svg: string, width?: number, height?: number): Promise<string | null>;
|
|
168
170
|
//# sourceMappingURL=whiteboard-channel.d.ts.map
|