@memberjunction/ng-composer 6.1.0-edge.1 → 6.1.0-edge.2
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/mention/mention-dropdown.component.d.ts +4 -2
- package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +21 -7
- package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +73 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +267 -21
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +103 -42
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +221 -119
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/events/composer-events.d.ts +40 -0
- package/dist/lib/events/composer-events.d.ts.map +1 -0
- package/dist/lib/events/composer-events.js +40 -0
- package/dist/lib/events/composer-events.js.map +1 -0
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,61 +1,77 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
2
|
+
import { BeforeSkillsOpenedEventArgs } from '../../events/composer-events';
|
|
2
3
|
import * as i0 from "@angular/core";
|
|
3
4
|
import * as i1 from "@angular/forms";
|
|
4
5
|
import * as i2 from "../mention/mention-editor.component";
|
|
5
6
|
const _c0 = ["mentionEditor"];
|
|
6
7
|
function MessageInputBoxComponent_Conditional_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
7
8
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
8
|
-
i0.ɵɵelementStart(0, "button",
|
|
9
|
-
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_1_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.
|
|
10
|
-
i0.ɵɵelement(1, "i",
|
|
9
|
+
i0.ɵɵelementStart(0, "button", 10);
|
|
10
|
+
i0.ɵɵlistener("mousedown", function MessageInputBoxComponent_Conditional_4_Conditional_1_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r2); $event.preventDefault(); return i0.ɵɵresetView($event.stopPropagation()); })("click", function MessageInputBoxComponent_Conditional_4_Conditional_1_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.OnSkillsClick($event); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
11
|
+
i0.ɵɵelement(1, "i", 11);
|
|
11
12
|
i0.ɵɵelementEnd();
|
|
12
13
|
} if (rf & 2) {
|
|
13
14
|
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
14
|
-
i0.ɵɵclassProp("
|
|
15
|
-
i0.ɵɵproperty("disabled", ctx_r2.
|
|
16
|
-
i0.ɵɵattribute("aria-
|
|
15
|
+
i0.ɵɵclassProp("skills-button-icon--active", ctx_r2.SkillsActive);
|
|
16
|
+
i0.ɵɵproperty("disabled", ctx_r2.Disabled);
|
|
17
|
+
i0.ɵɵattribute("aria-expanded", ctx_r2.SkillsActive);
|
|
17
18
|
} }
|
|
18
19
|
function MessageInputBoxComponent_Conditional_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
19
20
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
20
|
-
i0.ɵɵelementStart(0, "button",
|
|
21
|
-
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_2_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.
|
|
22
|
-
i0.ɵɵelement(1, "i",
|
|
21
|
+
i0.ɵɵelementStart(0, "button", 12);
|
|
22
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_2_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.PlanModeToggle.emit(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
23
|
+
i0.ɵɵelement(1, "i", 13);
|
|
23
24
|
i0.ɵɵelementEnd();
|
|
24
25
|
} if (rf & 2) {
|
|
25
26
|
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
26
|
-
i0.ɵɵ
|
|
27
|
+
i0.ɵɵclassProp("plan-mode-button-icon--active", ctx_r2.PlanModeActive);
|
|
28
|
+
i0.ɵɵproperty("disabled", ctx_r2.Disabled)("title", ctx_r2.PlanModeActive ? "Plan Mode ON \u2014 the agent presents a plan for your approval before it acts" : "Plan Mode: have the agent present a plan for your approval before it acts");
|
|
29
|
+
i0.ɵɵattribute("aria-pressed", ctx_r2.PlanModeActive);
|
|
27
30
|
} }
|
|
28
31
|
function MessageInputBoxComponent_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
29
32
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
30
|
-
i0.ɵɵelementStart(0, "button",
|
|
31
|
-
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_3_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.
|
|
32
|
-
i0.ɵɵelement(1, "i",
|
|
33
|
+
i0.ɵɵelementStart(0, "button", 14);
|
|
34
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_3_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.OpenFilePicker(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
35
|
+
i0.ɵɵelement(1, "i", 15);
|
|
33
36
|
i0.ɵɵelementEnd();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
i0.ɵɵ
|
|
37
|
+
} if (rf & 2) {
|
|
38
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
39
|
+
i0.ɵɵproperty("disabled", ctx_r2.Disabled);
|
|
40
|
+
} }
|
|
41
|
+
function MessageInputBoxComponent_Conditional_4_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
42
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
43
|
+
i0.ɵɵelementStart(0, "button", 16);
|
|
44
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_4_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.OnRealtimeClick(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
45
|
+
i0.ɵɵelement(1, "i", 17);
|
|
46
|
+
i0.ɵɵelementEnd();
|
|
47
|
+
i0.ɵɵelementStart(2, "button", 18);
|
|
48
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Conditional_4_Conditional_4_Template_button_click_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.OnRealtimeOptionsClick(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
49
|
+
i0.ɵɵelement(3, "i", 19);
|
|
37
50
|
i0.ɵɵelementEnd();
|
|
38
51
|
} if (rf & 2) {
|
|
39
52
|
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
40
|
-
i0.ɵɵclassProp("voice-button-icon--active", ctx_r2.
|
|
41
|
-
i0.ɵɵproperty("disabled", !ctx_r2.
|
|
53
|
+
i0.ɵɵclassProp("voice-button-icon--active", ctx_r2.VoiceActive);
|
|
54
|
+
i0.ɵɵproperty("disabled", !ctx_r2.CanStartRealtime)("title", ctx_r2.VoiceActive ? "Voice call active" : "Start a voice call");
|
|
42
55
|
i0.ɵɵadvance(2);
|
|
43
|
-
i0.ɵɵproperty("disabled", !ctx_r2.
|
|
56
|
+
i0.ɵɵproperty("disabled", !ctx_r2.CanStartRealtime);
|
|
44
57
|
} }
|
|
45
58
|
function MessageInputBoxComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
46
59
|
i0.ɵɵelementStart(0, "div", 4);
|
|
47
|
-
i0.ɵɵconditionalCreate(1, MessageInputBoxComponent_Conditional_4_Conditional_1_Template, 2,
|
|
48
|
-
i0.ɵɵconditionalCreate(2, MessageInputBoxComponent_Conditional_4_Conditional_2_Template, 2,
|
|
49
|
-
i0.ɵɵconditionalCreate(3, MessageInputBoxComponent_Conditional_4_Conditional_3_Template,
|
|
60
|
+
i0.ɵɵconditionalCreate(1, MessageInputBoxComponent_Conditional_4_Conditional_1_Template, 2, 4, "button", 7);
|
|
61
|
+
i0.ɵɵconditionalCreate(2, MessageInputBoxComponent_Conditional_4_Conditional_2_Template, 2, 5, "button", 8);
|
|
62
|
+
i0.ɵɵconditionalCreate(3, MessageInputBoxComponent_Conditional_4_Conditional_3_Template, 2, 1, "button", 9);
|
|
63
|
+
i0.ɵɵconditionalCreate(4, MessageInputBoxComponent_Conditional_4_Conditional_4_Template, 4, 5);
|
|
50
64
|
i0.ɵɵelementEnd();
|
|
51
65
|
} if (rf & 2) {
|
|
52
66
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
53
67
|
i0.ɵɵadvance();
|
|
54
|
-
i0.ɵɵconditional(ctx_r2.
|
|
68
|
+
i0.ɵɵconditional(ctx_r2.EnableSkills ? 1 : -1);
|
|
55
69
|
i0.ɵɵadvance();
|
|
56
|
-
i0.ɵɵconditional(ctx_r2.
|
|
70
|
+
i0.ɵɵconditional(ctx_r2.EnablePlanMode ? 2 : -1);
|
|
57
71
|
i0.ɵɵadvance();
|
|
58
|
-
i0.ɵɵconditional(ctx_r2.
|
|
72
|
+
i0.ɵɵconditional(ctx_r2.EnableAttachments ? 3 : -1);
|
|
73
|
+
i0.ɵɵadvance();
|
|
74
|
+
i0.ɵɵconditional(ctx_r2.EnableRealtime ? 4 : -1);
|
|
59
75
|
} }
|
|
60
76
|
/**
|
|
61
77
|
* Reusable message input box component (presentational)
|
|
@@ -74,99 +90,179 @@ function MessageInputBoxComponent_Conditional_4_Template(rf, ctx) { if (rf & 1)
|
|
|
74
90
|
*/
|
|
75
91
|
export class MessageInputBoxComponent {
|
|
76
92
|
mentionEditor;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
Placeholder = 'Type your message to start a new conversation...';
|
|
94
|
+
Disabled = false;
|
|
95
|
+
Value = '';
|
|
96
|
+
ShowCharacterCount = false;
|
|
81
97
|
/** Master switch for all mention/command triggers (pass-through to the mention editor). */
|
|
82
|
-
|
|
98
|
+
EnableMentions = true;
|
|
83
99
|
/** Explicit trigger-provider list (pass-through to the mention editor; explicit list wins over discovery). */
|
|
84
100
|
TriggerProviders = null;
|
|
85
101
|
/** Discovery-mode filter: provider Keys to skip (pass-through to the mention editor). */
|
|
86
102
|
ExcludedTriggerKeys = [];
|
|
87
103
|
/** Optional metadata provider scoping this composer (pass-through to the mention editor). */
|
|
88
104
|
Provider = null;
|
|
89
|
-
|
|
90
|
-
|
|
105
|
+
CurrentUser;
|
|
106
|
+
Rows = 3;
|
|
91
107
|
// Attachment settings
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
EnableAttachments = true;
|
|
109
|
+
MaxAttachments = 10;
|
|
110
|
+
MaxAttachmentSizeBytes = 20 * 1024 * 1024; // 20MB
|
|
111
|
+
AcceptedFileTypes = 'image/*';
|
|
96
112
|
/** Shows the in-composer mic button when true. */
|
|
97
|
-
|
|
113
|
+
EnableRealtime = false;
|
|
98
114
|
/** Whether a realtime voice session is currently active (mic renders in its active state). */
|
|
99
|
-
|
|
100
|
-
/** Whether a voice session can be started right now (mic
|
|
101
|
-
|
|
115
|
+
VoiceActive = false;
|
|
116
|
+
/** Whether a voice session can be started right now (mic Disabled when false). */
|
|
117
|
+
CanStartRealtime = true;
|
|
102
118
|
/** Shows the in-composer Plan Mode toggle button when true. */
|
|
103
|
-
|
|
119
|
+
EnablePlanMode = false;
|
|
104
120
|
/** Current Plan Mode toggle state (renders the button in its active state). */
|
|
105
|
-
|
|
121
|
+
PlanModeActive = false;
|
|
122
|
+
/**
|
|
123
|
+
* Shows the in-composer Skills button when true.
|
|
124
|
+
*
|
|
125
|
+
* Gated separately from `EnableMentions` because a host can have the `/` trigger active and
|
|
126
|
+
* still not want the button — but the common case is that a composer offering skill commands
|
|
127
|
+
* should advertise them, since `/` is otherwise invisible.
|
|
128
|
+
*/
|
|
129
|
+
EnableSkills = false;
|
|
130
|
+
/**
|
|
131
|
+
* True while the skill dropdown is open, driving the button's expanded state.
|
|
132
|
+
*
|
|
133
|
+
* Note the ARIA differs from Plan Mode next to it, deliberately: Plan Mode is a toggle BUTTON
|
|
134
|
+
* (a mode that stays on), so `aria-pressed` is right there. This one opens a popup, so it is
|
|
135
|
+
* `aria-expanded` + `aria-haspopup`. Using `aria-pressed` here would have a screen reader
|
|
136
|
+
* announce "pressed" for something that actually just revealed a list.
|
|
137
|
+
*
|
|
138
|
+
* DERIVED, not an @Input, and this is the difference from Plan Mode. Plan Mode's active state is
|
|
139
|
+
* a persisted user preference the host owns and threads down. "Is the skill dropdown open" is
|
|
140
|
+
* intrinsic to this composer, so an @Input would be an API the host cannot meaningfully answer
|
|
141
|
+
* and would leave the button permanently unpressed if nobody bound it.
|
|
142
|
+
*/
|
|
143
|
+
get SkillsActive() {
|
|
144
|
+
return this.mentionEditor?.IsTriggerOpen('/') ?? false;
|
|
145
|
+
}
|
|
106
146
|
/** Composer lost focus — hosts persist drafts on this. */
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
147
|
+
Blurred = new EventEmitter();
|
|
148
|
+
TextSubmitted = new EventEmitter();
|
|
149
|
+
ValueChange = new EventEmitter();
|
|
150
|
+
AttachmentsChanged = new EventEmitter();
|
|
151
|
+
AttachmentError = new EventEmitter();
|
|
152
|
+
AttachmentClicked = new EventEmitter();
|
|
113
153
|
/** Emitted when the user clicks the mic button to start/stop a voice session. */
|
|
114
|
-
|
|
154
|
+
VoiceRequested = new EventEmitter();
|
|
115
155
|
/**
|
|
116
156
|
* Emitted when the user clicks the small caret next to the phone button — the host opens the
|
|
117
157
|
* voice agent/model picker so call options (which agent, which voice model) stay reachable
|
|
118
158
|
* without adding friction to the plain phone click's instant-start path.
|
|
119
159
|
*/
|
|
120
|
-
|
|
160
|
+
VoiceOptionsRequested = new EventEmitter();
|
|
121
161
|
/** Emitted when the user clicks the in-composer Plan Mode toggle button. */
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
162
|
+
PlanModeToggle = new EventEmitter();
|
|
163
|
+
/**
|
|
164
|
+
* Fired BEFORE the Skills button opens the dropdown. Flip `Cancel` to veto — a host gating
|
|
165
|
+
* skills by entitlement, or surfacing them elsewhere, blocks it here.
|
|
166
|
+
*
|
|
167
|
+
* A pair rather than a lone emitter because this is an ACTION a host might reasonably refuse
|
|
168
|
+
* (UI_LAYERING_GUIDE section 6, rule 1). Handlers must be synchronous; `Cancel` travels back
|
|
169
|
+
* through EventEmitter's synchronous dispatch.
|
|
170
|
+
*/
|
|
171
|
+
BeforeSkillsOpened = new EventEmitter();
|
|
172
|
+
/**
|
|
173
|
+
* Fired AFTER the dropdown actually opened. Not emitted on the canceled path, and not emitted
|
|
174
|
+
* when no active provider owns the trigger — so a host counting this counts dropdowns the user
|
|
175
|
+
* saw, rather than clicks.
|
|
176
|
+
*/
|
|
177
|
+
AfterSkillsOpened = new EventEmitter();
|
|
178
|
+
/**
|
|
179
|
+
* Open the skill-command dropdown, the same one `/` opens.
|
|
180
|
+
*
|
|
181
|
+
* Routed through the editor's OpenTrigger rather than a parallel menu so permission filtering,
|
|
182
|
+
* per-skill icons and chip insertion all stay in one implementation.
|
|
183
|
+
*/
|
|
184
|
+
/**
|
|
185
|
+
* NOTE: the template pairs this with
|
|
186
|
+
* `(mousedown)="$event.preventDefault(); $event.stopPropagation()"`, and BOTH halves are
|
|
187
|
+
* load-bearing.
|
|
188
|
+
*
|
|
189
|
+
* `preventDefault` — a <button> takes focus on mousedown, which blurs the editor, and the editor
|
|
190
|
+
* closes its dropdown 200ms after losing focus. Without it the menu opened and then shut itself.
|
|
191
|
+
*
|
|
192
|
+
* `stopPropagation` — the editor's click-away listener is on `document:mousedown` and exempts only
|
|
193
|
+
* presses inside the EDITOR's host. This button is a sibling of `<mj-mention-editor>`, so a press
|
|
194
|
+
* on it read as an outside press: mousedown closed the dropdown, then click saw `SkillsActive`
|
|
195
|
+
* already false and reopened it. The menu blinked, could not be dismissed by the button that
|
|
196
|
+
* opened it, and the Before/After pair fired on every click — the exact over-counting the toggle
|
|
197
|
+
* branch below exists to prevent. Stopping propagation states that this press belongs to the
|
|
198
|
+
* dropdown machinery.
|
|
199
|
+
*/
|
|
200
|
+
OnSkillsClick(event) {
|
|
201
|
+
// Toggle closed first. A disclosure button has to be able to close what it opened, and without
|
|
202
|
+
// this a second click re-ran the open path: it re-emitted the Before/After pair (so a host
|
|
203
|
+
// counting opens over-counted) and re-captured the trigger's baseline at the new caret, which
|
|
204
|
+
// corrupts the query offset once anything has been typed.
|
|
205
|
+
if (this.SkillsActive) {
|
|
206
|
+
this.mentionEditor?.closeMentionDropdown();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const args = new BeforeSkillsOpenedEventArgs();
|
|
210
|
+
this.BeforeSkillsOpened.emit(args);
|
|
211
|
+
if (args.Cancel) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const anchor = event?.currentTarget ?? null;
|
|
215
|
+
if (this.mentionEditor?.OpenTrigger('/', anchor)) {
|
|
216
|
+
this.AfterSkillsOpened.emit();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
OnRealtimeClick() {
|
|
220
|
+
this.VoiceRequested.emit();
|
|
125
221
|
}
|
|
126
|
-
|
|
127
|
-
this.
|
|
222
|
+
OnRealtimeOptionsClick() {
|
|
223
|
+
this.VoiceOptionsRequested.emit();
|
|
128
224
|
}
|
|
129
|
-
get
|
|
130
|
-
const hasText = this.
|
|
225
|
+
get CanSend() {
|
|
226
|
+
const hasText = this.Value.trim().length > 0;
|
|
131
227
|
const hasAttachments = this.mentionEditor?.hasAttachments() || false;
|
|
132
|
-
return !this.
|
|
228
|
+
return !this.Disabled && (hasText || hasAttachments);
|
|
133
229
|
}
|
|
134
230
|
/**
|
|
135
|
-
* Handle
|
|
231
|
+
* Handle Value changes from MentionEditorComponent
|
|
136
232
|
*/
|
|
137
|
-
|
|
138
|
-
this.
|
|
139
|
-
this.
|
|
233
|
+
OnValueChange(newValue) {
|
|
234
|
+
this.Value = newValue;
|
|
235
|
+
this.ValueChange.emit(this.Value);
|
|
140
236
|
}
|
|
141
237
|
/**
|
|
142
238
|
* Handle attachment changes from MentionEditorComponent
|
|
143
239
|
*/
|
|
144
|
-
|
|
145
|
-
this.
|
|
240
|
+
OnAttachmentsChanged(attachments) {
|
|
241
|
+
this.AttachmentsChanged.emit(attachments);
|
|
146
242
|
}
|
|
147
243
|
/**
|
|
148
244
|
* Handle attachment errors from MentionEditorComponent
|
|
149
245
|
*/
|
|
150
|
-
|
|
151
|
-
this.
|
|
246
|
+
OnAttachmentError(error) {
|
|
247
|
+
this.AttachmentError.emit(error);
|
|
152
248
|
}
|
|
153
249
|
/**
|
|
154
250
|
* Handle attachment click from MentionEditorComponent
|
|
155
251
|
*/
|
|
156
|
-
|
|
157
|
-
this.
|
|
252
|
+
OnAttachmentClicked(attachment) {
|
|
253
|
+
this.AttachmentClicked.emit(attachment);
|
|
158
254
|
}
|
|
159
255
|
/**
|
|
160
256
|
* Handle Enter key from MentionEditorComponent
|
|
161
257
|
* Extracts plain text with JSON-encoded mentions for message submission
|
|
162
258
|
*/
|
|
163
|
-
|
|
164
|
-
this.
|
|
259
|
+
OnEnterPressed(_text) {
|
|
260
|
+
this.OnSendClick();
|
|
165
261
|
}
|
|
166
262
|
/**
|
|
167
263
|
* Handle mention selection from MentionEditorComponent
|
|
168
264
|
*/
|
|
169
|
-
|
|
265
|
+
OnMentionSelected(suggestion) {
|
|
170
266
|
// MentionEditorComponent already inserts the mention chip
|
|
171
267
|
// This is just for additional tracking/analytics if needed
|
|
172
268
|
}
|
|
@@ -174,24 +270,24 @@ export class MessageInputBoxComponent {
|
|
|
174
270
|
* Send the message
|
|
175
271
|
* Extracts plain text with JSON-encoded mentions for proper persistence
|
|
176
272
|
*/
|
|
177
|
-
|
|
178
|
-
if (this.
|
|
273
|
+
OnSendClick() {
|
|
274
|
+
if (this.CanSend) {
|
|
179
275
|
// Get plain text with JSON-encoded mentions (preserves configuration info)
|
|
180
|
-
const textToSend = this.mentionEditor?.getPlainTextWithJsonMentions() || this.
|
|
181
|
-
this.
|
|
182
|
-
this.
|
|
276
|
+
const textToSend = this.mentionEditor?.getPlainTextWithJsonMentions() || this.Value.trim();
|
|
277
|
+
this.TextSubmitted.emit(textToSend);
|
|
278
|
+
this.Value = ''; // Clear input after sending
|
|
183
279
|
// Clear the editor content
|
|
184
280
|
if (this.mentionEditor) {
|
|
185
281
|
this.mentionEditor.clear();
|
|
186
282
|
}
|
|
187
|
-
this.
|
|
283
|
+
this.ValueChange.emit(this.Value);
|
|
188
284
|
}
|
|
189
285
|
}
|
|
190
286
|
/**
|
|
191
287
|
* Handle clicks on the container - focus the mention editor
|
|
192
288
|
* Only moves cursor to end if clicking outside the contentEditable area
|
|
193
289
|
*/
|
|
194
|
-
|
|
290
|
+
OnContainerClick(event) {
|
|
195
291
|
const target = event.target;
|
|
196
292
|
// Don't handle clicks on the send button
|
|
197
293
|
if (target.closest('.send-button-icon')) {
|
|
@@ -235,19 +331,19 @@ export class MessageInputBoxComponent {
|
|
|
235
331
|
/**
|
|
236
332
|
* Get mention chip data including configuration presets
|
|
237
333
|
*/
|
|
238
|
-
|
|
334
|
+
GetMentionChipsData() {
|
|
239
335
|
return this.mentionEditor?.getMentionChipsData() || [];
|
|
240
336
|
}
|
|
241
337
|
/**
|
|
242
338
|
* Get pending attachments from the editor
|
|
243
339
|
*/
|
|
244
|
-
|
|
340
|
+
GetPendingAttachments() {
|
|
245
341
|
return this.mentionEditor?.getPendingAttachments() || [];
|
|
246
342
|
}
|
|
247
343
|
/**
|
|
248
344
|
* Open file picker programmatically
|
|
249
345
|
*/
|
|
250
|
-
|
|
346
|
+
OpenFilePicker() {
|
|
251
347
|
this.mentionEditor?.openFilePicker();
|
|
252
348
|
}
|
|
253
349
|
/**
|
|
@@ -262,44 +358,44 @@ export class MessageInputBoxComponent {
|
|
|
262
358
|
} if (rf & 2) {
|
|
263
359
|
let _t;
|
|
264
360
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.mentionEditor = _t.first);
|
|
265
|
-
} }, inputs: {
|
|
361
|
+
} }, inputs: { Placeholder: "Placeholder", Disabled: "Disabled", Value: "Value", ShowCharacterCount: "ShowCharacterCount", EnableMentions: "EnableMentions", TriggerProviders: "TriggerProviders", ExcludedTriggerKeys: "ExcludedTriggerKeys", Provider: "Provider", CurrentUser: "CurrentUser", Rows: "Rows", EnableAttachments: "EnableAttachments", MaxAttachments: "MaxAttachments", MaxAttachmentSizeBytes: "MaxAttachmentSizeBytes", AcceptedFileTypes: "AcceptedFileTypes", EnableRealtime: "EnableRealtime", VoiceActive: "VoiceActive", CanStartRealtime: "CanStartRealtime", EnablePlanMode: "EnablePlanMode", PlanModeActive: "PlanModeActive", EnableSkills: "EnableSkills" }, outputs: { Blurred: "Blurred", TextSubmitted: "TextSubmitted", ValueChange: "ValueChange", AttachmentsChanged: "AttachmentsChanged", AttachmentError: "AttachmentError", AttachmentClicked: "AttachmentClicked", VoiceRequested: "VoiceRequested", VoiceOptionsRequested: "VoiceOptionsRequested", PlanModeToggle: "PlanModeToggle", BeforeSkillsOpened: "BeforeSkillsOpened", AfterSkillsOpened: "AfterSkillsOpened" }, standalone: false, decls: 7, vars: 14, consts: [["mentionEditor", ""], [1, "message-input-box-container", 3, "click"], [1, "input-wrapper"], [3, "ngModelChange", "valueChange", "enterPressed", "mentionSelected", "attachmentsChanged", "attachmentError", "attachmentClicked", "editorBlurred", "placeholder", "disabled", "currentUser", "enableMentions", "TriggerProviders", "ExcludedTriggerKeys", "Provider", "enableAttachments", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "ngModel"], [1, "attach-buttons"], ["title", "Send message (Enter)", 1, "send-button-icon", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], ["aria-haspopup", "true", "title", "Skills, or type / in the message box", "aria-label", "Show skills", 1, "attach-button-icon", "skills-button-icon", 3, "skills-button-icon--active", "disabled"], ["aria-label", "Toggle Plan Mode", 1, "attach-button-icon", "plan-mode-button-icon", 3, "plan-mode-button-icon--active", "disabled", "title"], ["title", "Attach file", 1, "attach-button-icon", 3, "disabled"], ["aria-haspopup", "true", "title", "Skills, or type / in the message box", "aria-label", "Show skills", 1, "attach-button-icon", "skills-button-icon", 3, "mousedown", "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-wand-magic-sparkles"], ["aria-label", "Toggle Plan Mode", 1, "attach-button-icon", "plan-mode-button-icon", 3, "click", "disabled", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-route"], ["title", "Attach file", 1, "attach-button-icon", 3, "click", "disabled"], [1, "fa-solid", "fa-paperclip"], ["aria-label", "Start a voice call", 1, "attach-button-icon", "voice-button-icon", 3, "click", "disabled", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone"], ["title", "Voice call options (choose agent and voice model)", "aria-label", "Voice call options", 1, "attach-button-icon", "voice-options-button-icon", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"]], template: function MessageInputBoxComponent_Template(rf, ctx) { if (rf & 1) {
|
|
266
362
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
267
363
|
i0.ɵɵelementStart(0, "div", 1);
|
|
268
|
-
i0.ɵɵlistener("click", function MessageInputBoxComponent_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.
|
|
364
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnContainerClick($event)); });
|
|
269
365
|
i0.ɵɵelementStart(1, "div", 2)(2, "mj-mention-editor", 3, 0);
|
|
270
|
-
i0.ɵɵtwoWayListener("ngModelChange", function MessageInputBoxComponent_Template_mj_mention_editor_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.
|
|
271
|
-
i0.ɵɵlistener("valueChange", function MessageInputBoxComponent_Template_mj_mention_editor_valueChange_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.
|
|
366
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MessageInputBoxComponent_Template_mj_mention_editor_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.Value, $event) || (ctx.Value = $event); return i0.ɵɵresetView($event); });
|
|
367
|
+
i0.ɵɵlistener("valueChange", function MessageInputBoxComponent_Template_mj_mention_editor_valueChange_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnValueChange($event)); })("enterPressed", function MessageInputBoxComponent_Template_mj_mention_editor_enterPressed_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnEnterPressed($event)); })("mentionSelected", function MessageInputBoxComponent_Template_mj_mention_editor_mentionSelected_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnMentionSelected($event)); })("attachmentsChanged", function MessageInputBoxComponent_Template_mj_mention_editor_attachmentsChanged_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnAttachmentsChanged($event)); })("attachmentError", function MessageInputBoxComponent_Template_mj_mention_editor_attachmentError_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnAttachmentError($event)); })("attachmentClicked", function MessageInputBoxComponent_Template_mj_mention_editor_attachmentClicked_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnAttachmentClicked($event)); })("editorBlurred", function MessageInputBoxComponent_Template_mj_mention_editor_editorBlurred_2_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.Blurred.emit()); });
|
|
272
368
|
i0.ɵɵelementEnd();
|
|
273
|
-
i0.ɵɵconditionalCreate(4, MessageInputBoxComponent_Conditional_4_Template,
|
|
369
|
+
i0.ɵɵconditionalCreate(4, MessageInputBoxComponent_Conditional_4_Template, 5, 4, "div", 4);
|
|
274
370
|
i0.ɵɵelementStart(5, "button", 5);
|
|
275
|
-
i0.ɵɵlistener("click", function MessageInputBoxComponent_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.
|
|
371
|
+
i0.ɵɵlistener("click", function MessageInputBoxComponent_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnSendClick()); });
|
|
276
372
|
i0.ɵɵelement(6, "i", 6);
|
|
277
373
|
i0.ɵɵelementEnd()()();
|
|
278
374
|
} if (rf & 2) {
|
|
279
375
|
i0.ɵɵadvance(2);
|
|
280
|
-
i0.ɵɵproperty("placeholder", ctx.
|
|
281
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx.
|
|
376
|
+
i0.ɵɵproperty("placeholder", ctx.Placeholder)("disabled", ctx.Disabled)("currentUser", ctx.CurrentUser)("enableMentions", ctx.EnableMentions)("TriggerProviders", ctx.TriggerProviders)("ExcludedTriggerKeys", ctx.ExcludedTriggerKeys)("Provider", ctx.Provider)("enableAttachments", ctx.EnableAttachments)("maxAttachments", ctx.MaxAttachments)("maxAttachmentSizeBytes", ctx.MaxAttachmentSizeBytes)("acceptedFileTypes", ctx.AcceptedFileTypes);
|
|
377
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.Value);
|
|
282
378
|
i0.ɵɵadvance(2);
|
|
283
|
-
i0.ɵɵconditional(ctx.
|
|
379
|
+
i0.ɵɵconditional(ctx.EnableAttachments || ctx.EnableRealtime || ctx.EnablePlanMode || ctx.EnableSkills ? 4 : -1);
|
|
284
380
|
i0.ɵɵadvance();
|
|
285
|
-
i0.ɵɵproperty("disabled", !ctx.
|
|
286
|
-
} }, dependencies: [i1.NgControlStatus, i1.NgModel, i2.MentionEditorComponent], styles: [".message-input-box-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n overflow: visible;\n position: relative;\n cursor: text;\n}\n.message-input-box-container[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-end;\n padding: 5px;\n}\n.input-wrapper[_ngcontent-%COMP%] mj-mention-editor[_ngcontent-%COMP%] {\n flex: 1;\n display: block;\n}\n\n.message-input-box-textarea[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem;\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n color: var(--mj-text-primary);\n border: 0 !important;\n}\n.message-input-box-textarea[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n.message-input-box-textarea[_ngcontent-%COMP%]:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--mj-bg-surface-sunken);\n}\n.message-input-box-textarea[_ngcontent-%COMP%]:focus, .message-input-box-textarea[_ngcontent-%COMP%]:active, .message-input-box-textarea[_ngcontent-%COMP%]:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n}\n\n.send-button-icon[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n.send-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: scale(1.05);\n}\n.send-button-icon[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: scale(0.95);\n}\n.send-button-icon[_ngcontent-%COMP%]:disabled {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n\n\n.attach-buttons[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0.75rem;\n right: 3rem;\n display: flex;\n gap: 2px;\n}\n.attach-button-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n.attach-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-text-primary) 5%, transparent);\n color: var(--mj-brand-primary);\n transform: scale(1.05);\n}\n.attach-button-icon[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: scale(0.95);\n}\n.attach-button-icon[_ngcontent-%COMP%]:disabled {\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n\n\n\n.plan-mode-button-icon--active[_ngcontent-%COMP%]:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.plan-mode-button-icon--active[_ngcontent-%COMP%]:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n\n\n@media (max-width: 768px) {\n .message-input-box-container[_ngcontent-%COMP%] {\n border-radius: 10px;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 6%, transparent);\n }\n .message-input-box-textarea[_ngcontent-%COMP%] {\n min-height: 80px;\n padding: 0.75rem;\n padding-right: 3rem;\n font-size: 16px;\n line-height: 1.4;\n }\n .send-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n bottom: 0.625rem;\n right: 0.625rem;\n border-radius: 6px;\n }\n .send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n .attach-buttons[_ngcontent-%COMP%] {\n bottom: 0.625rem;\n right: 2.75rem;\n }\n .attach-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n@media (max-width: 480px) {\n .message-input-box-container[_ngcontent-%COMP%] {\n border-radius: 8px;\n border-width: 1.5px;\n }\n .message-input-box-textarea[_ngcontent-%COMP%] {\n min-height: 60px;\n padding: 0.625rem;\n padding-right: 2.75rem;\n font-size: 16px;\n line-height: 1.3;\n }\n .send-button-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n bottom: 0.5rem;\n right: 0.5rem;\n border-radius: 6px;\n }\n .send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n .attach-buttons[_ngcontent-%COMP%] {\n bottom: 0.5rem;\n right: 2.75rem;\n }\n .attach-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n\n\n\n\n.voice-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.voice-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) i[_ngcontent-%COMP%] {\n filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mj-brand-primary) 55%, transparent));\n}\n.voice-button-icon[_ngcontent-%COMP%]:disabled i[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n.voice-button-icon--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n.voice-button-icon--active[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n\n\n\n\n\n.voice-options-button-icon[_ngcontent-%COMP%] {\n width: 20px;\n margin-left: -4px;\n}\n.voice-options-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n.voice-options-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.voice-options-button-icon[_ngcontent-%COMP%]:disabled i[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}"] });
|
|
381
|
+
i0.ɵɵproperty("disabled", !ctx.CanSend);
|
|
382
|
+
} }, dependencies: [i1.NgControlStatus, i1.NgModel, i2.MentionEditorComponent], styles: [".message-input-box-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n overflow: visible;\n position: relative;\n cursor: text;\n}\n.message-input-box-container[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-end;\n padding: 5px;\n}\n.input-wrapper[_ngcontent-%COMP%] mj-mention-editor[_ngcontent-%COMP%] {\n flex: 1;\n display: block;\n}\n\n.message-input-box-textarea[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem;\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n color: var(--mj-text-primary);\n border: 0 !important;\n}\n.message-input-box-textarea[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n.message-input-box-textarea[_ngcontent-%COMP%]:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--mj-bg-surface-sunken);\n}\n.message-input-box-textarea[_ngcontent-%COMP%]:focus, .message-input-box-textarea[_ngcontent-%COMP%]:active, .message-input-box-textarea[_ngcontent-%COMP%]:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n}\n\n.send-button-icon[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n.send-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: scale(1.05);\n}\n.send-button-icon[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: scale(0.95);\n}\n.send-button-icon[_ngcontent-%COMP%]:disabled {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n\n\n.attach-buttons[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0.75rem;\n right: 3rem;\n display: flex;\n gap: 2px;\n}\n.attach-button-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n.attach-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-text-primary) 5%, transparent);\n color: var(--mj-brand-primary);\n transform: scale(1.05);\n}\n.attach-button-icon[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: scale(0.95);\n}\n.attach-button-icon[_ngcontent-%COMP%]:disabled {\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n\n\n\n.plan-mode-button-icon--active[_ngcontent-%COMP%]:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.plan-mode-button-icon--active[_ngcontent-%COMP%]:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n\n\n\n.skills-button-icon--active[_ngcontent-%COMP%]:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.skills-button-icon--active[_ngcontent-%COMP%]:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n\n\n@media (max-width: 768px) {\n .message-input-box-container[_ngcontent-%COMP%] {\n border-radius: 10px;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 6%, transparent);\n }\n .message-input-box-textarea[_ngcontent-%COMP%] {\n min-height: 80px;\n padding: 0.75rem;\n padding-right: 3rem;\n font-size: 16px;\n line-height: 1.4;\n }\n .send-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n bottom: 0.625rem;\n right: 0.625rem;\n border-radius: 6px;\n }\n .send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n .attach-buttons[_ngcontent-%COMP%] {\n bottom: 0.625rem;\n right: 2.75rem;\n }\n .attach-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n@media (max-width: 480px) {\n .message-input-box-container[_ngcontent-%COMP%] {\n border-radius: 8px;\n border-width: 1.5px;\n }\n .message-input-box-textarea[_ngcontent-%COMP%] {\n min-height: 60px;\n padding: 0.625rem;\n padding-right: 2.75rem;\n font-size: 16px;\n line-height: 1.3;\n }\n .send-button-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n bottom: 0.5rem;\n right: 0.5rem;\n border-radius: 6px;\n }\n .send-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n .attach-buttons[_ngcontent-%COMP%] {\n bottom: 0.5rem;\n right: 2.75rem;\n }\n .attach-button-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n\n\n\n\n.voice-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.voice-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) i[_ngcontent-%COMP%] {\n filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mj-brand-primary) 55%, transparent));\n}\n.voice-button-icon[_ngcontent-%COMP%]:disabled i[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n.voice-button-icon--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n.voice-button-icon--active[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n\n\n\n\n\n.voice-options-button-icon[_ngcontent-%COMP%] {\n width: 20px;\n margin-left: -4px;\n}\n.voice-options-button-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n.voice-options-button-icon[_ngcontent-%COMP%]:hover:not(:disabled) i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.voice-options-button-icon[_ngcontent-%COMP%]:disabled i[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}"] });
|
|
287
383
|
}
|
|
288
384
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MessageInputBoxComponent, [{
|
|
289
385
|
type: Component,
|
|
290
|
-
args: [{ standalone: false, selector: 'mj-message-input-box', template: "<div class=\"message-input-box-container\" (click)=\"onContainerClick($event)\">\n <div class=\"input-wrapper\">\n <mj-mention-editor\n #mentionEditor\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [currentUser]=\"currentUser\"\n [enableMentions]=\"enableMentions\"\n [TriggerProviders]=\"TriggerProviders\"\n [ExcludedTriggerKeys]=\"ExcludedTriggerKeys\"\n [Provider]=\"Provider\"\n [enableAttachments]=\"enableAttachments\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [(ngModel)]=\"value\"\n (valueChange)=\"onValueChange($event)\"\n (enterPressed)=\"onEnterPressed($event)\"\n (mentionSelected)=\"onMentionSelected($event)\"\n (attachmentsChanged)=\"onAttachmentsChanged($event)\"\n (attachmentError)=\"onAttachmentError($event)\"\n (attachmentClicked)=\"onAttachmentClicked($event)\"\n (editorBlurred)=\"blurred.emit()\">\n </mj-mention-editor>\n\n <!-- Attach + voice + plan-mode buttons - Positioned over editor -->\n @if (enableAttachments || enableRealtime || enablePlanMode) {\n <div class=\"attach-buttons\">\n @if (enablePlanMode) {\n <button\n class=\"attach-button-icon plan-mode-button-icon\"\n [class.plan-mode-button-icon--active]=\"planModeActive\"\n [disabled]=\"disabled\"\n [attr.aria-pressed]=\"planModeActive\"\n (click)=\"planModeToggle.emit(); $event.stopPropagation()\"\n [title]=\"planModeActive ? 'Plan Mode ON \u2014 the agent presents a plan for your approval before it acts' : 'Plan Mode: have the agent present a plan for your approval before it acts'\"\n aria-label=\"Toggle Plan Mode\"\n >\n <i class=\"fa-solid fa-route\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (enableAttachments) {\n <button\n class=\"attach-button-icon\"\n [disabled]=\"disabled\"\n (click)=\"openFilePicker(); $event.stopPropagation()\"\n title=\"Attach file\"\n >\n <i class=\"fa-solid fa-paperclip\"></i>\n </button>\n }\n @if (enableRealtime) {\n <button\n class=\"attach-button-icon voice-button-icon\"\n [class.voice-button-icon--active]=\"voiceActive\"\n [disabled]=\"!canStartRealtime\"\n (click)=\"onRealtimeClick(); $event.stopPropagation()\"\n [title]=\"voiceActive ? 'Voice call active' : 'Start a voice call'\"\n aria-label=\"Start a voice call\"\n >\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n </button>\n <!-- Caret beside the phone: opens the agent/model picker so call OPTIONS stay one\n click away while the plain phone click keeps its instant-start behavior. -->\n <button\n class=\"attach-button-icon voice-options-button-icon\"\n [disabled]=\"!canStartRealtime\"\n (click)=\"onRealtimeOptionsClick(); $event.stopPropagation()\"\n title=\"Voice call options (choose agent and voice model)\"\n aria-label=\"Voice call options\"\n >\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Send Button (Icon Only) - Positioned over editor -->\n <button\n class=\"send-button-icon\"\n [disabled]=\"!canSend\"\n (click)=\"onSendClick()\"\n title=\"Send message (Enter)\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n</div>\n", styles: [".message-input-box-container {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n overflow: visible;\n position: relative;\n cursor: text;\n}\n.message-input-box-container:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: flex-end;\n padding: 5px;\n}\n.input-wrapper mj-mention-editor {\n flex: 1;\n display: block;\n}\n\n.message-input-box-textarea {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem;\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n color: var(--mj-text-primary);\n border: 0 !important;\n}\n.message-input-box-textarea::placeholder {\n color: var(--mj-text-muted);\n}\n.message-input-box-textarea:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--mj-bg-surface-sunken);\n}\n.message-input-box-textarea:focus, .message-input-box-textarea:active, .message-input-box-textarea:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n}\n\n.send-button-icon {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.send-button-icon i {\n font-size: 1rem;\n}\n.send-button-icon:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: scale(1.05);\n}\n.send-button-icon:active:not(:disabled) {\n transform: scale(0.95);\n}\n.send-button-icon:disabled {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Attach buttons container */\n.attach-buttons {\n position: absolute;\n bottom: 0.75rem;\n right: 3rem;\n display: flex;\n gap: 2px;\n}\n.attach-button-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.attach-button-icon i {\n font-size: 1rem;\n}\n.attach-button-icon:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-text-primary) 5%, transparent);\n color: var(--mj-brand-primary);\n transform: scale(1.05);\n}\n.attach-button-icon:active:not(:disabled) {\n transform: scale(0.95);\n}\n.attach-button-icon:disabled {\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Plan Mode toggle \u2014 inherits .attach-button-icon; when active it fills with the brand color\n so the on/off state reads clearly at a glance (parallels the voice button's active state). */\n.plan-mode-button-icon--active:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.plan-mode-button-icon--active:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n/* Mobile adjustments: 481px - 768px */\n@media (max-width: 768px) {\n .message-input-box-container {\n border-radius: 10px;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 6%, transparent);\n }\n .message-input-box-textarea {\n min-height: 80px;\n padding: 0.75rem;\n padding-right: 3rem;\n font-size: 16px;\n line-height: 1.4;\n }\n .send-button-icon {\n width: 32px;\n height: 32px;\n bottom: 0.625rem;\n right: 0.625rem;\n border-radius: 6px;\n }\n .send-button-icon i {\n font-size: 0.875rem;\n }\n .attach-buttons {\n bottom: 0.625rem;\n right: 2.75rem;\n }\n .attach-button-icon {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon i {\n font-size: 0.875rem;\n }\n}\n/* Small Phone adjustments: <= 480px */\n@media (max-width: 480px) {\n .message-input-box-container {\n border-radius: 8px;\n border-width: 1.5px;\n }\n .message-input-box-textarea {\n min-height: 60px;\n padding: 0.625rem;\n padding-right: 2.75rem;\n font-size: 16px;\n line-height: 1.3;\n }\n .send-button-icon {\n width: 36px;\n height: 36px;\n bottom: 0.5rem;\n right: 0.5rem;\n border-radius: 6px;\n }\n .send-button-icon i {\n font-size: 0.875rem;\n }\n .attach-buttons {\n bottom: 0.5rem;\n right: 2.75rem;\n }\n .attach-button-icon {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon i {\n font-size: 0.875rem;\n }\n}\n\n/* Voice call button \u2014 a phone icon in the attach-buttons cluster, left of send.\n Inherits .attach-button-icon base. Subtle brand glow on hover; active state (call\n live) renders a brand-color tint. The orb visual now lives ONLY inside the call\n overlay's banner. */\n.voice-button-icon i {\n color: var(--mj-brand-primary);\n}\n.voice-button-icon:hover:not(:disabled) i {\n filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mj-brand-primary) 55%, transparent));\n}\n.voice-button-icon:disabled i {\n color: var(--mj-text-disabled);\n}\n.voice-button-icon--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n.voice-button-icon--active:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n\n/* Voice OPTIONS caret \u2014 a slim chevron hugging the phone button. Opens the agent/model\n picker; intentionally quieter (smaller icon, narrower hit area) than the phone so the\n common instant-start click stays the visual primary. */\n.voice-options-button-icon {\n width: 20px;\n margin-left: -4px;\n}\n.voice-options-button-icon i {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n.voice-options-button-icon:hover:not(:disabled) i {\n color: var(--mj-brand-primary);\n}\n.voice-options-button-icon:disabled i {\n color: var(--mj-text-disabled);\n}\n"] }]
|
|
386
|
+
args: [{ standalone: false, selector: 'mj-message-input-box', template: "<div class=\"message-input-box-container\" (click)=\"OnContainerClick($event)\">\n <div class=\"input-wrapper\">\n <mj-mention-editor\n #mentionEditor\n [placeholder]=\"Placeholder\"\n [disabled]=\"Disabled\"\n [currentUser]=\"CurrentUser\"\n [enableMentions]=\"EnableMentions\"\n [TriggerProviders]=\"TriggerProviders\"\n [ExcludedTriggerKeys]=\"ExcludedTriggerKeys\"\n [Provider]=\"Provider\"\n [enableAttachments]=\"EnableAttachments\"\n [maxAttachments]=\"MaxAttachments\"\n [maxAttachmentSizeBytes]=\"MaxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"AcceptedFileTypes\"\n [(ngModel)]=\"Value\"\n (valueChange)=\"OnValueChange($event)\"\n (enterPressed)=\"OnEnterPressed($event)\"\n (mentionSelected)=\"OnMentionSelected($event)\"\n (attachmentsChanged)=\"OnAttachmentsChanged($event)\"\n (attachmentError)=\"OnAttachmentError($event)\"\n (attachmentClicked)=\"OnAttachmentClicked($event)\"\n (editorBlurred)=\"Blurred.emit()\">\n </mj-mention-editor>\n\n <!-- Attach + voice + plan-mode buttons - Positioned over editor -->\n @if (EnableAttachments || EnableRealtime || EnablePlanMode || EnableSkills) {\n <div class=\"attach-buttons\">\n @if (EnableSkills) {\n <button\n class=\"attach-button-icon skills-button-icon\"\n [class.skills-button-icon--active]=\"SkillsActive\"\n [disabled]=\"Disabled\"\n [attr.aria-expanded]=\"SkillsActive\"\n aria-haspopup=\"true\"\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation()\"\n (click)=\"OnSkillsClick($event); $event.stopPropagation()\"\n title=\"Skills, or type / in the message box\"\n aria-label=\"Show skills\"\n >\n <i class=\"fa-solid fa-wand-magic-sparkles\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (EnablePlanMode) {\n <button\n class=\"attach-button-icon plan-mode-button-icon\"\n [class.plan-mode-button-icon--active]=\"PlanModeActive\"\n [disabled]=\"Disabled\"\n [attr.aria-pressed]=\"PlanModeActive\"\n (click)=\"PlanModeToggle.emit(); $event.stopPropagation()\"\n [title]=\"PlanModeActive ? 'Plan Mode ON \u2014 the agent presents a plan for your approval before it acts' : 'Plan Mode: have the agent present a plan for your approval before it acts'\"\n aria-label=\"Toggle Plan Mode\"\n >\n <i class=\"fa-solid fa-route\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (EnableAttachments) {\n <button\n class=\"attach-button-icon\"\n [disabled]=\"Disabled\"\n (click)=\"OpenFilePicker(); $event.stopPropagation()\"\n title=\"Attach file\"\n >\n <i class=\"fa-solid fa-paperclip\"></i>\n </button>\n }\n @if (EnableRealtime) {\n <button\n class=\"attach-button-icon voice-button-icon\"\n [class.voice-button-icon--active]=\"VoiceActive\"\n [disabled]=\"!CanStartRealtime\"\n (click)=\"OnRealtimeClick(); $event.stopPropagation()\"\n [title]=\"VoiceActive ? 'Voice call active' : 'Start a voice call'\"\n aria-label=\"Start a voice call\"\n >\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n </button>\n <!-- Caret beside the phone: opens the agent/model picker so call OPTIONS stay one\n click away while the plain phone click keeps its instant-start behavior. -->\n <button\n class=\"attach-button-icon voice-options-button-icon\"\n [disabled]=\"!CanStartRealtime\"\n (click)=\"OnRealtimeOptionsClick(); $event.stopPropagation()\"\n title=\"Voice call options (choose agent and voice model)\"\n aria-label=\"Voice call options\"\n >\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Send Button (Icon Only) - Positioned over editor -->\n <button\n class=\"send-button-icon\"\n [disabled]=\"!CanSend\"\n (click)=\"OnSendClick()\"\n title=\"Send message (Enter)\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n</div>\n", styles: [".message-input-box-container {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n overflow: visible;\n position: relative;\n cursor: text;\n}\n.message-input-box-container:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: flex-end;\n padding: 5px;\n}\n.input-wrapper mj-mention-editor {\n flex: 1;\n display: block;\n}\n\n.message-input-box-textarea {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem;\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n color: var(--mj-text-primary);\n border: 0 !important;\n}\n.message-input-box-textarea::placeholder {\n color: var(--mj-text-muted);\n}\n.message-input-box-textarea:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--mj-bg-surface-sunken);\n}\n.message-input-box-textarea:focus, .message-input-box-textarea:active, .message-input-box-textarea:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n}\n\n.send-button-icon {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.send-button-icon i {\n font-size: 1rem;\n}\n.send-button-icon:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: scale(1.05);\n}\n.send-button-icon:active:not(:disabled) {\n transform: scale(0.95);\n}\n.send-button-icon:disabled {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Attach buttons container */\n.attach-buttons {\n position: absolute;\n bottom: 0.75rem;\n right: 3rem;\n display: flex;\n gap: 2px;\n}\n.attach-button-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n.attach-button-icon i {\n font-size: 1rem;\n}\n.attach-button-icon:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-text-primary) 5%, transparent);\n color: var(--mj-brand-primary);\n transform: scale(1.05);\n}\n.attach-button-icon:active:not(:disabled) {\n transform: scale(0.95);\n}\n.attach-button-icon:disabled {\n color: var(--mj-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Plan Mode toggle \u2014 inherits .attach-button-icon; when active it fills with the brand color\n so the on/off state reads clearly at a glance (parallels the voice button's active state). */\n.plan-mode-button-icon--active:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.plan-mode-button-icon--active:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n/* Same active treatment as Plan Mode \u2014 the two are peers in the strip, so a different one would\n read as a different KIND of control. Everything else comes from .attach-button-icon. */\n.skills-button-icon--active:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.skills-button-icon--active:not(:disabled):hover {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n color: var(--mj-text-inverse);\n}\n\n/* Mobile adjustments: 481px - 768px */\n@media (max-width: 768px) {\n .message-input-box-container {\n border-radius: 10px;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 6%, transparent);\n }\n .message-input-box-textarea {\n min-height: 80px;\n padding: 0.75rem;\n padding-right: 3rem;\n font-size: 16px;\n line-height: 1.4;\n }\n .send-button-icon {\n width: 32px;\n height: 32px;\n bottom: 0.625rem;\n right: 0.625rem;\n border-radius: 6px;\n }\n .send-button-icon i {\n font-size: 0.875rem;\n }\n .attach-buttons {\n bottom: 0.625rem;\n right: 2.75rem;\n }\n .attach-button-icon {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon i {\n font-size: 0.875rem;\n }\n}\n/* Small Phone adjustments: <= 480px */\n@media (max-width: 480px) {\n .message-input-box-container {\n border-radius: 8px;\n border-width: 1.5px;\n }\n .message-input-box-textarea {\n min-height: 60px;\n padding: 0.625rem;\n padding-right: 2.75rem;\n font-size: 16px;\n line-height: 1.3;\n }\n .send-button-icon {\n width: 36px;\n height: 36px;\n bottom: 0.5rem;\n right: 0.5rem;\n border-radius: 6px;\n }\n .send-button-icon i {\n font-size: 0.875rem;\n }\n .attach-buttons {\n bottom: 0.5rem;\n right: 2.75rem;\n }\n .attach-button-icon {\n width: 32px;\n height: 32px;\n }\n .attach-button-icon i {\n font-size: 0.875rem;\n }\n}\n\n/* Voice call button \u2014 a phone icon in the attach-buttons cluster, left of send.\n Inherits .attach-button-icon base. Subtle brand glow on hover; active state (call\n live) renders a brand-color tint. The orb visual now lives ONLY inside the call\n overlay's banner. */\n.voice-button-icon i {\n color: var(--mj-brand-primary);\n}\n.voice-button-icon:hover:not(:disabled) i {\n filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mj-brand-primary) 55%, transparent));\n}\n.voice-button-icon:disabled i {\n color: var(--mj-text-disabled);\n}\n.voice-button-icon--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n.voice-button-icon--active:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n\n/* Voice OPTIONS caret \u2014 a slim chevron hugging the phone button. Opens the agent/model\n picker; intentionally quieter (smaller icon, narrower hit area) than the phone so the\n common instant-start click stays the visual primary. */\n.voice-options-button-icon {\n width: 20px;\n margin-left: -4px;\n}\n.voice-options-button-icon i {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n.voice-options-button-icon:hover:not(:disabled) i {\n color: var(--mj-brand-primary);\n}\n.voice-options-button-icon:disabled i {\n color: var(--mj-text-disabled);\n}\n"] }]
|
|
291
387
|
}], null, { mentionEditor: [{
|
|
292
388
|
type: ViewChild,
|
|
293
389
|
args: ['mentionEditor']
|
|
294
|
-
}],
|
|
390
|
+
}], Placeholder: [{
|
|
295
391
|
type: Input
|
|
296
|
-
}],
|
|
392
|
+
}], Disabled: [{
|
|
297
393
|
type: Input
|
|
298
|
-
}],
|
|
394
|
+
}], Value: [{
|
|
299
395
|
type: Input
|
|
300
|
-
}],
|
|
396
|
+
}], ShowCharacterCount: [{
|
|
301
397
|
type: Input
|
|
302
|
-
}],
|
|
398
|
+
}], EnableMentions: [{
|
|
303
399
|
type: Input
|
|
304
400
|
}], TriggerProviders: [{
|
|
305
401
|
type: Input
|
|
@@ -307,46 +403,52 @@ export class MessageInputBoxComponent {
|
|
|
307
403
|
type: Input
|
|
308
404
|
}], Provider: [{
|
|
309
405
|
type: Input
|
|
310
|
-
}],
|
|
406
|
+
}], CurrentUser: [{
|
|
311
407
|
type: Input
|
|
312
|
-
}],
|
|
408
|
+
}], Rows: [{
|
|
313
409
|
type: Input
|
|
314
|
-
}],
|
|
410
|
+
}], EnableAttachments: [{
|
|
315
411
|
type: Input
|
|
316
|
-
}],
|
|
412
|
+
}], MaxAttachments: [{
|
|
317
413
|
type: Input
|
|
318
|
-
}],
|
|
414
|
+
}], MaxAttachmentSizeBytes: [{
|
|
319
415
|
type: Input
|
|
320
|
-
}],
|
|
416
|
+
}], AcceptedFileTypes: [{
|
|
321
417
|
type: Input
|
|
322
|
-
}],
|
|
418
|
+
}], EnableRealtime: [{
|
|
323
419
|
type: Input
|
|
324
|
-
}],
|
|
420
|
+
}], VoiceActive: [{
|
|
325
421
|
type: Input
|
|
326
|
-
}],
|
|
422
|
+
}], CanStartRealtime: [{
|
|
327
423
|
type: Input
|
|
328
|
-
}],
|
|
424
|
+
}], EnablePlanMode: [{
|
|
329
425
|
type: Input
|
|
330
|
-
}],
|
|
426
|
+
}], PlanModeActive: [{
|
|
331
427
|
type: Input
|
|
332
|
-
}],
|
|
428
|
+
}], EnableSkills: [{
|
|
429
|
+
type: Input
|
|
430
|
+
}], Blurred: [{
|
|
431
|
+
type: Output
|
|
432
|
+
}], TextSubmitted: [{
|
|
433
|
+
type: Output
|
|
434
|
+
}], ValueChange: [{
|
|
333
435
|
type: Output
|
|
334
|
-
}],
|
|
436
|
+
}], AttachmentsChanged: [{
|
|
335
437
|
type: Output
|
|
336
|
-
}],
|
|
438
|
+
}], AttachmentError: [{
|
|
337
439
|
type: Output
|
|
338
|
-
}],
|
|
440
|
+
}], AttachmentClicked: [{
|
|
339
441
|
type: Output
|
|
340
|
-
}],
|
|
442
|
+
}], VoiceRequested: [{
|
|
341
443
|
type: Output
|
|
342
|
-
}],
|
|
444
|
+
}], VoiceOptionsRequested: [{
|
|
343
445
|
type: Output
|
|
344
|
-
}],
|
|
446
|
+
}], PlanModeToggle: [{
|
|
345
447
|
type: Output
|
|
346
|
-
}],
|
|
448
|
+
}], BeforeSkillsOpened: [{
|
|
347
449
|
type: Output
|
|
348
|
-
}],
|
|
450
|
+
}], AfterSkillsOpened: [{
|
|
349
451
|
type: Output
|
|
350
452
|
}] }); })();
|
|
351
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputBoxComponent, { className: "MessageInputBoxComponent", filePath: "src/lib/components/message/message-input-box.component.ts", lineNumber:
|
|
453
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputBoxComponent, { className: "MessageInputBoxComponent", filePath: "src/lib/components/message/message-input-box.component.ts", lineNumber: 28 }); })();
|
|
352
454
|
//# sourceMappingURL=message-input-box.component.js.map
|