@propbinder/mobile-design 0.2.35 → 0.2.37

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.
@@ -7164,6 +7164,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7164
7164
  * ```
7165
7165
  */
7166
7166
  class DsMobileMessageComposerComponent {
7167
+ cdr;
7168
+ constructor(cdr) {
7169
+ this.cdr = cdr;
7170
+ }
7167
7171
  /**
7168
7172
  * Avatar initials
7169
7173
  */
@@ -7258,41 +7262,40 @@ class DsMobileMessageComposerComponent {
7258
7262
  const users = this.mentionUsers();
7259
7263
  if (!query)
7260
7264
  return users;
7261
- return users.filter(user => user.name.toLowerCase().includes(query));
7265
+ return users.filter((user) => user.name.toLowerCase().includes(query));
7262
7266
  }, ...(ngDevMode ? [{ debugName: "filteredUsers" }] : []));
7263
7267
  /**
7264
7268
  * Convert filtered users to dropdown items
7265
7269
  */
7266
7270
  mentionDropdownItems = computed(() => {
7267
- return this.filteredUsers().map(user => ({
7271
+ return this.filteredUsers().map((user) => ({
7268
7272
  id: user.name,
7269
7273
  label: user.name,
7270
7274
  data: {
7271
7275
  name: user.name,
7272
7276
  initials: user.initials,
7273
- role: user.role
7274
- }
7277
+ role: user.role,
7278
+ },
7275
7279
  }));
7276
7280
  }, ...(ngDevMode ? [{ debugName: "mentionDropdownItems" }] : []));
7277
7281
  /**
7278
7282
  * Attachment menu items
7283
+ * Static list to prevent change detection loops
7279
7284
  */
7280
- attachmentMenuItems = computed(() => {
7281
- return [
7282
- {
7283
- id: 'photo',
7284
- leadingIcon: 'remixImageLine',
7285
- label: 'Photo',
7286
- action: () => this.handleAddPhoto()
7287
- },
7288
- {
7289
- id: 'file',
7290
- leadingIcon: 'remixFile3Line',
7291
- label: 'File',
7292
- action: () => this.handleAddFile()
7293
- }
7294
- ];
7295
- }, ...(ngDevMode ? [{ debugName: "attachmentMenuItems" }] : []));
7285
+ attachmentMenuItems = [
7286
+ {
7287
+ id: 'photo',
7288
+ leadingIcon: 'remixImageLine',
7289
+ label: 'Photo',
7290
+ action: () => this.handleAddPhoto(),
7291
+ },
7292
+ {
7293
+ id: 'file',
7294
+ leadingIcon: 'remixFile3Line',
7295
+ label: 'File',
7296
+ action: () => this.handleAddFile(),
7297
+ },
7298
+ ];
7296
7299
  /**
7297
7300
  * Emits when a message is sent
7298
7301
  */
@@ -7328,6 +7331,8 @@ class DsMobileMessageComposerComponent {
7328
7331
  }
7329
7332
  // Set up keyboard listeners
7330
7333
  this.setupKeyboardListeners();
7334
+ // Explicitly trigger change detection to avoid NG0100 with ViewChild bindings
7335
+ this.cdr.detectChanges();
7331
7336
  }
7332
7337
  ngOnDestroy() {
7333
7338
  // Clean up keyboard listeners
@@ -7339,22 +7344,22 @@ class DsMobileMessageComposerComponent {
7339
7344
  setupKeyboardListeners() {
7340
7345
  Keyboard.addListener('keyboardWillShow', (info) => {
7341
7346
  document.documentElement.style.setProperty('--keyboard-height', `${info.keyboardHeight}px`);
7342
- }).catch(e => console.log('Keyboard listeners not available:', e));
7347
+ }).catch(() => { });
7343
7348
  Keyboard.addListener('keyboardWillHide', () => {
7344
7349
  document.documentElement.style.setProperty('--keyboard-height', '0px');
7345
- }).catch(e => console.log('Keyboard listeners not available:', e));
7350
+ }).catch(() => { });
7346
7351
  }
7347
7352
  /**
7348
7353
  * Clean up keyboard event listeners
7349
7354
  */
7350
7355
  cleanupKeyboardListeners() {
7351
- Keyboard.removeAllListeners().catch(e => console.log('Keyboard cleanup not available:', e));
7356
+ Keyboard.removeAllListeners().catch(() => { });
7352
7357
  }
7353
7358
  /**
7354
7359
  * Show the keyboard when user interacts with input
7355
7360
  */
7356
7361
  showKeyboard() {
7357
- Keyboard.show().catch(e => console.log('Keyboard.show() not available'));
7362
+ Keyboard.show().catch(() => { });
7358
7363
  }
7359
7364
  /**
7360
7365
  * Handle keyboard shortcuts (Shift+Enter to send)
@@ -7527,7 +7532,7 @@ class DsMobileMessageComposerComponent {
7527
7532
  event.preventDefault();
7528
7533
  event.stopPropagation();
7529
7534
  }
7530
- this.isAttachmentMenuOpen.update(open => !open);
7535
+ this.isAttachmentMenuOpen.update((open) => !open);
7531
7536
  }
7532
7537
  /**
7533
7538
  * Close attachment menu
@@ -7573,15 +7578,13 @@ class DsMobileMessageComposerComponent {
7573
7578
  type: 'image',
7574
7579
  name: `Photo ${this.attachments().length + 1}`,
7575
7580
  size: '',
7576
- isLoading: true
7581
+ isLoading: true,
7577
7582
  };
7578
- this.attachments.update(attachments => [...attachments, loadingAttachment]);
7583
+ this.attachments.update((attachments) => [...attachments, loadingAttachment]);
7579
7584
  // Simulate processing time (in real app, this would be actual image processing)
7580
7585
  // TODO: Reduce to 300ms or remove in production
7581
7586
  setTimeout(() => {
7582
- this.attachments.update(attachments => attachments.map(a => a.id === attachmentId
7583
- ? { ...a, isLoading: false }
7584
- : a));
7587
+ this.attachments.update((attachments) => attachments.map((a) => (a.id === attachmentId ? { ...a, isLoading: false } : a)));
7585
7588
  }, 1500); // 1.5s for testing - shows loading overlay clearly
7586
7589
  }
7587
7590
  console.log('[MessageComposer] All photos added successfully');
@@ -7653,7 +7656,7 @@ class DsMobileMessageComposerComponent {
7653
7656
  const k = 1024;
7654
7657
  const sizes = ['B', 'KB', 'MB', 'GB'];
7655
7658
  const i = Math.floor(Math.log(bytes) / Math.log(k));
7656
- return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
7659
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
7657
7660
  }
7658
7661
  /**
7659
7662
  * Handle file selection from file input
@@ -7668,7 +7671,7 @@ class DsMobileMessageComposerComponent {
7668
7671
  // Process each selected file (up to 6 total)
7669
7672
  const remainingSlots = 6 - this.attachments().length;
7670
7673
  const filesToProcess = Array.from(files).slice(0, remainingSlots);
7671
- filesToProcess.forEach(file => {
7674
+ filesToProcess.forEach((file) => {
7672
7675
  const fileType = this.detectFileType(file);
7673
7676
  const attachmentId = `file-${Date.now()}-${Math.random()}`;
7674
7677
  // Add attachment with loading state immediately
@@ -7678,9 +7681,9 @@ class DsMobileMessageComposerComponent {
7678
7681
  type: fileType,
7679
7682
  name: file.name,
7680
7683
  size: this.formatFileSize(file.size),
7681
- isLoading: true
7684
+ isLoading: true,
7682
7685
  };
7683
- this.attachments.update(attachments => [...attachments, loadingAttachment]);
7686
+ this.attachments.update((attachments) => [...attachments, loadingAttachment]);
7684
7687
  // Create a data URL for preview
7685
7688
  const reader = new FileReader();
7686
7689
  reader.onload = (e) => {
@@ -7690,9 +7693,7 @@ class DsMobileMessageComposerComponent {
7690
7693
  // TODO: Remove setTimeout in production (use actual FileReader timing)
7691
7694
  setTimeout(() => {
7692
7695
  // Update attachment with actual data and remove loading state
7693
- this.attachments.update(attachments => attachments.map(a => a.id === attachmentId
7694
- ? { ...a, src: result, isLoading: false }
7695
- : a));
7696
+ this.attachments.update((attachments) => attachments.map((a) => (a.id === attachmentId ? { ...a, src: result, isLoading: false } : a)));
7696
7697
  // Notify parent that attachments changed so it can scroll
7697
7698
  setTimeout(() => {
7698
7699
  this.attachmentsChanged.emit();
@@ -7711,12 +7712,12 @@ class DsMobileMessageComposerComponent {
7711
7712
  * Keeps keyboard open by maintaining focus
7712
7713
  */
7713
7714
  removeAttachment(attachmentId) {
7714
- this.attachments.update(attachments => attachments.filter(a => a.id !== attachmentId));
7715
+ this.attachments.update((attachments) => attachments.filter((a) => a.id !== attachmentId));
7715
7716
  // Immediately refocus input to prevent keyboard from closing
7716
7717
  setTimeout(() => {
7717
7718
  if (this.messageInputRef?.nativeElement) {
7718
7719
  this.messageInputRef.nativeElement.focus();
7719
- Keyboard.show().catch(e => console.log('Keyboard.show() not available:', e));
7720
+ Keyboard.show().catch((e) => console.log('Keyboard.show() not available:', e));
7720
7721
  }
7721
7722
  }, 0);
7722
7723
  // Notify parent that attachments changed so it can scroll
@@ -7736,13 +7737,11 @@ class DsMobileMessageComposerComponent {
7736
7737
  const isReply = !!this.replyingTo();
7737
7738
  // Emit message sent event
7738
7739
  this.messageSent.emit({
7739
- content: isReply && this.replyingTo()
7740
- ? `@${this.replyingTo().authorName} ${text}`
7741
- : text,
7740
+ content: isReply && this.replyingTo() ? `@${this.replyingTo().authorName} ${text}` : text,
7742
7741
  isReply,
7743
7742
  replyTo: this.replyingTo()?.authorName,
7744
7743
  isEdit,
7745
- attachments: hasAttachments ? [...this.attachments()] : undefined
7744
+ attachments: hasAttachments ? [...this.attachments()] : undefined,
7746
7745
  });
7747
7746
  // Keep keyboard open by explicitly showing it before clearing
7748
7747
  // This prevents the keyboard from starting to close during the clear operation
@@ -7757,7 +7756,7 @@ class DsMobileMessageComposerComponent {
7757
7756
  this.messageInputRef.nativeElement.focus();
7758
7757
  }
7759
7758
  }
7760
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7759
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
7761
7760
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileMessageComposerComponent, isStandalone: true, selector: "ds-mobile-message-composer", inputs: { avatarInitials: { classPropertyName: "avatarInitials", publicName: "avatarInitials", isSignal: true, isRequired: false, transformFunction: null }, avatarType: { classPropertyName: "avatarType", publicName: "avatarType", isSignal: true, isRequired: false, transformFunction: null }, avatarSrc: { classPropertyName: "avatarSrc", publicName: "avatarSrc", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, sendButtonLabel: { classPropertyName: "sendButtonLabel", publicName: "sendButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, attachmentButtonLabel: { classPropertyName: "attachmentButtonLabel", publicName: "attachmentButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, showAttachmentButton: { classPropertyName: "showAttachmentButton", publicName: "showAttachmentButton", isSignal: true, isRequired: false, transformFunction: null }, editIndicatorText: { classPropertyName: "editIndicatorText", publicName: "editIndicatorText", isSignal: true, isRequired: false, transformFunction: null }, replyIndicatorText: { classPropertyName: "replyIndicatorText", publicName: "replyIndicatorText", isSignal: true, isRequired: false, transformFunction: null }, enableMentions: { classPropertyName: "enableMentions", publicName: "enableMentions", isSignal: true, isRequired: false, transformFunction: null }, mentionUsers: { classPropertyName: "mentionUsers", publicName: "mentionUsers", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSent: "messageSent", editCancelled: "editCancelled", replyCancelled: "replyCancelled", mentionSelected: "mentionSelected", attachmentClicked: "attachmentClicked", attachmentsChanged: "attachmentsChanged" }, viewQueries: [{ propertyName: "messageInputRef", first: true, predicate: ["messageInputEl"], descendants: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
7762
7761
  <div class="message-composer">
7763
7762
  <!-- Edit indicator (optional) -->
@@ -7772,7 +7771,7 @@ class DsMobileMessageComposerComponent {
7772
7771
  </button>
7773
7772
  </div>
7774
7773
  }
7775
-
7774
+
7776
7775
  <!-- Reply indicator (optional) -->
7777
7776
  @if (replyingTo() && !editingMessage()) {
7778
7777
  <div class="reply-indicator">
@@ -7787,21 +7786,18 @@ class DsMobileMessageComposerComponent {
7787
7786
  </button>
7788
7787
  </div>
7789
7788
  }
7790
-
7789
+
7791
7790
  <!-- Attachment Previews (if any) -->
7792
7791
  @if (attachments().length > 0) {
7793
7792
  <div class="attachment-previews-section">
7794
7793
  <div class="attachment-previews">
7795
7794
  @for (attachment of attachments(); track attachment.id) {
7796
- <ds-mobile-attachment-preview
7797
- [attachment]="attachment"
7798
- (remove)="removeAttachment($event)"
7799
- />
7795
+ <ds-mobile-attachment-preview [attachment]="attachment" (remove)="removeAttachment($event)" />
7800
7796
  }
7801
7797
  </div>
7802
7798
  </div>
7803
7799
  }
7804
-
7800
+
7805
7801
  <div class="composer-content">
7806
7802
  <!-- Attachment button replacing avatar (left side) -->
7807
7803
  @if (showAttachmentButton()) {
@@ -7812,34 +7808,30 @@ class DsMobileMessageComposerComponent {
7812
7808
  icon="remixAddLine"
7813
7809
  variant="secondary"
7814
7810
  size="lg"
7815
- (touchstart)="toggleAttachmentMenu($event)"
7816
- (mousedown)="toggleAttachmentMenu($event)"
7811
+ (clicked)="toggleAttachmentMenu($event)"
7817
7812
  [attr.aria-label]="attachmentButtonLabel()"
7818
- [attr.aria-expanded]="isAttachmentMenuOpen()">
7813
+ [attr.aria-expanded]="isAttachmentMenuOpen()"
7814
+ >
7819
7815
  </ds-icon-button>
7820
-
7816
+
7821
7817
  <!-- Attachment menu using dropdown -->
7822
7818
  <ds-mobile-dropdown
7823
- [items]="attachmentMenuItems()"
7819
+ [items]="attachmentMenuItems"
7824
7820
  [isOpen]="isAttachmentMenuOpen()"
7825
7821
  [trigger]="'attachment-trigger'"
7826
7822
  [keepFocusOn]="messageInputRef"
7827
7823
  position="above"
7828
7824
  align="start"
7829
7825
  (itemSelected)="handleAttachmentMenuSelect($event)"
7830
- (closed)="closeAttachmentMenu()">
7826
+ (closed)="closeAttachmentMenu()"
7827
+ >
7831
7828
  </ds-mobile-dropdown>
7832
7829
  </div>
7833
7830
  } @else {
7834
7831
  <!-- Avatar (only shown when attachment button is hidden) -->
7835
- <ds-avatar
7836
- [initials]="avatarInitials()"
7837
- [type]="avatarType()"
7838
- [src]="avatarSrc()"
7839
- size="lg"
7840
- />
7832
+ <ds-avatar [initials]="avatarInitials()" [type]="avatarType()" [src]="avatarSrc()" size="lg" />
7841
7833
  }
7842
-
7834
+
7843
7835
  <div class="composer-input-wrapper">
7844
7836
  <textarea
7845
7837
  #messageInputEl
@@ -7852,8 +7844,9 @@ class DsMobileMessageComposerComponent {
7852
7844
  (focus)="showKeyboard()"
7853
7845
  (click)="showKeyboard()"
7854
7846
  rows="1"
7855
- > </textarea>
7856
-
7847
+ >
7848
+ </textarea>
7849
+
7857
7850
  <!-- Mention menu using dropdown (only render if mentions are enabled) -->
7858
7851
  @if (enableMentions()) {
7859
7852
  <ds-mobile-dropdown
@@ -7864,12 +7857,10 @@ class DsMobileMessageComposerComponent {
7864
7857
  align="start"
7865
7858
  [maxHeight]="200"
7866
7859
  (itemSelected)="handleMentionSelect($event)"
7867
- (closed)="closeMentionMenu()">
7860
+ (closed)="closeMentionMenu()"
7861
+ >
7868
7862
  <ng-template #itemTemplate let-item>
7869
- <ds-avatar
7870
- [initials]="item.data.initials"
7871
- [type]="'initials'"
7872
- size="sm" />
7863
+ <ds-avatar [initials]="item.data.initials" [type]="'initials'" size="sm" />
7873
7864
  <div class="mention-user-info">
7874
7865
  <span class="mention-user-name">{{ item.data.name }}</span>
7875
7866
  <span class="mention-user-role">{{ item.data.role }}</span>
@@ -7877,7 +7868,7 @@ class DsMobileMessageComposerComponent {
7877
7868
  </ng-template>
7878
7869
  </ds-mobile-dropdown>
7879
7870
  }
7880
-
7871
+
7881
7872
  <!-- Send button (absolute positioned in top right, always rendered) -->
7882
7873
  <ds-icon-button
7883
7874
  icon="remixCheckLine"
@@ -7886,11 +7877,12 @@ class DsMobileMessageComposerComponent {
7886
7877
  (clicked)="sendMessage()"
7887
7878
  [attr.aria-label]="sendButtonLabel()"
7888
7879
  [class.send-button-inline]="true"
7889
- [class.show]="messageText().trim().length > 0 || attachments().length > 0">
7880
+ [class.show]="messageText().trim().length > 0 || attachments().length > 0"
7881
+ >
7890
7882
  </ds-icon-button>
7891
7883
  </div>
7892
7884
  </div>
7893
-
7885
+
7894
7886
  <!-- Hidden file input -->
7895
7887
  <input
7896
7888
  #fileInput
@@ -7902,19 +7894,11 @@ class DsMobileMessageComposerComponent {
7902
7894
  (change)="handleFileSelect($event)"
7903
7895
  />
7904
7896
  </div>
7905
- `, isInline: true, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6B5FF5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6B5FF5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6B5FF5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6B5FF5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileAttachmentPreviewComponent, selector: "ds-mobile-attachment-preview", inputs: ["attachment"], outputs: ["remove"] }, { kind: "component", type: DsMobileDropdownComponent, selector: "ds-mobile-dropdown", inputs: ["trigger", "keepFocusOn", "items", "isOpen", "position", "align", "maxHeight", "emptyMessage", "ariaLabel"], outputs: ["itemSelected", "closed"] }] });
7897
+ `, isInline: true, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6b5ff5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6b5ff5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6b5ff5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6b5ff5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileAttachmentPreviewComponent, selector: "ds-mobile-attachment-preview", inputs: ["attachment"], outputs: ["remove"] }, { kind: "component", type: DsMobileDropdownComponent, selector: "ds-mobile-dropdown", inputs: ["trigger", "keepFocusOn", "items", "isOpen", "position", "align", "maxHeight", "emptyMessage", "ariaLabel"], outputs: ["itemSelected", "closed"] }] });
7906
7898
  }
7907
7899
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, decorators: [{
7908
7900
  type: Component,
7909
- args: [{ selector: 'ds-mobile-message-composer', standalone: true, imports: [
7910
- CommonModule,
7911
- FormsModule,
7912
- DsAvatarComponent,
7913
- DsIconButtonComponent,
7914
- DsIconComponent,
7915
- DsMobileAttachmentPreviewComponent,
7916
- DsMobileDropdownComponent
7917
- ], template: `
7901
+ args: [{ selector: 'ds-mobile-message-composer', standalone: true, imports: [CommonModule, FormsModule, DsAvatarComponent, DsIconButtonComponent, DsIconComponent, DsMobileAttachmentPreviewComponent, DsMobileDropdownComponent], template: `
7918
7902
  <div class="message-composer">
7919
7903
  <!-- Edit indicator (optional) -->
7920
7904
  @if (editingMessage()) {
@@ -7928,7 +7912,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7928
7912
  </button>
7929
7913
  </div>
7930
7914
  }
7931
-
7915
+
7932
7916
  <!-- Reply indicator (optional) -->
7933
7917
  @if (replyingTo() && !editingMessage()) {
7934
7918
  <div class="reply-indicator">
@@ -7943,21 +7927,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7943
7927
  </button>
7944
7928
  </div>
7945
7929
  }
7946
-
7930
+
7947
7931
  <!-- Attachment Previews (if any) -->
7948
7932
  @if (attachments().length > 0) {
7949
7933
  <div class="attachment-previews-section">
7950
7934
  <div class="attachment-previews">
7951
7935
  @for (attachment of attachments(); track attachment.id) {
7952
- <ds-mobile-attachment-preview
7953
- [attachment]="attachment"
7954
- (remove)="removeAttachment($event)"
7955
- />
7936
+ <ds-mobile-attachment-preview [attachment]="attachment" (remove)="removeAttachment($event)" />
7956
7937
  }
7957
7938
  </div>
7958
7939
  </div>
7959
7940
  }
7960
-
7941
+
7961
7942
  <div class="composer-content">
7962
7943
  <!-- Attachment button replacing avatar (left side) -->
7963
7944
  @if (showAttachmentButton()) {
@@ -7968,34 +7949,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7968
7949
  icon="remixAddLine"
7969
7950
  variant="secondary"
7970
7951
  size="lg"
7971
- (touchstart)="toggleAttachmentMenu($event)"
7972
- (mousedown)="toggleAttachmentMenu($event)"
7952
+ (clicked)="toggleAttachmentMenu($event)"
7973
7953
  [attr.aria-label]="attachmentButtonLabel()"
7974
- [attr.aria-expanded]="isAttachmentMenuOpen()">
7954
+ [attr.aria-expanded]="isAttachmentMenuOpen()"
7955
+ >
7975
7956
  </ds-icon-button>
7976
-
7957
+
7977
7958
  <!-- Attachment menu using dropdown -->
7978
7959
  <ds-mobile-dropdown
7979
- [items]="attachmentMenuItems()"
7960
+ [items]="attachmentMenuItems"
7980
7961
  [isOpen]="isAttachmentMenuOpen()"
7981
7962
  [trigger]="'attachment-trigger'"
7982
7963
  [keepFocusOn]="messageInputRef"
7983
7964
  position="above"
7984
7965
  align="start"
7985
7966
  (itemSelected)="handleAttachmentMenuSelect($event)"
7986
- (closed)="closeAttachmentMenu()">
7967
+ (closed)="closeAttachmentMenu()"
7968
+ >
7987
7969
  </ds-mobile-dropdown>
7988
7970
  </div>
7989
7971
  } @else {
7990
7972
  <!-- Avatar (only shown when attachment button is hidden) -->
7991
- <ds-avatar
7992
- [initials]="avatarInitials()"
7993
- [type]="avatarType()"
7994
- [src]="avatarSrc()"
7995
- size="lg"
7996
- />
7973
+ <ds-avatar [initials]="avatarInitials()" [type]="avatarType()" [src]="avatarSrc()" size="lg" />
7997
7974
  }
7998
-
7975
+
7999
7976
  <div class="composer-input-wrapper">
8000
7977
  <textarea
8001
7978
  #messageInputEl
@@ -8008,8 +7985,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8008
7985
  (focus)="showKeyboard()"
8009
7986
  (click)="showKeyboard()"
8010
7987
  rows="1"
8011
- > </textarea>
8012
-
7988
+ >
7989
+ </textarea>
7990
+
8013
7991
  <!-- Mention menu using dropdown (only render if mentions are enabled) -->
8014
7992
  @if (enableMentions()) {
8015
7993
  <ds-mobile-dropdown
@@ -8020,12 +7998,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8020
7998
  align="start"
8021
7999
  [maxHeight]="200"
8022
8000
  (itemSelected)="handleMentionSelect($event)"
8023
- (closed)="closeMentionMenu()">
8001
+ (closed)="closeMentionMenu()"
8002
+ >
8024
8003
  <ng-template #itemTemplate let-item>
8025
- <ds-avatar
8026
- [initials]="item.data.initials"
8027
- [type]="'initials'"
8028
- size="sm" />
8004
+ <ds-avatar [initials]="item.data.initials" [type]="'initials'" size="sm" />
8029
8005
  <div class="mention-user-info">
8030
8006
  <span class="mention-user-name">{{ item.data.name }}</span>
8031
8007
  <span class="mention-user-role">{{ item.data.role }}</span>
@@ -8033,7 +8009,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8033
8009
  </ng-template>
8034
8010
  </ds-mobile-dropdown>
8035
8011
  }
8036
-
8012
+
8037
8013
  <!-- Send button (absolute positioned in top right, always rendered) -->
8038
8014
  <ds-icon-button
8039
8015
  icon="remixCheckLine"
@@ -8042,11 +8018,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8042
8018
  (clicked)="sendMessage()"
8043
8019
  [attr.aria-label]="sendButtonLabel()"
8044
8020
  [class.send-button-inline]="true"
8045
- [class.show]="messageText().trim().length > 0 || attachments().length > 0">
8021
+ [class.show]="messageText().trim().length > 0 || attachments().length > 0"
8022
+ >
8046
8023
  </ds-icon-button>
8047
8024
  </div>
8048
8025
  </div>
8049
-
8026
+
8050
8027
  <!-- Hidden file input -->
8051
8028
  <input
8052
8029
  #fileInput
@@ -8058,8 +8035,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8058
8035
  (change)="handleFileSelect($event)"
8059
8036
  />
8060
8037
  </div>
8061
- `, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6B5FF5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6B5FF5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6B5FF5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6B5FF5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"] }]
8062
- }], propDecorators: { avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], sendButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendButtonLabel", required: false }] }], attachmentButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachmentButtonLabel", required: false }] }], showAttachmentButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAttachmentButton", required: false }] }], editIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "editIndicatorText", required: false }] }], replyIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyIndicatorText", required: false }] }], enableMentions: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableMentions", required: false }] }], mentionUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionUsers", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], messageInputRef: [{
8038
+ `, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6b5ff5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6b5ff5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6b5ff5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6b5ff5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"] }]
8039
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], sendButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendButtonLabel", required: false }] }], attachmentButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachmentButtonLabel", required: false }] }], showAttachmentButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAttachmentButton", required: false }] }], editIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "editIndicatorText", required: false }] }], replyIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyIndicatorText", required: false }] }], enableMentions: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableMentions", required: false }] }], mentionUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionUsers", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], messageInputRef: [{
8063
8040
  type: ViewChild,
8064
8041
  args: ['messageInputEl']
8065
8042
  }], fileInput: [{
@@ -15144,8 +15121,10 @@ class DsMobileChatModalComponent {
15144
15121
  }, 150);
15145
15122
  });
15146
15123
  });
15147
- // In a real app, you would send this to your backend
15148
- // this.chatService.sendMessage(this.chatData.participant.id, event.content, event.attachments);
15124
+ // Executing the onSend callback if provided
15125
+ if (this.chatData.onSend) {
15126
+ this.chatData.onSend(event.content, event.attachments || []);
15127
+ }
15149
15128
  }
15150
15129
  /**
15151
15130
  * Handle attachment click
@@ -15251,8 +15230,28 @@ class DsMobileChatModalComponent {
15251
15230
  * Handle file attachment click
15252
15231
  */
15253
15232
  handleFileAttachmentClick(fileAttachment) {
15254
- console.log('[ChatModal] File attachment clicked:', fileAttachment);
15255
- // In a real app, you would open the file viewer
15233
+ // If a custom handler is provided, use it
15234
+ if (this.chatData.onFileClick) {
15235
+ this.chatData.onFileClick(fileAttachment);
15236
+ return;
15237
+ }
15238
+ // Default behavior: Try to open/download the file
15239
+ const url = fileAttachment.src || fileAttachment.url;
15240
+ if (url) {
15241
+ const link = document.createElement('a');
15242
+ link.href = url;
15243
+ link.target = '_blank';
15244
+ // If it has a name, setting download attribute suggests downloading
15245
+ if (fileAttachment.name) {
15246
+ link.download = fileAttachment.name;
15247
+ }
15248
+ document.body.appendChild(link);
15249
+ link.click();
15250
+ document.body.removeChild(link);
15251
+ }
15252
+ else {
15253
+ console.warn('[ChatModal] No URL or source for file attachment:', fileAttachment);
15254
+ }
15256
15255
  }
15257
15256
  /**
15258
15257
  * Handle image attachment click - opens lightbox
@@ -15809,7 +15808,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
15809
15808
  * ],
15810
15809
  * currentUserId: '456',
15811
15810
  * currentUserInitials: 'JD',
15812
- * autoFocus: true
15811
+ * currentUserInitials: 'JD',
15812
+ * autoFocus: true,
15813
+ * onSend: async (message, attachments) => {
15814
+ * console.log('Sending message:', message);
15815
+ * // await this.chatService.sendMessage(participant.id, message, attachments);
15816
+ * },
15817
+ * onFileClick: (file) => {
15818
+ * console.log('File clicked:', file);
15819
+ * // window.open(file.url, '_blank');
15820
+ * }
15813
15821
  * });
15814
15822
  * }
15815
15823
  * ```