@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.
@@ -1,4 +1,4 @@
1
- import { Component, Input, Output, EventEmitter, ViewChild, forwardRef } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ViewChild, forwardRef, HostListener } from '@angular/core';
2
2
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
3
3
  import { DiscoverComposerTriggerProviders } from '../../composer-trigger-provider';
4
4
  import { UUIDsEqual } from '@memberjunction/global';
@@ -62,7 +62,7 @@ function MentionEditorComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
62
62
  i0.ɵɵelementEnd();
63
63
  } if (rf & 2) {
64
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);
65
+ i0.ɵɵproperty("suggestions", ctx_r3.mentionSuggestions)("position", ctx_r3.mentionDropdownPosition)("showAbove", ctx_r3.mentionDropdownShowAbove)("alignRight", ctx_r3.mentionDropdownAlignRight)("useFixedPositioning", true)("visible", true);
66
66
  } }
67
67
  /**
68
68
  * ContentEditable-based mention editor with visual chips/pills
@@ -70,6 +70,7 @@ function MentionEditorComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
70
70
  */
71
71
  export class MentionEditorComponent {
72
72
  cdr;
73
+ hostRef;
73
74
  editorRef;
74
75
  placeholder = 'Type @ to mention agents or users, # for entities...';
75
76
  disabled = false;
@@ -112,10 +113,32 @@ export class MentionEditorComponent {
112
113
  mentionSuggestions = [];
113
114
  mentionDropdownPosition = { top: 0, left: 0 };
114
115
  mentionDropdownShowAbove = false;
116
+ /** Right-align the dropdown against its anchor. Only the button path sets this. */
117
+ mentionDropdownAlignRight = false;
115
118
  mentionStartIndex = -1;
116
119
  mentionQuery = '';
117
120
  /** The trigger char that opened the current mention dropdown */
118
121
  activeTrigger = '@';
122
+ /**
123
+ * Set while a dropdown was opened by {@link OpenTrigger} rather than by typing.
124
+ *
125
+ * In this mode the trigger character is NOT in the editor — there is nothing to strip on
126
+ * dismissal, and nothing for the user to see until they pick something. It also changes how the
127
+ * query and the chip insertion are measured, since neither can anchor on a character that is not
128
+ * there; {@link virtualTriggerBaseline} stands in for it.
129
+ */
130
+ virtualTriggerOpen = false;
131
+ /** Text length at the moment a virtual trigger opened — the origin for its query and deletion. */
132
+ virtualTriggerBaseline = 0;
133
+ /**
134
+ * The control that opened a virtual trigger, used to anchor the dropdown to it.
135
+ *
136
+ * STICKY for the whole session on purpose. `positionMentionDropdown()` re-runs on every keystroke
137
+ * while the user filters, and once there is text the caret measures real coordinates — so
138
+ * anchoring only on first paint would open at the button and then jump to the far-left caret on
139
+ * the first keypress, which is worse than not anchoring at all.
140
+ */
141
+ virtualTriggerAnchor = null;
119
142
  /**
120
143
  * Monotonic sequence guarding the async suggestion fetch — a response only applies
121
144
  * when no newer keystroke (or dropdown close) has superseded it.
@@ -149,8 +172,39 @@ export class MentionEditorComponent {
149
172
  onTouched = () => { };
150
173
  /** Value written via writeValue() before the view (editorRef) exists — applied in ngAfterViewInit. */
151
174
  pendingWriteValue = null;
152
- constructor(cdr) {
175
+ constructor(cdr, hostRef) {
153
176
  this.cdr = cdr;
177
+ this.hostRef = hostRef;
178
+ }
179
+ /**
180
+ * Close the dropdown when the pointer goes down anywhere outside it.
181
+ *
182
+ * Dismissal previously relied entirely on the editor's blur, which is not enough: clicking a
183
+ * non-focusable area (the message list, page background) does not blur a contenteditable, so the
184
+ * dropdown stayed open with nothing to close it. That was always true for a typed trigger; the
185
+ * Skills button makes it easy to hit, because the button deliberately keeps focus in the editor
186
+ * so the user's next click is the FIRST thing that could dismiss it.
187
+ *
188
+ * `mousedown` rather than `click`: it fires before the browser moves focus, so this decides
189
+ * before blur's own 200ms timer gets involved and the two cannot race.
190
+ *
191
+ * The dropdown renders with fixed positioning but stays inside this component's host, so the
192
+ * containment check covers a click on a suggestion row — which must select, not dismiss.
193
+ */
194
+ onDocumentMouseDown(event) {
195
+ // Also fires for a press still awaiting suggestions: on a cold session the provider load takes
196
+ // hundreds of ms, and without this the user's dismissing click is ignored and the menu pops
197
+ // open afterwards, unbidden. closeMentionDropdown bumps the request sequence, which drops the
198
+ // in-flight response.
199
+ if (!this.showMentionDropdown && !this.virtualTriggerOpen) {
200
+ return;
201
+ }
202
+ const target = event.target;
203
+ if (target && this.hostRef.nativeElement.contains(target)) {
204
+ return;
205
+ }
206
+ this.closeMentionDropdown();
207
+ this.cdr.markForCheck();
154
208
  }
155
209
  async ngOnInit() {
156
210
  // Warm up the active providers (best-effort — a provider that fails to warm
@@ -220,7 +274,7 @@ export class MentionEditorComponent {
220
274
  // Close dropdown when editor loses focus
221
275
  // Use setTimeout to allow mousedown events on dropdown to fire first
222
276
  setTimeout(() => {
223
- if (this.showMentionDropdown) {
277
+ if (this.showMentionDropdown || this.virtualTriggerOpen) {
224
278
  this.closeMentionDropdown();
225
279
  }
226
280
  }, 200);
@@ -272,9 +326,16 @@ export class MentionEditorComponent {
272
326
  * Handle keydown events
273
327
  */
274
328
  onKeyDown(event) {
275
- // Enter alone: Send message (if dropdown not showing)
276
- if (event.key === 'Enter' && !event.shiftKey && !this.showMentionDropdown) {
329
+ // Enter alone: Send message. The dropdown only earns Enter when it has something to pick. A
330
+ // button-opened menu stays open on an empty result set (so the press is not a silent no-op),
331
+ // which made "showing but empty" reachable for the first time — and there Enter was neither
332
+ // handled nor prevented, so it fell through to the contenteditable and inserted a newline
333
+ // instead of sending.
334
+ if (event.key === 'Enter' && !event.shiftKey && (!this.showMentionDropdown || this.mentionSuggestions.length === 0)) {
277
335
  event.preventDefault();
336
+ if (this.showMentionDropdown) {
337
+ this.closeMentionDropdown();
338
+ }
278
339
  const plainText = this.getPlainText();
279
340
  this.enterPressed.emit(plainText);
280
341
  return;
@@ -305,16 +366,33 @@ export class MentionEditorComponent {
305
366
  const range = selection.getRangeAt(0);
306
367
  const textBeforeCursor = this.getTextBeforeCursor(range);
307
368
  // Find the nearest active trigger char before the cursor — whichever is closest wins
369
+ // A button-opened session only recognises trigger characters typed AFTER it opened. Without
370
+ // this floor the scan runs over the whole message, so a URL ('.../docs'), an email ('a@b.io')
371
+ // or a date ('9/11') already in the box is found instead, and the first keystroke either closes
372
+ // the menu the button just opened or filters it by the wrong query. searchFrom is 0 on the
373
+ // typed path, which leaves that path's behaviour byte-for-byte unchanged.
374
+ const searchFrom = this.virtualTriggerOpen ? this.virtualTriggerBaseline : 0;
308
375
  let triggerIndex = -1;
309
376
  let triggerChar = '@';
310
377
  for (const t of activeTriggers) {
311
378
  const idx = textBeforeCursor.lastIndexOf(t);
312
- if (idx > triggerIndex) {
379
+ if (idx >= searchFrom && idx > triggerIndex) {
313
380
  triggerIndex = idx;
314
381
  triggerChar = t;
315
382
  }
316
383
  }
317
384
  if (triggerIndex === -1) {
385
+ // A virtual trigger has no character in the text, so the search above finds nothing. Keep it
386
+ // open and measure the query from where it opened, otherwise the first keystroke after
387
+ // clicking the button would dismiss the list the button just produced.
388
+ if (this.virtualTriggerOpen && textBeforeCursor.length >= this.virtualTriggerBaseline) {
389
+ const query = textBeforeCursor.substring(this.virtualTriggerBaseline);
390
+ if (!query.includes(' ')) {
391
+ this.mentionQuery = query;
392
+ void this.fetchSuggestions(this.activeTrigger, query);
393
+ return;
394
+ }
395
+ }
318
396
  this.closeMentionDropdown();
319
397
  return;
320
398
  }
@@ -324,6 +402,15 @@ export class MentionEditorComponent {
324
402
  this.closeMentionDropdown();
325
403
  return;
326
404
  }
405
+ // A real trigger character now owns the session, so the virtual one must let go: otherwise
406
+ // chip insertion still takes the virtual branch and deletes only the typed tail, orphaning the
407
+ // trigger text, and the menu stays pinned to the button instead of the caret.
408
+ if (this.virtualTriggerOpen) {
409
+ this.virtualTriggerOpen = false;
410
+ this.virtualTriggerBaseline = 0;
411
+ this.virtualTriggerAnchor = null;
412
+ this.mentionDropdownAlignRight = false;
413
+ }
327
414
  // Extract query
328
415
  this.mentionQuery = textAfterTrigger;
329
416
  this.mentionStartIndex = triggerIndex;
@@ -355,6 +442,14 @@ export class MentionEditorComponent {
355
442
  this.showMentionDropdown = true;
356
443
  this.positionMentionDropdown();
357
444
  }
445
+ else if (this.virtualTriggerOpen) {
446
+ // A button press must never be a silent no-op. Closing on empty results is right for a TYPED
447
+ // trigger (the user is mid-word and nothing matched yet), but a host with zero skills clicking
448
+ // the button would get no feedback at all and read it as broken. Staying open surfaces the
449
+ // dropdown's own empty state, which was otherwise unreachable.
450
+ this.showMentionDropdown = true;
451
+ this.positionMentionDropdown();
452
+ }
358
453
  else {
359
454
  this.closeMentionDropdown();
360
455
  }
@@ -382,17 +477,37 @@ export class MentionEditorComponent {
382
477
  const selection = window.getSelection();
383
478
  if (!selection || selection.rangeCount === 0)
384
479
  return;
480
+ // A button-opened trigger anchors to the BUTTON, not the caret. On the typed path the user's
481
+ // eyes and query are at the caret so the caret is right; on the button path nobody is looking at
482
+ // the caret, they are looking at the control they just pressed. Sticky for the session (see
483
+ // virtualTriggerAnchor) so filtering does not yank the menu to the caret on the first keystroke.
484
+ if (this.virtualTriggerOpen && this.virtualTriggerAnchor) {
485
+ this.positionToAnchor(this.virtualTriggerAnchor, containerRect);
486
+ return;
487
+ }
385
488
  const range = selection.getRangeAt(0);
386
- const cursorRect = range.getBoundingClientRect();
489
+ let cursorRect = range.getBoundingClientRect();
490
+ // A collapsed range in an EMPTY editor measures 0x0 at 0,0 in every browser, which pinned the
491
+ // dropdown to the bottom-left corner of the viewport and ran it off screen. Rare while typing
492
+ // (there is text to measure) but the normal case when a BUTTON opens the trigger on an empty
493
+ // composer. Fall back to the editor's own box so the menu lands over the composer either way.
494
+ if (cursorRect.width === 0 && cursorRect.height === 0 && cursorRect.top === 0 && cursorRect.left === 0) {
495
+ const editorRect = editor.getBoundingClientRect();
496
+ cursorRect = editorRect;
497
+ }
387
498
  // Check space below vs above
388
499
  const spaceBelow = window.innerHeight - cursorRect.bottom;
389
500
  const spaceAbove = cursorRect.top;
390
501
  const dropdownHeight = Math.min(this.mentionSuggestions.length * 56, 300);
391
- this.mentionDropdownShowAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;
502
+ // Prefer ABOVE. The composer sits at the bottom of the chat, so a dropdown that grows downward
503
+ // lands on top of the very text being typed. Below is the fallback for the rare host that
504
+ // mounts the composer high in a tall viewport.
505
+ this.mentionDropdownAlignRight = false;
506
+ this.mentionDropdownShowAbove = spaceAbove >= dropdownHeight || spaceAbove > spaceBelow;
392
507
  if (this.mentionDropdownShowAbove) {
393
508
  // Position above, aligning with container top if possible
394
509
  this.mentionDropdownPosition = {
395
- top: containerRect ? containerRect.top + window.scrollY : cursorRect.top + window.scrollY - 4,
510
+ top: (containerRect ? containerRect.top : cursorRect.top) + window.scrollY - 8,
396
511
  left: cursorRect.left + window.scrollX
397
512
  };
398
513
  }
@@ -404,6 +519,66 @@ export class MentionEditorComponent {
404
519
  };
405
520
  }
406
521
  }
522
+ /**
523
+ * Right-align the dropdown above a trigger control, matching where the voice-options picker puts
524
+ * its popover so two buttons in the same strip do not open menus on opposite corners.
525
+ *
526
+ * Right alignment is applied as a transform in CSS (`align-right`) rather than computed here,
527
+ * because the dropdown's width is content-based; `left` is still clamped so no anchor position can
528
+ * push it off the left edge on a narrow viewport.
529
+ */
530
+ positionToAnchor(anchor, containerRect) {
531
+ const GUTTER = 16;
532
+ const rect = anchor.getBoundingClientRect();
533
+ // The dropdown is rendered with `useFixedPositioning`, so `top`/`left` are VIEWPORT coordinates.
534
+ // Never add window.scrollX/scrollY here — getBoundingClientRect is already viewport-relative, and
535
+ // adding scroll converts to document coordinates, which under `position: fixed` drags the menu
536
+ // off by exactly the scroll offset.
537
+ // HORIZONTAL. Align the box's LEFT edge to the button's left edge and let it grow rightward.
538
+ // Right-alignment is wrong for this control: the Skills button sits in `.attach-buttons` on the
539
+ // LEFT of the composer, so pinning the box's right edge to the button's right edge sends a
540
+ // 280-400px menu off the left of the screen, and clamping it back parks it over the middle of
541
+ // the composer. Flip to right-aligned only when growing right would overflow the viewport,
542
+ // which is what a menu anchored to a right-hand control needs.
543
+ const assumedWidth = Math.min(400, window.innerWidth - GUTTER * 2);
544
+ const overflowsRight = rect.left + assumedWidth > window.innerWidth - GUTTER;
545
+ this.mentionDropdownAlignRight = overflowsRight;
546
+ // align-right shifts the box back by its own width, so `left` is then its RIGHT edge; otherwise
547
+ // `left` is its left edge. Clamp both forms inside the gutter.
548
+ //
549
+ // When flipping, align to the CONTAINER's right edge, not the button's. `.attach-buttons` is
550
+ // pinned to the composer's bottom-right and Skills is the leftmost of five icons, so pinning the
551
+ // box to that one button's right edge hangs its whole 400px body out to the left of the icon the
552
+ // user pressed. Aligning to the composer instead puts the menu above the button cluster, which is
553
+ // what "above the button" means when the menu is ten times the button's width.
554
+ const flippedRightEdge = containerRect
555
+ ? Math.min(containerRect.right, window.innerWidth - GUTTER)
556
+ : Math.min(rect.right, window.innerWidth - GUTTER);
557
+ const left = overflowsRight
558
+ ? Math.max(assumedWidth + GUTTER, flippedRightEdge)
559
+ : Math.min(Math.max(GUTTER, rect.left), window.innerWidth - GUTTER - assumedWidth);
560
+ // VERTICAL. Prefer the composer's top edge so the menu clears the whole input box rather than
561
+ // overlapping the text the user is composing; fall back to the button when there is no container.
562
+ // Not unconditional: `show-above` lifts the box by its own height, so forcing it where there is
563
+ // no room renders it off the top of the viewport where it cannot be reached.
564
+ const anchorTop = containerRect ? containerRect.top : rect.top;
565
+ const dropdownHeight = Math.min(Math.max(this.mentionSuggestions.length, 1) * 56, 300);
566
+ // Prefer above, but when it does not fit, take whichever side has MORE room rather than
567
+ // dropping below unconditionally — the composer is bottom-docked, so below is usually the worse
568
+ // side. In a short viewport (a popped-out chat, or mobile with the keyboard up) that difference
569
+ // is the whole menu versus a clipped sliver.
570
+ const spaceBelow = window.innerHeight - rect.bottom;
571
+ const showAbove = anchorTop >= dropdownHeight + GUTTER || anchorTop > spaceBelow;
572
+ this.mentionDropdownShowAbove = showAbove;
573
+ // Above: `top` is the box's BOTTOM edge (the transform lifts it). Below: it is the top edge.
574
+ // Clamped either way, because dropdownHeight is an estimate (rows with descriptions run taller
575
+ // than 56px) and an underestimate would otherwise clip the first row off the top of the screen.
576
+ const rawTop = showAbove ? anchorTop - 8 : rect.bottom + 8;
577
+ const top = showAbove
578
+ ? Math.max(GUTTER + dropdownHeight, Math.min(rawTop, window.innerHeight - GUTTER))
579
+ : Math.max(GUTTER, Math.min(rawTop, window.innerHeight - GUTTER - dropdownHeight));
580
+ this.mentionDropdownPosition = { top, left };
581
+ }
407
582
  /**
408
583
  * Handle mention selection from dropdown
409
584
  */
@@ -446,6 +621,61 @@ export class MentionEditorComponent {
446
621
  }
447
622
  return true;
448
623
  }
624
+ /**
625
+ * Open the suggestion dropdown for a trigger character, exactly as if the user had typed it.
626
+ *
627
+ * Exists so a trigger can have a BUTTON as well as a keystroke. `/` commands were previously
628
+ * reachable only by knowing to type `/`, which is not an affordance — nothing on screen says the
629
+ * feature is there.
630
+ *
631
+ * Deliberately inserts the character and re-runs the normal input path rather than opening the
632
+ * dropdown directly. Everything downstream (which providers own the char, permission filtering,
633
+ * the query the user then types, replacing the char with the chosen chip) is already driven by
634
+ * that path; short-circuiting it would fork the flow and leave `mentionStartIndex` /
635
+ * `activeTrigger` unset, so the first selection would insert in the wrong place.
636
+ *
637
+ * @returns false when the editor is disabled, unavailable, or no active provider owns the char.
638
+ */
639
+ OpenTrigger(triggerChar, anchorEl) {
640
+ const editor = this.editorRef?.nativeElement;
641
+ if (!editor || this.disabled) {
642
+ return false;
643
+ }
644
+ if (!this.mentionTriggers.includes(triggerChar)) {
645
+ return false;
646
+ }
647
+ if (!this.FocusCaretAtEnd()) {
648
+ return false;
649
+ }
650
+ const selection = window.getSelection();
651
+ if (!selection || selection.rangeCount === 0) {
652
+ return false;
653
+ }
654
+ // NOTHING is written into the editor. An earlier version inserted the trigger character to
655
+ // reuse the typed path, and cleaned it up on dismissal — but a character the user never typed,
656
+ // appearing and then vanishing, is visible churn in their own message. The dropdown is opened
657
+ // directly instead, and the character only ever exists as the chip the user chooses.
658
+ this.virtualTriggerOpen = true;
659
+ this.virtualTriggerAnchor = anchorEl ?? null;
660
+ this.virtualTriggerBaseline = this.getTextBeforeCursor(selection.getRangeAt(0)).length;
661
+ this.activeTrigger = triggerChar;
662
+ this.mentionQuery = '';
663
+ void this.fetchSuggestions(triggerChar, '');
664
+ return true;
665
+ }
666
+ /**
667
+ * True when the suggestion dropdown is open FOR THIS trigger character.
668
+ *
669
+ * Lets a control that opens a trigger render its own pressed state without duplicating the
670
+ * editor's state. Both halves matter: `showMentionDropdown` alone would light the Skills button
671
+ * while an unrelated `@` mention dropdown is open.
672
+ */
673
+ IsTriggerOpen(triggerChar) {
674
+ // virtualTriggerOpen covers the window between the press and the provider's response. Reporting
675
+ // "closed" there makes the second press of a quick double-click re-run the open path instead of
676
+ // toggling, re-emitting the Before/After pair.
677
+ return (this.showMentionDropdown || this.virtualTriggerOpen) && this.activeTrigger === triggerChar;
678
+ }
449
679
  /** True when keyboard focus currently sits inside this editor. */
450
680
  get HasFocus() {
451
681
  const editor = this.editorRef?.nativeElement;
@@ -486,12 +716,17 @@ export class MentionEditorComponent {
486
716
  if (!selection || selection.rangeCount === 0)
487
717
  return;
488
718
  const range = selection.getRangeAt(0);
489
- // Delete the trigger + query text (use the active trigger char)
719
+ // Delete the trigger + query text (use the active trigger char). A VIRTUAL trigger has no
720
+ // character in the editor, so the span to remove is only what the user typed since it opened —
721
+ // anchoring on the trigger char here would delete an unrelated earlier one, or nothing.
490
722
  const textBeforeCursor = this.getTextBeforeCursor(range);
491
- const lastAtIndex = textBeforeCursor.lastIndexOf(this.activeTrigger);
492
- const deleteLength = textBeforeCursor.length - lastAtIndex;
493
- range.setStart(range.startContainer, range.startOffset - deleteLength);
494
- range.deleteContents();
723
+ const deleteLength = this.virtualTriggerOpen
724
+ ? Math.max(0, textBeforeCursor.length - this.virtualTriggerBaseline)
725
+ : textBeforeCursor.length - textBeforeCursor.lastIndexOf(this.activeTrigger);
726
+ if (deleteLength > 0) {
727
+ range.setStart(range.startContainer, range.startOffset - deleteLength);
728
+ range.deleteContents();
729
+ }
495
730
  // Create mention chip element
496
731
  const chip = this.createMentionChip(suggestion);
497
732
  // Insert chip
@@ -855,6 +1090,12 @@ export class MentionEditorComponent {
855
1090
  * Close mention dropdown
856
1091
  */
857
1092
  closeMentionDropdown() {
1093
+ // No text cleanup: a virtual trigger never wrote anything into the editor, which is the whole
1094
+ // point of it. Dismissing leaves the message exactly as the user left it.
1095
+ this.virtualTriggerOpen = false;
1096
+ this.virtualTriggerBaseline = 0;
1097
+ this.virtualTriggerAnchor = null;
1098
+ this.mentionDropdownAlignRight = false;
858
1099
  // Invalidate any in-flight suggestion fetch so a late response can't reopen the dropdown
859
1100
  this.suggestionRequestSeq++;
860
1101
  this.showMentionDropdown = false;
@@ -1427,19 +1668,21 @@ export class MentionEditorComponent {
1427
1668
  input.onchange = (e) => this.onFileSelected(e);
1428
1669
  input.click();
1429
1670
  }
1430
- static ɵfac = function MentionEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MentionEditorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1671
+ static ɵfac = function MentionEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MentionEditorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef)); };
1431
1672
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MentionEditorComponent, selectors: [["mj-mention-editor"]], viewQuery: function MentionEditorComponent_Query(rf, ctx) { if (rf & 1) {
1432
1673
  i0.ɵɵviewQuery(_c0, 5);
1433
1674
  } if (rf & 2) {
1434
1675
  let _t;
1435
1676
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.editorRef = _t.first);
1677
+ } }, hostBindings: function MentionEditorComponent_HostBindings(rf, ctx) { if (rf & 1) {
1678
+ i0.ɵɵlistener("mousedown", function MentionEditorComponent_mousedown_HostBindingHandler($event) { return ctx.onDocumentMouseDown($event); }, i0.ɵɵresolveDocument);
1436
1679
  } }, inputs: { placeholder: "placeholder", disabled: "disabled", currentUser: "currentUser", enableMentions: "enableMentions", TriggerProviders: "TriggerProviders", ExcludedTriggerKeys: "ExcludedTriggerKeys", Provider: "Provider", autoFocus: "autoFocus", enableAttachments: "enableAttachments", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes" }, outputs: { valueChange: "valueChange", mentionSelected: "mentionSelected", enterPressed: "enterPressed", attachmentsChanged: "attachmentsChanged", attachmentError: "attachmentError", attachmentClicked: "attachmentClicked", editorBlurred: "editorBlurred" }, standalone: false, features: [i0.ɵɵProvidersFeature([
1437
1680
  {
1438
1681
  provide: NG_VALUE_ACCESSOR,
1439
1682
  useExisting: forwardRef(() => MentionEditorComponent),
1440
1683
  multi: true
1441
1684
  }
1442
- ])], decls: 6, vars: 7, consts: [["editor", ""], [1, "mention-editor-container", 3, "click", "dragover", "dragleave", "drop"], [1, "pending-attachments"], ["contenteditable", "true", 1, "mention-editor", 3, "input", "keydown", "blur", "paste"], [1, "drop-overlay"], [3, "suggestions", "position", "showAbove", "useFixedPositioning", "visible"], [1, "attachment-thumbnail"], [1, "attachment-thumbnail", 3, "click"], [1, "thumbnail-image", 3, "src", "alt"], [1, "thumbnail-placeholder"], ["title", "Remove attachment", 1, "remove-attachment", 3, "click"], [1, "fa-solid", "fa-times"], [1, "fa-solid", "fa-file"], [1, "file-name"], [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) {
1685
+ ])], decls: 6, vars: 7, consts: [["editor", ""], [1, "mention-editor-container", 3, "click", "dragover", "dragleave", "drop"], [1, "pending-attachments"], ["contenteditable", "true", 1, "mention-editor", 3, "input", "keydown", "blur", "paste"], [1, "drop-overlay"], [3, "suggestions", "position", "showAbove", "alignRight", "useFixedPositioning", "visible"], [1, "attachment-thumbnail"], [1, "attachment-thumbnail", 3, "click"], [1, "thumbnail-image", 3, "src", "alt"], [1, "thumbnail-placeholder"], ["title", "Remove attachment", 1, "remove-attachment", 3, "click"], [1, "fa-solid", "fa-times"], [1, "fa-solid", "fa-file"], [1, "file-name"], [1, "drop-message"], [1, "fa-solid", "fa-cloud-arrow-up"], [3, "suggestionSelected", "closed", "suggestions", "position", "showAbove", "alignRight", "useFixedPositioning", "visible"]], template: function MentionEditorComponent_Template(rf, ctx) { if (rf & 1) {
1443
1686
  const _r1 = i0.ɵɵgetCurrentView();
1444
1687
  i0.ɵɵelementStart(0, "div", 1);
1445
1688
  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)); });
@@ -1448,7 +1691,7 @@ export class MentionEditorComponent {
1448
1691
  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)); });
1449
1692
  i0.ɵɵelementEnd();
1450
1693
  i0.ɵɵconditionalCreate(4, MentionEditorComponent_Conditional_4_Template, 5, 0, "div", 4);
1451
- i0.ɵɵconditionalCreate(5, MentionEditorComponent_Conditional_5_Template, 1, 5, "mj-mention-dropdown", 5);
1694
+ i0.ɵɵconditionalCreate(5, MentionEditorComponent_Conditional_5_Template, 1, 6, "mj-mention-dropdown", 5);
1452
1695
  i0.ɵɵelementEnd();
1453
1696
  } if (rf & 2) {
1454
1697
  i0.ɵɵclassProp("drag-over", ctx.isDragOver);
@@ -1470,8 +1713,8 @@ export class MentionEditorComponent {
1470
1713
  useExisting: forwardRef(() => MentionEditorComponent),
1471
1714
  multi: true
1472
1715
  }
1473
- ], 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 @if (pendingAttachments.length > 0) {\n <div class=\"pending-attachments\">\n @for (attachment of pendingAttachments; track attachment) {\n <div class=\"attachment-thumbnail\"\n (click)=\"onAttachmentClick(attachment)\">\n @if (attachment.thumbnailUrl) {\n <img\n [src]=\"attachment.thumbnailUrl\"\n [alt]=\"attachment.fileName\"\n class=\"thumbnail-image\">\n }\n @if (!attachment.thumbnailUrl) {\n <div class=\"thumbnail-placeholder\">\n <i class=\"fa-solid fa-file\"></i>\n <span class=\"file-name\">{{ attachment.fileName }}</span>\n </div>\n }\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 }\n </div>\n }\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 @if (isDragOver) {\n <div class=\"drop-overlay\">\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\n <!-- Mention Dropdown -->\n @if (showMentionDropdown && enableMentions) {\n <mj-mention-dropdown\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 }\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: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--mj-brand-primary);\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(--mj-text-muted);\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(--mj-bg-surface-sunken);\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: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n box-shadow: var(--mj-shadow-md);\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: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n::ng-deep .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-lg);\n transition: all 0.2s ease;\n}\n::ng-deep .mention-chip:focus, ::ng-deep .mention-chip.selected {\n outline: 2px solid var(--mj-brand-primary);\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.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: color-mix(in srgb, var(--mj-text-primary) 20%, transparent);\n border-radius: 3px;\n}\n.mention-editor::-webkit-scrollbar-thumb:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\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 color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, transparent);\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: var(--mj-bg-surface-sunken);\n border: 1px solid color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n}\n\n.attachment-thumbnail:hover {\n transform: scale(1.05);\n box-shadow: var(--mj-shadow-lg);\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: var(--mj-text-secondary);\n}\n\n.thumbnail-placeholder i {\n font-size: 24px;\n margin-bottom: 4px;\n color: var(--mj-text-muted);\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: color-mix(in srgb, var(--mj-text-primary) 60%, transparent);\n color: var(--mj-text-inverse);\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: color-mix(in srgb, var(--mj-status-error) 90%, transparent);\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: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n backdrop-filter: blur(2px);\n border: 2px dashed var(--mj-brand-primary);\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: var(--mj-brand-primary);\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"] }]
1474
- }], () => [{ type: i0.ChangeDetectorRef }], { editorRef: [{
1716
+ ], 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 @if (pendingAttachments.length > 0) {\n <div class=\"pending-attachments\">\n @for (attachment of pendingAttachments; track attachment) {\n <div class=\"attachment-thumbnail\"\n (click)=\"onAttachmentClick(attachment)\">\n @if (attachment.thumbnailUrl) {\n <img\n [src]=\"attachment.thumbnailUrl\"\n [alt]=\"attachment.fileName\"\n class=\"thumbnail-image\">\n }\n @if (!attachment.thumbnailUrl) {\n <div class=\"thumbnail-placeholder\">\n <i class=\"fa-solid fa-file\"></i>\n <span class=\"file-name\">{{ attachment.fileName }}</span>\n </div>\n }\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 }\n </div>\n }\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 @if (isDragOver) {\n <div class=\"drop-overlay\">\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\n <!-- Mention Dropdown -->\n @if (showMentionDropdown && enableMentions) {\n <mj-mention-dropdown\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [showAbove]=\"mentionDropdownShowAbove\"\n [alignRight]=\"mentionDropdownAlignRight\"\n [useFixedPositioning]=\"true\"\n [visible]=\"true\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n }\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: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--mj-brand-primary);\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(--mj-text-muted);\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(--mj-bg-surface-sunken);\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: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n box-shadow: var(--mj-shadow-md);\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: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n::ng-deep .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-lg);\n transition: all 0.2s ease;\n}\n::ng-deep .mention-chip:focus, ::ng-deep .mention-chip.selected {\n outline: 2px solid var(--mj-brand-primary);\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.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: color-mix(in srgb, var(--mj-text-primary) 20%, transparent);\n border-radius: 3px;\n}\n.mention-editor::-webkit-scrollbar-thumb:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\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 color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, transparent);\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: var(--mj-bg-surface-sunken);\n border: 1px solid color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n}\n\n.attachment-thumbnail:hover {\n transform: scale(1.05);\n box-shadow: var(--mj-shadow-lg);\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: var(--mj-text-secondary);\n}\n\n.thumbnail-placeholder i {\n font-size: 24px;\n margin-bottom: 4px;\n color: var(--mj-text-muted);\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: color-mix(in srgb, var(--mj-text-primary) 60%, transparent);\n color: var(--mj-text-inverse);\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: color-mix(in srgb, var(--mj-status-error) 90%, transparent);\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: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n backdrop-filter: blur(2px);\n border: 2px dashed var(--mj-brand-primary);\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: var(--mj-brand-primary);\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"] }]
1717
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], { editorRef: [{
1475
1718
  type: ViewChild,
1476
1719
  args: ['editor', { static: false }]
1477
1720
  }], placeholder: [{
@@ -1512,6 +1755,9 @@ export class MentionEditorComponent {
1512
1755
  type: Output
1513
1756
  }], editorBlurred: [{
1514
1757
  type: Output
1758
+ }], onDocumentMouseDown: [{
1759
+ type: HostListener,
1760
+ args: ['document:mousedown', ['$event']]
1515
1761
  }] }); })();
1516
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MentionEditorComponent, { className: "MentionEditorComponent", filePath: "src/lib/components/mention/mention-editor.component.ts", lineNumber: 72 }); })();
1762
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MentionEditorComponent, { className: "MentionEditorComponent", filePath: "src/lib/components/mention/mention-editor.component.ts", lineNumber: 73 }); })();
1517
1763
  //# sourceMappingURL=mention-editor.component.js.map