@memberjunction/ng-conversations 2.129.0 → 2.130.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/attachment/image-viewer.component.d.ts +95 -0
- package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -0
- package/dist/lib/components/attachment/image-viewer.component.js +293 -0
- package/dist/lib/components/attachment/image-viewer.component.js.map +1 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +86 -25
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +524 -348
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +12 -3
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.js +68 -55
- package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +2 -0
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +157 -145
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +102 -5
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +349 -21
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +3 -2
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +29 -2
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +79 -12
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +56 -4
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +227 -60
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +34 -1
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +181 -93
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +4 -1
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +12 -1
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +44 -13
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +82 -108
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +26 -25
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +7 -3
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/services/active-tasks.service.d.ts +23 -0
- package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
- package/dist/lib/services/active-tasks.service.js +91 -2
- package/dist/lib/services/active-tasks.service.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +2 -0
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +20 -3
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +36 -5
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +233 -71
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts +79 -0
- package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -0
- package/dist/lib/services/conversation-attachment.service.js +327 -0
- package/dist/lib/services/conversation-attachment.service.js.map +1 -0
- package/dist/lib/services/conversation-data.service.d.ts +15 -1
- package/dist/lib/services/conversation-data.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-data.service.js +23 -1
- package/dist/lib/services/conversation-data.service.js.map +1 -1
- package/dist/lib/services/conversation-streaming.service.d.ts +50 -1
- package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-streaming.service.js +92 -4
- package/dist/lib/services/conversation-streaming.service.js.map +1 -1
- package/dist/lib/services/mention-parser.service.d.ts +15 -0
- package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
- package/dist/lib/services/mention-parser.service.js +30 -0
- package/dist/lib/services/mention-parser.service.js.map +1 -1
- package/dist/public-api.d.ts +2 -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 +17 -17
|
@@ -6,14 +6,63 @@ import * as i1 from "../../services/mention-autocomplete.service";
|
|
|
6
6
|
import * as i2 from "@angular/common";
|
|
7
7
|
import * as i3 from "./mention-dropdown.component";
|
|
8
8
|
const _c0 = ["editor"];
|
|
9
|
-
function
|
|
9
|
+
function MentionEditorComponent_div_1_div_1_img_1_Template(rf, ctx) { if (rf & 1) {
|
|
10
|
+
i0.ɵɵelement(0, "img", 13);
|
|
11
|
+
} if (rf & 2) {
|
|
12
|
+
const attachment_r3 = i0.ɵɵnextContext().$implicit;
|
|
13
|
+
i0.ɵɵproperty("src", attachment_r3.thumbnailUrl, i0.ɵɵsanitizeUrl)("alt", attachment_r3.fileName);
|
|
14
|
+
} }
|
|
15
|
+
function MentionEditorComponent_div_1_div_1_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
16
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
17
|
+
i0.ɵɵelement(1, "i", 15);
|
|
18
|
+
i0.ɵɵelementStart(2, "span", 16);
|
|
19
|
+
i0.ɵɵtext(3);
|
|
20
|
+
i0.ɵɵelementEnd()();
|
|
21
|
+
} if (rf & 2) {
|
|
22
|
+
const attachment_r3 = i0.ɵɵnextContext().$implicit;
|
|
23
|
+
i0.ɵɵadvance(3);
|
|
24
|
+
i0.ɵɵtextInterpolate(attachment_r3.fileName);
|
|
25
|
+
} }
|
|
26
|
+
function MentionEditorComponent_div_1_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
10
27
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
11
|
-
i0.ɵɵelementStart(0, "
|
|
12
|
-
i0.ɵɵlistener("
|
|
28
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
29
|
+
i0.ɵɵlistener("click", function MentionEditorComponent_div_1_div_1_Template_div_click_0_listener() { const attachment_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onAttachmentClick(attachment_r3)); });
|
|
30
|
+
i0.ɵɵtemplate(1, MentionEditorComponent_div_1_div_1_img_1_Template, 1, 2, "img", 9)(2, MentionEditorComponent_div_1_div_1_div_2_Template, 4, 1, "div", 10);
|
|
31
|
+
i0.ɵɵelementStart(3, "button", 11);
|
|
32
|
+
i0.ɵɵlistener("click", function MentionEditorComponent_div_1_div_1_Template_button_click_3_listener($event) { const attachment_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); ctx_r3.removeAttachment(attachment_r3.id); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
33
|
+
i0.ɵɵelement(4, "i", 12);
|
|
34
|
+
i0.ɵɵelementEnd()();
|
|
35
|
+
} if (rf & 2) {
|
|
36
|
+
const attachment_r3 = ctx.$implicit;
|
|
37
|
+
i0.ɵɵadvance();
|
|
38
|
+
i0.ɵɵproperty("ngIf", attachment_r3.thumbnailUrl);
|
|
39
|
+
i0.ɵɵadvance();
|
|
40
|
+
i0.ɵɵproperty("ngIf", !attachment_r3.thumbnailUrl);
|
|
41
|
+
} }
|
|
42
|
+
function MentionEditorComponent_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
43
|
+
i0.ɵɵelementStart(0, "div", 6);
|
|
44
|
+
i0.ɵɵtemplate(1, MentionEditorComponent_div_1_div_1_Template, 5, 2, "div", 7);
|
|
45
|
+
i0.ɵɵelementEnd();
|
|
46
|
+
} if (rf & 2) {
|
|
47
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
48
|
+
i0.ɵɵadvance();
|
|
49
|
+
i0.ɵɵproperty("ngForOf", ctx_r3.pendingAttachments);
|
|
50
|
+
} }
|
|
51
|
+
function MentionEditorComponent_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
52
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "div", 18);
|
|
53
|
+
i0.ɵɵelement(2, "i", 19);
|
|
54
|
+
i0.ɵɵelementStart(3, "span");
|
|
55
|
+
i0.ɵɵtext(4, "Drop files here");
|
|
56
|
+
i0.ɵɵelementEnd()()();
|
|
57
|
+
} }
|
|
58
|
+
function MentionEditorComponent_mj_mention_dropdown_5_Template(rf, ctx) { if (rf & 1) {
|
|
59
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
60
|
+
i0.ɵɵelementStart(0, "mj-mention-dropdown", 20);
|
|
61
|
+
i0.ɵɵlistener("suggestionSelected", function MentionEditorComponent_mj_mention_dropdown_5_Template_mj_mention_dropdown_suggestionSelected_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onMentionSelected($event)); })("closed", function MentionEditorComponent_mj_mention_dropdown_5_Template_mj_mention_dropdown_closed_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeMentionDropdown()); });
|
|
13
62
|
i0.ɵɵelementEnd();
|
|
14
63
|
} if (rf & 2) {
|
|
15
|
-
const
|
|
16
|
-
i0.ɵɵproperty("suggestions",
|
|
64
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
65
|
+
i0.ɵɵproperty("suggestions", ctx_r3.mentionSuggestions)("position", ctx_r3.mentionDropdownPosition)("showAbove", ctx_r3.mentionDropdownShowAbove)("useFixedPositioning", true)("visible", true);
|
|
17
66
|
} }
|
|
18
67
|
/**
|
|
19
68
|
* ContentEditable-based mention editor with visual chips/pills
|
|
@@ -21,14 +70,26 @@ function MentionEditorComponent_mj_mention_dropdown_3_Template(rf, ctx) { if (rf
|
|
|
21
70
|
*/
|
|
22
71
|
export class MentionEditorComponent {
|
|
23
72
|
mentionAutocomplete;
|
|
73
|
+
cdr;
|
|
24
74
|
editorRef;
|
|
25
75
|
placeholder = 'Type @ to mention agents or users...';
|
|
26
76
|
disabled = false;
|
|
27
77
|
currentUser;
|
|
28
78
|
enableMentions = true;
|
|
79
|
+
// Attachment settings
|
|
80
|
+
enableAttachments = true;
|
|
81
|
+
maxAttachments = 10;
|
|
82
|
+
maxAttachmentSizeBytes = 20 * 1024 * 1024; // 20MB default
|
|
83
|
+
acceptedFileTypes = 'image/*'; // MIME types to accept
|
|
29
84
|
valueChange = new EventEmitter();
|
|
30
85
|
mentionSelected = new EventEmitter();
|
|
31
86
|
enterPressed = new EventEmitter();
|
|
87
|
+
attachmentsChanged = new EventEmitter();
|
|
88
|
+
attachmentError = new EventEmitter();
|
|
89
|
+
attachmentClicked = new EventEmitter();
|
|
90
|
+
// Pending attachments state
|
|
91
|
+
pendingAttachments = [];
|
|
92
|
+
isDragOver = false;
|
|
32
93
|
// Mention dropdown state
|
|
33
94
|
showMentionDropdown = false;
|
|
34
95
|
mentionSuggestions = [];
|
|
@@ -38,8 +99,9 @@ export class MentionEditorComponent {
|
|
|
38
99
|
mentionQuery = '';
|
|
39
100
|
onChange = () => { };
|
|
40
101
|
onTouched = () => { };
|
|
41
|
-
constructor(mentionAutocomplete) {
|
|
102
|
+
constructor(mentionAutocomplete, cdr) {
|
|
42
103
|
this.mentionAutocomplete = mentionAutocomplete;
|
|
104
|
+
this.cdr = cdr;
|
|
43
105
|
}
|
|
44
106
|
async ngOnInit() {
|
|
45
107
|
if (this.enableMentions && this.currentUser) {
|
|
@@ -98,15 +160,31 @@ export class MentionEditorComponent {
|
|
|
98
160
|
// Use setTimeout to allow mousedown events on dropdown to fire first
|
|
99
161
|
setTimeout(() => {
|
|
100
162
|
if (this.showMentionDropdown) {
|
|
101
|
-
console.log('[MentionEditor] Closing dropdown on blur');
|
|
102
163
|
this.closeMentionDropdown();
|
|
103
164
|
}
|
|
104
165
|
}, 200);
|
|
105
166
|
}
|
|
106
167
|
/**
|
|
107
|
-
* Handle paste event -
|
|
168
|
+
* Handle paste event - images or plain text
|
|
108
169
|
*/
|
|
109
170
|
onPaste(event) {
|
|
171
|
+
// Check for image data in clipboard
|
|
172
|
+
if (this.enableAttachments && event.clipboardData?.items) {
|
|
173
|
+
const items = Array.from(event.clipboardData.items);
|
|
174
|
+
const imageItems = items.filter(item => item.type.startsWith('image/'));
|
|
175
|
+
if (imageItems.length > 0) {
|
|
176
|
+
event.preventDefault();
|
|
177
|
+
// Process each image
|
|
178
|
+
for (const item of imageItems) {
|
|
179
|
+
const file = item.getAsFile();
|
|
180
|
+
if (file) {
|
|
181
|
+
this.processFile(file);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// No images - handle as plain text
|
|
110
188
|
event.preventDefault();
|
|
111
189
|
// Get plain text from clipboard
|
|
112
190
|
const text = event.clipboardData?.getData('text/plain') || '';
|
|
@@ -232,7 +310,6 @@ export class MentionEditorComponent {
|
|
|
232
310
|
* Handle mention selection from dropdown
|
|
233
311
|
*/
|
|
234
312
|
onMentionSelected(suggestion) {
|
|
235
|
-
console.log('[MentionEditor] Mention selected:', suggestion);
|
|
236
313
|
this.insertMentionChip(suggestion);
|
|
237
314
|
this.closeMentionDropdown();
|
|
238
315
|
this.mentionSelected.emit(suggestion);
|
|
@@ -698,13 +775,14 @@ export class MentionEditorComponent {
|
|
|
698
775
|
this.editorRef?.nativeElement?.focus();
|
|
699
776
|
}
|
|
700
777
|
/**
|
|
701
|
-
* Clear the editor content
|
|
778
|
+
* Clear the editor content and pending attachments
|
|
702
779
|
*/
|
|
703
780
|
clear() {
|
|
704
781
|
if (this.editorRef?.nativeElement) {
|
|
705
782
|
this.editorRef.nativeElement.textContent = '';
|
|
706
783
|
this.onInput();
|
|
707
784
|
}
|
|
785
|
+
this.clearPendingAttachments();
|
|
708
786
|
}
|
|
709
787
|
/**
|
|
710
788
|
* Extract mention chips with their configuration data
|
|
@@ -788,33 +866,269 @@ export class MentionEditorComponent {
|
|
|
788
866
|
}
|
|
789
867
|
return plainText;
|
|
790
868
|
}
|
|
791
|
-
|
|
869
|
+
// ==================== Attachment Handling Methods ====================
|
|
870
|
+
/**
|
|
871
|
+
* Handle drag over event
|
|
872
|
+
*/
|
|
873
|
+
onDragOver(event) {
|
|
874
|
+
if (!this.enableAttachments)
|
|
875
|
+
return;
|
|
876
|
+
event.preventDefault();
|
|
877
|
+
event.stopPropagation();
|
|
878
|
+
this.isDragOver = true;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Handle drag leave event
|
|
882
|
+
*/
|
|
883
|
+
onDragLeave(event) {
|
|
884
|
+
event.preventDefault();
|
|
885
|
+
event.stopPropagation();
|
|
886
|
+
this.isDragOver = false;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Handle drop event
|
|
890
|
+
*/
|
|
891
|
+
onDrop(event) {
|
|
892
|
+
if (!this.enableAttachments)
|
|
893
|
+
return;
|
|
894
|
+
event.preventDefault();
|
|
895
|
+
event.stopPropagation();
|
|
896
|
+
this.isDragOver = false;
|
|
897
|
+
if (event.dataTransfer?.files) {
|
|
898
|
+
const files = Array.from(event.dataTransfer.files);
|
|
899
|
+
for (const file of files) {
|
|
900
|
+
if (this.isAcceptedFile(file)) {
|
|
901
|
+
this.processFile(file);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Handle file input change (from file picker)
|
|
908
|
+
*/
|
|
909
|
+
onFileSelected(event) {
|
|
910
|
+
const input = event.target;
|
|
911
|
+
if (input.files) {
|
|
912
|
+
const files = Array.from(input.files);
|
|
913
|
+
for (const file of files) {
|
|
914
|
+
this.processFile(file);
|
|
915
|
+
}
|
|
916
|
+
// Reset input so same file can be selected again
|
|
917
|
+
input.value = '';
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Process a file for attachment
|
|
922
|
+
*/
|
|
923
|
+
async processFile(file) {
|
|
924
|
+
// Validate file
|
|
925
|
+
const validation = this.validateFile(file);
|
|
926
|
+
if (!validation.valid) {
|
|
927
|
+
this.attachmentError.emit(validation.error);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
// Read file as data URL
|
|
931
|
+
const dataUrl = await this.readFileAsDataUrl(file);
|
|
932
|
+
if (!dataUrl) {
|
|
933
|
+
this.attachmentError.emit('Failed to read file');
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
// Get image dimensions if applicable
|
|
937
|
+
let width;
|
|
938
|
+
let height;
|
|
939
|
+
if (file.type.startsWith('image/')) {
|
|
940
|
+
const dimensions = await this.getImageDimensions(dataUrl);
|
|
941
|
+
width = dimensions.width;
|
|
942
|
+
height = dimensions.height;
|
|
943
|
+
}
|
|
944
|
+
// Create pending attachment
|
|
945
|
+
const attachment = {
|
|
946
|
+
id: this.generateAttachmentId(),
|
|
947
|
+
file,
|
|
948
|
+
dataUrl,
|
|
949
|
+
mimeType: file.type,
|
|
950
|
+
fileName: file.name,
|
|
951
|
+
sizeBytes: file.size,
|
|
952
|
+
width,
|
|
953
|
+
height,
|
|
954
|
+
thumbnailUrl: file.type.startsWith('image/') ? dataUrl : undefined
|
|
955
|
+
};
|
|
956
|
+
// Add to pending attachments
|
|
957
|
+
this.pendingAttachments.push(attachment);
|
|
958
|
+
this.attachmentsChanged.emit([...this.pendingAttachments]);
|
|
959
|
+
this.cdr.detectChanges();
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Validate a file against settings
|
|
963
|
+
*/
|
|
964
|
+
validateFile(file) {
|
|
965
|
+
// Check count limit
|
|
966
|
+
if (this.pendingAttachments.length >= this.maxAttachments) {
|
|
967
|
+
return {
|
|
968
|
+
valid: false,
|
|
969
|
+
error: `Maximum ${this.maxAttachments} attachments allowed`
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
// Check size limit
|
|
973
|
+
if (file.size > this.maxAttachmentSizeBytes) {
|
|
974
|
+
const maxMB = (this.maxAttachmentSizeBytes / (1024 * 1024)).toFixed(1);
|
|
975
|
+
const fileMB = (file.size / (1024 * 1024)).toFixed(1);
|
|
976
|
+
return {
|
|
977
|
+
valid: false,
|
|
978
|
+
error: `File size (${fileMB}MB) exceeds maximum (${maxMB}MB)`
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
// Check file type
|
|
982
|
+
if (!this.isAcceptedFile(file)) {
|
|
983
|
+
return {
|
|
984
|
+
valid: false,
|
|
985
|
+
error: `File type ${file.type || 'unknown'} not accepted`
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
return { valid: true };
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Check if file type is accepted
|
|
992
|
+
*/
|
|
993
|
+
isAcceptedFile(file) {
|
|
994
|
+
if (this.acceptedFileTypes === '*' || this.acceptedFileTypes === '*/*') {
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
const acceptedTypes = this.acceptedFileTypes.split(',').map(t => t.trim());
|
|
998
|
+
for (const accepted of acceptedTypes) {
|
|
999
|
+
// Handle wildcard MIME types like "image/*"
|
|
1000
|
+
if (accepted.endsWith('/*')) {
|
|
1001
|
+
const category = accepted.slice(0, -2);
|
|
1002
|
+
if (file.type.startsWith(category + '/')) {
|
|
1003
|
+
return true;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
else if (accepted.startsWith('.')) {
|
|
1007
|
+
// Handle file extensions like ".png"
|
|
1008
|
+
if (file.name.toLowerCase().endsWith(accepted.toLowerCase())) {
|
|
1009
|
+
return true;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
else if (file.type === accepted) {
|
|
1013
|
+
// Exact MIME type match
|
|
1014
|
+
return true;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Read file as data URL
|
|
1021
|
+
*/
|
|
1022
|
+
readFileAsDataUrl(file) {
|
|
1023
|
+
return new Promise((resolve) => {
|
|
1024
|
+
const reader = new FileReader();
|
|
1025
|
+
reader.onload = () => resolve(reader.result);
|
|
1026
|
+
reader.onerror = () => resolve(null);
|
|
1027
|
+
reader.readAsDataURL(file);
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Get image dimensions
|
|
1032
|
+
*/
|
|
1033
|
+
getImageDimensions(dataUrl) {
|
|
1034
|
+
return new Promise((resolve) => {
|
|
1035
|
+
const img = new Image();
|
|
1036
|
+
img.onload = () => {
|
|
1037
|
+
resolve({ width: img.naturalWidth, height: img.naturalHeight });
|
|
1038
|
+
};
|
|
1039
|
+
img.onerror = () => {
|
|
1040
|
+
resolve({ width: 0, height: 0 });
|
|
1041
|
+
};
|
|
1042
|
+
img.src = dataUrl;
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Generate unique attachment ID
|
|
1047
|
+
*/
|
|
1048
|
+
generateAttachmentId() {
|
|
1049
|
+
return `att_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Remove a pending attachment by ID
|
|
1053
|
+
*/
|
|
1054
|
+
removeAttachment(id) {
|
|
1055
|
+
const index = this.pendingAttachments.findIndex(a => a.id === id);
|
|
1056
|
+
if (index !== -1) {
|
|
1057
|
+
this.pendingAttachments.splice(index, 1);
|
|
1058
|
+
this.attachmentsChanged.emit([...this.pendingAttachments]);
|
|
1059
|
+
this.cdr.detectChanges();
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Get all pending attachments
|
|
1064
|
+
*/
|
|
1065
|
+
getPendingAttachments() {
|
|
1066
|
+
return [...this.pendingAttachments];
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Clear all pending attachments
|
|
1070
|
+
*/
|
|
1071
|
+
clearPendingAttachments() {
|
|
1072
|
+
this.pendingAttachments = [];
|
|
1073
|
+
this.attachmentsChanged.emit([]);
|
|
1074
|
+
this.cdr.detectChanges();
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Handle click on an attachment thumbnail
|
|
1078
|
+
*/
|
|
1079
|
+
onAttachmentClick(attachment) {
|
|
1080
|
+
this.attachmentClicked.emit(attachment);
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Check if there are any pending attachments
|
|
1084
|
+
*/
|
|
1085
|
+
hasAttachments() {
|
|
1086
|
+
return this.pendingAttachments.length > 0;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Trigger file picker programmatically
|
|
1090
|
+
*/
|
|
1091
|
+
openFilePicker() {
|
|
1092
|
+
const input = document.createElement('input');
|
|
1093
|
+
input.type = 'file';
|
|
1094
|
+
input.accept = this.acceptedFileTypes;
|
|
1095
|
+
input.multiple = true;
|
|
1096
|
+
input.onchange = (e) => this.onFileSelected(e);
|
|
1097
|
+
input.click();
|
|
1098
|
+
}
|
|
1099
|
+
static ɵfac = function MentionEditorComponent_Factory(t) { return new (t || MentionEditorComponent)(i0.ɵɵdirectiveInject(i1.MentionAutocompleteService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
792
1100
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MentionEditorComponent, selectors: [["mj-mention-editor"]], viewQuery: function MentionEditorComponent_Query(rf, ctx) { if (rf & 1) {
|
|
793
1101
|
i0.ɵɵviewQuery(_c0, 5);
|
|
794
1102
|
} if (rf & 2) {
|
|
795
1103
|
let _t;
|
|
796
1104
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.editorRef = _t.first);
|
|
797
|
-
} }, inputs: { placeholder: "placeholder", disabled: "disabled", currentUser: "currentUser", enableMentions: "enableMentions" }, outputs: { valueChange: "valueChange", mentionSelected: "mentionSelected", enterPressed: "enterPressed" }, features: [i0.ɵɵProvidersFeature([
|
|
1105
|
+
} }, inputs: { placeholder: "placeholder", disabled: "disabled", currentUser: "currentUser", enableMentions: "enableMentions", enableAttachments: "enableAttachments", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes" }, outputs: { valueChange: "valueChange", mentionSelected: "mentionSelected", enterPressed: "enterPressed", attachmentsChanged: "attachmentsChanged", attachmentError: "attachmentError", attachmentClicked: "attachmentClicked" }, features: [i0.ɵɵProvidersFeature([
|
|
798
1106
|
{
|
|
799
1107
|
provide: NG_VALUE_ACCESSOR,
|
|
800
1108
|
useExisting: forwardRef(() => MentionEditorComponent),
|
|
801
1109
|
multi: true
|
|
802
1110
|
}
|
|
803
|
-
])], decls:
|
|
1111
|
+
])], decls: 6, vars: 7, consts: [["editor", ""], [1, "mention-editor-container", 3, "click", "dragover", "dragleave", "drop"], ["class", "pending-attachments", 4, "ngIf"], ["contenteditable", "true", 1, "mention-editor", 3, "input", "keydown", "blur", "paste"], ["class", "drop-overlay", 4, "ngIf"], [3, "suggestions", "position", "showAbove", "useFixedPositioning", "visible", "suggestionSelected", "closed", 4, "ngIf"], [1, "pending-attachments"], ["class", "attachment-thumbnail", 3, "click", 4, "ngFor", "ngForOf"], [1, "attachment-thumbnail", 3, "click"], ["class", "thumbnail-image", 3, "src", "alt", 4, "ngIf"], ["class", "thumbnail-placeholder", 4, "ngIf"], ["title", "Remove attachment", 1, "remove-attachment", 3, "click"], [1, "fa-solid", "fa-times"], [1, "thumbnail-image", 3, "src", "alt"], [1, "thumbnail-placeholder"], [1, "fa-solid", "fa-file"], [1, "file-name"], [1, "drop-overlay"], [1, "drop-message"], [1, "fa-solid", "fa-cloud-arrow-up"], [3, "suggestionSelected", "closed", "suggestions", "position", "showAbove", "useFixedPositioning", "visible"]], template: function MentionEditorComponent_Template(rf, ctx) { if (rf & 1) {
|
|
804
1112
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
805
1113
|
i0.ɵɵelementStart(0, "div", 1);
|
|
806
|
-
i0.ɵɵlistener("click", function MentionEditorComponent_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onContainerClick($event)); });
|
|
807
|
-
i0.ɵɵ
|
|
808
|
-
i0.ɵɵ
|
|
1114
|
+
i0.ɵɵlistener("click", function MentionEditorComponent_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onContainerClick($event)); })("dragover", function MentionEditorComponent_Template_div_dragover_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onDragOver($event)); })("dragleave", function MentionEditorComponent_Template_div_dragleave_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onDragLeave($event)); })("drop", function MentionEditorComponent_Template_div_drop_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onDrop($event)); });
|
|
1115
|
+
i0.ɵɵtemplate(1, MentionEditorComponent_div_1_Template, 2, 1, "div", 2);
|
|
1116
|
+
i0.ɵɵelementStart(2, "div", 3, 0);
|
|
1117
|
+
i0.ɵɵlistener("input", function MentionEditorComponent_Template_div_input_2_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onInput()); })("keydown", function MentionEditorComponent_Template_div_keydown_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onKeyDown($event)); })("blur", function MentionEditorComponent_Template_div_blur_2_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onBlur()); })("paste", function MentionEditorComponent_Template_div_paste_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onPaste($event)); });
|
|
809
1118
|
i0.ɵɵelementEnd();
|
|
810
|
-
i0.ɵɵtemplate(
|
|
1119
|
+
i0.ɵɵtemplate(4, MentionEditorComponent_div_4_Template, 5, 0, "div", 4)(5, MentionEditorComponent_mj_mention_dropdown_5_Template, 1, 5, "mj-mention-dropdown", 5);
|
|
811
1120
|
i0.ɵɵelementEnd();
|
|
812
1121
|
} if (rf & 2) {
|
|
1122
|
+
i0.ɵɵclassProp("drag-over", ctx.isDragOver);
|
|
1123
|
+
i0.ɵɵadvance();
|
|
1124
|
+
i0.ɵɵproperty("ngIf", ctx.pendingAttachments.length > 0);
|
|
813
1125
|
i0.ɵɵadvance();
|
|
814
1126
|
i0.ɵɵattribute("contenteditable", !ctx.disabled)("data-placeholder", ctx.placeholder);
|
|
815
1127
|
i0.ɵɵadvance(2);
|
|
1128
|
+
i0.ɵɵproperty("ngIf", ctx.isDragOver);
|
|
1129
|
+
i0.ɵɵadvance();
|
|
816
1130
|
i0.ɵɵproperty("ngIf", ctx.showMentionDropdown && ctx.enableMentions);
|
|
817
|
-
} }, dependencies: [i2.NgIf, i3.MentionDropdownComponent], styles: [".mention-editor-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n display: block;\n}\n\n.mention-editor[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n min-height: 100px;\n max-height: 300px;\n padding: 7px 3.5rem 7px 12px;\n outline: none;\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n white-space: pre-wrap;\n cursor: text;\n user-select: text;\n box-sizing: border-box;\n}\n.mention-editor[_ngcontent-%COMP%]:empty:before {\n content: attr(data-placeholder);\n color: var(--text-tertiary, #999);\n pointer-events: none;\n position: absolute;\n}\n.mention-editor[_ngcontent-%COMP%]:focus {\n outline: none;\n}\n.mention-editor[contenteditable=false][_ngcontent-%COMP%] {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n}\n@media (max-width: 768px) {\n .mention-editor[_ngcontent-%COMP%] {\n font-size: 16px;\n padding: 5px;\n padding-right: 3rem;\n }\n}\n\n .mention-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n margin: 0 3px;\n border-radius: 16px;\n font-size: 13px;\n font-weight: 600;\n cursor: default;\n user-select: none;\n vertical-align: middle;\n white-space: nowrap;\n pointer-events: all;\n -webkit-user-modify: read-only;\n -moz-user-modify: read-only;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: 2px solid rgba(102, 126, 234, 0.4);\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0, 0, 0, 0.1);\n animation: _ngcontent-%COMP%_chipInsert 0.15s ease-out;\n}\n .mention-chip i {\n font-size: 12px;\n opacity: 0.95;\n}\n .mention-chip[data-mention-type=user] {\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: 2px solid rgba(240, 147, 251, 0.4);\n}\n .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.15);\n transition: all 0.2s ease;\n}\n .mention-chip:focus, .mention-chip.selected {\n outline: 2px solid var(--primary-color, #007bff);\n outline-offset: 2px;\n}\n@keyframes _ngcontent-%COMP%_chipInsert {\n 0% {\n transform: scale(0.8);\n opacity: 0;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n@media (prefers-color-scheme: dark) {\n .mention-editor[_ngcontent-%COMP%] {\n color: black; \n\n \n \n\n }\n .mention-editor[_ngcontent-%COMP%]:empty:before {\n color: #777;\n }\n .mention-editor[contenteditable=false][_ngcontent-%COMP%] {\n background: #2d2d2d;\n }\n .mention-chip[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #4a148c 0%, #6a1b9a 100%);\n color: #ce93d8;\n border-color: #8e24aa;\n }\n .mention-chip[data-mention-type=user][_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #880e4f 0%, #ad1457 100%);\n color: #f48fb1;\n border-color: #c2185b;\n }\n}\n.mention-editor[_ngcontent-%COMP%] .mention-chip[_ngcontent-%COMP%] + .mention-chip[_ngcontent-%COMP%] {\n margin-left: 4px;\n}\n.mention-editor[_ngcontent-%COMP%] br[_ngcontent-%COMP%] {\n display: block;\n content: \"\";\n margin: 0;\n}\n\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}"] });
|
|
1131
|
+
} }, dependencies: [i2.NgForOf, i2.NgIf, i3.MentionDropdownComponent], styles: [".mention-editor-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n display: block;\n}\n\n.mention-editor-container.drag-over[_ngcontent-%COMP%] {\n background: rgba(102, 126, 234, 0.05);\n border-color: #667eea;\n}\n\n.mention-editor[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n min-height: 100px;\n max-height: 300px;\n padding: 7px 3.5rem 7px 12px;\n outline: none;\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n white-space: pre-wrap;\n cursor: text;\n user-select: text;\n box-sizing: border-box;\n}\n.mention-editor[_ngcontent-%COMP%]:empty:before {\n content: attr(data-placeholder);\n color: var(--text-tertiary, #999);\n pointer-events: none;\n position: absolute;\n}\n.mention-editor[_ngcontent-%COMP%]:focus {\n outline: none;\n}\n.mention-editor[contenteditable=false][_ngcontent-%COMP%] {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n}\n@media (max-width: 768px) {\n .mention-editor[_ngcontent-%COMP%] {\n font-size: 16px;\n padding: 5px;\n padding-right: 3rem;\n }\n}\n\n .mention-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n margin: 0 3px;\n border-radius: 16px;\n font-size: 13px;\n font-weight: 600;\n cursor: default;\n user-select: none;\n vertical-align: middle;\n white-space: nowrap;\n pointer-events: all;\n -webkit-user-modify: read-only;\n -moz-user-modify: read-only;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: 2px solid rgba(102, 126, 234, 0.4);\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0, 0, 0, 0.1);\n animation: _ngcontent-%COMP%_chipInsert 0.15s ease-out;\n}\n .mention-chip i {\n font-size: 12px;\n opacity: 0.95;\n}\n .mention-chip[data-mention-type=user] {\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: 2px solid rgba(240, 147, 251, 0.4);\n}\n .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.15);\n transition: all 0.2s ease;\n}\n .mention-chip:focus, .mention-chip.selected {\n outline: 2px solid var(--primary-color, #007bff);\n outline-offset: 2px;\n}\n@keyframes _ngcontent-%COMP%_chipInsert {\n 0% {\n transform: scale(0.8);\n opacity: 0;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n@media (prefers-color-scheme: dark) {\n .mention-editor[_ngcontent-%COMP%] {\n color: black; \n\n \n \n\n }\n .mention-editor[_ngcontent-%COMP%]:empty:before {\n color: #777;\n }\n .mention-editor[contenteditable=false][_ngcontent-%COMP%] {\n background: #2d2d2d;\n }\n .mention-chip[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #4a148c 0%, #6a1b9a 100%);\n color: #ce93d8;\n border-color: #8e24aa;\n }\n .mention-chip[data-mention-type=user][_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #880e4f 0%, #ad1457 100%);\n color: #f48fb1;\n border-color: #c2185b;\n }\n}\n.mention-editor[_ngcontent-%COMP%] .mention-chip[_ngcontent-%COMP%] + .mention-chip[_ngcontent-%COMP%] {\n margin-left: 4px;\n}\n.mention-editor[_ngcontent-%COMP%] br[_ngcontent-%COMP%] {\n display: block;\n content: \"\";\n margin: 0;\n}\n\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n.mention-editor[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n\n\n\n.pending-attachments[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n background: rgba(0, 0, 0, 0.02);\n}\n\n.attachment-thumbnail[_ngcontent-%COMP%] {\n position: relative;\n width: 80px;\n height: 80px;\n border-radius: 8px;\n overflow: hidden;\n cursor: pointer;\n transition: transform 0.2s, box-shadow 0.2s;\n background: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.attachment-thumbnail[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.thumbnail-image[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.thumbnail-placeholder[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 8px;\n color: #666;\n}\n\n.thumbnail-placeholder[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 4px;\n color: #999;\n}\n\n.thumbnail-placeholder[_ngcontent-%COMP%] .file-name[_ngcontent-%COMP%] {\n font-size: 10px;\n text-align: center;\n word-break: break-all;\n line-height: 1.2;\n max-height: 36px;\n overflow: hidden;\n}\n\n.remove-attachment[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: white;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.2s, background 0.2s;\n}\n\n.attachment-thumbnail[_ngcontent-%COMP%]:hover .remove-attachment[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.remove-attachment[_ngcontent-%COMP%]:hover {\n background: rgba(220, 53, 69, 0.9);\n}\n\n.remove-attachment[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.drop-overlay[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n background: rgba(102, 126, 234, 0.15);\n backdrop-filter: blur(2px);\n border: 2px dashed #667eea;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 100;\n pointer-events: none;\n}\n\n.drop-message[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n color: #667eea;\n font-weight: 600;\n}\n\n.drop-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.drop-message[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n@media (prefers-color-scheme: dark) {\n .pending-attachments[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.05);\n border-bottom-color: rgba(255, 255, 255, 0.1);\n }\n\n .attachment-thumbnail[_ngcontent-%COMP%] {\n background: #333;\n border-color: rgba(255, 255, 255, 0.15);\n }\n\n .thumbnail-placeholder[_ngcontent-%COMP%] {\n color: #aaa;\n }\n\n .thumbnail-placeholder[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #777;\n }\n\n .drop-overlay[_ngcontent-%COMP%] {\n background: rgba(102, 126, 234, 0.25);\n }\n}"] });
|
|
818
1132
|
}
|
|
819
1133
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MentionEditorComponent, [{
|
|
820
1134
|
type: Component,
|
|
@@ -824,8 +1138,8 @@ export class MentionEditorComponent {
|
|
|
824
1138
|
useExisting: forwardRef(() => MentionEditorComponent),
|
|
825
1139
|
multi: true
|
|
826
1140
|
}
|
|
827
|
-
], template: "<div class=\"mention-editor-container\"
|
|
828
|
-
}], () => [{ type: i1.MentionAutocompleteService }], { editorRef: [{
|
|
1141
|
+
], template: "<div class=\"mention-editor-container\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onContainerClick($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n\n <!-- Pending Attachments Preview -->\n <div class=\"pending-attachments\" *ngIf=\"pendingAttachments.length > 0\">\n <div class=\"attachment-thumbnail\"\n *ngFor=\"let attachment of pendingAttachments\"\n (click)=\"onAttachmentClick(attachment)\">\n <img *ngIf=\"attachment.thumbnailUrl\"\n [src]=\"attachment.thumbnailUrl\"\n [alt]=\"attachment.fileName\"\n class=\"thumbnail-image\">\n <div *ngIf=\"!attachment.thumbnailUrl\" class=\"thumbnail-placeholder\">\n <i class=\"fa-solid fa-file\"></i>\n <span class=\"file-name\">{{ attachment.fileName }}</span>\n </div>\n <button class=\"remove-attachment\"\n (click)=\"removeAttachment(attachment.id); $event.stopPropagation()\"\n title=\"Remove attachment\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n\n <div\n #editor\n class=\"mention-editor\"\n contenteditable=\"true\"\n [attr.contenteditable]=\"!disabled\"\n [attr.data-placeholder]=\"placeholder\"\n (input)=\"onInput()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n (paste)=\"onPaste($event)\"\n ></div>\n\n <!-- Drag & Drop Overlay -->\n <div class=\"drop-overlay\" *ngIf=\"isDragOver\">\n <div class=\"drop-message\">\n <i class=\"fa-solid fa-cloud-arrow-up\"></i>\n <span>Drop files here</span>\n </div>\n </div>\n\n <!-- Mention Dropdown -->\n <mj-mention-dropdown\n *ngIf=\"showMentionDropdown && enableMentions\"\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [showAbove]=\"mentionDropdownShowAbove\"\n [useFixedPositioning]=\"true\"\n [visible]=\"true\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n</div>\n", styles: [".mention-editor-container {\n position: relative;\n width: 100%;\n display: block;\n}\n\n.mention-editor-container.drag-over {\n background: rgba(102, 126, 234, 0.05);\n border-color: #667eea;\n}\n\n.mention-editor {\n display: block;\n width: 100%;\n min-height: 100px;\n max-height: 300px;\n padding: 7px 3.5rem 7px 12px;\n outline: none;\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n white-space: pre-wrap;\n cursor: text;\n user-select: text;\n box-sizing: border-box;\n}\n.mention-editor:empty:before {\n content: attr(data-placeholder);\n color: var(--text-tertiary, #999);\n pointer-events: none;\n position: absolute;\n}\n.mention-editor:focus {\n outline: none;\n}\n.mention-editor[contenteditable=false] {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n}\n@media (max-width: 768px) {\n .mention-editor {\n font-size: 16px;\n padding: 5px;\n padding-right: 3rem;\n }\n}\n\n::ng-deep .mention-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n margin: 0 3px;\n border-radius: 16px;\n font-size: 13px;\n font-weight: 600;\n cursor: default;\n user-select: none;\n vertical-align: middle;\n white-space: nowrap;\n pointer-events: all;\n -webkit-user-modify: read-only;\n -moz-user-modify: read-only;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: 2px solid rgba(102, 126, 234, 0.4);\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0, 0, 0, 0.1);\n animation: chipInsert 0.15s ease-out;\n}\n::ng-deep .mention-chip i {\n font-size: 12px;\n opacity: 0.95;\n}\n::ng-deep .mention-chip[data-mention-type=user] {\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: 2px solid rgba(240, 147, 251, 0.4);\n}\n::ng-deep .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.15);\n transition: all 0.2s ease;\n}\n::ng-deep .mention-chip:focus, ::ng-deep .mention-chip.selected {\n outline: 2px solid var(--primary-color, #007bff);\n outline-offset: 2px;\n}\n@keyframes chipInsert {\n 0% {\n transform: scale(0.8);\n opacity: 0;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n@media (prefers-color-scheme: dark) {\n .mention-editor {\n color: black; /*computer preference level not yet supported*/\n /*color: #e0e0e0;*/ /*Matt - please work on this - for some as it didn't work*/\n }\n .mention-editor:empty:before {\n color: #777;\n }\n .mention-editor[contenteditable=false] {\n background: #2d2d2d;\n }\n .mention-chip {\n background: linear-gradient(135deg, #4a148c 0%, #6a1b9a 100%);\n color: #ce93d8;\n border-color: #8e24aa;\n }\n .mention-chip[data-mention-type=user] {\n background: linear-gradient(135deg, #880e4f 0%, #ad1457 100%);\n color: #f48fb1;\n border-color: #c2185b;\n }\n}\n.mention-editor .mention-chip + .mention-chip {\n margin-left: 4px;\n}\n.mention-editor br {\n display: block;\n content: \"\";\n margin: 0;\n}\n\n.mention-editor::-webkit-scrollbar {\n width: 6px;\n}\n.mention-editor::-webkit-scrollbar-track {\n background: transparent;\n}\n.mention-editor::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n.mention-editor::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n/* ==================== Attachment Styles ==================== */\n\n.pending-attachments {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n background: rgba(0, 0, 0, 0.02);\n}\n\n.attachment-thumbnail {\n position: relative;\n width: 80px;\n height: 80px;\n border-radius: 8px;\n overflow: hidden;\n cursor: pointer;\n transition: transform 0.2s, box-shadow 0.2s;\n background: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.attachment-thumbnail:hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.thumbnail-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.thumbnail-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 8px;\n color: #666;\n}\n\n.thumbnail-placeholder i {\n font-size: 24px;\n margin-bottom: 4px;\n color: #999;\n}\n\n.thumbnail-placeholder .file-name {\n font-size: 10px;\n text-align: center;\n word-break: break-all;\n line-height: 1.2;\n max-height: 36px;\n overflow: hidden;\n}\n\n.remove-attachment {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: white;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.2s, background 0.2s;\n}\n\n.attachment-thumbnail:hover .remove-attachment {\n opacity: 1;\n}\n\n.remove-attachment:hover {\n background: rgba(220, 53, 69, 0.9);\n}\n\n.remove-attachment i {\n font-size: 10px;\n}\n\n/* Drop Overlay */\n.drop-overlay {\n position: absolute;\n inset: 0;\n background: rgba(102, 126, 234, 0.15);\n backdrop-filter: blur(2px);\n border: 2px dashed #667eea;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 100;\n pointer-events: none;\n}\n\n.drop-message {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n color: #667eea;\n font-weight: 600;\n}\n\n.drop-message i {\n font-size: 32px;\n}\n\n.drop-message span {\n font-size: 14px;\n}\n\n/* Dark Mode for Attachments */\n@media (prefers-color-scheme: dark) {\n .pending-attachments {\n background: rgba(255, 255, 255, 0.05);\n border-bottom-color: rgba(255, 255, 255, 0.1);\n }\n\n .attachment-thumbnail {\n background: #333;\n border-color: rgba(255, 255, 255, 0.15);\n }\n\n .thumbnail-placeholder {\n color: #aaa;\n }\n\n .thumbnail-placeholder i {\n color: #777;\n }\n\n .drop-overlay {\n background: rgba(102, 126, 234, 0.25);\n }\n}\n"] }]
|
|
1142
|
+
}], () => [{ type: i1.MentionAutocompleteService }, { type: i0.ChangeDetectorRef }], { editorRef: [{
|
|
829
1143
|
type: ViewChild,
|
|
830
1144
|
args: ['editor', { static: false }]
|
|
831
1145
|
}], placeholder: [{
|
|
@@ -836,12 +1150,26 @@ export class MentionEditorComponent {
|
|
|
836
1150
|
type: Input
|
|
837
1151
|
}], enableMentions: [{
|
|
838
1152
|
type: Input
|
|
1153
|
+
}], enableAttachments: [{
|
|
1154
|
+
type: Input
|
|
1155
|
+
}], maxAttachments: [{
|
|
1156
|
+
type: Input
|
|
1157
|
+
}], maxAttachmentSizeBytes: [{
|
|
1158
|
+
type: Input
|
|
1159
|
+
}], acceptedFileTypes: [{
|
|
1160
|
+
type: Input
|
|
839
1161
|
}], valueChange: [{
|
|
840
1162
|
type: Output
|
|
841
1163
|
}], mentionSelected: [{
|
|
842
1164
|
type: Output
|
|
843
1165
|
}], enterPressed: [{
|
|
844
1166
|
type: Output
|
|
1167
|
+
}], attachmentsChanged: [{
|
|
1168
|
+
type: Output
|
|
1169
|
+
}], attachmentError: [{
|
|
1170
|
+
type: Output
|
|
1171
|
+
}], attachmentClicked: [{
|
|
1172
|
+
type: Output
|
|
845
1173
|
}] }); })();
|
|
846
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MentionEditorComponent, { className: "MentionEditorComponent", filePath: "src/lib/components/mention/mention-editor.component.ts", lineNumber:
|
|
1174
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MentionEditorComponent, { className: "MentionEditorComponent", filePath: "src/lib/components/mention/mention-editor.component.ts", lineNumber: 61 }); })();
|
|
847
1175
|
//# sourceMappingURL=mention-editor.component.js.map
|