@memberjunction/ng-conversations 5.35.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +62 -2
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +300 -24
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts +31 -0
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/dialogs/rating-dialog.component.js +290 -0
- package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -0
- package/dist/lib/components/mention/mention-editor.component.d.ts +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +1 -0
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts +43 -18
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +235 -193
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +1 -1
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +7 -1
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +28 -3
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.js +20 -20
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +73 -5
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +202 -37
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +24 -23
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +4 -0
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +0 -1
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/dialog.service.d.ts +24 -0
- package/dist/lib/services/dialog.service.d.ts.map +1 -1
- package/dist/lib/services/dialog.service.js +45 -0
- package/dist/lib/services/dialog.service.js.map +1 -1
- package/package.json +22 -22
|
@@ -40,6 +40,14 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
40
40
|
private static readonly MIN_HEIGHT;
|
|
41
41
|
private static readonly MAX_WIDTH;
|
|
42
42
|
private static readonly MAX_HEIGHT;
|
|
43
|
+
/** Default `bottom` for both bubble and panel (matches CSS 1.5rem). */
|
|
44
|
+
private static readonly BASE_BOTTOM_PX;
|
|
45
|
+
/** Floating bubble diameter in pixels (matches CSS 3.5rem). */
|
|
46
|
+
private static readonly BUBBLE_SIZE_PX;
|
|
47
|
+
/** Minimum gap to keep between the overlay and the viewport top edge. */
|
|
48
|
+
private static readonly VIEWPORT_TOP_PADDING_PX;
|
|
49
|
+
/** Mousedown-to-mousemove distance that promotes a click into a drag. */
|
|
50
|
+
private static readonly BUBBLE_DRAG_THRESHOLD_PX;
|
|
43
51
|
/** Controls external visibility (e.g., parent hides overlay on chat route) */
|
|
44
52
|
private _IsVisible;
|
|
45
53
|
set IsVisible(value: boolean);
|
|
@@ -52,6 +60,13 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
52
60
|
AppContext: Record<string, unknown> | null;
|
|
53
61
|
/** Greeting message shown in the empty state when no conversation is active */
|
|
54
62
|
EmptyStateGreeting: string;
|
|
63
|
+
/**
|
|
64
|
+
* Pixels reserved at the top of the viewport that the bubble and panel must not
|
|
65
|
+
* cross. Set this from the host app to the height of any fixed top chrome (e.g.
|
|
66
|
+
* Explorer's shell-header). Defaults to 0 — generic apps without top chrome
|
|
67
|
+
* keep the full viewport available.
|
|
68
|
+
*/
|
|
69
|
+
TopBoundaryPx: number;
|
|
55
70
|
/** Emitted when the overlay visibility changes */
|
|
56
71
|
VisibilityChanged: EventEmitter<ChatOverlayState>;
|
|
57
72
|
/** Emitted when a tool finishes executing in the agent client */
|
|
@@ -74,6 +89,20 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
74
89
|
/** Panel dimensions (persisted via UserInfoEngine) */
|
|
75
90
|
PanelWidth: number;
|
|
76
91
|
PanelHeight: number;
|
|
92
|
+
/**
|
|
93
|
+
* Pixels the floating bubble has been dragged up from its default
|
|
94
|
+
* bottom-right corner position. Always >= 0; clamping at render time
|
|
95
|
+
* keeps the bubble on-screen even after a viewport resize.
|
|
96
|
+
*/
|
|
97
|
+
BubbleOffsetY: number;
|
|
98
|
+
/** True while the user is actively dragging the bubble; used to swap cursor + suppress click. */
|
|
99
|
+
IsBubbleDragging: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* True from mousedown until mouseup on the bubble, regardless of whether the
|
|
102
|
+
* gesture became a drag. Used to give immediate "I'm being held" feedback so
|
|
103
|
+
* the user can see drag is possible even before crossing the move threshold.
|
|
104
|
+
*/
|
|
105
|
+
IsBubblePressed: boolean;
|
|
77
106
|
/** Active conversation ID managed locally */
|
|
78
107
|
private _conversationId;
|
|
79
108
|
get ConversationId(): string | null;
|
|
@@ -92,6 +121,15 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
92
121
|
private resizeStartY;
|
|
93
122
|
private resizeStartWidth;
|
|
94
123
|
private resizeStartHeight;
|
|
124
|
+
/** Bubble drag state */
|
|
125
|
+
private bubbleDragStartMouseY;
|
|
126
|
+
private bubbleDragStartOffset;
|
|
127
|
+
/** True once the pointer has moved past BUBBLE_DRAG_THRESHOLD_PX; suppresses the implicit click. */
|
|
128
|
+
private bubbleDragMoved;
|
|
129
|
+
/** ID of the pointer currently driving the drag — guards against multi-touch confusion. */
|
|
130
|
+
private activeBubblePointerId;
|
|
131
|
+
/** Element that captured the pointer; needed to release capture on end/cancel. */
|
|
132
|
+
private bubbleCaptureTarget;
|
|
95
133
|
ngOnInit(): void;
|
|
96
134
|
ngOnDestroy(): void;
|
|
97
135
|
/** Toggle between collapsed and expanded states */
|
|
@@ -138,12 +176,42 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
138
176
|
private removeResizeListeners;
|
|
139
177
|
private clampWidth;
|
|
140
178
|
private clampHeight;
|
|
179
|
+
/**
|
|
180
|
+
* Start tracking a potential bubble drag. We don't enter drag mode until
|
|
181
|
+
* the pointer moves past BUBBLE_DRAG_THRESHOLD_PX — releasing before that
|
|
182
|
+
* threshold is treated as a normal click/tap and opens the chat (via Toggle()).
|
|
183
|
+
*
|
|
184
|
+
* Pointer Events (not mousedown) so the same code path serves desktop mouse,
|
|
185
|
+
* touch on phones/tablets, and pen input. setPointerCapture keeps the gesture
|
|
186
|
+
* tied to this element even if the finger or cursor strays off the bubble.
|
|
187
|
+
*/
|
|
188
|
+
OnBubblePointerDown(event: PointerEvent): void;
|
|
189
|
+
private onBubbleDragMove;
|
|
190
|
+
private onBubbleDragEnd;
|
|
191
|
+
private removeBubbleDragListeners;
|
|
192
|
+
/**
|
|
193
|
+
* Reserved space at the top of the viewport — host-supplied chrome plus
|
|
194
|
+
* the padding gap we always keep above the bubble/panel.
|
|
195
|
+
*/
|
|
196
|
+
private get topReservedPx();
|
|
197
|
+
/** Clamp the offset so the bubble stays fully visible below the top boundary. */
|
|
198
|
+
private clampBubbleOffsetY;
|
|
199
|
+
/** Effective `bottom` (px) for the floating bubble, clamped to the current viewport. */
|
|
200
|
+
get BubbleBottomPx(): number;
|
|
201
|
+
/**
|
|
202
|
+
* Effective `bottom` (px) for the expanded panel. Anchors to the bubble's
|
|
203
|
+
* current bottom edge so the panel grows up from where the user parked the
|
|
204
|
+
* bubble, but clamps downward whenever the panel would otherwise extend
|
|
205
|
+
* past the viewport's top boundary — that's the "reposition lower so the
|
|
206
|
+
* chat interface stays visible" behavior.
|
|
207
|
+
*/
|
|
208
|
+
get PanelBottomPx(): number;
|
|
141
209
|
/** Auto-resolve CurrentUser and EnvironmentId from Metadata when not provided as inputs */
|
|
142
210
|
private resolveDefaults;
|
|
143
|
-
/** Load saved panel size from UserInfoEngine */
|
|
144
|
-
private
|
|
145
|
-
/** Persist panel size to UserInfoEngine (debounced) */
|
|
146
|
-
private
|
|
211
|
+
/** Load saved panel size and bubble position from UserInfoEngine */
|
|
212
|
+
private loadPreferences;
|
|
213
|
+
/** Persist panel size and bubble position to UserInfoEngine (debounced) */
|
|
214
|
+
private savePreferences;
|
|
147
215
|
/** Subscribe to bridge events for cross-view coordination */
|
|
148
216
|
private subscribeToBridgeEvents;
|
|
149
217
|
/** Subscribe to agent client tool execution events */
|
|
@@ -153,6 +221,6 @@ export declare class ChatAgentsOverlayComponent extends BaseAngularComponent imp
|
|
|
153
221
|
/** Emit a conversation switched event */
|
|
154
222
|
private emitConversationSwitched;
|
|
155
223
|
static ɵfac: i0.ɵɵFactoryDeclaration<ChatAgentsOverlayComponent, never>;
|
|
156
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ChatAgentsOverlayComponent, "mj-chat-agents-overlay", never, { "IsVisible": { "alias": "IsVisible"; "required": false; }; "CurrentUser": { "alias": "CurrentUser"; "required": false; }; "EnvironmentId": { "alias": "EnvironmentId"; "required": false; }; "AppContext": { "alias": "AppContext"; "required": false; }; "EmptyStateGreeting": { "alias": "EmptyStateGreeting"; "required": false; }; }, { "VisibilityChanged": "VisibilityChanged"; "ToolExecuted": "ToolExecuted"; "ConversationSwitched": "ConversationSwitched"; "OpenFullChatWorkspace": "OpenFullChatWorkspace"; "NavigationRequested": "NavigationRequested"; "OpenEntityRecord": "OpenEntityRecord"; "TaskClicked": "TaskClicked"; }, never, never, false, never>;
|
|
224
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ChatAgentsOverlayComponent, "mj-chat-agents-overlay", never, { "IsVisible": { "alias": "IsVisible"; "required": false; }; "CurrentUser": { "alias": "CurrentUser"; "required": false; }; "EnvironmentId": { "alias": "EnvironmentId"; "required": false; }; "AppContext": { "alias": "AppContext"; "required": false; }; "EmptyStateGreeting": { "alias": "EmptyStateGreeting"; "required": false; }; "TopBoundaryPx": { "alias": "TopBoundaryPx"; "required": false; }; }, { "VisibilityChanged": "VisibilityChanged"; "ToolExecuted": "ToolExecuted"; "ConversationSwitched": "ConversationSwitched"; "OpenFullChatWorkspace": "OpenFullChatWorkspace"; "NavigationRequested": "NavigationRequested"; "OpenEntityRecord": "OpenEntityRecord"; "TaskClicked": "TaskClicked"; }, never, never, false, never>;
|
|
157
225
|
}
|
|
158
226
|
//# sourceMappingURL=chat-overlay.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-overlay.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/overlay/chat-overlay.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAEH,YAAY,EAEZ,SAAS,EACT,MAAM,EAIT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAY,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAA+C,MAAM,+BAA+B,CAAC;AAEhI,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;;AAExE,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC;AAEtE,wEAAwE;AACxE,MAAM,WAAW,gCAAgC;IAC7C,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;
|
|
1
|
+
{"version":3,"file":"chat-overlay.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/overlay/chat-overlay.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,8 +22,8 @@ import { AgentClientService } from '@memberjunction/ng-agent-client';
|
|
|
22
22
|
import { ConversationBridgeService } from '../../services/conversation-bridge.service';
|
|
23
23
|
import * as i0 from "@angular/core";
|
|
24
24
|
import * as i1 from "../conversation/conversation-chat-area.component";
|
|
25
|
-
function
|
|
26
|
-
i0.ɵɵelementStart(0, "span",
|
|
25
|
+
function ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelementStart(0, "span", 6);
|
|
27
27
|
i0.ɵɵtext(1);
|
|
28
28
|
i0.ɵɵelementEnd();
|
|
29
29
|
} if (rf & 2) {
|
|
@@ -34,62 +34,64 @@ function ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Conditional_2_Te
|
|
|
34
34
|
function ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
35
35
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
36
36
|
i0.ɵɵelementStart(0, "div", 2);
|
|
37
|
-
i0.ɵɵlistener("
|
|
38
|
-
i0.ɵɵelement(1, "i", 3);
|
|
39
|
-
i0.ɵɵconditionalCreate(
|
|
37
|
+
i0.ɵɵlistener("pointerdown", function ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Template_div_pointerdown_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnBubblePointerDown($event)); });
|
|
38
|
+
i0.ɵɵelement(1, "i", 3)(2, "i", 4)(3, "i", 5);
|
|
39
|
+
i0.ɵɵconditionalCreate(4, ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Conditional_4_Template, 2, 1, "span", 6);
|
|
40
40
|
i0.ɵɵelementEnd();
|
|
41
41
|
} if (rf & 2) {
|
|
42
42
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
43
|
-
i0.ɵɵ
|
|
44
|
-
i0.ɵɵ
|
|
43
|
+
i0.ɵɵstyleProp("bottom", ctx_r1.BubbleBottomPx, "px");
|
|
44
|
+
i0.ɵɵclassProp("is-pressed", ctx_r1.IsBubblePressed)("is-dragging", ctx_r1.IsBubbleDragging);
|
|
45
|
+
i0.ɵɵadvance(4);
|
|
46
|
+
i0.ɵɵconditional(ctx_r1.UnreadCount > 0 ? 4 : -1);
|
|
45
47
|
} }
|
|
46
48
|
function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
47
49
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
48
|
-
i0.ɵɵelementStart(0, "div",
|
|
50
|
+
i0.ɵɵelementStart(0, "div", 21);
|
|
49
51
|
i0.ɵɵlistener("mousedown", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_1_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnResizeStart($event, "left")); });
|
|
50
52
|
i0.ɵɵelementEnd();
|
|
51
|
-
i0.ɵɵelementStart(1, "div",
|
|
53
|
+
i0.ɵɵelementStart(1, "div", 22);
|
|
52
54
|
i0.ɵɵlistener("mousedown", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_1_Template_div_mousedown_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnResizeStart($event, "top")); });
|
|
53
55
|
i0.ɵɵelementEnd();
|
|
54
|
-
i0.ɵɵelementStart(2, "div",
|
|
56
|
+
i0.ɵɵelementStart(2, "div", 23);
|
|
55
57
|
i0.ɵɵlistener("mousedown", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_1_Template_div_mousedown_2_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnResizeStart($event, "top-left")); });
|
|
56
58
|
i0.ɵɵelementEnd();
|
|
57
59
|
} }
|
|
58
60
|
function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
59
61
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
60
|
-
i0.ɵɵelementStart(0, "button",
|
|
62
|
+
i0.ɵɵelementStart(0, "button", 24);
|
|
61
63
|
i0.ɵɵlistener("click", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnOpenFullChatWorkspace()); });
|
|
62
|
-
i0.ɵɵelement(1, "i",
|
|
64
|
+
i0.ɵɵelement(1, "i", 25);
|
|
63
65
|
i0.ɵɵelementEnd();
|
|
64
66
|
} }
|
|
65
67
|
function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
66
68
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
67
|
-
i0.ɵɵelementStart(0, "div",
|
|
69
|
+
i0.ɵɵelementStart(0, "div", 7);
|
|
68
70
|
i0.ɵɵconditionalCreate(1, ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_1_Template, 3, 0);
|
|
69
|
-
i0.ɵɵelementStart(2, "div",
|
|
70
|
-
i0.ɵɵelement(4, "i",
|
|
71
|
+
i0.ɵɵelementStart(2, "div", 8)(3, "div", 9);
|
|
72
|
+
i0.ɵɵelement(4, "i", 10);
|
|
71
73
|
i0.ɵɵelementStart(5, "span");
|
|
72
74
|
i0.ɵɵtext(6, "AI Assistant");
|
|
73
75
|
i0.ɵɵelementEnd()();
|
|
74
|
-
i0.ɵɵelementStart(7, "div",
|
|
76
|
+
i0.ɵɵelementStart(7, "div", 11)(8, "button", 12);
|
|
75
77
|
i0.ɵɵlistener("click", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.StartNewConversation()); });
|
|
76
|
-
i0.ɵɵelement(9, "i",
|
|
78
|
+
i0.ɵɵelement(9, "i", 13);
|
|
77
79
|
i0.ɵɵelementEnd();
|
|
78
|
-
i0.ɵɵconditionalCreate(10, ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_10_Template, 2, 0, "button",
|
|
79
|
-
i0.ɵɵelementStart(11, "button",
|
|
80
|
+
i0.ɵɵconditionalCreate(10, ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Conditional_10_Template, 2, 0, "button", 14);
|
|
81
|
+
i0.ɵɵelementStart(11, "button", 15);
|
|
80
82
|
i0.ɵɵlistener("click", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleMaximize()); });
|
|
81
|
-
i0.ɵɵelement(12, "i",
|
|
83
|
+
i0.ɵɵelement(12, "i", 16);
|
|
82
84
|
i0.ɵɵelementEnd();
|
|
83
|
-
i0.ɵɵelementStart(13, "button",
|
|
85
|
+
i0.ɵɵelementStart(13, "button", 17);
|
|
84
86
|
i0.ɵɵlistener("click", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.Collapse()); });
|
|
85
|
-
i0.ɵɵelement(14, "i",
|
|
87
|
+
i0.ɵɵelement(14, "i", 18);
|
|
86
88
|
i0.ɵɵelementEnd()()();
|
|
87
|
-
i0.ɵɵelementStart(15, "div",
|
|
89
|
+
i0.ɵɵelementStart(15, "div", 19)(16, "mj-conversation-chat-area", 20);
|
|
88
90
|
i0.ɵɵlistener("conversationCreated", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_conversationCreated_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnConversationCreated($event)); })("conversationRenamed", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_conversationRenamed_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnConversationRenamed($event)); })("pendingMessageConsumed", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_pendingMessageConsumed_16_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPendingMessageConsumed()); })("openEntityRecord", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_openEntityRecord_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnOpenEntityRecord($event)); })("navigationRequest", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_navigationRequest_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnNavigationRequest($event)); })("taskClicked", function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template_mj_conversation_chat_area_taskClicked_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTaskClicked($event)); });
|
|
89
91
|
i0.ɵɵelementEnd()()();
|
|
90
92
|
} if (rf & 2) {
|
|
91
93
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
92
|
-
i0.ɵɵstyleProp("width", ctx_r1.State === "maximized" ? null : ctx_r1.PanelWidth, "px")("height", ctx_r1.State === "maximized" ? null : ctx_r1.PanelHeight, "px");
|
|
94
|
+
i0.ɵɵstyleProp("width", ctx_r1.State === "maximized" ? null : ctx_r1.PanelWidth, "px")("height", ctx_r1.State === "maximized" ? null : ctx_r1.PanelHeight, "px")("bottom", ctx_r1.State === "maximized" ? null : ctx_r1.PanelBottomPx, "px");
|
|
93
95
|
i0.ɵɵclassProp("maximized", ctx_r1.State === "maximized");
|
|
94
96
|
i0.ɵɵadvance();
|
|
95
97
|
i0.ɵɵconditional(ctx_r1.State === "expanded" ? 1 : -1);
|
|
@@ -103,8 +105,8 @@ function ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template(rf, ctx
|
|
|
103
105
|
i0.ɵɵproperty("environmentId", ctx_r1.EnvironmentId)("currentUser", ctx_r1.CurrentUser)("conversationId", ctx_r1.ConversationId)("conversation", ctx_r1.Conversation)("isNewConversation", ctx_r1.IsNewConversation)("pendingMessage", ctx_r1.PendingMessage)("pendingAttachments", ctx_r1.PendingAttachments)("overlayMode", true)("showExportButton", false)("showShareButton", false)("showArtifactIndicator", false)("appContext", ctx_r1.AppContext)("emptyStateGreeting", ctx_r1.EmptyStateGreeting);
|
|
104
106
|
} }
|
|
105
107
|
function ChatAgentsOverlayComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
106
|
-
i0.ɵɵconditionalCreate(0, ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Template,
|
|
107
|
-
i0.ɵɵconditionalCreate(1, ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template, 17,
|
|
108
|
+
i0.ɵɵconditionalCreate(0, ChatAgentsOverlayComponent_Conditional_0_Conditional_0_Template, 5, 7, "div", 0);
|
|
109
|
+
i0.ɵɵconditionalCreate(1, ChatAgentsOverlayComponent_Conditional_0_Conditional_1_Template, 17, 28, "div", 1);
|
|
108
110
|
} if (rf & 2) {
|
|
109
111
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
110
112
|
i0.ɵɵconditional(ctx_r1.State === "collapsed" ? 0 : -1);
|
|
@@ -124,6 +126,15 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
124
126
|
static MIN_HEIGHT = 350;
|
|
125
127
|
static MAX_WIDTH = 900;
|
|
126
128
|
static MAX_HEIGHT = 1000;
|
|
129
|
+
// --- Bubble drag constants ---
|
|
130
|
+
/** Default `bottom` for both bubble and panel (matches CSS 1.5rem). */
|
|
131
|
+
static BASE_BOTTOM_PX = 24;
|
|
132
|
+
/** Floating bubble diameter in pixels (matches CSS 3.5rem). */
|
|
133
|
+
static BUBBLE_SIZE_PX = 56;
|
|
134
|
+
/** Minimum gap to keep between the overlay and the viewport top edge. */
|
|
135
|
+
static VIEWPORT_TOP_PADDING_PX = 16;
|
|
136
|
+
/** Mousedown-to-mousemove distance that promotes a click into a drag. */
|
|
137
|
+
static BUBBLE_DRAG_THRESHOLD_PX = 5;
|
|
127
138
|
// --- Inputs ---
|
|
128
139
|
/** Controls external visibility (e.g., parent hides overlay on chat route) */
|
|
129
140
|
_IsVisible = true;
|
|
@@ -146,6 +157,13 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
146
157
|
AppContext = null;
|
|
147
158
|
/** Greeting message shown in the empty state when no conversation is active */
|
|
148
159
|
EmptyStateGreeting = 'How can I help you?';
|
|
160
|
+
/**
|
|
161
|
+
* Pixels reserved at the top of the viewport that the bubble and panel must not
|
|
162
|
+
* cross. Set this from the host app to the height of any fixed top chrome (e.g.
|
|
163
|
+
* Explorer's shell-header). Defaults to 0 — generic apps without top chrome
|
|
164
|
+
* keep the full viewport available.
|
|
165
|
+
*/
|
|
166
|
+
TopBoundaryPx = 0;
|
|
149
167
|
// --- Outputs ---
|
|
150
168
|
/** Emitted when the overlay visibility changes */
|
|
151
169
|
VisibilityChanged = new EventEmitter();
|
|
@@ -167,6 +185,20 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
167
185
|
/** Panel dimensions (persisted via UserInfoEngine) */
|
|
168
186
|
PanelWidth = ChatAgentsOverlayComponent.DEFAULT_WIDTH;
|
|
169
187
|
PanelHeight = ChatAgentsOverlayComponent.DEFAULT_HEIGHT;
|
|
188
|
+
/**
|
|
189
|
+
* Pixels the floating bubble has been dragged up from its default
|
|
190
|
+
* bottom-right corner position. Always >= 0; clamping at render time
|
|
191
|
+
* keeps the bubble on-screen even after a viewport resize.
|
|
192
|
+
*/
|
|
193
|
+
BubbleOffsetY = 0;
|
|
194
|
+
/** True while the user is actively dragging the bubble; used to swap cursor + suppress click. */
|
|
195
|
+
IsBubbleDragging = false;
|
|
196
|
+
/**
|
|
197
|
+
* True from mousedown until mouseup on the bubble, regardless of whether the
|
|
198
|
+
* gesture became a drag. Used to give immediate "I'm being held" feedback so
|
|
199
|
+
* the user can see drag is possible even before crossing the move threshold.
|
|
200
|
+
*/
|
|
201
|
+
IsBubblePressed = false;
|
|
170
202
|
/** Active conversation ID managed locally */
|
|
171
203
|
_conversationId = null;
|
|
172
204
|
get ConversationId() {
|
|
@@ -187,10 +219,19 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
187
219
|
resizeStartY = 0;
|
|
188
220
|
resizeStartWidth = 0;
|
|
189
221
|
resizeStartHeight = 0;
|
|
222
|
+
/** Bubble drag state */
|
|
223
|
+
bubbleDragStartMouseY = 0;
|
|
224
|
+
bubbleDragStartOffset = 0;
|
|
225
|
+
/** True once the pointer has moved past BUBBLE_DRAG_THRESHOLD_PX; suppresses the implicit click. */
|
|
226
|
+
bubbleDragMoved = false;
|
|
227
|
+
/** ID of the pointer currently driving the drag — guards against multi-touch confusion. */
|
|
228
|
+
activeBubblePointerId = null;
|
|
229
|
+
/** Element that captured the pointer; needed to release capture on end/cancel. */
|
|
230
|
+
bubbleCaptureTarget = null;
|
|
190
231
|
// --- Lifecycle ---
|
|
191
232
|
ngOnInit() {
|
|
192
233
|
this.resolveDefaults();
|
|
193
|
-
this.
|
|
234
|
+
this.loadPreferences();
|
|
194
235
|
this.subscribeToBridgeEvents();
|
|
195
236
|
this.subscribeToToolEvents();
|
|
196
237
|
}
|
|
@@ -198,6 +239,7 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
198
239
|
this.destroy$.next();
|
|
199
240
|
this.destroy$.complete();
|
|
200
241
|
this.removeResizeListeners();
|
|
242
|
+
this.removeBubbleDragListeners();
|
|
201
243
|
}
|
|
202
244
|
// --- Public Methods ---
|
|
203
245
|
/** Toggle between collapsed and expanded states */
|
|
@@ -330,7 +372,7 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
330
372
|
this.isResizing = false;
|
|
331
373
|
this.resizeEdge = null;
|
|
332
374
|
this.removeResizeListeners();
|
|
333
|
-
this.
|
|
375
|
+
this.savePreferences();
|
|
334
376
|
};
|
|
335
377
|
removeResizeListeners() {
|
|
336
378
|
document.removeEventListener('mousemove', this.onResizeMove);
|
|
@@ -342,6 +384,123 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
342
384
|
clampHeight(value) {
|
|
343
385
|
return Math.max(ChatAgentsOverlayComponent.MIN_HEIGHT, Math.min(ChatAgentsOverlayComponent.MAX_HEIGHT, value));
|
|
344
386
|
}
|
|
387
|
+
// --- Bubble Drag Methods (Pointer Events — unified mouse / touch / pen) ---
|
|
388
|
+
/**
|
|
389
|
+
* Start tracking a potential bubble drag. We don't enter drag mode until
|
|
390
|
+
* the pointer moves past BUBBLE_DRAG_THRESHOLD_PX — releasing before that
|
|
391
|
+
* threshold is treated as a normal click/tap and opens the chat (via Toggle()).
|
|
392
|
+
*
|
|
393
|
+
* Pointer Events (not mousedown) so the same code path serves desktop mouse,
|
|
394
|
+
* touch on phones/tablets, and pen input. setPointerCapture keeps the gesture
|
|
395
|
+
* tied to this element even if the finger or cursor strays off the bubble.
|
|
396
|
+
*/
|
|
397
|
+
OnBubblePointerDown(event) {
|
|
398
|
+
// Mouse: respect primary-button only. Touch/pen: button is always 0, so this passes naturally.
|
|
399
|
+
if (event.pointerType === 'mouse' && event.button !== 0)
|
|
400
|
+
return;
|
|
401
|
+
// Don't start a second drag while one is in flight (e.g. second finger on touch).
|
|
402
|
+
if (this.activeBubblePointerId !== null)
|
|
403
|
+
return;
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
const target = event.currentTarget;
|
|
406
|
+
target.setPointerCapture(event.pointerId);
|
|
407
|
+
this.bubbleCaptureTarget = target;
|
|
408
|
+
this.activeBubblePointerId = event.pointerId;
|
|
409
|
+
this.bubbleDragStartMouseY = event.clientY;
|
|
410
|
+
this.bubbleDragStartOffset = this.BubbleOffsetY;
|
|
411
|
+
this.bubbleDragMoved = false;
|
|
412
|
+
this.IsBubblePressed = true;
|
|
413
|
+
this.cdr.detectChanges();
|
|
414
|
+
document.addEventListener('pointermove', this.onBubbleDragMove);
|
|
415
|
+
document.addEventListener('pointerup', this.onBubbleDragEnd);
|
|
416
|
+
document.addEventListener('pointercancel', this.onBubbleDragEnd);
|
|
417
|
+
}
|
|
418
|
+
onBubbleDragMove = (event) => {
|
|
419
|
+
if (event.pointerId !== this.activeBubblePointerId)
|
|
420
|
+
return;
|
|
421
|
+
const deltaY = this.bubbleDragStartMouseY - event.clientY; // dragging up = positive
|
|
422
|
+
if (!this.bubbleDragMoved) {
|
|
423
|
+
if (Math.abs(deltaY) < ChatAgentsOverlayComponent.BUBBLE_DRAG_THRESHOLD_PX)
|
|
424
|
+
return;
|
|
425
|
+
this.bubbleDragMoved = true;
|
|
426
|
+
this.IsBubbleDragging = true;
|
|
427
|
+
}
|
|
428
|
+
this.BubbleOffsetY = this.clampBubbleOffsetY(this.bubbleDragStartOffset + deltaY);
|
|
429
|
+
this.cdr.detectChanges();
|
|
430
|
+
};
|
|
431
|
+
onBubbleDragEnd = (event) => {
|
|
432
|
+
if (event.pointerId !== this.activeBubblePointerId)
|
|
433
|
+
return;
|
|
434
|
+
this.removeBubbleDragListeners();
|
|
435
|
+
if (this.bubbleCaptureTarget) {
|
|
436
|
+
// Browser may have implicitly released capture on pointerup already (per the
|
|
437
|
+
// Pointer Events spec). releasePointerCapture throws in that race; safe to ignore.
|
|
438
|
+
try {
|
|
439
|
+
this.bubbleCaptureTarget.releasePointerCapture(event.pointerId);
|
|
440
|
+
}
|
|
441
|
+
catch { /* noop */ }
|
|
442
|
+
}
|
|
443
|
+
this.bubbleCaptureTarget = null;
|
|
444
|
+
this.activeBubblePointerId = null;
|
|
445
|
+
const wasDragged = this.bubbleDragMoved;
|
|
446
|
+
const wasCancelled = event.type === 'pointercancel';
|
|
447
|
+
this.bubbleDragMoved = false;
|
|
448
|
+
this.IsBubbleDragging = false;
|
|
449
|
+
this.IsBubblePressed = false;
|
|
450
|
+
if (wasDragged) {
|
|
451
|
+
this.savePreferences();
|
|
452
|
+
this.cdr.detectChanges();
|
|
453
|
+
}
|
|
454
|
+
else if (!wasCancelled) {
|
|
455
|
+
this.Toggle();
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
this.cdr.detectChanges();
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
removeBubbleDragListeners() {
|
|
462
|
+
document.removeEventListener('pointermove', this.onBubbleDragMove);
|
|
463
|
+
document.removeEventListener('pointerup', this.onBubbleDragEnd);
|
|
464
|
+
document.removeEventListener('pointercancel', this.onBubbleDragEnd);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Reserved space at the top of the viewport — host-supplied chrome plus
|
|
468
|
+
* the padding gap we always keep above the bubble/panel.
|
|
469
|
+
*/
|
|
470
|
+
get topReservedPx() {
|
|
471
|
+
return Math.max(0, this.TopBoundaryPx) + ChatAgentsOverlayComponent.VIEWPORT_TOP_PADDING_PX;
|
|
472
|
+
}
|
|
473
|
+
/** Clamp the offset so the bubble stays fully visible below the top boundary. */
|
|
474
|
+
clampBubbleOffsetY(value) {
|
|
475
|
+
const maxOffset = window.innerHeight
|
|
476
|
+
- ChatAgentsOverlayComponent.BUBBLE_SIZE_PX
|
|
477
|
+
- ChatAgentsOverlayComponent.BASE_BOTTOM_PX
|
|
478
|
+
- this.topReservedPx;
|
|
479
|
+
return Math.max(0, Math.min(Math.max(0, maxOffset), value));
|
|
480
|
+
}
|
|
481
|
+
// --- Render Position Getters ---
|
|
482
|
+
/** Effective `bottom` (px) for the floating bubble, clamped to the current viewport. */
|
|
483
|
+
get BubbleBottomPx() {
|
|
484
|
+
const ideal = ChatAgentsOverlayComponent.BASE_BOTTOM_PX + this.BubbleOffsetY;
|
|
485
|
+
const max = window.innerHeight
|
|
486
|
+
- ChatAgentsOverlayComponent.BUBBLE_SIZE_PX
|
|
487
|
+
- this.topReservedPx;
|
|
488
|
+
return Math.max(ChatAgentsOverlayComponent.BASE_BOTTOM_PX, Math.min(ideal, Math.max(ChatAgentsOverlayComponent.BASE_BOTTOM_PX, max)));
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Effective `bottom` (px) for the expanded panel. Anchors to the bubble's
|
|
492
|
+
* current bottom edge so the panel grows up from where the user parked the
|
|
493
|
+
* bubble, but clamps downward whenever the panel would otherwise extend
|
|
494
|
+
* past the viewport's top boundary — that's the "reposition lower so the
|
|
495
|
+
* chat interface stays visible" behavior.
|
|
496
|
+
*/
|
|
497
|
+
get PanelBottomPx() {
|
|
498
|
+
const ideal = ChatAgentsOverlayComponent.BASE_BOTTOM_PX + this.BubbleOffsetY;
|
|
499
|
+
const maxBottomForVisibility = window.innerHeight
|
|
500
|
+
- this.PanelHeight
|
|
501
|
+
- this.topReservedPx;
|
|
502
|
+
return Math.max(ChatAgentsOverlayComponent.BASE_BOTTOM_PX, Math.min(ideal, maxBottomForVisibility));
|
|
503
|
+
}
|
|
345
504
|
// --- Private Methods ---
|
|
346
505
|
/** Auto-resolve CurrentUser and EnvironmentId from Metadata when not provided as inputs */
|
|
347
506
|
resolveDefaults() {
|
|
@@ -353,8 +512,8 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
353
512
|
this.EnvironmentId = MJEnvironmentEntityExtended.DefaultEnvironmentID;
|
|
354
513
|
}
|
|
355
514
|
}
|
|
356
|
-
/** Load saved panel size from UserInfoEngine */
|
|
357
|
-
|
|
515
|
+
/** Load saved panel size and bubble position from UserInfoEngine */
|
|
516
|
+
loadPreferences() {
|
|
358
517
|
try {
|
|
359
518
|
const engine = UserInfoEngine.Instance;
|
|
360
519
|
const raw = engine.GetSetting(ChatAgentsOverlayComponent.SIZE_SETTING_KEY);
|
|
@@ -362,17 +521,21 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
362
521
|
const prefs = JSON.parse(raw);
|
|
363
522
|
this.PanelWidth = this.clampWidth(prefs.width);
|
|
364
523
|
this.PanelHeight = this.clampHeight(prefs.height);
|
|
524
|
+
if (typeof prefs.bubbleOffsetY === 'number') {
|
|
525
|
+
this.BubbleOffsetY = Math.max(0, prefs.bubbleOffsetY);
|
|
526
|
+
}
|
|
365
527
|
}
|
|
366
528
|
}
|
|
367
529
|
catch {
|
|
368
530
|
// Use defaults on error
|
|
369
531
|
}
|
|
370
532
|
}
|
|
371
|
-
/** Persist panel size to UserInfoEngine (debounced) */
|
|
372
|
-
|
|
533
|
+
/** Persist panel size and bubble position to UserInfoEngine (debounced) */
|
|
534
|
+
savePreferences() {
|
|
373
535
|
const prefs = {
|
|
374
536
|
width: this.PanelWidth,
|
|
375
|
-
height: this.PanelHeight
|
|
537
|
+
height: this.PanelHeight,
|
|
538
|
+
bubbleOffsetY: this.BubbleOffsetY
|
|
376
539
|
};
|
|
377
540
|
UserInfoEngine.Instance.SetSettingDebounced(ChatAgentsOverlayComponent.SIZE_SETTING_KEY, JSON.stringify(prefs));
|
|
378
541
|
}
|
|
@@ -424,15 +587,15 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
424
587
|
});
|
|
425
588
|
}
|
|
426
589
|
static ɵfac = /*@__PURE__*/ (() => { let ɵChatAgentsOverlayComponent_BaseFactory; return function ChatAgentsOverlayComponent_Factory(__ngFactoryType__) { return (ɵChatAgentsOverlayComponent_BaseFactory || (ɵChatAgentsOverlayComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ChatAgentsOverlayComponent)))(__ngFactoryType__ || ChatAgentsOverlayComponent); }; })();
|
|
427
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ChatAgentsOverlayComponent, selectors: [["mj-chat-agents-overlay"]], inputs: { IsVisible: "IsVisible", CurrentUser: "CurrentUser", EnvironmentId: "EnvironmentId", AppContext: "AppContext", EmptyStateGreeting: "EmptyStateGreeting" }, outputs: { VisibilityChanged: "VisibilityChanged", ToolExecuted: "ToolExecuted", ConversationSwitched: "ConversationSwitched", OpenFullChatWorkspace: "OpenFullChatWorkspace", NavigationRequested: "NavigationRequested", OpenEntityRecord: "OpenEntityRecord", TaskClicked: "TaskClicked" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[
|
|
590
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ChatAgentsOverlayComponent, selectors: [["mj-chat-agents-overlay"]], inputs: { IsVisible: "IsVisible", CurrentUser: "CurrentUser", EnvironmentId: "EnvironmentId", AppContext: "AppContext", EmptyStateGreeting: "EmptyStateGreeting", TopBoundaryPx: "TopBoundaryPx" }, outputs: { VisibilityChanged: "VisibilityChanged", ToolExecuted: "ToolExecuted", ConversationSwitched: "ConversationSwitched", OpenFullChatWorkspace: "OpenFullChatWorkspace", NavigationRequested: "NavigationRequested", OpenEntityRecord: "OpenEntityRecord", TaskClicked: "TaskClicked" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[1, "chat-overlay-bubble", 3, "is-pressed", "is-dragging", "bottom"], [1, "chat-overlay-panel", 3, "maximized", "width", "height", "bottom"], [1, "chat-overlay-bubble", 3, "pointerdown"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-up", "chat-overlay-bubble-arrow", "chat-overlay-bubble-arrow-up"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down", "chat-overlay-bubble-arrow", "chat-overlay-bubble-arrow-down"], [1, "fa-solid", "fa-comments", "chat-overlay-bubble-icon"], [1, "chat-overlay-badge"], [1, "chat-overlay-panel"], [1, "chat-overlay-header"], [1, "chat-overlay-title"], [1, "fa-solid", "fa-robot"], [1, "chat-overlay-header-actions"], ["title", "New conversation", 1, "chat-overlay-header-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["title", "Open in full chat workspace", 1, "chat-overlay-header-btn"], [1, "chat-overlay-header-btn", 3, "click", "title"], [1, "fa-solid"], ["title", "Minimize", 1, "chat-overlay-header-btn", 3, "click"], [1, "fa-solid", "fa-minus"], [1, "chat-overlay-body"], [3, "conversationCreated", "conversationRenamed", "pendingMessageConsumed", "openEntityRecord", "navigationRequest", "taskClicked", "environmentId", "currentUser", "conversationId", "conversation", "isNewConversation", "pendingMessage", "pendingAttachments", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "appContext", "emptyStateGreeting"], [1, "resize-handle", "resize-left", 3, "mousedown"], [1, "resize-handle", "resize-top", 3, "mousedown"], [1, "resize-handle", "resize-top-left", 3, "mousedown"], ["title", "Open in full chat workspace", 1, "chat-overlay-header-btn", 3, "click"], [1, "fa-solid", "fa-up-right-from-square"]], template: function ChatAgentsOverlayComponent_Template(rf, ctx) { if (rf & 1) {
|
|
428
591
|
i0.ɵɵconditionalCreate(0, ChatAgentsOverlayComponent_Conditional_0_Template, 2, 2);
|
|
429
592
|
} if (rf & 2) {
|
|
430
593
|
i0.ɵɵconditional(ctx.IsVisible ? 0 : -1);
|
|
431
|
-
} }, dependencies: [i1.ConversationChatAreaComponent], styles: ["\n\n\n\n\n\n\n\n\n.chat-overlay-bubble[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n z-index:
|
|
594
|
+
} }, dependencies: [i1.ConversationChatAreaComponent], styles: ["\n\n\n\n\n\n\n\n\n.chat-overlay-bubble[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n z-index: 2147483647;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n animation: _ngcontent-%COMP%_overlayBubbleIn 0.3s ease;\n \n\n\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n\n\n\n\n\n\n.chat-overlay-bubble-arrow[_ngcontent-%COMP%] {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n color: var(--mj-text-muted);\n font-size: 0.65rem;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.18s ease;\n}\n\n.chat-overlay-bubble-arrow-up[_ngcontent-%COMP%] {\n top: -0.85rem;\n}\n\n.chat-overlay-bubble-arrow-down[_ngcontent-%COMP%] {\n bottom: -0.85rem;\n}\n\n\n\n.chat-overlay-bubble[_ngcontent-%COMP%]:hover .chat-overlay-bubble-arrow[_ngcontent-%COMP%], \n.chat-overlay-bubble.is-pressed[_ngcontent-%COMP%] .chat-overlay-bubble-arrow[_ngcontent-%COMP%], \n.chat-overlay-bubble.is-dragging[_ngcontent-%COMP%] .chat-overlay-bubble-arrow[_ngcontent-%COMP%] {\n opacity: 0.85;\n}\n\n\n\n\n\n@media (hover: none) {\n .chat-overlay-bubble-arrow[_ngcontent-%COMP%] {\n opacity: 0.5;\n }\n}\n\n.chat-overlay-bubble[_ngcontent-%COMP%]:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.3);\n}\n\n\n\n\n.chat-overlay-bubble.is-pressed[_ngcontent-%COMP%] {\n cursor: grabbing;\n transform: scale(0.94);\n transition: transform 0.08s ease;\n box-shadow:\n 0 2px 6px rgba(0, 0, 0, 0.25),\n 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n\n\n.chat-overlay-bubble.is-dragging[_ngcontent-%COMP%] {\n cursor: grabbing;\n transform: scale(1.04);\n transition: none;\n box-shadow:\n 0 8px 28px rgba(0, 0, 0, 0.35),\n 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n@keyframes _ngcontent-%COMP%_overlayBubbleIn {\n from {\n transform: scale(0);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.chat-overlay-bubble-icon[_ngcontent-%COMP%] {\n font-size: 1.3rem;\n}\n\n.chat-overlay-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 1.2rem;\n height: 1.2rem;\n border-radius: 9999px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.65rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 0.25rem;\n border: 2px solid var(--mj-bg-page);\n}\n\n\n\n\n.chat-overlay-panel[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 50%, var(--mj-border-strong));\n box-shadow:\n 0 8px 32px rgba(0, 0, 0, 0.3),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 2147483647;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: _ngcontent-%COMP%_overlayPanelIn 0.25s ease;\n max-height: calc(100vh - 3rem);\n max-width: calc(100vw - 3rem);\n}\n\n.chat-overlay-panel.maximized[_ngcontent-%COMP%] {\n bottom: 1rem;\n right: 1rem;\n width: calc(100vw - 2rem) !important;\n height: calc(100vh - 2rem) !important;\n max-height: none;\n max-width: none;\n border-radius: 12px;\n}\n\n@keyframes _ngcontent-%COMP%_overlayPanelIn {\n from {\n opacity: 0;\n transform: scale(0.9) translateY(10px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n\n\n\n.resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n z-index: 2;\n}\n\n.resize-left[_ngcontent-%COMP%] {\n left: -3px;\n top: 20px;\n bottom: 20px;\n width: 6px;\n cursor: ew-resize;\n}\n\n.resize-top[_ngcontent-%COMP%] {\n top: -3px;\n left: 20px;\n right: 20px;\n height: 6px;\n cursor: ns-resize;\n}\n\n.resize-top-left[_ngcontent-%COMP%] {\n top: -4px;\n left: -4px;\n width: 16px;\n height: 16px;\n cursor: nwse-resize;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n border-radius: 3px;\n}\n\n\n\n\n.chat-overlay-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 0.75rem;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.chat-overlay-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n\n.chat-overlay-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.chat-overlay-header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n}\n\n.chat-overlay-header-btn[_ngcontent-%COMP%] {\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 6px;\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n transition: all 0.15s ease;\n}\n\n.chat-overlay-header-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n\n.chat-overlay-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.chat-overlay-body[_ngcontent-%COMP%] mj-conversation-chat-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n\n\n\n\n@media (max-width: 640px) {\n .chat-overlay-panel[_ngcontent-%COMP%] {\n bottom: 0 !important;\n right: 0;\n width: 100% !important;\n height: 100vh !important;\n max-height: 100vh;\n border-radius: 0;\n }\n\n .chat-overlay-bubble[_ngcontent-%COMP%] {\n \n\n\n\n\n width: 2.75rem;\n height: 2.75rem;\n right: 1rem;\n }\n\n .chat-overlay-bubble-icon[_ngcontent-%COMP%] {\n font-size: 1.1rem;\n }\n\n .chat-overlay-badge[_ngcontent-%COMP%] {\n min-width: 1rem;\n height: 1rem;\n font-size: 0.6rem;\n top: -3px;\n right: -3px;\n }\n\n .resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n}"] });
|
|
432
595
|
}
|
|
433
596
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ChatAgentsOverlayComponent, [{
|
|
434
597
|
type: Component,
|
|
435
|
-
args: [{ standalone: false, selector: 'mj-chat-agents-overlay', template: "@if (IsVisible) {\n <!-- Floating Button (collapsed state) -->\n @if (State === 'collapsed') {\n <div class=\"chat-overlay-bubble\" (click)=\"Toggle()\" title=\"Open Chat\">\n <i class=\"fa-solid fa-comments chat-overlay-bubble-icon\"></i>\n @if (UnreadCount > 0) {\n <span class=\"chat-overlay-badge\">{{ UnreadCount > 9 ? '9+' : UnreadCount }}</span>\n }\n </div>\n }\n\n <!-- Expanded / Maximized Chat Panel -->\n @if (State === 'expanded' || State === 'maximized') {\n <div class=\"chat-overlay-panel\"\n [class.maximized]=\"State === 'maximized'\"\n [style.width.px]=\"State === 'maximized' ? null : PanelWidth\"\n [style.height.px]=\"State === 'maximized' ? null : PanelHeight\">\n\n <!-- Resize handles (only in expanded, not maximized) -->\n @if (State === 'expanded') {\n <div class=\"resize-handle resize-left\"\n (mousedown)=\"OnResizeStart($event, 'left')\"></div>\n <div class=\"resize-handle resize-top\"\n (mousedown)=\"OnResizeStart($event, 'top')\"></div>\n <div class=\"resize-handle resize-top-left\"\n (mousedown)=\"OnResizeStart($event, 'top-left')\"></div>\n }\n\n <!-- Panel Header -->\n <div class=\"chat-overlay-header\">\n <div class=\"chat-overlay-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <div class=\"chat-overlay-header-actions\">\n <button\n class=\"chat-overlay-header-btn\"\n title=\"New conversation\"\n (click)=\"StartNewConversation()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n @if (ConversationId) {\n <button\n class=\"chat-overlay-header-btn\"\n title=\"Open in full chat workspace\"\n (click)=\"OnOpenFullChatWorkspace()\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n }\n <button\n class=\"chat-overlay-header-btn\"\n [title]=\"State === 'maximized' ? 'Restore size' : 'Maximize'\"\n (click)=\"ToggleMaximize()\">\n <i class=\"fa-solid\" [class.fa-expand]=\"State !== 'maximized'\" [class.fa-compress]=\"State === 'maximized'\"></i>\n </button>\n <button\n class=\"chat-overlay-header-btn\"\n title=\"Minimize\"\n (click)=\"Collapse()\">\n <i class=\"fa-solid fa-minus\"></i>\n </button>\n </div>\n </div>\n\n <!-- Chat Content \u2014 wraps conversation-chat-area -->\n <div class=\"chat-overlay-body\">\n <mj-conversation-chat-area\n [environmentId]=\"EnvironmentId\"\n [currentUser]=\"CurrentUser\"\n [conversationId]=\"ConversationId\"\n [conversation]=\"Conversation\"\n [isNewConversation]=\"IsNewConversation\"\n [pendingMessage]=\"PendingMessage\"\n [pendingAttachments]=\"PendingAttachments\"\n [overlayMode]=\"true\"\n [showExportButton]=\"false\"\n [showShareButton]=\"false\"\n [showArtifactIndicator]=\"false\"\n [appContext]=\"AppContext\"\n [emptyStateGreeting]=\"EmptyStateGreeting\"\n (conversationCreated)=\"OnConversationCreated($event)\"\n (conversationRenamed)=\"OnConversationRenamed($event)\"\n (pendingMessageConsumed)=\"OnPendingMessageConsumed()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\"\n (navigationRequest)=\"OnNavigationRequest($event)\"\n (taskClicked)=\"OnTaskClicked($event)\"\n ></mj-conversation-chat-area>\n </div>\n </div>\n }\n}\n", styles: ["/* ============================================================\n Chat Overlay \u2014 Floating Bubble + Expanding Panel\n All colors use MJ design tokens (--mj-* CSS variables).\n ============================================================ */\n\n/* --- Floating Bubble (collapsed state) --- */\n\n.chat-overlay-bubble {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n z-index: 999;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n animation: overlayBubbleIn 0.3s ease;\n}\n\n.chat-overlay-bubble:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.3);\n}\n\n@keyframes overlayBubbleIn {\n from {\n transform: scale(0);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.chat-overlay-bubble-icon {\n font-size: 1.3rem;\n}\n\n.chat-overlay-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 1.2rem;\n height: 1.2rem;\n border-radius: 9999px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.65rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 0.25rem;\n border: 2px solid var(--mj-bg-page);\n}\n\n/* --- Expanded Panel --- */\n\n.chat-overlay-panel {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 50%, var(--mj-border-strong));\n box-shadow:\n 0 8px 32px rgba(0, 0, 0, 0.3),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: overlayPanelIn 0.25s ease;\n max-height: calc(100vh - 3rem);\n max-width: calc(100vw - 3rem);\n}\n\n.chat-overlay-panel.maximized {\n bottom: 1rem;\n right: 1rem;\n width: calc(100vw - 2rem) !important;\n height: calc(100vh - 2rem) !important;\n max-height: none;\n max-width: none;\n border-radius: 12px;\n}\n\n@keyframes overlayPanelIn {\n from {\n opacity: 0;\n transform: scale(0.9) translateY(10px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* --- Resize Handles --- */\n\n.resize-handle {\n position: absolute;\n z-index: 2;\n}\n\n.resize-left {\n left: -3px;\n top: 20px;\n bottom: 20px;\n width: 6px;\n cursor: ew-resize;\n}\n\n.resize-top {\n top: -3px;\n left: 20px;\n right: 20px;\n height: 6px;\n cursor: ns-resize;\n}\n\n.resize-top-left {\n top: -4px;\n left: -4px;\n width: 16px;\n height: 16px;\n cursor: nwse-resize;\n}\n\n.resize-handle:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n border-radius: 3px;\n}\n\n/* --- Panel Header --- */\n\n.chat-overlay-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 0.75rem;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.chat-overlay-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n\n.chat-overlay-title i {\n color: var(--mj-brand-primary);\n}\n\n.chat-overlay-header-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.chat-overlay-header-btn {\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 6px;\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n transition: all 0.15s ease;\n}\n\n.chat-overlay-header-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* --- Panel Body --- */\n\n.chat-overlay-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.chat-overlay-body mj-conversation-chat-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n/* --- Mobile Responsive --- */\n\n@media (max-width: 480px) {\n .chat-overlay-panel {\n bottom: 0;\n right: 0;\n width: 100% !important;\n height: 100vh !important;\n max-height: 100vh;\n border-radius: 0;\n }\n\n .chat-overlay-bubble {\n bottom: 1rem;\n right: 1rem;\n }\n\n .resize-handle {\n display: none;\n }\n}\n"] }]
|
|
598
|
+
args: [{ standalone: false, selector: 'mj-chat-agents-overlay', template: "@if (IsVisible) {\n <!-- Floating Button (collapsed state) -->\n @if (State === 'collapsed') {\n <div class=\"chat-overlay-bubble\"\n [class.is-pressed]=\"IsBubblePressed\"\n [class.is-dragging]=\"IsBubbleDragging\"\n [style.bottom.px]=\"BubbleBottomPx\"\n (pointerdown)=\"OnBubblePointerDown($event)\">\n <i class=\"fa-solid fa-chevron-up chat-overlay-bubble-arrow chat-overlay-bubble-arrow-up\" aria-hidden=\"true\"></i>\n <i class=\"fa-solid fa-chevron-down chat-overlay-bubble-arrow chat-overlay-bubble-arrow-down\" aria-hidden=\"true\"></i>\n <i class=\"fa-solid fa-comments chat-overlay-bubble-icon\"></i>\n @if (UnreadCount > 0) {\n <span class=\"chat-overlay-badge\">{{ UnreadCount > 9 ? '9+' : UnreadCount }}</span>\n }\n </div>\n }\n\n <!-- Expanded / Maximized Chat Panel -->\n @if (State === 'expanded' || State === 'maximized') {\n <div class=\"chat-overlay-panel\"\n [class.maximized]=\"State === 'maximized'\"\n [style.width.px]=\"State === 'maximized' ? null : PanelWidth\"\n [style.height.px]=\"State === 'maximized' ? null : PanelHeight\"\n [style.bottom.px]=\"State === 'maximized' ? null : PanelBottomPx\">\n\n <!-- Resize handles (only in expanded, not maximized) -->\n @if (State === 'expanded') {\n <div class=\"resize-handle resize-left\"\n (mousedown)=\"OnResizeStart($event, 'left')\"></div>\n <div class=\"resize-handle resize-top\"\n (mousedown)=\"OnResizeStart($event, 'top')\"></div>\n <div class=\"resize-handle resize-top-left\"\n (mousedown)=\"OnResizeStart($event, 'top-left')\"></div>\n }\n\n <!-- Panel Header -->\n <div class=\"chat-overlay-header\">\n <div class=\"chat-overlay-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <div class=\"chat-overlay-header-actions\">\n <button\n class=\"chat-overlay-header-btn\"\n title=\"New conversation\"\n (click)=\"StartNewConversation()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n @if (ConversationId) {\n <button\n class=\"chat-overlay-header-btn\"\n title=\"Open in full chat workspace\"\n (click)=\"OnOpenFullChatWorkspace()\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n }\n <button\n class=\"chat-overlay-header-btn\"\n [title]=\"State === 'maximized' ? 'Restore size' : 'Maximize'\"\n (click)=\"ToggleMaximize()\">\n <i class=\"fa-solid\" [class.fa-expand]=\"State !== 'maximized'\" [class.fa-compress]=\"State === 'maximized'\"></i>\n </button>\n <button\n class=\"chat-overlay-header-btn\"\n title=\"Minimize\"\n (click)=\"Collapse()\">\n <i class=\"fa-solid fa-minus\"></i>\n </button>\n </div>\n </div>\n\n <!-- Chat Content \u2014 wraps conversation-chat-area -->\n <div class=\"chat-overlay-body\">\n <mj-conversation-chat-area\n [environmentId]=\"EnvironmentId\"\n [currentUser]=\"CurrentUser\"\n [conversationId]=\"ConversationId\"\n [conversation]=\"Conversation\"\n [isNewConversation]=\"IsNewConversation\"\n [pendingMessage]=\"PendingMessage\"\n [pendingAttachments]=\"PendingAttachments\"\n [overlayMode]=\"true\"\n [showExportButton]=\"false\"\n [showShareButton]=\"false\"\n [showArtifactIndicator]=\"false\"\n [appContext]=\"AppContext\"\n [emptyStateGreeting]=\"EmptyStateGreeting\"\n (conversationCreated)=\"OnConversationCreated($event)\"\n (conversationRenamed)=\"OnConversationRenamed($event)\"\n (pendingMessageConsumed)=\"OnPendingMessageConsumed()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\"\n (navigationRequest)=\"OnNavigationRequest($event)\"\n (taskClicked)=\"OnTaskClicked($event)\"\n ></mj-conversation-chat-area>\n </div>\n </div>\n }\n}\n", styles: ["/* ============================================================\n Chat Overlay \u2014 Floating Bubble + Expanding Panel\n All colors use MJ design tokens (--mj-* CSS variables).\n ============================================================ */\n\n/* --- Floating Bubble (collapsed state) --- */\n\n.chat-overlay-bubble {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n z-index: 2147483647;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n animation: overlayBubbleIn 0.3s ease;\n /* Required for touch drag: blocks browser pan/zoom so pointermove fires\n continuously instead of being swallowed by scroll-handling. */\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n/* Subtle up/down chevrons just outside the bubble, hinting that it can be\n dragged vertically. On hover-capable devices (mouse/pen) they stay hidden\n in the resting state and reveal on hover/press/drag \u2014 keeps the corner\n visually clean. On touch-only devices (no hover) they're always visible at\n low opacity so the affordance is discoverable without needing a hover. */\n.chat-overlay-bubble-arrow {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n color: var(--mj-text-muted);\n font-size: 0.65rem;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.18s ease;\n}\n\n.chat-overlay-bubble-arrow-up {\n top: -0.85rem;\n}\n\n.chat-overlay-bubble-arrow-down {\n bottom: -0.85rem;\n}\n\n/* Hover-capable devices: reveal on hover, press, or active drag. */\n.chat-overlay-bubble:hover .chat-overlay-bubble-arrow,\n.chat-overlay-bubble.is-pressed .chat-overlay-bubble-arrow,\n.chat-overlay-bubble.is-dragging .chat-overlay-bubble-arrow {\n opacity: 0.85;\n}\n\n/* Touch-only devices (no hover): always show at subtle opacity. The\n :hover/.is-pressed/.is-dragging rules above still apply via higher\n specificity, so touching the bubble briefly bumps them to 0.85. */\n@media (hover: none) {\n .chat-overlay-bubble-arrow {\n opacity: 0.5;\n }\n}\n\n.chat-overlay-bubble:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.3);\n}\n\n/* Immediate press feedback \u2014 fires on mousedown before the drag threshold is crossed,\n so the user sees \"I'm being held\" right away and learns the bubble is draggable. */\n.chat-overlay-bubble.is-pressed {\n cursor: grabbing;\n transform: scale(0.94);\n transition: transform 0.08s ease;\n box-shadow:\n 0 2px 6px rgba(0, 0, 0, 0.25),\n 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n/* Active drag \u2014 overrides the press state once movement passes the threshold. */\n.chat-overlay-bubble.is-dragging {\n cursor: grabbing;\n transform: scale(1.04);\n transition: none;\n box-shadow:\n 0 8px 28px rgba(0, 0, 0, 0.35),\n 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n@keyframes overlayBubbleIn {\n from {\n transform: scale(0);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.chat-overlay-bubble-icon {\n font-size: 1.3rem;\n}\n\n.chat-overlay-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 1.2rem;\n height: 1.2rem;\n border-radius: 9999px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.65rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 0.25rem;\n border: 2px solid var(--mj-bg-page);\n}\n\n/* --- Expanded Panel --- */\n\n.chat-overlay-panel {\n position: fixed;\n bottom: 1.5rem;\n right: 1.5rem;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 50%, var(--mj-border-strong));\n box-shadow:\n 0 8px 32px rgba(0, 0, 0, 0.3),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 2147483647;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: overlayPanelIn 0.25s ease;\n max-height: calc(100vh - 3rem);\n max-width: calc(100vw - 3rem);\n}\n\n.chat-overlay-panel.maximized {\n bottom: 1rem;\n right: 1rem;\n width: calc(100vw - 2rem) !important;\n height: calc(100vh - 2rem) !important;\n max-height: none;\n max-width: none;\n border-radius: 12px;\n}\n\n@keyframes overlayPanelIn {\n from {\n opacity: 0;\n transform: scale(0.9) translateY(10px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* --- Resize Handles --- */\n\n.resize-handle {\n position: absolute;\n z-index: 2;\n}\n\n.resize-left {\n left: -3px;\n top: 20px;\n bottom: 20px;\n width: 6px;\n cursor: ew-resize;\n}\n\n.resize-top {\n top: -3px;\n left: 20px;\n right: 20px;\n height: 6px;\n cursor: ns-resize;\n}\n\n.resize-top-left {\n top: -4px;\n left: -4px;\n width: 16px;\n height: 16px;\n cursor: nwse-resize;\n}\n\n.resize-handle:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n border-radius: 3px;\n}\n\n/* --- Panel Header --- */\n\n.chat-overlay-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 0.75rem;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.chat-overlay-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n\n.chat-overlay-title i {\n color: var(--mj-brand-primary);\n}\n\n.chat-overlay-header-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.chat-overlay-header-btn {\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 6px;\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n transition: all 0.15s ease;\n}\n\n.chat-overlay-header-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* --- Panel Body --- */\n\n.chat-overlay-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.chat-overlay-body mj-conversation-chat-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n/* --- Mobile / Small-Screen Responsive ---\n 640px = small-screen cutoff (covers all phones in both orientations). Tablets\n in portrait (\u2265768px) keep the floating-panel treatment because they have the\n real estate for it. */\n\n@media (max-width: 640px) {\n .chat-overlay-panel {\n bottom: 0 !important;\n right: 0;\n width: 100% !important;\n height: 100vh !important;\n max-height: 100vh;\n border-radius: 0;\n }\n\n .chat-overlay-bubble {\n /* No !important on `bottom` \u2014 the inline [style.bottom.px] binding owns it\n so users can drag the bubble out of the way of underlying app buttons.\n Smaller diameter on small screens: 2.75rem (44px) hits the WCAG minimum\n touch target while ~38% less occluding than the desktop 3.5rem. */\n width: 2.75rem;\n height: 2.75rem;\n right: 1rem;\n }\n\n .chat-overlay-bubble-icon {\n font-size: 1.1rem;\n }\n\n .chat-overlay-badge {\n min-width: 1rem;\n height: 1rem;\n font-size: 0.6rem;\n top: -3px;\n right: -3px;\n }\n\n .resize-handle {\n display: none;\n }\n}\n"] }]
|
|
436
599
|
}], null, { IsVisible: [{
|
|
437
600
|
type: Input
|
|
438
601
|
}], CurrentUser: [{
|
|
@@ -443,6 +606,8 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
443
606
|
type: Input
|
|
444
607
|
}], EmptyStateGreeting: [{
|
|
445
608
|
type: Input
|
|
609
|
+
}], TopBoundaryPx: [{
|
|
610
|
+
type: Input
|
|
446
611
|
}], VisibilityChanged: [{
|
|
447
612
|
type: Output
|
|
448
613
|
}], ToolExecuted: [{
|
|
@@ -458,5 +623,5 @@ export class ChatAgentsOverlayComponent extends BaseAngularComponent {
|
|
|
458
623
|
}], TaskClicked: [{
|
|
459
624
|
type: Output
|
|
460
625
|
}] }); })();
|
|
461
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ChatAgentsOverlayComponent, { className: "ChatAgentsOverlayComponent", filePath: "src/lib/components/overlay/chat-overlay.component.ts", lineNumber:
|
|
626
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ChatAgentsOverlayComponent, { className: "ChatAgentsOverlayComponent", filePath: "src/lib/components/overlay/chat-overlay.component.ts", lineNumber: 61 }); })();
|
|
462
627
|
//# sourceMappingURL=chat-overlay.component.js.map
|